diff options
| author | Jake Mannens <jake72360@gmail.com> | 2018-12-23 17:22:14 +1100 |
|---|---|---|
| committer | Jake Mannens <jake72360@gmail.com> | 2018-12-23 17:22:14 +1100 |
| commit | ce91afe04bd24fe9277a3f7b68ddf0654f1634ac (patch) | |
| tree | 428ca2ee2ca73e5c24c45c724178d2cdc9320c4d /kernel/fs/buffer.c | |
| parent | a8a4f0710210ed91097a30fc26308c50be73d4de (diff) | |
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.
Diffstat (limited to 'kernel/fs/buffer.c')
| -rw-r--r-- | kernel/fs/buffer.c | 82 |
1 files changed, 82 insertions, 0 deletions
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 <kernel/con.h> +#include <kernel/fs.h> +#include <stdint.h> +#include <string.h> + +/* 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; +} |
