diff options
author | Matt Fleming <matt.fleming@intel.com> | 2012-03-28 13:57:54 +0100 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2012-03-28 14:38:34 +0100 |
commit | 0376c8d3b618c53914c44dd0c90b03e1f66c4bdc (patch) | |
tree | c68df1fa761d7beed1d35669be20b2005a3e60a1 | |
parent | 5b138643e73cd2ffc7edab1aea197c200c46f9d4 (diff) | |
download | syslinux-0376c8d3b618c53914c44dd0c90b03e1f66c4bdc.tar.gz syslinux-0376c8d3b618c53914c44dd0c90b03e1f66c4bdc.tar.xz syslinux-0376c8d3b618c53914c44dd0c90b03e1f66c4bdc.zip |
firmware, diskio: Create struct disk_private
We need a way of passing firmware-specific information to the disk I/O
subsystem. Split the BIOS code into diskio_bios.c so that we don't
include any disk BIOS symbols in the EFI executable. This way, the
code in core/fs/diskio.c is firmware independent.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r-- | com32/include/syslinux/firmware.h | 2 | ||||
-rw-r--r-- | core/fs/diskio.c | 388 | ||||
-rw-r--r-- | core/fs/diskio_bios.c | 398 | ||||
-rw-r--r-- | core/fs/fs.c | 9 | ||||
-rw-r--r-- | core/include/disk.h | 19 | ||||
-rw-r--r-- | core/include/fs.h | 1 | ||||
-rw-r--r-- | efi/Makefile | 3 | ||||
-rw-r--r-- | efi/diskio.c | 17 | ||||
-rw-r--r-- | efi/main.c | 4 |
9 files changed, 430 insertions, 411 deletions
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h index e23a1b3d..ceb006fe 100644 --- a/com32/include/syslinux/firmware.h +++ b/com32/include/syslinux/firmware.h @@ -24,6 +24,8 @@ struct adv_ops { int (*write)(void); }; +struct disk_private; + struct firmware { void (*init)(void); int (*scan_memory)(scan_memory_callback_t, void *); diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 1644eae4..9e1f63fd 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -10,288 +10,6 @@ #include <syslinux/firmware.h> -#define RETRY_COUNT 6 - -static inline sector_t chs_max(const struct disk *disk) -{ - return (sector_t)disk->secpercyl << 10; -} - -static int chs_rdwr_sectors(struct disk *disk, void *buf, - sector_t lba, size_t count, bool is_write) -{ - char *ptr = buf; - char *tptr; - size_t chunk, freeseg; - int sector_shift = disk->sector_shift; - uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */ - uint32_t t; - uint32_t c, h, s; - com32sys_t ireg, oreg; - size_t done = 0; - size_t bytes; - int retry; - uint32_t maxtransfer = disk->maxtransfer; - - if (lba + disk->part_start >= chs_max(disk)) - return 0; /* Impossible CHS request */ - - memset(&ireg, 0, sizeof ireg); - - ireg.eax.b[1] = 0x02 + is_write; - ireg.edx.b[0] = disk->disk_number; - - while (count) { - chunk = count; - if (chunk > maxtransfer) - chunk = maxtransfer; - - freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; - - if ((size_t)buf <= 0xf0000 && freeseg) { - /* Can do a direct load */ - tptr = ptr; - } else { - /* Either accessing high memory or we're crossing a 64K line */ - tptr = core_xfer_buf; - freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; - } - if (chunk > freeseg) - chunk = freeseg; - - s = xlba % disk->s; - t = xlba / disk->s; - h = t % disk->h; - c = t / disk->h; - - if (chunk > (disk->s - s)) - chunk = disk->s - s; - - bytes = chunk << sector_shift; - - if (tptr != ptr && is_write) - memcpy(tptr, ptr, bytes); - - ireg.eax.b[0] = chunk; - ireg.ecx.b[1] = c; - ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); - ireg.edx.b[1] = h; - ireg.ebx.w[0] = OFFS(tptr); - ireg.es = SEG(tptr); - - retry = RETRY_COUNT; - - for (;;) { - if (c < 1024) { - dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n", - ireg.edx.b[0], chunk, xlba, c, h, s+1, - ireg.es, ireg.ebx.w[0], - (ireg.eax.b[1] & 1) ? "<-" : "->", - ptr); - - __intcall(0x13, &ireg, &oreg); - if (!(oreg.eflags.l & EFLAGS_CF)) - break; - - dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]); - - if (retry--) - continue; - - /* - * For any starting value, this will always end with - * ..., 1, 0 - */ - chunk >>= 1; - if (chunk) { - maxtransfer = chunk; - retry = RETRY_COUNT; - ireg.eax.b[0] = chunk; - continue; - } - } - - printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n", - oreg.eax.w[0], - is_write ? "writing" : "reading", - lba, c, h, s+1); - return done; /* Failure */ - } - - bytes = chunk << sector_shift; - - if (tptr != ptr && !is_write) - memcpy(ptr, tptr, bytes); - - /* If we dropped maxtransfer, it eventually worked, so remember it */ - disk->maxtransfer = maxtransfer; - - ptr += bytes; - xlba += chunk; - count -= chunk; - done += chunk; - } - - return done; -} - -struct edd_rdwr_packet { - uint16_t size; - uint16_t blocks; - far_ptr_t buf; - uint64_t lba; -}; - -static int edd_rdwr_sectors(struct disk *disk, void *buf, - sector_t lba, size_t count, bool is_write) -{ - static __lowmem struct edd_rdwr_packet pkt; - char *ptr = buf; - char *tptr; - size_t chunk, freeseg; - int sector_shift = disk->sector_shift; - com32sys_t ireg, oreg, reset; - size_t done = 0; - size_t bytes; - int retry; - uint32_t maxtransfer = disk->maxtransfer; - - memset(&ireg, 0, sizeof ireg); - - ireg.eax.b[1] = 0x42 + is_write; - ireg.edx.b[0] = disk->disk_number; - ireg.ds = SEG(&pkt); - ireg.esi.w[0] = OFFS(&pkt); - - memset(&reset, 0, sizeof reset); - - lba += disk->part_start; - while (count) { - chunk = count; - if (chunk > maxtransfer) - chunk = maxtransfer; - - freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; - - if ((size_t)ptr <= 0xf0000 && freeseg) { - /* Can do a direct load */ - tptr = ptr; - } else { - /* Either accessing high memory or we're crossing a 64K line */ - tptr = core_xfer_buf; - freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; - } - if (chunk > freeseg) - chunk = freeseg; - - bytes = chunk << sector_shift; - - if (tptr != ptr && is_write) - memcpy(tptr, ptr, bytes); - - retry = RETRY_COUNT; - - for (;;) { - pkt.size = sizeof pkt; - pkt.blocks = chunk; - pkt.buf = FAR_PTR(tptr); - pkt.lba = lba; - - dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n", - ireg.edx.b[0], pkt.blocks, pkt.lba, - pkt.buf.seg, pkt.buf.offs, - (ireg.eax.b[1] & 1) ? "<-" : "->", - ptr); - - __intcall(0x13, &ireg, &oreg); - if (!(oreg.eflags.l & EFLAGS_CF)) - break; - - dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]); - - if (retry--) - continue; - - /* - * Some systems seem to get "stuck" in an error state when - * using EBIOS. Doesn't happen when using CBIOS, which is - * good, since some other systems get timeout failures - * waiting for the floppy disk to spin up. - */ - __intcall(0x13, &reset, NULL); - - /* For any starting value, this will always end with ..., 1, 0 */ - chunk >>= 1; - if (chunk) { - maxtransfer = chunk; - retry = RETRY_COUNT; - continue; - } - - /* - * Total failure. There are systems which identify as - * EDD-capable but aren't; the known such systems return - * error code AH=1 (invalid function), but let's not - * assume that for now. - * - * Try to fall back to CHS. If the LBA is absurd, the - * chs_max() test in chs_rdwr_sectors() will catch it. - */ - done = chs_rdwr_sectors(disk, buf, lba - disk->part_start, - count, is_write); - if (done == (count << sector_shift)) { - /* Successful, assume this is a CHS disk */ - disk->rdwr_sectors = chs_rdwr_sectors; - return done; - } - printf("EDD: Error %04x %s sector %llu\n", - oreg.eax.w[0], - is_write ? "writing" : "reading", - lba); - return done; /* Failure */ - } - - bytes = chunk << sector_shift; - - if (tptr != ptr && !is_write) - memcpy(ptr, tptr, bytes); - - /* If we dropped maxtransfer, it eventually worked, so remember it */ - disk->maxtransfer = maxtransfer; - - ptr += bytes; - lba += chunk; - count -= chunk; - done += chunk; - } - return done; -} - -struct edd_disk_params { - uint16_t len; - uint16_t flags; - uint32_t phys_c; - uint32_t phys_h; - uint32_t phys_s; - uint64_t sectors; - uint16_t sector_size; - far_ptr_t dpte; - uint16_t devpath_key; - uint8_t devpath_len; - uint8_t _pad1[3]; - char bus_type[4]; - char if_type[8]; - uint8_t if_path[8]; - uint8_t dev_path[16]; - uint8_t _pad2; - uint8_t devpath_csum; /* Depends on devpath_len! */ -} __attribute__((packed)); - -static inline bool is_power_of_2(uint32_t x) -{ - return !(x & (x-1)); -} - void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) { int sec_per_block = block_size / disk->sector_size; @@ -299,116 +17,12 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0); } - -struct disk *bios_disk_init(com32sys_t *regs) -{ - static struct disk disk; - static __lowmem struct edd_disk_params edd_params; - com32sys_t ireg, oreg; - uint8_t devno = regs->edx.b[0]; - bool cdrom = regs->edx.b[1]; - sector_t part_start = regs->ecx.l | ((sector_t)regs->ebx.l << 32); - uint16_t bsHeads = regs->esi.w[0]; - uint16_t bsSecPerTrack = regs->edi.w[0]; - uint32_t MaxTransfer = regs->ebp.l; - bool ebios; - int sector_size; - unsigned int hard_max_transfer; - - memset(&ireg, 0, sizeof ireg); - ireg.edx.b[0] = devno; - - if (cdrom) { - /* - * The query functions don't work right on some CD-ROM stacks. - * Known affected systems: ThinkPad T22, T23. - */ - sector_size = 2048; - ebios = true; - hard_max_transfer = 32; - } else { - sector_size = 512; - ebios = false; - hard_max_transfer = 63; - - /* CBIOS parameters */ - disk.h = bsHeads; - disk.s = bsSecPerTrack; - - if ((int8_t)devno < 0) { - /* Get hard disk geometry from BIOS */ - - ireg.eax.b[1] = 0x08; - __intcall(0x13, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF)) { - disk.h = oreg.edx.b[1] + 1; - disk.s = oreg.ecx.b[0] & 63; - } - } - - /* Get EBIOS support */ - ireg.eax.b[1] = 0x41; - ireg.ebx.w[0] = 0x55aa; - ireg.eflags.b[0] = 0x3; /* CF set */ - - __intcall(0x13, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF) && - oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) { - ebios = true; - hard_max_transfer = 127; - - /* Query EBIOS parameters */ - /* The memset() is needed once this function can be called - more than once */ - /* memset(&edd_params, 0, sizeof edd_params); */ - edd_params.len = sizeof edd_params; - - ireg.eax.b[1] = 0x48; - ireg.ds = SEG(&edd_params); - ireg.esi.w[0] = OFFS(&edd_params); - __intcall(0x13, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) { - if (edd_params.len < sizeof edd_params) - memset((char *)&edd_params + edd_params.len, 0, - sizeof edd_params - edd_params.len); - - if (edd_params.sector_size >= 512 && - is_power_of_2(edd_params.sector_size)) - sector_size = edd_params.sector_size; - } - } - - } - - disk.disk_number = devno; - disk.sector_size = sector_size; - disk.sector_shift = ilog2(sector_size); - disk.part_start = part_start; - disk.secpercyl = disk.h * disk.s; - disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; - - if (!MaxTransfer || MaxTransfer > hard_max_transfer) - MaxTransfer = hard_max_transfer; - - disk.maxtransfer = MaxTransfer; - - dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", - devno, cdrom, ebios, sector_size, disk.sector_shift, - part_start, disk.maxtransfer); - - return &disk; -} - - /* * Initialize the device structure. * * NOTE: the disk cache needs to be revamped to support multiple devices... */ -struct device * device_init(void *args) +struct device * device_init(struct disk_private *args) { static struct device dev; static __hugebss char diskcache[128*1024]; diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c new file mode 100644 index 00000000..52d20172 --- /dev/null +++ b/core/fs/diskio_bios.c @@ -0,0 +1,398 @@ +#include <core.h> +#include <com32.h> +#include <fs.h> +#include <ilog2.h> + +#define RETRY_COUNT 6 + +static inline sector_t chs_max(const struct disk *disk) +{ + return (sector_t)disk->secpercyl << 10; +} + +struct edd_rdwr_packet { + uint16_t size; + uint16_t blocks; + far_ptr_t buf; + uint64_t lba; +}; + +struct edd_disk_params { + uint16_t len; + uint16_t flags; + uint32_t phys_c; + uint32_t phys_h; + uint32_t phys_s; + uint64_t sectors; + uint16_t sector_size; + far_ptr_t dpte; + uint16_t devpath_key; + uint8_t devpath_len; + uint8_t _pad1[3]; + char bus_type[4]; + char if_type[8]; + uint8_t if_path[8]; + uint8_t dev_path[16]; + uint8_t _pad2; + uint8_t devpath_csum; /* Depends on devpath_len! */ +} __attribute__((packed)); + +static inline bool is_power_of_2(uint32_t x) +{ + return !(x & (x-1)); +} + +static int chs_rdwr_sectors(struct disk *disk, void *buf, + sector_t lba, size_t count, bool is_write) +{ + char *ptr = buf; + char *tptr; + size_t chunk, freeseg; + int sector_shift = disk->sector_shift; + uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */ + uint32_t t; + uint32_t c, h, s; + com32sys_t ireg, oreg; + size_t done = 0; + size_t bytes; + int retry; + uint32_t maxtransfer = disk->maxtransfer; + + if (lba + disk->part_start >= chs_max(disk)) + return 0; /* Impossible CHS request */ + + memset(&ireg, 0, sizeof ireg); + + ireg.eax.b[1] = 0x02 + is_write; + ireg.edx.b[0] = disk->disk_number; + + while (count) { + chunk = count; + if (chunk > maxtransfer) + chunk = maxtransfer; + + freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; + + if ((size_t)buf <= 0xf0000 && freeseg) { + /* Can do a direct load */ + tptr = ptr; + } else { + /* Either accessing high memory or we're crossing a 64K line */ + tptr = core_xfer_buf; + freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; + } + if (chunk > freeseg) + chunk = freeseg; + + s = xlba % disk->s; + t = xlba / disk->s; + h = t % disk->h; + c = t / disk->h; + + if (chunk > (disk->s - s)) + chunk = disk->s - s; + + bytes = chunk << sector_shift; + + if (tptr != ptr && is_write) + memcpy(tptr, ptr, bytes); + + ireg.eax.b[0] = chunk; + ireg.ecx.b[1] = c; + ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); + ireg.edx.b[1] = h; + ireg.ebx.w[0] = OFFS(tptr); + ireg.es = SEG(tptr); + + retry = RETRY_COUNT; + + for (;;) { + if (c < 1024) { + dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n", + ireg.edx.b[0], chunk, xlba, c, h, s+1, + ireg.es, ireg.ebx.w[0], + (ireg.eax.b[1] & 1) ? "<-" : "->", + ptr); + + __intcall(0x13, &ireg, &oreg); + if (!(oreg.eflags.l & EFLAGS_CF)) + break; + + dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]); + + if (retry--) + continue; + + /* + * For any starting value, this will always end with + * ..., 1, 0 + */ + chunk >>= 1; + if (chunk) { + maxtransfer = chunk; + retry = RETRY_COUNT; + ireg.eax.b[0] = chunk; + continue; + } + } + + printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n", + oreg.eax.w[0], + is_write ? "writing" : "reading", + lba, c, h, s+1); + return done; /* Failure */ + } + + bytes = chunk << sector_shift; + + if (tptr != ptr && !is_write) + memcpy(ptr, tptr, bytes); + + /* If we dropped maxtransfer, it eventually worked, so remember it */ + disk->maxtransfer = maxtransfer; + + ptr += bytes; + xlba += chunk; + count -= chunk; + done += chunk; + } + + return done; +} + +static int edd_rdwr_sectors(struct disk *disk, void *buf, + sector_t lba, size_t count, bool is_write) +{ + static __lowmem struct edd_rdwr_packet pkt; + char *ptr = buf; + char *tptr; + size_t chunk, freeseg; + int sector_shift = disk->sector_shift; + com32sys_t ireg, oreg, reset; + size_t done = 0; + size_t bytes; + int retry; + uint32_t maxtransfer = disk->maxtransfer; + + memset(&ireg, 0, sizeof ireg); + + ireg.eax.b[1] = 0x42 + is_write; + ireg.edx.b[0] = disk->disk_number; + ireg.ds = SEG(&pkt); + ireg.esi.w[0] = OFFS(&pkt); + + memset(&reset, 0, sizeof reset); + + lba += disk->part_start; + while (count) { + chunk = count; + if (chunk > maxtransfer) + chunk = maxtransfer; + + freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift; + + if ((size_t)ptr <= 0xf0000 && freeseg) { + /* Can do a direct load */ + tptr = ptr; + } else { + /* Either accessing high memory or we're crossing a 64K line */ + tptr = core_xfer_buf; + freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift; + } + if (chunk > freeseg) + chunk = freeseg; + + bytes = chunk << sector_shift; + + if (tptr != ptr && is_write) + memcpy(tptr, ptr, bytes); + + retry = RETRY_COUNT; + + for (;;) { + pkt.size = sizeof pkt; + pkt.blocks = chunk; + pkt.buf = FAR_PTR(tptr); + pkt.lba = lba; + + dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n", + ireg.edx.b[0], pkt.blocks, pkt.lba, + pkt.buf.seg, pkt.buf.offs, + (ireg.eax.b[1] & 1) ? "<-" : "->", + ptr); + + __intcall(0x13, &ireg, &oreg); + if (!(oreg.eflags.l & EFLAGS_CF)) + break; + + dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]); + + if (retry--) + continue; + + /* + * Some systems seem to get "stuck" in an error state when + * using EBIOS. Doesn't happen when using CBIOS, which is + * good, since some other systems get timeout failures + * waiting for the floppy disk to spin up. + */ + __intcall(0x13, &reset, NULL); + + /* For any starting value, this will always end with ..., 1, 0 */ + chunk >>= 1; + if (chunk) { + maxtransfer = chunk; + retry = RETRY_COUNT; + continue; + } + + /* + * Total failure. There are systems which identify as + * EDD-capable but aren't; the known such systems return + * error code AH=1 (invalid function), but let's not + * assume that for now. + * + * Try to fall back to CHS. If the LBA is absurd, the + * chs_max() test in chs_rdwr_sectors() will catch it. + */ + done = chs_rdwr_sectors(disk, buf, lba - disk->part_start, + count, is_write); + if (done == (count << sector_shift)) { + /* Successful, assume this is a CHS disk */ + disk->rdwr_sectors = chs_rdwr_sectors; + return done; + } + printf("EDD: Error %04x %s sector %llu\n", + oreg.eax.w[0], + is_write ? "writing" : "reading", + lba); + return done; /* Failure */ + } + + bytes = chunk << sector_shift; + + if (tptr != ptr && !is_write) + memcpy(ptr, tptr, bytes); + + /* If we dropped maxtransfer, it eventually worked, so remember it */ + disk->maxtransfer = maxtransfer; + + ptr += bytes; + lba += chunk; + count -= chunk; + done += chunk; + } + return done; +} + +struct disk *bios_disk_init(struct disk_private *priv) +{ + static struct disk disk; + com32sys_t *regs = priv->regs; + static __lowmem struct edd_disk_params edd_params; + com32sys_t ireg, oreg; + uint8_t devno = regs->edx.b[0]; + bool cdrom = regs->edx.b[1]; + sector_t part_start = regs->ecx.l | ((sector_t)regs->ebx.l << 32); + uint16_t bsHeads = regs->esi.w[0]; + uint16_t bsSecPerTrack = regs->edi.w[0]; + uint32_t MaxTransfer = regs->ebp.l; + bool ebios; + int sector_size; + unsigned int hard_max_transfer; + + memset(&ireg, 0, sizeof ireg); + ireg.edx.b[0] = devno; + + if (cdrom) { + /* + * The query functions don't work right on some CD-ROM stacks. + * Known affected systems: ThinkPad T22, T23. + */ + sector_size = 2048; + ebios = true; + hard_max_transfer = 32; + } else { + sector_size = 512; + ebios = false; + hard_max_transfer = 63; + + /* CBIOS parameters */ + disk.h = bsHeads; + disk.s = bsSecPerTrack; + + if ((int8_t)devno < 0) { + /* Get hard disk geometry from BIOS */ + + ireg.eax.b[1] = 0x08; + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF)) { + disk.h = oreg.edx.b[1] + 1; + disk.s = oreg.ecx.b[0] & 63; + } + } + + /* Get EBIOS support */ + ireg.eax.b[1] = 0x41; + ireg.ebx.w[0] = 0x55aa; + ireg.eflags.b[0] = 0x3; /* CF set */ + + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && + oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) { + ebios = true; + hard_max_transfer = 127; + + /* Query EBIOS parameters */ + /* The memset() is needed once this function can be called + more than once */ + /* memset(&edd_params, 0, sizeof edd_params); */ + edd_params.len = sizeof edd_params; + + ireg.eax.b[1] = 0x48; + ireg.ds = SEG(&edd_params); + ireg.esi.w[0] = OFFS(&edd_params); + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) { + if (edd_params.len < sizeof edd_params) + memset((char *)&edd_params + edd_params.len, 0, + sizeof edd_params - edd_params.len); + + if (edd_params.sector_size >= 512 && + is_power_of_2(edd_params.sector_size)) + sector_size = edd_params.sector_size; + } + } + + } + + disk.disk_number = devno; + disk.sector_size = sector_size; + disk.sector_shift = ilog2(sector_size); + disk.part_start = part_start; + disk.secpercyl = disk.h * disk.s; + disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + + if (!MaxTransfer || MaxTransfer > hard_max_transfer) + MaxTransfer = hard_max_transfer; + + disk.maxtransfer = MaxTransfer; + + dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", + devno, cdrom, ebios, sector_size, disk.sector_shift, + part_start, disk.maxtransfer); + + disk.private = priv; + return &disk; +} + +void pm_fs_init(com32sys_t *regs) +{ + static struct disk_private priv; + + priv.regs = regs; + fs_init((const struct fs_ops **)regs->eax.l, &priv); +} diff --git a/core/fs/fs.c b/core/fs/fs.c index c2d17dc2..e6f35370 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -433,7 +433,7 @@ void pm_close_file(com32sys_t *regs) */ __bss16 uint16_t SectorSize, SectorShift; -void fs_init(const struct fs_ops **ops, void *args) +void fs_init(const struct fs_ops **ops, struct disk_private *priv) { static struct fs_info fs; /* The actual filesystem buffer */ int blk_shift = -1; @@ -457,7 +457,7 @@ void fs_init(const struct fs_ops **ops, void *args) fs.fs_dev = NULL; } else { if (!dev) - dev = device_init(args); + dev = device_init(priv); fs.fs_dev = dev; } /* invoke the fs-specific init code */ @@ -489,8 +489,3 @@ void fs_init(const struct fs_ops **ops, void *args) SectorShift = fs.sector_shift; SectorSize = fs.sector_size; } - -void pm_fs_init(com32sys_t *regs) -{ - fs_init(regs->eax.l, regs); -} diff --git a/core/include/disk.h b/core/include/disk.h index d0d50ede..2aec11ce 100644 --- a/core/include/disk.h +++ b/core/include/disk.h @@ -4,16 +4,29 @@ #include <stddef.h> #include <stdint.h> #include <stdbool.h> +#include <core.h> typedef uint64_t sector_t; typedef uint64_t block_t; +#ifdef SYSLINUX_EFI +struct disk_private { + EFI_HANDLE dev_handle; + EFI_BLOCK_IO *bio; + EFI_DISK_IO *dio; +}; +#else +struct disk_private { + com32sys_t *regs; +}; +#endif + /* * struct disk: contains the information about a specific disk and also * contains the I/O function. */ struct disk { - void *private; /* Firmware-private disk info */ + struct disk_private *private; /* Firmware-private disk info */ unsigned int disk_number; /* in BIOS style */ unsigned int sector_size; /* gener512B or 2048B */ unsigned int sector_shift; @@ -32,7 +45,7 @@ extern void read_sectors(char *, sector_t, int); extern void getoneblk(struct disk *, char *, block_t, int); /* diskio.c */ -struct disk *bios_disk_init(com32sys_t *); -struct device *device_init(void *); +struct disk *bios_disk_init(struct disk_private *); +struct device *device_init(struct disk_private *); #endif /* DISK_H */ diff --git a/core/include/fs.h b/core/include/fs.h index a554a46d..decada64 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -181,7 +181,6 @@ static inline struct file *handle_to_file(uint16_t handle) extern char *PATH; -/* fs.c */ void pm_mangle_name(com32sys_t *); void pm_searchdir(com32sys_t *); void mangle_name(char *, const char *); diff --git a/efi/Makefile b/efi/Makefile index b67af60f..338f4512 100644 --- a/efi/Makefile +++ b/efi/Makefile @@ -20,7 +20,8 @@ CORE_COBJ := $(patsubst %.c,%.o,$(CORE_CSRC)) # Don't include console objects CORE_OBJS = $(filter-out $(core)/hello.o $(core)/rawcon.o \ - $(core)/plaincon.o $(core)/strcasecmp.o $(core)/bios.o,$(CORE_COBJ)) + $(core)/plaincon.o $(core)/strcasecmp.o $(core)/bios.o \ + $(core)/fs/diskio_bios.o,$(CORE_COBJ)) LIB_OBJS = $(addprefix $(com32)/lib/,$(MINLIBOBJS)) CSRC = $(wildcard *.c) diff --git a/efi/diskio.c b/efi/diskio.c index 89779a5b..5e7898af 100644 --- a/efi/diskio.c +++ b/efi/diskio.c @@ -5,11 +5,6 @@ #include <dprintf.h> #include "efi.h" -struct disk_efi_private { - EFI_BLOCK_IO *bio; - EFI_DISK_IO *dio; -}; - static inline EFI_STATUS read_blocks(EFI_BLOCK_IO *bio, uint32_t id, sector_t lba, UINTN bytes, void *buf) { @@ -25,7 +20,7 @@ static inline EFI_STATUS write_blocks(EFI_BLOCK_IO *bio, uint32_t id, static int efi_rdwr_sectors(struct disk *disk, void *buf, sector_t lba, size_t count, bool is_write) { - struct disk_efi_private *priv = disk->private; + struct disk_private *priv = disk->private; EFI_BLOCK_IO *bio = priv->bio; EFI_DISK_IO *dio = priv->dio; EFI_STATUS status; @@ -45,10 +40,10 @@ static int efi_rdwr_sectors(struct disk *disk, void *buf, return count << disk->sector_shift; } -struct disk *efi_disk_init(EFI_HANDLE handle) +struct disk *efi_disk_init(struct disk_private *priv) { - static struct disk_efi_private priv; static struct disk disk; + EFI_HANDLE handle = priv->dev_handle; unsigned int hard_max_transfer; EFI_BLOCK_IO *bio; EFI_DISK_IO *dio; @@ -78,9 +73,9 @@ struct disk *efi_disk_init(EFI_HANDLE handle) Print(L"sector_size=%d, disk_number=%d\n", disk.sector_size, disk.disk_number); - priv.bio = bio; - priv.dio = dio; - disk.private = &priv; + priv->bio = bio; + priv->dio = dio; + disk.private = priv; #if 0 disk.part_start = part_start; @@ -687,6 +687,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) EFI_STATUS status = EFI_SUCCESS; struct fs_ops *ops[] = { &vfat_fs_ops, NULL }; unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start; + static struct disk_private priv; memset(__bss_start, 0, len); InitializeLib(image, table); @@ -711,7 +712,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table) /* TODO: once all errors are captured in efi_errno, bail out if necessary */ /* XXX figure out what file system we're on */ - fs_init(ops, info->DeviceHandle); + priv.dev_handle = info->DeviceHandle; + fs_init(ops, &priv); load_env32(); out: |