1 // 16bit code to access hard drives.
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002 MandrakeSoft S.A.
6 // This file may be distributed under the terms of the GNU GPLv3 license.
8 #include "disk.h" // floppy_13
9 #include "biosvar.h" // SET_BDA
10 #include "config.h" // CONFIG_*
11 #include "util.h" // debug_enter
12 #include "pic.h" // eoi_pic2
13 #include "bregs.h" // struct bregs
14 #include "pci.h" // pci_bdf_to_bus
15 #include "atabits.h" // ATA_CB_STAT
18 /****************************************************************
20 ****************************************************************/
23 __disk_ret(struct bregs *regs, u32 linecode, const char *fname)
26 SET_BDA(disk_last_status, code);
28 __set_code_fail(regs, linecode, fname);
30 set_code_success(regs);
34 __disk_stub(struct bregs *regs, int lineno, const char *fname)
36 __debug_stub(regs, lineno, fname);
37 __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
40 #define DISK_STUB(regs) \
41 __disk_stub((regs), __LINE__, __func__)
44 __send_disk_op(struct disk_op_s *op_p, u16 op_s)
47 memcpy_far(MAKE_FARPTR(GET_SEG(SS), &dop)
48 , MAKE_FARPTR(op_s, op_p)
51 dprintf(DEBUG_HDL_13, "disk_op d=%d lba=%d buf=%p count=%d cmd=%d\n"
52 , dop.driveid, (u32)dop.lba, dop.far_buffer
53 , dop.count, dop.command);
58 if (dop.command == CMD_CDEMU_READ)
59 status = cdrom_read_512(&dop);
60 else if (dop.command == CMD_CDROM_READ)
61 status = cdrom_read(&dop);
63 status = ata_cmd_data(&dop);
71 send_disk_op(struct disk_op_s *op)
73 return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
77 basic_access(struct bregs *regs, u8 device, u16 command)
82 u8 type = GET_GLOBAL(ATA.devices[device].type);
84 if (type == ATA_TYPE_ATA) {
85 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
86 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
87 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
88 dop.command = command;
90 // Must be cd emulation.
91 u16 ebda_seg = get_ebda_seg();
92 nlc = GET_EBDA2(ebda_seg, cdemu.cylinders);
93 nlh = GET_EBDA2(ebda_seg, cdemu.heads);
94 nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
95 dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) * 4;
96 dop.command = CMD_CDEMU_READ;
100 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
101 u16 sector = regs->cl & 0x3f;
104 if (dop.count > 128 || dop.count == 0 || sector == 0) {
105 dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
107 disk_ret(regs, DISK_RET_EPARAM);
111 // sanity check on cyl heads, sec
112 if (cylinder >= nlc || head >= nlh || sector > nlspt) {
113 dprintf(1, "int13_harddisk: function %02x, parameters out of"
114 " range %04x/%04x/%04x!\n"
115 , regs->ah, cylinder, head, sector);
116 disk_ret(regs, DISK_RET_EPARAM);
122 disk_ret(regs, DISK_RET_SUCCESS);
126 // translate lchs to lba
127 dop.lba += (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
130 u16 segment = regs->es;
131 u16 offset = regs->bx;
132 dop.far_buffer = MAKE_FARPTR(segment, offset);
134 int status = send_disk_op(&dop);
136 // Set nb of sector transferred
137 regs->al = GET_EBDA(sector_count);
140 dprintf(1, "int13_harddisk: function %02x, error %d!\n"
142 disk_ret(regs, DISK_RET_EBADTRACK);
145 disk_ret(regs, DISK_RET_SUCCESS);
149 extended_access(struct bregs *regs, u8 device, u16 command)
151 struct disk_op_s dop;
152 // Get lba and check.
153 dop.lba = GET_INT13EXT(regs, lba);
154 dop.command = command;
155 dop.driveid = device;
156 u8 type = GET_GLOBAL(ATA.devices[device].type);
157 if (type == ATA_TYPE_ATA) {
158 if (dop.lba >= GET_GLOBAL(ATA.devices[device].sectors)) {
159 dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
161 disk_ret(regs, DISK_RET_EPARAM);
165 dop.command = CMD_CDROM_READ;
170 disk_ret(regs, DISK_RET_SUCCESS);
174 u16 segment = GET_INT13EXT(regs, segment);
175 u16 offset = GET_INT13EXT(regs, offset);
176 dop.far_buffer = MAKE_FARPTR(segment, offset);
177 dop.count = GET_INT13EXT(regs, count);
179 int status = send_disk_op(&dop);
181 SET_INT13EXT(regs, count, GET_EBDA(sector_count));
184 dprintf(1, "int13_harddisk: function %02x, error %d!\n"
186 disk_ret(regs, DISK_RET_EBADTRACK);
189 disk_ret(regs, DISK_RET_SUCCESS);
193 /****************************************************************
194 * Hard Drive functions
195 ****************************************************************/
197 // disk controller reset
199 disk_1300(struct bregs *regs, u8 device)
206 disk_1301(struct bregs *regs, u8 device)
208 u8 v = GET_BDA(disk_last_status);
211 // XXX - clear disk_last_status?
216 disk_1302(struct bregs *regs, u8 device)
218 basic_access(regs, device, ATA_CMD_READ_SECTORS);
221 // write disk sectors
223 disk_1303(struct bregs *regs, u8 device)
225 basic_access(regs, device, ATA_CMD_WRITE_SECTORS);
228 // verify disk sectors
230 disk_1304(struct bregs *regs, u8 device)
232 basic_access(regs, device, 0);
238 disk_1305(struct bregs *regs, u8 device)
243 // read disk drive parameters
245 disk_1308(struct bregs *regs, u8 device)
247 // Get logical geometry from table
248 u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
249 u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
250 u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
251 u16 count = GET_BDA(hdcount);
253 nlc = nlc - 2; /* 0 based , last sector not used */
255 regs->ch = nlc & 0xff;
256 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
258 regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
260 // FIXME should set ES & DI
261 disk_ret(regs, DISK_RET_SUCCESS);
264 // initialize drive parameters
266 disk_1309(struct bregs *regs, u8 device)
271 // seek to specified cylinder
273 disk_130c(struct bregs *regs, u8 device)
278 // alternate disk reset
280 disk_130d(struct bregs *regs, u8 device)
287 disk_1310(struct bregs *regs, u8 device)
289 // should look at 40:8E also???
291 // Read the status from controller
292 u8 status = inb(GET_GLOBAL(ATA.channels[device/2].iobase1) + ATA_CB_STAT);
293 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
294 disk_ret(regs, DISK_RET_SUCCESS);
296 disk_ret(regs, DISK_RET_ENOTREADY);
301 disk_1311(struct bregs *regs, u8 device)
306 // controller internal diagnostic
308 disk_1314(struct bregs *regs, u8 device)
313 // read disk drive size
315 disk_1315(struct bregs *regs, u8 device)
317 // Get logical geometry from table
318 u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
319 u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
320 u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
322 // Compute sector count seen by int13
323 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
324 regs->cx = lba >> 16;
325 regs->dx = lba & 0xffff;
327 disk_ret(regs, DISK_RET_SUCCESS);
328 regs->ah = 3; // hard disk accessible
331 // IBM/MS installation check
333 disk_1341(struct bregs *regs, u8 device)
335 regs->bx = 0xaa55; // install check
336 regs->cx = 0x0007; // ext disk access and edd, removable supported
337 disk_ret(regs, DISK_RET_SUCCESS);
338 regs->ah = 0x30; // EDD 3.0
341 // IBM/MS extended read
343 disk_1342(struct bregs *regs, u8 device)
345 extended_access(regs, device, ATA_CMD_READ_SECTORS);
348 // IBM/MS extended write
350 disk_1343(struct bregs *regs, u8 device)
352 extended_access(regs, device, ATA_CMD_WRITE_SECTORS);
357 disk_1344(struct bregs *regs, u8 device)
359 extended_access(regs, device, 0);
362 // IBM/MS lock/unlock drive
364 disk_1345(struct bregs *regs, u8 device)
366 // Always success for HD
367 disk_ret(regs, DISK_RET_SUCCESS);
370 // IBM/MS eject media
372 disk_1346(struct bregs *regs, u8 device)
374 // Volume Not Removable
375 disk_ret(regs, DISK_RET_ENOTREMOVABLE);
378 // IBM/MS extended seek
380 disk_1347(struct bregs *regs, u8 device)
382 extended_access(regs, device, 0);
385 // IBM/MS get drive parameters
387 disk_1348(struct bregs *regs, u8 device)
389 u16 size = GET_INT13DPT(regs, size);
391 // Buffer is too small
393 disk_ret(regs, DISK_RET_EPARAM);
399 u8 type = GET_GLOBAL(ATA.devices[device].type);
400 u16 npc = GET_GLOBAL(ATA.devices[device].pchs.cylinders);
401 u16 nph = GET_GLOBAL(ATA.devices[device].pchs.heads);
402 u16 npspt = GET_GLOBAL(ATA.devices[device].pchs.spt);
403 u64 lba = GET_GLOBAL(ATA.devices[device].sectors);
404 u16 blksize = GET_GLOBAL(ATA.devices[device].blksize);
406 dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
407 , size, type, npc, nph, npspt, (u32)lba, blksize);
409 SET_INT13DPT(regs, size, 26);
410 if (type == ATA_TYPE_ATA) {
411 if (lba > (u64)npspt*nph*0x3fff) {
412 SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
413 SET_INT13DPT(regs, cylinders, 0x3fff);
415 SET_INT13DPT(regs, infos, 0x02); // geometry is valid
416 SET_INT13DPT(regs, cylinders, (u32)npc);
418 SET_INT13DPT(regs, heads, (u32)nph);
419 SET_INT13DPT(regs, spt, (u32)npspt);
420 SET_INT13DPT(regs, sector_count, lba);
423 // 0x74 = removable, media change, lockable, max values
424 SET_INT13DPT(regs, infos, 0x74);
425 SET_INT13DPT(regs, cylinders, 0xffffffff);
426 SET_INT13DPT(regs, heads, 0xffffffff);
427 SET_INT13DPT(regs, spt, 0xffffffff);
428 SET_INT13DPT(regs, sector_count, (u64)-1);
430 SET_INT13DPT(regs, blksize, blksize);
433 disk_ret(regs, DISK_RET_SUCCESS);
439 u16 ebda_seg = get_ebda_seg();
440 SET_INT13DPT(regs, size, 30);
442 SET_INT13DPT(regs, dpte_segment, ebda_seg);
443 SET_INT13DPT(regs, dpte_offset
444 , offsetof(struct extended_bios_data_area_s, dpte));
447 u8 channel = device / 2;
448 u8 slave = device % 2;
449 u16 iobase1 = GET_GLOBAL(ATA.channels[channel].iobase1);
450 u16 iobase2 = GET_GLOBAL(ATA.channels[channel].iobase2);
451 u8 irq = GET_GLOBAL(ATA.channels[channel].irq);
452 u8 mode = GET_GLOBAL(ATA.devices[device].mode);
455 if (type == ATA_TYPE_ATA) {
456 u8 translation = GET_GLOBAL(ATA.devices[device].translation);
457 if (translation != ATA_TRANSLATION_NONE) {
458 options |= 1<<3; // CHS translation
459 if (translation == ATA_TRANSLATION_LBA)
461 if (translation == ATA_TRANSLATION_RECHS)
466 options |= 1<<5; // removable device
467 options |= 1<<6; // atapi device
469 options |= 1<<4; // lba translation
470 if (mode == ATA_MODE_PIO32)
473 SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
474 SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
475 SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
477 SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
478 SET_EBDA2(ebda_seg, dpte.irq, irq);
479 SET_EBDA2(ebda_seg, dpte.blkcount, 1);
480 SET_EBDA2(ebda_seg, dpte.dma, 0);
481 SET_EBDA2(ebda_seg, dpte.pio, 0);
482 SET_EBDA2(ebda_seg, dpte.options, options);
483 SET_EBDA2(ebda_seg, dpte.reserved, 0);
484 SET_EBDA2(ebda_seg, dpte.revision, 0x11);
486 u8 *p = MAKE_FARPTR(ebda_seg
487 , offsetof(struct extended_bios_data_area_s, dpte));
488 SET_EBDA2(ebda_seg, dpte.checksum, -checksum(p, 15));
491 disk_ret(regs, DISK_RET_SUCCESS);
496 SET_INT13DPT(regs, key, 0xbedd);
497 SET_INT13DPT(regs, dpi_length, 36);
498 SET_INT13DPT(regs, reserved1, 0);
499 SET_INT13DPT(regs, reserved2, 0);
501 SET_INT13DPT(regs, host_bus[0], 'P');
502 SET_INT13DPT(regs, host_bus[1], 'C');
503 SET_INT13DPT(regs, host_bus[2], 'I');
504 SET_INT13DPT(regs, host_bus[3], 0);
506 u32 bdf = GET_GLOBAL(ATA.channels[channel].pci_bdf);
507 u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
508 | (pci_bdf_to_fn(bdf) << 16));
509 SET_INT13DPT(regs, iface_path, path);
511 SET_INT13DPT(regs, iface_type[0], 'A');
512 SET_INT13DPT(regs, iface_type[1], 'T');
513 SET_INT13DPT(regs, iface_type[2], 'A');
514 SET_INT13DPT(regs, iface_type[3], 0);
515 SET_INT13DPT(regs, iface_type[4], 0);
516 SET_INT13DPT(regs, iface_type[5], 0);
517 SET_INT13DPT(regs, iface_type[6], 0);
518 SET_INT13DPT(regs, iface_type[7], 0);
520 SET_INT13DPT(regs, device_path, slave);
522 SET_INT13DPT(regs, checksum, -checksum(MAKE_FARPTR(regs->ds, 30), 35));
524 disk_ret(regs, DISK_RET_SUCCESS);
527 // IBM/MS extended media change
529 disk_1349(struct bregs *regs, u8 device)
531 // Always success for HD
532 disk_ret(regs, DISK_RET_SUCCESS);
536 disk_134e01(struct bregs *regs, u8 device)
538 disk_ret(regs, DISK_RET_SUCCESS);
542 disk_134e03(struct bregs *regs, u8 device)
544 disk_ret(regs, DISK_RET_SUCCESS);
548 disk_134e04(struct bregs *regs, u8 device)
550 disk_ret(regs, DISK_RET_SUCCESS);
554 disk_134e06(struct bregs *regs, u8 device)
556 disk_ret(regs, DISK_RET_SUCCESS);
560 disk_134eXX(struct bregs *regs, u8 device)
562 disk_ret(regs, DISK_RET_EPARAM);
565 // IBM/MS set hardware configuration
567 disk_134e(struct bregs *regs, u8 device)
570 case 0x01: disk_134e01(regs, device); break;
571 case 0x03: disk_134e03(regs, device); break;
572 case 0x04: disk_134e04(regs, device); break;
573 case 0x06: disk_134e06(regs, device); break;
574 default: disk_134eXX(regs, device); break;
579 disk_13XX(struct bregs *regs, u8 device)
581 disk_ret(regs, DISK_RET_EPARAM);
585 disk_13(struct bregs *regs, u8 device)
589 // clear completion flag
590 SET_BDA(disk_interrupt_flag, 0);
593 case 0x00: disk_1300(regs, device); break;
594 case 0x01: disk_1301(regs, device); break;
595 case 0x02: disk_1302(regs, device); break;
596 case 0x03: disk_1303(regs, device); break;
597 case 0x04: disk_1304(regs, device); break;
598 case 0x05: disk_1305(regs, device); break;
599 case 0x08: disk_1308(regs, device); break;
600 case 0x09: disk_1309(regs, device); break;
601 case 0x0c: disk_130c(regs, device); break;
602 case 0x0d: disk_130d(regs, device); break;
603 case 0x10: disk_1310(regs, device); break;
604 case 0x11: disk_1311(regs, device); break;
605 case 0x14: disk_1314(regs, device); break;
606 case 0x15: disk_1315(regs, device); break;
607 case 0x41: disk_1341(regs, device); break;
608 case 0x42: disk_1342(regs, device); break;
609 case 0x43: disk_1343(regs, device); break;
610 case 0x44: disk_1344(regs, device); break;
611 case 0x45: disk_1345(regs, device); break;
612 case 0x46: disk_1346(regs, device); break;
613 case 0x47: disk_1347(regs, device); break;
614 case 0x48: disk_1348(regs, device); break;
615 case 0x49: disk_1349(regs, device); break;
616 case 0x4e: disk_134e(regs, device); break;
617 default: disk_13XX(regs, device); break;
622 /****************************************************************
624 ****************************************************************/
627 get_device(struct bregs *regs, u8 iscd, u8 drive)
629 // basic check : device has to be defined
630 if (drive >= CONFIG_MAX_ATA_DEVICES) {
631 disk_ret(regs, DISK_RET_EPARAM);
632 return CONFIG_MAX_ATA_DEVICES;
635 // Get the ata channel
636 u8 device = GET_GLOBAL(ATA.idmap[iscd][drive]);
638 // basic check : device has to be valid
639 if (device >= CONFIG_MAX_ATA_DEVICES) {
640 disk_ret(regs, DISK_RET_EPARAM);
641 return CONFIG_MAX_ATA_DEVICES;
648 handle_legacy_disk(struct bregs *regs, u8 drive)
651 floppy_13(regs, drive);
656 // XXX - old code had other disk access method.
657 disk_ret(regs, DISK_RET_EPARAM);
662 u8 device = get_device(regs, 1, drive - 0xe0);
663 if (device >= CONFIG_MAX_ATA_DEVICES)
665 cdrom_13(regs, device);
669 u8 device = get_device(regs, 0, drive - 0x80);
670 if (device >= CONFIG_MAX_ATA_DEVICES)
672 disk_13(regs, device);
676 handle_40(struct bregs *regs)
678 debug_enter(regs, DEBUG_HDL_40);
679 handle_legacy_disk(regs, regs->dl);
682 // INT 13h Fixed Disk Services Entry Point
684 handle_13(struct bregs *regs)
686 debug_enter(regs, DEBUG_HDL_13);
689 if (CONFIG_CDROM_EMU) {
690 if (regs->ah == 0x4b) {
694 u16 ebda_seg = get_ebda_seg();
695 if (GET_EBDA2(ebda_seg, cdemu.active)) {
696 if (drive == GET_EBDA2(ebda_seg, cdemu.emulated_drive)) {
704 handle_legacy_disk(regs, drive);
707 // record completion in BIOS task complete flag
711 debug_isr(DEBUG_ISR_76);
712 SET_BDA(disk_interrupt_flag, 0xff);