1 /*- 2 * Copyright (c) 2009 Alex Keda <admin@lissyara.su> 3 * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_x86bios.h" 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/proc.h> 41 42 #include <contrib/x86emu/x86emu.h> 43 #include <contrib/x86emu/x86emu_regs.h> 44 #include <compat/x86bios/x86bios.h> 45 46 #include <dev/pci/pcireg.h> 47 #include <dev/pci/pcivar.h> 48 49 #include <machine/cpufunc.h> 50 51 #include <vm/vm.h> 52 #include <vm/pmap.h> 53 54 #define X86BIOS_PAGE_SIZE 0x00001000 /* 4K */ 55 56 #define X86BIOS_IVT_SIZE 0x00000500 /* 1K + 256 (BDA) */ 57 #define X86BIOS_SEG_SIZE 0x00010000 /* 64K */ 58 #define X86BIOS_MEM_SIZE 0x00100000 /* 1M */ 59 60 #define X86BIOS_IVT_BASE 0x00000000 61 #define X86BIOS_RAM_BASE 0x00001000 62 #define X86BIOS_ROM_BASE 0x000a0000 /* XXX EBDA? */ 63 64 #define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - X86BIOS_ROM_BASE) 65 66 #define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE) 67 68 #define X86BIOS_R_DS _pad1 69 #define X86BIOS_R_SS _pad2 70 71 static struct x86emu x86bios_emu; 72 73 static struct mtx x86bios_lock; 74 75 static void *x86bios_ivt; 76 static void *x86bios_rom; 77 static void *x86bios_seg; 78 79 static vm_offset_t *x86bios_map; 80 81 static vm_paddr_t x86bios_seg_phys; 82 83 static void * 84 x86bios_get_pages(uint32_t offset, size_t size) 85 { 86 int i; 87 88 if (offset + size > X86BIOS_MEM_SIZE) 89 return (NULL); 90 91 i = offset / X86BIOS_PAGE_SIZE; 92 if (x86bios_map[i] != 0) 93 return ((void *)(x86bios_map[i] + offset - 94 i * X86BIOS_PAGE_SIZE)); 95 96 return (NULL); 97 } 98 99 static void 100 x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size) 101 { 102 int i, j; 103 104 for (i = pa / X86BIOS_PAGE_SIZE, j = 0; 105 j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++) 106 x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE; 107 } 108 109 static uint8_t 110 x86bios_emu_rdb(struct x86emu *emu, uint32_t addr) 111 { 112 uint8_t *va; 113 114 va = x86bios_get_pages(addr, sizeof(*va)); 115 if (va == NULL) 116 x86emu_halt_sys(emu); 117 118 return (*va); 119 } 120 121 static uint16_t 122 x86bios_emu_rdw(struct x86emu *emu, uint32_t addr) 123 { 124 uint16_t *va; 125 126 va = x86bios_get_pages(addr, sizeof(*va)); 127 if (va == NULL) 128 x86emu_halt_sys(emu); 129 130 return (le16toh(*va)); 131 } 132 133 static uint32_t 134 x86bios_emu_rdl(struct x86emu *emu, uint32_t addr) 135 { 136 uint32_t *va; 137 138 va = x86bios_get_pages(addr, sizeof(*va)); 139 if (va == NULL) 140 x86emu_halt_sys(emu); 141 142 return (le32toh(*va)); 143 } 144 145 static void 146 x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val) 147 { 148 uint8_t *va; 149 150 va = x86bios_get_pages(addr, sizeof(*va)); 151 if (va == NULL) 152 x86emu_halt_sys(emu); 153 154 *va = val; 155 } 156 157 static void 158 x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val) 159 { 160 uint16_t *va; 161 162 va = x86bios_get_pages(addr, sizeof(*va)); 163 if (va == NULL) 164 x86emu_halt_sys(emu); 165 166 *va = htole16(val); 167 } 168 169 static void 170 x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val) 171 { 172 uint32_t *va; 173 174 va = x86bios_get_pages(addr, sizeof(*va)); 175 if (va == NULL) 176 x86emu_halt_sys(emu); 177 178 *va = htole32(val); 179 } 180 181 static uint8_t 182 x86bios_emu_inb(struct x86emu *emu, uint16_t port) 183 { 184 185 if (port == 0xb2) /* APM scratch register */ 186 return (0); 187 if (port >= 0x80 && port < 0x88) /* POST status register */ 188 return (0); 189 190 return (inb(port)); 191 } 192 193 static uint16_t 194 x86bios_emu_inw(struct x86emu *emu, uint16_t port) 195 { 196 197 if (port >= 0x80 && port < 0x88) /* POST status register */ 198 return (0); 199 200 return (inw(port)); 201 } 202 203 static uint32_t 204 x86bios_emu_inl(struct x86emu *emu, uint16_t port) 205 { 206 207 if (port >= 0x80 && port < 0x88) /* POST status register */ 208 return (0); 209 210 return (inl(port)); 211 } 212 213 static void 214 x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val) 215 { 216 217 if (port == 0xb2) /* APM scratch register */ 218 return; 219 if (port >= 0x80 && port < 0x88) /* POST status register */ 220 return; 221 222 outb(port, val); 223 } 224 225 static void 226 x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val) 227 { 228 229 if (port >= 0x80 && port < 0x88) /* POST status register */ 230 return; 231 232 outw(port, val); 233 } 234 235 static void 236 x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val) 237 { 238 239 if (port >= 0x80 && port < 0x88) /* POST status register */ 240 return; 241 242 outl(port, val); 243 } 244 245 static void 246 x86bios_emu_get_intr(struct x86emu *emu, int intno) 247 { 248 uint16_t *sp; 249 uint32_t iv; 250 251 emu->x86.R_SP -= 6; 252 253 sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP); 254 sp[0] = htole16(emu->x86.R_IP); 255 sp[1] = htole16(emu->x86.R_CS); 256 sp[2] = htole16(emu->x86.R_FLG); 257 258 iv = x86bios_get_intr(intno); 259 emu->x86.R_IP = iv & 0x000f; 260 emu->x86.R_CS = (iv >> 12) & 0xffff; 261 emu->x86.R_FLG &= ~(F_IF | F_TF); 262 } 263 264 void * 265 x86bios_alloc(uint32_t *offset, size_t size) 266 { 267 void *vaddr; 268 269 if (offset == NULL || size == 0) 270 return (NULL); 271 272 vaddr = contigmalloc(size, M_DEVBUF, M_NOWAIT, X86BIOS_RAM_BASE, 273 X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); 274 if (vaddr != NULL) { 275 *offset = vtophys(vaddr); 276 x86bios_set_pages((vm_offset_t)vaddr, *offset, size); 277 } 278 279 return (vaddr); 280 } 281 282 void 283 x86bios_free(void *addr, size_t size) 284 { 285 vm_paddr_t paddr; 286 287 if (addr == NULL || size == 0) 288 return; 289 290 paddr = vtophys(addr); 291 if (paddr < X86BIOS_RAM_BASE || paddr >= X86BIOS_ROM_BASE || 292 paddr % X86BIOS_PAGE_SIZE != 0) 293 return; 294 295 bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE, 296 sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE)); 297 contigfree(addr, size, M_DEVBUF); 298 } 299 300 void 301 x86bios_init_regs(struct x86regs *regs) 302 { 303 304 bzero(regs, sizeof(*regs)); 305 regs->X86BIOS_R_DS = regs->X86BIOS_R_SS = x86bios_seg_phys >> 4; 306 } 307 308 void 309 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) 310 { 311 312 if (x86bios_map == NULL) 313 return; 314 315 if (bootverbose) 316 printf("Calling 0x%05x (ax=0x%04x bx=0x%04x " 317 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 318 (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, 319 regs->R_DX, regs->R_ES, regs->R_DI); 320 321 mtx_lock_spin(&x86bios_lock); 322 memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); 323 x86emu_exec_call(&x86bios_emu, seg, off); 324 memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 325 mtx_unlock_spin(&x86bios_lock); 326 327 if (bootverbose) 328 printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x " 329 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 330 (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, 331 regs->R_DX, regs->R_ES, regs->R_DI); 332 } 333 334 uint32_t 335 x86bios_get_intr(int intno) 336 { 337 uint32_t *iv; 338 339 iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4); 340 341 return (le32toh(*iv)); 342 } 343 344 void 345 x86bios_intr(struct x86regs *regs, int intno) 346 { 347 348 if (intno < 0 || intno > 255) 349 return; 350 351 if (x86bios_map == NULL) 352 return; 353 354 if (bootverbose) 355 printf("Calling int 0x%x (ax=0x%04x bx=0x%04x " 356 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 357 intno, regs->R_AX, regs->R_BX, regs->R_CX, 358 regs->R_DX, regs->R_ES, regs->R_DI); 359 360 mtx_lock_spin(&x86bios_lock); 361 memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); 362 x86emu_exec_intr(&x86bios_emu, intno); 363 memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 364 mtx_unlock_spin(&x86bios_lock); 365 366 if (bootverbose) 367 printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x " 368 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 369 intno, regs->R_AX, regs->R_BX, regs->R_CX, 370 regs->R_DX, regs->R_ES, regs->R_DI); 371 } 372 373 void * 374 x86bios_offset(uint32_t offset) 375 { 376 377 return (x86bios_get_pages(offset, 1)); 378 } 379 380 void * 381 x86bios_get_orm(uint32_t offset) 382 { 383 uint8_t *p; 384 385 /* Does the shadow ROM contain BIOS POST code for x86? */ 386 p = x86bios_offset(offset); 387 if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9) 388 return (NULL); 389 390 return (p); 391 } 392 393 int 394 x86bios_match_device(uint32_t offset, device_t dev) 395 { 396 uint8_t *p; 397 uint16_t device, vendor; 398 uint8_t class, progif, subclass; 399 400 /* Does the shadow ROM contain BIOS POST code for x86? */ 401 p = x86bios_get_orm(offset); 402 if (p == NULL) 403 return (0); 404 405 /* Does it contain PCI data structure? */ 406 p += le16toh(*(uint16_t *)(p + 0x18)); 407 if (bcmp(p, "PCIR", 4) != 0 || 408 le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0) 409 return (0); 410 411 /* Does it match the vendor, device, and classcode? */ 412 vendor = le16toh(*(uint16_t *)(p + 0x04)); 413 device = le16toh(*(uint16_t *)(p + 0x06)); 414 progif = *(p + 0x0d); 415 subclass = *(p + 0x0e); 416 class = *(p + 0x0f); 417 if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) || 418 class != pci_get_class(dev) || subclass != pci_get_subclass(dev) || 419 progif != pci_get_progif(dev)) 420 return (0); 421 422 return (1); 423 } 424 425 static __inline int 426 x86bios_map_mem(void) 427 { 428 429 x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE); 430 if (x86bios_ivt == NULL) 431 return (1); 432 x86bios_rom = pmap_mapdev(X86BIOS_ROM_BASE, X86BIOS_ROM_SIZE); 433 if (x86bios_rom == NULL) { 434 pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); 435 return (1); 436 } 437 x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK, 438 X86BIOS_RAM_BASE, X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); 439 x86bios_seg_phys = vtophys(x86bios_seg); 440 441 return (0); 442 } 443 444 static __inline void 445 x86bios_unmap_mem(void) 446 { 447 448 pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); 449 pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE); 450 contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF); 451 } 452 453 static void 454 x86bios_init(void *arg __unused) 455 { 456 int i; 457 458 mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN); 459 460 if (x86bios_map_mem() != 0) 461 return; 462 463 x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF, 464 M_WAITOK | M_ZERO); 465 x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE, 466 X86BIOS_IVT_SIZE); 467 x86bios_set_pages((vm_offset_t)x86bios_rom, X86BIOS_ROM_BASE, 468 X86BIOS_ROM_SIZE); 469 x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys, 470 X86BIOS_SEG_SIZE); 471 472 bzero(&x86bios_emu, sizeof(x86bios_emu)); 473 474 x86bios_emu.emu_rdb = x86bios_emu_rdb; 475 x86bios_emu.emu_rdw = x86bios_emu_rdw; 476 x86bios_emu.emu_rdl = x86bios_emu_rdl; 477 x86bios_emu.emu_wrb = x86bios_emu_wrb; 478 x86bios_emu.emu_wrw = x86bios_emu_wrw; 479 x86bios_emu.emu_wrl = x86bios_emu_wrl; 480 481 x86bios_emu.emu_inb = x86bios_emu_inb; 482 x86bios_emu.emu_inw = x86bios_emu_inw; 483 x86bios_emu.emu_inl = x86bios_emu_inl; 484 x86bios_emu.emu_outb = x86bios_emu_outb; 485 x86bios_emu.emu_outw = x86bios_emu_outw; 486 x86bios_emu.emu_outl = x86bios_emu_outl; 487 488 for (i = 0; i < 256; i++) 489 x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr; 490 } 491 492 static void 493 x86bios_uninit(void *arg __unused) 494 { 495 vm_offset_t *map = x86bios_map; 496 497 mtx_lock_spin(&x86bios_lock); 498 if (x86bios_map != NULL) { 499 free(x86bios_map, M_DEVBUF); 500 x86bios_map = NULL; 501 } 502 mtx_unlock_spin(&x86bios_lock); 503 504 if (map != NULL) 505 x86bios_unmap_mem(); 506 507 mtx_destroy(&x86bios_lock); 508 } 509 510 static int 511 x86bios_modevent(module_t mod __unused, int type, void *data __unused) 512 { 513 514 switch (type) { 515 case MOD_LOAD: 516 x86bios_init(NULL); 517 break; 518 case MOD_UNLOAD: 519 x86bios_uninit(NULL); 520 break; 521 default: 522 return (ENOTSUP); 523 } 524 525 return (0); 526 } 527 528 static moduledata_t x86bios_mod = { 529 "x86bios", 530 x86bios_modevent, 531 NULL, 532 }; 533 534 DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY); 535 MODULE_VERSION(x86bios, 1); 536