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