vga_post.c revision 1.4
1/* $OpenBSD: vga_post.c,v 1.4 2009/06/14 20:27:24 miod Exp $ */ 2/* $NetBSD: vga_post.c,v 1.12 2009/03/15 21:32:36 cegger Exp $ */ 3 4/*- 5 * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34 35#include <sys/param.h> 36#include <sys/device.h> 37#include <sys/malloc.h> 38#include <uvm/uvm_extern.h> 39#include <uvm/uvm_page.h> 40 41#include <machine/pio.h> 42 43#include <machine/vga_post.h> 44 45#include <dev/x86emu/x86emu.h> 46#include <dev/x86emu/x86emu_regs.h> 47 48#define BASE_MEMORY 65536 /* How much memory to allocate in Real Mode */ 49 50struct vga_post { 51 struct x86emu emu; 52 vaddr_t sys_image; 53 uint32_t initial_eax; 54 uint8_t bios_data[PAGE_SIZE]; 55 struct pglist ram_backing; 56}; 57 58#ifdef DDB 59static struct vga_post *ddb_vgapostp; 60void ddb_vgapost(void); 61#endif 62 63static uint8_t 64vm86_emu_inb(struct x86emu *emu, uint16_t port) 65{ 66 if (port == 0xb2) /* APM scratch register */ 67 return 0; 68 69 if (port >= 0x80 && port < 0x88) /* POST status register */ 70 return 0; 71 72 return inb(port); 73} 74 75static uint16_t 76vm86_emu_inw(struct x86emu *emu, uint16_t port) 77{ 78 if (port >= 0x80 && port < 0x88) /* POST status register */ 79 return 0; 80 81 return inw(port); 82} 83 84static uint32_t 85vm86_emu_inl(struct x86emu *emu, uint16_t port) 86{ 87 if (port >= 0x80 && port < 0x88) /* POST status register */ 88 return 0; 89 90 return inl(port); 91} 92 93static void 94vm86_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val) 95{ 96 if (port == 0xb2) /* APM scratch register */ 97 return; 98 99 if (port >= 0x80 && port < 0x88) /* POST status register */ 100 return; 101 102 outb(port, val); 103} 104 105static void 106vm86_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val) 107{ 108 if (port >= 0x80 && port < 0x88) /* POST status register */ 109 return; 110 111 outw(port, val); 112} 113 114static void 115vm86_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val) 116{ 117 if (port >= 0x80 && port < 0x88) /* POST status register */ 118 return; 119 120 outl(port, val); 121} 122 123struct vga_post * 124vga_post_init(int bus, int device, int function) 125{ 126 struct vga_post *sc; 127 vaddr_t iter; 128 struct vm_page *pg; 129 vaddr_t sys_image, sys_bios_data; 130 int err; 131 132 sys_bios_data = uvm_km_valloc(kernel_map, PAGE_SIZE); 133 if (sys_bios_data == 0) 134 return NULL; 135 136 sys_image = uvm_km_valloc(kernel_map, 1024 * 1024); 137 if (sys_image == 0) { 138 uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE); 139 return NULL; 140 } 141 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 142 143 TAILQ_INIT(&sc->ram_backing); 144 err = uvm_pglistalloc(BASE_MEMORY, 0, (paddr_t)-1, 0, 0, 145 &sc->ram_backing, BASE_MEMORY/PAGE_SIZE, UVM_PLA_WAITOK); 146 if (err) { 147 uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024); 148 free(sc, M_DEVBUF); 149 return NULL; 150 } 151 152 sc->sys_image = sys_image; 153 sc->emu.sys_private = sc; 154 155 pmap_kenter_pa(sys_bios_data, 0, VM_PROT_READ); 156 pmap_update(pmap_kernel()); 157 memcpy((void *)sc->bios_data, (void *)sys_bios_data, PAGE_SIZE); 158 pmap_kremove(sys_bios_data, PAGE_SIZE); 159 uvm_km_free(kernel_map, sys_bios_data, PAGE_SIZE); 160 161 iter = 0; 162 TAILQ_FOREACH(pg, &sc->ram_backing, pageq) { 163 pmap_kenter_pa(sc->sys_image + iter, VM_PAGE_TO_PHYS(pg), 164 VM_PROT_READ | VM_PROT_WRITE); 165 iter += PAGE_SIZE; 166 } 167 KASSERT(iter == BASE_MEMORY); 168 169 for (iter = 640 * 1024; iter < 1024 * 1024; iter += PAGE_SIZE) 170 pmap_kenter_pa(sc->sys_image + iter, iter, 171 VM_PROT_READ | VM_PROT_WRITE); 172 pmap_update(pmap_kernel()); 173 174 memset(&sc->emu, 0, sizeof(sc->emu)); 175 x86emu_init_default(&sc->emu); 176 sc->emu.emu_inb = vm86_emu_inb; 177 sc->emu.emu_inw = vm86_emu_inw; 178 sc->emu.emu_inl = vm86_emu_inl; 179 sc->emu.emu_outb = vm86_emu_outb; 180 sc->emu.emu_outw = vm86_emu_outw; 181 sc->emu.emu_outl = vm86_emu_outl; 182 183 sc->emu.mem_base = (char *)sc->sys_image; 184 sc->emu.mem_size = 1024 * 1024; 185 186 sc->initial_eax = bus * 256 + device * 8 + function; 187#ifdef DDB 188 ddb_vgapostp = sc; 189#endif 190 return sc; 191} 192 193void 194vga_post_call(struct vga_post *sc) 195{ 196 sc->emu.x86.R_EAX = sc->initial_eax; 197 sc->emu.x86.R_EDX = 0x00000080; 198 sc->emu.x86.R_DS = 0x0040; 199 sc->emu.x86.register_flags = 0x3200; 200 201 memcpy((void *)sc->sys_image, sc->bios_data, PAGE_SIZE); 202 203 /* stack is at the end of the first 64KB */ 204 sc->emu.x86.R_SS = 0; 205 sc->emu.x86.R_ESP = 0; 206 207 /* Jump straight into the VGA BIOS POST code */ 208 x86emu_exec_call(&sc->emu, 0xc000, 0x0003); 209} 210 211void 212vga_post_free(struct vga_post *sc) 213{ 214 uvm_pglistfree(&sc->ram_backing); 215 pmap_kremove(sc->sys_image, 1024 * 1024); 216 uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024); 217 pmap_update(pmap_kernel()); 218 free(sc, M_DEVBUF); 219} 220 221#ifdef DDB 222void 223ddb_vgapost(void) 224{ 225 226 if (ddb_vgapostp) 227 vga_post_call(ddb_vgapostp); 228 else 229 printf("ddb_vgapost: vga_post not initialized\n"); 230} 231#endif 232