|
|
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
1.1.1.4 ! root 238: count = GET_GLOBAL(FloppyCount);
1.1 root 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);
1.1.1.4 ! root 506: u16 t13 = size == 74;
1.1 root 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:
1.1.1.4 ! root 548: if (size < 30 ||
! 549: (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) {
1.1 root 550: disk_ret(regs, DISK_RET_SUCCESS);
551: return;
552: }
553:
554: // EDD 2.x
555:
1.1.1.4 ! root 556: int bdf;
! 557: u16 iobase1 = 0;
! 558: u64 device_path = 0;
! 559: u8 channel = 0;
1.1 root 560: SET_INT13DPT(regs, size, 30);
1.1.1.4 ! root 561: if (type == DTYPE_ATA || type == DTYPE_ATAPI) {
! 562: u16 ebda_seg = get_ebda_seg();
1.1 root 563:
1.1.1.4 ! root 564: SET_INT13DPT(regs, dpte_segment, ebda_seg);
! 565: SET_INT13DPT(regs, dpte_offset
! 566: , offsetof(struct extended_bios_data_area_s, dpte));
! 567:
! 568: // Fill in dpte
! 569: struct atadrive_s *adrive_g = container_of(
! 570: drive_g, struct atadrive_s, drive);
! 571: struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
! 572: u8 slave = GET_GLOBAL(adrive_g->slave);
! 573: u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
! 574: u8 irq = GET_GLOBALFLAT(chan_gf->irq);
! 575: iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
! 576: bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
! 577: device_path = slave;
! 578: channel = GET_GLOBALFLAT(chan_gf->chanid);
! 579:
! 580: u16 options = 0;
! 581: if (type == DTYPE_ATA) {
! 582: u8 translation = GET_GLOBAL(drive_g->translation);
! 583: if (translation != TRANSLATION_NONE) {
! 584: options |= 1<<3; // CHS translation
! 585: if (translation == TRANSLATION_LBA)
! 586: options |= 1<<9;
! 587: if (translation == TRANSLATION_RECHS)
! 588: options |= 3<<9;
! 589: }
! 590: } else {
! 591: // ATAPI
! 592: options |= 1<<5; // removable device
! 593: options |= 1<<6; // atapi device
1.1 root 594: }
1.1.1.4 ! root 595: options |= 1<<4; // lba translation
! 596: if (CONFIG_ATA_PIO32)
! 597: options |= 1<<7;
! 598:
! 599: SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
! 600: SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
! 601: SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
! 602: | ATA_CB_DH_LBA));
! 603: SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
! 604: SET_EBDA2(ebda_seg, dpte.irq, irq);
! 605: SET_EBDA2(ebda_seg, dpte.blkcount, 1);
! 606: SET_EBDA2(ebda_seg, dpte.dma, 0);
! 607: SET_EBDA2(ebda_seg, dpte.pio, 0);
! 608: SET_EBDA2(ebda_seg, dpte.options, options);
! 609: SET_EBDA2(ebda_seg, dpte.reserved, 0);
! 610: SET_EBDA2(ebda_seg, dpte.revision, 0x11);
! 611:
! 612: u8 sum = checksum_far(
! 613: ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
! 614: SET_EBDA2(ebda_seg, dpte.checksum, -sum);
1.1 root 615: } else {
1.1.1.4 ! root 616: SET_INT13DPT(regs, dpte_segment, 0);
! 617: SET_INT13DPT(regs, dpte_offset, 0);
! 618: bdf = GET_GLOBAL(drive_g->cntl_id);
! 619: }
1.1 root 620:
621: if (size < 66) {
622: disk_ret(regs, DISK_RET_SUCCESS);
623: return;
624: }
625:
626: // EDD 3.x
627: SET_INT13DPT(regs, key, 0xbedd);
1.1.1.4 ! root 628: SET_INT13DPT(regs, dpi_length, t13 ? 44 : 36);
1.1 root 629: SET_INT13DPT(regs, reserved1, 0);
630: SET_INT13DPT(regs, reserved2, 0);
631:
632: if (bdf != -1) {
633: SET_INT13DPT(regs, host_bus[0], 'P');
634: SET_INT13DPT(regs, host_bus[1], 'C');
635: SET_INT13DPT(regs, host_bus[2], 'I');
1.1.1.4 ! root 636: SET_INT13DPT(regs, host_bus[3], ' ');
1.1 root 637:
638: u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
639: | (pci_bdf_to_fn(bdf) << 16));
1.1.1.4 ! root 640: if (t13)
! 641: path |= channel << 24;
! 642:
1.1 root 643: SET_INT13DPT(regs, iface_path, path);
644: } else {
645: // ISA
646: SET_INT13DPT(regs, host_bus[0], 'I');
647: SET_INT13DPT(regs, host_bus[1], 'S');
648: SET_INT13DPT(regs, host_bus[2], 'A');
1.1.1.4 ! root 649: SET_INT13DPT(regs, host_bus[3], ' ');
1.1 root 650:
651: SET_INT13DPT(regs, iface_path, iobase1);
652: }
653:
1.1.1.4 ! root 654: if (type != DTYPE_VIRTIO) {
! 655: SET_INT13DPT(regs, iface_type[0], 'A');
! 656: SET_INT13DPT(regs, iface_type[1], 'T');
! 657: SET_INT13DPT(regs, iface_type[2], 'A');
! 658: SET_INT13DPT(regs, iface_type[3], ' ');
! 659: } else {
! 660: SET_INT13DPT(regs, iface_type[0], 'S');
! 661: SET_INT13DPT(regs, iface_type[1], 'C');
! 662: SET_INT13DPT(regs, iface_type[2], 'S');
! 663: SET_INT13DPT(regs, iface_type[3], 'I');
! 664: }
! 665: SET_INT13DPT(regs, iface_type[4], ' ');
! 666: SET_INT13DPT(regs, iface_type[5], ' ');
! 667: SET_INT13DPT(regs, iface_type[6], ' ');
! 668: SET_INT13DPT(regs, iface_type[7], ' ');
! 669:
! 670: if (t13) {
! 671: SET_INT13DPT(regs, t13.device_path[0], device_path);
! 672: SET_INT13DPT(regs, t13.device_path[1], 0);
1.1 root 673:
1.1.1.4 ! root 674: SET_INT13DPT(regs, t13.checksum
! 675: , -checksum_far(regs->ds, (void*)(regs->si+30), 43));
! 676: } else {
! 677: SET_INT13DPT(regs, phoenix.device_path, device_path);
1.1 root 678:
1.1.1.4 ! root 679: SET_INT13DPT(regs, phoenix.checksum
! 680: , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
! 681: }
1.1 root 682:
683: disk_ret(regs, DISK_RET_SUCCESS);
684: }
685:
686: // IBM/MS extended media change
687: static void
688: disk_1349(struct bregs *regs, struct drive_s *drive_g)
689: {
690: if (regs->dl < EXTSTART_CD) {
691: // Always success for HD
692: disk_ret(regs, DISK_RET_SUCCESS);
693: return;
694: }
695: set_invalid(regs);
696: // always send changed ??
697: regs->ah = DISK_RET_ECHANGED;
698: }
699:
700: static void
701: disk_134e01(struct bregs *regs, struct drive_s *drive_g)
702: {
703: disk_ret(regs, DISK_RET_SUCCESS);
704: }
705:
706: static void
707: disk_134e03(struct bregs *regs, struct drive_s *drive_g)
708: {
709: disk_ret(regs, DISK_RET_SUCCESS);
710: }
711:
712: static void
713: disk_134e04(struct bregs *regs, struct drive_s *drive_g)
714: {
715: disk_ret(regs, DISK_RET_SUCCESS);
716: }
717:
718: static void
719: disk_134e06(struct bregs *regs, struct drive_s *drive_g)
720: {
721: disk_ret(regs, DISK_RET_SUCCESS);
722: }
723:
724: static void
725: disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
726: {
727: disk_ret(regs, DISK_RET_EPARAM);
728: }
729:
730: // IBM/MS set hardware configuration
731: static void
732: disk_134e(struct bregs *regs, struct drive_s *drive_g)
733: {
734: switch (regs->al) {
735: case 0x01: disk_134e01(regs, drive_g); break;
736: case 0x03: disk_134e03(regs, drive_g); break;
737: case 0x04: disk_134e04(regs, drive_g); break;
738: case 0x06: disk_134e06(regs, drive_g); break;
739: default: disk_134eXX(regs, drive_g); break;
740: }
741: }
742:
743: static void
744: disk_13XX(struct bregs *regs, struct drive_s *drive_g)
745: {
746: disk_ret_unimplemented(regs, DISK_RET_EPARAM);
747: }
748:
749: static void
750: disk_13(struct bregs *regs, struct drive_s *drive_g)
751: {
752: //debug_stub(regs);
753:
754: // clear completion flag
755: SET_BDA(disk_interrupt_flag, 0);
756:
757: switch (regs->ah) {
758: case 0x00: disk_1300(regs, drive_g); break;
759: case 0x01: disk_1301(regs, drive_g); break;
760: case 0x02: disk_1302(regs, drive_g); break;
761: case 0x03: disk_1303(regs, drive_g); break;
762: case 0x04: disk_1304(regs, drive_g); break;
763: case 0x05: disk_1305(regs, drive_g); break;
764: case 0x08: disk_1308(regs, drive_g); break;
765: case 0x09: disk_1309(regs, drive_g); break;
766: case 0x0c: disk_130c(regs, drive_g); break;
767: case 0x0d: disk_130d(regs, drive_g); break;
768: case 0x10: disk_1310(regs, drive_g); break;
769: case 0x11: disk_1311(regs, drive_g); break;
770: case 0x14: disk_1314(regs, drive_g); break;
771: case 0x15: disk_1315(regs, drive_g); break;
772: case 0x16: disk_1316(regs, drive_g); break;
773: case 0x41: disk_1341(regs, drive_g); break;
774: case 0x42: disk_1342(regs, drive_g); break;
775: case 0x43: disk_1343(regs, drive_g); break;
776: case 0x44: disk_1344(regs, drive_g); break;
777: case 0x45: disk_1345(regs, drive_g); break;
778: case 0x46: disk_1346(regs, drive_g); break;
779: case 0x47: disk_1347(regs, drive_g); break;
780: case 0x48: disk_1348(regs, drive_g); break;
781: case 0x49: disk_1349(regs, drive_g); break;
782: case 0x4e: disk_134e(regs, drive_g); break;
783: default: disk_13XX(regs, drive_g); break;
784: }
785: }
786:
787: static void
788: floppy_13(struct bregs *regs, struct drive_s *drive_g)
789: {
790: // Only limited commands are supported on floppies.
791: switch (regs->ah) {
792: case 0x00:
793: case 0x01:
794: case 0x02:
795: case 0x03:
796: case 0x04:
797: case 0x05:
798: case 0x08:
799: case 0x15:
800: case 0x16:
801: disk_13(regs, drive_g);
802: break;
803: default: disk_13XX(regs, drive_g); break;
804: }
805: }
806:
807:
808: /****************************************************************
809: * Entry points
810: ****************************************************************/
811:
812: static void
813: handle_legacy_disk(struct bregs *regs, u8 extdrive)
814: {
815: if (! CONFIG_DRIVES) {
816: // XXX - support handle_1301 anyway?
817: disk_ret(regs, DISK_RET_EPARAM);
818: return;
819: }
820:
821: if (extdrive < EXTSTART_HD) {
822: struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
823: if (!drive_g)
824: goto fail;
825: floppy_13(regs, drive_g);
826: return;
827: }
828:
829: struct drive_s *drive_g;
830: if (extdrive >= EXTSTART_CD)
831: drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
832: else
833: drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
834: if (!drive_g)
835: goto fail;
836: disk_13(regs, drive_g);
837: return;
838:
839: fail:
840: // XXX - support 1301/1308/1315 anyway?
841: disk_ret(regs, DISK_RET_EPARAM);
842: }
843:
844: void VISIBLE16
845: handle_40(struct bregs *regs)
846: {
847: debug_enter(regs, DEBUG_HDL_40);
848: handle_legacy_disk(regs, regs->dl);
849: }
850:
851: // INT 13h Fixed Disk Services Entry Point
852: void VISIBLE16
853: handle_13(struct bregs *regs)
854: {
855: debug_enter(regs, DEBUG_HDL_13);
856: u8 extdrive = regs->dl;
857:
858: if (CONFIG_CDROM_EMU) {
859: if (regs->ah == 0x4b) {
860: cdemu_134b(regs);
861: return;
862: }
863: u16 ebda_seg = get_ebda_seg();
864: if (GET_EBDA2(ebda_seg, cdemu.active)) {
865: u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
866: if (extdrive == emudrive) {
867: // Access to an emulated drive.
1.1.1.3 root 868: struct drive_s *cdemu_g;
869: cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
1.1 root 870: if (regs->ah > 0x16) {
871: // Only old-style commands supported.
1.1.1.3 root 872: disk_13XX(regs, cdemu_g);
1.1 root 873: return;
874: }
1.1.1.3 root 875: disk_13(regs, cdemu_g);
1.1 root 876: return;
877: }
878: if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
879: // Adjust id to make room for emulated drive.
880: extdrive--;
881: }
882: }
883: handle_legacy_disk(regs, extdrive);
884: }
885:
886: // record completion in BIOS task complete flag
887: void VISIBLE16
1.1.1.2 root 888: handle_76(void)
1.1 root 889: {
890: debug_isr(DEBUG_ISR_76);
891: SET_BDA(disk_interrupt_flag, 0xff);
892: eoi_pic2();
893: }
894:
895: // Old Fixed Disk Parameter Table (newer tables are in the ebda).
896: 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.