From a0c2ab8dfe966473026caf0fe7507eb5d2751cea Mon Sep 17 00:00:00 2001 From: Will Sowerbutts Date: Sun, 4 Jan 2015 21:54:01 +0000 Subject: [PATCH] Introduce new "blkdev" layer for 512-byte sector partitioned drives. Hardware drivers are now responsible for the bare mimumum -- identify the storage devices present, figure out how large they are, and provide a function to read/write sectors. The concept of "slices" goes away, instead we will use a separate partition for each file system. The blkdev layer handles PC-style MBR partition tables, both primary and extended partitions, up to a maximum of 15 partitions per drive. The partition numbering is chosen to be compatible with Linux. Storage drivers no longer each require a separate entry in the device switch table. --- Kernel/dev/blkdev.c | 149 ++++++++++++ Kernel/dev/blkdev.h | 24 ++ Kernel/dev/devide.c | 224 ++++-------------- Kernel/dev/devide.h | 3 - Kernel/dev/devsd.c | 316 +++++++++----------------- Kernel/dev/devsd.h | 3 - Kernel/dev/mbr.c | 96 +++++--- Kernel/dev/mbr.h | 2 +- Kernel/include/kernel.h | 2 - Kernel/platform-msx2/Makefile | 2 +- Kernel/platform-msx2/config.h | 2 + Kernel/platform-msx2/devices.c | 7 +- Kernel/platform-msx2/fuzix.lnk | 1 + Kernel/platform-n8vem-mark4/Makefile | 2 +- Kernel/platform-n8vem-mark4/config.h | 2 + Kernel/platform-n8vem-mark4/devices.c | 20 +- Kernel/platform-n8vem-mark4/fuzix.lnk | 1 + Kernel/platform-p112/Makefile | 2 +- Kernel/platform-p112/config.h | 2 + Kernel/platform-p112/devices.c | 20 +- Kernel/platform-p112/fuzix.lnk | 1 + 21 files changed, 430 insertions(+), 451 deletions(-) create mode 100644 Kernel/dev/blkdev.c create mode 100644 Kernel/dev/blkdev.h diff --git a/Kernel/dev/blkdev.c b/Kernel/dev/blkdev.c new file mode 100644 index 00000000..675e6df2 --- /dev/null +++ b/Kernel/dev/blkdev.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include + +/* + Minor numbers + + The kernel identifies our storage devices with an 8-bit minor number. + + The top four bits of the minor identify the drive, allowing a maximum of + sixteen drives. + + The bottom four bits of the minor identify the partition number. Partition + zero addresses "the whole drive", with no translation. Due to limitations + within the kernel only the first 32MB can currently be accessed through + partition zero. + + Partition zero is intended to be used primarily for writing a partition + table to the drive, although it can also be used to store a single Fuzix + filesystem on an unpartitioned disk. + + Partitions 1 through 15 are identified by reading a PC-style MBR partition + table from the drive. The first four partitions are always the primary + partitions on the drive, the remainder are logical partitions stored within + an extended partition. + + To create the required device nodes, use: + + mknod /dev/hda 60660 0 + mknod /dev/hdb 60660 16 + mknod /dev/hdc 60660 32 + mknod /dev/hdd 60660 48 + ... (etc) ... + mknod /dev/hdp 60660 240 + + mknod /dev/hda1 60660 1 + mknod /dev/hda2 60660 2 + mknod /dev/hda3 60660 3 + ... (etc) ... + mknod /dev/hda15 60660 15 + + mknod /dev/hdb1 60660 17 + mknod /dev/hdb2 60660 18 + mknod /dev/hdb3 60660 19 + ... (etc) ... + mknod /dev/hdb15 60660 31 +*/ + +static blkdev_t blkdev_table[MAX_BLKDEV]; + +int blkdev_open(uint8_t minor, uint16_t flags) +{ + uint8_t drive, partition; + + flags; /* unused */ + + drive = minor >> 4; + partition = minor & 0x0F; + + if(drive < MAX_BLKDEV){ + if(blkdev_table[drive].drive_lba_count && (partition == 0 || blkdev_table[drive].lba_count[partition-1])) + return 0; /* that is a valid minor number */ + } + + /* sorry, can't find it */ + udata.u_error = ENODEV; + return -1; +} + +static int blkdev_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + void *target; + uint32_t lba; + uint8_t partition; + blkdev_t *blk; + + /* we trust that blkdev_open() has already verified that this minor number is valid */ + blk = &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; + + if(partition == 0){ + /* partition 0 is the whole disk and requires no translation */ + if(lba >= blk->drive_lba_count) + goto xferfail; + }else{ + /* partitions 1+ require us to add in an offset */ + if(lba >= blk->lba_count[partition-1]) + goto xferfail; + + lba += blk->lba_first[partition-1]; + } + + if(blk->transfer(blk->drive_number, lba, target, is_read)) + return 1; /* 10/10, would transfer sectors again */ + +xferfail: + udata.u_error = EIO; + return -1; +} + +int blkdev_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; /* not used */ + return blkdev_transfer(minor, true, rawflag); +} + +int blkdev_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; /* not used */ + return blkdev_transfer(minor, false, rawflag); +} + +void blkdev_add(transfer_function_t transfer, uint8_t drive_number, uint32_t lba_count) +{ + char letter; + blkdev_t *blk = NULL; + + letter = 'a'; + blk = &blkdev_table[0]; + + /* find an empty slot */ + while(blk <= &blkdev_table[MAX_BLKDEV-1]){ + if(blk->drive_lba_count == 0){ + blk->drive_lba_count = lba_count; + blk->drive_number = drive_number; + blk->transfer = transfer; + + /* now we parse the partition table; might need a hook for platforms to + parse their platform-specific partition table first? eg P112 has its + own partitioning scheme */ + kprintf("hd%c: ", letter); + mbr_parse(blk, letter); + kputchar('\n'); + return; + } + blk++; + letter++; + } + + kputs("blkdev: full!\n"); +} diff --git a/Kernel/dev/blkdev.h b/Kernel/dev/blkdev.h new file mode 100644 index 00000000..f9acbaee --- /dev/null +++ b/Kernel/dev/blkdev.h @@ -0,0 +1,24 @@ +#ifndef __BLKDEV_DOT_H__ +#define __BLKDEV_DOT_H__ + +/* 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); + +/* public interface */ +void blkdev_add(transfer_function_t transfer, uint8_t drive_number, uint32_t lba_count); +int blkdev_open(uint8_t minor, uint16_t flags); +int blkdev_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int blkdev_write(uint8_t minor, uint8_t rawflag, uint8_t flag); + +/* the following details should be required only by partition parsing code */ +#define MAX_PARTITIONS 15 /* must be at least 4, at most 15 */ +typedef struct { + uint32_t drive_lba_count; /* count of sectors on raw disk device */ + uint8_t drive_number; /* driver's drive number */ + 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 */ + transfer_function_t transfer; /* function to read and write sectors */ +} blkdev_t; + +#endif diff --git a/Kernel/dev/devide.c b/Kernel/dev/devide.c index 49d0e4f0..ced4c893 100644 --- a/Kernel/dev/devide.c +++ b/Kernel/dev/devide.c @@ -3,75 +3,18 @@ /* 2014-11-02 Will Sowerbutts (unreleased UZI-mark4) */ /* 2014-12-22 WRS ported to Fuzix */ /* 2014-12-25 WRS updated to also support P112 GIDE */ +/* 2015-01-04 WRS updated to new blkdev API */ /*-----------------------------------------------------------------------*/ -/* Minor numbers - - The kernel identifies our storage devices with an 8-bit minor number. - - The top two bits of the minor identify the drive, allowing a maximum of four - drives, the current hardware supports only two but future controllers may - support more. - - The bottom six bits of the minor identify the slice number. Slice 0 - addresses "the whole drive", with no translation. Due to limitations within - the kernel only the first 32MB can currently be accessed through slice 0. - - Slice 0 is intended to be used primarily for writing a partition table to - the drive, although it can also be used to store a single Fuzix filesystem - on an unpartitioned disk. - - Slices 1+ are stored in a partition on the drive. The partition is stored in - a PC-style MBR partition table and must be a primary partition of type 0x5A. - Only the first suitable partition is found. Multiple filesystems are stored - in this partition by dividing it into 32MB slices. - - To create the required device nodes, use: - - mknod /dev/hda 60660 0 - mknod /dev/hdb 60660 64 - mknod /dev/hdc 60660 128 - mknod /dev/hdd 60660 192 - - mknod /dev/hda1 60660 1 - mknod /dev/hda2 60660 2 - mknod /dev/hda3 60660 3 - ... - mknod /dev/hda63 60660 63 - - mknod /dev/hdb1 60660 65 - mknod /dev/hdb2 60660 66 - mknod /dev/hdb3 60660 67 - ... - mknod /dev/hdb63 60660 127 - - mknod /dev/hdc1 60660 129 - mknod /dev/hdc2 60660 130 - mknod /dev/hdc3 60660 131 - ... - mknod /dev/hdc63 60660 191 - - mknod /dev/hdd1 60660 193 - mknod /dev/hdd2 60660 194 - mknod /dev/hdd3 60660 195 - ... - mknod /dev/hdd63 60660 255 -*/ - #include #include #include #include #include #include -#include +#include #define DRIVE_COUNT 2 /* range 1 -- 4 */ -#define MAX_SLICES 63 - -static uint8_t ide_drives_present; /* bitmap */ -static uint32_t ide_partition_start[DRIVE_COUNT]; -static uint8_t ide_slice_count[DRIVE_COUNT]; #ifdef IDE_REG_ALTSTATUS __sfr __at IDE_REG_ALTSTATUS ide_reg_altstatus; @@ -127,16 +70,6 @@ static void devide_write_data(void *buffer, uint8_t ioport) __naked __endasm; } -static void devide_delay(void) -{ - timer_t timeout; - - timeout = set_timer_ms(25); - - while(!timer_expired(timeout)) - platform_idle(); -} - static bool devide_wait(uint8_t bits) { uint8_t status; @@ -162,122 +95,71 @@ static bool devide_wait(uint8_t bits) }; } -static bool devide_read_sector(uint8_t *buffer) -{ - if(!devide_wait(IDE_STATUS_DATAREQUEST)) - return false; - - devide_read_data(buffer, IDE_REG_DATA); - - return true; -} - -static bool devide_write_sector(uint8_t *buffer) +static bool devide_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, bool read_notwrite) { - if(!devide_wait(IDE_STATUS_DATAREQUEST)) - return false; - - devide_write_data(buffer, IDE_REG_DATA); - - if(!devide_wait(IDE_STATUS_READY)) - return false; - - return true; -} - -static int devide_transfer(uint8_t minor, bool is_read, uint8_t rawflag) -{ - uint8_t *target, *p; - uint32_t lba; - uint8_t drive; - - drive = minor >> 6; - minor = minor & 0x3F; - - if(rawflag == 0) { - target = udata.u_buf->bf_data; - lba = udata.u_buf->bf_blk; - }else - goto xferfail; - - /* minor 0 is the whole disk and requires no translation */ - if(minor > 0){ - /* minor 1+ are slices located within the partition */ - lba += (ide_partition_start[drive]); - lba += ((uint32_t)(minor-1) << SLICE_SIZE_LOG2_SECTORS); - } - #if 0 ide_reg_lba_3 = ((lba >> 24) & 0xF) | ((drive == 0) ? 0xE0 : 0xF0); // select drive, start loading LBA ide_reg_lba_2 = (lba >> 16); ide_reg_lba_1 = (lba >> 8); ide_reg_lba_0 = lba; -#else +#else /* sdcc sadly unable to figure this out for itself yet */ - p = (uint8_t *)&lba; + uint8_t *p = (uint8_t *)&lba; ide_reg_lba_3 = (p[3] & 0x0F) | ((drive == 0) ? 0xE0 : 0xF0); // select drive, start loading LBA ide_reg_lba_2 = p[2]; ide_reg_lba_1 = p[1]; ide_reg_lba_0 = p[0]; #endif - ide_reg_sec_count = 1; - - if(is_read){ - ide_reg_command = IDE_CMD_READ_SECTOR; - if(!devide_read_sector(target)) - goto xferfail; - }else{ - ide_reg_command = IDE_CMD_WRITE_SECTOR; - if(!devide_write_sector(target)) - goto xferfail; - } - return 1; -xferfail: - udata.u_error = EIO; - return -1; -} + if(!devide_wait(IDE_STATUS_READY)) + return false; -int devide_open(uint8_t minor, uint16_t flags) -{ - uint8_t drive; - flags; /* not used */ + ide_reg_sec_count = 1; + ide_reg_command = read_notwrite ? IDE_CMD_READ_SECTOR : IDE_CMD_WRITE_SECTOR; - drive = minor >> 6; - minor = minor & 0x3F; + if(!devide_wait(IDE_STATUS_DATAREQUEST)) + return false; - if(ide_drives_present & (1 << drive) && (minor == 0 || minor < ide_slice_count[drive])) - return 0; + if(read_notwrite) + devide_read_data(buffer, IDE_REG_DATA); + else{ + devide_write_data(buffer, IDE_REG_DATA); + if(!devide_wait(IDE_STATUS_READY)) + return false; + } - udata.u_error = ENODEV; - return -1; + return true; } -int devide_read(uint8_t minor, uint8_t rawflag, uint8_t flag) -{ - flag; /* not used */ - return devide_transfer(minor, true, rawflag); -} +/****************************************************************************/ +/* Code below this point used only once, at startup, so we want it to live */ +/* in the DISCARD segment. sdcc only allows us to specify one segment for */ +/* each source file. This "solution" is a bit (well, very) hacky ... */ +/****************************************************************************/ +static void DISCARDSEG(void) __naked { __asm .area _DISCARD __endasm; } -int devide_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +static void devide_delay(void) { - flag; /* not used */ - return devide_transfer(minor, false, rawflag); + timer_t timeout; + + timeout = set_timer_ms(25); + + while(!timer_expired(timeout)) + platform_idle(); } -void devide_init_drive(uint8_t drive) +static void devide_init_drive(uint8_t drive) { uint8_t *buffer, select; + uint32_t size; switch(drive){ - case 0: select = 0xE0; break; - case 1: select = 0xF0; break; + case 0: select = 0xE0; break; + case 1: select = 0xF0; break; default: return; } - kprintf("hd%c: ", 'a' + drive); - ide_partition_start[drive] = 0; - ide_slice_count[drive] = 0; + kprintf("IDE drive %d: ", drive); /* Reset depends upon the presence of alt control, which is optional */ #ifdef IDE_REG_CONTROL @@ -303,38 +185,32 @@ void devide_init_drive(uint8_t drive) /* confirm drive has LBA support */ if(!devide_wait(IDE_STATUS_READY)) return; + + /* send identify command */ ide_reg_command = IDE_CMD_IDENTIFY; /* allocate temporary sector buffer memory */ buffer = (uint8_t *)tmpbuf(); - if(!devide_read_sector(buffer)) - goto failout; + if(!devide_wait(IDE_STATUS_DATAREQUEST)) + goto failout; + + devide_read_data(buffer, IDE_REG_DATA); if(!(buffer[99] & 0x02)){ kputs("LBA unsupported.\n"); goto failout; } - /* read first sector (looking for the partition table) */ - if(!devide_wait(IDE_STATUS_READY)) - goto failout; - - ide_reg_devhead = select; - ide_reg_lba_2 = 0; - ide_reg_lba_1 = 0; - ide_reg_lba_0 = 0; - ide_reg_sec_count = 1; - ide_reg_command = IDE_CMD_READ_SECTOR; + /* read out the drive's sector count */ + size = *((uint32_t*)&buffer[120]); - if(!devide_read_sector(buffer)) - goto failout; - - /* if we get this far the drive is apparently present and functioning */ - ide_drives_present |= (1 << drive); + /* done with our temporary memory */ + brelse((bufptr)buffer); - parse_partition_table(buffer, &ide_partition_start[drive], &ide_slice_count[drive], MAX_SLICES); + blkdev_add(devide_transfer_sector, drive, size); + return; failout: brelse((bufptr)buffer); } @@ -343,8 +219,6 @@ void devide_init(void) { uint8_t d; - ide_drives_present = 0; - for(d=0; d #include #include #include #include #include -#include -#include "config.h" - -#define MAX_SLICES 63 +#include -/* keep track of current card type, UZI partition offset */ -static uint8_t sd_drive_present; /* bitmap */ -static uint8_t sd_card_type[SD_DRIVE_COUNT]; -static uint32_t sd_partition_start[SD_DRIVE_COUNT]; -static uint8_t sd_slice_count[SD_DRIVE_COUNT]; +static uint8_t sd_card_type[SD_DRIVE_COUNT]; /* internal functions */ static void sd_init_drive(uint8_t drive); -static int sd_readwrite(uint8_t minor, uint8_t rawflag, bool do_write); static int sd_spi_init(uint8_t drive); static void sd_spi_release(uint8_t drive); static int sd_spi_wait_ready(uint8_t drive); @@ -37,178 +28,36 @@ static bool sd_spi_transmit_sector(uint8_t drive, void *ptr, unsigned int length static bool sd_spi_receive_sector(uint8_t drive, void *ptr, unsigned int length); static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg); static uint32_t sd_get_size_sectors(uint8_t drive); -static bool sd_read_sector(uint8_t drive, void *ptr, uint32_t lba); -static bool sd_write_sector(uint8_t drive, void *ptr, uint32_t lba); - -int devsd_open(uint8_t minor, uint16_t flags) -{ - uint8_t drive; - flags; /* not used */ - - drive = minor >> 6; - minor = minor & 0x3F; - - if(sd_drive_present & (1 << drive) && (minor == 0 || minor < sd_slice_count[drive])) - return 0; - - udata.u_error = ENODEV; - return -1; -} - -int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) -{ - flag; /* not used */ - return sd_readwrite(minor, rawflag, false); -} - -int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) -{ - flag; /* not used */ - return sd_readwrite(minor, rawflag, true); -} -void devsd_init(void) +static bool devsd_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, bool read_notwrite) { - uint8_t d; + uint8_t attempt; + bool success; - sd_drive_present = 0; - for(d=0; d> 6; - minor = minor & 0x3F; + for(attempt=0; attempt<8; attempt++){ + if(sd_send_command(drive, read_notwrite ? CMD17 : CMD24, lba) == 0){ + if(read_notwrite) + success = sd_spi_receive_sector(drive, buffer, 512); + else + success = sd_spi_transmit_sector(drive, buffer, 512); + }else + success = false; - if(rawflag == 0){ - target = udata.u_buf->bf_data; + sd_spi_release(drive); - for(attempt=0; attempt<5; attempt++){ - lba = udata.u_buf->bf_blk; + if(success) + return 1; - /* minor 0 is the whole drive, without translation */ - if(minor > 0){ - lba += sd_partition_start[drive]; - lba += ((unsigned long)(minor-1) << SLICE_SIZE_LOG2_SECTORS); - } - if(do_write){ - if(sd_write_sector(drive, udata.u_buf->bf_data, lba)) - return 1; - }else{ - if(sd_read_sector(drive, udata.u_buf->bf_data, lba)) - return 1; - } - kputs("sd: failed, retrying.\n"); - } + kputs("sd: failed, retrying.\n"); } udata.u_error = EIO; return -1; } -static void sd_init_drive(uint8_t drive) -{ - uint32_t sector_count; - unsigned char *sector; - - sd_partition_start[drive] = 0; - sd_slice_count[drive] = 0; - - kprintf("sd%c: ", 'a'+drive); - sd_card_type[drive] = sd_spi_init(drive); - - if(!(sd_card_type[drive] & (~CT_BLOCK))){ - kprintf("no card found\n"); - return; - } - - /* read and compute card size */ - sector_count = sd_get_size_sectors(drive); - if(!sector_count){ - kputs("weird card\n"); - return; - } - - /* read partition table, locate the UZI partition */ - sector = (unsigned char*)tmpbuf(); - - if(!sd_read_sector(drive, sector, 0)){ - kprintf("failed to read partition table\n"); - goto failout; - } - - /* if we get this far the drive is probably ok */ - sd_drive_present |= (1 << drive); - - /* look for our partition */ - parse_partition_table(sector, &sd_partition_start[drive], &sd_slice_count[drive], MAX_SLICES); - -failout: - brelse((bufptr)sector); -} - -static int sd_spi_init(uint8_t drive) -{ - unsigned char n, cmd, card_type, ocr[4]; - timer_t timer; - - sd_spi_raise_cs(drive); - - sd_spi_clock(drive, false); - for (n = 20; n; n--) - sd_spi_receive_byte(drive); /* 160 dummy clocks */ - - card_type = 0; - /* Enter Idle state */ - if (sd_send_command(drive, CMD0, 0) == 1) { - /* initialisation timeout 1 second */ - timer = set_timer_sec(1); - if (sd_send_command(drive, CMD8, (uint32_t)0x1AA) == 1) { /* SDHC */ - /* Get trailing return value of R7 resp */ - for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive); - /* The card can work at vdd range of 2.7-3.6V */ - if (ocr[2] == 0x01 && ocr[3] == 0xAA) { - /* Wait for leaving idle state (ACMD41 with HCS bit) */ - while(!timer_expired(timer) && sd_send_command(drive, ACMD41, (uint32_t)1 << 30)); - /* Check CCS bit in the OCR */ - if (!timer_expired(timer) && sd_send_command(drive, CMD58, 0) == 0) { - for (n = 0; n < 4; n++) ocr[n] = sd_spi_receive_byte(drive); - card_type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ - } - } - } else { /* SDSC or MMC */ - if (sd_send_command(drive, ACMD41, 0) <= 1) { - /* SDv1 */ - card_type = CT_SD1; - cmd = ACMD41; - } else { - /* MMCv3 */ - card_type = CT_MMC; - cmd = CMD1; - } - /* Wait for leaving idle state */ - while(!timer_expired(timer) && sd_send_command(drive, cmd, 0)); - /* Set R/W block length to 512 */ - if(timer_expired || sd_send_command(drive, CMD16, 512) != 0) - card_type = 0; - } - } - sd_spi_release(drive); - - if (card_type) { - sd_spi_clock(drive, true); /* up to 20MHz should be OK */ - return card_type; - } - - return 0; /* failed */ -} - static void sd_spi_release(uint8_t drive) { sd_spi_raise_cs(drive); @@ -320,54 +169,113 @@ static int sd_send_command(uint8_t drive, unsigned char cmd, uint32_t arg) return res; /* Return with the response value */ } -static uint32_t sd_get_size_sectors(uint8_t drive) +/****************************************************************************/ +/* Code below this point used only once, at startup, so we want it to live */ +/* in the DISCARD segment. sdcc only allows us to specify one segment for */ +/* each source file. This "solution" is a bit (well, very) hacky ... */ +/****************************************************************************/ +static void DISCARDSEG(void) __naked { __asm .area _DISCARD __endasm; } + +void devsd_init(void) { - unsigned char csd[16], n; - uint32_t sectors = 0; + uint8_t d; - if(sd_send_command(drive, CMD9, 0) == 0 && sd_spi_receive_sector(drive, csd, 16)){ - if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ - sectors = ((uint32_t)csd[9] + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10; - } else { /* SDC ver 1.XX or MMC*/ - n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; - sectors = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) + ((unsigned int)(csd[6] & 3) << 10) + 1; - sectors = sectors << (n - 9); - } - } - sd_spi_release(drive); - return sectors; + for(d=0; d> 6) == 1) { /* SDC ver 2.00 */ + sectors = ((uint32_t)csd[9] + (uint32_t)((unsigned int)csd[8] << 8) + 1) << 10; + } else { /* SDC ver 1.XX or MMC*/ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + sectors = (csd[8] >> 6) + ((unsigned int)csd[7] << 2) + ((unsigned int)(csd[6] & 3) << 10) + 1; + sectors = sectors << (n - 9); + } + } + sd_spi_release(drive); + return sectors; } diff --git a/Kernel/dev/devsd.h b/Kernel/dev/devsd.h index 5ab232b5..840015b7 100644 --- a/Kernel/dev/devsd.h +++ b/Kernel/dev/devsd.h @@ -15,9 +15,6 @@ /* public interface */ -int devsd_open(uint8_t minor, uint16_t flags); -int devsd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); -int devsd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); void devsd_init(void); /* platform-specific SPI functions */ diff --git a/Kernel/dev/mbr.c b/Kernel/dev/mbr.c index 9985b642..1a90c805 100644 --- a/Kernel/dev/mbr.c +++ b/Kernel/dev/mbr.c @@ -1,46 +1,80 @@ #include #include #include +#include typedef struct { - unsigned char status; - unsigned char chs_first[3]; - unsigned char type; - unsigned char chs_last[3]; - unsigned long lba_first; - unsigned long lba_count; + uint8_t status; + uint8_t chs_first[3]; + uint8_t type; + uint8_t chs_last[3]; + uint32_t lba_first; + uint32_t lba_count; } partition_table_entry_t; #define MBR_ENTRY_COUNT 4 +#define MBR_SIGNATURE 0xAA55 typedef struct { - unsigned char bootcode[446]; + uint8_t bootcode[446]; partition_table_entry_t partition[MBR_ENTRY_COUNT]; - unsigned int signature; -} master_boot_record_t; + uint16_t signature; +} boot_record_t; -void parse_partition_table(void *buffer, uint32_t *first_lba, uint8_t *slice_count, uint8_t max_slices) +void mbr_parse(blkdev_t *blk, char letter) { - master_boot_record_t *mbr = (master_boot_record_t*)buffer; - uint16_t slices = 0; + boot_record_t *br; uint8_t i; + uint32_t lba = 0, ep_offset = 0, br_offset = 0; + uint8_t next = 0; - /* check for MBR table signature */ - if(mbr->signature != 0xaa55){ - kputs("no partition table\n"); - return; - } - - /* look for a fuzix partition (type 0x5A) */ - for(i=0; ipartition[i].type == 0x5A){ - *first_lba = mbr->partition[i].lba_first; - slices = mbr->partition[i].lba_count >> SLICE_SIZE_LOG2_SECTORS; - if(slices > max_slices) - slices = max_slices; - *slice_count = slices; - break; - } - } - - kprintf("%d slices\n", slices); + /* allocate temporary memory */ + br = (boot_record_t *)tmpbuf(); + + do{ + if(!blk->transfer(blk->drive_number, lba, br, true) || br->signature != MBR_SIGNATURE) + break; + + if(next < 4 && lba != 0){ + /* we just loaded the first extended boot record */ + ep_offset = lba; + next = 4; + kputs("< "); + } + + br_offset = lba; + lba = 0; + + for(i=0; ipartition[i].type){ + case 0: + break; + case 0x05: + case 0x0f: + case 0x85: + /* 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 + br->partition[i].lba_first; + if(next >= 4) + break; + /* we include all primary partitions but we deliberately knobble the size in + order to prevent catastrophic accidents */ + br->partition[i].lba_count = 2; + /* fall through */ + default: + /* Regular partition: In EBRs these are relative to the EBR (not the disk, nor + the extended partition) */ + blk->lba_first[next] = br_offset + br->partition[i].lba_first; + blk->lba_count[next] = br->partition[i].lba_count; + kprintf("hd%c%d ", letter, 1+next); + next++; + } + } + }while(lba); + + if(next >= 4) + kputs("> "); + + /* release temporary memory */ + brelse((bufptr)br); } diff --git a/Kernel/dev/mbr.h b/Kernel/dev/mbr.h index 1bb5c016..82861608 100644 --- a/Kernel/dev/mbr.h +++ b/Kernel/dev/mbr.h @@ -1,6 +1,6 @@ #ifndef __MBR_DOT_H__ #define __MBR_DOT_H__ -void parse_partition_table(void *buffer, uint32_t *first_lba, uint8_t *slice_count, uint8_t max_slices); +void mbr_parse(blkdev_t *blk, char letter); #endif diff --git a/Kernel/include/kernel.h b/Kernel/include/kernel.h index 601b9796..30c8df37 100644 --- a/Kernel/include/kernel.h +++ b/Kernel/include/kernel.h @@ -88,8 +88,6 @@ typedef uint16_t blkno_t; /* Can have 65536 512-byte blocks in filesystem */ #define BLKSHIFT 9 #define BLKMASK 511 -#define SLICE_SIZE_LOG2_SECTORS 16 /* 32MB slices */ - /* FIXME: if we could split the data and the header we could keep blocks outside of our kernel data (as ELKS does) which would be a win, but need some more care on copies, block indexes and directory ops */ diff --git a/Kernel/platform-msx2/Makefile b/Kernel/platform-msx2/Makefile index 7f22686b..58670708 100644 --- a/Kernel/platform-msx2/Makefile +++ b/Kernel/platform-msx2/Makefile @@ -1,5 +1,5 @@ -CSRCS = ../dev/devsd.c ../dev/mbr.c devfd.c devhd.c devlpr.c +CSRCS = ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c devfd.c devhd.c devlpr.c CSRCS += devices.c main.c devtty.c DSRCS = devmegasd.c ASRCS = msx2.s crt0.s vdp.s diff --git a/Kernel/platform-msx2/config.h b/Kernel/platform-msx2/config.h index ae555496..05543155 100644 --- a/Kernel/platform-msx2/config.h +++ b/Kernel/platform-msx2/config.h @@ -43,3 +43,5 @@ #define DEVICE_SD #define SD_DRIVE_COUNT 1 + +#define MAX_BLKDEV 1 /* Single SD drive */ diff --git a/Kernel/platform-msx2/devices.c b/Kernel/platform-msx2/devices.c index 1fd53bf6..98bf22cc 100644 --- a/Kernel/platform-msx2/devices.c +++ b/Kernel/platform-msx2/devices.c @@ -8,7 +8,8 @@ #include #include #include -#include <../dev/devsd.h> +#include +#include extern int megasd_probe(); @@ -16,8 +17,8 @@ struct devsw dev_tab[] = /* The device driver switch table */ { /* 0: /dev/fd Floppy disc block devices */ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, - /* 1: /dev/sd MegaSD Interface */ - { devsd_open, no_close, devsd_read, devsd_write, no_ioctl }, + /* 1: /dev/hd MegaSD Interface */ + { blkdev_open, no_close, blkdev_read, blkdev_write, no_ioctl }, /* 2: /dev/tty TTY devices */ { tty_open, tty_close, tty_read, tty_write, vt_ioctl }, /* 3: /dev/lpr Printer devices */ diff --git a/Kernel/platform-msx2/fuzix.lnk b/Kernel/platform-msx2/fuzix.lnk index 3d1bad0c..7ca30f29 100644 --- a/Kernel/platform-msx2/fuzix.lnk +++ b/Kernel/platform-msx2/fuzix.lnk @@ -36,6 +36,7 @@ vt.rel devsys.rel usermem.rel usermem_std-z80.rel +platform-msx2/blkdev.rel platform-msx2/devsd.rel platform-msx2/devmegasd.rel platform-msx2/mbr.rel diff --git a/Kernel/platform-n8vem-mark4/Makefile b/Kernel/platform-n8vem-mark4/Makefile index db10613b..84942f99 100644 --- a/Kernel/platform-n8vem-mark4/Makefile +++ b/Kernel/platform-n8vem-mark4/Makefile @@ -1,5 +1,5 @@ CSRCS += devices.c main.c devtty.c devsdspi.c -DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/mbr.c ../dev/ds1302.c +DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c ../dev/ds1302.c ASRCS = crt0.s z180.s commonmem.s mark4.s ds1302-mark4.s AOBJS = $(ASRCS:.s=.rel) diff --git a/Kernel/platform-n8vem-mark4/config.h b/Kernel/platform-n8vem-mark4/config.h index 28a47cf2..5a85b73b 100644 --- a/Kernel/platform-n8vem-mark4/config.h +++ b/Kernel/platform-n8vem-mark4/config.h @@ -50,6 +50,8 @@ #define Z180_IO_BASE 0x40 #define MARK4_IO_BASE 0x80 +#define MAX_BLKDEV 3 /* 2 IDE drives, 1 SD drive */ + #define DEVICE_IDE /* enable if IDE interface present */ #define IDE_REG_BASE MARK4_IO_BASE #define IDE_8BIT_ONLY diff --git a/Kernel/platform-n8vem-mark4/devices.c b/Kernel/platform-n8vem-mark4/devices.c index c1d72b1f..e5c493de 100644 --- a/Kernel/platform-n8vem-mark4/devices.c +++ b/Kernel/platform-n8vem-mark4/devices.c @@ -6,23 +6,17 @@ #include #include #include +#include #include struct devsw dev_tab[] = /* The device driver switch table */ { -// minor open close read write ioctl -// ----------------------------------------------------------------- - /* 0: /dev/hd IDE-8 interface */ - { devide_open, no_close, devide_read, devide_write, no_ioctl }, - /* 1: /dev/sd SD interface */ - { devsd_open, no_close, devsd_read, devsd_write, no_ioctl }, - /* 2: /dev/tty serial ports */ - { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, - /* 3: /dev/lpr Unused slot (pad to keep system devices at index 4) */ - { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, - /* 4: /dev/mem etc System devices (one offs) */ - { no_open, no_close, sys_read, sys_write, sys_ioctl }, - /* Pack to 7 with nxio if adding private devices and start at 8 */ +/* open close read write ioctl */ + { blkdev_open, no_close, blkdev_read, blkdev_write, no_ioctl }, /* 0: /dev/hd -- standard block device interface */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 1: unused slot */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, /* 2: /dev/tty -- serial ports */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 3: unused slot */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, /* 4: /dev/mem etc System devices (one offs) */ }; bool validdev(uint16_t dev) diff --git a/Kernel/platform-n8vem-mark4/fuzix.lnk b/Kernel/platform-n8vem-mark4/fuzix.lnk index 2b4e8012..dcce1857 100644 --- a/Kernel/platform-n8vem-mark4/fuzix.lnk +++ b/Kernel/platform-n8vem-mark4/fuzix.lnk @@ -36,6 +36,7 @@ platform-n8vem-mark4/devide.rel platform-n8vem-mark4/devsd.rel platform-n8vem-mark4/devsdspi.rel platform-n8vem-mark4/mbr.rel +platform-n8vem-mark4/blkdev.rel platform-n8vem-mark4/ds1302.rel platform-n8vem-mark4/ds1302-mark4.rel -e diff --git a/Kernel/platform-p112/Makefile b/Kernel/platform-p112/Makefile index c1328197..9f195fd4 100644 --- a/Kernel/platform-p112/Makefile +++ b/Kernel/platform-p112/Makefile @@ -1,5 +1,5 @@ CSRCS += devices.c main.c devtty.c -DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/ds1302.c +DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c ../dev/ds1302.c ASRCS = crt0.s z180.s commonmem.s p112.s ds1302-p112.s AOBJS = $(ASRCS:.s=.rel) diff --git a/Kernel/platform-p112/config.h b/Kernel/platform-p112/config.h index dc464760..f664412e 100644 --- a/Kernel/platform-p112/config.h +++ b/Kernel/platform-p112/config.h @@ -49,6 +49,8 @@ /* Hardware parameters */ #define Z180_IO_BASE 0x00 +#define MAX_BLKDEV 2 /* 2 IDE drives */ + #define DEVICE_IDE /* enable if IDE interface present */ #define IDE_REG_BASE 0x50 #define IDE_REG_CS0_FIRST diff --git a/Kernel/platform-p112/devices.c b/Kernel/platform-p112/devices.c index 9f69e361..f36711c1 100644 --- a/Kernel/platform-p112/devices.c +++ b/Kernel/platform-p112/devices.c @@ -5,23 +5,17 @@ #include #include #include +#include #include struct devsw dev_tab[] = /* The device driver switch table */ { -// minor open close read write ioctl -// ----------------------------------------------------------------- - /* 0: /dev/hd IDE-8 interface */ - { devide_open, no_close, devide_read, devide_write, no_ioctl }, - /* 1: /dev/sd SD interface */ - { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, - /* 2: /dev/tty serial ports */ - { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, - /* 3: /dev/lpr Unused slot (pad to keep system devices at index 4) */ - { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, - /* 4: /dev/mem etc System devices (one offs) */ - { no_open, no_close, sys_read, sys_write, sys_ioctl }, - /* Pack to 7 with nxio if adding private devices and start at 8 */ +/* open close read write ioctl */ + { blkdev_open, no_close, blkdev_read, blkdev_write, no_ioctl }, /* 0: /dev/hd -- standard block device interface */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 1: unused slot */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, /* 2: /dev/tty -- serial ports */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 3: unused slot */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, /* 4: /dev/mem etc System devices (one offs) */ }; bool validdev(uint16_t dev) diff --git a/Kernel/platform-p112/fuzix.lnk b/Kernel/platform-p112/fuzix.lnk index 94a4f485..00fe4cfc 100644 --- a/Kernel/platform-p112/fuzix.lnk +++ b/Kernel/platform-p112/fuzix.lnk @@ -33,6 +33,7 @@ swap.rel devsys.rel platform-p112/devtty.rel platform-p112/devide.rel +platform-p112/blkdev.rel platform-p112/mbr.rel platform-p112/ds1302.rel platform-p112/ds1302-p112.rel -- 2.34.1