blkdev: Support rawflag=1, pass parameters using global variables rather
authorWill Sowerbutts <will@sowerbutts.com>
Sun, 25 Jan 2015 21:55:30 +0000 (21:55 +0000)
committerWill Sowerbutts <will@sowerbutts.com>
Sun, 25 Jan 2015 21:55:30 +0000 (21:55 +0000)
than function call parameters.

Kernel/dev/blkdev.c
Kernel/dev/blkdev.h
Kernel/dev/mbr.c
Kernel/dev/mbr.h

index 514bf64..1475736 100644 (file)
@@ -51,6 +51,7 @@
 */
 
 static blkdev_t blkdev_table[MAX_BLKDEV];
+struct blkparam blk_op;
 
 int blkdev_open(uint8_t minor, uint16_t flags)
 {
@@ -71,38 +72,56 @@ int blkdev_open(uint8_t minor, uint16_t flags)
     return -1;
 }
 
-static int blkdev_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+static int blkdev_transfer(uint8_t minor, uint8_t rawflag)
 {
-    void *target;
-    uint32_t lba;
-    uint8_t partition;
-    blkdev_t *blk;
+    uint8_t partition, n, count=0;
 
     /* we trust that blkdev_open() has already verified that this minor number is valid */
-    blk = &blkdev_table[minor >> 4];
+    blk_op.blkdev = &blkdev_table[minor >> 4];
     partition = minor & 0x0F;
 
-    if(rawflag == 0) {
-        target = udata.u_buf->bf_data;
-        lba = udata.u_buf->bf_blk;
-    }else
-        goto xferfail;
+    switch(rawflag){
+        case 0:
+            /* read single 512-byte sector to buffer in kernel memory */
+            blk_op.nblock = 1;
+            blk_op.lba = udata.u_buf->bf_blk;
+            blk_op.addr = udata.u_buf->bf_data;
+            blk_op.is_user = false;
+            break;
+        case 1:
+            /* read some number of 512-byte sectors directly to user memory */
+            blk_op.nblock = (udata.u_count >> BLKSHIFT);
+            if((udata.u_count | (uint16_t)udata.u_offset) & BLKMASK)
+                panic("blkdev: not integral");
+            blk_op.lba = (udata.u_offset >> BLKSHIFT);
+            blk_op.addr = udata.u_base;
+            blk_op.is_user = true;
+            break;
+        default:
+            goto xferfail;
+    }
 
     if(partition == 0){
        /* partition 0 is the whole disk and requires no translation */
-       if(lba >= blk->drive_lba_count)
+       if(blk_op.lba >= blk_op.blkdev->drive_lba_count)
            goto xferfail;
     }else{
        /* partitions 1+ require us to add in an offset */
-       if(lba >= blk->lba_count[partition-1])
+       if(blk_op.lba >= blk_op.blkdev->lba_count[partition-1])
            goto xferfail;
 
-       lba += blk->lba_first[partition-1];
+       blk_op.lba += blk_op.blkdev->lba_first[partition-1];
     }
 
-    if(blk->transfer(blk->drive_number, lba, target, is_read))
-       return 1; /* 10/10, would transfer sectors again */
+    while(blk_op.nblock){
+        n = blk_op.blkdev->transfer();
+        if(n == 0)
+            goto xferfail;
+        blk_op.nblock -= n;
+        count += n;
+    }
 
+    return count; /* 10/10, would transfer sectors again */
 xferfail:
     udata.u_error = EIO;
     return -1;
@@ -111,28 +130,29 @@ xferfail:
 int blkdev_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
     flag; /* not used */
-    return blkdev_transfer(minor, true, rawflag);
+    blk_op.is_read = true;
+    return blkdev_transfer(minor, rawflag);
 }
 
 int blkdev_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
 {
     flag; /* not used */
-    return blkdev_transfer(minor, false, rawflag);
+    blk_op.is_read = false;
+    return blkdev_transfer(minor, rawflag);
 }
 
 int blkdev_ioctl(uint8_t minor, uint16_t request, char *data)
 {
-    blkdev_t *blk;
     data; /* unused */
 
     if (request != BLKFLSBUF)
        return -1;
 
     /* we trust that blkdev_open() has already verified that this minor number is valid */
-    blk = &blkdev_table[minor >> 4];
+    blk_op.blkdev = &blkdev_table[minor >> 4];
 
-    if (blk->flush)
-       return blk->flush(blk->drive_number);
+    if (blk_op.blkdev->flush)
+       return blk_op.blkdev->flush();
     else
        return 0;
 }
@@ -159,9 +179,9 @@ void blkdev_scan(blkdev_t *blk, uint8_t flags)
 {
     uint8_t letter = 'a' + (blk - blkdev_table);
 
-    flags;
+    flags; /* not used */
 
-    kprintf("hd%c: ", letter);
-    mbr_parse(blk, letter);
+    blk_op.blkdev = blk;
+    mbr_parse(letter);
     kputchar('\n');
 }
index 099ad3b..c1b5f32 100644 (file)
@@ -3,25 +3,42 @@
 
 /* block device drives should call blkdev_add() for each block device found,
    and implement a sector transfer function matching the following prototype. */
-typedef bool (*transfer_function_t)(uint8_t drive, uint32_t lba, void *buffer, bool read_notwrite);
-typedef int (*flush_function_t)(uint8_t drive);
+typedef uint8_t (*transfer_function_t)(void);
+typedef int (*flush_function_t)(void);
 
 /* the following details should be required only by partition parsing code */
-#define MAX_PARTITIONS 15                  /* must be at least 4, at most 15 */
+#define MAX_PARTITIONS 15                   /* must be at least 4, at most 15 */
 typedef struct {
-    transfer_function_t transfer;          /* function to read and write sectors */
-    flush_function_t flush;                /* flush device cache */
-    uint32_t drive_lba_count;              /* count of sectors on raw disk device */
-    uint32_t lba_first[MAX_PARTITIONS];            /* LBA of first sector of each partition; 0 if partition absent */
-    uint32_t lba_count[MAX_PARTITIONS];            /* count of sectors in each partition; 0 if partition absent */
-    uint8_t drive_number;                  /* driver's drive number */
+    uint8_t driver_data;                    /* opaque parameter used by underlying driver (should be first) */
+    transfer_function_t transfer;           /* function to read and write sectors */
+    flush_function_t flush;                 /* flush device cache */
+    uint32_t drive_lba_count;               /* count of sectors on raw disk device */
+    uint32_t lba_first[MAX_PARTITIONS];     /* LBA of first sector of each partition; 0 if partition absent */
+    uint32_t lba_count[MAX_PARTITIONS];     /* count of sectors in each partition; 0 if partition absent */
 } blkdev_t;
 
-/* public interface */
+/* Holds the parameters for the current block operation.
+ * Block I/O being single threaded is deep in the design of UZI/FUZIX
+ * so let's make good use of every advantage we can from it. */
+struct blkparam {
+    /* do not change the order without adjusting BLKPARAM_*_OFFSET macros below */
+    void *addr;                             /* address for transfer buffer */
+    bool is_user;                           /* true: addr is in user memory, false: addr is in kernel memory */
+    blkdev_t *blkdev;                       /* active block device */
+    uint32_t lba;                           /* LBA for first sectors to transfer */
+    uint8_t nblock;                         /* number of sectors to transfer */
+    bool is_read;                           /* true: read sectors, false: write sectors */
+};
+/* macros that inline assembler code can use to access blkparam fields */
+#define BLKPARAM_ADDR_OFFSET    0
+#define BLKPARAM_IS_USER_OFFSET 2
+
+extern struct blkparam blk_op;
+
 /* public interface */
 extern blkdev_t *blkdev_alloc(void);
 extern void blkdev_scan(blkdev_t *blk, uint8_t flags);
-#define SWAPSCAN       0x01
+#define SWAPSCAN    0x01
 extern int blkdev_open(uint8_t minor, uint16_t flags);
 extern int blkdev_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
 extern int blkdev_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
index 2c7855c..9f9ee20 100644 (file)
@@ -22,18 +22,26 @@ typedef struct {
     uint16_t signature;
 } boot_record_t;
 
-void mbr_parse(blkdev_t *blk, char letter)
+void mbr_parse(char letter)
 {
     boot_record_t *br;
     uint8_t i, seen = 0;
-    uint32_t lba = 0, ep_offset = 0, br_offset = 0;
+    uint32_t ep_offset = 0, br_offset = 0;
     uint8_t next = 0;
 
+    kprintf("hd%c: ", letter);
+
     /* allocate temporary memory */
     br = (boot_record_t *)tmpbuf();
 
+    blk_op.is_read = true;
+    blk_op.is_user = false;
+    blk_op.nblock = 1;
+    blk_op.addr = br;
+    blk_op.lba = 0;
+
     do{
-       if(!blk->transfer(blk->drive_number, lba, br, true) || le16_to_cpu(br->signature) != MBR_SIGNATURE)
+        if(!blk_op.blkdev->transfer() || le16_to_cpu(br->signature) != MBR_SIGNATURE)
            break;
 
        /* avoid an infinite loop where extended boot records form a loop */
@@ -42,13 +50,13 @@ void mbr_parse(blkdev_t *blk, char letter)
 
        if(seen == 1){ 
            /* we just loaded the first extended boot record */
-           ep_offset = lba;
+           ep_offset = blk_op.lba;
            next = 4;
            kputs("< ");
        }
 
-       br_offset = lba;
-       lba = 0;
+       br_offset = blk_op.lba;
+       blk_op.lba = 0;
 
        for(i=0; i<MBR_ENTRY_COUNT && next < MAX_PARTITIONS; i++){
            switch(br->partition[i].type){
@@ -60,7 +68,7 @@ void mbr_parse(blkdev_t *blk, char letter)
                    /* Extended boot record, or chained table; in principle a drive should contain
                       at most one extended partition so this code is OK even for parsing the MBR.
                       Chained EBR addresses are relative to the start of the extended partiton. */
-                   lba = ep_offset + le32_to_cpu(br->partition[i].lba_first);
+                   blk_op.lba = ep_offset + le32_to_cpu(br->partition[i].lba_first);
                    if(next >= 4)
                        break;
                    /* we include all primary partitions but we deliberately knobble the size in 
@@ -70,14 +78,14 @@ void mbr_parse(blkdev_t *blk, char letter)
                default:
                    /* Regular partition: In EBRs these are relative to the EBR (not the disk, nor
                       the extended partition) */
-                   blk->lba_first[next] = br_offset + le32_to_cpu(br->partition[i].lba_first);
-                   blk->lba_count[next] = le32_to_cpu(br->partition[i].lba_count);
+                   blk_op.blkdev->lba_first[next] = br_offset + le32_to_cpu(br->partition[i].lba_first);
+                   blk_op.blkdev->lba_count[next] = le32_to_cpu(br->partition[i].lba_count);
                    next++;
                    kprintf("hd%c%d ", letter, next);
            }
        }
        seen++;
-    }while(lba);
+    }while(blk_op.lba);
 
     if(ep_offset && next >= 4)
        kputs("> ");
index 8286160..e728803 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef __MBR_DOT_H__
 #define __MBR_DOT_H__
 
-void mbr_parse(blkdev_t *blk, char letter);
+void mbr_parse(char letter);
 
 #endif