Improve debugging output.
[seabios.git] / src / disk.c
1 // 16bit code to access hard drives.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU GPLv3 license.
7
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 "ata.h" // ATA_*
13 #include "pic.h" // eoi_pic2
14 #include "bregs.h" // struct bregs
15
16
17 /****************************************************************
18  * Helper functions
19  ****************************************************************/
20
21 void
22 __disk_ret(const char *fname, int lineno, struct bregs *regs, u8 code)
23 {
24     SET_BDA(disk_last_status, code);
25     if (code)
26         __set_code_fail(fname, lineno, regs, code);
27     else
28         set_code_success(regs);
29 }
30
31 static void
32 __disk_stub(const char *fname, int lineno, struct bregs *regs)
33 {
34     __debug_stub(fname, lineno, regs);
35     __disk_ret(fname, lineno, regs, DISK_RET_SUCCESS);
36 }
37
38 #define DISK_STUB(regs) \
39     __disk_stub(__func__, __LINE__, (regs))
40
41 static void
42 basic_access(struct bregs *regs, u8 device, u16 command)
43 {
44     u8 type = GET_EBDA(ata.devices[device].type);
45     u16 nlc, nlh, nlspt;
46     if (type == ATA_TYPE_ATA) {
47         nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
48         nlh   = GET_EBDA(ata.devices[device].lchs.heads);
49         nlspt = GET_EBDA(ata.devices[device].lchs.spt);
50     } else {
51         // Must be cd emulation.
52         nlc   = GET_EBDA(cdemu.vdevice.cylinders);
53         nlh   = GET_EBDA(cdemu.vdevice.heads);
54         nlspt = GET_EBDA(cdemu.vdevice.spt);
55     }
56
57     u16 count       = regs->al;
58     u16 cylinder    = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
59     u16 sector      = regs->cl & 0x3f;
60     u16 head        = regs->dh;
61
62     if (count > 128 || count == 0 || sector == 0) {
63         dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
64                 , regs->ah);
65         disk_ret(regs, DISK_RET_EPARAM);
66         return;
67     }
68
69     // sanity check on cyl heads, sec
70     if (cylinder >= nlc || head >= nlh || sector > nlspt) {
71         dprintf(1, "int13_harddisk: function %02x, parameters out of"
72                 " range %04x/%04x/%04x!\n"
73                 , regs->ah, cylinder, head, sector);
74         disk_ret(regs, DISK_RET_EPARAM);
75         return;
76     }
77
78     if (!command) {
79         // If verify or seek
80         disk_ret(regs, DISK_RET_SUCCESS);
81         return;
82     }
83
84     // translate lchs to lba
85     u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
86                + (u32)sector - 1);
87
88     u16 segment = regs->es;
89     u16 offset  = regs->bx;
90     void *far_buffer = MAKE_FARPTR(segment, offset);
91
92     irq_enable();
93
94     int status;
95     if (type == ATA_TYPE_ATA)
96         status = ata_cmd_data(device, command, lba, count, far_buffer);
97     else
98         status = cdrom_read_emu(device, lba, count, far_buffer);
99
100     irq_disable();
101
102     // Set nb of sector transferred
103     regs->al = GET_EBDA(ata.trsfsectors);
104
105     if (status != 0) {
106         dprintf(1, "int13_harddisk: function %02x, error %d!\n"
107                 , regs->ah, status);
108         disk_ret(regs, DISK_RET_EBADTRACK);
109     }
110     disk_ret(regs, DISK_RET_SUCCESS);
111 }
112
113 static void
114 extended_access(struct bregs *regs, u8 device, u16 command)
115 {
116     // Get lba and check.
117     u64 lba = GET_INT13EXT(regs, lba);
118     u8 type = GET_EBDA(ata.devices[device].type);
119     if (type == ATA_TYPE_ATA
120         && lba >= GET_EBDA(ata.devices[device].sectors)) {
121         dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
122                 , regs->ah);
123         disk_ret(regs, DISK_RET_EPARAM);
124         return;
125     }
126
127     if (!command) {
128         // If verify or seek
129         disk_ret(regs, DISK_RET_SUCCESS);
130         return;
131     }
132
133     u16 segment = GET_INT13EXT(regs, segment);
134     u16 offset = GET_INT13EXT(regs, offset);
135     void *far_buffer = MAKE_FARPTR(segment, offset);
136     u16 count = GET_INT13EXT(regs, count);
137
138     irq_enable();
139
140     int status;
141     if (type == ATA_TYPE_ATA)
142         status = ata_cmd_data(device, command, lba, count, far_buffer);
143     else
144         status = cdrom_read(device, lba, count, far_buffer);
145
146     irq_disable();
147
148     SET_INT13EXT(regs, count, GET_EBDA(ata.trsfsectors));
149
150     if (status != 0) {
151         dprintf(1, "int13_harddisk: function %02x, error %d!\n"
152                 , regs->ah, status);
153         disk_ret(regs, DISK_RET_EBADTRACK);
154         return;
155     }
156     disk_ret(regs, DISK_RET_SUCCESS);
157 }
158
159
160 /****************************************************************
161  * Hard Drive functions
162  ****************************************************************/
163
164 // disk controller reset
165 static void
166 disk_1300(struct bregs *regs, u8 device)
167 {
168     ata_reset(device);
169 }
170
171 // read disk status
172 static void
173 disk_1301(struct bregs *regs, u8 device)
174 {
175     u8 v = GET_BDA(disk_last_status);
176     regs->ah = v;
177     set_cf(regs, v);
178     // XXX - clear disk_last_status?
179 }
180
181 // read disk sectors
182 static void
183 disk_1302(struct bregs *regs, u8 device)
184 {
185     basic_access(regs, device, ATA_CMD_READ_SECTORS);
186 }
187
188 // write disk sectors
189 static void
190 disk_1303(struct bregs *regs, u8 device)
191 {
192     basic_access(regs, device, ATA_CMD_WRITE_SECTORS);
193 }
194
195 // verify disk sectors
196 static void
197 disk_1304(struct bregs *regs, u8 device)
198 {
199     basic_access(regs, device, 0);
200     // FIXME verify
201 }
202
203 // format disk track
204 static void
205 disk_1305(struct bregs *regs, u8 device)
206 {
207     DISK_STUB(regs);
208 }
209
210 // read disk drive parameters
211 static void
212 disk_1308(struct bregs *regs, u8 device)
213 {
214     // Get logical geometry from table
215     u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
216     u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
217     u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
218     u16 count = GET_EBDA(ata.hdcount);
219
220     nlc = nlc - 2; /* 0 based , last sector not used */
221     regs->al = 0;
222     regs->ch = nlc & 0xff;
223     regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
224     regs->dh = nlh - 1;
225     regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
226
227     // FIXME should set ES & DI
228     disk_ret(regs, DISK_RET_SUCCESS);
229 }
230
231 // initialize drive parameters
232 static void
233 disk_1309(struct bregs *regs, u8 device)
234 {
235     DISK_STUB(regs);
236 }
237
238 // seek to specified cylinder
239 static void
240 disk_130c(struct bregs *regs, u8 device)
241 {
242     DISK_STUB(regs);
243 }
244
245 // alternate disk reset
246 static void
247 disk_130d(struct bregs *regs, u8 device)
248 {
249     DISK_STUB(regs);
250 }
251
252 // check drive ready
253 static void
254 disk_1310(struct bregs *regs, u8 device)
255 {
256     // should look at 40:8E also???
257
258     // Read the status from controller
259     u8 status = inb(GET_EBDA(ata.channels[device/2].iobase1) + ATA_CB_STAT);
260     if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
261         disk_ret(regs, DISK_RET_SUCCESS);
262     else
263         disk_ret(regs, DISK_RET_ENOTREADY);
264 }
265
266 // recalibrate
267 static void
268 disk_1311(struct bregs *regs, u8 device)
269 {
270     DISK_STUB(regs);
271 }
272
273 // controller internal diagnostic
274 static void
275 disk_1314(struct bregs *regs, u8 device)
276 {
277     DISK_STUB(regs);
278 }
279
280 // read disk drive size
281 static void
282 disk_1315(struct bregs *regs, u8 device)
283 {
284     // Get logical geometry from table
285     u16 nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
286     u16 nlh   = GET_EBDA(ata.devices[device].lchs.heads);
287     u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
288
289     // Compute sector count seen by int13
290     u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
291     regs->cx = lba >> 16;
292     regs->dx = lba & 0xffff;
293
294     disk_ret(regs, DISK_RET_SUCCESS);
295     regs->ah = 3; // hard disk accessible
296 }
297
298 // IBM/MS installation check
299 static void
300 disk_1341(struct bregs *regs, u8 device)
301 {
302     regs->bx = 0xaa55;  // install check
303     regs->cx = 0x0007;  // ext disk access and edd, removable supported
304     disk_ret(regs, DISK_RET_SUCCESS);
305     regs->ah = 0x30;    // EDD 3.0
306 }
307
308 // IBM/MS extended read
309 static void
310 disk_1342(struct bregs *regs, u8 device)
311 {
312     extended_access(regs, device, ATA_CMD_READ_SECTORS);
313 }
314
315 // IBM/MS extended write
316 static void
317 disk_1343(struct bregs *regs, u8 device)
318 {
319     extended_access(regs, device, ATA_CMD_WRITE_SECTORS);
320 }
321
322 // IBM/MS verify
323 static void
324 disk_1344(struct bregs *regs, u8 device)
325 {
326     extended_access(regs, device, 0);
327 }
328
329 // IBM/MS lock/unlock drive
330 static void
331 disk_1345(struct bregs *regs, u8 device)
332 {
333     // Always success for HD
334     disk_ret(regs, DISK_RET_SUCCESS);
335 }
336
337 // IBM/MS eject media
338 static void
339 disk_1346(struct bregs *regs, u8 device)
340 {
341     // Volume Not Removable
342     disk_ret(regs, DISK_RET_ENOTREMOVABLE);
343 }
344
345 // IBM/MS extended seek
346 static void
347 disk_1347(struct bregs *regs, u8 device)
348 {
349     extended_access(regs, device, 0);
350 }
351
352 // IBM/MS get drive parameters
353 static void
354 disk_1348(struct bregs *regs, u8 device)
355 {
356     u16 size = GET_INT13DPT(regs, size);
357
358     // Buffer is too small
359     if (size < 0x1a) {
360         disk_ret(regs, DISK_RET_EPARAM);
361         return;
362     }
363
364     // EDD 1.x
365
366     u8  type    = GET_EBDA(ata.devices[device].type);
367     u16 npc     = GET_EBDA(ata.devices[device].pchs.cylinders);
368     u16 nph     = GET_EBDA(ata.devices[device].pchs.heads);
369     u16 npspt   = GET_EBDA(ata.devices[device].pchs.spt);
370     u64 lba     = GET_EBDA(ata.devices[device].sectors);
371     u16 blksize = GET_EBDA(ata.devices[device].blksize);
372
373     SET_INT13DPT(regs, size, 0x1a);
374     if (type == ATA_TYPE_ATA) {
375         if (lba > (u64)npspt*nph*0x3fff) {
376             SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
377             SET_INT13DPT(regs, cylinders, 0x3fff);
378         } else {
379             SET_INT13DPT(regs, infos, 0x02); // geometry is valid
380             SET_INT13DPT(regs, cylinders, (u32)npc);
381         }
382         SET_INT13DPT(regs, heads, (u32)nph);
383         SET_INT13DPT(regs, spt, (u32)npspt);
384         SET_INT13DPT(regs, sector_count, lba);
385     } else {
386         // ATAPI
387         // 0x74 = removable, media change, lockable, max values
388         SET_INT13DPT(regs, infos, 0x74);
389         SET_INT13DPT(regs, cylinders, 0xffffffff);
390         SET_INT13DPT(regs, heads, 0xffffffff);
391         SET_INT13DPT(regs, spt, 0xffffffff);
392         SET_INT13DPT(regs, sector_count, (u64)-1);
393     }
394     SET_INT13DPT(regs, blksize, blksize);
395
396     if (size < 0x1e) {
397         disk_ret(regs, DISK_RET_SUCCESS);
398         return;
399     }
400
401     // EDD 2.x
402
403     SET_INT13DPT(regs, size, 0x1e);
404
405     SET_INT13DPT(regs, dpte_segment, SEG_EBDA);
406     SET_INT13DPT(regs, dpte_offset
407                  , offsetof(struct extended_bios_data_area_s, ata.dpte));
408
409     // Fill in dpte
410     u8 channel = device / 2;
411     u16 iobase1 = GET_EBDA(ata.channels[channel].iobase1);
412     u16 iobase2 = GET_EBDA(ata.channels[channel].iobase2);
413     u8 irq = GET_EBDA(ata.channels[channel].irq);
414     u8 mode = GET_EBDA(ata.devices[device].mode);
415
416     u16 options;
417     if (type == ATA_TYPE_ATA) {
418         u8 translation = GET_EBDA(ata.devices[device].translation);
419         options  = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation
420         options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9;
421         options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9;
422     } else {
423         // ATAPI
424         options  = (1<<5); // removable device
425         options |= (1<<6); // atapi device
426     }
427     options |= (1<<4); // lba translation
428     options |= (mode==ATA_MODE_PIO32?1:0)<<7;
429
430     SET_EBDA(ata.dpte.iobase1, iobase1);
431     SET_EBDA(ata.dpte.iobase2, iobase2 + ATA_CB_DC);
432     SET_EBDA(ata.dpte.prefix, (0xe | (device % 2))<<4 );
433     SET_EBDA(ata.dpte.unused, 0xcb );
434     SET_EBDA(ata.dpte.irq, irq );
435     SET_EBDA(ata.dpte.blkcount, 1 );
436     SET_EBDA(ata.dpte.dma, 0 );
437     SET_EBDA(ata.dpte.pio, 0 );
438     SET_EBDA(ata.dpte.options, options);
439     SET_EBDA(ata.dpte.reserved, 0);
440     if (size >= 0x42)
441         SET_EBDA(ata.dpte.revision, 0x11);
442     else
443         SET_EBDA(ata.dpte.revision, 0x10);
444
445     u8 *p = MAKE_FARPTR(SEG_EBDA
446                         , offsetof(struct extended_bios_data_area_s, ata.dpte));
447     u8 sum = checksum(p, 15);
448     SET_EBDA(ata.dpte.checksum, ~sum);
449
450     if (size < 0x42) {
451         disk_ret(regs, DISK_RET_SUCCESS);
452         return;
453     }
454
455     // EDD 3.x
456     channel = device / 2;
457     u8 iface = GET_EBDA(ata.channels[channel].iface);
458     iobase1 = GET_EBDA(ata.channels[channel].iobase1);
459
460     SET_INT13DPT(regs, size, 0x42);
461     SET_INT13DPT(regs, key, 0xbedd);
462     SET_INT13DPT(regs, dpi_length, 0x24);
463     SET_INT13DPT(regs, reserved1, 0);
464     SET_INT13DPT(regs, reserved2, 0);
465
466     if (iface==ATA_IFACE_ISA) {
467         SET_INT13DPT(regs, host_bus[0], 'I');
468         SET_INT13DPT(regs, host_bus[1], 'S');
469         SET_INT13DPT(regs, host_bus[2], 'A');
470         SET_INT13DPT(regs, host_bus[3], 0);
471     } else {
472         // FIXME PCI
473     }
474     SET_INT13DPT(regs, iface_type[0], 'A');
475     SET_INT13DPT(regs, iface_type[1], 'T');
476     SET_INT13DPT(regs, iface_type[2], 'A');
477     SET_INT13DPT(regs, iface_type[3], 0);
478
479     if (iface==ATA_IFACE_ISA) {
480         SET_INT13DPT(regs, iface_path[0], iobase1);
481         SET_INT13DPT(regs, iface_path[2], 0);
482         SET_INT13DPT(regs, iface_path[4], 0L);
483     } else {
484         // FIXME PCI
485     }
486     SET_INT13DPT(regs, device_path[0], device%2);
487     SET_INT13DPT(regs, device_path[1], 0);
488     SET_INT13DPT(regs, device_path[2], 0);
489     SET_INT13DPT(regs, device_path[4], 0L);
490
491     sum = checksum(MAKE_FARPTR(regs->ds, 30), 34);
492     SET_INT13DPT(regs, checksum, ~sum);
493 }
494
495 // IBM/MS extended media change
496 static void
497 disk_1349(struct bregs *regs, u8 device)
498 {
499     // Always success for HD
500     disk_ret(regs, DISK_RET_SUCCESS);
501 }
502
503 static void
504 disk_134e01(struct bregs *regs, u8 device)
505 {
506     disk_ret(regs, DISK_RET_SUCCESS);
507 }
508
509 static void
510 disk_134e03(struct bregs *regs, u8 device)
511 {
512     disk_ret(regs, DISK_RET_SUCCESS);
513 }
514
515 static void
516 disk_134e04(struct bregs *regs, u8 device)
517 {
518     disk_ret(regs, DISK_RET_SUCCESS);
519 }
520
521 static void
522 disk_134e06(struct bregs *regs, u8 device)
523 {
524     disk_ret(regs, DISK_RET_SUCCESS);
525 }
526
527 static void
528 disk_134eXX(struct bregs *regs, u8 device)
529 {
530     disk_ret(regs, DISK_RET_EPARAM);
531 }
532
533 // IBM/MS set hardware configuration
534 static void
535 disk_134e(struct bregs *regs, u8 device)
536 {
537     switch (regs->al) {
538     case 0x01: disk_134e01(regs, device); break;
539     case 0x03: disk_134e03(regs, device); break;
540     case 0x04: disk_134e04(regs, device); break;
541     case 0x06: disk_134e06(regs, device); break;
542     default:   disk_134eXX(regs, device); break;
543     }
544 }
545
546 void
547 disk_13XX(struct bregs *regs, u8 device)
548 {
549     disk_ret(regs, DISK_RET_EPARAM);
550 }
551
552 void
553 disk_13(struct bregs *regs, u8 device)
554 {
555     //debug_stub(regs);
556
557     // clear completion flag
558     SET_BDA(disk_interrupt_flag, 0);
559
560     switch (regs->ah) {
561     case 0x00: disk_1300(regs, device); break;
562     case 0x01: disk_1301(regs, device); break;
563     case 0x02: disk_1302(regs, device); break;
564     case 0x03: disk_1303(regs, device); break;
565     case 0x04: disk_1304(regs, device); break;
566     case 0x05: disk_1305(regs, device); break;
567     case 0x08: disk_1308(regs, device); break;
568     case 0x09: disk_1309(regs, device); break;
569     case 0x0c: disk_130c(regs, device); break;
570     case 0x0d: disk_130d(regs, device); break;
571     case 0x10: disk_1310(regs, device); break;
572     case 0x11: disk_1311(regs, device); break;
573     case 0x14: disk_1314(regs, device); break;
574     case 0x15: disk_1315(regs, device); break;
575     case 0x41: disk_1341(regs, device); break;
576     case 0x42: disk_1342(regs, device); break;
577     case 0x43: disk_1343(regs, device); break;
578     case 0x44: disk_1344(regs, device); break;
579     case 0x45: disk_1345(regs, device); break;
580     case 0x46: disk_1346(regs, device); break;
581     case 0x47: disk_1347(regs, device); break;
582     case 0x48: disk_1348(regs, device); break;
583     case 0x49: disk_1349(regs, device); break;
584     case 0x4e: disk_134e(regs, device); break;
585     default:   disk_13XX(regs, device); break;
586     }
587 }
588
589
590 /****************************************************************
591  * Entry points
592  ****************************************************************/
593
594 static u8
595 get_device(struct bregs *regs, u8 iscd, u8 drive)
596 {
597     // basic check : device has to be defined
598     if (drive >= CONFIG_MAX_ATA_DEVICES) {
599         disk_ret(regs, DISK_RET_EPARAM);
600         return CONFIG_MAX_ATA_DEVICES;
601     }
602
603     // Get the ata channel
604     u8 device = GET_EBDA(ata.idmap[iscd][drive]);
605
606     // basic check : device has to be valid
607     if (device >= CONFIG_MAX_ATA_DEVICES) {
608         disk_ret(regs, DISK_RET_EPARAM);
609         return CONFIG_MAX_ATA_DEVICES;
610     }
611
612     return device;
613 }
614
615 static void
616 handle_legacy_disk(struct bregs *regs, u8 drive)
617 {
618     if (drive < 0x80) {
619         floppy_13(regs, drive);
620         return;
621     }
622
623     if (! CONFIG_ATA) {
624         // XXX - old code had other disk access method.
625         disk_ret(regs, DISK_RET_EPARAM);
626         return;
627     }
628
629     if (drive >= 0xe0) {
630         u8 device = get_device(regs, 1, drive - 0xe0);
631         if (device >= CONFIG_MAX_ATA_DEVICES)
632             return;
633         cdrom_13(regs, device);
634         return;
635     }
636
637     u8 device = get_device(regs, 0, drive - 0x80);
638     if (device >= CONFIG_MAX_ATA_DEVICES)
639         return;
640     disk_13(regs, device);
641 }
642
643 void VISIBLE16
644 handle_40(struct bregs *regs)
645 {
646     debug_enter(regs, DEBUG_HDL_40);
647     handle_legacy_disk(regs, regs->dl);
648 }
649
650 // INT 13h Fixed Disk Services Entry Point
651 void VISIBLE16
652 handle_13(struct bregs *regs)
653 {
654     debug_enter(regs, DEBUG_HDL_13);
655     u8 drive = regs->dl;
656
657     if (CONFIG_CDROM_EMU) {
658         if (regs->ah == 0x4b) {
659             cdemu_134b(regs);
660             return;
661         }
662         if (GET_EBDA(cdemu.active)) {
663             if (drive == GET_EBDA(cdemu.emulated_drive)) {
664                 cdemu_13(regs);
665                 return;
666             }
667             if (drive < 0xe0)
668                 drive--;
669         }
670     }
671     handle_legacy_disk(regs, drive);
672 }
673
674 // record completion in BIOS task complete flag
675 void VISIBLE16
676 handle_76()
677 {
678     debug_isr(DEBUG_ISR_76);
679     SET_BDA(disk_interrupt_flag, 0xff);
680     eoi_pic2();
681 }