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