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