Example #1
0
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
}
Example #2
0
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));
    }
}
Example #3
0
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);
}
Example #4
0
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);
    }
}
Example #5
0
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);
}
Example #6
0
static void return_status()
{
	inb(port + (io_addr) RS232_LSR, &value);
	setAH(value);
	inb(port + (io_addr) RS232_MSR, &value);
	setAL(value);
}
Example #7
0
void MsBopB(){

    switch (getAH()) {

        case 0 :
            setAH(0);
        while (!tkbhit());
        setAL((BYTE)tgetch());
            break;

        case 1 :
        tputch(getAL());
            break;
    }
}
Example #8
0
File: dem.c Project: GYGit/reactos
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);
}
Example #9
0
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*)&registers[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");
}
Example #10
0
// 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);
}
Example #11
0
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;
        }
Example #12
0
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
}
Example #13
0
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;
   }
}
Example #14
0
/*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());
        }
    }
}