diff options
| author | Jake Mannens <jake72360@gmail.com> | 2018-09-09 00:19:12 +1000 |
|---|---|---|
| committer | Jake Mannens <jake72360@gmail.com> | 2018-09-09 00:19:12 +1000 |
| commit | 02107df3f476c19bb7eaa3c49a368d703898615b (patch) | |
| tree | 7cbace89d150f2f6c39f3ec5766f7263441fea22 /kernel/hd.c | |
| parent | 6d87016287ea76afbdf7e16fb2cf9e4fa20cc0de (diff) | |
Re-ordered system call numbers and definitions into alphabetical order
to make management/maintenance easier.
Defined the structures super_block and m_inode in kernel/fs.h for super
blocks and inodes respectively.
Added the new header file sys/stat.h which contains basic definitions
for inode types and permissions. These definitions will be required by
any functions handling m_inode structures.
Moved the sys_read and sys_write system calls to the filesystem's main
source file at kernel/fs/fs.c.
Added the file kernel/fs/mount.c which will contain the super-blocks
table as well as the function mount_root() which will attempt to mount
the root filesystem during boot. Eventually, this file will be expanded
to include a general-purpose mount function to mount any filesystem as
well as the system call handler for sys_mount.
Seperated block I/O functions into their own subsystem under
kernel/fs/block.c which currently supports two functions; block_read()
and block_write() to read and write blocks from block devices.
Currently, no device can be specified since the primary ATA master drive
is the only possible target. This will change in the future however.
Modified the hard disk driver's read and write functions to use
filesystem blocks rather than sectors as the units of transfer. This is
intended to keep the block I/O subsystem simple by ensuring a uniform
transfer unit is used across all block devices and drivers.
The hard disk driver is no longer initialized during the main boot
procedure. Instead, a call is made to the new function fs_init() which
will setup filesystem tables and structures, call hd_init() to
initialize the disk and finally, attempt to load the super-block for the
root filesystem.
The hard disk driver now stores the disk's size and sanity checks
addresses and sizes in read and write calls against this value.
Diffstat (limited to 'kernel/hd.c')
| -rw-r--r-- | kernel/hd.c | 207 |
1 files changed, 131 insertions, 76 deletions
diff --git a/kernel/hd.c b/kernel/hd.c index 65ebfd7..eab82dc 100644 --- a/kernel/hd.c +++ b/kernel/hd.c @@ -1,7 +1,12 @@ #include <asm/io.h> #include <kernel/con.h> +#include <kernel/fs.h> #include <kernel/kernel.h> #include <stdint.h> +#include <sys/types.h> + +#define SECTS(n) ((n) * (BLOCK_SIZE / 512)) +#define BLOCKS(n) ((n) / (BLOCK_SIZE / 512)) #define ST_ERR 1 #define ST_DRQ 8 @@ -10,53 +15,23 @@ #define ST_RDY 64 #define ST_BSY 128 -/* sector buffer */ +/* status buffer */ static char sbuf[512]; -void hd_init(void) { - int i; - uint8_t s; - uint16_t *buf = (uint16_t*) sbuf; - - /* select the master drive */ - outb(0x1F6, 0xA0); - /* send the IDENTIFY command */ - outb(0x1F7, 0xEC); +static uint32_t nblocks; - while(1) { - s = inb(0x1F7); - if(!s) { - printk("[hd] Master drive not detected on primary bus!\n"); - return; - } - if(s & ST_ERR) { - if(!inb(0x1F4) && !inb(0x1F5)) - continue; - printk("[hd] IDENTIFY command error!\n"); - return; - } - if(s & ST_DRQ && !(s & ST_ERR)) - break; - } - - printk("[hd] Master drive detected on primary bus! (status: 0x%02x)\n", s); - - for(i = 0; i < 256; i++) - buf[i] = inw(0x1F0); -} - -int hd_read(void *buf, uint32_t lba, uint8_t c) { +static int read_sect(void *buf, uint32_t lba) { int n; uint8_t s; uint16_t *p = buf; - if(!c) - return 0; + if(lba > nblocks - 1) + return -1; /* select the master disk on the primary bus */ outb(0x1F6, 0xE0 | ((lba >> 24) & 0xF)); /* set the number of sectors to be read */ - outb(0x1F2, c); + outb(0x1F2, 1); /* set the LBA address for the read operation */ outb(0x1F3, lba); outb(0x1F4, lba >> 8); @@ -64,42 +39,40 @@ int hd_read(void *buf, uint32_t lba, uint8_t c) { /* send the READ command */ outb(0x1F7, 0x20); - while(c--) { - /* wait for the drive */ - while(1) { - /* poll the drive's status */ - s = inb(0x1F7); - if(s & ST_DF) { - printk("[hd] Drive failure!\n"); - panic(); - } - if(s & ST_ERR) - return -1; - if(!(s & ST_BSY) && s & ST_DRQ) - break; + /* wait for the drive */ + while(1) { + /* poll the drive's status */ + s = inb(0x1F7); + if(s & ST_DF) { + printk("[hd] Drive failure!\n"); + panic(); } - - /* buffer is full, copy it's data */ - n = 256; - while(n--) - *(p++) = inw(0x1F0); + if(s & ST_ERR) + return -1; + if(!(s & ST_BSY) && s & ST_DRQ) + break; } + /* buffer is full, copy it's data */ + n = 256; + while(n--) + *(p++) = inw(0x1F0); + return 0; } -int hd_write(void *buf, uint32_t lba, uint8_t c) { +static int write_sect(void *buf, uint32_t lba) { int n; uint8_t s; uint16_t *p = buf; - if(!c) - return 0; + if(lba > nblocks - 1) + return -1; /* select the master disk on the primary bus */ outb(0x1F6, 0xE0 | ((lba >> 24) & 0xF)); /* set the number of sectors to be written */ - outb(0x1F2, c); + outb(0x1F2, 1); /* set the LBA address for the write operation */ outb(0x1F3, lba); outb(0x1F4, lba >> 8); @@ -107,26 +80,108 @@ int hd_write(void *buf, uint32_t lba, uint8_t c) { /* send the WRITE command */ outb(0x1F7, 0x30); - while(c--) { - /* wait for the drive */ - while(1) { - /* poll the drive's status */ - s = inb(0x1F7); - if(s & ST_DF) { - printk("[hd] Drive failure!\n"); - panic(); - } - if(s & ST_ERR) - return -1; - if(!(s & ST_BSY) && s & ST_DRQ) - break; + /* wait for the drive */ + while(1) { + /* poll the drive's status */ + s = inb(0x1F7); + if(s & ST_DF) { + printk("[hd] Drive failure!\n"); + panic(); } - - /* refill the drive's buffer */ - n = 256; - while(n--) - outw(0x1F0, *(p++)); + if(s & ST_ERR) + return -1; + if(!(s & ST_BSY) && s & ST_DRQ) + break; } + /* refill the drive's buffer */ + n = 256; + while(n--) + outw(0x1F0, *(p++)); + return 0; } + +size_t hd_read_block(void *buf, size_t block, size_t len) { + int ret; + size_t i; + uint32_t s = SECTS(block); + uint32_t e = SECTS(block + len); + + if(s > nblocks - 1) + s = nblocks - 1; + if(e > nblocks - 1) + e = nblocks - 1; + + for(i = 0; i < (e - s); i++) { + ret = read_sect(buf, i + s); + + if(ret < 0) + return BLOCKS(i); + + buf = ((char*) buf + 512); + } + + return len; +} + +size_t hd_write_block(void *buf, size_t block, size_t len) { + int ret; + size_t i; + uint32_t s = SECTS(block); + uint32_t e = SECTS(block + len); + + if(s > nblocks - 1) + s = nblocks - 1; + if(e > nblocks - 1) + e = nblocks - 1; + + for(i = 0; i < (e - s); i++) { + ret = write_sect(buf, i + s); + + if(ret < 0) + return BLOCKS(i); + + buf = ((char*) buf + 512); + } + + return len; +} + +void hd_init(void) { + int i; + uint8_t s; + uint16_t *buf = (uint16_t*) sbuf; + + /* select the master drive */ + outb(0x1F6, 0xA0); + /* send the IDENTIFY command */ + outb(0x1F7, 0xEC); + + while(1) { + s = inb(0x1F7); + if(!s) { + printk("[hd] Master drive not detected on primary bus!\n"); + return; + } + if(s & ST_ERR) { + if(!inb(0x1F4) && !inb(0x1F5)) + continue; + printk("[hd] IDENTIFY command error!\n"); + return; + } + if(s & ST_DRQ && !(s & ST_ERR)) + break; + } + + for(i = 0; i < 256; i++) + buf[i] = inw(0x1F0); + + nblocks = *((uint32_t*) &buf[60]); + if(!nblocks) { + printk("[hd] Drive does not support LBA28 addressing!\n"); + return; + } + + printk("[hd] Primary bus master drive initialized! (status: 0x%02x, nblocks: 0x%01x)\n", s, nblocks); +} |
