1/*- 2 * Copyright (c) 2005 3 * Bill Paul <wpaul@windriver.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/unistd.h> 39#include <sys/types.h> 40 41#include <sys/kernel.h> 42#include <sys/malloc.h> 43#include <sys/lock.h> 44#include <sys/mutex.h> 45#include <sys/module.h> 46#include <sys/conf.h> 47#include <sys/mbuf.h> 48#include <sys/bus.h> 49#include <sys/proc.h> 50#include <sys/sched.h> 51#include <sys/smp.h> 52 53#include <sys/queue.h> 54 55#ifdef __i386__ 56#include <machine/segments.h> 57#endif 58 59#include <dev/usb/usb.h> 60 61#include <compat/ndis/pe_var.h> 62#include <compat/ndis/cfg_var.h> 63#include <compat/ndis/resource_var.h> 64#include <compat/ndis/ntoskrnl_var.h> 65#include <compat/ndis/ndis_var.h> 66#include <compat/ndis/hal_var.h> 67#include <compat/ndis/usbd_var.h> 68 69static struct mtx drvdb_mtx; 70static STAILQ_HEAD(drvdb, drvdb_ent) drvdb_head; 71 72static driver_object fake_pci_driver; /* serves both PCI and cardbus */ 73static driver_object fake_pccard_driver; 74 75#ifdef __i386__ 76static void x86_oldldt(void *); 77static void x86_newldt(void *); 78 79struct tid { 80 void *tid_except_list; /* 0x00 */ 81 uint32_t tid_oldfs; /* 0x04 */ 82 uint32_t tid_selector; /* 0x08 */ 83 struct tid *tid_self; /* 0x0C */ 84 int tid_cpu; /* 0x10 */ 85}; 86 87static struct tid *my_tids; 88#endif /* __i386__ */ 89 90#define DUMMY_REGISTRY_PATH "\\\\some\\bogus\\path" 91 92int 93windrv_libinit(void) 94{ 95 STAILQ_INIT(&drvdb_head); 96 mtx_init(&drvdb_mtx, "Windows driver DB lock", 97 "Windows internal lock", MTX_DEF); 98 99 /* 100 * PCI and pccard devices don't need to use IRPs to 101 * interact with their bus drivers (usually), so our 102 * emulated PCI and pccard drivers are just stubs. 103 * USB devices, on the other hand, do all their I/O 104 * by exchanging IRPs with the USB bus driver, so 105 * for that we need to provide emulator dispatcher 106 * routines, which are in a separate module. 107 */ 108 109 windrv_bus_attach(&fake_pci_driver, "PCI Bus"); 110 windrv_bus_attach(&fake_pccard_driver, "PCCARD Bus"); 111 112#ifdef __i386__ 113 114 /* 115 * In order to properly support SMP machines, we have 116 * to modify the GDT on each CPU, since we never know 117 * on which one we'll end up running. 118 */ 119 120 my_tids = ExAllocatePoolWithTag(NonPagedPool, 121 sizeof(struct tid) * mp_ncpus, 0); 122 if (my_tids == NULL) 123 panic("failed to allocate thread info blocks"); 124 smp_rendezvous(NULL, x86_newldt, NULL, NULL); 125#endif 126 return (0); 127} 128 129int 130windrv_libfini(void) 131{ 132 struct drvdb_ent *d; 133 134 mtx_lock(&drvdb_mtx); 135 while(STAILQ_FIRST(&drvdb_head) != NULL) { 136 d = STAILQ_FIRST(&drvdb_head); 137 STAILQ_REMOVE_HEAD(&drvdb_head, link); 138 free(d, M_DEVBUF); 139 } 140 mtx_unlock(&drvdb_mtx); 141 142 RtlFreeUnicodeString(&fake_pci_driver.dro_drivername); 143 RtlFreeUnicodeString(&fake_pccard_driver.dro_drivername); 144 145 mtx_destroy(&drvdb_mtx); 146 147#ifdef __i386__ 148 smp_rendezvous(NULL, x86_oldldt, NULL, NULL); 149 ExFreePool(my_tids); 150#endif 151 return (0); 152} 153 154/* 155 * Given the address of a driver image, find its corresponding 156 * driver_object. 157 */ 158 159driver_object * 160windrv_lookup(img, name) 161 vm_offset_t img; 162 char *name; 163{ 164 struct drvdb_ent *d; 165 unicode_string us; 166 ansi_string as; 167 168 bzero((char *)&us, sizeof(us)); 169 170 /* Damn unicode. */ 171 172 if (name != NULL) { 173 RtlInitAnsiString(&as, name); 174 if (RtlAnsiStringToUnicodeString(&us, &as, TRUE)) 175 return (NULL); 176 } 177 178 mtx_lock(&drvdb_mtx); 179 STAILQ_FOREACH(d, &drvdb_head, link) { 180 if (d->windrv_object->dro_driverstart == (void *)img || 181 (bcmp((char *)d->windrv_object->dro_drivername.us_buf, 182 (char *)us.us_buf, us.us_len) == 0 && us.us_len)) { 183 mtx_unlock(&drvdb_mtx); 184 if (name != NULL) 185 ExFreePool(us.us_buf); 186 return (d->windrv_object); 187 } 188 } 189 mtx_unlock(&drvdb_mtx); 190 191 if (name != NULL) 192 RtlFreeUnicodeString(&us); 193 194 return (NULL); 195} 196 197struct drvdb_ent * 198windrv_match(matchfunc, ctx) 199 matchfuncptr matchfunc; 200 void *ctx; 201{ 202 struct drvdb_ent *d; 203 int match; 204 205 mtx_lock(&drvdb_mtx); 206 STAILQ_FOREACH(d, &drvdb_head, link) { 207 if (d->windrv_devlist == NULL) 208 continue; 209 match = matchfunc(d->windrv_bustype, d->windrv_devlist, ctx); 210 if (match == TRUE) { 211 mtx_unlock(&drvdb_mtx); 212 return (d); 213 } 214 } 215 mtx_unlock(&drvdb_mtx); 216 217 return (NULL); 218} 219 220/* 221 * Remove a driver_object from our datatabase and destroy it. Throw 222 * away any custom driver extension info that may have been added. 223 */ 224 225int 226windrv_unload(mod, img, len) 227 module_t mod; 228 vm_offset_t img; 229 int len; 230{ 231 struct drvdb_ent *db, *r = NULL; 232 driver_object *drv; 233 device_object *d, *pdo; 234 device_t dev; 235 list_entry *e; 236 237 drv = windrv_lookup(img, NULL); 238 239 /* 240 * When we unload a driver image, we need to force a 241 * detach of any devices that might be using it. We 242 * need the PDOs of all attached devices for this. 243 * Getting at them is a little hard. We basically 244 * have to walk the device lists of all our bus 245 * drivers. 246 */ 247 248 mtx_lock(&drvdb_mtx); 249 STAILQ_FOREACH(db, &drvdb_head, link) { 250 /* 251 * Fake bus drivers have no devlist info. 252 * If this driver has devlist info, it's 253 * a loaded Windows driver and has no PDOs, 254 * so skip it. 255 */ 256 if (db->windrv_devlist != NULL) 257 continue; 258 pdo = db->windrv_object->dro_devobj; 259 while (pdo != NULL) { 260 d = pdo->do_attacheddev; 261 if (d->do_drvobj != drv) { 262 pdo = pdo->do_nextdev; 263 continue; 264 } 265 dev = pdo->do_devext; 266 pdo = pdo->do_nextdev; 267 mtx_unlock(&drvdb_mtx); 268 device_detach(dev); 269 mtx_lock(&drvdb_mtx); 270 } 271 } 272 273 STAILQ_FOREACH(db, &drvdb_head, link) { 274 if (db->windrv_object->dro_driverstart == (void *)img) { 275 r = db; 276 STAILQ_REMOVE(&drvdb_head, db, drvdb_ent, link); 277 break; 278 } 279 } 280 mtx_unlock(&drvdb_mtx); 281 282 if (r == NULL) 283 return (ENOENT); 284 285 if (drv == NULL) 286 return (ENOENT); 287 288 /* 289 * Destroy any custom extensions that may have been added. 290 */ 291 drv = r->windrv_object; 292 while (!IsListEmpty(&drv->dro_driverext->dre_usrext)) { 293 e = RemoveHeadList(&drv->dro_driverext->dre_usrext); 294 ExFreePool(e); 295 } 296 297 /* Free the driver extension */ 298 free(drv->dro_driverext, M_DEVBUF); 299 300 /* Free the driver name */ 301 RtlFreeUnicodeString(&drv->dro_drivername); 302 303 /* Free driver object */ 304 free(drv, M_DEVBUF); 305 306 /* Free our DB handle */ 307 free(r, M_DEVBUF); 308 309 return (0); 310} 311 312#define WINDRV_LOADED htonl(0x42534F44) 313 314#ifdef __amd64__ 315static void 316patch_user_shared_data_address(vm_offset_t img, size_t len) 317{ 318 unsigned long i, n, max_addr, *addr; 319 320 n = len - sizeof(unsigned long); 321 max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); 322 for (i = 0; i < n; i++) { 323 addr = (unsigned long *)(img + i); 324 if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { 325 *addr -= KI_USER_SHARED_DATA; 326 *addr += (unsigned long)&kuser_shared_data; 327 } 328 } 329} 330#endif 331 332/* 333 * Loader routine for actual Windows driver modules, ultimately 334 * calls the driver's DriverEntry() routine. 335 */ 336 337int 338windrv_load(mod, img, len, bustype, devlist, regvals) 339 module_t mod; 340 vm_offset_t img; 341 int len; 342 interface_type bustype; 343 void *devlist; 344 ndis_cfg *regvals; 345{ 346 image_import_descriptor imp_desc; 347 image_optional_header opt_hdr; 348 driver_entry entry; 349 struct drvdb_ent *new; 350 struct driver_object *drv; 351 int status; 352 uint32_t *ptr; 353 ansi_string as; 354 355 /* 356 * First step: try to relocate and dynalink the executable 357 * driver image. 358 */ 359 360 ptr = (uint32_t *)(img + 8); 361 if (*ptr == WINDRV_LOADED) 362 goto skipreloc; 363 364 /* Perform text relocation */ 365 if (pe_relocate(img)) 366 return (ENOEXEC); 367 368 /* Dynamically link the NDIS.SYS routines -- required. */ 369 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 370 return (ENOEXEC); 371 372 /* Dynamically link the HAL.dll routines -- optional. */ 373 if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) { 374 if (pe_patch_imports(img, "HAL", hal_functbl)) 375 return (ENOEXEC); 376 } 377 378 /* Dynamically link ntoskrnl.exe -- optional. */ 379 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { 380 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) 381 return (ENOEXEC); 382 } 383 384#ifdef __amd64__ 385 patch_user_shared_data_address(img, len); 386#endif 387 388 /* Dynamically link USBD.SYS -- optional */ 389 if (pe_get_import_descriptor(img, &imp_desc, "USBD") == 0) { 390 if (pe_patch_imports(img, "USBD", usbd_functbl)) 391 return (ENOEXEC); 392 } 393 394 *ptr = WINDRV_LOADED; 395 396skipreloc: 397 398 /* Next step: find the driver entry point. */ 399 400 pe_get_optional_header(img, &opt_hdr); 401 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 402 403 /* Next step: allocate and store a driver object. */ 404 405 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO); 406 if (new == NULL) 407 return (ENOMEM); 408 409 drv = malloc(sizeof(driver_object), M_DEVBUF, M_NOWAIT|M_ZERO); 410 if (drv == NULL) { 411 free (new, M_DEVBUF); 412 return (ENOMEM); 413 } 414 415 /* Allocate a driver extension structure too. */ 416 417 drv->dro_driverext = malloc(sizeof(driver_extension), 418 M_DEVBUF, M_NOWAIT|M_ZERO); 419 420 if (drv->dro_driverext == NULL) { 421 free(new, M_DEVBUF); 422 free(drv, M_DEVBUF); 423 return (ENOMEM); 424 } 425 426 InitializeListHead((&drv->dro_driverext->dre_usrext)); 427 428 drv->dro_driverstart = (void *)img; 429 drv->dro_driversize = len; 430 431 RtlInitAnsiString(&as, DUMMY_REGISTRY_PATH); 432 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) { 433 free(new, M_DEVBUF); 434 free(drv, M_DEVBUF); 435 return (ENOMEM); 436 } 437 438 new->windrv_object = drv; 439 new->windrv_regvals = regvals; 440 new->windrv_devlist = devlist; 441 new->windrv_bustype = bustype; 442 443 /* Now call the DriverEntry() function. */ 444 445 status = MSCALL2(entry, drv, &drv->dro_drivername); 446 447 if (status != STATUS_SUCCESS) { 448 RtlFreeUnicodeString(&drv->dro_drivername); 449 free(drv, M_DEVBUF); 450 free(new, M_DEVBUF); 451 return (ENODEV); 452 } 453 454 mtx_lock(&drvdb_mtx); 455 STAILQ_INSERT_HEAD(&drvdb_head, new, link); 456 mtx_unlock(&drvdb_mtx); 457 458 return (0); 459} 460 461/* 462 * Make a new Physical Device Object for a device that was 463 * detected/plugged in. For us, the PDO is just a way to 464 * get at the device_t. 465 */ 466 467int 468windrv_create_pdo(drv, bsddev) 469 driver_object *drv; 470 device_t bsddev; 471{ 472 device_object *dev; 473 474 /* 475 * This is a new physical device object, which technically 476 * is the "top of the stack." Consequently, we don't do 477 * an IoAttachDeviceToDeviceStack() here. 478 */ 479 480 mtx_lock(&drvdb_mtx); 481 IoCreateDevice(drv, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev); 482 mtx_unlock(&drvdb_mtx); 483 484 /* Stash pointer to our BSD device handle. */ 485 486 dev->do_devext = bsddev; 487 488 return (STATUS_SUCCESS); 489} 490 491void 492windrv_destroy_pdo(drv, bsddev) 493 driver_object *drv; 494 device_t bsddev; 495{ 496 device_object *pdo; 497 498 pdo = windrv_find_pdo(drv, bsddev); 499 500 /* Remove reference to device_t */ 501 502 pdo->do_devext = NULL; 503 504 mtx_lock(&drvdb_mtx); 505 IoDeleteDevice(pdo); 506 mtx_unlock(&drvdb_mtx); 507} 508 509/* 510 * Given a device_t, find the corresponding PDO in a driver's 511 * device list. 512 */ 513 514device_object * 515windrv_find_pdo(drv, bsddev) 516 driver_object *drv; 517 device_t bsddev; 518{ 519 device_object *pdo; 520 521 mtx_lock(&drvdb_mtx); 522 pdo = drv->dro_devobj; 523 while (pdo != NULL) { 524 if (pdo->do_devext == bsddev) { 525 mtx_unlock(&drvdb_mtx); 526 return (pdo); 527 } 528 pdo = pdo->do_nextdev; 529 } 530 mtx_unlock(&drvdb_mtx); 531 532 return (NULL); 533} 534 535/* 536 * Add an internally emulated driver to the database. We need this 537 * to set up an emulated bus driver so that it can receive IRPs. 538 */ 539 540int 541windrv_bus_attach(drv, name) 542 driver_object *drv; 543 char *name; 544{ 545 struct drvdb_ent *new; 546 ansi_string as; 547 548 new = malloc(sizeof(struct drvdb_ent), M_DEVBUF, M_NOWAIT|M_ZERO); 549 if (new == NULL) 550 return (ENOMEM); 551 552 RtlInitAnsiString(&as, name); 553 if (RtlAnsiStringToUnicodeString(&drv->dro_drivername, &as, TRUE)) 554 { 555 free(new, M_DEVBUF); 556 return (ENOMEM); 557 } 558 559 /* 560 * Set up a fake image pointer to avoid false matches 561 * in windrv_lookup(). 562 */ 563 drv->dro_driverstart = (void *)0xFFFFFFFF; 564 565 new->windrv_object = drv; 566 new->windrv_devlist = NULL; 567 new->windrv_regvals = NULL; 568 569 mtx_lock(&drvdb_mtx); 570 STAILQ_INSERT_HEAD(&drvdb_head, new, link); 571 mtx_unlock(&drvdb_mtx); 572 573 return (0); 574} 575 576#ifdef __amd64__ 577 578extern void x86_64_wrap(void); 579extern void x86_64_wrap_call(void); 580extern void x86_64_wrap_end(void); 581 582int 583windrv_wrap(func, wrap, argcnt, ftype) 584 funcptr func; 585 funcptr *wrap; 586 int argcnt; 587 int ftype; 588{ 589 funcptr p; 590 vm_offset_t *calladdr; 591 vm_offset_t wrapstart, wrapend, wrapcall; 592 593 wrapstart = (vm_offset_t)&x86_64_wrap; 594 wrapend = (vm_offset_t)&x86_64_wrap_end; 595 wrapcall = (vm_offset_t)&x86_64_wrap_call; 596 597 /* Allocate a new wrapper instance. */ 598 599 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); 600 if (p == NULL) 601 return (ENOMEM); 602 603 /* Copy over the code. */ 604 605 bcopy((char *)wrapstart, p, (wrapend - wrapstart)); 606 607 /* Insert the function address into the new wrapper instance. */ 608 609 calladdr = (uint64_t *)((char *)p + (wrapcall - wrapstart) + 2); 610 *calladdr = (vm_offset_t)func; 611 612 *wrap = p; 613 614 return (0); 615} 616#endif /* __amd64__ */ 617 618 619#ifdef __i386__ 620 621struct x86desc { 622 uint16_t x_lolimit; 623 uint16_t x_base0; 624 uint8_t x_base1; 625 uint8_t x_flags; 626 uint8_t x_hilimit; 627 uint8_t x_base2; 628}; 629 630struct gdt { 631 uint16_t limit; 632 void *base; 633} __attribute__((__packed__)); 634 635extern uint16_t x86_getfs(void); 636extern void x86_setfs(uint16_t); 637extern void *x86_gettid(void); 638extern void x86_critical_enter(void); 639extern void x86_critical_exit(void); 640extern void x86_getldt(struct gdt *, uint16_t *); 641extern void x86_setldt(struct gdt *, uint16_t); 642 643#define SEL_LDT 4 /* local descriptor table */ 644#define SEL_TO_FS(x) (((x) << 3)) 645 646/* 647 * FreeBSD 6.0 and later has a special GDT segment reserved 648 * specifically for us, so if GNDIS_SEL is defined, use that. 649 * If not, use GTGATE_SEL, which is uninitialized and infrequently 650 * used. 651 */ 652 653#ifdef GNDIS_SEL 654#define FREEBSD_EMPTYSEL GNDIS_SEL 655#else 656#define FREEBSD_EMPTYSEL GTGATE_SEL /* slot 7 */ 657#endif 658 659/* 660 * The meanings of various bits in a descriptor vary a little 661 * depending on whether the descriptor will be used as a 662 * code, data or system descriptor. (And that in turn depends 663 * on which segment register selects the descriptor.) 664 * We're only trying to create a data segment, so the definitions 665 * below are the ones that apply to a data descriptor. 666 */ 667 668#define SEGFLAGLO_PRESENT 0x80 /* segment is present */ 669#define SEGFLAGLO_PRIVLVL 0x60 /* privlevel needed for this seg */ 670#define SEGFLAGLO_CD 0x10 /* 1 = code/data, 0 = system */ 671#define SEGFLAGLO_MBZ 0x08 /* must be zero */ 672#define SEGFLAGLO_EXPANDDOWN 0x04 /* limit expands down */ 673#define SEGFLAGLO_WRITEABLE 0x02 /* segment is writeable */ 674#define SEGGLAGLO_ACCESSED 0x01 /* segment has been accessed */ 675 676#define SEGFLAGHI_GRAN 0x80 /* granularity, 1 = byte, 0 = page */ 677#define SEGFLAGHI_BIG 0x40 /* 1 = 32 bit stack, 0 = 16 bit */ 678 679/* 680 * Context switch from UNIX to Windows. Save the existing value 681 * of %fs for this processor, then change it to point to our 682 * fake TID. Note that it is also possible to pin ourselves 683 * to our current CPU, though I'm not sure this is really 684 * necessary. It depends on whether or not an interrupt might 685 * preempt us while Windows code is running and we wind up 686 * scheduled onto another CPU as a result. So far, it doesn't 687 * seem like this is what happens. 688 */ 689 690void 691ctxsw_utow(void) 692{ 693 struct tid *t; 694 695 t = &my_tids[curthread->td_oncpu]; 696 697 /* 698 * Ugly hack. During system bootstrap (cold == 1), only CPU 0 699 * is running. So if we were loaded at bootstrap, only CPU 0 700 * will have our special GDT entry. This is a problem for SMP 701 * systems, so to deal with this, we check here to make sure 702 * the TID for this processor has been initialized, and if it 703 * hasn't, we need to do it right now or else things will 704 * explode. 705 */ 706 707 if (t->tid_self != t) 708 x86_newldt(NULL); 709 710 x86_critical_enter(); 711 t->tid_oldfs = x86_getfs(); 712 t->tid_cpu = curthread->td_oncpu; 713 sched_pin(); 714 x86_setfs(SEL_TO_FS(t->tid_selector)); 715 x86_critical_exit(); 716 717 /* Now entering Windows land, population: you. */ 718} 719 720/* 721 * Context switch from Windows back to UNIX. Restore %fs to 722 * its previous value. This always occurs after a call to 723 * ctxsw_utow(). 724 */ 725 726void 727ctxsw_wtou(void) 728{ 729 struct tid *t; 730 731 x86_critical_enter(); 732 t = x86_gettid(); 733 x86_setfs(t->tid_oldfs); 734 sched_unpin(); 735 x86_critical_exit(); 736 737 /* Welcome back to UNIX land, we missed you. */ 738 739#ifdef EXTRA_SANITY 740 if (t->tid_cpu != curthread->td_oncpu) 741 panic("ctxsw GOT MOVED TO OTHER CPU!"); 742#endif 743} 744 745static int windrv_wrap_stdcall(funcptr, funcptr *, int); 746static int windrv_wrap_fastcall(funcptr, funcptr *, int); 747static int windrv_wrap_regparm(funcptr, funcptr *); 748 749extern void x86_fastcall_wrap(void); 750extern void x86_fastcall_wrap_call(void); 751extern void x86_fastcall_wrap_arg(void); 752extern void x86_fastcall_wrap_end(void); 753 754static int 755windrv_wrap_fastcall(func, wrap, argcnt) 756 funcptr func; 757 funcptr *wrap; 758 int8_t argcnt; 759{ 760 funcptr p; 761 vm_offset_t *calladdr; 762 uint8_t *argaddr; 763 vm_offset_t wrapstart, wrapend, wrapcall, wraparg; 764 765 wrapstart = (vm_offset_t)&x86_fastcall_wrap; 766 wrapend = (vm_offset_t)&x86_fastcall_wrap_end; 767 wrapcall = (vm_offset_t)&x86_fastcall_wrap_call; 768 wraparg = (vm_offset_t)&x86_fastcall_wrap_arg; 769 770 /* Allocate a new wrapper instance. */ 771 772 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); 773 if (p == NULL) 774 return (ENOMEM); 775 776 /* Copy over the code. */ 777 778 bcopy((char *)wrapstart, p, (wrapend - wrapstart)); 779 780 /* Insert the function address into the new wrapper instance. */ 781 782 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 783 *calladdr = (vm_offset_t)func; 784 785 argcnt -= 2; 786 if (argcnt < 1) 787 argcnt = 0; 788 789 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1)); 790 *argaddr = argcnt * sizeof(uint32_t); 791 792 *wrap = p; 793 794 return (0); 795} 796 797extern void x86_stdcall_wrap(void); 798extern void x86_stdcall_wrap_call(void); 799extern void x86_stdcall_wrap_arg(void); 800extern void x86_stdcall_wrap_end(void); 801 802static int 803windrv_wrap_stdcall(func, wrap, argcnt) 804 funcptr func; 805 funcptr *wrap; 806 uint8_t argcnt; 807{ 808 funcptr p; 809 vm_offset_t *calladdr; 810 uint8_t *argaddr; 811 vm_offset_t wrapstart, wrapend, wrapcall, wraparg; 812 813 wrapstart = (vm_offset_t)&x86_stdcall_wrap; 814 wrapend = (vm_offset_t)&x86_stdcall_wrap_end; 815 wrapcall = (vm_offset_t)&x86_stdcall_wrap_call; 816 wraparg = (vm_offset_t)&x86_stdcall_wrap_arg; 817 818 /* Allocate a new wrapper instance. */ 819 820 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); 821 if (p == NULL) 822 return (ENOMEM); 823 824 /* Copy over the code. */ 825 826 bcopy((char *)wrapstart, p, (wrapend - wrapstart)); 827 828 /* Insert the function address into the new wrapper instance. */ 829 830 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 831 *calladdr = (vm_offset_t)func; 832 833 argaddr = (u_int8_t *)((char *)p + ((wraparg - wrapstart) + 1)); 834 *argaddr = argcnt * sizeof(uint32_t); 835 836 *wrap = p; 837 838 return (0); 839} 840 841extern void x86_regparm_wrap(void); 842extern void x86_regparm_wrap_call(void); 843extern void x86_regparm_wrap_end(void); 844 845static int 846windrv_wrap_regparm(func, wrap) 847 funcptr func; 848 funcptr *wrap; 849{ 850 funcptr p; 851 vm_offset_t *calladdr; 852 vm_offset_t wrapstart, wrapend, wrapcall; 853 854 wrapstart = (vm_offset_t)&x86_regparm_wrap; 855 wrapend = (vm_offset_t)&x86_regparm_wrap_end; 856 wrapcall = (vm_offset_t)&x86_regparm_wrap_call; 857 858 /* Allocate a new wrapper instance. */ 859 860 p = malloc((wrapend - wrapstart), M_DEVBUF, M_NOWAIT); 861 if (p == NULL) 862 return (ENOMEM); 863 864 /* Copy over the code. */ 865 866 bcopy(x86_regparm_wrap, p, (wrapend - wrapstart)); 867 868 /* Insert the function address into the new wrapper instance. */ 869 870 calladdr = (vm_offset_t *)((char *)p + ((wrapcall - wrapstart) + 1)); 871 *calladdr = (vm_offset_t)func; 872 873 *wrap = p; 874 875 return (0); 876} 877 878int 879windrv_wrap(func, wrap, argcnt, ftype) 880 funcptr func; 881 funcptr *wrap; 882 int argcnt; 883 int ftype; 884{ 885 switch(ftype) { 886 case WINDRV_WRAP_FASTCALL: 887 return (windrv_wrap_fastcall(func, wrap, argcnt)); 888 case WINDRV_WRAP_STDCALL: 889 return (windrv_wrap_stdcall(func, wrap, argcnt)); 890 case WINDRV_WRAP_REGPARM: 891 return (windrv_wrap_regparm(func, wrap)); 892 case WINDRV_WRAP_CDECL: 893 return (windrv_wrap_stdcall(func, wrap, 0)); 894 default: 895 break; 896 } 897 898 return (EINVAL); 899} 900 901static void 902x86_oldldt(dummy) 903 void *dummy; 904{ 905 struct x86desc *gdt; 906 struct gdt gtable; 907 uint16_t ltable; 908 909 mtx_lock_spin(&dt_lock); 910 911 /* Grab location of existing GDT. */ 912 913 x86_getldt(>able, <able); 914 915 /* Find the slot we updated. */ 916 917 gdt = gtable.base; 918 gdt += FREEBSD_EMPTYSEL; 919 920 /* Empty it out. */ 921 922 bzero((char *)gdt, sizeof(struct x86desc)); 923 924 /* Restore GDT. */ 925 926 x86_setldt(>able, ltable); 927 928 mtx_unlock_spin(&dt_lock); 929} 930 931static void 932x86_newldt(dummy) 933 void *dummy; 934{ 935 struct gdt gtable; 936 uint16_t ltable; 937 struct x86desc *l; 938 struct thread *t; 939 940 t = curthread; 941 942 mtx_lock_spin(&dt_lock); 943 944 /* Grab location of existing GDT. */ 945 946 x86_getldt(>able, <able); 947 948 /* Get pointer to the GDT table. */ 949 950 l = gtable.base; 951 952 /* Get pointer to empty slot */ 953 954 l += FREEBSD_EMPTYSEL; 955 956 /* Initialize TID for this CPU. */ 957 958 my_tids[t->td_oncpu].tid_selector = FREEBSD_EMPTYSEL; 959 my_tids[t->td_oncpu].tid_self = &my_tids[t->td_oncpu]; 960 961 /* Set up new GDT entry. */ 962 963 l->x_lolimit = sizeof(struct tid); 964 l->x_hilimit = SEGFLAGHI_GRAN|SEGFLAGHI_BIG; 965 l->x_base0 = (vm_offset_t)(&my_tids[t->td_oncpu]) & 0xFFFF; 966 l->x_base1 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 16) & 0xFF; 967 l->x_base2 = ((vm_offset_t)(&my_tids[t->td_oncpu]) >> 24) & 0xFF; 968 l->x_flags = SEGFLAGLO_PRESENT|SEGFLAGLO_CD|SEGFLAGLO_WRITEABLE; 969 970 /* Update the GDT. */ 971 972 x86_setldt(>able, ltable); 973 974 mtx_unlock_spin(&dt_lock); 975 976 /* Whew. */ 977} 978 979#endif /* __i386__ */ 980 981int 982windrv_unwrap(func) 983 funcptr func; 984{ 985 free(func, M_DEVBUF); 986 987 return (0); 988} 989