From ce91afe04bd24fe9277a3f7b68ddf0654f1634ac Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Sun, 23 Dec 2018 17:22:14 +1100 Subject: Corrected a bug in the hard-disk driver where calls to hd_read_block() after hd_init() failed (on a system without a disk), would hang. Now, hd_read_block() will fail if no hard disk is present on the system (as indicated by the nblocks count being equal to zero). The same fix also applies to the hd_write_block() function. The hd_init() function now returns a status indicating either successful drive detection and initialization, or failure. This return status won't likely be needed due to the above bug-fix, but may prove useful in the future. Added framework for a block buffer subsystem. This subsystem uses pre-allocated memory to cache blocks that are requested from the block device subsystem. Cached blocks are stored on a linked list sorted in order of usage frequency. Modified the block read/write functions so that they no longer accept a length parameter. The block I/O functions will only read or write a single block at a time. If multiple blocks are required, multiple calls will have to be made. This is to reduce complexity of block device drivers and make integration with the new buffer subsystem easier. Removed all calls to the ATA hard-disk driver. For now, it seems that floppy media will be best as it allows for real-world hardware testing. Furthermore, large portions of the hard-disk driver will need to be re-written anyway once the block buffer subsystem is complete as it only supports PIO transfers, whilst a buffer system will require DMA transfers. As the hard-disk was previously the only supported block device, the block device read/write functions will now always fail, returning -1. --- Makefile | 3 +- include/kernel/fs.h | 15 ++++++++-- include/kernel/hd.h | 6 ++-- kernel/boot.s | 2 +- kernel/fs/block.c | 9 +++--- kernel/fs/buffer.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/fs/fs.c | 5 ++-- kernel/fs/mount.c | 6 ++-- kernel/hd.c | 41 ++++++++++++++------------- 9 files changed, 132 insertions(+), 37 deletions(-) create mode 100644 kernel/fs/buffer.c diff --git a/Makefile b/Makefile index 391597f..0d62a8f 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ clean: rm -f $(TARGET) run: $(TARGET) - qemu-system-x86_64 -s -kernel $(TARGET) -drive file=hd.img,format=raw -serial stdio + #qemu-system-x86_64 -s -kernel $(TARGET) -drive file=hd.img,format=raw -serial stdio + qemu-system-x86_64 -s -kernel $(TARGET) #qemu-system-x86_64 -s -S -kernel $(TARGET) -drive file=hd.img,format=raw .FORCE: diff --git a/include/kernel/fs.h b/include/kernel/fs.h index a752ddf..4ec4de1 100644 --- a/include/kernel/fs.h +++ b/include/kernel/fs.h @@ -50,13 +50,24 @@ struct m_inode { uint16_t i_zone[9]; } __attribute__((packed)); +struct buffer { + void *b_data; + uint16_t b_device; + uint16_t b_block; + struct buffer *b_next; + struct buffer *b_prev; +} __attribute__((packed)); + extern struct super_block sblocks[NRSUPER]; -size_t block_read(void*, size_t , size_t); -size_t block_write(void*, size_t , size_t); +int block_read(void*, size_t); +int block_write(void*, size_t); void mount_root(void); void fs_init(void); +/* various init functions called by fs_init() */ +void buffer_init(void); + #endif diff --git a/include/kernel/hd.h b/include/kernel/hd.h index 7244c92..d4cf2e4 100644 --- a/include/kernel/hd.h +++ b/include/kernel/hd.h @@ -3,9 +3,9 @@ #include -void hd_init(void); +int hd_init(void); -size_t hd_read_block(void*, size_t , size_t); -size_t hd_write_block(void*, size_t , size_t); +int hd_read_block(void*, size_t); +int hd_write_block(void*, size_t); #endif diff --git a/kernel/boot.s b/kernel/boot.s index 5050705..4db2cf7 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -40,7 +40,7 @@ kboot: call flush_idt ; initialize the console call con_init - ; add this point, we can display *some* output + ; at this point, we can display *some* output push .msg call printk add esp, 4 diff --git a/kernel/fs/block.c b/kernel/fs/block.c index b3f7386..caf97d2 100644 --- a/kernel/fs/block.c +++ b/kernel/fs/block.c @@ -1,10 +1,9 @@ -#include #include -size_t block_read(void *buf, size_t block, size_t len) { - return hd_read_block(buf, block, len); +int block_read(void *buf, size_t block) { + return -1; } -size_t block_write(void *buf, size_t block, size_t len) { - return hd_write_block(buf, block, len); +int block_write(void *buf, size_t block) { + return -1; } diff --git a/kernel/fs/buffer.c b/kernel/fs/buffer.c new file mode 100644 index 0000000..7405738 --- /dev/null +++ b/kernel/fs/buffer.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +/* memory dedicated to the block cache */ +#define BSTART 0x80000 +#define BEND 0xA0000 + +static struct buffer *lru; +static struct buffer *mru; + +struct buffer *buffer_get_block(uint16_t device, uint16_t block); + +void buffer_init(void) { + int c = 0; + struct buffer *last = NULL; + struct buffer *b = (struct buffer*) BSTART; + void *d = (void*) (BEND - BLOCK_SIZE); + + while(d > (void*) b) { + memset(b, 0, sizeof(struct buffer)); + + b->b_data = d; + b->b_prev = last; + + if(last) + last->b_next = b; + + last = b; + + b = (struct buffer*) ((void*) b + sizeof(struct buffer)); + d = (void*) (d - (void*) BLOCK_SIZE); + + c++; + } + + lru = (struct buffer*) BSTART; + mru = last; + + printk("[buf] Buffers initialized (0x%x buffers in pool)\n", c); +} + +struct buffer *buffer_get_block(uint16_t device, uint16_t block) { + int ret; + struct buffer **p = &mru; + struct buffer *b; + + /* check if the requested block is already in the cache */ + while(*p) { + if((*p)->b_device == device && (*p)->b_block == block) { + /* put the buffer back at the MRU end of the list */ + (*p)->b_next = NULL; + (*p)->b_prev = mru; + mru = *p; + return *p; + } + p = &(*p)->b_prev; + } + + /* find a buffer at the end of the LRU list */ + b = lru; + lru = lru->b_next; + lru->b_prev = NULL; + ret = block_read(b->b_data, block); + /* abort if we failed to read in the block */ + if(ret < 0) { + /* release the allocated buffer to the pool */ + lru->b_prev = b; + b->b_next = lru; + b->b_prev = NULL; + lru = b; + return NULL; + } + b->b_device = device; + b->b_block = block; + /* put the buffer back at the MRU end of the list */ + b->b_next = NULL; + b->b_prev = mru; + mru = b; + return b; +} diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c index 792668e..e0d9205 100644 --- a/kernel/fs/fs.c +++ b/kernel/fs/fs.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -22,7 +21,9 @@ void fs_init(void) { memset(&sblocks, 0, sizeof(sblocks)); memset(&ftable, 0, sizeof(ftable)); - hd_init(); + buffer_init(); + + /* hd_init(); */ mount_root(); } diff --git a/kernel/fs/mount.c b/kernel/fs/mount.c index 47911fb..9cdf49b 100644 --- a/kernel/fs/mount.c +++ b/kernel/fs/mount.c @@ -6,12 +6,12 @@ struct super_block sblocks[NRSUPER]; void mount_root(void) { - size_t ret; + int ret; char buf[BLOCK_SIZE]; struct super_block *s = (void*) buf; - ret = block_read(buf, 1, 1); - if(ret < 1) { + ret = block_read(buf, 1); + if(ret < 0) { printk("[fs] Failed to read super block\n"); return; } diff --git a/kernel/hd.c b/kernel/hd.c index 3b2aa3c..2f680d1 100644 --- a/kernel/hd.c +++ b/kernel/hd.c @@ -102,53 +102,53 @@ static int write_sect(void *buf, uint32_t lba) { return 0; } -size_t hd_read_block(void *buf, size_t block, size_t len) { +int hd_read_block(void *buf, size_t block) { int ret; size_t i; uint32_t s = SECTS(block); - uint32_t e = SECTS(block + len); + uint32_t e = SECTS(block + 1); - if(s > nblocks - 1) - s = nblocks - 1; - if(e > nblocks - 1) - e = nblocks - 1; + if(nblocks <= s) + return -1; + if(nblocks <= e) + return -1; for(i = 0; i < (e - s); i++) { ret = read_sect(buf, i + s); if(ret < 0) - return BLOCKS(i); + return -1; buf = ((char*) buf + 512); } - return len; + return 0; } -size_t hd_write_block(void *buf, size_t block, size_t len) { +int hd_write_block(void *buf, size_t block) { int ret; size_t i; uint32_t s = SECTS(block); - uint32_t e = SECTS(block + len); + uint32_t e = SECTS(block + 1); - if(s > nblocks - 1) - s = nblocks - 1; - if(e > nblocks - 1) - e = nblocks - 1; + if(nblocks <= s) + return -1; + if(nblocks <= e) + return -1; for(i = 0; i < (e - s); i++) { ret = write_sect(buf, i + s); if(ret < 0) - return BLOCKS(i); + return -1; buf = ((char*) buf + 512); } - return len; + return 0; } -void hd_init(void) { +int hd_init(void) { int i; uint8_t s; uint16_t *buf = (uint16_t*) sbuf; @@ -162,13 +162,13 @@ void hd_init(void) { s = inb(0x1F7); if(!s) { printk("[hd] Master drive not detected on primary bus!\n"); - return; + return -1; } if(s & ST_ERR) { if(!inb(0x1F4) && !inb(0x1F5)) continue; printk("[hd] IDENTIFY command error!\n"); - return; + return -1; } if(s & ST_DRQ && !(s & ST_ERR)) break; @@ -180,8 +180,9 @@ void hd_init(void) { nblocks = *((uint32_t*) &buf[60]); if(!nblocks) { printk("[hd] Drive does not support LBA28 addressing!\n"); - return; + return -1; } printk("[hd] Primary bus master drive initialized! (status: 0x%02x, nsects: 0x%01x)\n", s, nblocks); + return 0; } -- cgit v1.3