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