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