aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2008-05-14 00:43:13 -0400
committerKevin O'Connor <kevin@koconnor.net>2008-05-14 00:43:13 -0400
commit1bb3b5c25284cb98f40f245f5d621721c6959fe1 (patch)
tree87898414b768de1b56b43d256491121e01a97947
parent022709521842e8f075c9cf5b070295a25f2b5636 (diff)
downloadseabios-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.c34
-rw-r--r--src/ata.h2
-rw-r--r--src/biosvar.h2
-rw-r--r--src/disk.c27
-rw-r--r--src/disk.h6
-rw-r--r--src/farptr.h19
-rw-r--r--src/types.h5
7 files changed, 57 insertions, 38 deletions
diff --git a/src/ata.c b/src/ata.c
index 0b48dcd..e8a4a28 100644
--- a/src/ata.c
+++ b/src/ata.c
@@ -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
diff --git a/src/ata.h b/src/ata.h
index a778120..59b01d3 100644
--- a/src/ata.h
+++ b/src/ata.h
@@ -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 {
diff --git a/src/disk.c b/src/disk.c
index 7228529..152b811 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -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);
diff --git a/src/disk.h b/src/disk.h
index 30ef0bb..e70d3a7 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -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.