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