2 * \file x86emu/lib/int10/int10.c(c)
3 * \brief Call VESA BIOS functions using the real mode interface
6 * \author Frank Mehnert <fm3@os.inf.tu-dresden.de>
7 * Adam Lackorzynski <adam@os.inf.tu-dresden.de>
8 * Alexander Warg <warg@os.inf.tu-dresden.de>
11 * (c) 2005-2009 Author(s)
12 * economic rights: Technische Universität Dresden (Germany)
14 * This file is part of TUD:OS and distributed under the terms of the
15 * GNU General Public License 2.
16 * Please see the COPYING-GPL-2 file for details.
19 #include <l4/sys/types.h>
20 #include <l4/sys/ipc.h>
21 #include <l4/sys/kdebug.h>
22 #include <l4/x86emu/x86emu.h>
24 #include <l4/re/mem_alloc>
26 #include <l4/re/util/cap_alloc>
27 #include <l4/re/namespace>
28 #include <l4/re/dataspace>
29 #include <l4/util/mb_info.h>
30 #include <l4/util/macros.h>
31 #include <l4/sys/err.h>
33 #include <l4/vbus/vbus.h>
34 #include <l4/vbus/vbus_types.h>
35 #include <l4/vbus/vbus_pci.h>
41 #include <l4/x86emu/int10.h>
50 static l4_addr_t v_page[1024*1024/(L4_PAGESIZE)];
51 static l4_addr_t v_area;
52 static l4_umword_t initialized;
53 static L4::Cap<void> vbus;
54 static l4vbus_device_handle_t root_bridge;
57 warn(u32 addr, const char *func)
59 printf("\033[31mWARNING: Function %s access %08lx\033[m\n", func,
63 #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
64 #define PCI_FUNC(devfn) ((devfn) & 0x07)
66 static int do_pcicfg(unsigned long addr, u32 *val32, int size, int out)
68 static l4_uint32_t config_reg;
69 /* check for PCI addr and data ports */
70 if (addr < 0xcf8 || addr >= 0xd00)
83 unsigned df = (config_reg >> 8) & 0xff;
84 unsigned bus = (config_reg >> 16) & 0xff;
86 df = (PCI_SLOT(df) << 16) | PCI_FUNC(df);
88 reg = (addr & 3) | (config_reg & 0xfc) | ((config_reg >> 16) & 0xf00);
90 printf("CFG ACCESS(%d-%d): %02x:%03x.%02x reg=%x val=%p (*val=%lx)\n",
91 out, size, bus, (df >> 16) & 0xffff, df & 0xffff,
92 reg, val32, (unsigned long)*val32);
95 l4vbus_pci_cfg_write(vbus.cap(), root_bridge, bus, df, reg,
99 l4vbus_pci_cfg_read(vbus.cap(), root_bridge, bus, df, reg, &v, size);
104 printf("Uups: %lx\n", addr);
107 printf("access to PCI %lx %s %lx\n", addr, out ? "WRITE" : "READ",
108 (unsigned long)*val32);
113 template< typename W >
115 port_in(X86EMU_pioAddr addr)
118 if (do_pcicfg(addr, &r, sizeof(W) * 8, 0))
123 case 1: asm volatile ("in %w1, %b0" : "=a" (r) : "d" (addr)); break;
124 case 2: asm volatile ("in %w1, %w0" : "=a" (r) : "d" (addr)); break;
125 case 4: asm volatile ("in %w1, %0" : "=a" (r) : "d" (addr)); break;
131 static char const *const ws[4] = { "b", "w", "X", "l" };
132 printf("%04x:%04x in%s %x -> %lx\n", M.x86.R_CS, M.x86.R_IP,
133 ws[sizeof(W)-1], addr, (unsigned long)r);
140 template< typename W >
142 port_out(X86EMU_pioAddr addr, W val)
145 if (do_pcicfg(addr, &r, sizeof(W) * 8, 1))
150 static char const *const ws[4] = { "b", "w", "X", "l" };
151 printf("%04x:%04x out%s %x -> %lx\n", M.x86.R_CS, M.x86.R_IP,
152 ws[sizeof(W)-1], addr, (unsigned long)r);
158 case 1: asm volatile ("out %b0, %w1" : : "a" (r), "d" (addr)); break;
159 case 2: asm volatile ("out %w0, %w1" : : "a" (r), "d" (addr)); break;
160 case 4: asm volatile ("out %0, %w1" : : "a" (r), "d" (addr)); break;
165 template< typename W >
169 if (addr > (1 << 20))
170 warn(addr, __FUNCTION__);
173 printf("read(%d) %08x => ", (int)sizeof(W), (unsigned)addr);
175 W const *a = (W const *)(v_page[addr/L4_PAGESIZE] + (addr % L4_PAGESIZE));
178 printf("%0*x\n", (int)sizeof(W)*2, (unsigned)*a);
183 template< typename W >
185 mem_write(u32 addr, W val)
187 if (addr > (1 << 20))
188 warn(addr, __FUNCTION__);
191 printf("write(%d) %0*x => %08x\n", (int)sizeof(W), (int)sizeof(W)*2, (unsigned)val, (unsigned)addr);
193 W *a = (W *)(v_page[addr/L4_PAGESIZE] + (addr % L4_PAGESIZE));
198 X86EMU_pioFuncs my_pioFuncs =
200 port_in<u8>, port_in<u16>, port_in<u32>,
201 port_out<u8>, port_out<u16>, port_out<u32>
204 X86EMU_memFuncs my_memFuncs =
206 mem_read<u8>, mem_read<u16>, mem_read<u32>,
207 mem_write<u8>, mem_write<u16>, mem_write<u32>
211 printk(const char *format, ...)
214 va_start(list, format);
215 vprintf(format, list);
221 x86emu_int10_init(void)
226 L4::Cap<L4Re::Dataspace> ds;
232 vbus = L4Re::Env::env()->get_cap<void>("vbus");
233 if (!vbus.is_valid())
235 printf("no 'vbus' found in namespace\n");
240 err = l4vbus_get_device_by_hid(vbus.cap(), 0, &root_bridge, "PNP0A03", 0, 0);
243 printf("No PCI root bridge found\n");
244 L4Re::Util::cap_alloc.free(vbus);
249 X86EMU_setupPioFuncs(&my_pioFuncs);
250 X86EMU_setupMemFuncs(&my_memFuncs);
251 M.x86.debug = 0 /*| DEBUG_DECODE_F*/;
253 l4io_request_all_ioports();
255 /* Reserve region for physical memory 0x00000...0xfffff. Make sure that we
256 * can unmap it using one single l4_fpage_unmap (alignment). */
258 if ((error = L4Re::Env::env()->rm()->reserve_area(&v_page[0], 1<<20,
259 L4Re::Rm::Search_addr, 20)))
261 printf("Error %d reserving area for x86emu\n", error);
266 /* Map physical page 0x00000 */
267 if (l4io_request_iomem_region(0, v_page[0], L4_PAGESIZE, L4IO_MEM_CACHED | L4IO_MEM_USE_RESERVED_AREA) < 0)
269 printf("Error %d allocating physical page 0 for x86emu\n", error);
273 ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
277 if ((error = L4Re::Env::env()->mem_alloc()->alloc(L4_PAGESIZE, ds, 0)))
279 printf("Error %d allocating page for x86emu\n", error);
283 /* Map dummy as physical page 0x01000 */
284 v_page[1] = v_page[0] + L4_PAGESIZE;
285 if ((error = L4Re::Env::env()->rm()->attach((void**)&v_page[1], L4_PAGESIZE,
286 L4Re::Rm::In_area, ds,
289 printf("Error %d attaching page for x86emu\n", error);
293 for (idx=0x09F000/L4_PAGESIZE, addr=0x09F000;
295 idx++, addr+=L4_PAGESIZE)
296 v_page[idx] = v_page[0] + addr;
298 if ((error = l4io_request_iomem_region(0x09F000, v_page[0x9f],
301 L4IO_MEM_USE_RESERVED_AREA)) < 0)
303 printf("BIOS area mapping failed: %x\n", error);
308 *(l4_uint8_t*)(v_page[1]+0) = 0xcd;
309 *(l4_uint8_t*)(v_page[1]+1) = 0x10;
310 *(l4_uint8_t*)(v_page[1]+2) = 0xf4;
318 x86emu_int10_done(void)
326 for (; i < sizeof(v_page) / sizeof(v_page[0]); ++i)
328 L4Re::Env::env()->rm()->detach((void *)v_page[i], 0);
331 ret = L4Re::Env::env()->rm()->free_area(v_area);
338 static l4_addr_t far_to_addr(l4_uint32_t farp)
340 l4_addr_t p = (farp & 0x0FFFF) + ((farp >> 12) & 0xFFFF0);
341 return (l4_addr_t)(v_page[p / L4_PAGESIZE] + (p % L4_PAGESIZE));
344 static void dump_mode(int mode, l4util_mb_vbe_mode_t *m)
350 printf("Mode: 0x%x: No information available\n", mode);
354 snprintf(s, sizeof(s), "%dx%d@%d",
355 m->x_resolution, m->y_resolution, m->bits_per_pixel);
356 s[sizeof(s) - 1] = 0;
358 printf("Mode: 0x%x %13s, RGB: %d(%d):%d(%d):%d(%d) mode: %x\n",
360 m->red_field_position, m->red_mask_size,
361 m->green_field_position, m->green_mask_size,
362 m->blue_field_position, m->blue_mask_size,
367 l4util_mb_vbe_mode_t *get_mode_info(int mode)
369 M.x86.R_EAX = 0x4F01; /* int10 function number */
370 M.x86.R_ECX = mode; /* VESA mode */
371 M.x86.R_EDI = 0x800; /* ES:DI pointer to at least 256 bytes */
372 M.x86.R_IP = 0; /* address of "int10; hlt" */
373 M.x86.R_SP = L4_PAGESIZE; /* SS:SP pointer to stack */
377 M.x86.R_SS = L4_PAGESIZE >> 4;
380 if (M.x86.R_AX != 0x004F)
383 l4util_mb_vbe_mode_t *m = (l4util_mb_vbe_mode_t*)(v_page[1] + 0x800);
384 if ((m->mode_attributes & 0x91) == 0x91)
392 x86emu_int10_set_vbemode(int mode, l4util_mb_vbe_ctrl_t **ctrl_info,
393 l4util_mb_vbe_mode_t **mode_info)
397 if ((error = x86emu_int10_init()))
400 printf("Trying execution of ``set VBE mode'' using x86emu\n");
402 /* Get VESA BIOS controller information. */
403 M.x86.R_EAX = 0x4F00; /* int10 function number */
404 M.x86.R_EDI = 0x100; /* ES:DI pointer to at least 512 bytes */
405 M.x86.R_IP = 0; /* address of "int10; hlt" */
406 M.x86.R_SP = L4_PAGESIZE; /* SS:SP pointer to stack */
410 M.x86.R_SS = L4_PAGESIZE >> 4;
412 *ctrl_info = (l4util_mb_vbe_ctrl_t*)(v_page[1] + 0x100);
413 if (M.x86.R_AX != 0x4F)
415 printf("VBE BIOS not present.\n");
419 const char *oem_string = (const char *)far_to_addr((*ctrl_info)->oem_string);
420 printf("Found VESA BIOS version %d.%d\n"
422 (int)((*ctrl_info)->version >> 8),
423 (int)((*ctrl_info)->version & 0xFF),
424 (*ctrl_info)->oem_string ? oem_string : "[unknown]");
425 if ((*ctrl_info)->version < 0x0200)
427 printf("VESA BIOS 2.0 or later required.\n");
433 // mode == ~0 means to look for the 'best' mode available, we'll look
434 // for the highest 16bit mode
436 printf("Scanning for 'best' possible mode:\n");
437 l4_uint16_t *mode_list = (l4_uint16_t *)far_to_addr((*ctrl_info)->video_mode);
438 for (; *mode_list != 0xffff; ++mode_list)
440 l4util_mb_vbe_mode_t *m = get_mode_info(*mode_list);
441 dump_mode(*mode_list, m);
444 // our 'best' expression...
445 if (m->x_resolution > max_val && m->bits_per_pixel == 16)
447 max_val = m->x_resolution;
455 printf("Could not find suitable mode\n");
458 printf("Choosen mode:\n");
459 dump_mode(mode, get_mode_info(mode));
460 printf("To force a specific setting use a '-m <mode>' option.\n");
462 else if (!(*mode_info = get_mode_info(mode)))
464 printf("Mode %x not supported\n", mode);
465 printf("List of supported graphics modes:\n");
466 l4_uint16_t *mode_list = (l4_uint16_t *)far_to_addr((*ctrl_info)->video_mode);
467 for (; *mode_list != 0xffff; ++mode_list)
468 dump_mode(*mode_list, get_mode_info(*mode_list));
474 M.x86.R_EAX = 0x4F02; /* int10 function number */
475 M.x86.R_EBX = mode & 0xf7ff; /* VESA mode; use current refresh rate */
476 M.x86.R_EBX |= (1<<14); /* use flat buffer model */
478 M.x86.R_EBX |= (1<<15); /* no screen clearing */
479 M.x86.R_IP = 0; /* address of "int10; hlt" */
480 M.x86.R_SP = L4_PAGESIZE; /* SS:SP pointer to stack */
484 M.x86.R_SS = L4_PAGESIZE >> 4;
487 printf("VBE mode 0x%x successfully set.\n", mode);
492 x86emu_int10_pan(unsigned *x, unsigned *y)
496 if ((error = x86emu_int10_init()))
499 printf("Trying execution of ``set display start'' using x86emu\n");
501 /* Get VESA BIOS controller information. */
502 M.x86.R_EAX = 0x4F07; /* int10 function number */
503 M.x86.R_BL = 0x00; /* set display start */
504 M.x86.R_CX = *x; /* first displayed pixel in scanline */
505 M.x86.R_DX = *y; /* first displayed scanline */
506 M.x86.R_IP = 0; /* address of "int10; hlt" */
507 M.x86.R_SP = L4_PAGESIZE; /* SS:SP pointer to stack */
511 M.x86.R_SS = L4_PAGESIZE >> 4;
514 if (M.x86.R_AX != 0x004F)
516 printf("Panning to %d,%d not supported\n", *x, *y);
520 printf("Successful.\n");