void printer_bop_flush(void) { #ifdef PRINTER int adapter; adapter = sas_hw_at_no_check(lp16BitPrtId); if (host_print_buffer (adapter) == FALSE) setAH(0x08); /* IO error */ else setAH(0x90); /* Success */ return; #endif }
BOOLEAN DosCheckInput(VOID) { HANDLE Handle = DosGetRealHandle(DOS_INPUT_HANDLE); if (IsConsoleHandle(Handle)) { /* Save AX */ USHORT AX = getAX(); /* Call the BIOS */ setAH(0x01); // or 0x11 for enhanced, but what to choose? Int32Call(&DosContext, BIOS_KBD_INTERRUPT); /* Restore AX */ setAX(AX); /* Return keyboard status */ return (getZF() == 0); } else { DWORD FileSizeHigh; DWORD FileSize = GetFileSize(Handle, &FileSizeHigh); LONG LocationHigh = 0; DWORD Location = SetFilePointer(Handle, 0, &LocationHigh, FILE_CURRENT); return ((Location != FileSize) || (LocationHigh != FileSizeHigh)); } }
void bootstrap3() { char *p; char error_str[80]; if (getCF()) { /* * Write error on PC screen - assumes reset has positioned the * cursor for us. Note that we can call the video using a BOP since * the video code does not itself use interrupts. */ sprintf(error_str,"DOS boot error - cannot open hard disk file"); p = error_str; while (*p != '\0') { setAH(14); setAL(*p++); bop(BIOS_VIDEO_IO); } } /* * enable hardware interrupts before we jump to DOS */ setIF(1); }
void bootstrap2() { /* * If the Carry Flag is set then the previous read failed and we go and * try the hard disk. */ if (getCF()) { /* * Load up the registers to call the disk routine that will load * the first sector of DOS into memory. This ALWAYS resides on the * first sector of the disk. */ setAH(2); /* Read sector */ setAL(1); /* 1 block */ setCH(0); /* Cylinder 0 */ setCL(1); /* Sector 1 */ setDH(0); /* Head 0 */ setDL(0x80); /* Hard disk */ setES(DOS_SEGMENT); /* Load address */ setBX(DOS_OFFSET); } }
void bootstrap1() { /* * Try and read the first sector off the diskette */ setAH(2); /* read */ setAL(1); /* 1 block */ #ifdef SECURE if ((IBOOL) config_inquire(C_SECURE, NULL)) { setDH(0); /* Head 0 */ setDL(0x80); /* on Hard Disk */ } else { setDX(0); /* head 0 on drive 0 (floppy)*/ } #else setDX(0); /* head 0 on drive 0 (floppy)*/ #endif setCX(1); /* track 0, sector 1 */ setES(DOS_SEGMENT); /* Load address */ setBX(DOS_OFFSET); }
static void return_status() { inb(port + (io_addr) RS232_LSR, &value); setAH(value); inb(port + (io_addr) RS232_MSR, &value); setAL(value); }
void MsBopB(){ switch (getAH()) { case 0 : setAH(0); while (!tkbhit()); setAL((BYTE)tgetch()); break; case 1 : tputch(getAL()); break; } }
VOID BiosCharPrint(CHAR Character) { /* Save AX and BX */ USHORT AX = getAX(); USHORT BX = getBX(); /* * Set the parameters: * AL contains the character to print, * BL contains the character attribute, * BH contains the video page to use. */ setAL(Character); setBL(DEFAULT_ATTRIBUTE); setBH(Bda->VideoPage); /* Call the BIOS INT 10h, AH=0Eh "Teletype Output" */ setAH(0x0E); Int32Call(&DosContext, BIOS_VIDEO_INTERRUPT); /* Restore AX and BX */ setBX(BX); setAX(AX); }
int main(int argc, char* argv[]) { if (argc < 2) { printf("Usage: %s <program name>\n", argv[0]); exit(0); } filename = argv[1]; FILE* fp = fopen(filename, "rb"); if (fp == 0) error("opening"); ram = (Byte*)malloc(0x10000); memset(ram, 0, 0x10000); if (ram == 0) { fprintf(stderr, "Out of memory\n"); exit(1); } if (fseek(fp, 0, SEEK_END) != 0) error("seeking"); length = ftell(fp); if (length == -1) error("telling"); if (fseek(fp, 0, SEEK_SET) != 0) error("seeking"); if (length > 0x10000 - 0x100) { fprintf(stderr, "%s is too long to be a .com file\n", filename); exit(1); } if (fread(&ram[0x100], length, 1, fp) != 1) error("reading"); fclose(fp); Word segment = 0x1000; setAX(0x0000); setCX(0x00FF); setDX(segment); registers[3] = 0x0000; setSP(0xFFFE); registers[5] = 0x091C; setSI(0x0100); setDI(0xFFFE); for (int i = 0; i < 4; ++i) registers[8 + i] = segment; Byte* byteData = (Byte*)®isters[0]; int bigEndian = (byteData[2] == 0 ? 1 : 0); int byteNumbers[8] = {0, 2, 4, 6, 1, 3, 5, 7}; for (int i = 0 ; i < 8; ++i) byteRegisters[i] = &byteData[byteNumbers[i] ^ bigEndian]; bool prefix = false; for (int i = 0; i < 1000000000; ++i) { if (!repeating) { if (!prefix) { segmentOverride = -1; rep = 0; } prefix = false; opcode = fetchByte(); } wordSize = ((opcode & 1) != 0); bool sourceIsRM = ((opcode & 2) != 0); int operation = (opcode >> 3) & 7; bool jump; switch (opcode) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x10: case 0x11: case 0x12: case 0x13: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x20: case 0x21: case 0x22: case 0x23: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x30: case 0x31: case 0x32: case 0x33: case 0x38: case 0x39: case 0x3a: case 0x3b: // alu rmv,rmv data = readEA(); if (!sourceIsRM) { destination = data; source = getReg(); } else { destination = getReg(); source = data; } aluOperation = operation; doALUOperation(); if (aluOperation != 7) { if (!sourceIsRM) finishWriteEA(data); else setReg(data); } break; case 0x04: case 0x05: case 0x0c: case 0x0d: case 0x14: case 0x15: case 0x1c: case 0x1d: case 0x24: case 0x25: case 0x2c: case 0x2d: case 0x34: case 0x35: case 0x3c: case 0x3d: // alu accum,i destination = getAccum(); source = !wordSize ? fetchByte() : fetchWord(); aluOperation = operation; doALUOperation(); if (aluOperation != 7) setAccum(); break; case 0x06: case 0x0e: case 0x16: case 0x1e: // PUSH segreg push(registers[operation + 8]); break; case 0x07: case 0x17: case 0x1f: // POP segreg registers[operation + 8] = pop(); break; case 0x26: case 0x2e: case 0x36: case 0x3e: // segment override segmentOverride = operation; prefix = true; break; case 0x27: case 0x2f: // DA if (af() || (al() & 0x0f) > 9) { data = al() + (opcode == 0x27 ? 6 : -6); setAL(data); setAF(true); if ((data & 0x100) != 0) setCF(true); } setCF(cf() || al() > 0x9f); if (cf()) setAL(al() + (opcode == 0x27 ? 0x60 : -0x60)); wordSize = false; data = al(); setPZS(); break; case 0x37: case 0x3f: // AA if (af() || (al() & 0xf) > 9) { setAL(al() + (opcode == 0x37 ? 6 : -6)); setAH(ah() + (opcode == 0x37 ? 1 : -1)); setCA(); } else clearCA(); setAL(al() & 0x0f); break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: // incdec rw destination = rw(); wordSize = true; setRW(incdec((opcode & 8) != 0)); break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: // PUSH rw push(rw()); break; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: // POP rw setRW(pop()); break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: case 0xc0: case 0xc1: case 0xc8: case 0xc9: // invalid case 0xcc: case 0xf0: case 0xf1: case 0xf4: // INT 3, LOCK, HLT case 0x9b: case 0xce: case 0x0f: // WAIT, INTO, POP CS case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: // escape case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: // IN, OUT fprintf(stderr, "Invalid opcode %02x", opcode); runtimeError(""); break; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // Jcond cb switch (opcode & 0x0e) { case 0x00: jump = of(); break; case 0x02: jump = cf(); break; case 0x04: jump = zf(); break; case 0x06: jump = cf() || zf(); break; case 0x08: jump = sf(); break; case 0x0a: jump = pf(); break; case 0x0c: jump = sf() != of(); break; default: jump = sf() != of() || zf(); break; } jumpShort(fetchByte(), jump == ((opcode & 1) == 0)); break; case 0x80: case 0x81: case 0x82: case 0x83: // alu rmv,iv destination = readEA(); data = fetch(opcode == 0x81); if (opcode != 0x83) source = data; else source = signExtend(data); aluOperation = modRMReg(); doALUOperation(); if (aluOperation != 7) finishWriteEA(data); break; case 0x84: case 0x85: // TEST rmv,rv data = readEA(); test(data, getReg()); break; case 0x86: case 0x87: // XCHG rmv,rv data = readEA(); finishWriteEA(getReg()); setReg(data); break; case 0x88: case 0x89: // MOV rmv,rv ea(); finishWriteEA(getReg()); break; case 0x8a: case 0x8b: // MOV rv,rmv setReg(readEA()); break; case 0x8c: // MOV rmw,segreg ea(); wordSize = 1; finishWriteEA(registers[modRMReg() + 8]); break; case 0x8d: // LEA address = ea(); if (!useMemory) runtimeError("LEA needs a memory address"); setReg(address); break; case 0x8e: // MOV segreg,rmw wordSize = 1; data = readEA(); registers[modRMReg() + 8] = data; break; case 0x8f: // POP rmw writeEA(pop()); break; case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: // XCHG AX,rw data = ax(); setAX(rw()); setRW(data); break; case 0x98: // CBW setAX(signExtend(al())); break; case 0x99: // CWD setDX((ax() & 0x8000) == 0 ? 0x0000 : 0xffff); break; case 0x9a: // CALL cp savedIP = fetchWord(); savedCS = fetchWord(); farCall(); break; case 0x9c: // PUSHF push((flags & 0x0fd7) | 0xf000); break; case 0x9d: // POPF flags = pop() | 2; break; case 0x9e: // SAHF flags = (flags & 0xff02) | ah(); break; case 0x9f: // LAHF setAH(flags & 0xd7); break; case 0xa0: case 0xa1: // MOV accum,xv data = read(fetchWord()); setAccum(); break; case 0xa2: case 0xa3: // MOV xv,accum write(getAccum(), fetchWord()); break; case 0xa4: case 0xa5: // MOVSv stoS(lodS()); doRep(); break; case 0xa6: case 0xa7: // CMPSv lodDIS(); source = data; sub(); doRep(); break; case 0xa8: case 0xa9: // TEST accum,iv data = fetch(wordSize); test(getAccum(), data); break; case 0xaa: case 0xab: // STOSv stoS(getAccum()); doRep(); break; case 0xac: case 0xad: // LODSv data = lodS(); setAccum(); doRep(); break; case 0xae: case 0xaf: // SCASv lodDIS(); destination = getAccum(); source = data; sub(); doRep(); break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: setRB(fetchByte()); break; case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: // MOV rv,iv setRW(fetchWord()); break; case 0xc2: case 0xc3: case 0xca: case 0xcb: // RET savedIP = pop(); savedCS = (opcode & 8) == 0 ? cs() : pop(); if (!wordSize) setSP(sp() + fetchWord()); farJump(); break; case 0xc4: case 0xc5: // LES/LDS ea(); farLoad(); *modRMRW() = savedIP; registers[8 + (!wordSize ? 0 : 3)] = savedCS; break; case 0xc6: case 0xc7: // MOV rmv,iv ea(); finishWriteEA(fetch(wordSize)); break; case 0xcd: data = fetchByte(); if (data != 0x21) { fprintf(stderr, "Unknown interrupt 0x%02x", data); runtimeError(""); } switch (ah()) { case 2: printf("%c", dl()); break; case 0x4c: printf("*** Bytes: %i\n", length); printf("*** Cycles: %i\n", ios); printf("*** EXIT code %i\n", al()); exit(0); break; default: fprintf(stderr, "Unknown DOS call 0x%02x", data); runtimeError(""); } break; case 0xcf: ip = pop(); setCS(pop()); flags = pop() | 2; break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: // rot rmv,n data = readEA(); if ((opcode & 2) == 0) source = 1; else source = cl(); while (source != 0) { destination = data; switch (modRMReg()) { case 0: // ROL data <<= 1; doCF(); data |= (cf() ? 1 : 0); setOFRotate(); break; case 1: // ROR setCF((data & 1) != 0); data >>= 1; if (cf()) data |= (!wordSize ? 0x80 : 0x8000); setOFRotate(); break; case 2: // RCL data = (data << 1) | (cf() ? 1 : 0); doCF(); setOFRotate(); break; case 3: // RCR data >>= 1; if (cf()) data |= (!wordSize ? 0x80 : 0x8000); setCF((destination & 1) != 0); setOFRotate(); break; case 4: // SHL case 6: data <<= 1; doCF(); setOFRotate(); setPZS(); break; case 5: // SHR setCF((data & 1) != 0); data >>= 1; setOFRotate(); setAF(true); setPZS(); break; case 7: // SAR setCF((data & 1) != 0); data >>= 1; if (!wordSize) data |= (destination & 0x80); else data |= (destination & 0x8000); setOFRotate(); setAF(true); setPZS(); break; } --source; } finishWriteEA(data); break; case 0xd4: // AAM data = fetchByte(); if (data == 0) divideOverflow(); setAH(al() / data); setAL(al() % data); wordSize = true; setPZS(); break; case 0xd5: // AAD data = fetchByte(); setAL(al() + ah()*data); setAH(0); setPZS(); break; case 0xd6: // SALC setAL(cf() ? 0xff : 0x00); break; case 0xd7: // XLATB setAL(readByte(bx() + al())); break; case 0xe0: case 0xe1: case 0xe2: // LOOPc cb setCX(cx() - 1); jump = (cx() != 0); switch (opcode) { case 0xe0: if (zf()) jump = false; break; case 0xe1: if (!zf()) jump = false; break; } jumpShort(fetchByte(), jump); break; case 0xe3: // JCXZ cb jumpShort(fetchByte(), cx() == 0); break; case 0xe8: // CALL cw call(ip + fetchWord()); break; case 0xe9: // JMP cw ip += fetchWord(); break; case 0xea: // JMP cp savedIP = fetchWord(); savedCS = fetchWord(); farJump(); break; case 0xeb: // JMP cb jumpShort(fetchByte(), true); break; case 0xf2: case 0xf3: // REP rep = opcode == 0xf2 ? 1 : 2; prefix = true; break; case 0xf5: // CMC flags ^= 1; break; case 0xf6: case 0xf7: // math rmv data = readEA(); switch (modRMReg()) { case 0: case 1: // TEST rmv,iv test(data, fetch(wordSize)); break; case 2: // NOT iv finishWriteEA(~data); break; case 3: // NEG iv source = data; destination = 0; sub(); finishWriteEA(data); break; case 4: case 5: // MUL rmv, IMUL rmv source = data; destination = getAccum(); data = destination; setSF(); setPF(); data *= source; setAX(data); if (!wordSize) { if (modRMReg() == 4) setCF(ah() != 0); else { if ((source & 0x80) != 0) setAH(ah() - destination); if ((destination & 0x80) != 0) setAH(ah() - source); setCF(ah() == ((al() & 0x80) == 0 ? 0 : 0xff)); } } else { setDX(data >> 16); if (modRMReg() == 4) { data |= dx(); setCF(dx() != 0); } else { if ((source & 0x8000) != 0) setDX(dx() - destination); if ((destination & 0x8000) != 0) setDX(dx() - source); data |= dx(); setCF(dx() == ((ax() & 0x8000) == 0 ? 0 : 0xffff)); } } setZF(); setOF(cf()); break; case 6: case 7: // DIV rmv, IDIV rmv source = data; if (source == 0) divideOverflow(); if (!wordSize) { destination = ax(); if (modRMReg() == 6) { div(); if (data > 0xff) divideOverflow(); } else { destination = ax(); if ((destination & 0x8000) != 0) destination |= 0xffff0000; source = signExtend(source); div(); if (data > 0x7f && data < 0xffffff80) divideOverflow(); } setAH(remainder); setAL(data); } else { destination = (dx() << 16) + ax(); div(); if (modRMReg() == 6) { if (data > 0xffff) divideOverflow(); } else { if (data > 0x7fff && data < 0xffff8000) divideOverflow(); } setDX(remainder); setAX(data); } break; } break; case 0xf8: case 0xf9: // STC/CLC setCF(wordSize); break; case 0xfa: case 0xfb: // STI/CLI setIF(wordSize); break; case 0xfc: case 0xfd: // STD/CLD setDF(wordSize); break; case 0xfe: case 0xff: // misc ea(); if ((!wordSize && modRMReg() >= 2 && modRMReg() <= 6) || modRMReg() == 7) { fprintf(stderr, "Invalid instruction %02x %02x", opcode, modRM); runtimeError(""); } switch (modRMReg()) { case 0: case 1: // incdec rmv destination = readEA2(); finishWriteEA(incdec(modRMReg() != 0)); break; case 2: // CALL rmv call(readEA2()); break; case 3: // CALL mp farLoad(); farCall(); break; case 4: // JMP rmw ip = readEA2(); break; case 5: // JMP mp farLoad(); farJump(); break; case 6: // PUSH rmw push(readEA2()); break; } break; } } runtimeError("Timed out"); }
// Keyboard IRQ 1 static VOID WINAPI BiosKeyboardIrq(LPWORD Stack) { BOOLEAN SkipScanCode; BYTE ScanCode, VirtualKey; WORD Character; /* * Get the scan code from the PS/2 port, then call the * INT 15h, AH=4Fh Keyboard Intercept function to try to * translate the scan code. CF must be set before the call. * In return, if CF is set we continue processing the scan code * stored in AL, and if not, we skip it. */ BYTE CF; WORD AX; CF = getCF(); AX = getAX(); setCF(1); setAL(IOReadB(PS2_DATA_PORT)); setAH(0x4F); Int32Call(&BiosContext, BIOS_MISC_INTERRUPT); /* Retrieve the modified scan code in AL */ SkipScanCode = (getCF() == 0); ScanCode = getAL(); setAX(AX); setCF(CF); /* Check whether CF is clear. If so, skip the scan code. */ if (SkipScanCode) goto Quit; /* Get the corresponding virtual key code */ VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK); /* Check if this is a key press or release */ if (!(ScanCode & (1 << 7))) { /* Key press */ if (VirtualKey == VK_NUMLOCK || VirtualKey == VK_CAPITAL || VirtualKey == VK_SCROLL || VirtualKey == VK_INSERT) { /* For toggle keys, toggle the lowest bit in the keyboard map */ BiosKeyboardMap[VirtualKey] ^= ~(1 << 0); } /* Set the highest bit */ BiosKeyboardMap[VirtualKey] |= (1 << 7); /* Find out which character this is */ Character = 0; if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0) { /* Not ASCII */ Character = 0; } /* Push it onto the BIOS keyboard queue */ BiosKbdBufferPush(MAKEWORD(Character, ScanCode)); } else { /* Key release, unset the highest bit */ BiosKeyboardMap[VirtualKey] &= ~(1 << 7); } /* Clear the keyboard flags */ Bda->KeybdShiftFlags = 0; /* Set the appropriate flags based on the state */ if (BiosKeyboardMap[VK_RSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RSHIFT; if (BiosKeyboardMap[VK_LSHIFT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LSHIFT; if (BiosKeyboardMap[VK_CONTROL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CTRL; if (BiosKeyboardMap[VK_MENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_ALT; if (BiosKeyboardMap[VK_SCROLL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL_ON; if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK_ON; if (BiosKeyboardMap[VK_CAPITAL] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK_ON; if (BiosKeyboardMap[VK_INSERT] & (1 << 0)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT_ON; if (BiosKeyboardMap[VK_RMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_RALT; if (BiosKeyboardMap[VK_LMENU] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_LALT; if (BiosKeyboardMap[VK_SNAPSHOT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SYSRQ; if (BiosKeyboardMap[VK_PAUSE] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_PAUSE; if (BiosKeyboardMap[VK_SCROLL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_SCROLL; if (BiosKeyboardMap[VK_NUMLOCK] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_NUMLOCK; if (BiosKeyboardMap[VK_CAPITAL] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_CAPSLOCK; if (BiosKeyboardMap[VK_INSERT] & (1 << 7)) Bda->KeybdShiftFlags |= BDA_KBDFLAG_INSERT; DPRINT("BiosKeyboardIrq - Character = 0x%X, ScanCode = 0x%X, KeybdShiftFlags = 0x%X\n", Character, ScanCode, Bda->KeybdShiftFlags); Quit: PicIRQComplete(Stack); }
static VOID WINAPI EmsIntHandler(LPWORD Stack) { switch (getAH()) { /* Get Manager Status */ case 0x40: { setAH(EMS_STATUS_SUCCESS); break; } /* Get Page Frame Segment */ case 0x41: { setAH(EMS_STATUS_SUCCESS); setBX(EmsSegment); break; } /* Get Number of Unallocated Pages */ case 0x42: { setAH(EMS_STATUS_SUCCESS); setBX(RtlNumberOfClearBits(&AllocBitmap)); setDX(EmsTotalPages); break; } /* Get Handle and Allocate Memory */ case 0x43: { USHORT Handle; UCHAR Status = EmsAlloc(getBX(), &Handle); if (Status == EMS_STATUS_SUCCESS) setDX(Handle); setAH(Status); break; } /* Map Memory */ case 0x44: { setAH(EmsMap(getDX(), getAL(), getBX())); break; } /* Release Handle and Memory */ case 0x45: { setAH(EmsFree(getDX())); break; } /* Get EMM Version */ case 0x46: { setAH(EMS_STATUS_SUCCESS); setAL(EMS_VERSION_NUM); break; } /* Save Page Map */ case 0x47: { // FIXME: This depends on an EMS handle given in DX RtlCopyMemory(MappingBackup, Mapping, sizeof(Mapping)); setAH(EMS_STATUS_SUCCESS); break; } /* Restore Page Map */ case 0x48: { // FIXME: This depends on an EMS handle given in DX RtlCopyMemory(Mapping, MappingBackup, sizeof(Mapping)); setAH(EMS_STATUS_SUCCESS); break; } /* Get Number of Opened Handles */ case 0x4B: { USHORT NumOpenHandles = 0; USHORT i; for (i = 0; i < ARRAYSIZE(HandleTable); i++) { if (HandleTable[i].Allocated) ++NumOpenHandles; } setAH(EMS_STATUS_SUCCESS); setBX(NumOpenHandles); break; } /* Get Handle Number of Pages */ case 0x4C: { PEMS_HANDLE HandleEntry = GetHandleRecord(getDX()); if (!ValidateHandle(HandleEntry)) { setAH(EMS_STATUS_INVALID_HANDLE); break; } setAH(EMS_STATUS_SUCCESS); setBX(HandleEntry->PageCount); break; } /* Get All Handles Number of Pages */ case 0x4D: { PEMS_HANDLE_PAGE_INFO HandlePageInfo = (PEMS_HANDLE_PAGE_INFO)SEG_OFF_TO_PTR(getES(), getDI()); USHORT NumOpenHandles = 0; USHORT i; for (i = 0; i < ARRAYSIZE(HandleTable); i++) { if (HandleTable[i].Allocated) { HandlePageInfo->Handle = i; HandlePageInfo->PageCount = HandleTable[i].PageCount; ++HandlePageInfo; ++NumOpenHandles; } } setAH(EMS_STATUS_SUCCESS); setBX(NumOpenHandles); break; } /* Get or Set Page Map */ case 0x4E: { switch (getAL()) { /* Get Mapping Registers */ // case 0x00: // TODO: NOT IMPLEMENTED /* Set Mapping Registers */ // case 0x01: // TODO: NOT IMPLEMENTED /* Get and Set Mapping Registers At Once */ // case 0x02: // TODO: NOT IMPLEMENTED /* Get Size of Page-Mapping Array */ case 0x03: { setAH(EMS_STATUS_SUCCESS); setAL(sizeof(Mapping)); break; } default: { DPRINT1("EMS function AH = 0x4E, subfunction AL = %02X NOT IMPLEMENTED\n", getAL()); setAH(EMS_STATUS_UNKNOWN_FUNCTION); break; } } break; } /* Get/Set Handle Name */ case 0x53: { PEMS_HANDLE HandleEntry = GetHandleRecord(getDX()); if (!ValidateHandle(HandleEntry)) { setAH(EMS_STATUS_INVALID_HANDLE); break; } if (getAL() == 0x00) { /* Retrieve the name */ RtlCopyMemory(SEG_OFF_TO_PTR(getES(), getDI()), HandleEntry->Name, sizeof(HandleEntry->Name)); setAH(EMS_STATUS_SUCCESS); } else if (getAL() == 0x01) { /* Store the name */ RtlCopyMemory(HandleEntry->Name, SEG_OFF_TO_PTR(getDS(), getSI()), sizeof(HandleEntry->Name)); setAH(EMS_STATUS_SUCCESS); } else { DPRINT1("Invalid subfunction %02X for EMS function AH = 53h\n", getAL()); setAH(EMS_STATUS_INVALID_SUBFUNCTION); } break; } /* Handle Directory functions */ case 0x54: { if (getAL() == 0x00) { /* Get Handle Directory */ PEMS_HANDLE_DIR_ENTRY HandleDir = (PEMS_HANDLE_DIR_ENTRY)SEG_OFF_TO_PTR(getES(), getDI()); USHORT NumOpenHandles = 0; USHORT i; for (i = 0; i < ARRAYSIZE(HandleTable); i++) { if (HandleTable[i].Allocated) { HandleDir->Handle = i; RtlCopyMemory(HandleDir->Name, HandleTable[i].Name, sizeof(HandleDir->Name)); ++HandleDir; ++NumOpenHandles; } } setAH(EMS_STATUS_SUCCESS); setAL((UCHAR)NumOpenHandles); } else if (getAL() == 0x01) { /* Search for Named Handle */ PUCHAR HandleName = (PUCHAR)SEG_OFF_TO_PTR(getDS(), getSI()); PEMS_HANDLE HandleFound = NULL; USHORT i; for (i = 0; i < ARRAYSIZE(HandleTable); i++) { if (HandleTable[i].Allocated && RtlCompareMemory(HandleName, HandleTable[i].Name, sizeof(HandleTable[i].Name)) == sizeof(HandleTable[i].Name)) { HandleFound = &HandleTable[i]; break; } } /* Bail out if no handle was found */ if (i >= ARRAYSIZE(HandleTable)) // HandleFound == NULL { setAH(EMS_STATUS_HANDLE_NOT_FOUND); break; } /* Return the handle number */ setDX(i); /* Sanity check: Check whether the handle was unnamed */ i = 0; while ((i < sizeof(HandleFound->Name)) && (HandleFound->Name[i] == '\0')) ++i; if (i >= sizeof(HandleFound->Name)) { setAH(EMS_STATUS_UNNAMED_HANDLE); } else { setAH(EMS_STATUS_SUCCESS); } } else if (getAL() == 0x02) { /* * Get Total Number of Handles * * This function retrieves the maximum number of handles * (allocated or not) the memory manager supports, which * a program may request. */ setAH(EMS_STATUS_SUCCESS); setBX(ARRAYSIZE(HandleTable)); } else { DPRINT1("Invalid subfunction %02X for EMS function AH = 54h\n", getAL()); setAH(EMS_STATUS_INVALID_SUBFUNCTION); } break; } /* Move/Exchange Memory */ case 0x57: { PUCHAR SourcePtr, DestPtr; PEMS_HANDLE HandleEntry; PEMS_PAGE PageEntry; BOOLEAN Exchange = getAL(); PEMS_COPY_DATA Data = (PEMS_COPY_DATA)SEG_OFF_TO_PTR(getDS(), getSI()); if (Data->SourceType) { /* Expanded memory */ HandleEntry = GetHandleRecord(Data->SourceHandle); if (!ValidateHandle(HandleEntry)) { setAH(EMS_STATUS_INVALID_HANDLE); break; } PageEntry = GetLogicalPage(HandleEntry, Data->SourceSegment); if (!PageEntry) { setAH(EMS_STATUS_INV_LOGICAL_PAGE); break; } SourcePtr = (PUCHAR)((ULONG_PTR)EmsMemory + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE + Data->SourceOffset); } else { /* Conventional memory */ SourcePtr = (PUCHAR)SEG_OFF_TO_PTR(Data->SourceSegment, Data->SourceOffset); } if (Data->DestType) { /* Expanded memory */ HandleEntry = GetHandleRecord(Data->DestHandle); if (!ValidateHandle(HandleEntry)) { setAH(EMS_STATUS_INVALID_HANDLE); break; } PageEntry = GetLogicalPage(HandleEntry, Data->DestSegment); if (!PageEntry) { setAH(EMS_STATUS_INV_LOGICAL_PAGE); break; } DestPtr = (PUCHAR)((ULONG_PTR)EmsMemory + ARRAY_INDEX(PageEntry, PageTable) * EMS_PAGE_SIZE + Data->DestOffset); } else { /* Conventional memory */ DestPtr = (PUCHAR)SEG_OFF_TO_PTR(Data->DestSegment, Data->DestOffset); } if (Exchange) { ULONG i; /* Exchange */ for (i = 0; i < Data->RegionLength; i++) { UCHAR Temp = DestPtr[i]; DestPtr[i] = SourcePtr[i]; SourcePtr[i] = Temp; } } else { /* Move */ RtlMoveMemory(DestPtr, SourcePtr, Data->RegionLength); } setAH(EMS_STATUS_SUCCESS); break; } /* Get Mappable Physical Address Array */ case 0x58: { if (getAL() == 0x00) { PEMS_MAPPABLE_PHYS_PAGE PageArray = (PEMS_MAPPABLE_PHYS_PAGE)SEG_OFF_TO_PTR(getES(), getDI()); ULONG i; for (i = 0; i < EMS_PHYSICAL_PAGES; i++) { PageArray->PageSegment = EMS_SEGMENT + i * (EMS_PAGE_SIZE >> 4); PageArray->PageNumber = i; ++PageArray; } setAH(EMS_STATUS_SUCCESS); setCX(EMS_PHYSICAL_PAGES); } else if (getAL() == 0x01) { setAH(EMS_STATUS_SUCCESS); setCX(EMS_PHYSICAL_PAGES); } else { DPRINT1("Invalid subfunction %02X for EMS function AH = 58h\n", getAL()); setAH(EMS_STATUS_INVALID_SUBFUNCTION); } break; }
void printer_io() { #ifdef PRINTER half_word time_out, status; word printer_io_address, printer_io_reg, printer_status_reg, printer_control_reg; boolean printer_busy = TRUE; unsigned long time_count; int adapter; #ifdef NTVDM int bopsubfunction = getSI(); switch (bopsubfunction) { #ifdef MONITOR case 0: /* this is the bop to flush 16bit printer buffer */ printer_bop_flush (); return; #endif case 1: case 2: /* this is the bop to track a DOS open/close on LPTn */ printer_bop_openclose (bopsubfunction); return; } #endif setIF(1); adapter = getDX() % NUM_PARALLEL_PORTS; sas_loadw(port_address[adapter], &printer_io_address); printer_io_reg = printer_io_address; printer_status_reg = printer_io_address + 1; printer_control_reg = printer_io_address + 2; sas_load(timeout_address[adapter], &time_out); time_count = time_out * 0xFFFF; if (printer_io_address != 0) { IDLE_comlpt (); switch(getAH()) { case 0: /* Check the port status for busy before sending the character*/ while(printer_busy && time_count > 0) { /* The host_lpt_status() should check for status changes */ /* possibly by calling AsyncEventManager() if it's using */ /* XON /XOFF flow control. */ inb(printer_status_reg, &status); if (status & 0x80) printer_busy = FALSE; else time_count--; } if (printer_busy) { status &= 0xF8; /* clear bottom unused bits */ status |= 1; /* set error flag */ } else { /* Only send the character if the port isn't still busy */ outb(printer_io_reg, getAL()); outb(printer_control_reg, 0x0D); /* strobe low-high */ outb(printer_control_reg, 0x0C); /* strobe high-low */ inb(printer_status_reg, &status); status &= 0xF8; /* clear unused bits */ } status ^= 0x48; /* flip the odd bit */ setAH(status); break; case 1: outb(printer_control_reg, 0x08); /* set init line low */ outb(printer_control_reg, 0x0C); /* set init line high */ inb(printer_status_reg, &status); status &= 0xF8; /* clear unused bits */ status ^= 0x48; /* flip the odd bit */ setAH(status); break; case 2: inb(printer_status_reg, &status); status &= 0xF8; /* clear unused bits */ status ^= 0x48; /* flip the odd bit */ setAH(status); break; default: break; } } #endif }
void rs232_io() { #ifdef BIT_ORDER2 union { half_word all; struct { HALF_WORD_BIT_FIELD word_length:2; HALF_WORD_BIT_FIELD stop_bit:1; HALF_WORD_BIT_FIELD parity:2; HALF_WORD_BIT_FIELD baud_rate:3; } bit; } parameters; #endif #ifdef BIT_ORDER1 union { half_word all; struct { HALF_WORD_BIT_FIELD baud_rate:3; HALF_WORD_BIT_FIELD parity:2; HALF_WORD_BIT_FIELD stop_bit:1; HALF_WORD_BIT_FIELD word_length:2; } bit; } parameters; #endif DIVISOR_LATCH divisor_latch; int j; half_word timeout; sys_addr timeout_location; /* clear com/lpt idle flag */ IDLE_comlpt (); setIF(1); /* * Which adapter? */ switch (getDX ()) { case 0: port = RS232_COM1_PORT_START; timeout_location = RS232_COM1_TIMEOUT; break; case 1: port = RS232_COM2_PORT_START; timeout_location = RS232_COM2_TIMEOUT; break; case 2: port = RS232_COM3_PORT_START; timeout_location = RS232_COM3_TIMEOUT; break; case 3: port = RS232_COM4_PORT_START; timeout_location = RS232_COM4_TIMEOUT; break; default: break; } /* * Determine function */ switch (getAH ()) { case 0: /* * Initialise the communication port */ value = 0x80; /* set DLAB */ outb(port + (io_addr) RS232_LCR, value); /* * Set baud rate */ parameters.all = getAL(); divisor_latch.all = divisors[parameters.bit.baud_rate]; outb(port + (io_addr) RS232_IER, divisor_latch.byte.MSByte); outb(port + (io_addr) RS232_TX_RX, divisor_latch.byte.LSByte); /* * Set word length, stop bits and parity */ parameters.bit.baud_rate = 0; outb(port + (io_addr) RS232_LCR, parameters.all); /* * Disable interrupts */ value = 0; outb(port + (io_addr) RS232_IER, value); return_status(); break; case 1: /* * Send char over the comms line */ /* * Set DTR and RTS */ outb(port + (io_addr) RS232_MCR, 3); /* * Real BIOS checks CTS and DSR - we know DSR ok. * Real BIOS check THRE - we know it's ok. * We only check CTS - this is supported on a few ports, eg. Macintosh. */ /* * Wait for CTS to go high, or timeout */ sas_load(timeout_location, &timeout); for ( j = 0; j < timeout; j++) { inb(port + (io_addr) RS232_MSR, &value); if(value & 0x10)break; /* CTS High, all is well */ } if(j < timeout) { outb(port + (io_addr) RS232_TX_RX, getAL()); /* Send byte */ inb(port + (io_addr) RS232_LSR, &value); setAH(value); /* Return Line Status Reg in AH */ } else { setAH(value | 0x80); /* Indicate time out */ } break; case 2: /* * Receive char over the comms line */ /* * Set DTR */ value = 1; outb(port + (io_addr) RS232_MCR, value); /* * Real BIOS checks DSR - we know it's ok. */ /* * Wait for data to appear, or timeout(just an empirical guess) */ sas_load(timeout_location, &timeout); for ( j = 0; j < timeout; j++) { inb(port + (io_addr) RS232_LSR, &value); if ( (value & 1) == 1 ) { /* * Data ready go read it */ value &= 0x1e; /* keep error bits only */ setAH(value); inb(port + (io_addr) RS232_TX_RX, &value); setAL(value); return; } } /* * Set timeout */ value |= 0x80; setAH(value); break; case 3: /* * Return the communication port status */ return_status(); break; case 4: /* * EXTENDED (PS/2) Initialise the communication port */ value = 0x80; /* set DLAB */ outb(port + (io_addr) RS232_LCR, value); parameters.bit.word_length = getCH(); parameters.bit.stop_bit = getBL(); parameters.bit.parity = getBH(); parameters.bit.baud_rate = getCL(); /* Set baud rate */ divisor_latch.all = divisors[parameters.bit.baud_rate]; outb(port + (io_addr) RS232_IER, divisor_latch.byte.MSByte); outb(port + (io_addr) RS232_TX_RX, divisor_latch.byte.LSByte); /* * Set word length, stop bits and parity */ parameters.bit.baud_rate = 0; outb(port + (io_addr) RS232_LCR, parameters.all); /* * Disable interrupts */ value = 0; outb(port + (io_addr) RS232_IER, value); return_status(); break; case 5: /* EXTENDED Comms Port Control */ switch( getAL() ) { case 0: /* Read modem control register */ inb( port + (io_addr) RS232_MCR, &value); setBL(value); break; case 1: /* Write modem control register */ outb( port + (io_addr) RS232_MCR, getBL()); break; } /* Return the communication port status */ return_status(); break; default: /* ** Yes both XT and AT BIOS's really do this. */ setAH( getAH()-3 ); break; } }
/*static*/ VOID WINAPI BiosDiskService(LPWORD Stack) { BYTE Drive; PDISK_IMAGE DiskImage; switch (getAH()) { /* Disk -- Reset Disk System */ case 0x00: { Drive = getDL(); if (Drive & 0x80) { AllDisksReset(); /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } Drive &= ~0x80; if (Drive >= ARRAYSIZE(FloppyDrive)) { DPRINT1("BiosDiskService(0x00): Drive number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } // TODO: Reset drive /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Disk -- Get Status of Last Operation */ case 0x01: { BYTE LastOperationStatus = 0x00; Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x01): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } LastOperationStatus = DiskImage->LastOperationStatus; if (Drive & 0x80) Bda->LastDiskOperation = LastOperationStatus; else Bda->LastDisketteOperation = LastOperationStatus; /* Return last error */ setAH(LastOperationStatus); if (LastOperationStatus == 0x00) Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; else Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Disk -- Read Sectors into Memory */ case 0x02: { BYTE Status; BYTE Head = getDH(); BYTE NumSectors = getAL(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x02): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Read the sectors */ Status = ReadDisk(DiskImage, Cylinder, Head, Sector, NumSectors); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x02): Error when reading from disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Disk -- Write Disk Sectors */ case 0x03: { BYTE Status; BYTE Head = getDH(); BYTE NumSectors = getAL(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x03): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Write the sectors */ Status = WriteDisk(DiskImage, Cylinder, Head, Sector, NumSectors); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x03): Error when writing to disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Disk -- Verify Disk Sectors */ case 0x04: /* Floppy/Fixed Disk -- Format Track */ case 0x05: /* Fixed Disk -- Format Track and Set Bad Sector Flags */ case 0x06: /* Fixed Disk -- Format Drive starting at Given Track */ case 0x07: goto Default; /* Disk -- Get Drive Parameters */ case 0x08: { WORD MaxCylinders; BYTE MaxHeads; BYTE PresentDrives = 0; BYTE i; Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x08): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } // Minus 2 because it's the maximum cylinder number (not count), // and the last cylinder is reserved (for compatibility with BIOSes // which reserve it for testing purposes). MaxCylinders = DiskImage->DiskInfo.Cylinders - 2; // Minus 1 because it's the maximum head number (not count). MaxHeads = DiskImage->DiskInfo.Heads - 1; // CL: Sector number 1-63 (bits 0-5) // High two bits of cylinder (bits 6-7, hard disk only) setCL((DiskImage->DiskInfo.Sectors & 0x3F) | ((HIBYTE(MaxCylinders) & 0x02) << 6)); // CH: Low eight bits of cylinder number setCH(LOBYTE(MaxCylinders)); setDH(MaxHeads); if (Drive & 0x80) { /* Count the number of active HDDs */ for (i = 0; i < ARRAYSIZE(HardDrive); ++i) { if (IsDiskPresent(HardDrive[i])) ++PresentDrives; } /* Reset ES:DI to NULL */ // FIXME: NONONO!! Apps expect (for example, MS-DOS kernel) // that this function does not modify ES:DI if it was called // for a HDD. // setES(0x0000); // setDI(0x0000); } else { /* Count the number of active floppies */ for (i = 0; i < ARRAYSIZE(FloppyDrive); ++i) { if (IsDiskPresent(FloppyDrive[i])) ++PresentDrives; } /* ES:DI points to the floppy parameter table */ setES(HIWORD(((PULONG)BaseAddress)[0x1E])); setDI(LOWORD(((PULONG)BaseAddress)[0x1E])); } setDL(PresentDrives); setBL(DiskImage->DiskType); // DiskGeometryList[DiskImage->DiskType].biosval setAL(0x00); /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Hard Disk -- Initialize Controller with Drive Parameters */ case 0x09: /* Hard Disk -- Read Long Sectors */ case 0x0A: /* Hard Disk -- Write Long Sectors */ case 0x0B: goto Default; /* Hard Disk -- Seek to Cylinder */ case 0x0C: { BYTE Status; BYTE Head = getDH(); // CH: Low eight bits of cylinder number // CL: High two bits of cylinder (bits 6-7, hard disk only) WORD Cylinder = MAKEWORD(getCH(), (getCL() >> 6) & 0x02); // CL: Sector number 1-63 (bits 0-5) BYTE Sector = (getCL() & 0x3F); // 1-based Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x0C): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Set position */ Status = SeekDisk(DiskImage, Cylinder, Head, Sector); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x0C): Error when seeking in disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Hard Disk -- Reset Hard Disks */ case 0x0D: { // FIXME: Should do what 0x11 does. UNIMPLEMENTED; } /* Hard Disk -- Read Sector Buffer (XT only) */ case 0x0E: /* Hard Disk -- Write Sector Buffer (XT only) */ case 0x0F: goto Default; /* Hard Disk -- Check if Drive is ready */ case 0x10: { Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x10): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x10): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Hard Disk -- Recalibrate Drive */ case 0x11: { BYTE Status; Drive = getDL(); if (!(Drive & 0x80)) { DPRINT1("BiosDiskService(0x11): Disk number 0x%02X is not a HDD\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x11): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } /* Set position to zero */ Status = SeekDisk(DiskImage, /*Cylinder*/ 0, /*Head*/ 0, /*Sector*/ 1); if (Status == 0x00) { /* Return success */ setAH(0x00); Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; } else { DPRINT1("BiosDiskService(0x11): Error when recalibrating disk number 0x%02X (0x%02X)\n", Drive, Status); /* Return error */ setAH(Status); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; } break; } /* Hard Disk -- Controller RAM Diagnostic */ case 0x12: /* Hard Disk -- Drive Diagnostic */ case 0x13: /* Hard Disk -- Controller Internal Diagnostic */ case 0x14: goto Default; /* Disk -- Get Disk Type */ case 0x15: { Drive = getDL(); DiskImage = GetDisk(Drive); if (!DiskImage || !IsDiskPresent(DiskImage)) { DPRINT1("BiosDiskService(0x15): Disk number 0x%02X invalid\n", Drive); /* Return error */ setAH(0x01); Stack[STACK_FLAGS] |= EMULATOR_FLAG_CF; break; } if (Drive & 0x80) { ULONG NumSectors; /* Hard disk */ setAH(0x03); /* Number of 512-byte sectors in CX:DX */ NumSectors = (ULONG)((ULONG)DiskImage->DiskInfo.Cylinders * DiskImage->DiskInfo.Heads) * DiskImage->DiskInfo.Sectors; setCX(HIWORD(NumSectors)); setDX(LOWORD(NumSectors)); } else { /* Floppy */ setAH(0x01); } /* Return success */ Stack[STACK_FLAGS] &= ~EMULATOR_FLAG_CF; break; } /* Floppy Disk -- Detect Disk Change */ case 0x16: /* Floppy Disk -- Set Disk Type for Format */ case 0x17: /* Disk -- Set Media Type for Format */ case 0x18: goto Default; default: Default: { DPRINT1("BIOS Function INT 13h, AH = 0x%02X, AL = 0x%02X, BH = 0x%02X NOT IMPLEMENTED\n", getAH(), getAL(), getBH()); } } }