1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ex/harderr.c 5 * PURPOSE: Error Functions and Status/Exception Dispatching/Raising 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define TAG_ERR ' rrE' 16 17 /* GLOBALS ******************************************************************/ 18 19 BOOLEAN ExReadyForErrors = FALSE; 20 PVOID ExpDefaultErrorPort = NULL; 21 PEPROCESS ExpDefaultErrorPortProcess = NULL; 22 23 /* FUNCTIONS ****************************************************************/ 24 25 /*++ 26 * @name ExpSystemErrorHandler 27 * 28 * For now it's a stub 29 * 30 * @param ErrorStatus 31 * FILLME 32 * 33 * @param NumberOfParameters 34 * FILLME 35 * 36 * @param UnicodeStringParameterMask 37 * FILLME 38 * 39 * @param Parameters 40 * FILLME 41 * 42 * @param ValidResponseOptions 43 * FILLME 44 * 45 * @param Response 46 * FILLME 47 * 48 * @return None 49 * 50 * @remarks None 51 * 52 *--*/ 53 NTSTATUS 54 NTAPI 55 ExpSystemErrorHandler(IN NTSTATUS ErrorStatus, 56 IN ULONG NumberOfParameters, 57 IN ULONG UnicodeStringParameterMask, 58 IN PULONG_PTR Parameters, 59 IN BOOLEAN Shutdown) 60 { 61 ULONG_PTR BugCheckParameters[MAXIMUM_HARDERROR_PARAMETERS] = {0, 0, 0, 0}; 62 ULONG i; 63 64 /* Sanity check */ 65 ASSERT(NumberOfParameters <= MAXIMUM_HARDERROR_PARAMETERS); 66 67 /* 68 * KeBugCheck expects MAXIMUM_HARDERROR_PARAMETERS parameters, 69 * but we might get called with less, so use a local buffer here. 70 */ 71 for (i = 0; i < NumberOfParameters; i++) 72 { 73 /* Copy them over */ 74 BugCheckParameters[i] = Parameters[i]; 75 } 76 77 /* FIXME: STUB */ 78 KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR, 79 ErrorStatus, 80 (ULONG_PTR)BugCheckParameters, 81 0, 82 0); 83 return STATUS_SUCCESS; 84 } 85 86 /*++ 87 * @name ExpRaiseHardError 88 * @implemented 89 * 90 * See ExRaiseHardError and NtRaiseHardError, same parameters. 91 * 92 * This function performs the central work for both ExRaiseHardError 93 * and NtRaiseHardError. ExRaiseHardError is the service for kernel-mode 94 * that copies the parameters to user-mode, and NtRaiseHardError is the 95 * service for both kernel-mode and user-mode that performs parameters 96 * validation and capture if necessary. 97 * 98 *--*/ 99 NTSTATUS 100 NTAPI 101 ExpRaiseHardError(IN NTSTATUS ErrorStatus, 102 IN ULONG NumberOfParameters, 103 IN ULONG UnicodeStringParameterMask, 104 IN PULONG_PTR Parameters, 105 IN ULONG ValidResponseOptions, 106 OUT PULONG Response) 107 { 108 NTSTATUS Status; 109 PEPROCESS Process = PsGetCurrentProcess(); 110 PETHREAD Thread = PsGetCurrentThread(); 111 UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; 112 PHARDERROR_MSG Message = (PHARDERROR_MSG)Buffer; 113 HANDLE PortHandle; 114 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 115 116 PAGED_CODE(); 117 118 /* Check if this error will shutdown the system */ 119 if (ValidResponseOptions == OptionShutdownSystem) 120 { 121 /* 122 * Check if we have the privileges. 123 * 124 * NOTE: In addition to the Shutdown privilege we also check whether 125 * the caller has the Tcb privilege. The purpose is to allow only 126 * SYSTEM processes to "shutdown" the system on hard errors (BSOD) 127 * while forbidding regular processes to do so. This behaviour differs 128 * from Windows, where any user-mode process, as soon as it has the 129 * Shutdown privilege, can trigger a hard-error BSOD. 130 */ 131 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode) || 132 !SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) 133 { 134 /* No rights */ 135 *Response = ResponseNotHandled; 136 return STATUS_PRIVILEGE_NOT_HELD; 137 } 138 139 /* Don't handle any new hard errors */ 140 ExReadyForErrors = FALSE; 141 } 142 143 /* Check if hard errors are not disabled */ 144 if (!Thread->HardErrorsAreDisabled) 145 { 146 /* Check if we can't do errors anymore, and this is serious */ 147 if (!ExReadyForErrors && NT_ERROR(ErrorStatus)) 148 { 149 /* Use the system handler */ 150 ExpSystemErrorHandler(ErrorStatus, 151 NumberOfParameters, 152 UnicodeStringParameterMask, 153 Parameters, 154 (PreviousMode != KernelMode) ? TRUE : FALSE); 155 } 156 } 157 158 /* 159 * Enable hard error processing if it is enabled for the process 160 * or if the exception status forces it. 161 */ 162 if ((Process->DefaultHardErrorProcessing & SEM_FAILCRITICALERRORS) || 163 (ErrorStatus & HARDERROR_OVERRIDE_ERRORMODE)) 164 { 165 /* Check if we have an exception port */ 166 if (Process->ExceptionPort) 167 { 168 /* Use the port */ 169 PortHandle = Process->ExceptionPort; 170 } 171 else 172 { 173 /* Use our default system port */ 174 PortHandle = ExpDefaultErrorPort; 175 } 176 } 177 else 178 { 179 /* Don't process the error */ 180 PortHandle = NULL; 181 } 182 183 /* If hard errors are disabled, do nothing */ 184 if (Thread->HardErrorsAreDisabled) PortHandle = NULL; 185 186 /* 187 * If this is not the system thread, check whether hard errors are 188 * disabled for this thread on user-mode side, and if so, do nothing. 189 */ 190 if (!Thread->SystemThread && (PortHandle != NULL)) 191 { 192 /* Check if we have a TEB */ 193 PTEB Teb = PsGetCurrentThread()->Tcb.Teb; 194 if (Teb) 195 { 196 _SEH2_TRY 197 { 198 if (Teb->HardErrorMode & RTL_SEM_FAILCRITICALERRORS) 199 { 200 PortHandle = NULL; 201 } 202 } 203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 204 { 205 NOTHING; 206 } 207 _SEH2_END; 208 } 209 } 210 211 /* Now check if we have a port */ 212 if (PortHandle == NULL) 213 { 214 /* Just return to caller */ 215 *Response = ResponseReturnToCaller; 216 return STATUS_SUCCESS; 217 } 218 219 /* Check if this is the default process */ 220 if (Process == ExpDefaultErrorPortProcess) 221 { 222 /* We can't handle the error, check if this is critical */ 223 if (NT_ERROR(ErrorStatus)) 224 { 225 /* It is, invoke the system handler */ 226 ExpSystemErrorHandler(ErrorStatus, 227 NumberOfParameters, 228 UnicodeStringParameterMask, 229 Parameters, 230 (PreviousMode != KernelMode) ? TRUE : FALSE); 231 232 /* If we survived, return to caller */ 233 *Response = ResponseReturnToCaller; 234 return STATUS_SUCCESS; 235 } 236 } 237 238 /* Setup the LPC Message */ 239 Message->h.u1.Length = (sizeof(HARDERROR_MSG) << 16) | 240 (sizeof(HARDERROR_MSG) - sizeof(PORT_MESSAGE)); 241 Message->h.u2.ZeroInit = 0; 242 Message->h.u2.s2.Type = LPC_ERROR_EVENT; 243 Message->Status = ErrorStatus & ~HARDERROR_OVERRIDE_ERRORMODE; 244 Message->ValidResponseOptions = ValidResponseOptions; 245 Message->UnicodeStringParameterMask = UnicodeStringParameterMask; 246 Message->NumberOfParameters = NumberOfParameters; 247 KeQuerySystemTime(&Message->ErrorTime); 248 249 /* Copy the parameters */ 250 if (Parameters) 251 { 252 RtlMoveMemory(&Message->Parameters, 253 Parameters, 254 sizeof(ULONG_PTR) * NumberOfParameters); 255 } 256 257 /* Send the LPC Message */ 258 Status = LpcRequestWaitReplyPort(PortHandle, 259 (PPORT_MESSAGE)Message, 260 (PPORT_MESSAGE)Message); 261 if (NT_SUCCESS(Status)) 262 { 263 /* Check what kind of response we got */ 264 if ((Message->Response != ResponseReturnToCaller) && 265 (Message->Response != ResponseNotHandled) && 266 (Message->Response != ResponseAbort) && 267 (Message->Response != ResponseCancel) && 268 (Message->Response != ResponseIgnore) && 269 (Message->Response != ResponseNo) && 270 (Message->Response != ResponseOk) && 271 (Message->Response != ResponseRetry) && 272 (Message->Response != ResponseYes) && 273 (Message->Response != ResponseTryAgain) && 274 (Message->Response != ResponseContinue)) 275 { 276 /* Reset to a default one */ 277 Message->Response = ResponseReturnToCaller; 278 } 279 280 /* Set the response */ 281 *Response = Message->Response; 282 } 283 else 284 { 285 /* Set the response */ 286 *Response = ResponseReturnToCaller; 287 } 288 289 /* Return status */ 290 return Status; 291 } 292 293 /*++ 294 * @name ExRaiseAccessViolation 295 * @implemented 296 * 297 * The ExRaiseAccessViolation routine can be used with structured exception 298 * handling to throw a driver-determined exception for a memory access 299 * violation that occurs when a driver processes I/O requests. 300 * See: http://msdn.microsoft.com/library/en-us/Kernel_r/hh/Kernel_r/k102_71b4c053-599c-4a6d-8a59-08aae6bdc534.xml.asp?frame=true 301 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm 302 * 303 * @return None 304 * 305 * @remarks None 306 * 307 *--*/ 308 VOID 309 NTAPI 310 ExRaiseAccessViolation(VOID) 311 { 312 /* Raise the Right Status */ 313 RtlRaiseStatus(STATUS_ACCESS_VIOLATION); 314 } 315 316 /*++ 317 * @name ExRaiseDatatypeMisalignment 318 * @implemented 319 * 320 * ExRaiseDatatypeMisalignment raises an exception with the exception 321 * code set to STATUS_DATATYPE_MISALIGNMENT 322 * See: MSDN / DDK 323 * http://www.osronline.com/ddkx/kmarch/k102_814i.htm 324 * 325 * @return None 326 * 327 * @remarks None 328 * 329 *--*/ 330 VOID 331 NTAPI 332 ExRaiseDatatypeMisalignment(VOID) 333 { 334 /* Raise the Right Status */ 335 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); 336 } 337 338 /*++ 339 * @name ExSystemExceptionFilter 340 * @implemented 341 * 342 * TODO: Add description 343 * 344 * @return FILLME 345 * 346 * @remarks None 347 * 348 *--*/ 349 LONG 350 NTAPI 351 ExSystemExceptionFilter(VOID) 352 { 353 return KeGetPreviousMode() != KernelMode ? 354 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; 355 } 356 357 /*++ 358 * @name ExRaiseHardError 359 * @implemented 360 * 361 * See NtRaiseHardError and ExpRaiseHardError. 362 * 363 * @param ErrorStatus 364 * Error Code 365 * 366 * @param NumberOfParameters 367 * Number of optional parameters in Parameters array 368 * 369 * @param UnicodeStringParameterMask 370 * Optional string parameter (can be only one per error code) 371 * 372 * @param Parameters 373 * Array of ULONG parameters for use in error message string 374 * 375 * @param ValidResponseOptions 376 * See HARDERROR_RESPONSE_OPTION for possible values description 377 * 378 * @param Response 379 * Pointer to HARDERROR_RESPONSE enumeration 380 * 381 * @return Status 382 * 383 *--*/ 384 NTSTATUS 385 NTAPI 386 ExRaiseHardError(IN NTSTATUS ErrorStatus, 387 IN ULONG NumberOfParameters, 388 IN ULONG UnicodeStringParameterMask, 389 IN PULONG_PTR Parameters, 390 IN ULONG ValidResponseOptions, 391 OUT PULONG Response) 392 { 393 NTSTATUS Status; 394 SIZE_T Size; 395 UNICODE_STRING CapturedParams[MAXIMUM_HARDERROR_PARAMETERS]; 396 ULONG i; 397 PVOID UserData = NULL; 398 PHARDERROR_USER_PARAMETERS UserParams; 399 PWSTR BufferBase; 400 ULONG SafeResponse = ResponseNotHandled; 401 402 PAGED_CODE(); 403 404 /* Check if we have parameters */ 405 if (Parameters) 406 { 407 /* Check if we have strings */ 408 if (UnicodeStringParameterMask) 409 { 410 /* Calculate the required size */ 411 Size = FIELD_OFFSET(HARDERROR_USER_PARAMETERS, Buffer[0]); 412 413 /* Loop each parameter */ 414 for (i = 0; i < NumberOfParameters; i++) 415 { 416 /* Check if it's part of the mask */ 417 if (UnicodeStringParameterMask & (1 << i)) 418 { 419 /* Copy it */ 420 RtlMoveMemory(&CapturedParams[i], 421 (PVOID)Parameters[i], 422 sizeof(UNICODE_STRING)); 423 424 /* Increase the size */ 425 Size += CapturedParams[i].MaximumLength; 426 } 427 } 428 429 /* Allocate the user data region */ 430 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 431 &UserData, 432 0, 433 &Size, 434 MEM_COMMIT, 435 PAGE_READWRITE); 436 if (!NT_SUCCESS(Status)) 437 { 438 /* Return failure */ 439 *Response = ResponseNotHandled; 440 return Status; 441 } 442 443 /* Set the pointers to our data */ 444 UserParams = UserData; 445 BufferBase = UserParams->Buffer; 446 447 /* Enter SEH block as we are writing to user-mode space */ 448 _SEH2_TRY 449 { 450 /* Loop parameters again */ 451 for (i = 0; i < NumberOfParameters; i++) 452 { 453 /* Check if we are in the mask */ 454 if (UnicodeStringParameterMask & (1 << i)) 455 { 456 /* Update the base */ 457 UserParams->Parameters[i] = (ULONG_PTR)&UserParams->Strings[i]; 458 459 /* Copy the string buffer */ 460 RtlMoveMemory(BufferBase, 461 CapturedParams[i].Buffer, 462 CapturedParams[i].MaximumLength); 463 464 /* Set buffer */ 465 CapturedParams[i].Buffer = BufferBase; 466 467 /* Copy the string structure */ 468 UserParams->Strings[i] = CapturedParams[i]; 469 470 /* Update the pointer */ 471 BufferBase += CapturedParams[i].MaximumLength; 472 } 473 else 474 { 475 /* No need to copy any strings */ 476 UserParams->Parameters[i] = Parameters[i]; 477 } 478 } 479 } 480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 481 { 482 /* Return the exception code */ 483 Status = _SEH2_GetExceptionCode(); 484 DPRINT1("ExRaiseHardError - Exception when writing data to user-mode, Status 0x%08lx\n", Status); 485 } 486 _SEH2_END; 487 } 488 else 489 { 490 /* Just keep the data as is */ 491 UserData = Parameters; 492 } 493 } 494 495 /* Now call the worker function */ 496 Status = ExpRaiseHardError(ErrorStatus, 497 NumberOfParameters, 498 UnicodeStringParameterMask, 499 UserData, 500 ValidResponseOptions, 501 &SafeResponse); 502 503 /* Check if we had done user-mode allocation */ 504 if ((UserData) && (UserData != Parameters)) 505 { 506 /* We did! Delete it */ 507 Size = 0; 508 ZwFreeVirtualMemory(NtCurrentProcess(), 509 &UserData, 510 &Size, 511 MEM_RELEASE); 512 } 513 514 /* Return status and the response */ 515 *Response = SafeResponse; 516 return Status; 517 } 518 519 /*++ 520 * @name NtRaiseHardError 521 * @implemented 522 * 523 * This function sends HARDERROR_MSG LPC message to a hard-error listener, 524 * typically CSRSS.EXE. See NtSetDefaultHardErrorPort for more information. 525 * See also: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtRaiseHardError.html 526 * 527 * @param ErrorStatus 528 * Error Code 529 * 530 * @param NumberOfParameters 531 * Number of optional parameters in Parameters array 532 * 533 * @param UnicodeStringParameterMask 534 * Optional string parameter (can be only one per error code) 535 * 536 * @param Parameters 537 * Array of ULONG_PTR parameters for use in error message string 538 * 539 * @param ValidResponseOptions 540 * See HARDERROR_RESPONSE_OPTION for possible values description 541 * 542 * @param Response 543 * Pointer to HARDERROR_RESPONSE enumeration 544 * 545 * @return Status 546 * 547 * @remarks NtRaiseHardError constitutes an easy way to display messages 548 * in GUI without loading any Win32 API libraries. 549 * 550 *--*/ 551 NTSTATUS 552 NTAPI 553 NtRaiseHardError(IN NTSTATUS ErrorStatus, 554 IN ULONG NumberOfParameters, 555 IN ULONG UnicodeStringParameterMask, 556 IN PULONG_PTR Parameters, 557 IN ULONG ValidResponseOptions, 558 OUT PULONG Response) 559 { 560 NTSTATUS Status = STATUS_SUCCESS; 561 PULONG_PTR SafeParams = NULL; 562 ULONG SafeResponse = ResponseNotHandled; 563 UNICODE_STRING SafeString; 564 ULONG i; 565 ULONG ParamSize = 0; 566 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 567 568 PAGED_CODE(); 569 570 /* Validate parameter count */ 571 if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS) 572 { 573 /* Fail */ 574 return STATUS_INVALID_PARAMETER_2; 575 } 576 577 /* Make sure we have some at least */ 578 if ((Parameters != NULL) && (NumberOfParameters == 0)) 579 { 580 /* Fail */ 581 return STATUS_INVALID_PARAMETER_2; 582 } 583 584 /* Check if we were called from user-mode */ 585 if (PreviousMode != KernelMode) 586 { 587 /* First validate the responses */ 588 switch (ValidResponseOptions) 589 { 590 /* Check all valid cases */ 591 case OptionAbortRetryIgnore: 592 case OptionOk: 593 case OptionOkCancel: 594 case OptionRetryCancel: 595 case OptionYesNo: 596 case OptionYesNoCancel: 597 case OptionShutdownSystem: 598 case OptionOkNoWait: 599 case OptionCancelTryContinue: 600 break; 601 602 /* Anything else is invalid */ 603 default: 604 return STATUS_INVALID_PARAMETER_4; 605 } 606 607 /* Check if we have parameters */ 608 if (Parameters) 609 { 610 /* Calculate size of the parameters */ 611 ParamSize = sizeof(ULONG_PTR) * NumberOfParameters; 612 613 /* Allocate a safe buffer */ 614 SafeParams = ExAllocatePoolWithTag(PagedPool, ParamSize, TAG_ERR); 615 if (!SafeParams) 616 { 617 return STATUS_INSUFFICIENT_RESOURCES; 618 } 619 } 620 621 /* Enter SEH Block */ 622 _SEH2_TRY 623 { 624 /* Validate the response pointer */ 625 ProbeForWriteUlong(Response); 626 627 /* Check if we have parameters */ 628 if (Parameters) 629 { 630 /* Validate the parameter pointers */ 631 ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR)); 632 633 /* Copy them */ 634 RtlCopyMemory(SafeParams, Parameters, ParamSize); 635 636 /* Now check if there's strings in it */ 637 if (UnicodeStringParameterMask) 638 { 639 /* Loop every string */ 640 for (i = 0; i < NumberOfParameters; i++) 641 { 642 /* Check if this parameter is a string */ 643 if (UnicodeStringParameterMask & (1 << i)) 644 { 645 /* Probe the structure */ 646 ProbeForRead((PVOID)SafeParams[i], 647 sizeof(UNICODE_STRING), 648 sizeof(ULONG_PTR)); 649 650 /* Capture it */ 651 RtlCopyMemory(&SafeString, 652 (PVOID)SafeParams[i], 653 sizeof(UNICODE_STRING)); 654 655 /* Probe the buffer */ 656 ProbeForRead(SafeString.Buffer, 657 SafeString.MaximumLength, 658 sizeof(UCHAR)); 659 } 660 } 661 } 662 } 663 } 664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 665 { 666 /* Free captured buffer */ 667 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR); 668 669 /* Return the exception code */ 670 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 671 } 672 _SEH2_END; 673 674 /* Call the system function directly, because we probed */ 675 Status = ExpRaiseHardError(ErrorStatus, 676 NumberOfParameters, 677 UnicodeStringParameterMask, 678 SafeParams, 679 ValidResponseOptions, 680 &SafeResponse); 681 682 /* Free captured buffer */ 683 if (SafeParams) ExFreePoolWithTag(SafeParams, TAG_ERR); 684 685 /* Enter SEH Block to return the response */ 686 _SEH2_TRY 687 { 688 /* Return the response */ 689 *Response = SafeResponse; 690 } 691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 692 { 693 /* Get the exception code */ 694 Status = _SEH2_GetExceptionCode(); 695 } 696 _SEH2_END; 697 } 698 else 699 { 700 /* Reuse variable */ 701 SafeParams = Parameters; 702 703 /* 704 * Call the Executive Function. It will probe 705 * and copy pointers to user-mode. 706 */ 707 Status = ExRaiseHardError(ErrorStatus, 708 NumberOfParameters, 709 UnicodeStringParameterMask, 710 SafeParams, 711 ValidResponseOptions, 712 &SafeResponse); 713 714 /* Return the response */ 715 *Response = SafeResponse; 716 } 717 718 /* Return status */ 719 return Status; 720 } 721 722 /*++ 723 * @name NtSetDefaultHardErrorPort 724 * @implemented 725 * 726 * NtSetDefaultHardErrorPort is typically called only once. After the call, 727 * the kernel sets a BOOLEAN flag named ExReadyForErrors to TRUE, and all other 728 * attempts to change the default port fail with STATUS_UNSUCCESSFUL error code. 729 * See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Error/NtSetDefaultHardErrorPort.html 730 * https://web.archive.org/web/20070716133753/http://www.windowsitlibrary.com/Content/356/08/2.html 731 * 732 * @param PortHandle 733 * Handle to named port object 734 * 735 * @return Status 736 * 737 * @remarks Privileges: SE_TCB_PRIVILEGE 738 * 739 *--*/ 740 NTSTATUS 741 NTAPI 742 NtSetDefaultHardErrorPort(IN HANDLE PortHandle) 743 { 744 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 745 NTSTATUS Status = STATUS_UNSUCCESSFUL; 746 747 PAGED_CODE(); 748 749 /* Check if we have the privileges */ 750 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 751 { 752 DPRINT1("NtSetDefaultHardErrorPort: Caller requires " 753 "the SeTcbPrivilege privilege!\n"); 754 return STATUS_PRIVILEGE_NOT_HELD; 755 } 756 757 /* Only called once during bootup, make sure we weren't called yet */ 758 if (!ExReadyForErrors) 759 { 760 /* Reference the hard-error port */ 761 Status = ObReferenceObjectByHandle(PortHandle, 762 0, 763 LpcPortObjectType, 764 PreviousMode, 765 (PVOID*)&ExpDefaultErrorPort, 766 NULL); 767 if (NT_SUCCESS(Status)) 768 { 769 /* Keep also a reference to the process handling the hard errors */ 770 ExpDefaultErrorPortProcess = PsGetCurrentProcess(); 771 ObReferenceObject(ExpDefaultErrorPortProcess); 772 ExReadyForErrors = TRUE; 773 Status = STATUS_SUCCESS; 774 } 775 } 776 777 /* Return status to caller */ 778 return Status; 779 } 780 781 VOID 782 __cdecl 783 _purecall(VOID) 784 { 785 /* Not supported in Kernel Mode */ 786 RtlRaiseStatus(STATUS_NOT_IMPLEMENTED); 787 } 788 789 /* EOF */ 790