Use 64bit integers for sector and lba values.
****************************************************************/
struct ata_op_s {
- u32 lba;
+ u64 lba;
void *far_buffer;
u16 driveid;
u16 count;
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));
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;
// 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;
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);
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)
heads = 32;
else
heads = 16;
- cylinders = sectors / heads;
+ cylinders = sect / heads;
break;
case ATA_TRANSLATION_RECHS:
BX_INFO("r-echs");
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
// 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);
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 {
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);
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();
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 {
}
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
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);
u16 count;
u16 offset;
u16 segment;
- u32 lba1;
- u32 lba2;
+ u64 lba;
} PACKED;
#define GET_INT13EXT(regs,var) \
u32 cylinders;
u32 heads;
u32 spt;
- u32 sector_count1;
- u32 sector_count2;
+ u64 sector_count;
u16 blksize;
u16 dpte_offset;
u16 dpte_segment;
__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))
#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) \
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; })
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)
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.