1/** 2 * \file 3 * \brief Video BIOS int 10h interface. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <stdarg.h> 17#include <barrelfish/barrelfish.h> 18#include <x86emu.h> 19#include <mackerel/mackerel.h> 20 21#include "int10.h" 22 23#define M _X86EMU_env 24 25#define X86_EAX M.x86.R_EAX 26#define X86_EBX M.x86.R_EBX 27#define X86_ECX M.x86.R_ECX 28#define X86_EDX M.x86.R_EDX 29#define X86_ESI M.x86.R_ESI 30#define X86_EDI M.x86.R_EDI 31#define X86_EBP M.x86.R_EBP 32#define X86_EIP M.x86.R_EIP 33#define X86_ESP M.x86.R_ESP 34#define X86_EFLAGS M.x86.R_EFLG 35 36#define X86_FLAGS M.x86.R_FLG 37#define X86_AX M.x86.R_AX 38#define X86_BX M.x86.R_BX 39#define X86_CX M.x86.R_CX 40#define X86_DX M.x86.R_DX 41#define X86_SI M.x86.R_SI 42#define X86_DI M.x86.R_DI 43#define X86_BP M.x86.R_BP 44#define X86_IP M.x86.R_IP 45#define X86_SP M.x86.R_SP 46#define X86_CS M.x86.R_CS 47#define X86_DS M.x86.R_DS 48#define X86_ES M.x86.R_ES 49#define X86_SS M.x86.R_SS 50#define X86_FS M.x86.R_FS 51#define X86_GS M.x86.R_GS 52 53#define X86_AL M.x86.R_AL 54#define X86_BL M.x86.R_BL 55#define X86_CL M.x86.R_CL 56#define X86_DL M.x86.R_DL 57 58#define X86_AH M.x86.R_AH 59#define X86_BH M.x86.R_BH 60#define X86_CH M.x86.R_CH 61#define X86_DH M.x86.R_DH 62 63#define X86_IF_MASK 0x00000200 64#define X86_IOPL_MASK 0x00003000 65 66static void *mymem = NULL; 67 68/// XXX: Dunno if this is a save address 69#define STACKSEG 0x30000 70 71/** 72 * \brief Dump all registers of the emulated x86. 73 */ 74static void dump_registers(void) 75{ 76 printf("EAX=0x%8.8lx, EBX=0x%8.8lx, ECX=0x%8.8lx, EDX=0x%8.8lx\n", 77 (unsigned long)X86_EAX, (unsigned long)X86_EBX, 78 (unsigned long)X86_ECX, (unsigned long)X86_EDX); 79 printf("ESP=0x%8.8lx, EBP=0x%8.8lx, ESI=0x%8.8lx, EDI=0x%8.8lx\n", 80 (unsigned long)X86_ESP, (unsigned long)X86_EBP, 81 (unsigned long)X86_ESI, (unsigned long)X86_EDI); 82 printf("CS=0x%4.4x, SS=0x%4.4x," 83 " DS=0x%4.4x, ES=0x%4.4x, FS=0x%4.4x, GS=0x%4.4x\n", 84 X86_CS, X86_SS, X86_DS, X86_ES, X86_FS, X86_GS); 85 printf("EIP=0x%8.8lx, EFLAGS=0x%8.8lx\n", 86 (unsigned long)X86_EIP, (unsigned long)X86_EFLAGS); 87} 88 89static uint8_t mem_rb(u32 addr) 90{ 91 assert(addr < REALMODE_MEM_SIZE); 92 assert(mymem != NULL); 93 return *(uint8_t *)(mymem + addr); 94} 95 96static uint16_t mem_rw(u32 addr) 97{ 98 assert(addr < REALMODE_MEM_SIZE); 99 assert(mymem != NULL); 100 return *(uint16_t *)(mymem + addr); 101} 102 103static u32 mem_rl(u32 addr) 104{ 105 assert(addr < REALMODE_MEM_SIZE); 106 assert(mymem != NULL); 107 return *(uint32_t *)(mymem + addr); 108} 109 110static void mem_wb(u32 addr, uint8_t val) 111{ 112 assert(addr < REALMODE_MEM_SIZE); 113 assert(mymem != NULL); 114 *(uint8_t *)(mymem + addr) = val; 115} 116 117static void mem_ww(u32 addr, uint16_t val) 118{ 119 assert(addr < REALMODE_MEM_SIZE); 120 assert(mymem != NULL); 121 *(uint16_t *)(mymem + addr) = val; 122} 123 124static void mem_wl(u32 addr, u32 val) 125{ 126 assert(addr < REALMODE_MEM_SIZE); 127 assert(mymem != NULL); 128 *(uint32_t *)(mymem + addr) = val; 129} 130 131/** 132 * \brief Pushes one 16-bit word onto the emulated x86's stack. 133 * 134 * \param val Word to push 135 */ 136static void pushw(uint16_t val) 137{ 138 X86_ESP -= 2; 139 mem_ww(((uint32_t) X86_SS << 4) + X86_SP, val); 140} 141 142/** 143 * \brief Emulates an x86 software interrupt. 144 * 145 * \param int Interrupt number to call. 146 * 147 * \return 1 on success, 0 on error. 148 */ 149static int run_bios_int(int num) 150{ 151 uint32_t eflags; 152/* printf("calling video BIOS (int %x) at: ", num); */ 153 eflags = X86_EFLAGS; 154 pushw(eflags); 155 pushw(X86_CS); 156 pushw(X86_IP); 157 X86_CS = mem_rw((num << 2) + 2); 158 X86_IP = mem_rw(num << 2); 159/* printf("0x%x:%x\n", X86_CS, X86_EIP); */ 160 161 return 1; 162} 163 164static int int1A_handler(void) 165{ 166 USER_PANIC("NYI"); 167 return 0; 168} 169 170static int intE6_handler(void) 171{ 172 USER_PANIC("NYI"); 173 return 0; 174} 175 176static void int_handler(int num) 177{ 178 int ret = 0; 179 180 switch (num) { 181 case 0x1a: 182 // Int 0x1a deals with PCI config space 183 ret = int1A_handler(); 184 break; 185 186 case 0xe6: 187 // Int 0xe6 deals with PCI config space 188 ret = intE6_handler(); 189 break; 190 191 default: 192 break; 193 } 194 195 if (!ret) { 196 ret = run_bios_int(num); 197 } 198 199 if (!ret) { 200 printf("Halting on int 0x%2.2x!\n", num); 201 dump_registers(); 202 X86EMU_halt_sys(); 203 } 204} 205 206static uint8_t xinb(uint16_t port) 207{ 208 uint8_t val = mackerel_read_io_8(port, 0); 209 //printf("inb %x %x\n", port, val); 210 return val; 211} 212 213static uint16_t xinw(uint16_t port) 214{ 215 uint16_t val = mackerel_read_io_16(port, 0); 216 //printf("inw %x %x\n", port, val); 217 return val; 218} 219 220static u32 xinl(uint16_t port) 221{ 222 uint32_t val = mackerel_read_io_32(port, 0); 223 //printf("inl %x %x\n", port, val); 224 return val; 225} 226 227static void xoutb(uint16_t port, uint8_t val) 228{ 229 //printf("outb %x %x\n", port, val); 230 mackerel_write_io_8(port, 0, val); 231} 232 233static void xoutw(uint16_t port, uint16_t val) 234{ 235 //printf("outw %x %x\n", port, val); 236 mackerel_write_io_16(port, 0, val); 237} 238 239static void xoutl(uint16_t port, u32 val) 240{ 241 //printf("outl %x %x\n", port, val); 242 mackerel_write_io_32(port, 0, val); 243} 244 245static void set_return_trap(void) 246{ 247 /* 248 * Here we set the exit condition: We return when we encounter 249 * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory. 250 */ 251 mem_wb(0x0600, 0xf4); 252} 253 254void int10_init(void *mem) 255{ 256 int i; 257 X86EMU_intrFuncs intFuncs[256]; 258 X86EMU_pioFuncs pioFuncs = { 259 (&xinb), 260 (&xinw), 261 (&xinl), 262 (&xoutb), 263 (&xoutw), 264 (&xoutl) 265 }; 266 X86EMU_memFuncs memFuncs = { 267 (&mem_rb), 268 (&mem_rw), 269 (&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