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, Universitaetstrasse 6, 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