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