12703SN/A/**
22703SN/A * \file
32703SN/A * \brief Video BIOS int 10h interface.
42703SN/A */
52703SN/A
62703SN/A/*
72703SN/A * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich
82703SN/A * All rights reserved.
92703SN/A *
102703SN/A * This file is distributed under the terms in the attached LICENSE file.
112703SN/A * If you do not find this file, copies can be found by writing to:
122703SN/A * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
132703SN/A */
142703SN/A
152703SN/A#include <stdio.h>
162703SN/A#include <stdarg.h>
172703SN/A#include <barrelfish/barrelfish.h>
182703SN/A#include <x86emu.h>
193941SN/A#include <mackerel/mackerel.h>
203941SN/A
213941SN/A#include "int10.h"
222703SN/A
232703SN/A#define M _X86EMU_env
242703SN/A
252703SN/A#define X86_EAX M.x86.R_EAX
262703SN/A#define X86_EBX M.x86.R_EBX
272703SN/A#define X86_ECX M.x86.R_ECX
282703SN/A#define X86_EDX M.x86.R_EDX
292703SN/A#define X86_ESI M.x86.R_ESI
302703SN/A#define X86_EDI M.x86.R_EDI
312703SN/A#define X86_EBP M.x86.R_EBP
322703SN/A#define X86_EIP M.x86.R_EIP
332703SN/A#define X86_ESP M.x86.R_ESP
342703SN/A#define X86_EFLAGS M.x86.R_EFLG
352703SN/A
362703SN/A#define X86_FLAGS M.x86.R_FLG
372703SN/A#define X86_AX M.x86.R_AX
382703SN/A#define X86_BX M.x86.R_BX
392703SN/A#define X86_CX M.x86.R_CX
402703SN/A#define X86_DX M.x86.R_DX
412703SN/A#define X86_SI M.x86.R_SI
422703SN/A#define X86_DI M.x86.R_DI
432703SN/A#define X86_BP M.x86.R_BP
442703SN/A#define X86_IP M.x86.R_IP
452703SN/A#define X86_SP M.x86.R_SP
462703SN/A#define X86_CS M.x86.R_CS
472703SN/A#define X86_DS M.x86.R_DS
482703SN/A#define X86_ES M.x86.R_ES
492703SN/A#define X86_SS M.x86.R_SS
502703SN/A#define X86_FS M.x86.R_FS
512703SN/A#define X86_GS M.x86.R_GS
522703SN/A
532703SN/A#define X86_AL M.x86.R_AL
542703SN/A#define X86_BL M.x86.R_BL
552703SN/A#define X86_CL M.x86.R_CL
562703SN/A#define X86_DL M.x86.R_DL
572703SN/A
582703SN/A#define X86_AH M.x86.R_AH
592703SN/A#define X86_BH M.x86.R_BH
602703SN/A#define X86_CH M.x86.R_CH
612703SN/A#define X86_DH M.x86.R_DH
622703SN/A
632703SN/A#define X86_IF_MASK             0x00000200
642703SN/A#define X86_IOPL_MASK           0x00003000
652703SN/A
662703SN/Astatic void *mymem = NULL;
672703SN/A
682703SN/A/// XXX: Dunno if this is a save address
692703SN/A#define STACKSEG        0x30000
702703SN/A
712703SN/A/**
722703SN/A * \brief Dump all registers of the emulated x86.
732703SN/A */
742703SN/Astatic void dump_registers(void)
752703SN/A{
762703SN/A    printf("EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n",
772703SN/A           (unsigned long)X86_EAX, (unsigned long)X86_EBX,
782703SN/A           (unsigned long)X86_ECX, (unsigned long)X86_EDX);
792703SN/A    printf("ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n",
802703SN/A           (unsigned long)X86_ESP, (unsigned long)X86_EBP,
812703SN/A           (unsigned long)X86_ESI, (unsigned long)X86_EDI);
822703SN/A    printf("CS=0x%4.4x, SS=0x%4.4x,"
832703SN/A           " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n",
842703SN/A           X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS);
852703SN/A    printf("EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n",
862703SN/A           (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS);
872703SN/A}
882703SN/A
892703SN/Astatic uint8_t mem_rb(u32 addr)
902703SN/A{
912703SN/A    assert(addr < REALMODE_MEM_SIZE);
922703SN/A    assert(mymem != NULL);
932703SN/A    return *(uint8_t *)(mymem + addr);
942703SN/A}
952703SN/A
962703SN/Astatic uint16_t mem_rw(u32 addr)
972703SN/A{
982703SN/A    assert(addr < REALMODE_MEM_SIZE);
992703SN/A    assert(mymem != NULL);
1002703SN/A    return *(uint16_t *)(mymem + addr);
1012703SN/A}
1022703SN/A
1032703SN/Astatic u32 mem_rl(u32 addr)
1042703SN/A{
1052703SN/A    assert(addr < REALMODE_MEM_SIZE);
1062703SN/A    assert(mymem != NULL);
1072703SN/A    return *(uint32_t *)(mymem + addr);
1082703SN/A}
1092703SN/A
1102703SN/Astatic void mem_wb(u32 addr, uint8_t val)
1112703SN/A{
1122703SN/A    assert(addr < REALMODE_MEM_SIZE);
1132703SN/A    assert(mymem != NULL);
1142703SN/A    *(uint8_t *)(mymem + addr) = val;
1152703SN/A}
1162703SN/A
1172703SN/Astatic void mem_ww(u32 addr, uint16_t val)
1182703SN/A{
1192703SN/A    assert(addr < REALMODE_MEM_SIZE);
1202703SN/A    assert(mymem != NULL);
1212703SN/A    *(uint16_t *)(mymem + addr) = val;
1222703SN/A}
1232703SN/A
1242703SN/Astatic void mem_wl(u32 addr, u32 val)
1252703SN/A{
1262703SN/A    assert(addr < REALMODE_MEM_SIZE);
1272703SN/A    assert(mymem != NULL);
1282703SN/A    *(uint32_t *)(mymem + addr) = val;
1292703SN/A}
1302703SN/A
1312703SN/A/**
1322703SN/A * \brief Pushes one 16-bit word onto the emulated x86's stack.
1332703SN/A *
1342703SN/A * \param val   Word to push
1352703SN/A */
1362703SN/Astatic void pushw(uint16_t val)
1372703SN/A{
1382703SN/A    X86_ESP -= 2;
1392703SN/A    mem_ww(((uint32_t) X86_SS << 4) + X86_SP, val);
1402703SN/A}
1412703SN/A
1422703SN/A/**
1432703SN/A * \brief Emulates an x86 software interrupt.
1442703SN/A *
1452703SN/A * \param int   Interrupt number to call.
1462703SN/A *
1472703SN/A * \return 1 on success, 0 on error.
1482703SN/A */
1492703SN/Astatic int run_bios_int(int num)
1502703SN/A{
1512703SN/A    uint32_t eflags;
1522703SN/A/*     printf("calling video BIOS (int %x) at: ", num); */
1532703SN/A    eflags = X86_EFLAGS;
1542703SN/A    pushw(eflags);
1552703SN/A    pushw(X86_CS);
1562703SN/A    pushw(X86_IP);
1572703SN/A    X86_CS = mem_rw((num << 2) + 2);
1582703SN/A    X86_IP = mem_rw(num << 2);
1592703SN/A/*     printf("0x%x:%x\n", X86_CS, X86_EIP); */
1602703SN/A
1612703SN/A    return 1;
1622703SN/A}
1632703SN/A
1642703SN/Astatic int int1A_handler(void)
1652703SN/A{
1662703SN/A    USER_PANIC("NYI");
1672703SN/A    return 0;
1682703SN/A}
1692703SN/A
1702703SN/Astatic int intE6_handler(void)
1712703SN/A{
1722703SN/A    USER_PANIC("NYI");
1732703SN/A    return 0;
1742703SN/A}
1752703SN/A
1762703SN/Astatic void int_handler(int num)
1772703SN/A{
1782703SN/A    int ret = 0;
1792703SN/A
1802703SN/A    switch (num) {
1812703SN/A    case 0x1a:
1822703SN/A        // Int 0x1a deals with PCI config space
1832703SN/A        ret = int1A_handler();
1842703SN/A        break;
1852703SN/A
1862703SN/A    case 0xe6:
1872703SN/A        // Int 0xe6 deals with PCI config space
1882703SN/A        ret = intE6_handler();
1892703SN/A        break;
1902703SN/A
1912703SN/A    default:
1922703SN/A        break;
1932703SN/A    }
1942703SN/A
1952703SN/A    if (!ret) {
1962703SN/A        ret = run_bios_int(num);
1972703SN/A    }
1982703SN/A
1992703SN/A    if (!ret) {
2002703SN/A        printf("Halting on int 0x%2.2x!\n", num);
2012703SN/A        dump_registers();
2022703SN/A        X86EMU_halt_sys();
2032703SN/A    }
2042703SN/A}
2052703SN/A
2062703SN/Astatic uint8_t xinb(uint16_t port)
2072703SN/A{
2082703SN/A    uint8_t val = mackerel_read_io_8(port, 0);
2092703SN/A    //printf("inb %x %x\n", port, val);
2102703SN/A    return val;
2112703SN/A}
2122703SN/A
2132703SN/Astatic uint16_t xinw(uint16_t port)
2142703SN/A{
2152703SN/A    uint16_t val = mackerel_read_io_16(port, 0);
2162703SN/A    //printf("inw %x %x\n", port, val);
2172703SN/A    return val;
2182703SN/A}
2192703SN/A
2202703SN/Astatic u32 xinl(uint16_t port)
2212703SN/A{
2222703SN/A    uint32_t val = mackerel_read_io_32(port, 0);
2232703SN/A    //printf("inl %x %x\n", port, val);
2242703SN/A    return val;
2252703SN/A}
2262703SN/A
2272703SN/Astatic void xoutb(uint16_t port, uint8_t val)
2282703SN/A{
2292703SN/A    //printf("outb %x %x\n", port, val);
2302703SN/A    mackerel_write_io_8(port, 0, val);
2312703SN/A}
2322703SN/A
2332703SN/Astatic void xoutw(uint16_t port, uint16_t val)
2342703SN/A{
2352703SN/A    //printf("outw %x %x\n", port, val);
2362703SN/A    mackerel_write_io_16(port, 0, val);
2372703SN/A}
2382703SN/A
2392703SN/Astatic void xoutl(uint16_t port, u32 val)
2402703SN/A{
2412703SN/A    //printf("outl %x %x\n", port, val);
2422703SN/A    mackerel_write_io_32(port, 0, val);
2432703SN/A}
2442703SN/A
2452703SN/Astatic void set_return_trap(void)
2462703SN/A{
2472703SN/A    /*
2482703SN/A     * Here we set the exit condition:  We return when we encounter
2492703SN/A     * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory.
2502703SN/A     */
2512703SN/A    mem_wb(0x0600, 0xf4);
2522703SN/A}
2532703SN/A
2542703SN/Avoid int10_init(void *mem)
2552703SN/A{
2562703SN/A    int i;
2572703SN/A    X86EMU_intrFuncs intFuncs[256];
2582703SN/A    X86EMU_pioFuncs pioFuncs = {
2592703SN/A        (&xinb),
2602703SN/A        (&xinw),
2612703SN/A        (&xinl),
2622703SN/A        (&xoutb),
2632703SN/A        (&xoutw),
2642703SN/A        (&xoutl)
2652703SN/A    };
2662703SN/A    X86EMU_memFuncs memFuncs = {
2672703SN/A        (&mem_rb),
2682703SN/A        (&mem_rw),
2692703SN/A        (&mem_rl),
270        (&mem_wb),
271        (&mem_ww),
272        (&mem_wl)
273    };
274
275    X86EMU_setupMemFuncs(&memFuncs);
276
277    _X86EMU_env.mem_base = 0;
278    _X86EMU_env.mem_size = 1024 * 1024 + 1024;
279    X86EMU_setupPioFuncs(&pioFuncs);
280
281    for(i = 0; i < 256; i++) {
282        intFuncs[i] = int_handler;
283    }
284
285    X86EMU_setupIntrFuncs(intFuncs);
286
287    mymem = mem;
288
289    set_return_trap();
290}
291
292#if 0
293static void
294SetResetBIOSVars(xf86Int10InfoPtr pInt, Bool set)
295{
296    int pagesize = getpagesize();
297    unsigned char* base = xf86MapVidMem(pInt->scrnIndex,
298                                        VIDMEM_MMIO, 0, pagesize);
299    int i;
300
301    if (set) {
302        for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
303            mem_ww(pInt, i, *(base + i));
304    } else {
305        for (i = BIOS_SCRATCH_OFF; i < BIOS_SCRATCH_END; i++)
306            *(base + i) = MEM_RW(pInt, i);
307    }
308
309    xf86UnMapVidMem(pInt->scrnIndex,base,pagesize);
310}
311#endif
312
313void int10(struct int10_regs *regs)
314{
315    X86_EAX = regs->eax;
316    X86_EBX = regs->ebx;
317    X86_ECX = regs->ecx;
318    X86_EDX = regs->edx;
319    X86_ESI = regs->esi;
320    X86_EDI = regs->edi;
321    X86_EBP = regs->ebp;
322    X86_ESP = 0x1000; X86_SS = STACKSEG >> 4;
323    X86_EIP = 0x0600; X86_CS = 0x0;     /* address of 'hlt' */
324    X86_DS = 0x40;                      /* standard pc ds */
325    X86_ES = regs->es;
326    X86_FS = 0;
327    X86_GS = 0;
328    X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;
329
330    int_handler(0x10);
331    X86EMU_exec();
332
333    regs->eax = X86_EAX;
334    regs->ebx = X86_EBX;
335    regs->ecx = X86_ECX;
336    regs->edx = X86_EDX;
337    regs->esi = X86_ESI;
338    regs->edi = X86_EDI;
339    regs->es = X86_ES;
340    regs->ebp = X86_EBP;
341    regs->eflags = X86_EFLAGS;
342}
343
344void printk(const char *fmt, ...)
345{
346    va_list ap;
347
348    va_start(ap, fmt);
349    vprintf(fmt, ap);
350    va_end(ap);
351}
352