1 /* $OpenBSD: vga_post.c,v 1.4 2009/06/14 20:27:25 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 50 struct 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 59 struct vga_post *ddb_vgapostp; 60 void ddb_vgapost(void); 61 #endif 62 63 static uint8_t 64 vm86_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 75 static uint16_t 76 vm86_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 84 static uint32_t 85 vm86_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 93 static void 94 vm86_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 105 static void 106 vm86_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 114 static void 115 vm86_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 123 struct vga_post * 124 vga_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 193 void 194 vga_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 211 void 212 vga_post_free(struct vga_post *sc) 213 { 214 uvm_pglistfree(&sc->ram_backing); 215 pmap_kremove(sc->sys_image, 1024 * 1024); 216 217 uvm_km_free(kernel_map, sc->sys_image, 1024 * 1024); 218 pmap_update(pmap_kernel()); 219 free(sc, M_DEVBUF); 220 } 221 222 #ifdef DDB 223 void 224 ddb_vgapost(void) 225 { 226 227 if (ddb_vgapostp) 228 vga_post_call(ddb_vgapostp); 229 else 230 printf("ddb_vgapost: vga_post not initialized\n"); 231 } 232 #endif 233