diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2008-05-14 00:43:13 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2008-05-14 00:43:13 -0400 |
commit | 1bb3b5c25284cb98f40f245f5d621721c6959fe1 (patch) | |
tree | 87898414b768de1b56b43d256491121e01a97947 | |
parent | 022709521842e8f075c9cf5b070295a25f2b5636 (diff) | |
download | seabios-hppa-1bb3b5c25284cb98f40f245f5d621721c6959fe1.zip seabios-hppa-1bb3b5c25284cb98f40f245f5d621721c6959fe1.tar.gz seabios-hppa-1bb3b5c25284cb98f40f245f5d621721c6959fe1.tar.bz2 |
Add full support for drives with more that 2<<32 sectors.
Use 64bit integers for sector and lba values.
-rw-r--r-- | src/ata.c | 34 | ||||
-rw-r--r-- | src/ata.h | 2 | ||||
-rw-r--r-- | src/biosvar.h | 2 | ||||
-rw-r--r-- | src/disk.c | 27 | ||||
-rw-r--r-- | src/disk.h | 6 | ||||
-rw-r--r-- | src/farptr.h | 19 | ||||
-rw-r--r-- | src/types.h | 5 |
7 files changed, 57 insertions, 38 deletions
@@ -147,7 +147,7 @@ ata_reset(int driveid) ****************************************************************/ struct ata_op_s { - u32 lba; + u64 lba; void *far_buffer; u16 driveid; u16 count; @@ -358,7 +358,7 @@ static noinline int send_cmd_disk(const struct ata_op_s *op, u16 command) { u8 slave = op->driveid % 2; - u32 lba = op->lba; + u64 lba = op->lba; struct ata_pio_command cmd; memset(&cmd, 0, sizeof(cmd)); @@ -367,8 +367,8 @@ send_cmd_disk(const struct ata_op_s *op, u16 command) if (op->count >= (1<<8) || lba + op->count >= (1<<28)) { cmd.sector_count2 = op->count >> 8; cmd.lba_low2 = lba >> 24; - cmd.lba_mid2 = 0; - cmd.lba_high2 = 0; + cmd.lba_mid2 = lba >> 32; + cmd.lba_high2 = lba >> 40; cmd.command |= 0x04; lba &= 0xffffff; @@ -387,7 +387,7 @@ send_cmd_disk(const struct ata_op_s *op, u16 command) // Read/write count blocks from a harddrive. __always_inline int -ata_cmd_data(int driveid, u16 command, u32 lba, u16 count, void *far_buffer) +ata_cmd_data(int driveid, u16 command, u64 lba, u16 count, void *far_buffer) { struct ata_op_s op; op.driveid = driveid; @@ -627,7 +627,11 @@ init_drive_ata(int driveid) u16 heads = *(u16*)&buffer[3*2]; // word 3 u16 spt = *(u16*)&buffer[6*2]; // word 6 - u32 sectors = *(u32*)&buffer[60*2]; // word 60 and word 61 + u64 sectors; + if (*(u16*)&buffer[83*2] & (1 << 10)) // word 83 - lba48 support + sectors = *(u64*)&buffer[100*2]; // word 100-103 + else + sectors = *(u32*)&buffer[60*2]; // word 60 and word 61 SET_EBDA(ata.devices[driveid].device,ATA_DEVICE_HD); SET_EBDA(ata.devices[driveid].removable, removable); @@ -657,8 +661,13 @@ init_drive_ata(int driveid) case ATA_TRANSLATION_LBA: BX_INFO("lba"); spt = 63; - sectors /= 63; - heads = sectors / 1024; + if (sectors > 63*255*1024) { + heads = 255; + cylinders = 1024; + break; + } + u32 sect = (u32)sectors / 63; + heads = sect / 1024; if (heads>128) heads = 255; else if (heads>64) @@ -669,7 +678,7 @@ init_drive_ata(int driveid) heads = 32; else heads = 16; - cylinders = sectors / heads; + cylinders = sect / heads; break; case ATA_TRANSLATION_RECHS: BX_INFO("r-echs"); @@ -708,15 +717,16 @@ init_drive_ata(int driveid) SET_EBDA(ata.idmap[0][hdcount], driveid); SET_EBDA(ata.hdcount, ++hdcount); - u32 sizeinmb = GET_EBDA(ata.devices[driveid].sectors); + u64 sizeinmb = GET_EBDA(ata.devices[driveid].sectors); sizeinmb >>= 11; report_model(driveid, buffer); u8 version = get_ata_version(buffer); if (sizeinmb < (1 << 16)) - printf(" ATA-%d Hard-Disk (%u MBytes)\n", version, sizeinmb); + printf(" ATA-%d Hard-Disk (%u MBytes)\n", version, (u32)sizeinmb); else - printf(" ATA-%d Hard-Disk (%u GBytes)\n", version, sizeinmb >> 10); + printf(" ATA-%d Hard-Disk (%u GBytes)\n", version + , (u32)(sizeinmb >> 10)); } static void @@ -13,7 +13,7 @@ // Function definitions void ata_reset(int driveid); -int ata_cmd_data(int driveid, u16 command, u32 lba, u16 count, void *far_buffer); +int ata_cmd_data(int driveid, u16 command, u64 lba, u16 count, void *far_buffer); int ata_cmd_packet(int driveid, u8 *cmdbuf, u8 cmdlen , u32 length, void *far_buffer); int cdrom_read(int driveid, u32 lba, u32 count, void *far_buffer); diff --git a/src/biosvar.h b/src/biosvar.h index 9528523..8f694e4 100644 --- a/src/biosvar.h +++ b/src/biosvar.h @@ -160,7 +160,7 @@ struct ata_device_s { struct chs_s lchs; // Logical CHS struct chs_s pchs; // Physical CHS - u32 sectors; // Total sectors count + u64 sectors; // Total sectors count }; struct ata_s { @@ -115,21 +115,9 @@ basic_access(struct bregs *regs, u8 device, u16 command) static void extended_access(struct bregs *regs, u8 device, u16 command) { - u16 count = GET_INT13EXT(regs, count); - - // Can't use 64 bits lba - u32 lba = GET_INT13EXT(regs, lba2); - if (lba != 0L) { - BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n" - , regs->ah); - disk_ret(regs, DISK_RET_EPARAM); - return; - } - + // Get lba and check. + u64 lba = GET_INT13EXT(regs, lba); u8 type = GET_EBDA(ata.devices[device].type); - - // Get 32 bits lba and check - lba = GET_INT13EXT(regs, lba1); if (type == ATA_TYPE_ATA && lba >= GET_EBDA(ata.devices[device].sectors)) { BX_INFO("int13_harddisk: function %02x. LBA out of range\n", regs->ah); @@ -146,6 +134,7 @@ extended_access(struct bregs *regs, u8 device, u16 command) u16 segment = GET_INT13EXT(regs, segment); u16 offset = GET_INT13EXT(regs, offset); void *far_buffer = MAKE_FARPTR(segment, offset); + u16 count = GET_INT13EXT(regs, count); irq_enable(); @@ -379,12 +368,12 @@ disk_1348(struct bregs *regs, u8 device) u16 npc = GET_EBDA(ata.devices[device].pchs.cylinders); u16 nph = GET_EBDA(ata.devices[device].pchs.heads); u16 npspt = GET_EBDA(ata.devices[device].pchs.spt); - u32 lba = GET_EBDA(ata.devices[device].sectors); + u64 lba = GET_EBDA(ata.devices[device].sectors); u16 blksize = GET_EBDA(ata.devices[device].blksize); SET_INT13DPT(regs, size, 0x1a); if (type == ATA_TYPE_ATA) { - if ((lba/npspt)/nph > 0x3fff) { + if (lba > (u64)npspt*nph*0x3fff) { SET_INT13DPT(regs, infos, 0x00); // geometry is invalid SET_INT13DPT(regs, cylinders, 0x3fff); } else { @@ -393,8 +382,7 @@ disk_1348(struct bregs *regs, u8 device) } SET_INT13DPT(regs, heads, (u32)nph); SET_INT13DPT(regs, spt, (u32)npspt); - SET_INT13DPT(regs, sector_count1, lba); // FIXME should be Bit64 - SET_INT13DPT(regs, sector_count2, 0L); + SET_INT13DPT(regs, sector_count, lba); } else { // ATAPI // 0x74 = removable, media change, lockable, max values @@ -402,8 +390,7 @@ disk_1348(struct bregs *regs, u8 device) SET_INT13DPT(regs, cylinders, 0xffffffff); SET_INT13DPT(regs, heads, 0xffffffff); SET_INT13DPT(regs, spt, 0xffffffff); - SET_INT13DPT(regs, sector_count1, 0xffffffff); // FIXME should be Bit64 - SET_INT13DPT(regs, sector_count2, 0xffffffff); + SET_INT13DPT(regs, sector_count, (u64)-1); } SET_INT13DPT(regs, blksize, blksize); @@ -33,8 +33,7 @@ struct int13ext_s { u16 count; u16 offset; u16 segment; - u32 lba1; - u32 lba2; + u64 lba; } PACKED; #define GET_INT13EXT(regs,var) \ @@ -49,8 +48,7 @@ struct int13dpt_s { u32 cylinders; u32 heads; u32 spt; - u32 sector_count1; - u32 sector_count2; + u64 sector_count; u16 blksize; u16 dpte_offset; u16 dpte_segment; diff --git a/src/farptr.h b/src/farptr.h index 56219d2..ef0aa42 100644 --- a/src/farptr.h +++ b/src/farptr.h @@ -28,6 +28,12 @@ extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS; __asm__("movl %%" #SEG ":%1, %0" : "=ri"(__value) \ : "m"(var), "m"(__segment_ ## SEG)); \ __value; }) +#define READ64_SEG(SEG, var) ({ \ + union u64_u32_u __value; \ + union u64_u32_u *__r64_ptr = (union u64_u32_u *)&(var); \ + __value.hi = READ32_SEG(SEG, __r64_ptr->hi); \ + __value.lo = READ32_SEG(SEG, __r64_ptr->lo); \ + __value.val; }) #define WRITE8_SEG(SEG, var, value) \ __asm__("movb %b1, %%" #SEG ":%0" : "=m"(var) \ : "Q"(value), "m"(__segment_ ## SEG)) @@ -37,6 +43,13 @@ extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS; #define WRITE32_SEG(SEG, var, value) \ __asm__("movl %1, %%" #SEG ":%0" : "=m"(var) \ : "r"(value), "m"(__segment_ ## SEG)) +#define WRITE64_SEG(SEG, var, value) do { \ + union u64_u32_u __value; \ + union u64_u32_u *__w64_ptr = (union u64_u32_u *)&(var); \ + __value.val = (value); \ + WRITE32_SEG(SEG, __w64_ptr->hi, __value.hi); \ + WRITE32_SEG(SEG, __w64_ptr->lo, __value.lo); \ + } while (0) // Low level macros for getting/setting a segment register. #define __SET_SEG(SEG, value) \ @@ -63,6 +76,9 @@ extern void __force_link_error__unknown_type(); else if (__builtin_types_compatible_p(typeof(__val), u32) \ || __builtin_types_compatible_p(typeof(__val), s32)) \ __val = READ32_SEG(seg, var); \ + else if (__builtin_types_compatible_p(typeof(__val), u64) \ + || __builtin_types_compatible_p(typeof(__val), s64)) \ + __val = READ64_SEG(seg, var); \ else \ __force_link_error__unknown_type(); \ __val; }) @@ -77,6 +93,9 @@ extern void __force_link_error__unknown_type(); else if (__builtin_types_compatible_p(typeof(var), u32) \ || __builtin_types_compatible_p(typeof(var), s32)) \ WRITE32_SEG(seg, var, (val)); \ + else if (__builtin_types_compatible_p(typeof(var), u64) \ + || __builtin_types_compatible_p(typeof(var), s64)) \ + WRITE64_SEG(seg, var, (val)); \ else \ __force_link_error__unknown_type(); \ } while (0) diff --git a/src/types.h b/src/types.h index eb13011..d356451 100644 --- a/src/types.h +++ b/src/types.h @@ -16,6 +16,11 @@ typedef unsigned long long u64; typedef signed long long s64; typedef u32 size_t; +union u64_u32_u { + struct { u32 hi, lo; }; + u64 val; +}; + #define __VISIBLE __attribute__((externally_visible)) #ifdef MODE16 // Notes a function as externally visible in the 16bit code chunk. |