|
|
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: {
1.1.1.3 ! root 61: if (CONFIG_CDROM_EMU
! 62: && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) {
1.1 root 63: // Emulated drive - get info from ebda. (It's not possible to
64: // populate the geometry directly in the driveid because the
65: // geometry is only known after the bios segment is made
66: // read-only).
67: u16 ebda_seg = get_ebda_seg();
68: *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
69: *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
70: *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
71: return;
72: }
73: *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
74: *nlh = GET_GLOBAL(drive_g->lchs.heads);
75: *nlspt = GET_GLOBAL(drive_g->lchs.spt);
76: }
77:
78: // Perform read/write/verify using old-style chs accesses
79: static void
80: basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
81: {
82: struct disk_op_s dop;
83: dop.drive_g = drive_g;
84: dop.command = command;
85:
86: u8 count = regs->al;
87: u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
88: u16 sector = regs->cl & 0x3f;
89: u16 head = regs->dh;
90:
91: if (count > 128 || count == 0 || sector == 0) {
1.1.1.3 ! root 92: warn_invalid(regs);
1.1 root 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) {
1.1.1.3 ! root 103: warn_invalid(regs);
1.1 root 104: disk_ret(regs, DISK_RET_EPARAM);
105: return;
106: }
107:
108: // translate lchs to lba
109: dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
110: + (u32)sector - 1);
111:
112: dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
113:
114: int status = send_disk_op(&dop);
115:
116: regs->al = dop.count;
117:
118: disk_ret(regs, status);
119: }
120:
121: // Perform read/write/verify using new-style "int13ext" accesses.
122: static void
123: extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
124: {
125: struct disk_op_s dop;
126: // Get lba and check.
127: dop.lba = GET_INT13EXT(regs, lba);
128: dop.command = command;
129: dop.drive_g = drive_g;
130: if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
1.1.1.3 ! root 131: warn_invalid(regs);
1.1 root 132: disk_ret(regs, DISK_RET_EPARAM);
133: return;
134: }
135:
136: dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
137: dop.count = GET_INT13EXT(regs, count);
138:
139: int status = send_disk_op(&dop);
140:
141: SET_INT13EXT(regs, count, dop.count);
142:
143: disk_ret(regs, status);
144: }
145:
146:
147: /****************************************************************
148: * Hard Drive functions
149: ****************************************************************/
150:
151: // disk controller reset
152: static void
153: disk_1300(struct bregs *regs, struct drive_s *drive_g)
154: {
155: struct disk_op_s dop;
156: dop.drive_g = drive_g;
157: dop.command = CMD_RESET;
158: int status = send_disk_op(&dop);
159: disk_ret(regs, status);
160: }
161:
162: // read disk status
163: static void
164: disk_1301(struct bregs *regs, struct drive_s *drive_g)
165: {
166: u8 v;
167: if (regs->dl < EXTSTART_HD)
168: // Floppy
169: v = GET_BDA(floppy_last_status);
170: else
171: v = GET_BDA(disk_last_status);
172: regs->ah = v;
173: set_cf(regs, v);
174: // XXX - clear disk_last_status?
175: }
176:
177: // read disk sectors
178: static void
179: disk_1302(struct bregs *regs, struct drive_s *drive_g)
180: {
181: basic_access(regs, drive_g, CMD_READ);
182: }
183:
184: // write disk sectors
185: static void
186: disk_1303(struct bregs *regs, struct drive_s *drive_g)
187: {
188: basic_access(regs, drive_g, CMD_WRITE);
189: }
190:
191: // verify disk sectors
192: static void
193: disk_1304(struct bregs *regs, struct drive_s *drive_g)
194: {
195: basic_access(regs, drive_g, CMD_VERIFY);
196: }
197:
198: // format disk track
199: static void
200: disk_1305(struct bregs *regs, struct drive_s *drive_g)
201: {
202: debug_stub(regs);
203:
204: u16 nlc, nlh, nlspt;
205: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
206:
207: u8 num_sectors = regs->al;
208: u8 head = regs->dh;
209:
210: if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
211: disk_ret(regs, DISK_RET_EPARAM);
212: return;
213: }
214:
215: struct disk_op_s dop;
216: dop.drive_g = drive_g;
217: dop.command = CMD_FORMAT;
218: dop.lba = head;
219: dop.count = num_sectors;
220: dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
221: int status = send_disk_op(&dop);
222: disk_ret(regs, status);
223: }
224:
225: // read disk drive parameters
226: static void
227: disk_1308(struct bregs *regs, struct drive_s *drive_g)
228: {
229: u16 ebda_seg = get_ebda_seg();
230: // Get logical geometry from table
231: u16 nlc, nlh, nlspt;
232: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
233: nlc--;
234: nlh--;
235: u8 count;
236: if (regs->dl < EXTSTART_HD) {
237: // Floppy
238: count = GET_GLOBAL(Drives.floppycount);
239:
1.1.1.3 ! root 240: if (CONFIG_CDROM_EMU
! 241: && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)))
1.1 root 242: regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
243: else
244: regs->bx = GET_GLOBAL(drive_g->floppy_type);
245:
246: // set es & di to point to 11 byte diskette param table in ROM
247: regs->es = SEG_BIOS;
248: regs->di = (u32)&diskette_param_table2;
249: } else if (regs->dl < EXTSTART_CD) {
250: // Hard drive
251: count = GET_BDA(hdcount);
252: nlc--; // last sector reserved
253: } else {
254: // Not supported on CDROM
255: disk_ret(regs, DISK_RET_EPARAM);
256: return;
257: }
258:
259: if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
260: u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
261: if (((emudrive ^ regs->dl) & 0x80) == 0)
262: // Note extra drive due to emulation.
263: count++;
264: if (regs->dl < EXTSTART_HD && count > 2)
265: // Max of two floppy drives.
266: count = 2;
267: }
268:
269: regs->al = 0;
270: regs->ch = nlc & 0xff;
271: regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
272: regs->dh = nlh;
273:
274: disk_ret(regs, DISK_RET_SUCCESS);
275: regs->dl = count;
276: }
277:
278: // initialize drive parameters
279: static void
280: disk_1309(struct bregs *regs, struct drive_s *drive_g)
281: {
282: DISK_STUB(regs);
283: }
284:
285: // seek to specified cylinder
286: static void
287: disk_130c(struct bregs *regs, struct drive_s *drive_g)
288: {
289: DISK_STUB(regs);
290: }
291:
292: // alternate disk reset
293: static void
294: disk_130d(struct bregs *regs, struct drive_s *drive_g)
295: {
296: DISK_STUB(regs);
297: }
298:
299: // check drive ready
300: static void
301: disk_1310(struct bregs *regs, struct drive_s *drive_g)
302: {
303: // should look at 40:8E also???
304:
305: struct disk_op_s dop;
306: dop.drive_g = drive_g;
307: dop.command = CMD_ISREADY;
308: int status = send_disk_op(&dop);
309: disk_ret(regs, status);
310: }
311:
312: // recalibrate
313: static void
314: disk_1311(struct bregs *regs, struct drive_s *drive_g)
315: {
316: DISK_STUB(regs);
317: }
318:
319: // controller internal diagnostic
320: static void
321: disk_1314(struct bregs *regs, struct drive_s *drive_g)
322: {
323: DISK_STUB(regs);
324: }
325:
326: // read disk drive size
327: static void
328: disk_1315(struct bregs *regs, struct drive_s *drive_g)
329: {
330: disk_ret(regs, DISK_RET_SUCCESS);
331: if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
332: // Floppy or cdrom
333: regs->ah = 1;
334: return;
335: }
336: // Hard drive
337:
338: // Get logical geometry from table
339: u16 nlc, nlh, nlspt;
340: fillLCHS(drive_g, &nlc, &nlh, &nlspt);
341:
342: // Compute sector count seen by int13
343: u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
344: regs->cx = lba >> 16;
345: regs->dx = lba & 0xffff;
346: regs->ah = 3; // hard disk accessible
347: }
348:
349: static void
350: disk_1316(struct bregs *regs, struct drive_s *drive_g)
351: {
352: if (regs->dl >= EXTSTART_HD) {
353: // Hard drive
354: disk_ret(regs, DISK_RET_EPARAM);
355: return;
356: }
357: disk_ret(regs, DISK_RET_ECHANGED);
358: }
359:
360: // IBM/MS installation check
361: static void
362: disk_1341(struct bregs *regs, struct drive_s *drive_g)
363: {
364: regs->bx = 0xaa55; // install check
365: regs->cx = 0x0007; // ext disk access and edd, removable supported
366: disk_ret(regs, DISK_RET_SUCCESS);
367: regs->ah = 0x30; // EDD 3.0
368: }
369:
370: // IBM/MS extended read
371: static void
372: disk_1342(struct bregs *regs, struct drive_s *drive_g)
373: {
374: extended_access(regs, drive_g, CMD_READ);
375: }
376:
377: // IBM/MS extended write
378: static void
379: disk_1343(struct bregs *regs, struct drive_s *drive_g)
380: {
381: extended_access(regs, drive_g, CMD_WRITE);
382: }
383:
384: // IBM/MS verify
385: static void
386: disk_1344(struct bregs *regs, struct drive_s *drive_g)
387: {
388: extended_access(regs, drive_g, CMD_VERIFY);
389: }
390:
391: // lock
392: static void
393: disk_134500(struct bregs *regs, struct drive_s *drive_g)
394: {
395: u16 ebda_seg = get_ebda_seg();
396: int cdid = regs->dl - EXTSTART_CD;
397: u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
398: if (locks == 0xff) {
399: regs->al = 1;
400: disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
401: return;
402: }
403: SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
404: regs->al = 1;
405: disk_ret(regs, DISK_RET_SUCCESS);
406: }
407:
408: // unlock
409: static void
410: disk_134501(struct bregs *regs, struct drive_s *drive_g)
411: {
412: u16 ebda_seg = get_ebda_seg();
413: int cdid = regs->dl - EXTSTART_CD;
414: u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
415: if (locks == 0x00) {
416: regs->al = 0;
417: disk_ret(regs, DISK_RET_ENOTLOCKED);
418: return;
419: }
420: locks--;
421: SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
422: regs->al = (locks ? 1 : 0);
423: disk_ret(regs, DISK_RET_SUCCESS);
424: }
425:
426: // status
427: static void
428: disk_134502(struct bregs *regs, struct drive_s *drive_g)
429: {
430: int cdid = regs->dl - EXTSTART_CD;
431: u8 locks = GET_EBDA(cdrom_locks[cdid]);
432: regs->al = (locks ? 1 : 0);
433: disk_ret(regs, DISK_RET_SUCCESS);
434: }
435:
436: static void
437: disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
438: {
439: disk_ret_unimplemented(regs, DISK_RET_EPARAM);
440: }
441:
442: // IBM/MS lock/unlock drive
443: static void
444: disk_1345(struct bregs *regs, struct drive_s *drive_g)
445: {
446: if (regs->dl < EXTSTART_CD) {
447: // Always success for HD
448: disk_ret(regs, DISK_RET_SUCCESS);
449: return;
450: }
451:
452: switch (regs->al) {
453: case 0x00: disk_134500(regs, drive_g); break;
454: case 0x01: disk_134501(regs, drive_g); break;
455: case 0x02: disk_134502(regs, drive_g); break;
456: default: disk_1345XX(regs, drive_g); break;
457: }
458: }
459:
460: // IBM/MS eject media
461: static void
462: disk_1346(struct bregs *regs, struct drive_s *drive_g)
463: {
464: if (regs->dl < EXTSTART_CD) {
465: // Volume Not Removable
466: disk_ret(regs, DISK_RET_ENOTREMOVABLE);
467: return;
468: }
469:
470: int cdid = regs->dl - EXTSTART_CD;
471: u8 locks = GET_EBDA(cdrom_locks[cdid]);
472: if (locks != 0) {
473: disk_ret(regs, DISK_RET_ELOCKED);
474: return;
475: }
476:
477: // FIXME should handle 0x31 no media in device
478: // FIXME should handle 0xb5 valid request failed
479:
480: // Call removable media eject
481: struct bregs br;
482: memset(&br, 0, sizeof(br));
483: br.ah = 0x52;
1.1.1.3 ! root 484: br.dl = regs->dl;
1.1 root 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
1.1.1.3 ! root 562: struct atadrive_s *adrive_g = container_of(
! 563: drive_g, struct atadrive_s, drive);
! 564: struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
! 565: u8 slave = GET_GLOBAL(adrive_g->slave);
! 566: u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
! 567: u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
! 568: u8 irq = GET_GLOBALFLAT(chan_gf->irq);
1.1 root 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:
1.1.1.3 ! root 617: int bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
1.1 root 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.
1.1.1.3 ! root 836: struct drive_s *cdemu_g;
! 837: cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
1.1 root 838: if (regs->ah > 0x16) {
839: // Only old-style commands supported.
1.1.1.3 ! root 840: disk_13XX(regs, cdemu_g);
1.1 root 841: return;
842: }
1.1.1.3 ! root 843: disk_13(regs, cdemu_g);
1.1 root 844: return;
845: }
846: if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
847: // Adjust id to make room for emulated drive.
848: extdrive--;
849: }
850: }
851: handle_legacy_disk(regs, extdrive);
852: }
853:
854: // record completion in BIOS task complete flag
855: void VISIBLE16
1.1.1.2 root 856: handle_76(void)
1.1 root 857: {
858: debug_isr(DEBUG_ISR_76);
859: SET_BDA(disk_interrupt_flag, 0xff);
860: eoi_pic2();
861: }
862:
863: // Old Fixed Disk Parameter Table (newer tables are in the ebda).
864: 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.