|
|
1.1 root 1: // 16bit code to access hard drives.
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
4: // Copyright (C) 2002 MandrakeSoft S.A.
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 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 "ata.h" // ATA_CB_DC
16:
17:
18: /****************************************************************
19: * Helper functions
20: ****************************************************************/
21:
22: void
23: __disk_ret(struct bregs *regs, u32 linecode, const char *fname)
24: {
25: u8 code = linecode;
26: if (regs->dl < EXTSTART_HD)
27: SET_BDA(floppy_last_status, code);
28: else
29: SET_BDA(disk_last_status, code);
30: if (code)
31: __set_code_invalid(regs, linecode, fname);
32: else
33: set_code_success(regs);
34: }
35:
36: void
37: __disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
38: {
39: u8 code = linecode;
40: if (regs->dl < EXTSTART_HD)
41: SET_BDA(floppy_last_status, code);
42: else
43: SET_BDA(disk_last_status, code);
44: __set_code_unimplemented(regs, linecode, fname);
45: }
46:
47: static void
48: __disk_stub(struct bregs *regs, int lineno, const char *fname)
49: {
50: __warn_unimplemented(regs, lineno, fname);
51: __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
52: }
53:
54: #define DISK_STUB(regs) \
55: __disk_stub((regs), __LINE__, __func__)
56:
57: static void
58: fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
59: {
60: if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive)) {
61: // Emulated drive - get info from ebda. (It's not possible to
62: // populate the geometry directly in the driveid because the
63: // geometry is only known after the bios segment is made
64: // read-only).
65: u16 ebda_seg = get_ebda_seg();
66: *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
67: *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
68: *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
69: return;
70: }
71: *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
72: *nlh = GET_GLOBAL(drive_g->lchs.heads);
73: *nlspt = GET_GLOBAL(drive_g->lchs.spt);
74: }
75:
76: // Perform read/write/verify using old-style chs accesses
77: static void
78: basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
79: {
80: struct disk_op_s dop;
81: dop.drive_g = drive_g;
82: dop.command = command;
83:
84: u8 count = regs->al;
85: u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
86: u16 sector = regs->cl & 0x3f;
87: u16 head = regs->dh;
88:
89: if (count > 128 || count == 0 || sector == 0) {
90: dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
91: , regs->ah);
92: disk_ret(regs, DISK_RET_EPARAM);
93: return;
94: }
95: dop.count = count;
96:
97: u16 nlc, nlh, nlspt;
98: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
99:
100: // sanity check on cyl heads, sec
101: if (cylinder >= nlc || head >= nlh || sector > nlspt) {
102: dprintf(1, "int13_harddisk: function %02x, parameters out of"
103: " range %04x/%04x/%04x!\n"
104: , regs->ah, cylinder, head, sector);
105: disk_ret(regs, DISK_RET_EPARAM);
106: return;
107: }
108:
109: // translate lchs to lba
110: dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
111: + (u32)sector - 1);
112:
113: dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
114:
115: int status = send_disk_op(&dop);
116:
117: regs->al = dop.count;
118:
119: disk_ret(regs, status);
120: }
121:
122: // Perform read/write/verify using new-style "int13ext" accesses.
123: static void
124: extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
125: {
126: struct disk_op_s dop;
127: // Get lba and check.
128: dop.lba = GET_INT13EXT(regs, lba);
129: dop.command = command;
130: dop.drive_g = drive_g;
131: if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
132: dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
133: , regs->ah);
134: disk_ret(regs, DISK_RET_EPARAM);
135: return;
136: }
137:
138: dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
139: dop.count = GET_INT13EXT(regs, count);
140:
141: int status = send_disk_op(&dop);
142:
143: SET_INT13EXT(regs, count, dop.count);
144:
145: disk_ret(regs, status);
146: }
147:
148:
149: /****************************************************************
150: * Hard Drive functions
151: ****************************************************************/
152:
153: // disk controller reset
154: static void
155: disk_1300(struct bregs *regs, struct drive_s *drive_g)
156: {
157: struct disk_op_s dop;
158: dop.drive_g = drive_g;
159: dop.command = CMD_RESET;
160: int status = send_disk_op(&dop);
161: disk_ret(regs, status);
162: }
163:
164: // read disk status
165: static void
166: disk_1301(struct bregs *regs, struct drive_s *drive_g)
167: {
168: u8 v;
169: if (regs->dl < EXTSTART_HD)
170: // Floppy
171: v = GET_BDA(floppy_last_status);
172: else
173: v = GET_BDA(disk_last_status);
174: regs->ah = v;
175: set_cf(regs, v);
176: // XXX - clear disk_last_status?
177: }
178:
179: // read disk sectors
180: static void
181: disk_1302(struct bregs *regs, struct drive_s *drive_g)
182: {
183: basic_access(regs, drive_g, CMD_READ);
184: }
185:
186: // write disk sectors
187: static void
188: disk_1303(struct bregs *regs, struct drive_s *drive_g)
189: {
190: basic_access(regs, drive_g, CMD_WRITE);
191: }
192:
193: // verify disk sectors
194: static void
195: disk_1304(struct bregs *regs, struct drive_s *drive_g)
196: {
197: basic_access(regs, drive_g, CMD_VERIFY);
198: }
199:
200: // format disk track
201: static void
202: disk_1305(struct bregs *regs, struct drive_s *drive_g)
203: {
204: debug_stub(regs);
205:
206: u16 nlc, nlh, nlspt;
207: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
208:
209: u8 num_sectors = regs->al;
210: u8 head = regs->dh;
211:
212: if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
213: disk_ret(regs, DISK_RET_EPARAM);
214: return;
215: }
216:
217: struct disk_op_s dop;
218: dop.drive_g = drive_g;
219: dop.command = CMD_FORMAT;
220: dop.lba = head;
221: dop.count = num_sectors;
222: dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
223: int status = send_disk_op(&dop);
224: disk_ret(regs, status);
225: }
226:
227: // read disk drive parameters
228: static void
229: disk_1308(struct bregs *regs, struct drive_s *drive_g)
230: {
231: u16 ebda_seg = get_ebda_seg();
232: // Get logical geometry from table
233: u16 nlc, nlh, nlspt;
234: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
235: nlc--;
236: nlh--;
237: u8 count;
238: if (regs->dl < EXTSTART_HD) {
239: // Floppy
240: count = GET_GLOBAL(Drives.floppycount);
241:
242: if (CONFIG_CDROM_EMU && drive_g == GET_GLOBAL(cdemu_drive))
243: regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
244: else
245: regs->bx = GET_GLOBAL(drive_g->floppy_type);
246:
247: // set es & di to point to 11 byte diskette param table in ROM
248: regs->es = SEG_BIOS;
249: regs->di = (u32)&diskette_param_table2;
250: } else if (regs->dl < EXTSTART_CD) {
251: // Hard drive
252: count = GET_BDA(hdcount);
253: nlc--; // last sector reserved
254: } else {
255: // Not supported on CDROM
256: disk_ret(regs, DISK_RET_EPARAM);
257: return;
258: }
259:
260: if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
261: u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
262: if (((emudrive ^ regs->dl) & 0x80) == 0)
263: // Note extra drive due to emulation.
264: count++;
265: if (regs->dl < EXTSTART_HD && count > 2)
266: // Max of two floppy drives.
267: count = 2;
268: }
269:
270: regs->al = 0;
271: regs->ch = nlc & 0xff;
272: regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
273: regs->dh = nlh;
274:
275: disk_ret(regs, DISK_RET_SUCCESS);
276: regs->dl = count;
277: }
278:
279: // initialize drive parameters
280: static void
281: disk_1309(struct bregs *regs, struct drive_s *drive_g)
282: {
283: DISK_STUB(regs);
284: }
285:
286: // seek to specified cylinder
287: static void
288: disk_130c(struct bregs *regs, struct drive_s *drive_g)
289: {
290: DISK_STUB(regs);
291: }
292:
293: // alternate disk reset
294: static void
295: disk_130d(struct bregs *regs, struct drive_s *drive_g)
296: {
297: DISK_STUB(regs);
298: }
299:
300: // check drive ready
301: static void
302: disk_1310(struct bregs *regs, struct drive_s *drive_g)
303: {
304: // should look at 40:8E also???
305:
306: struct disk_op_s dop;
307: dop.drive_g = drive_g;
308: dop.command = CMD_ISREADY;
309: int status = send_disk_op(&dop);
310: disk_ret(regs, status);
311: }
312:
313: // recalibrate
314: static void
315: disk_1311(struct bregs *regs, struct drive_s *drive_g)
316: {
317: DISK_STUB(regs);
318: }
319:
320: // controller internal diagnostic
321: static void
322: disk_1314(struct bregs *regs, struct drive_s *drive_g)
323: {
324: DISK_STUB(regs);
325: }
326:
327: // read disk drive size
328: static void
329: disk_1315(struct bregs *regs, struct drive_s *drive_g)
330: {
331: disk_ret(regs, DISK_RET_SUCCESS);
332: if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
333: // Floppy or cdrom
334: regs->ah = 1;
335: return;
336: }
337: // Hard drive
338:
339: // Get logical geometry from table
340: u16 nlc, nlh, nlspt;
341: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
342:
343: // Compute sector count seen by int13
344: u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
345: regs->cx = lba >> 16;
346: regs->dx = lba & 0xffff;
347: regs->ah = 3; // hard disk accessible
348: }
349:
350: static void
351: disk_1316(struct bregs *regs, struct drive_s *drive_g)
352: {
353: if (regs->dl >= EXTSTART_HD) {
354: // Hard drive
355: disk_ret(regs, DISK_RET_EPARAM);
356: return;
357: }
358: disk_ret(regs, DISK_RET_ECHANGED);
359: }
360:
361: // IBM/MS installation check
362: static void
363: disk_1341(struct bregs *regs, struct drive_s *drive_g)
364: {
365: regs->bx = 0xaa55; // install check
366: regs->cx = 0x0007; // ext disk access and edd, removable supported
367: disk_ret(regs, DISK_RET_SUCCESS);
368: regs->ah = 0x30; // EDD 3.0
369: }
370:
371: // IBM/MS extended read
372: static void
373: disk_1342(struct bregs *regs, struct drive_s *drive_g)
374: {
375: extended_access(regs, drive_g, CMD_READ);
376: }
377:
378: // IBM/MS extended write
379: static void
380: disk_1343(struct bregs *regs, struct drive_s *drive_g)
381: {
382: extended_access(regs, drive_g, CMD_WRITE);
383: }
384:
385: // IBM/MS verify
386: static void
387: disk_1344(struct bregs *regs, struct drive_s *drive_g)
388: {
389: extended_access(regs, drive_g, CMD_VERIFY);
390: }
391:
392: // lock
393: static void
394: disk_134500(struct bregs *regs, struct drive_s *drive_g)
395: {
396: u16 ebda_seg = get_ebda_seg();
397: int cdid = regs->dl - EXTSTART_CD;
398: u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
399: if (locks == 0xff) {
400: regs->al = 1;
401: disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
402: return;
403: }
404: SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
405: regs->al = 1;
406: disk_ret(regs, DISK_RET_SUCCESS);
407: }
408:
409: // unlock
410: static void
411: disk_134501(struct bregs *regs, struct drive_s *drive_g)
412: {
413: u16 ebda_seg = get_ebda_seg();
414: int cdid = regs->dl - EXTSTART_CD;
415: u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
416: if (locks == 0x00) {
417: regs->al = 0;
418: disk_ret(regs, DISK_RET_ENOTLOCKED);
419: return;
420: }
421: locks--;
422: SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
423: regs->al = (locks ? 1 : 0);
424: disk_ret(regs, DISK_RET_SUCCESS);
425: }
426:
427: // status
428: static void
429: disk_134502(struct bregs *regs, struct drive_s *drive_g)
430: {
431: int cdid = regs->dl - EXTSTART_CD;
432: u8 locks = GET_EBDA(cdrom_locks[cdid]);
433: regs->al = (locks ? 1 : 0);
434: disk_ret(regs, DISK_RET_SUCCESS);
435: }
436:
437: static void
438: disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
439: {
440: disk_ret_unimplemented(regs, DISK_RET_EPARAM);
441: }
442:
443: // IBM/MS lock/unlock drive
444: static void
445: disk_1345(struct bregs *regs, struct drive_s *drive_g)
446: {
447: if (regs->dl < EXTSTART_CD) {
448: // Always success for HD
449: disk_ret(regs, DISK_RET_SUCCESS);
450: return;
451: }
452:
453: switch (regs->al) {
454: case 0x00: disk_134500(regs, drive_g); break;
455: case 0x01: disk_134501(regs, drive_g); break;
456: case 0x02: disk_134502(regs, drive_g); break;
457: default: disk_1345XX(regs, drive_g); break;
458: }
459: }
460:
461: // IBM/MS eject media
462: static void
463: disk_1346(struct bregs *regs, struct drive_s *drive_g)
464: {
465: if (regs->dl < EXTSTART_CD) {
466: // Volume Not Removable
467: disk_ret(regs, DISK_RET_ENOTREMOVABLE);
468: return;
469: }
470:
471: int cdid = regs->dl - EXTSTART_CD;
472: u8 locks = GET_EBDA(cdrom_locks[cdid]);
473: if (locks != 0) {
474: disk_ret(regs, DISK_RET_ELOCKED);
475: return;
476: }
477:
478: // FIXME should handle 0x31 no media in device
479: // FIXME should handle 0xb5 valid request failed
480:
481: // Call removable media eject
482: struct bregs br;
483: memset(&br, 0, sizeof(br));
484: br.ah = 0x52;
485: call16_int(0x15, &br);
486:
487: if (br.ah || br.flags & F_CF) {
488: disk_ret(regs, DISK_RET_ELOCKED);
489: return;
490: }
491: disk_ret(regs, DISK_RET_SUCCESS);
492: }
493:
494: // IBM/MS extended seek
495: static void
496: disk_1347(struct bregs *regs, struct drive_s *drive_g)
497: {
498: extended_access(regs, drive_g, CMD_SEEK);
499: }
500:
501: // IBM/MS get drive parameters
502: static void
503: disk_1348(struct bregs *regs, struct drive_s *drive_g)
504: {
505: u16 size = GET_INT13DPT(regs, size);
506:
507: // Buffer is too small
508: if (size < 26) {
509: disk_ret(regs, DISK_RET_EPARAM);
510: return;
511: }
512:
513: // EDD 1.x
514:
515: u8 type = GET_GLOBAL(drive_g->type);
516: u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
517: u16 nph = GET_GLOBAL(drive_g->pchs.heads);
518: u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
519: u64 lba = GET_GLOBAL(drive_g->sectors);
520: u16 blksize = GET_GLOBAL(drive_g->blksize);
521:
522: dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
523: , size, type, npc, nph, npspt, (u32)lba, blksize);
524:
525: SET_INT13DPT(regs, size, 26);
526: if (type == DTYPE_ATAPI) {
527: // 0x74 = removable, media change, lockable, max values
528: SET_INT13DPT(regs, infos, 0x74);
529: SET_INT13DPT(regs, cylinders, 0xffffffff);
530: SET_INT13DPT(regs, heads, 0xffffffff);
531: SET_INT13DPT(regs, spt, 0xffffffff);
532: SET_INT13DPT(regs, sector_count, (u64)-1);
533: } else {
534: if (lba > (u64)npspt*nph*0x3fff) {
535: SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
536: SET_INT13DPT(regs, cylinders, 0x3fff);
537: } else {
538: SET_INT13DPT(regs, infos, 0x02); // geometry is valid
539: SET_INT13DPT(regs, cylinders, (u32)npc);
540: }
541: SET_INT13DPT(regs, heads, (u32)nph);
542: SET_INT13DPT(regs, spt, (u32)npspt);
543: SET_INT13DPT(regs, sector_count, lba);
544: }
545: SET_INT13DPT(regs, blksize, blksize);
546:
547: if (size < 30 || (type != DTYPE_ATA && type != DTYPE_ATAPI)) {
548: disk_ret(regs, DISK_RET_SUCCESS);
549: return;
550: }
551:
552: // EDD 2.x
553:
554: u16 ebda_seg = get_ebda_seg();
555: SET_INT13DPT(regs, size, 30);
556:
557: SET_INT13DPT(regs, dpte_segment, ebda_seg);
558: SET_INT13DPT(regs, dpte_offset
559: , offsetof(struct extended_bios_data_area_s, dpte));
560:
561: // Fill in dpte
562: u8 ataid = GET_GLOBAL(drive_g->cntl_id);
563: u8 channel = ataid / 2;
564: u8 slave = ataid % 2;
565: u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1);
566: u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
567: u8 irq = GET_GLOBAL(ATA_channels[channel].irq);
568:
569: u16 options = 0;
570: if (type == DTYPE_ATA) {
571: u8 translation = GET_GLOBAL(drive_g->translation);
572: if (translation != TRANSLATION_NONE) {
573: options |= 1<<3; // CHS translation
574: if (translation == TRANSLATION_LBA)
575: options |= 1<<9;
576: if (translation == TRANSLATION_RECHS)
577: options |= 3<<9;
578: }
579: } else {
580: // ATAPI
581: options |= 1<<5; // removable device
582: options |= 1<<6; // atapi device
583: }
584: options |= 1<<4; // lba translation
585: if (CONFIG_ATA_PIO32)
586: options |= 1<<7;
587:
588: SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
589: SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
590: SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
591: | ATA_CB_DH_LBA));
592: SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
593: SET_EBDA2(ebda_seg, dpte.irq, irq);
594: SET_EBDA2(ebda_seg, dpte.blkcount, 1);
595: SET_EBDA2(ebda_seg, dpte.dma, 0);
596: SET_EBDA2(ebda_seg, dpte.pio, 0);
597: SET_EBDA2(ebda_seg, dpte.options, options);
598: SET_EBDA2(ebda_seg, dpte.reserved, 0);
599: SET_EBDA2(ebda_seg, dpte.revision, 0x11);
600:
601: u8 sum = checksum_far(
602: ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
603: SET_EBDA2(ebda_seg, dpte.checksum, -sum);
604:
605: if (size < 66) {
606: disk_ret(regs, DISK_RET_SUCCESS);
607: return;
608: }
609:
610: // EDD 3.x
611: SET_INT13DPT(regs, key, 0xbedd);
612: SET_INT13DPT(regs, dpi_length, 36);
613: SET_INT13DPT(regs, reserved1, 0);
614: SET_INT13DPT(regs, reserved2, 0);
615:
616: int bdf = GET_GLOBAL(ATA_channels[channel].pci_bdf);
617: if (bdf != -1) {
618: SET_INT13DPT(regs, host_bus[0], 'P');
619: SET_INT13DPT(regs, host_bus[1], 'C');
620: SET_INT13DPT(regs, host_bus[2], 'I');
621: SET_INT13DPT(regs, host_bus[3], 0);
622:
623: u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
624: | (pci_bdf_to_fn(bdf) << 16));
625: SET_INT13DPT(regs, iface_path, path);
626: } else {
627: // ISA
628: SET_INT13DPT(regs, host_bus[0], 'I');
629: SET_INT13DPT(regs, host_bus[1], 'S');
630: SET_INT13DPT(regs, host_bus[2], 'A');
631: SET_INT13DPT(regs, host_bus[3], 0);
632:
633: SET_INT13DPT(regs, iface_path, iobase1);
634: }
635:
636: SET_INT13DPT(regs, iface_type[0], 'A');
637: SET_INT13DPT(regs, iface_type[1], 'T');
638: SET_INT13DPT(regs, iface_type[2], 'A');
639: SET_INT13DPT(regs, iface_type[3], 0);
640: SET_INT13DPT(regs, iface_type[4], 0);
641: SET_INT13DPT(regs, iface_type[5], 0);
642: SET_INT13DPT(regs, iface_type[6], 0);
643: SET_INT13DPT(regs, iface_type[7], 0);
644:
645: SET_INT13DPT(regs, device_path, slave);
646:
647: SET_INT13DPT(regs, checksum
648: , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
649:
650: disk_ret(regs, DISK_RET_SUCCESS);
651: }
652:
653: // IBM/MS extended media change
654: static void
655: disk_1349(struct bregs *regs, struct drive_s *drive_g)
656: {
657: if (regs->dl < EXTSTART_CD) {
658: // Always success for HD
659: disk_ret(regs, DISK_RET_SUCCESS);
660: return;
661: }
662: set_invalid(regs);
663: // always send changed ??
664: regs->ah = DISK_RET_ECHANGED;
665: }
666:
667: static void
668: disk_134e01(struct bregs *regs, struct drive_s *drive_g)
669: {
670: disk_ret(regs, DISK_RET_SUCCESS);
671: }
672:
673: static void
674: disk_134e03(struct bregs *regs, struct drive_s *drive_g)
675: {
676: disk_ret(regs, DISK_RET_SUCCESS);
677: }
678:
679: static void
680: disk_134e04(struct bregs *regs, struct drive_s *drive_g)
681: {
682: disk_ret(regs, DISK_RET_SUCCESS);
683: }
684:
685: static void
686: disk_134e06(struct bregs *regs, struct drive_s *drive_g)
687: {
688: disk_ret(regs, DISK_RET_SUCCESS);
689: }
690:
691: static void
692: disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
693: {
694: disk_ret(regs, DISK_RET_EPARAM);
695: }
696:
697: // IBM/MS set hardware configuration
698: static void
699: disk_134e(struct bregs *regs, struct drive_s *drive_g)
700: {
701: switch (regs->al) {
702: case 0x01: disk_134e01(regs, drive_g); break;
703: case 0x03: disk_134e03(regs, drive_g); break;
704: case 0x04: disk_134e04(regs, drive_g); break;
705: case 0x06: disk_134e06(regs, drive_g); break;
706: default: disk_134eXX(regs, drive_g); break;
707: }
708: }
709:
710: static void
711: disk_13XX(struct bregs *regs, struct drive_s *drive_g)
712: {
713: disk_ret_unimplemented(regs, DISK_RET_EPARAM);
714: }
715:
716: static void
717: disk_13(struct bregs *regs, struct drive_s *drive_g)
718: {
719: //debug_stub(regs);
720:
721: // clear completion flag
722: SET_BDA(disk_interrupt_flag, 0);
723:
724: switch (regs->ah) {
725: case 0x00: disk_1300(regs, drive_g); break;
726: case 0x01: disk_1301(regs, drive_g); break;
727: case 0x02: disk_1302(regs, drive_g); break;
728: case 0x03: disk_1303(regs, drive_g); break;
729: case 0x04: disk_1304(regs, drive_g); break;
730: case 0x05: disk_1305(regs, drive_g); break;
731: case 0x08: disk_1308(regs, drive_g); break;
732: case 0x09: disk_1309(regs, drive_g); break;
733: case 0x0c: disk_130c(regs, drive_g); break;
734: case 0x0d: disk_130d(regs, drive_g); break;
735: case 0x10: disk_1310(regs, drive_g); break;
736: case 0x11: disk_1311(regs, drive_g); break;
737: case 0x14: disk_1314(regs, drive_g); break;
738: case 0x15: disk_1315(regs, drive_g); break;
739: case 0x16: disk_1316(regs, drive_g); break;
740: case 0x41: disk_1341(regs, drive_g); break;
741: case 0x42: disk_1342(regs, drive_g); break;
742: case 0x43: disk_1343(regs, drive_g); break;
743: case 0x44: disk_1344(regs, drive_g); break;
744: case 0x45: disk_1345(regs, drive_g); break;
745: case 0x46: disk_1346(regs, drive_g); break;
746: case 0x47: disk_1347(regs, drive_g); break;
747: case 0x48: disk_1348(regs, drive_g); break;
748: case 0x49: disk_1349(regs, drive_g); break;
749: case 0x4e: disk_134e(regs, drive_g); break;
750: default: disk_13XX(regs, drive_g); break;
751: }
752: }
753:
754: static void
755: floppy_13(struct bregs *regs, struct drive_s *drive_g)
756: {
757: // Only limited commands are supported on floppies.
758: switch (regs->ah) {
759: case 0x00:
760: case 0x01:
761: case 0x02:
762: case 0x03:
763: case 0x04:
764: case 0x05:
765: case 0x08:
766: case 0x15:
767: case 0x16:
768: disk_13(regs, drive_g);
769: break;
770: default: disk_13XX(regs, drive_g); break;
771: }
772: }
773:
774:
775: /****************************************************************
776: * Entry points
777: ****************************************************************/
778:
779: static void
780: handle_legacy_disk(struct bregs *regs, u8 extdrive)
781: {
782: if (! CONFIG_DRIVES) {
783: // XXX - support handle_1301 anyway?
784: disk_ret(regs, DISK_RET_EPARAM);
785: return;
786: }
787:
788: if (extdrive < EXTSTART_HD) {
789: struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
790: if (!drive_g)
791: goto fail;
792: floppy_13(regs, drive_g);
793: return;
794: }
795:
796: struct drive_s *drive_g;
797: if (extdrive >= EXTSTART_CD)
798: drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
799: else
800: drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
801: if (!drive_g)
802: goto fail;
803: disk_13(regs, drive_g);
804: return;
805:
806: fail:
807: // XXX - support 1301/1308/1315 anyway?
808: disk_ret(regs, DISK_RET_EPARAM);
809: }
810:
811: void VISIBLE16
812: handle_40(struct bregs *regs)
813: {
814: debug_enter(regs, DEBUG_HDL_40);
815: handle_legacy_disk(regs, regs->dl);
816: }
817:
818: // INT 13h Fixed Disk Services Entry Point
819: void VISIBLE16
820: handle_13(struct bregs *regs)
821: {
822: debug_enter(regs, DEBUG_HDL_13);
823: u8 extdrive = regs->dl;
824:
825: if (CONFIG_CDROM_EMU) {
826: if (regs->ah == 0x4b) {
827: cdemu_134b(regs);
828: return;
829: }
830: u16 ebda_seg = get_ebda_seg();
831: if (GET_EBDA2(ebda_seg, cdemu.active)) {
832: u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
833: if (extdrive == emudrive) {
834: // Access to an emulated drive.
835: struct drive_s *cdemu = GET_GLOBAL(cdemu_drive);
836: if (regs->ah > 0x16) {
837: // Only old-style commands supported.
838: disk_13XX(regs, cdemu);
839: return;
840: }
841: disk_13(regs, cdemu);
842: return;
843: }
844: if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
845: // Adjust id to make room for emulated drive.
846: extdrive--;
847: }
848: }
849: handle_legacy_disk(regs, extdrive);
850: }
851:
852: // record completion in BIOS task complete flag
853: void VISIBLE16
854: handle_76()
855: {
856: debug_isr(DEBUG_ISR_76);
857: SET_BDA(disk_interrupt_flag, 0xff);
858: eoi_pic2();
859: }
860:
861: // Old Fixed Disk Parameter Table (newer tables are in the ebda).
862: struct fdpt_s OldFDPT VAR16FIXED(0xe401);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.