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 #include <sys/sysctl.h> 42 43 #include <contrib/x86emu/x86emu.h> 44 #include <contrib/x86emu/x86emu_regs.h> 45 #include <compat/x86bios/x86bios.h> 46 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcivar.h> 49 50 #include <machine/cpufunc.h> 51 52 #include <vm/vm.h> 53 #include <vm/pmap.h> 54 55 #define X86BIOS_PAGE_SIZE 0x00001000 /* 4K */ 56 57 #define X86BIOS_IVT_SIZE 0x00000500 /* 1K + 256 (BDA) */ 58 #define X86BIOS_SEG_SIZE 0x00010000 /* 64K */ 59 #define X86BIOS_MEM_SIZE 0x00100000 /* 1M */ 60 61 #define X86BIOS_IVT_BASE 0x00000000 62 #define X86BIOS_RAM_BASE 0x00001000 63 #define X86BIOS_ROM_BASE 0x000a0000 /* XXX EBDA? */ 64 65 #define X86BIOS_ROM_SIZE (X86BIOS_MEM_SIZE - X86BIOS_ROM_BASE) 66 67 #define X86BIOS_PAGES (X86BIOS_MEM_SIZE / X86BIOS_PAGE_SIZE) 68 69 #define X86BIOS_R_DS _pad1 70 #define X86BIOS_R_SS _pad2 71 72 static struct x86emu x86bios_emu; 73 74 static struct mtx x86bios_lock; 75 76 static void *x86bios_ivt; 77 static void *x86bios_rom; 78 static void *x86bios_seg; 79 80 static vm_offset_t *x86bios_map; 81 82 static vm_paddr_t x86bios_seg_phys; 83 84 SYSCTL_NODE(_debug, OID_AUTO, x86bios, CTLFLAG_RD, NULL, "x86bios debugging"); 85 static int x86bios_trace_call; 86 TUNABLE_INT("debug.x86bios.call", &x86bios_trace_call); 87 SYSCTL_INT(_debug_x86bios, OID_AUTO, call, CTLFLAG_RW, &x86bios_trace_call, 0, 88 "Trace far function calls"); 89 static int x86bios_trace_int; 90 TUNABLE_INT("debug.x86bios.int", &x86bios_trace_int); 91 SYSCTL_INT(_debug_x86bios, OID_AUTO, int, CTLFLAG_RW, &x86bios_trace_int, 0, 92 "Trace software interrupt handlers"); 93 94 static void * 95 x86bios_get_pages(uint32_t offset, size_t size) 96 { 97 int i; 98 99 if (offset + size > X86BIOS_MEM_SIZE) 100 return (NULL); 101 102 i = offset / X86BIOS_PAGE_SIZE; 103 if (x86bios_map[i] != 0) 104 return ((void *)(x86bios_map[i] + offset - 105 i * X86BIOS_PAGE_SIZE)); 106 107 return (NULL); 108 } 109 110 static void 111 x86bios_set_pages(vm_offset_t va, vm_paddr_t pa, size_t size) 112 { 113 int i, j; 114 115 for (i = pa / X86BIOS_PAGE_SIZE, j = 0; 116 j < howmany(size, X86BIOS_PAGE_SIZE); i++, j++) 117 x86bios_map[i] = va + j * X86BIOS_PAGE_SIZE; 118 } 119 120 static uint8_t 121 x86bios_emu_rdb(struct x86emu *emu, uint32_t addr) 122 { 123 uint8_t *va; 124 125 va = x86bios_get_pages(addr, sizeof(*va)); 126 if (va == NULL) 127 x86emu_halt_sys(emu); 128 129 return (*va); 130 } 131 132 static uint16_t 133 x86bios_emu_rdw(struct x86emu *emu, uint32_t addr) 134 { 135 uint16_t *va; 136 137 va = x86bios_get_pages(addr, sizeof(*va)); 138 if (va == NULL) 139 x86emu_halt_sys(emu); 140 141 return (le16toh(*va)); 142 } 143 144 static uint32_t 145 x86bios_emu_rdl(struct x86emu *emu, uint32_t addr) 146 { 147 uint32_t *va; 148 149 va = x86bios_get_pages(addr, sizeof(*va)); 150 if (va == NULL) 151 x86emu_halt_sys(emu); 152 153 return (le32toh(*va)); 154 } 155 156 static void 157 x86bios_emu_wrb(struct x86emu *emu, uint32_t addr, uint8_t val) 158 { 159 uint8_t *va; 160 161 va = x86bios_get_pages(addr, sizeof(*va)); 162 if (va == NULL) 163 x86emu_halt_sys(emu); 164 165 *va = val; 166 } 167 168 static void 169 x86bios_emu_wrw(struct x86emu *emu, uint32_t addr, uint16_t val) 170 { 171 uint16_t *va; 172 173 va = x86bios_get_pages(addr, sizeof(*va)); 174 if (va == NULL) 175 x86emu_halt_sys(emu); 176 177 *va = htole16(val); 178 } 179 180 static void 181 x86bios_emu_wrl(struct x86emu *emu, uint32_t addr, uint32_t val) 182 { 183 uint32_t *va; 184 185 va = x86bios_get_pages(addr, sizeof(*va)); 186 if (va == NULL) 187 x86emu_halt_sys(emu); 188 189 *va = htole32(val); 190 } 191 192 static uint8_t 193 x86bios_emu_inb(struct x86emu *emu, uint16_t port) 194 { 195 196 if (port == 0xb2) /* APM scratch register */ 197 return (0); 198 if (port >= 0x80 && port < 0x88) /* POST status register */ 199 return (0); 200 201 return (inb(port)); 202 } 203 204 static uint16_t 205 x86bios_emu_inw(struct x86emu *emu, uint16_t port) 206 { 207 208 if (port >= 0x80 && port < 0x88) /* POST status register */ 209 return (0); 210 211 return (inw(port)); 212 } 213 214 static uint32_t 215 x86bios_emu_inl(struct x86emu *emu, uint16_t port) 216 { 217 218 if (port >= 0x80 && port < 0x88) /* POST status register */ 219 return (0); 220 221 return (inl(port)); 222 } 223 224 static void 225 x86bios_emu_outb(struct x86emu *emu, uint16_t port, uint8_t val) 226 { 227 228 if (port == 0xb2) /* APM scratch register */ 229 return; 230 if (port >= 0x80 && port < 0x88) /* POST status register */ 231 return; 232 233 outb(port, val); 234 } 235 236 static void 237 x86bios_emu_outw(struct x86emu *emu, uint16_t port, uint16_t val) 238 { 239 240 if (port >= 0x80 && port < 0x88) /* POST status register */ 241 return; 242 243 outw(port, val); 244 } 245 246 static void 247 x86bios_emu_outl(struct x86emu *emu, uint16_t port, uint32_t val) 248 { 249 250 if (port >= 0x80 && port < 0x88) /* POST status register */ 251 return; 252 253 outl(port, val); 254 } 255 256 static void 257 x86bios_emu_get_intr(struct x86emu *emu, int intno) 258 { 259 uint16_t *sp; 260 uint32_t iv; 261 262 emu->x86.R_SP -= 6; 263 264 sp = (uint16_t *)((vm_offset_t)x86bios_seg + emu->x86.R_SP); 265 sp[0] = htole16(emu->x86.R_IP); 266 sp[1] = htole16(emu->x86.R_CS); 267 sp[2] = htole16(emu->x86.R_FLG); 268 269 iv = x86bios_get_intr(intno); 270 emu->x86.R_IP = iv & 0x000f; 271 emu->x86.R_CS = (iv >> 12) & 0xffff; 272 emu->x86.R_FLG &= ~(F_IF | F_TF); 273 } 274 275 void * 276 x86bios_alloc(uint32_t *offset, size_t size) 277 { 278 void *vaddr; 279 280 if (offset == NULL || size == 0) 281 return (NULL); 282 283 vaddr = contigmalloc(size, M_DEVBUF, M_NOWAIT, X86BIOS_RAM_BASE, 284 X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); 285 if (vaddr != NULL) { 286 *offset = vtophys(vaddr); 287 x86bios_set_pages((vm_offset_t)vaddr, *offset, size); 288 } 289 290 return (vaddr); 291 } 292 293 void 294 x86bios_free(void *addr, size_t size) 295 { 296 vm_paddr_t paddr; 297 298 if (addr == NULL || size == 0) 299 return; 300 301 paddr = vtophys(addr); 302 if (paddr < X86BIOS_RAM_BASE || paddr >= X86BIOS_ROM_BASE || 303 paddr % X86BIOS_PAGE_SIZE != 0) 304 return; 305 306 bzero(x86bios_map + paddr / X86BIOS_PAGE_SIZE, 307 sizeof(*x86bios_map) * howmany(size, X86BIOS_PAGE_SIZE)); 308 contigfree(addr, size, M_DEVBUF); 309 } 310 311 void 312 x86bios_init_regs(struct x86regs *regs) 313 { 314 315 bzero(regs, sizeof(*regs)); 316 regs->X86BIOS_R_DS = regs->X86BIOS_R_SS = x86bios_seg_phys >> 4; 317 } 318 319 void 320 x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) 321 { 322 323 if (x86bios_map == NULL) 324 return; 325 326 if (x86bios_trace_call) 327 printf("Calling 0x%05x (ax=0x%04x bx=0x%04x " 328 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 329 (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, 330 regs->R_DX, regs->R_ES, regs->R_DI); 331 332 mtx_lock_spin(&x86bios_lock); 333 memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); 334 x86emu_exec_call(&x86bios_emu, seg, off); 335 memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 336 mtx_unlock_spin(&x86bios_lock); 337 338 if (x86bios_trace_call) 339 printf("Exiting 0x%05x (ax=0x%04x bx=0x%04x " 340 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 341 (seg << 4) + off, regs->R_AX, regs->R_BX, regs->R_CX, 342 regs->R_DX, regs->R_ES, regs->R_DI); 343 } 344 345 uint32_t 346 x86bios_get_intr(int intno) 347 { 348 uint32_t *iv; 349 350 iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4); 351 352 return (le32toh(*iv)); 353 } 354 355 void 356 x86bios_intr(struct x86regs *regs, int intno) 357 { 358 359 if (intno < 0 || intno > 255) 360 return; 361 362 if (x86bios_map == NULL) 363 return; 364 365 if (x86bios_trace_int) 366 printf("Calling int 0x%x (ax=0x%04x bx=0x%04x " 367 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 368 intno, regs->R_AX, regs->R_BX, regs->R_CX, 369 regs->R_DX, regs->R_ES, regs->R_DI); 370 371 mtx_lock_spin(&x86bios_lock); 372 memcpy(&x86bios_emu.x86, regs, sizeof(*regs)); 373 x86emu_exec_intr(&x86bios_emu, intno); 374 memcpy(regs, &x86bios_emu.x86, sizeof(*regs)); 375 mtx_unlock_spin(&x86bios_lock); 376 377 if (x86bios_trace_int) 378 printf("Exiting int 0x%x (ax=0x%04x bx=0x%04x " 379 "cx=0x%04x dx=0x%04x es=0x%04x di=0x%04x)\n", 380 intno, regs->R_AX, regs->R_BX, regs->R_CX, 381 regs->R_DX, regs->R_ES, regs->R_DI); 382 } 383 384 void * 385 x86bios_offset(uint32_t offset) 386 { 387 388 return (x86bios_get_pages(offset, 1)); 389 } 390 391 void * 392 x86bios_get_orm(uint32_t offset) 393 { 394 uint8_t *p; 395 396 /* Does the shadow ROM contain BIOS POST code for x86? */ 397 p = x86bios_offset(offset); 398 if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9) 399 return (NULL); 400 401 return (p); 402 } 403 404 int 405 x86bios_match_device(uint32_t offset, device_t dev) 406 { 407 uint8_t *p; 408 uint16_t device, vendor; 409 uint8_t class, progif, subclass; 410 411 /* Does the shadow ROM contain BIOS POST code for x86? */ 412 p = x86bios_get_orm(offset); 413 if (p == NULL) 414 return (0); 415 416 /* Does it contain PCI data structure? */ 417 p += le16toh(*(uint16_t *)(p + 0x18)); 418 if (bcmp(p, "PCIR", 4) != 0 || 419 le16toh(*(uint16_t *)(p + 0x0a)) < 0x18 || *(p + 0x14) != 0) 420 return (0); 421 422 /* Does it match the vendor, device, and classcode? */ 423 vendor = le16toh(*(uint16_t *)(p + 0x04)); 424 device = le16toh(*(uint16_t *)(p + 0x06)); 425 progif = *(p + 0x0d); 426 subclass = *(p + 0x0e); 427 class = *(p + 0x0f); 428 if (vendor != pci_get_vendor(dev) || device != pci_get_device(dev) || 429 class != pci_get_class(dev) || subclass != pci_get_subclass(dev) || 430 progif != pci_get_progif(dev)) 431 return (0); 432 433 return (1); 434 } 435 436 static __inline int 437 x86bios_map_mem(void) 438 { 439 440 x86bios_ivt = pmap_mapbios(X86BIOS_IVT_BASE, X86BIOS_IVT_SIZE); 441 if (x86bios_ivt == NULL) 442 return (1); 443 x86bios_rom = pmap_mapdev(X86BIOS_ROM_BASE, X86BIOS_ROM_SIZE); 444 if (x86bios_rom == NULL) { 445 pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); 446 return (1); 447 } 448 x86bios_seg = contigmalloc(X86BIOS_SEG_SIZE, M_DEVBUF, M_WAITOK, 449 X86BIOS_RAM_BASE, X86BIOS_ROM_BASE, X86BIOS_PAGE_SIZE, 0); 450 x86bios_seg_phys = vtophys(x86bios_seg); 451 452 return (0); 453 } 454 455 static __inline void 456 x86bios_unmap_mem(void) 457 { 458 459 pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); 460 pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE); 461 contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF); 462 } 463 464 static void 465 x86bios_init(void *arg __unused) 466 { 467 int i; 468 469 mtx_init(&x86bios_lock, "x86bios lock", NULL, MTX_SPIN); 470 471 if (x86bios_map_mem() != 0) 472 return; 473 474 x86bios_map = malloc(sizeof(*x86bios_map) * X86BIOS_PAGES, M_DEVBUF, 475 M_WAITOK | M_ZERO); 476 x86bios_set_pages((vm_offset_t)x86bios_ivt, X86BIOS_IVT_BASE, 477 X86BIOS_IVT_SIZE); 478 x86bios_set_pages((vm_offset_t)x86bios_rom, X86BIOS_ROM_BASE, 479 X86BIOS_ROM_SIZE); 480 x86bios_set_pages((vm_offset_t)x86bios_seg, x86bios_seg_phys, 481 X86BIOS_SEG_SIZE); 482 483 bzero(&x86bios_emu, sizeof(x86bios_emu)); 484 485 x86bios_emu.emu_rdb = x86bios_emu_rdb; 486 x86bios_emu.emu_rdw = x86bios_emu_rdw; 487 x86bios_emu.emu_rdl = x86bios_emu_rdl; 488 x86bios_emu.emu_wrb = x86bios_emu_wrb; 489 x86bios_emu.emu_wrw = x86bios_emu_wrw; 490 x86bios_emu.emu_wrl = x86bios_emu_wrl; 491 492 x86bios_emu.emu_inb = x86bios_emu_inb; 493 x86bios_emu.emu_inw = x86bios_emu_inw; 494 x86bios_emu.emu_inl = x86bios_emu_inl; 495 x86bios_emu.emu_outb = x86bios_emu_outb; 496 x86bios_emu.emu_outw = x86bios_emu_outw; 497 x86bios_emu.emu_outl = x86bios_emu_outl; 498 499 for (i = 0; i < 256; i++) 500 x86bios_emu._x86emu_intrTab[i] = x86bios_emu_get_intr; 501 } 502 503 static void 504 x86bios_uninit(void *arg __unused) 505 { 506 vm_offset_t *map = x86bios_map; 507 508 mtx_lock_spin(&x86bios_lock); 509 if (x86bios_map != NULL) { 510 free(x86bios_map, M_DEVBUF); 511 x86bios_map = NULL; 512 } 513 mtx_unlock_spin(&x86bios_lock); 514 515 if (map != NULL) 516 x86bios_unmap_mem(); 517 518 mtx_destroy(&x86bios_lock); 519 } 520 521 static int 522 x86bios_modevent(module_t mod __unused, int type, void *data __unused) 523 { 524 525 switch (type) { 526 case MOD_LOAD: 527 x86bios_init(NULL); 528 break; 529 case MOD_UNLOAD: 530 x86bios_uninit(NULL); 531 break; 532 default: 533 return (ENOTSUP); 534 } 535 536 return (0); 537 } 538 539 static moduledata_t x86bios_mod = { 540 "x86bios", 541 x86bios_modevent, 542 NULL, 543 }; 544 545 DECLARE_MODULE(x86bios, x86bios_mod, SI_SUB_CPU, SI_ORDER_ANY); 546 MODULE_VERSION(x86bios, 1); 547