diff options
Diffstat (limited to 'private/ntos/rtl/i386')
23 files changed, 6661 insertions, 0 deletions
diff --git a/private/ntos/rtl/i386/context.c b/private/ntos/rtl/i386/context.c new file mode 100644 index 000000000..44ab2b358 --- /dev/null +++ b/private/ntos/rtl/i386/context.c @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + context.c + +Abstract: + + This module implements user-mode callable context manipulation routines. + The interfaces exported from this module are portable, but they must + be re-implemented for each architecture. + +Author: + + Mark Lucovsky (markl) 20-Jun-1989 + +Revision History: + + Bryan Willman (bryanwi) 8-Mar-90 + + Ported to the 80386 + +--*/ + +#include "ntrtlp.h" + +#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) +#pragma alloc_text(PAGE,RtlInitializeContext) +#pragma alloc_text(PAGE,RtlRemoteCall) +#endif + + +VOID +RtlInitializeContext( + IN HANDLE Process, + OUT PCONTEXT Context, + IN PVOID Parameter OPTIONAL, + IN PVOID InitialPc OPTIONAL, + IN PVOID InitialSp OPTIONAL + ) + +/*++ + +Routine Description: + + This function initializes a context structure so that it can + be used in a subsequent call to NtCreateThread. + +Arguments: + + Context - Supplies a context buffer to be initialized by this routine. + + InitialPc - Supplies an initial program counter value. + + InitialSp - Supplies an initial stack pointer value. + +Return Value: + + Raises STATUS_BAD_INITIAL_STACK if the value of InitialSp is not properly + aligned. + + Raises STATUS_BAD_INITIAL_PC if the value of InitialPc is not properly + aligned. + +--*/ + +{ + RTL_PAGED_CODE(); + + Context->Eax = 0L; + Context->Ebx = 1L; + Context->Ecx = 2L; + Context->Edx = 3L; + Context->Esi = 4L; + Context->Edi = 5L; + Context->Ebp = 0L; + + Context->SegGs = 0; + Context->SegFs = KGDT_R3_TEB; + Context->SegEs = KGDT_R3_DATA; + Context->SegDs = KGDT_R3_DATA; + Context->SegSs = KGDT_R3_DATA; + Context->SegCs = KGDT_R3_CODE; + + Context->EFlags = 0x200L; // force interrupts on, clear all else. + + // + // Even though these are optional, they are used as is, since NULL + // is what these would have been initialized to anyway + // + + Context->Esp = (ULONG) InitialSp; + Context->Eip = (ULONG) InitialPc; + + // + // add code to check alignment and raise exception... + // + + Context->ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS; + + // + // Set the initial context of the thread in a machine specific way. + // ie, pass the initial parameter to the start address + // + + Context->Esp -= sizeof(Parameter); + ZwWriteVirtualMemory(Process, + (PVOID)Context->Esp, + (PVOID)&Parameter, + sizeof(Parameter), + NULL); + Context->Esp -= sizeof(Parameter); // Reserve room for ret address + + +} + + + +NTSTATUS +RtlRemoteCall( + HANDLE Process, + HANDLE Thread, + PVOID CallSite, + ULONG ArgumentCount, + PULONG Arguments, + BOOLEAN PassContext, + BOOLEAN AlreadySuspended + ) + +/*++ + +Routine Description: + + This function calls a procedure in another thread/process, using + NtGetContext and NtSetContext. Parameters are passed to the + target procedure via its stack. + +Arguments: + + Process - Handle of the target process + + Thread - Handle of the target thread within that process + + CallSite - Address of the procedure to call in the target process. + + ArgumentCount - Number of 32 bit parameters to pass to the target + procedure. + + Arguments - Pointer to the array of 32 bit parameters to pass. + + PassContext - TRUE if an additional parameter is to be passed that + points to a context record. + + AlreadySuspended - TRUE if the target thread is already in a suspended + or waiting state. + +Return Value: + + Status - Status value + +--*/ + +{ + NTSTATUS Status; + CONTEXT Context; + ULONG NewSp; + ULONG ArgumentsCopy[5]; + + RTL_PAGED_CODE(); + + if (ArgumentCount > 4) + return STATUS_INVALID_PARAMETER; + + // + // If necessary, suspend the guy before with we mess with his stack. + // + if (!AlreadySuspended) { + Status = NtSuspendThread( Thread, NULL ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + } + + + // + // Get the context record for the target thread. + // + + Context.ContextFlags = CONTEXT_FULL; + Status = NtGetContextThread( Thread, &Context ); + if (!NT_SUCCESS( Status )) { + if (!AlreadySuspended) { + NtResumeThread( Thread, NULL ); + } + return( Status ); + } + + + // + // Pass all parameters on the stack, regardless of whether a + // a context record is passed. + // + + // + // Put Context Record on stack first, so it is above other args. + // + NewSp = Context.Esp; + if (PassContext) { + NewSp -= sizeof( CONTEXT ); + Status = NtWriteVirtualMemory( Process, + (PVOID)NewSp, + &Context, + sizeof( CONTEXT ), + NULL + ); + if (!NT_SUCCESS( Status )) { + if (!AlreadySuspended) { + NtResumeThread( Thread, NULL ); + } + return( Status ); + } + ArgumentsCopy[0] = NewSp; // pass pointer to context + RtlMoveMemory(&(ArgumentsCopy[1]),Arguments,ArgumentCount*sizeof( ULONG )); + ArgumentCount++; + } + else { + RtlMoveMemory(ArgumentsCopy,Arguments,ArgumentCount*sizeof( ULONG )); + } + + // + // Copy the arguments onto the target stack + // + if (ArgumentCount) { + NewSp -= ArgumentCount * sizeof( ULONG ); + Status = NtWriteVirtualMemory( Process, + (PVOID)NewSp, + ArgumentsCopy, + ArgumentCount * sizeof( ULONG ), + NULL + ); + if (!NT_SUCCESS( Status )) { + if (!AlreadySuspended) { + NtResumeThread( Thread, NULL ); + } + return( Status ); + } + } + + // + // Set the address of the target code into Eip, the new target stack + // into Esp, and reload context to make it happen. + // + Context.Esp = NewSp; + Context.Eip = (ULONG)CallSite; + Status = NtSetContextThread( Thread, &Context ); + if (!AlreadySuspended) { + NtResumeThread( Thread, NULL ); + } + + return( Status ); +} diff --git a/private/ntos/rtl/i386/debug2.asm b/private/ntos/rtl/i386/debug2.asm new file mode 100644 index 000000000..fcf84484b --- /dev/null +++ b/private/ntos/rtl/i386/debug2.asm @@ -0,0 +1,65 @@ + title "Debug Support Functions" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; debug.s +; +; Abstract: +; +; This module implements functions to support debugging NT. +; +; Author: +; +; Steven R. Wood (stevewo) 3-Aug-1989 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +; 11 April 90 (and before) bryanwi +; Ported to 386, 386 specific support added. +; +; 2 Aug. 90 (tomp) +; Added _DbgUnLoadImageSymbols routine. +; +;-- +.386p + + + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +_TEXT SEGMENT PUBLIC DWORD 'CODE' +ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING + +cPublicProc _DbgBreakPoint ,0 +cPublicFpo 0,0 + int 3 + stdRET _DbgBreakPoint +stdENDP _DbgBreakPoint + +cPublicProc _DbgUserBreakPoint ,0 +cPublicFpo 0,0 + int 3 + stdRET _DbgUserBreakPoint +stdENDP _DbgUserBreakPoint + +cPublicProc _DbgBreakPointWithStatus,1 +cPublicFpo 1,0 + mov eax,[esp+4] + public _RtlpBreakWithStatusInstruction@0 +_RtlpBreakWithStatusInstruction@0: + int 3 + stdRET _DbgBreakPointWithStatus +stdENDP _DbgBreakPointWithStatus + + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/debug3.c b/private/ntos/rtl/i386/debug3.c new file mode 100644 index 000000000..90944833d --- /dev/null +++ b/private/ntos/rtl/i386/debug3.c @@ -0,0 +1,121 @@ +//++ +// +// Copyright (c) 1990 Microsoft Corporation +// +// Module Name: +// +// debug3.c +// +// Abstract: +// +// This module implements architecture specific functions to support debugging NT. +// +// Author: +// +// Steven R. Wood (stevewo) 3-Aug-1989 +// +// Environment: +// +// Any mode. +// +// Revision History: +// +//-- + +#include "stdarg.h" +#include "stdio.h" +#include "string.h" +#include "ntrtlp.h" + +// +// Prototype for local procedure +// + +NTSTATUS +DebugService( + ULONG ServiceClass, + PVOID Arg1, + PVOID Arg2 + ); + +VOID _fptrap() {}; + +NTSTATUS +DebugPrint( + IN PSTRING Output + ) +{ + return DebugService( BREAKPOINT_PRINT, Output, 0 ); +} + + +ULONG +DebugPrompt( + IN PSTRING Output, + IN PSTRING Input + ) +{ + return DebugService( BREAKPOINT_PROMPT, Output, Input ); +} + +VOID +DebugLoadImageSymbols( + IN PSTRING FileName, + IN PKD_SYMBOLS_INFO SymbolInfo + ) +{ + DebugService( BREAKPOINT_LOAD_SYMBOLS, FileName, SymbolInfo ); +} + + +VOID +DebugUnLoadImageSymbols( + IN PSTRING FileName, + IN PKD_SYMBOLS_INFO SymbolInfo + ) +{ + DebugService( BREAKPOINT_UNLOAD_SYMBOLS, FileName, SymbolInfo ); +} + +NTSTATUS +DebugService( + ULONG ServiceClass, + PVOID Arg1, + PVOID Arg2 + ) + +//++ +// +// Routine Description: +// +// Allocate an ExceptionRecord, fill in data to allow exception +// dispatch code to do the right thing with the service, and +// call RtlRaiseException (NOT ExRaiseException!!!). +// +// Arguments: +// ServiceClass - which call is to be performed +// Arg1 - generic first argument +// Arg2 - generic second argument +// +// Returns: +// Whatever the exception returns in eax +// +//-- + +{ + NTSTATUS RetValue; + + _asm { + mov eax, ServiceClass + mov ecx, Arg1 + mov edx, Arg2 + + int 2dh ; Raise exception + int 3 ; DO NOT REMOVE (See KiDebugService) + + mov RetValue, eax + + } + + return RetValue; +} diff --git a/private/ntos/rtl/i386/divlarge.c b/private/ntos/rtl/i386/divlarge.c new file mode 100644 index 000000000..12cf1dce0 --- /dev/null +++ b/private/ntos/rtl/i386/divlarge.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + largediv.c + +Abstract: + + This module implements the NT runtime library large integer divide + routines. + + N.B. These routines use a one bit at a time algorithm and is slow. + They should be used only when absolutely necessary. + +Author: + + David N. Cutler 10-Aug-1992 + +Revision History: + +--*/ + +#include "ntrtlp.h" + +LARGE_INTEGER +RtlLargeIntegerDivide ( + IN LARGE_INTEGER Dividend, + IN LARGE_INTEGER Divisor, + OUT PLARGE_INTEGER Remainder OPTIONAL + ) + +/*++ + +Routine Description: + + This routine divides an unsigned 64-bit dividend by an unsigned 64-bit + divisor and returns a 64-bit quotient, and optionally a 64-bit remainder. + +Arguments: + + Dividend - Supplies the 64-bit dividend for the divide operation. + + Divisor - Supplies the 64-bit divisor for the divide operation. + + Remainder - Supplies an optional pointer to a variable which receives + the remainder + +Return Value: + + The 64-bit quotient is returned as the function value. + +--*/ + +{ + + ULONG Index = 64; + LARGE_INTEGER Partial = {0, 0}; + LARGE_INTEGER Quotient; + +#ifndef BLDR_KERNEL_RUNTIME + // + // Check for divide by zero + // + + if (!(Divisor.LowPart | Divisor.HighPart)) { + RtlRaiseStatus (STATUS_INTEGER_DIVIDE_BY_ZERO); + } +#endif + + // + // Loop through the dividend bits and compute the quotient and remainder. + // + + Quotient = Dividend; + do { + + // + // Shift the next dividend bit into the parital remainder and shift + // the partial quotient (dividend) left one bit. + // + + Partial.HighPart = (Partial.HighPart << 1) | (Partial.LowPart >> 31); + Partial.LowPart = (Partial.LowPart << 1) | ((ULONG)Quotient.HighPart >> 31); + Quotient.HighPart = (Quotient.HighPart << 1) | (Quotient.LowPart >> 31); + Quotient.LowPart <<= 1; + + // + // If the partial remainder is greater than or equal to the divisor, + // then subtract the divisor from the partial remainder and insert a + // one bit into the quotient. + // + + if (((ULONG)Partial.HighPart > (ULONG)Divisor.HighPart) || + ((Partial.HighPart == Divisor.HighPart) && + (Partial.LowPart >= Divisor.LowPart))) { + + Quotient.LowPart |= 1; + Partial.HighPart -= Divisor.HighPart; + if (Partial.LowPart < Divisor.LowPart) { + Partial.HighPart -= 1; + } + + Partial.LowPart -= Divisor.LowPart; + } + + Index -= 1; + } while (Index > 0); + + // + // If the remainder is requested, then return the 64-bit remainder. + // + + if (ARGUMENT_PRESENT(Remainder)) { + *Remainder = Partial; + } + + // + // Return the 64-bit quotient. + // + + return Quotient; +} diff --git a/private/ntos/rtl/i386/exdsptch.c b/private/ntos/rtl/i386/exdsptch.c new file mode 100644 index 000000000..2efec6aca --- /dev/null +++ b/private/ntos/rtl/i386/exdsptch.c @@ -0,0 +1,535 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + exdsptch.c + +Abstract: + + This module implements the dispatching of exception and the unwinding of + procedure call frames. + +Author: + + David N. Cutler (davec) 13-Aug-1989 + +Environment: + + Any mode. + +Revision History: + + 10 april 90 bryanwi + + Port to the 386. + +--*/ + +#include "ntrtlp.h" + + +// +// Dispatcher context structure definition. +// + +typedef struct _DISPATCHER_CONTEXT { + PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; + } DISPATCHER_CONTEXT; + +// +// Execute handler for exception function prototype. +// + +EXCEPTION_DISPOSITION +RtlpExecuteHandlerForException ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PVOID DispatcherContext, + IN PEXCEPTION_ROUTINE ExceptionRoutine + ); + +// +// Execute handler for unwind function prototype. +// + +EXCEPTION_DISPOSITION +RtlpExecuteHandlerForUnwind ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PVOID EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PVOID DispatcherContext, + IN PEXCEPTION_ROUTINE ExceptionRoutine + ); + + + +BOOLEAN +RtlDispatchException ( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT ContextRecord + ) + +/*++ + +Routine Description: + + This function attempts to dispatch an exception to a call frame based + handler by searching backwards through the stack based call frames. The + search begins with the frame specified in the context record and continues + backward until either a handler is found that handles the exception, the + stack is found to be invalid (i.e., out of limits or unaligned), or the end + of the call hierarchy is reached. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + ContextRecord - Supplies a pointer to a context record. + +Return Value: + + If the exception is handled by one of the frame based handlers, then + a value of TRUE is returned. Otherwise a value of FALSE is returned. + +--*/ + +{ + + DISPATCHER_CONTEXT DispatcherContext; + EXCEPTION_DISPOSITION Disposition; + PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; + PEXCEPTION_REGISTRATION_RECORD NestedRegistration; + ULONG HighAddress; + ULONG HighLimit; + ULONG LowLimit; + EXCEPTION_RECORD ExceptionRecord1; + + // + // Get current stack limits. + // + + RtlpGetStackLimits(&LowLimit, &HighLimit); + + // + // Start with the frame specified by the context record and search + // backwards through the call frame hierarchy attempting to find an + // exception handler that will handler the exception. + // + + RegistrationPointer = RtlpGetRegistrationHead(); + NestedRegistration = 0; + while (RegistrationPointer != EXCEPTION_CHAIN_END) { + + // + // If the call frame is not within the specified stack limits or the + // call frame is unaligned, then set the stack invalid flag in the + // exception record and return FALSE. Else check to determine if the + // frame has an exception handler. + // + + HighAddress = (ULONG)RegistrationPointer + + sizeof(EXCEPTION_REGISTRATION_RECORD); + + if ( ((ULONG)RegistrationPointer < LowLimit) || + (HighAddress > HighLimit) || + (((ULONG)RegistrationPointer & 0x3) != 0) ) { + ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; + return FALSE; + } else { + +#if !defined(WX86_i386) + + ULONG Index; + // + // The handler must be executed by calling another routine + // that is written in assembler. This is required because + // up level addressing of the handler information is required + // when a nested exception is encountered. + // + + if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) { + Index = RtlpLogExceptionHandler( + ExceptionRecord, + ContextRecord, + 0, + (PULONG)RegistrationPointer, + 4 * sizeof(ULONG)); + // can't use sizeof(EXCEPTION_REGISTRATION_RECORD + // because we need the 2 dwords above it. + } +#endif + + Disposition = RtlpExecuteHandlerForException( + ExceptionRecord, + (PVOID)RegistrationPointer, + ContextRecord, + (PVOID)&DispatcherContext, + (PEXCEPTION_ROUTINE)RegistrationPointer->Handler); + +#if !defined(WX86_i386) + if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) { + RtlpLogLastExceptionDisposition(Index, Disposition); + } +#endif + + + // + // If the current scan is within a nested context and the frame + // just examined is the end of the context region, then clear + // the nested context frame and the nested exception in the + // exception flags. + // + + if (NestedRegistration == RegistrationPointer) { + ExceptionRecord->ExceptionFlags &= (~EXCEPTION_NESTED_CALL); + NestedRegistration = 0; + } + + // + // Case on the handler disposition. + // + + switch (Disposition) { + + // + // The disposition is to continue execution. If the + // exception is not continuable, then raise the exception + // STATUS_NONCONTINUABLE_EXCEPTION. Otherwise return + // TRUE. + // + + case ExceptionContinueExecution : + if ((ExceptionRecord->ExceptionFlags & + EXCEPTION_NONCONTINUABLE) != 0) { + ExceptionRecord1.ExceptionCode = + STATUS_NONCONTINUABLE_EXCEPTION; + ExceptionRecord1.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord1.ExceptionRecord = ExceptionRecord; + ExceptionRecord1.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord1); + } else { + return TRUE; + } + + // + // The disposition is to continue the search. Get next + // frame address and continue the search. + // + + case ExceptionContinueSearch : + break; + + // + // The disposition is nested exception. Set the nested + // context frame to the establisher frame address and set + // nested exception in the exception flags. + // + + case ExceptionNestedException : + ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL; + if (DispatcherContext.RegistrationPointer > NestedRegistration) { + NestedRegistration = DispatcherContext.RegistrationPointer; + } + break; + + // + // All other disposition values are invalid. Raise + // invalid disposition exception. + // + + default : + ExceptionRecord1.ExceptionCode = STATUS_INVALID_DISPOSITION; + ExceptionRecord1.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord1.ExceptionRecord = ExceptionRecord; + ExceptionRecord1.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord1); + break; + } + + // + // If chain goes in wrong direction or loops, report an + // invalid exception stack, otherwise go on to the next one. + // + + RegistrationPointer = RegistrationPointer->Next; + } + } + return FALSE; +} + +VOID +RtlUnwind ( + IN PVOID TargetFrame OPTIONAL, + IN PVOID TargetIp OPTIONAL, + IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, + IN PVOID ReturnValue + ) + +/*++ + +Routine Description: + + This function initiates an unwind of procedure call frames. The machine + state at the time of the call to unwind is captured in a context record + and the unwinding flag is set in the exception flags of the exception + record. If the TargetFrame parameter is not specified, then the exit unwind + flag is also set in the exception flags of the exception record. A backward + walk through the procedure call frames is then performed to find the target + of the unwind operation. + + N.B. The captured context passed to unwinding handlers will not be + a completely accurate context set for the 386. This is because + there isn't a standard stack frame in which registers are stored. + + Only the integer registers are affected. The segement and + control registers (ebp, esp) will have correct values for + the flat 32 bit environment. + + N.B. If you change the number of arguments, make sure you change the + adjustment of ESP after the call to RtlpCaptureContext (for + STDCALL calling convention) + +Arguments: + + TargetFrame - Supplies an optional pointer to the call frame that is the + target of the unwind. If this parameter is not specified, then an exit + unwind is performed. + + TargetIp - Supplies an optional instruction address that specifies the + continuation address of the unwind. This address is ignored if the + target frame parameter is not specified. + + ExceptionRecord - Supplies an optional pointer to an exception record. + + ReturnValue - Supplies a value that is to be placed in the integer + function return register just before continuing execution. + +Return Value: + + None. + +--*/ + +{ + PCONTEXT ContextRecord; + CONTEXT ContextRecord1; + DISPATCHER_CONTEXT DispatcherContext; + EXCEPTION_DISPOSITION Disposition; + PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; + PEXCEPTION_REGISTRATION_RECORD PriorPointer; + ULONG HighAddress; + ULONG HighLimit; + ULONG LowLimit; + EXCEPTION_RECORD ExceptionRecord1; + EXCEPTION_RECORD ExceptionRecord2; + + // + // Get current stack limits. + // + + RtlpGetStackLimits(&LowLimit, &HighLimit); + + // + // If an exception record is not specified, then build a local exception + // record for use in calling exception handlers during the unwind operation. + // + + if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) { + ExceptionRecord = &ExceptionRecord1; + ExceptionRecord1.ExceptionCode = STATUS_UNWIND; + ExceptionRecord1.ExceptionFlags = 0; + ExceptionRecord1.ExceptionRecord = NULL; + ExceptionRecord1.ExceptionAddress = RtlpGetReturnAddress(); + ExceptionRecord1.NumberParameters = 0; + } + + // + // If the target frame of the unwind is specified, then set EXCEPTION_UNWINDING + // flag in the exception flags. Otherwise set both EXCEPTION_EXIT_UNWIND and + // EXCEPTION_UNWINDING flags in the exception flags. + // + + if (ARGUMENT_PRESENT(TargetFrame) == TRUE) { + ExceptionRecord->ExceptionFlags |= EXCEPTION_UNWINDING; + } else { + ExceptionRecord->ExceptionFlags |= (EXCEPTION_UNWINDING | + EXCEPTION_EXIT_UNWIND); + } + + // + // Capture the context. + // + + ContextRecord = &ContextRecord1; + ContextRecord1.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; + RtlpCaptureContext(ContextRecord); + +#ifdef STD_CALL + // + // Adjust captured context to pop our arguments off the stack + // + ContextRecord->Esp += sizeof(TargetFrame) + + sizeof(TargetIp) + + sizeof(ExceptionRecord) + + sizeof(ReturnValue); +#endif + ContextRecord->Eax = (ULONG)ReturnValue; + + // + // Scan backward through the call frame hierarchy, calling exception + // handlers as they are encountered, until the target frame of the unwind + // is reached. + // + + RegistrationPointer = RtlpGetRegistrationHead(); + while (RegistrationPointer != EXCEPTION_CHAIN_END) { + + // + // If this is the target of the unwind, then continue execution + // by calling the continue system service. + // + + if ((ULONG)RegistrationPointer == (ULONG)TargetFrame) { + ZwContinue(ContextRecord, FALSE); + + // + // If the target frame is lower in the stack than the current frame, + // then raise STATUS_INVALID_UNWIND exception. + // + + } else if ( (ARGUMENT_PRESENT(TargetFrame) == TRUE) && + ((ULONG)TargetFrame < (ULONG)RegistrationPointer) ) { + ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; + ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord2.ExceptionRecord = ExceptionRecord; + ExceptionRecord2.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord2); + } + + // + // If the call frame is not within the specified stack limits or the + // call frame is unaligned, then raise the exception STATUS_BAD_STACK. + // Else restore the state from the specified frame to the context + // record. + // + + HighAddress = (ULONG)RegistrationPointer + + sizeof(EXCEPTION_REGISTRATION_RECORD); + + if ( ((ULONG)RegistrationPointer < LowLimit) || + (HighAddress > HighLimit) || + (((ULONG)RegistrationPointer & 0x3) != 0) ) { + ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK; + ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord2.ExceptionRecord = ExceptionRecord; + ExceptionRecord2.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord2); + } else { + + // + // The handler must be executed by calling another routine + // that is written in assembler. This is required because + // up level addressing of the handler information is required + // when a collided unwind is encountered. + // + + Disposition = RtlpExecuteHandlerForUnwind( + ExceptionRecord, + (PVOID)RegistrationPointer, + ContextRecord, + (PVOID)&DispatcherContext, + RegistrationPointer->Handler); + + // + // Case on the handler disposition. + // + + switch (Disposition) { + + // + // The disposition is to continue the search. Get next + // frame address and continue the search. + // + + case ExceptionContinueSearch : + break; + + // + // The disposition is colided unwind. Maximize the target + // of the unwind and change the context record pointer. + // + + case ExceptionCollidedUnwind : + + // + // Pick up the registration pointer that was active at + // the time of the unwind, and simply continue. + // + + RegistrationPointer = DispatcherContext.RegistrationPointer; + break; + + + // + // All other disposition values are invalid. Raise + // invalid disposition exception. + // + + default : + ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; + ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord2.ExceptionRecord = ExceptionRecord; + ExceptionRecord2.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord2); + break; + } + + // + // Step to next registration record + // + + PriorPointer = RegistrationPointer; + RegistrationPointer = RegistrationPointer->Next; + + // + // Unlink the unwind handler, since it's been called. + // + + RtlpUnlinkHandler(PriorPointer); + + // + // If chain goes in wrong direction or loops, raise an + // exception. + // + + } + } + + if (TargetFrame == EXCEPTION_CHAIN_END) { + + // + // Caller simply wants to unwind all exception records. + // This differs from an exit_unwind in that no "exit" is desired. + // Do a normal continue, since we've effectively found the + // "target" the caller wanted. + // + + ZwContinue(ContextRecord, FALSE); + + } else { + + // + // Either (1) a real exit unwind was performed, or (2) the + // specified TargetFrame is not present in the exception handler + // list. In either case, give debugger and subsystem a chance + // to see the unwind. + // + + ZwRaiseException(ExceptionRecord, ContextRecord, FALSE); + + } + return; +} diff --git a/private/ntos/rtl/i386/exsup.asm b/private/ntos/rtl/i386/exsup.asm new file mode 100644 index 000000000..cfa02a6fb --- /dev/null +++ b/private/ntos/rtl/i386/exsup.asm @@ -0,0 +1,15 @@ + title "Public Constant (__except_list) Definition" + +.386p +.xlist +include ks386.inc +include callconv.inc ; calling convention macros +include mac386.inc +.list + +COMM __setjmpexused:dword + +public __except_list +__except_list equ 0 + +END diff --git a/private/ntos/rtl/i386/forceres.asm b/private/ntos/rtl/i386/forceres.asm new file mode 100644 index 000000000..cd941803a --- /dev/null +++ b/private/ntos/rtl/i386/forceres.asm @@ -0,0 +1,23 @@ +.386p + +; forceres.asm - generate publics to force resolution of symbols we +; don't want to deal with yet. +; + + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + public __fltused + +foo proc near ; make the assembler shut up + +__fltused: + int 3 + ret + +foo endp + + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/halvprnt.c b/private/ntos/rtl/i386/halvprnt.c new file mode 100644 index 000000000..9179241c9 --- /dev/null +++ b/private/ntos/rtl/i386/halvprnt.c @@ -0,0 +1,407 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + halvprnt.c + +Author: + + John Vert (jvert) 13-Aug-1991 + based on TomP's video.c + +Abstract: + + Video support routines. + + The vprintf function here outputs to the console via HalDisplayString. + All the global variables have been made local, so multiple processors + can execute it simultaneously. If this is the case, it relies on + HalDisplayString to sort the output to avoid interleaving the text from + the processors. + +History: + +--*/ + +#include <ntos.h> + +typedef unsigned char BYTE, *PBYTE; + + +// +// Internal routines +// + +static +int +xatoi(char c); + +static +int +fields( + char *cp, + int *zerofill, + int *fieldwidth + ); + +static +VOID +putx( + ULONG x, + int digits, + int zerofill, + int *fieldwidth + ); + +static +VOID +puti( + LONG i, + int digits, + int zerofill, + int *fieldwidth + ); + +static +VOID +putu( + ULONG u, + int digits, + int zerofill, + int *fieldwidth + ); + +static +VOID +putc( + CHAR c + ); + + +/*++ + +Name + + vprintf - DbgPrint function on standard video + + Currently handles + + + %i, %li - signed short, signed long (same as d) + %d, %ld - signed short, signed long + %u, %lu - unsigned short, unsigned long + %c, %s, %.*s - character, string + %Z - PSTRING data type + %x, %lx - unsigned print in hex, unsigned long print in hex + %X, %lX, %X, %X, %X, %X - same as %x and %lx + field widths + leading 0 fills + + Does not do yet: + + No floating point. + + +--*/ +void +vprintf(PCHAR cp,USHORT a1) +{ + ULONG cb; + USHORT b,c; + PBYTE ap; + PCHAR s; + PSTRING str; + ULONG Flags; + int zerofill, fieldwidth; + + // + // Cast a pointer to the first word on the stack + // + + ap = (PBYTE)&a1; + + + // Save flags in automatic variable on stack, turn off ints. + + _asm { + pushfd + pop Flags + cli + } + + // + // Process the argements using the descriptor string + // + + while (b = *cp++) { + if (b == '%') { + cp += fields(cp, &zerofill, &fieldwidth); + c = *cp++; + + switch (c) { + case '.': + if (*cp != '*' || cp[1] != 's') { + putc((char)b); + putc((char)c); + break; + } + cp += 2; + cb = *((ULONG *)ap); + ap += sizeof( ULONG ); + s = *((PCHAR *)ap); + ap += sizeof( PCHAR ); + if (s == NULL) { + s = "(null)"; + cb = 6; + } + if (cb > 0xFFF) { + s = "(overflow)"; + cb = 10; + } + + while (cb--) { + if (*s) { + putc(*s++); + } else { + putc(' '); + } + } + break; + + case 'i': + case 'd': + puti((long)*((int *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(int); + break; + + case 'S': + str = *((PSTRING *)ap); + ap += sizeof (STRING *); + b = str->Length; + s = str->Buffer; + if (s == NULL) + s = "(null)"; + while (b--) + putc(*s++); + break; + + case 's': + s = *((PCHAR *)ap); + ap += sizeof( PCHAR ); + if (s == NULL) + s = "(null)"; + while (*s) + putc(*s++); + break; + + case 'c': + putc(*((char *)ap)); + ap += sizeof(int); + break; + + + // + // If we cannot find the status value in the table, print it in + // hex. + // + case 'C': + case 'B': + // + // Should search bugcodes.h to display bug code + // symbolically. For now just show as hex + // + + case 'X': + case 'x': + putx((ULONG)*((USHORT *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(int); + break; + + case 'u': + putu((ULONG)*((USHORT *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(int); + break; + + case 'l': + c = *cp++; + + switch(c) { + case 'u': + putu(*((ULONG *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(long); + break; + + case 'C': + case 'B': + // + // Should search bugcodes.h to display bug code + // symbolically. For now just show as hex + // + + case 'X': + case 'x': + putx(*((ULONG *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(long); + break; + + case 'i': + case 'd': + puti(*((ULONG *)ap), 1, zerofill, &fieldwidth); + ap += sizeof(long); + break; + } // inner switch + break; + + default : + putc((char)b); + putc((char)c); + } // outer switch + } // if + else + putc((char)b); + } // while + + // Restore flags from automatic variable on stack + + _asm { + push Flags + popfd + } + return; +} + + +// +// Fields computation +// + +static int fields(char *cp, int *zerofill, int *fieldwidth) +{ + int incval = 0; + + *zerofill = 0; + *fieldwidth = 0; + + if (*cp == '0') { + *zerofill = 1; + cp++; + incval++; + } + + while ((*cp >= '0') && (*cp <= '9')) { + *fieldwidth = (*fieldwidth * 10) + xatoi(*cp); + cp++; + incval++; + } + return incval; +} + +// +// Write a hex short to display +// + +static void putx(ULONG x, int digits, int zerofill, int *fieldwidth) +{ + ULONG j; + + if (x/16) + putx(x/16, digits+1, zerofill, fieldwidth); + + if (*fieldwidth > digits) { + while (*fieldwidth > digits) { + if (zerofill) + putc('0'); + else + putc(' '); + *fieldwidth--; + } + } + *fieldwidth = 0; + + + if((j=x%16) > 9) + putc((char)(j+'A'- 10)); + else + putc((char)(j+'0')); + +} + + +// +// Write a short integer to display +// + +static void puti(long i, int digits, int zerofill, int *fieldwidth) +{ + if (i<0) { + i = -i; + putc((char)'-'); + } + + if (i/10) + puti(i/10, digits+1, zerofill, fieldwidth); + + if (*fieldwidth > digits) { + while (*fieldwidth > digits) { + if (zerofill) + putc('0'); + else + putc(' '); + *fieldwidth--; + } + } + *fieldwidth = 0; + + putc((char)((i%10)+'0')); +} + + +// +// Write an unsigned short to display +// + +static void putu(ULONG u, int digits, int zerofill, int *fieldwidth) +{ + if (u/10) + putu(u/10, digits+1, zerofill, fieldwidth); + + if (*fieldwidth > digits) { + while (*fieldwidth > digits) { + if (zerofill) + putc('0'); + else + putc(' '); + *fieldwidth--; + } + } + *fieldwidth = 0; + + putc((char)((u%10)+'0')); +} + +// +// Write a character to display +// + +VOID putc( + CHAR c + ) +{ + static UCHAR OneCharacter[2]; + + OneCharacter[1] = '\0'; + OneCharacter[0] = c; + HalDisplayString(OneCharacter); +} + + +// +// Return the integer value of numeral represented by ascii char +// + +int xatoi(char c) +{ + return c - '0'; +} diff --git a/private/ntos/rtl/i386/ioaccess.asm b/private/ntos/rtl/i386/ioaccess.asm new file mode 100644 index 000000000..17dbd1e36 --- /dev/null +++ b/private/ntos/rtl/i386/ioaccess.asm @@ -0,0 +1,423 @@ + title "ioaccess" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; ioaccess.asm +; +; Abstract: +; +; Procedures to correctly touch I/O registers. +; +; Author: +; +; Bryan Willman (bryanwi) 16 May 1990 +; +; Environment: +; +; User or Kernel, although privledge (IOPL) may be required. +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING +;++ +; +; I/O memory space read and write functions. +; +; These have to be actual functions on the 386, because we need +; to use assembler, but cannot return a value if we inline it. +; +; This set of functions manipulates I/O registers in MEMORY space. +; (Uses x86 mov instructions) +; +;-- + + + +;++ +; +; UCHAR +; READ_REGISTER_UCHAR( +; PUCHAR Register +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; +; Returns: +; Value in register. +; +;-- +cPublicProc _READ_REGISTER_UCHAR ,1 +cPublicFpo 1,0 + + mov edx,[esp+4] ; (edx) = Register + mov al,[edx] ; (al) = byte, lock forces real access + stdRET _READ_REGISTER_UCHAR + +stdENDP _READ_REGISTER_UCHAR + + + +;++ +; +; USHORT +; READ_REGISTER_USHORT( +; PUSHORT Register +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; +; Returns: +; Value in register. +; +;-- +cPublicProc _READ_REGISTER_USHORT ,1 +cPublicFpo 1,0 + + mov edx,[esp+4] ; (edx) = Register + mov ax,[edx] ; (ax) = word, lock forces real access + stdRET _READ_REGISTER_USHORT + +stdENDP _READ_REGISTER_USHORT + + + +;++ +; +; ULONG +; READ_REGISTER_ULONG( +; PULONG Register +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; +; Returns: +; Value in register. +; +;-- +cPublicProc _READ_REGISTER_ULONG ,1 +cPublicFpo 1,0 + + mov edx,[esp+4] ; (edx) = Register + mov eax,[edx] ; (eax) = dword, lock forces real access + stdRET _READ_REGISTER_ULONG + +stdENDP _READ_REGISTER_ULONG + + +;++ +; +; VOID +; READ_REGISTER_BUFFER_UCHAR( +; PUCHAR Register, +; PUCHAR Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _READ_REGISTER_BUFFER_UCHAR ,3 +cPublicFpo 3,0 + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+4] ; (edx) = Register + mov edi,[esp+8] ; (edi) = buffer + rep movsb + + mov edi, edx + mov esi, eax + + stdRET _READ_REGISTER_BUFFER_UCHAR + +stdENDP _READ_REGISTER_BUFFER_UCHAR + + +;++ +; +; VOID +; READ_REGISTER_BUFFER_USHORT( +; PUSHORT Register, +; PUSHORT Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _READ_REGISTER_BUFFER_USHORT ,3 +cPublicFpo 3,0 + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+4] ; (edx) = Register + mov edi,[esp+8] ; (edi) = buffer + rep movsw + + mov edi, edx + mov esi, eax + stdRET _READ_REGISTER_BUFFER_USHORT + +stdENDP _READ_REGISTER_BUFFER_USHORT + + +;++ +; +; VOID +; READ_REGISTER_BUFFER_ULONG( +; PULONG Register, +; PULONG Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _READ_REGISTER_BUFFER_ULONG ,3 +cPublicFpo 3,0 + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+4] ; (edx) = Register + mov edi,[esp+8] ; (edi) = buffer + rep movsd + + mov edi, edx + mov esi, eax + stdRET _READ_REGISTER_BUFFER_ULONG + +stdENDP _READ_REGISTER_BUFFER_ULONG + + + +;++ +; +; VOID +; WRITE_REGISTER_UCHAR( +; PUCHAR Register, +; UCHAR Value +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Value +; +;-- +cPublicProc _WRITE_REGISTER_UCHAR ,2 +cPublicFpo 2,0 + + mov edx,[esp+4] ; (edx) = Register + mov al,[esp+8] ; (al) = Value + mov [edx],al ; do write + lock or [esp+4],edx ; flush processors posted-write buffers + stdRET _WRITE_REGISTER_UCHAR + +stdENDP _WRITE_REGISTER_UCHAR + + + +;++ +; +; VOID +; WRITE_REGISTER_USHORT( +; PUSHORT Register, +; USHORT Value +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Value +; +;-- +cPublicProc _WRITE_REGISTER_USHORT ,2 +cPublicFpo 2,0 + + mov edx,[esp+4] ; (edx) = Register + mov eax,[esp+8] ; (ax) = Value + mov [edx],ax ; do write + lock or [esp+4],edx ; flush processors posted-write buffers + stdRET _WRITE_REGISTER_USHORT + +stdENDP _WRITE_REGISTER_USHORT + + + +;++ +; +; VOID +; WRITE_REGISTER_ULONG( +; PULONG Register, +; ULONG Value +; ) +; +; Memory space references will use lock prefix to force real access, +; flush through posted write buffers, and so forth. +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Value +; +;-- +cPublicProc _WRITE_REGISTER_ULONG ,2 +cPublicFpo 2,0 + + mov edx,[esp+4] ; (edx) = Register + mov eax,[esp+8] ; (eax) = Value + mov [edx],eax ; do write + lock or [esp+4],edx ; flush processors posted-write buffers + stdRET _WRITE_REGISTER_ULONG + +stdENDP _WRITE_REGISTER_ULONG + + +;++ +; +; VOID +; WRITE_REGISTER_BUFFER_UCHAR( +; PUCHAR Register, +; PUCHAR Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _WRITE_REGISTER_BUFFER_UCHAR ,3 +cPublicFpo 3,0 + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+8] ; (edi) = buffer + mov edi,[esp+4] ; (edx) = Register + rep movsb + lock or [esp+4],ecx ; flush processors posted-write buffers + + mov edi, edx + mov esi, eax + + stdRET _WRITE_REGISTER_BUFFER_UCHAR + +stdENDP _WRITE_REGISTER_BUFFER_UCHAR + + +;++ +; +; VOID +; WRITE_REGISTER_BUFFER_USHORT( +; PUSHORT Register, +; PUSHORT Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _WRITE_REGISTER_BUFFER_USHORT ,3 +cPublicFpo 3,0 + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+8] ; (edi) = buffer + mov edi,[esp+4] ; (edx) = Register + rep movsw + lock or [esp+4],ecx ; flush processors posted-write buffers + + mov edi, edx + mov esi, eax + stdRET _WRITE_REGISTER_BUFFER_USHORT + +stdENDP _WRITE_REGISTER_BUFFER_USHORT + + +;++ +; +; VOID +; WRITE_REGISTER_BUFFER_ULONG( +; PULONG Register, +; PULONG Buffer, +; ULONG Count +; ) +; +; Arguments: +; (esp+4) = Register +; (esp+8) = Buffer address +; (esp+12) = Count +; +;-- +cPublicProc _WRITE_REGISTER_BUFFER_ULONG ,3 +cPublicFpo 0, 3 + +;FPO ( 0, 3, 0, 0, 0, 0 ) + + mov eax, esi + mov edx, edi ; Save esi, edi + + mov ecx,[esp+12] ; (ecx) = transfer count + mov esi,[esp+8] ; (edi) = buffer + mov edi,[esp+4] ; (edx) = Register + rep movsd + lock or [esp+4],ecx ; flush processors posted-write buffers + + mov edi, edx + mov esi, eax + stdRET _WRITE_REGISTER_BUFFER_ULONG + +stdENDP _WRITE_REGISTER_BUFFER_ULONG + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/largeint.asm b/private/ntos/rtl/i386/largeint.asm new file mode 100644 index 000000000..d376cbd7e --- /dev/null +++ b/private/ntos/rtl/i386/largeint.asm @@ -0,0 +1,855 @@ + TITLE "Large Integer Arithmetic" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; largeint.s +; +; Abstract: +; +; This module implements routines for performing extended integer +; arithmtic. +; +; Author: +; +; David N. Cutler (davec) 24-Aug-1989 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +IFNDEF BLDR_KERNEL_RUNTIME + EXTRNP _RtlRaiseStatus, 1 +ENDIF + + +_TEXT$00 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "RtlLargeIntegerAdd" +;++ +; +; LARGE_INTEGER +; RtlLargeIntegerAdd ( +; IN LARGE_INTEGER Addend1, +; IN LARGE_INTEGER Addend2 +; ) +; +; Routine Description: +; +; This function adds a signed large integer to a signed large integer and +; returns the signed large integer result. +; +; Arguments: +; +; (TOS+4) = Addend1 - first addend value +; (TOS+12) = Addend2 - second addend value +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlLargeIntegerAdd ,4 +cPublicFpo 4,0 + + mov eax,[esp]+4 ; (eax)=add1.low + add eax,[esp]+12 ; (eax)=sum.low + mov edx,[esp]+8 ; (edx)=add1.hi + adc edx,[esp]+16 ; (edx)=sum.hi + stdRET _RtlLargeIntegerAdd + +stdENDP _RtlLargeIntegerAdd + + + page + subttl "Enlarged Integer Multiply" +;++ +; +; LARGE_INTEGER +; RtlEnlargedIntegerMultiply ( +; IN LONG Multiplicand, +; IN LONG Multiplier +; ) +; +; Routine Description: +; +; This function multiplies a signed integer by an signed integer and +; returns a signed large integer result. +; +; Arguments: +; +; (TOS+4) = Factor1 +; (TOS+8) = Factor2 +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlEnlargedIntegerMultiply ,2 +cPublicFpo 2,0 + + mov eax,[esp]+4 ; (eax) = factor1 + imul dword ptr [esp]+8 ; (edx:eax) = signed result + stdRET _RtlEnlargedIntegerMultiply + +stdENDP _RtlEnlargedIntegerMultiply + + + page + subttl "Enlarged Unsigned Integer Multiply" +;++ +; +; LARGE_INTEGER +; RtlEnlargedUnsignedMultiply ( +; IN ULONG Multiplicand, +; IN ULONG Multiplier +; ) +; +; Routine Description: +; +; This function multiplies an un signed integer by an unsigned integer and +; returns a signed large integer result. +; +; Arguments: +; +; (TOS+4) = Factor1 +; (TOS+8) = Factor2 +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlEnlargedUnsignedMultiply ,2 +cPublicFpo 2,0 + + mov eax,[esp]+4 ; (eax) = factor1 + mul dword ptr [esp]+8 ; (edx:eax) = unsigned result + stdRET _RtlEnlargedUnsignedMultiply + +stdENDP _RtlEnlargedUnsignedMultiply + + page + subttl "Enlarged Unsigned Integer Divide" + +;++ +; +; ULONG +; RtlEnlargedUnsignedDivide ( +; IN ULARGE_INTEGER Dividend, +; IN ULONG Divisor, +; IN PULONG Remainder +; ) +; +; +; Routine Description: +; +; This function divides an unsigned large integer by an unsigned long +; and returns the resultant quotient and optionally the remainder. +; +; Arguments: +; +; Dividend - Supplies the dividend value. +; +; Divisor - Supplies the divisor value. +; +; Remainder - Supplies an optional pointer to a variable that +; receives the remainder. +; +; Return Value: +; +; The unsigned long integer quotient is returned as the function value. +; +;-- + +cPublicProc _RtlEnlargedUnsignedDivide,4 +cPublicFpo 4,0 + + mov eax, [esp+4] ; (eax) = Dividend.LowPart + mov edx, [esp+8] ; (edx) = Dividend.HighPart + mov ecx, [esp+16] ; (ecx) = pRemainder + div dword ptr [esp+12] ; divide by Divisor + + or ecx, ecx ; return remainder? + jnz short @f + + stdRET _RtlEnlargedUnsignedDivide ; (eax) = Quotient + +align 4 +@@: mov [ecx], edx ; save remainder + stdRET _RtlEnlargedUnsignedDivide ; (eax) = Quotient + +stdENDP _RtlEnlargedUnsignedDivide + + page + subttl "Extended Large Integer Divide" + +;++ +; +; LARGE_INTEGER +; RtlExtendedLargeIntegerDivide ( +; IN LARGE_INTEGER Dividend, +; IN ULONG Divisor, +; OUT PULONG Remainder OPTIONAL +; ) +; +; Routine Description: +; +; This routine divides an unsigned 64 bit dividend by a 32 bit divisor +; and returns a 64-bit quotient, and optionally the 32-bit remainder. +; +; +; Arguments: +; +; Dividend - Supplies the 64 bit dividend for the divide operation. +; +; Divisor - Supplies the 32 bit divisor for the divide operation. +; +; Remainder - Supplies an optional pointer to a variable which receives +; the remainder +; +; Return Value: +; +; The 64-bit quotient is returned as the function value. +; +;-- + +cPublicProc _RtlExtendedLargeIntegerDivide, 4 +cPublicFpo 4,3 + + push esi + push edi + push ebx + + mov eax, [esp+16] ; (eax) = Dividend.LowPart + mov edx, [esp+20] ; (edx) = Dividend.HighPart + +lid00: mov ebx, [esp+24] ; (ebx) = Divisor + or ebx, ebx + jz short lid_zero ; Attempted a divide by zero + + push ebp + + mov ecx, 64 ; Loop count + xor esi, esi ; Clear partial remainder + +; (edx:eax) = Dividend +; (ebx) = Divisor +; (ecx) = Loop count +; (esi) = partial remainder + +align 4 +lid10: shl eax, 1 ; (LowPart << 1) | 0 + rcl edx, 1 ; (HighPart << 1) | CF + rcl esi, 1 ; (Partial << 1) | CF + + sbb edi, edi ; clone CF into edi (0 or -1) + + cmp esi, ebx ; check if partial remainder less then divisor + cmc + sbb ebp, ebp ; clone CF intp ebp + or edi, ebp ; merge with remainder of high bit + + sub eax, edi ; merge quotient bit + and edi, ebx ; Select divisor or 0 + sub esi, edi + + dec ecx ; dec interration count + jnz short lid10 ; go around again + + pop ebp + pop ebx + pop edi + + mov ecx, [esp+20] ; (ecx) = Remainder + or ecx, ecx + jnz short lid20 + + pop esi + stdRET _RtlExtendedLargeIntegerDivide + +align 4 +lid20: + mov [ecx], esi ; store remainder + pop esi + stdRET _RtlExtendedLargeIntegerDivide + +lid_zero: +IFNDEF BLDR_KERNEL_RUNTIME + stdCall _RtlRaiseStatus, <STATUS_INTEGER_DIVIDE_BY_ZERO> +ENDIF + pop ebx + pop edi + pop esi + stdRET _RtlExtendedLargeIntegerDivide + +stdENDP _RtlExtendedLargeIntegerDivide + + page + subttl "Extended Magic Divide" +;++ +; +; LARGE_INTEGER +; RtlExtendedMagicDivide ( +; IN LARGE_INTEGER Dividend, +; IN LARGE_INTEGER MagicDivisor, +; IN CCHAR ShiftCount +; ) +; +; Routine Description: +; +; This function divides a signed large integer by an unsigned large integer +; and returns the signed large integer result. The division is performed +; using reciprocal multiplication of a signed large integer value by an +; unsigned large integer fraction which represents the most significant +; 64-bits of the reciprocal divisor rounded up in its least significant bit +; and normalized with respect to bit 63. A shift count is also provided +; which is used to truncate the fractional bits from the result value. +; +; Arguments: +; +; (ebp+8) = Dividend +; (ebp+16) = MagicDivisor value is a 64-bit multiplicative reciprocal +; (ebp+24) = ShiftCount - Right shift adjustment value. +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +RemdDiv equ [ebp+8] ; Dividend +RemdRec equ [ebp+16] ; Reciprocal (magic divisor) +RemdShift equ [ebp+24] +RemdTmp1 equ [ebp-4] +RemdTmp2 equ [ebp-8] +RemdTmp3 equ [ebp-12] + +cPublicProc _RtlExtendedMagicDivide ,5 + + push ebp + mov ebp,esp + sub esp,12 + push esi + + mov esi, RemdDiv+4 + test esi,80000000h + jz remd10 ; no sign, no need to negate + + neg dword ptr RemdDiv+4 + neg dword ptr RemdDiv + sbb dword ptr RemdDiv+4,0 ; negate + +remd10: mov eax,RemdRec + mul dword ptr RemdDiv ; (edx:eax) = Div.lo * Rec.lo + mov RemdTmp1,edx + + mov eax,RemdRec + mul dword ptr RemdDiv+4 ; (edx:eax) = Div.hi * Rec.lo + mov RemdTmp2,eax + mov RemdTmp3,edx + + mov eax,RemdRec+4 + mul dword ptr RemdDiv ; (edx:eax) = Div.lo * Rec.hi + +; +; Col 0 doesn't matter +; Col 1 = Hi(Div.lo * Rec.lo) + Low(Div.Hi * Rec.lo) + Low(Div.lo * Rec.hi) +; = RemdTmp1 + RemdTmp2 + eax +; -> Only want carry from Col 1 +; + + xor ecx,ecx ; (ecx) = 0 + add eax,RemdTmp1 + adc ecx, 0 ; save carry in ecx + add eax,RemdTmp2 + adc ecx, 0 ; Save Carry, all we want from Col2 + + mov RemdTmp1,edx + + mov eax,RemdRec+4 + mul dword ptr RemdDiv+4 ; (edx:eax) = Div.Hi * Rec.Hi + +; +; TOS = carry flag from Col 1 +; +; Col 2 = Col1 CF + +; Hi(Div.Hi * Rec.Lo) + Hi(Div.Lo * Rec.Hi) + Low(Div.Hi * Rec.Hi) +; = CF + RemdTmp3 + RemdTmp1 + eax +; +; Col 3 = Col2 CF + Hi(Div.Hi * Rec.Hi) +; = CF + edx +; + + add eax,RemdTmp1 + adc edx, 0 ; add carry to edx + add eax,RemdTmp3 ; (eax) = col 2 + adc edx, 0 ; add carry to edx + add eax, ecx + adc edx, 0 ; (edx) = col 3 + +; +; (edx:eax) = the high 64 bits of the multiply, shift it right by +; shift count to discard bits to right of virtual decimal pt. +; +; RemdShift could be as large as 63 and still not 0 the result, 386 +; will only shift 31 bits at a time, so must do the sift multiple +; times to get correct effect. +; + + mov cl,RemdShift +remd20: cmp cl,31 + jbe remd30 + sub cl,31 + shrd eax,edx,31 + shr edx,31 + jmp remd20 + +remd30: shrd eax,edx,cl + shr edx,cl + +; +; Negate the result if need be +; + + test esi,80000000h + jz remd40 ; no sign, go return without negate + + neg edx + neg eax + sbb edx,0 + +; +; Store the result +; + +remd40: + ; results in (edx:eax) + + pop esi + mov esp,ebp + pop ebp + stdRET _RtlExtendedMagicDivide + +stdENDP _RtlExtendedMagicDivide + + + page + subttl "Extended Integer Multiply" +;++ +; +; LARGE_INTEGER +; RtlExtendedIntegerMultiply ( +; IN LARGE_INTEGER Multiplicand, +; IN ULONG Multiplier +; ) +; +; Routine Description: +; +; This function multiplies a signed large integer by a signed integer and +; returns the signed large integer result. +; +; Arguments: +; +; (ebp+8,12)=multiplican (MCAN) +; (ebp+16)=multiplier (MPER) +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +ReimMCAN equ <dword ptr [ebp+8]> +ReimMPER equ <dword ptr [ebp+16]> + +cPublicProc _RtlExtendedIntegerMultiply ,3 + + push ebp + mov ebp,esp + push esi + + mov esi,ReimMPER + xor esi,ReimMCAN+4 ; (esi) = result sign + + test ReimMCAN+4,80000000h + jz short reim10 ; MCAN pos, go look at MPER + + neg dword ptr ReimMCAN+4 + neg dword ptr ReimMCAN + sbb dword ptr ReimMCAN+4,0 ; negate multiplican + +reim10: test ReimMPER,80000000h + jz short reim20 ; MPER pos, go do multiply + + neg dword ptr ReimMPER ; negate multiplier + +reim20: mov eax,ReimMPER + mul dword ptr ReimMCAN ; (edx:eax) = MPER * MCAN.low + push edx + mov ecx, eax + mov eax,ReimMPER + mul dword ptr ReimMCAN+4 ; (edx:eax) = MPER * MCAN.high + add eax,[esp] ; (eax) = hi part of MPER*MCAN.low + ; plus low part of MPER*MCAN.hi + + test esi,80000000h + jz short reim30 ; result sign is OK, go return + + neg eax + neg ecx + sbb eax,0 ; negate result + +reim30: add esp,4 ; clean eax off stack + pop esi ; restore nonvolatile reg + mov edx,eax ; (edx:ecx) = result + mov eax,ecx ; (edx:eax) = result + + pop ebp + stdRET _RtlExtendedIntegerMultiply + +stdENDP _RtlExtendedIntegerMultiply + + page + subttl "Large Integer Shift Left" +;++ +; +; LARGE_INTEGER +; RtlLargeIntegerShiftLeft ( +; IN LARGE_INTEGER LargeInteger, +; IN CCHAR ShiftCount +; ) +; +; +; Routine Description: +; +; This routine does a left logical shift of a large integer by a +; specified amount (ShiftCount) modulo 64. +; +; Arguments: +; +; LargeInteger - Supplies the large integer to be shifted +; +; ShiftCount - Supplies the left shift count +; +; Return Value: +; +; LARGE_INTEGER - Receives the shift large integer result +; +;-- +cPublicProc _RtlLargeIntegerShiftLeft,3 +cPublicFpo 3,0 + + mov ecx, [esp+12] ; (ecx) = ShiftCount + and ecx, 3fh ; mod 64 + + cmp ecx, 32 + jnc short sl10 +; +; Shift count is less then 32 bits. +; + mov eax, [esp+4] ; (eax) = LargeInteger.LowPart + mov edx, [esp+8] ; (edx) = LargeInteger.HighPart + shld edx, eax, cl + shl eax, cl + + stdRET _RtlLargeIntegerShiftLeft + +align 4 +sl10: +; +; Shift count is greater than or equal 32 bits - low half of result is zero, +; high half is the low half shifted left by remaining count. +; + mov edx, [esp+4] ; (edx) = LargeInteger.LowPart + xor eax, eax ; store lowpart + shl edx, cl ; store highpart + + stdRET _RtlLargeIntegerShiftLeft + +stdENDP _RtlLargeIntegerShiftLeft + + page + subttl "Large Integer Shift Right" + +;-- +; +;LARGE_INTEGER +;RtlLargeIntegerShiftRight ( +; IN LARGE_INTEGER LargeInteger, +; IN CCHAR ShiftCount +; ) +; +;Routine Description: +; +; This routine does a right logical shift of a large integer by a +; specified amount (ShiftCount) modulo 64. +; +;Arguments: +; +; LargeInteger - Supplies the large integer to be shifted +; +; ShiftCount - Supplies the right shift count +; +;Return Value: +; +; LARGE_INTEGER - Receives the shift large integer result +; +;--*/ +cPublicProc _RtlLargeIntegerShiftRight,3 +cPublicFpo 3,0 + + mov ecx, [esp+12] ; (ecx) = ShiftCount + and ecx, 3fh ; mod 64 + + cmp ecx, 32 + jnc short sr10 + +; +; Shift count is less then 32 bits. +; + mov eax, [esp+4] ; (eax) = LargeInteger.LowPart + mov edx, [esp+8] ; (edx) = LargeInteger.HighPart + shrd eax, edx, cl + shr edx, cl + + stdRET _RtlLargeIntegerShiftRight + +align 4 +sr10: +; +; Shift count is greater than or equal 32 bits - high half of result is zero, +; low half is the high half shifted right by remaining count. +; + mov eax, [esp+8] ; (eax) = LargeInteger.HighPart + xor edx, edx ; store highpart + shr eax, cl ; store lowpart + + stdRET _RtlLargeIntegerShiftRight + +stdENDP _RtlLargeIntegerShiftRight + +;++ +; +;LARGE_INTEGER +;RtlLargeIntegerArithmeticShift ( +; IN LARGE_INTEGER LargeInteger, +; IN CCHAR ShiftCount +; ) +; +;Routine Description: +; +; This routine does a right arithmetic shift of a large integer by a +; specified amount (ShiftCount) modulo 64. +; +;Arguments: +; +; LargeInteger - Supplies the large integer to be shifted +; +; ShiftCount - Supplies the right shift count +; +;Return Value: +; +; LARGE_INTEGER - Receives the shift large integer result +; +;-- +cPublicProc _RtlLargeIntegerArithmeticShift,3 +cPublicFpo 3,0 + + mov ecx, [esp+12] ; (ecx) = ShiftCount + and ecx, 3fh ; mod 64 + + cmp ecx, 32 + jc short sar10 + +; +; Shift count is greater than or equal 32 bits - high half of result is sign +; bit, low half is the high half shifted right by remaining count. +; + mov eax, [esp+8] ; (eax) = LargeInteger.HighPart + sar eax, cl ; store highpart + bt eax, 31 ; sign bit set? + sbb edx, edx ; duplicate sign bit into highpart + + stdRET _RtlLargeIntegerArithmeticShift + +align 4 +sar10: +; +; Shift count is less then 32 bits. +; +; + mov eax, [esp+4] ; (eax) = LargeInteger.LowPart + mov edx, [esp+8] ; (edx) = LargeInteger.HighPart + shrd eax, edx, cl + sar edx, cl + + stdRET _RtlLargeIntegerArithmeticShift + +stdENDP _RtlLargeIntegerArithmeticShift,3 + + + page + subttl "Large Integer Negate" +;++ +; +; LARGE_INTEGER +; RtlLargeIntegerNegate ( +; IN LARGE_INTEGER Subtrahend +; ) +; +; Routine Description: +; +; This function negates a signed large integer and returns the signed +; large integer result. +; +; Arguments: +; +; (TOS+4) = Subtrahend +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlLargeIntegerNegate ,2 +cPublicFpo 2,0 + + mov eax,[esp]+4 ; (eax) = lo + mov edx,[esp]+8 + neg edx ; (edx) = 2's comp of hi part + neg eax ; if ((eax) == 0) CF = 0 + ; else CF = 1 + sbb edx,0 ; (edx) = (edx) - CF + ; (edx:eax) = result + stdRET _RtlLargeIntegerNegate + +stdENDP _RtlLargeIntegerNegate + + + page + subttl "Large Integer Subtract" +;++ +; +; LARGE_INTEGER +; RtlLargeIntegerSubtract ( +; IN LARGE_INTEGER Minuend, +; IN LARGE_INTEGER Subtrahend +; ) +; +; Routine Description: +; +; This function subtracts a signed large integer from a signed large +; integer and returns the signed large integer result. +; +; Arguments: +; +; (TOS+4) = Minuend +; (TOS+12) = Subtrahend +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlLargeIntegerSubtract ,4 +cPublicFpo 4,0 + + mov eax,[esp]+4 + sub eax,[esp]+12 ; (eax) = result.low + mov edx,[esp]+8 + sbb edx,[esp]+16 ; (edx) = result.high + stdRET _RtlLargeIntegerSubtract + +stdENDP _RtlLargeIntegerSubtract + + page + subttl "Convert Long to Large Integer" +;++ +; +; LARGE_INTEGER +; RtlConvertLongToLargeInteger ( +; IN LONG SignedInteger +; ) +; +; Routine Description: +; +; This function converts the input signed integer to a signed large +; integer and returns the latter as the result. +; +; Arguments: +; +; (TOS+4) = SignedInteger +; +; Return Value: +; +; The large integer result is stored (edx:eax) +; +;-- + +cPublicProc _RtlConvertLongToLargeInteger ,1 +cPublicFpo 1,0 + + mov eax,[esp]+4 ; (eax) = SignedInteger + cdq ; (edx:eax) = signed LargeInt + stdRET _RtlConvertLongToLargeInteger + +stdENDP _RtlConvertLongToLargeInteger + + + page + subttl "Convert Ulong to Large Integer" +;++ +; +; LARGE_INTEGER +; RtlConvertUlongToLargeInteger ( +; IN LONG UnsignedInteger +; ) +; +; Routine Description: +; +; This function converts the input unsigned integer to a signed large +; integer and returns the latter as the result. +; +; Arguments: +; +; (TOS+4) = UnsignedInteger +; +; Return Value: +; +; The large integer result is stored in (edx:eax) +; +;-- + +cPublicProc _RtlConvertUlongToLargeInteger ,1 +cPublicFpo 1,0 + + mov eax,[esp]+4 ; store low + xor edx,edx ; store 0 in high + stdRET _RtlConvertUlongToLargeInteger + +stdENDP _RtlConvertUlongToLargeInteger + + +_TEXT$00 ends + end diff --git a/private/ntos/rtl/i386/lzntx86.asm b/private/ntos/rtl/i386/lzntx86.asm new file mode 100644 index 000000000..cf21d5456 --- /dev/null +++ b/private/ntos/rtl/i386/lzntx86.asm @@ -0,0 +1,445 @@ + title "Compression and Decompression Engines" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; lzntx86.asm +; +; Abstract: +; +; This module implements the compression and decompression engines needed +; to support file system compression. Functions are provided to +; compress a buffer and decompress a buffer. +; +; Author: +; +; Mark Zbikowski (markz) 15-Mar-1994 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +; 15-Mar-1994 markz +; +; 386 version created +; +;-- +.386p + + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +_TEXT$01 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page + subttl "Decompress a buffer" +;++ +; +; NTSTATUS +; LZNT1DecompressChunk ( +; OUT PUCHAR UncompressedBuffer, +; IN PUCHAR EndOfUncompressedBufferPlus1, +; IN PUCHAR CompressedBuffer, +; IN PUCHAR EndOfCompressedBufferPlus1, +; OUT PULONG FinalUncompressedChunkSize +; ) +; +; Routine Description: +; +; This function decodes a stream of compression tokens and places the +; resultant output into the destination buffer. The format of the input +; is described ..\lznt1.c. As the input is decoded, checks are made to +; ensure that no data is read past the end of the compressed input buffer +; and that no data is stored past the end of the output buffer. Violations +; indicate corrupt input and are indicated by a status return. +; +; The following code takes advantage of two distinct observations. +; First, literal tokens occur at least twice as often as copy tokens. +; This argues for having a "fall-through" being the case where a literal +; token is found. We structure the main decomposition loop in eight +; pieces where the first piece is a sequence of literal-test fall-throughs +; and the remainder are a copy token followed by 7,6,...,0 literal-test +; fall-throughs. Each test examines a particular bit in the tag byte +; and jumps to the relevant code piece. +; +; The second observation involves performing bounds checking only +; when needed. Bounds checking the compressed buffer need only be done +; when fetching the tag byte. If there is not enough room left in the +; input for a tag byte and 8 (worst case) copy tokens, a branch is made +; to a second loop that handles a byte-by-byte "safe" copy to finish +; up the decompression. Similarly, at the head of the loop a check is +; made to ensure that there is enough room in the output buffer for 8 +; literal bytes. If not enough room is left, then the second loop is +; used. Finally, after performing each copy, the output-buffer check +; is made as well since a copy may take the destination pointer +; arbitrarily close to the end of the destination. +; +; The register conventions used in the loops below are: +; +; (al) contains the current tag byte +; (ebx) contains the current width in bits of the length given +; the maximum offset +; that can be utilized in a copy token. We update this +; value only prior to performing a copy. This width is used +; both to index a mask table (for extracting the length) as +; well as shifting (for extracting the copy offset) +; (ecx) is used to contain counts during copies +; (edx) is used as a temp variable during copies +; (esi) is used mainly as the source of the next compressed token. +; It is also used for copies. +; (edi) is used as the destination of literals and copies +; (ebp) is used as a frame pointer +; +; Arguments: +; +; UncompressedBuffer (ebp+8) - pointer to destination of uncompression. +; +; EndOfUncompressedBufferPlus1 (ebp+12) - pointer just beyond the +; output buffer. This is used for consistency checking of the stored +; compressed data. +; +; CompressedBuffer (ebp+16) - pointer to compressed source. This pointer +; has been adjusted by the caller to point past the header word, so +; the pointer points to the first tag byte describing which of the +; following tokens are literals and which are copy groups. +; +; EndOfCompressedBufferPlus1 (ebp+20) - pointer just beyond end of input +; buffer. This is used to terminate the decompression. +; +; FinalUncompressedChunkSize (ebp+24) - pointer to a returned decompressed +; size. This has meaningful data ONLY when LZNT1DecompressChunk returns +; STATUS_SUCCESS +; +; Return Value: +; +; STATUS_SUCCESS is returned only if the decompression consumes thee entire +; input buffer and does not exceed the output buffer. +; STATUS_BAD_COMPRESSION_BUFFER is returned when the output buffer would be +; overflowed. +; +;-- + +; Decompression macros + +;** TestLiteralAt - tests to see if there's a literal at a specific +; bit position. If so, it branches to the appropriate copy code +; (decorated by the bit being used). +; +; This code does no bounds checking + +TestLiteralAt macro CopyLabel,bit,IsMain + test al,1 SHL bit ; is there a copy token at this position? + jnz CopyLabel&bit ; yes, go copy it + + mov dl,[esi+bit+1] ; (dl) = literal byte from compressed stream +ifidn <IsMain>,<Y> + mov [edi+bit],dl ; store literal byte +else + mov [edi],dl ; store literal byte + inc edi ; point to next literal +endif + +endm + + +; Jump - allow specific jumps with computed labels. + +Jump macro lab,tag + jmp lab&tag +endm + + + +;** DoCopy - perform a copy. If a bit position is specified +; then branch to the appropriate point in the "safe" tail when +; the copy takes us too close to the end of the output buffer +; +; This code checks the bounds of the copy token: copying before the +; beginning of the buffer and copying beyond the end of the buffer. + +DoCopy macro AdjustLabel,bit,IsMain + +ifidn <IsMain>,<Y> +if bit ne 0 + add edi,bit +endif +endif + +Test&AdjustLabel&bit: + cmp edi,WidthBoundary + ja Adjust&AdjustLabel&bit + + xor ecx,ecx + mov cx,word ptr [esi+bit+1] ; (ecx) = encoded length:offset + lea edx,[esi+1] ; (edx) = next token location + mov Temp,edx + + mov esi,ecx ; (esi) = encoded length:offset + and ecx,MaskTab[ebx*4] ; (ecx) = length + xchg ebx,ecx ; (ebx) = length/(ecx) = width + shr esi,cl ; (esi) = offset + xchg ebx,ecx ; (ebx) = width, (ecx) = length + + neg esi ; (esi) = negative real offset + lea esi,[esi+edi-1] ; (esi) = pointer to previous string + + cmp esi,UncompressedBuffer ; off front of buffer? + jb DOA ; yes, error + + add ecx,3 ; (ecx) = real length + + lea edx,[edi+ecx] ; (edx) = end of copy +ifidn <IsMain>,<Y> + cmp edx,EndOfSpecialDest ; do we exceed buffer? + jae TailAdd&bit ; yes, handle in safe tail +else + cmp edx,EndOfUncompressedBufferPlus1 + ; do we exceed buffer? + ja DOA ; yes, error +endif + + rep movsb ; Copy the bytes + + mov esi,Temp ; (esi) = next token location + +ifidn <IsMain>,<Y> + sub edi,bit+1 +endif + +endm + + + + + +;** AdjustWidth - adjust width of length based upon current position of +; input buffer (max offset) + + +AdjustWidth macro l,i +Adjust&l&i: + dec ebx ; (ebx) = new width pointer + mov edx,UncompressedBuffer ; (edx) = pointer to dest buffer + add edx,WidthTab[ebx*4] ; (edx) = new width boundary + mov WidthBoundary,edx ; save boundary for comparison + jmp Test&l&i + +endm + + +;** GenerateBlock - generates the unsafe block of copy/literal pieces. +; +; This code does no checking for simple input/output checking. Only +; the data referred to by the copy tokens is checked. + +GenerateBlock macro bit +Copy&bit: + + DoCopy Body,bit,Y + + j = bit + 1 + while j lt 8 + TestLiteralAt Copy,%(j),Y + j = j + 1 + endm + + add esi,9 + add edi,8 + + jmp Top + + AdjustWidth Body,bit +endm + + + +;** GenerateTailBlock - generates safe tail block for compression. This +; code checks everything before each byte stored so it is expected +; to be executed only at the end of the buffer. + + +GenerateTailBlock macro bit +TailAdd&bit: + add EndOfCompressedBufferPlus1,1+2*8 + ; restore buffer length to true length + mov esi,Temp ; (esi) = source of copy token block + dec esi + +Tail&bit: + lea ecx,[esi+bit+1] ; (ecx) = source of next token + cmp ecx,EndOfCompressedBufferPlus1 ; are we done? + jz Done ; yes - we exactly match end of buffer +; ja DOA ; INTERNAL ERROR only + + cmp edi,EndOfUncompressedBufferPlus1 + jz Done ; go quit, destination is full +; ja DOA ; INTERNAL ERROR only + + TestLiteralAt TailCopy,bit,N + + Jump Tail,%(bit+1) + + +; We expect a copy token to be at [esi+bit+1]. This means that +; esi+bit+1+tokensize must be <= EndOfCompressedBufferPlus1 +TailCopy&bit: + lea ecx,[esi+bit+3] ; (ecx) = next input position + cmp ecx,EndOfCompressedBufferPlus1 ; do we go too far + ja DOA ; yes, we are beyond the end of buffer + + DoCopy Tail,bit,N ; perform copy + + Jump Tail,%(bit+1) + + AdjustWidth Tail,bit + +endm + + + +cPublicProc _LZNT1DecompressChunk ,5 + push ebp ; (tos) = saved frame pointer + mov ebp,esp ; (ebp) = frame pointer to arguments + sub esp,12 ; Open up room for locals + +Temp equ dword ptr [ebp-12] +WidthBoundary equ dword ptr [ebp-8] +EndOfSpecialDest equ dword ptr [ebp-4] + +;SavedEBP equ dword ptr [ebp] +;ReturnAddress equ dword ptr [ebp+4] + +UncompressedBuffer equ dword ptr [ebp+8] +EndOfUncompressedBufferPlus1 equ dword ptr [ebp+12] +CompressedBuffer equ dword ptr [ebp+16] +EndOfCompressedBufferPlus1 equ dword ptr [ebp+20] +FinalUncompressedChunkSize equ dword ptr [ebp+24] + + + push ebx + push esi + push edi + + mov edi,UncompressedBuffer ; (edi) = destination of decompress + mov esi,CompressedBuffer ; (esi) = header + sub EndOfCompressedBufferPlus1,1+2*8 ; make room for special source + + mov eax,EndOfUncompressedBufferPlus1 ; (eax) = end of destination + sub eax,8 ; (eax) = beginning of special tail + mov EndOfSpecialDest,eax ; store special tail + + mov WidthBoundary,edi ; force initial width mismatch + mov ebx,13 ; initial width of output + + +Top: cmp esi,EndOfCompressedBufferPlus1 ; Will this be the last tag group in source? + jae DoTail ; yes, go handle specially + cmp edi,EndOfSpecialDest ; are we too close to end of buffer? + jae DoTail ; yes, go skip to end + + mov al,byte ptr [esi] ; (al) = tag byte, (esi) points to token + + irpc i,<01234567> + TestLiteralAt Copy,%(i),Y + endm + + add esi,9 + add edi,8 + + jmp Top +; ; Width of offset Width of length +WidthTab dd 0FFFFh ; 16 0 + dd 0FFFFh ; 15 1 + dd 0FFFFh ; 14 2 + dd 0FFFFh ; 13 3 + dd 0FFFFh ; 12 4 + dd 2048 ; 11 5 + dd 1024 ; 10 6 + dd 512 ; 9 7 + dd 256 ; 8 8 + dd 128 ; 7 9 + dd 64 ; 6 10 + dd 32 ; 5 11 + dd 16 ; 4 12 + dd 0 ; 3 13 + dd 0 ; 2 14 + dd 0 ; 1 15 + dd 0 ; 0 16 + + +; ; +MaskTab dd 0000000000000000b ; 0 + dd 0000000000000001b ; 1 + dd 0000000000000011b ; 2 + dd 0000000000000111b ; 3 + dd 0000000000001111b ; 4 + dd 0000000000011111b ; 5 + dd 0000000000111111b ; 6 + dd 0000000001111111b ; 7 + dd 0000000011111111b ; 8 + dd 0000000111111111b ; 9 + dd 0000001111111111b ; 10 + dd 0000011111111111b ; 11 + dd 0000111111111111b ; 12 + dd 0001111111111111b ; 13 + dd 0011111111111111b ; 14 + dd 0111111111111111b ; 15 + dd 1111111111111111b ; 16 + + + irpc i,<01234567> + GenerateBlock %(i) + endm + +; We're handling a tail specially for this. We must check at all +; spots for running out of input as well as overflowing output. +; +; (esi) = pointer to possible next tag + +DoTail: add EndOfCompressedBufferPlus1,1+2*8 ; point to end of compressed input + +TailLoop: + cmp esi,EndOfCompressedBufferPlus1 ; are we totally done? + jz Done ; yes, go return + mov al,byte ptr [esi] ; (al) = tag byte + + jmp Tail0 + + irpc i,<01234567> + GenerateTailBlock i + endm + +Tail8: add esi,9 + jmp TailLoop + + + +DOA: mov eax,STATUS_BAD_COMPRESSION_BUFFER + jmp Final + +Done: mov eax,edi ; (eax) = pointer to next byte to store + sub eax,UncompressedBuffer ; (eax) = length of uncompressed + mov edi,FinalUncompressedChunkSize ; (edi) = user return value location + mov [edi],eax ; return total transfer size to user + xor eax,eax ; (eax) = STATUS_SUCCESS + +Final: pop edi + pop esi + pop ebx + mov esp,ebp + pop ebp + + + stdRET _LZNT1DecompressChunk + +stdENDP _LZNT1DecompressChunk + +_TEXT$01 ends + end diff --git a/private/ntos/rtl/i386/movemem.asm b/private/ntos/rtl/i386/movemem.asm new file mode 100644 index 000000000..f5131312d --- /dev/null +++ b/private/ntos/rtl/i386/movemem.asm @@ -0,0 +1,659 @@ + title "User Mode Zero and Move Memory functions" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; movemem.asm +; +; Abstract: +; +; This module implements functions to zero and copy blocks of memory +; +; +; Author: +; +; Steven R. Wood (stevewo) 25-May-1990 +; +; Environment: +; +; User mode only. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +if DBG +_DATA SEGMENT DWORD PUBLIC 'DATA' + + public _RtlpZeroCount + public _RtlpZeroBytes + +_RtlpZeroCount dd 0 +_RtlpZeroBytes dd 0 + +ifndef BLDR_KERNEL_RUNTIME +_MsgUnalignedPtr db 'RTL: RtlCompare/FillMemoryUlong called with unaligned pointer (%x)\n',0 +endif + +_DATA ENDS + +ifndef BLDR_KERNEL_RUNTIME +ifdef NTOS_KERNEL_RUNTIME + extrn _KdDebuggerEnabled:BYTE +endif + EXTRNP _DbgBreakPoint,0 + extrn _DbgPrint:near +endif +endif + +; +; Alignment parameters for zeroing and moving memory. +; + +ZERO_MEMORY_ALIGNMENT = 4 +ZERO_MEMORY_ALIGNMENT_LOG2 = 2 +ZERO_MEMORY_ALIGNMENT_MASK = ZERO_MEMORY_ALIGNMENT - 1 + +MEMORY_ALIGNMENT = 4 +MEMORY_ALIGNMENT_LOG2 = 2 +MEMORY_ALIGNMENT_MASK = MEMORY_ALIGNMENT - 1 + + +; +; Alignment for functions in this module +; + +CODE_ALIGNMENT macro + align 16 +endm + + +_TEXT$00 SEGMENT PARA PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page , 132 + subttl "RtlCompareMemory" +;++ +; +; ULONG +; RtlCompareMemory ( +; IN PVOID Source1, +; IN PVOID Source2, +; IN ULONG Length +; ) +; +; Routine Description: +; +; This function compares two blocks of memory and returns the number +; of bytes that compared equal. +; +; Arguments: +; +; Source1 (esp+4) - Supplies a pointer to the first block of memory to +; compare. +; +; Source2 (esp+8) - Supplies a pointer to the second block of memory to +; compare. +; +; Length (esp+12) - Supplies the Length, in bytes, of the memory to be +; compared. +; +; Return Value: +; +; The number of bytes that compared equal is returned as the function +; value. If all bytes compared equal, then the length of the orginal +; block of memory is returned. +; +;-- + +RcmSource1 equ [esp+12] +RcmSource2 equ [esp+16] +RcmLength equ [esp+20] + +CODE_ALIGNMENT +cPublicProc _RtlCompareMemory,3 +cPublicFpo 3,0 + + push esi ; save registers + push edi ; + cld ; clear direction + mov esi,RcmSource1 ; (esi) -> first block to compare + mov edi,RcmSource2 ; (edi) -> second block to compare + +; +; Compare dwords, if any. +; + +rcm10: mov ecx,RcmLength ; (ecx) = length in bytes + shr ecx,2 ; (ecx) = length in dwords + jz rcm20 ; no dwords, try bytes + repe cmpsd ; compare dwords + jnz rcm40 ; mismatch, go find byte + +; +; Compare residual bytes, if any. +; + +rcm20: mov ecx,RcmLength ; (ecx) = length in bytes + and ecx,3 ; (ecx) = length mod 4 + jz rcm30 ; 0 odd bytes, go do dwords + repe cmpsb ; compare odd bytes + jnz rcm50 ; mismatch, go report how far we got + +; +; All bytes in the block match. +; + +rcm30: mov eax,RcmLength ; set number of matching bytes + pop edi ; restore registers + pop esi ; + stdRET _RtlCompareMemory + +; +; When we come to rcm40, esi (and edi) points to the dword after the +; one which caused the mismatch. Back up 1 dword and find the byte. +; Since we know the dword didn't match, we can assume one byte won't. +; + +rcm40: sub esi,4 ; back up + sub edi,4 ; back up + mov ecx,5 ; ensure that ecx doesn't count out + repe cmpsb ; find mismatch byte + +; +; When we come to rcm50, esi points to the byte after the one that +; did not match, which is TWO after the last byte that did match. +; + +rcm50: dec esi ; back up + sub esi,RcmSource1 ; compute bytes that matched + mov eax,esi ; + pop edi ; restore registers + pop esi ; + stdRET _RtlCompareMemory + +stdENDP _RtlCompareMemory + + + subttl "RtlCompareMemory" +EcmlSource equ [esp + 4 + 4] +EcmlLength equ [esp + 4 + 8] +EcmlPattern equ [esp + 4 + 12] + +; end of arguments + +CODE_ALIGNMENT +cPublicProc _RtlCompareMemoryUlong ,3 + +; +; Save the non-volatile registers that we will use, without the benefit of +; a frame pointer. No exception handling in this routine. +; + + push edi + +; +; Setup the registers for using REP STOS instruction to zero memory. +; +; edi -> memory to zero +; ecx = number of 32-bits words to zero +; edx = number of extra 8-bit bytes to zero at the end (0 - 3) +; eax = value to store in destination +; direction flag is clear for auto-increment +; + + mov edi,EcmlSource +if DBG +ifndef BLDR_KERNEL_RUNTIME + test edi,3 + jz @F + push edi + push offset FLAT:_MsgUnalignedPtr + call _DbgPrint + add esp, 2 * 4 +ifdef NTOS_KERNEL_RUNTIME + cmp _KdDebuggerEnabled,0 +else + mov eax,fs:[PcTeb] + mov eax,[eax].TebPeb + cmp byte ptr [eax].PebBeingDebugged,0 +endif + je @F + call _DbgBreakPoint@0 +@@: +endif +endif + mov ecx,EcmlLength + mov eax,EcmlPattern + shr ecx,ZERO_MEMORY_ALIGNMENT_LOG2 + + +; +; If number of 32-bit words to compare is non-zero, then do it. +; + + repe scasd + je @F + sub edi,4 +@@: + sub edi,EcmlSource + mov eax,edi + pop edi + stdRET _RtlCompareMemoryUlong + +stdENDP _RtlCompareMemoryUlong + + + subttl "RtlFillMemory" +;++ +; +; VOID +; RtlFillMemory ( +; IN PVOID Destination, +; IN ULONG Length, +; IN UCHAR Fill +; ) +; +; Routine Description: +; +; This function fills memory with a byte value. +; +; Arguments: +; +; Destination - Supplies a pointer to the memory to zero. +; +; Length - Supplies the Length, in bytes, of the memory to be zeroed. +; +; Fill - Supplies the byte value to fill memory with. +; +; Return Value: +; +; None. +; +;-- + +; definitions for arguments +; (TOS) = Return address + +EfmDestination equ [esp + 4 + 4] +EfmLength equ [esp + 4 + 8] +EfmFill equ byte ptr [esp + 4 + 12] + +; end of arguments + +CODE_ALIGNMENT +cPublicProc _RtlFillMemory ,3 +cPublicFpo 3,1 + +; +; Save the non-volatile registers that we will use, without the benefit of +; a frame pointer. No exception handling in this routine. +; + + push edi + +; +; Setup the registers for using REP STOS instruction to zero memory. +; +; edi -> memory to zero +; ecx = number of 32-bits words to zero +; edx = number of extra 8-bit bytes to zero at the end (0 - 3) +; eax = value to store in destination +; direction flag is clear for auto-increment +; + + mov edi,EfmDestination + mov ecx,EfmLength + mov al,EfmFill + mov ah,al + shl eax,16 + mov al,EfmFill + mov ah,al + cld + + mov edx,ecx + and edx,ZERO_MEMORY_ALIGNMENT_MASK + shr ecx,ZERO_MEMORY_ALIGNMENT_LOG2 + + +; +; If number of 32-bit words to zero is non-zero, then do it. +; + + rep stosd + +; +; If number of extra 8-bit bytes to zero is non-zero, then do it. In either +; case restore non-volatile registers and return. +; + + or ecx,edx + jnz @F + pop edi + stdRET _RtlFillMemory +@@: + rep stosb + pop edi + stdRET _RtlFillMemory + +stdENDP _RtlFillMemory + + subttl "RtlFillMemory" +;++ +; +; VOID +; RtlFillMemoryUlong ( +; IN PVOID Destination, +; IN ULONG Length, +; IN ULONG Fill +; ) +; +; Routine Description: +; +; This function fills memory with a 32-bit value. The Destination pointer +; must be aligned on a 4 byte boundary and the low order two bits of the +; Length parameter are ignored. +; +; Arguments: +; +; Destination - Supplies a pointer to the memory to zero. +; +; Length - Supplies the Length, in bytes, of the memory to be zeroed. +; +; Fill - Supplies the 32-bit value to fill memory with. +; +; Return Value: +; +; None. +; +;-- + +; definitions for arguments +; (TOS) = Return address + +EfmlDestination equ [esp + 4 + 4] +EfmlLength equ [esp + 4 + 8] +EfmlFill equ [esp + 4 + 12] + +; end of arguments + +CODE_ALIGNMENT +cPublicProc _RtlFillMemoryUlong ,3 +cPublicFpo 3,1 + +; +; Save the non-volatile registers that we will use, without the benefit of +; a frame pointer. No exception handling in this routine. +; + + push edi + +; +; Setup the registers for using REP STOS instruction to zero memory. +; +; edi -> memory to zero +; ecx = number of 32-bits words to zero +; edx = number of extra 8-bit bytes to zero at the end (0 - 3) +; eax = value to store in destination +; direction flag is clear for auto-increment +; + + mov edi,EfmlDestination +if DBG +ifndef BLDR_KERNEL_RUNTIME + test edi,3 + jz @F + push edi + push offset FLAT:_MsgUnalignedPtr + call _DbgPrint + add esp, 2 * 4 +ifdef NTOS_KERNEL_RUNTIME + cmp _KdDebuggerEnabled,0 +else + mov eax,fs:[PcTeb] + mov eax,[eax].TebPeb + cmp byte ptr [eax].PebBeingDebugged,0 +endif + je @F + call _DbgBreakPoint@0 +@@: +endif +endif + mov ecx,EfmlLength + mov eax,EfmlFill + shr ecx,ZERO_MEMORY_ALIGNMENT_LOG2 + + +; +; If number of 32-bit words to zero is non-zero, then do it. +; + + rep stosd + + pop edi + stdRET _RtlFillMemoryUlong + +stdENDP _RtlFillMemoryUlong + + subttl "RtlZeroMemory" +;++ +; +; VOID +; RtlZeroMemory ( +; IN PVOID Destination, +; IN ULONG Length +; ) +; +; Routine Description: +; +; This function zeros memory. +; +; Arguments: +; +; Destination - Supplies a pointer to the memory to zero. +; +; Length - Supplies the Length, in bytes, of the memory to be zeroed. +; +; Return Value: +; +; None. +; +;-- + +; definitions for arguments +; (TOS) = Return address + +EzmDestination equ [esp + 4 + 4] +EzmLength equ [esp + 4 + 8] + +; end of arguments + +CODE_ALIGNMENT +cPublicProc _RtlZeroMemory ,2 +cPublicFpo 2,1 + +; +; Save the non-volatile registers that we will use, without the benefit of +; a frame pointer. No exception handling in this routine. +; + + push edi + +; +; Setup the registers for using REP STOS instruction to zero memory. +; +; edi -> memory to zero +; ecx = number of 32-bits words to zero +; edx = number of extra 8-bit bytes to zero at the end (0 - 3) +; eax = zero (value to store in destination) +; direction flag is clear for auto-increment +; + + mov edi,EzmDestination + mov ecx,EzmLength + xor eax,eax + cld + + mov edx,ecx + and edx,ZERO_MEMORY_ALIGNMENT_MASK + shr ecx,ZERO_MEMORY_ALIGNMENT_LOG2 + + +; +; If number of 32-bit words to zero is non-zero, then do it. +; + + rep stosd + +; +; If number of extra 8-bit bytes to zero is non-zero, then do it. In either +; case restore non-volatile registers and return. +; + + or ecx,edx + jnz @F + pop edi + stdRET _RtlZeroMemory +@@: + rep stosb + pop edi + stdRET _RtlZeroMemory + +stdENDP _RtlZeroMemory + + page , 132 + subttl "RtlMoveMemory" +;++ +; +; VOID +; RtlMoveMemory ( +; IN PVOID Destination, +; IN PVOID Source OPTIONAL, +; IN ULONG Length +; ) +; +; Routine Description: +; +; This function moves memory either forward or backward, aligned or +; unaligned, in 4-byte blocks, followed by any remaining bytes. +; +; Arguments: +; +; Destination - Supplies a pointer to the destination of the move. +; +; Source - Supplies a pointer to the memory to move. +; +; Length - Supplies the Length, in bytes, of the memory to be moved. +; +; Return Value: +; +; None. +; +;-- + +; Definitions of arguments +; (TOS) = Return address + +EmmDestination equ [esp + 8 + 4] +EmmSource equ [esp + 8 + 8] +EmmLength equ [esp + 8 + 12] + +; End of arguments + +CODE_ALIGNMENT +cPublicProc _RtlMoveMemory ,3 +cPublicFpo 3,2 + +; +; Save the non-volatile registers that we will use, without the benefit of +; a frame pointer. No exception handling in this routine. +; + + push esi + push edi + +; +; Setup the registers for using REP MOVS instruction to move memory. +; +; esi -> memory to move (NULL implies the destination will be zeroed) +; edi -> destination of move +; ecx = number of 32-bits words to move +; edx = number of extra 8-bit bytes to move at the end (0 - 3) +; direction flag is clear for auto-increment +; + + mov esi,EmmSource + mov edi,EmmDestination + mov ecx,EmmLength +if DBG + inc _RtlpZeroCount + add _RtlpZeroBytes,ecx +endif + cld + + cmp esi,edi ; Special case if Source > Destination + jbe overlap + +nooverlap: + mov edx,ecx + and edx,MEMORY_ALIGNMENT_MASK + shr ecx,MEMORY_ALIGNMENT_LOG2 + +; +; If number of 32-bit words to move is non-zero, then do it. +; + + rep movsd + +; +; If number of extra 8-bit bytes to move is non-zero, then do it. In either +; case restore non-volatile registers and return. +; + + or ecx,edx + jnz @F + pop edi + pop esi + stdRET _RtlMoveMemory +@@: + rep movsb + +movedone: + pop edi + pop esi + stdRET _RtlMoveMemory + +; +; Here to handle special case when Source > Destination and therefore is a +; potential overlapping move. If Source == Destination, then nothing to do. +; Otherwise, increment the Source and Destination pointers by Length and do +; the move backwards, a byte at a time. +; + +overlap: + je movedone + mov eax,edi + sub eax,esi + cmp ecx,eax + jbe nooverlap + + std + add esi,ecx + add edi,ecx + dec esi + dec edi + rep movsb + cld + jmp short movedone + +stdENDP _RtlMoveMemory + +_TEXT$00 ends + end diff --git a/private/ntos/rtl/i386/nlssup.asm b/private/ntos/rtl/i386/nlssup.asm new file mode 100644 index 000000000..3604542a7 --- /dev/null +++ b/private/ntos/rtl/i386/nlssup.asm @@ -0,0 +1,146 @@ + TITLE "String support routines" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; stringsup.asm +; +; Abstract: +; +; This module implements suplimentary routines for performing string +; operations. +; +; Author: +; +; Larry Osterman (larryo) 18-Sep-1991 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- + +.386p +include callconv.inc ; calling convention macros + + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "RtlAnsiCharToUnicodeChar" +;++ +; +; WCHAR +;RtlAnsiCharToUnicodeChar( +; IN OUT PCHAR *SourceCharacter +; ) +; +; +; Routine Description: +; +; This function translates the specified ansi character to unicode and +; returns the unicode value. The purpose for this routine is to allow +; for character by character ansi to unicode translation. The +; translation is done with respect to the current system locale +; information. +; +; +; Arguments: +; +; (TOS+4) = SourceCharacter - Supplies a pointer to an ansi character pointer. +; Through two levels of indirection, this supplies an ansi +; character that is to be translated to unicode. After +; translation, the ansi character pointer is modified to point to +; the next character to be converted. This is done to allow for +; dbcs ansi characters. +; +; Return Value: +; +; Returns the unicode equivalent of the specified ansi character. +; +; Note: +; +; This routine will have to be converted to use the proper unicode mapping +; tables. +; +;-- +cPublicProc _RtlAnsiCharToUnicodeChar ,1 +cPublicFpo 1,2 + push esi + mov esi, [esp+8] + push dword ptr [esi] ; Save the old input string + inc dword ptr [esi] ; Bump the input string + pop esi ; (ESI) = input string + xor eax, eax ; Zero out the EAX register. + lodsb ; Grab the first character from string + pop esi + stdRET _RtlAnsiCharToUnicodeChar + +stdENDP _RtlAnsiCharToUnicodeChar + + page + subttl "RtlpAnsiPszToUnicodePsz" +;++ +; +; VOID +; RtlpAnsiPszToUnicodePsz( +; IN PCHAR AnsiString, +; IN PWCHAR UnicodeString, +; IN USHORT AnsiStringLength +; ) +; +; +; Routine Description: +; +; This function translates the specified ansi character to unicode and +; returns the unicode value. The purpose for this routine is to allow +; for character by character ansi to unicode translation. The +; translation is done with respect to the current system locale +; information. +; +; +; Arguments: +; +; (ESP+4) = AnsiString - Supplies a pointer to the ANSI string to convert to unicode. +; (ESP+8) = UnicodeString - Supplies a pointer to a buffer to hold the unicode string +; (ESP+12) = AnsiStringLength - Supplies the length of the ANSI string. +; +; Return Value: +; +; None. +; +; +; Note: +; +; This routine will have to be converted to use the proper unicode mapping +; tables. +;-- + +cPublicProc _RtlpAnsiPszToUnicodePsz ,3 +cPublicFpo 3,2 + push esi + push edi + xor ecx, ecx + mov cx, [esp]+12+8 + jecxz raptup9 + mov esi, [esp]+4+8 + mov edi, [esp]+8+8 + xor ah, ah +@@: lodsb + stosw + loop @b + xor eax, eax + stosw ; Don't forget to stick the null at end +raptup9:pop edi + pop esi + stdRET _RtlpAnsiPszToUnicodePsz + +stdENDP _RtlpAnsiPszToUnicodePsz + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/nlstrans.asm b/private/ntos/rtl/i386/nlstrans.asm new file mode 100644 index 000000000..188e79578 --- /dev/null +++ b/private/ntos/rtl/i386/nlstrans.asm @@ -0,0 +1,668 @@ + title "NLS Translation" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; nlstrans.asm +; +; Abstract: +; +; This module implements the function to translate from Unicode +; characters to ANSI and OEM characters. The translation is based on +; the installed ACP and OEMCP. +; +; Author: +; +; Gregory Wilson 15 may 92 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc + .list + +_DATA SEGMENT DWORD PUBLIC 'DATA' + + extrn _NlsUnicodeToAnsiData:DWORD + extrn _NlsUnicodeToMbAnsiData:DWORD + extrn _NlsMbCodePageTag:BYTE + extrn _NlsUnicodeToOemData:DWORD + extrn _NlsUnicodeToMbOemData:DWORD + extrn _NlsMbOemCodePageTag:BYTE + +_DATA ENDS + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING + +_MultiByteString$ equ 8 +_MaxBytesInMultiByteString$ equ 12 +_BytesInMultiByteString$ equ 16 +_UnicodeString$ equ 20 +_BytesInUnicodeString$ equ 24 +_LoopCount$ equ -4 +_MultiByteStringAnchor$ equ -8 +_CharsInUnicodeString$ equ -12 + + align 4 + + public _RtlUnicodeToMultiByteN + +; NTSTATUS +; RtlUnicodeToMultiByteN( +; OUT PCH MultiByteString, +; IN ULONG MaxBytesInMultiByteString, +; OUT PULONG BytesInMultiByteString OPTIONAL, +; IN PWCH UnicodeString, +; IN ULONG BytesInUnicodeString) +; +; /*++ +; +; Routine Description: +; +; This functions converts the specified unicode source string into an +; ansi string. The translation is done with respect to the +; ANSI Code Page (ACP) loaded at boot time. +; +; Arguments: +; +; MultiByteString - Returns an ansi string that is equivalent to the +; unicode source string. If the translation can not be done +; because a character in the unicode string does not map to an +; ansi character in the ACP, an error is returned. +; +; MaxBytesInMultiByteString - Supplies the maximum number of bytes to be +; written to MultiByteString. If this causes MultiByteString to be a +; truncated equivalent of UnicodeString, no error condition results. +; +; BytesInMultiByteString - Returns the number of bytes in the returned +; ansi string pointed to by MultiByteString. +; +; UnicodeString - Supplies the unicode source string that is to be +; converted to ansi. +; +; BytesInUnicodeString - The number of bytes in the the string pointed to by +; UnicodeString. +; +; Return Value: +; +; SUCCESS - The conversion was successful +; +; --*/ +; +_RtlUnicodeToMultiByteN proc + push ebp + mov ebp, esp + sub esp, 12 + push ebx + ; + ; Save beginning position of MultiByteString ptr for later + ; use in calculating number of characters translated. + ; + mov eax, DWORD PTR _MultiByteString$[ebp] + mov DWORD PTR _MultiByteStringAnchor$[ebp], eax + ; + ; Convert BytesInUnicodeString to a character count and + ; compare against the maximum number of characters we have + ; room to translate. Use the minimum for the loop count. + ; + mov eax, DWORD PTR _BytesInUnicodeString$[ebp] + shr eax, 1 + mov ecx, DWORD PTR _MaxBytesInMultiByteString$[ebp] + sub eax, ecx + sbb edx, edx + and eax, edx + add eax, ecx + mov DWORD PTR _LoopCount$[ebp], eax + + ; + ; Set up registers such that: + ; ebx: UnicodeString + ; ecx: NlsUnicodeToAnsiData + ; edx: MultiByteString + ; + mov edx, DWORD PTR _MultiByteString$[ebp] + mov ebx, DWORD PTR _UnicodeString$[ebp] + mov ecx, DWORD PTR _NlsUnicodeToAnsiData + ; + ; Determine if we're dealing with SBCS or MBCS. + ; + cmp BYTE PTR _NlsMbCodePageTag, 0 ; 0 -> sbcs, 1 -> mbcs + jne $ACP_MBCS + ; + ; If the string to be translated does not contain a multiple + ; of 16 characters then figure out where to jump into the + ; translation loop to translate the left over characters first. + ; From then on the loop only deals with 16 characters at a time. + ; + and eax, 15 + je SHORT $ACP_TopOfSBLoop ; already a multiple of 16 chars. + + push eax ; save for indexing into jump table + sub DWORD PTR _LoopCount$[ebp], eax ; decrement LoopCount + add edx, eax ; increment MultiByteString ptr + lea eax, DWORD PTR [eax*2] + add ebx, eax ; increment UnicodeString ptr + + ; + ; Use ACP_JumpTable to jump into the while loop at the appropriate + ; spot to take care of the *extra* characters. + ; + pop eax + dec eax + jmp DWORD PTR cs:$ACP_JumpTable[eax*4] + + ; + ; Main translation loop. Translates 16 characters on each iteration. + ; +$ACP_TopOfSBLoop: + cmp DWORD PTR _LoopCount$[ebp], 0 + jbe $ACP_FinishedTranslation + ; + ; Adjust pointers for next iteration + ; + add edx, 16 ; increment MultiByteString ptr + add ebx, 32 ; increment UnicodeString ptr + sub DWORD PTR _LoopCount$[ebp], 16 ; decrement LoopCount + + ; + ; begin translation + ; + movzx eax, WORD PTR [ebx-32] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-16], al +$ACP_SBAdjust15: + movzx eax, WORD PTR [ebx-30] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-15], al +$ACP_SBAdjust14: + movzx eax, WORD PTR [ebx-28] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-14], al +$ACP_SBAdjust13: + movzx eax, WORD PTR [ebx-26] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-13], al +$ACP_SBAdjust12: + movzx eax, WORD PTR [ebx-24] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-12], al +$ACP_SBAdjust11: + movzx eax, WORD PTR [ebx-22] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-11], al +$ACP_SBAdjust10: + movzx eax, WORD PTR [ebx-20] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-10], al +$ACP_SBAdjust9: + movzx eax, WORD PTR [ebx-18] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-9], al +$ACP_SBAdjust8: + movzx eax, WORD PTR [ebx-16] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-8], al +$ACP_SBAdjust7: + movzx eax, WORD PTR [ebx-14] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-7], al +$ACP_SBAdjust6: + movzx eax, WORD PTR [ebx-12] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-6], al +$ACP_SBAdjust5: + movzx eax, WORD PTR [ebx-10] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-5], al +$ACP_SBAdjust4: + movzx eax, WORD PTR [ebx-8] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-4], al +$ACP_SBAdjust3: + movzx eax, WORD PTR [ebx-6] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-3], al +$ACP_SBAdjust2: + movzx eax, WORD PTR [ebx-4] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-2], al +$ACP_SBAdjust1: + movzx eax, WORD PTR [ebx-2] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-1], al + + jmp $ACP_TopOfSBLoop + + ; + ; The ACP is a multibyte code page. Translation is done here. + ; + ; WARNING!! WARNING!! No optimization has been done on this loop. + ; +$ACP_MBCS: + mov eax, DWORD PTR _BytesInUnicodeString$[ebp] + shr eax, 1 + mov DWORD PTR _CharsInUnicodeString$[ebp], eax + dec DWORD PTR _CharsInUnicodeString$[ebp] + or eax, eax + mov ecx, DWORD PTR _NlsUnicodeToMbAnsiData + je SHORT $ACP_FinishedTranslation +$ACP_TopOfMBLoop: + ; + ; Check to make sure we have room in the destination string. + ; + mov eax, DWORD PTR _MaxBytesInMultiByteString$[ebp] + dec DWORD PTR _MaxBytesInMultiByteString$[ebp] + or eax, eax + je SHORT $ACP_FinishedTranslation + ; + ; Grab the multibyte character(s) from the translation table + ; and increment the source string pointer. + ; + mov eax, DWORD PTR _UnicodeString$[ebp] + movzx eax, WORD PTR [eax] + mov dx, WORD PTR [ecx+eax*2] + add DWORD PTR _UnicodeString$[ebp], 2 + mov bl, dh + ; + ; Check for a lead byte. + ; + or bl, bl + je SHORT $ACP_NoLeadByte + ; + ; There is a lead byte. Make sure there's room in the + ; destination buffer for both the lead byte and trail byte. + ; + mov eax, DWORD PTR _MaxBytesInMultiByteString$[ebp] + dec DWORD PTR _MaxBytesInMultiByteString$[ebp] + or eax, eax + je SHORT $ACP_FinishedTranslation + ; + ; Store the lead byte in the destination buffer, increment + ; the destination pointer and decrement the count of remaining + ; space. + ; + mov eax, DWORD PTR _MultiByteString$[ebp] + mov BYTE PTR [eax], bl + inc DWORD PTR _MultiByteString$[ebp] + dec DWORD PTR _MaxBytesInMultiByteString$[ebp] + ; + ; Store the single byte or trail byte. + ; +$ACP_NoLeadByte: + mov eax, DWORD PTR _MultiByteString$[ebp] + mov BYTE PTR [eax], dl + inc DWORD PTR _MultiByteString$[ebp] + ; + ; Check to see if there are any more characters to translate. + ; + mov eax, DWORD PTR _CharsInUnicodeString$[ebp] + dec DWORD PTR _CharsInUnicodeString$[ebp] + or eax, eax + jne SHORT $ACP_TopOfMBLoop + ; + ; We're finished translating for the multibyte case. + ; Set up edx so we can calculate the number of characters + ; written (if the user has requested it). + ; + mov edx, DWORD PTR _MultiByteString$[ebp] + +$ACP_FinishedTranslation: + mov eax, DWORD PTR _BytesInMultiByteString$[ebp] + or eax, eax + je SHORT $ACP_NoOptParam + sub edx, DWORD PTR _MultiByteStringAnchor$[ebp] + mov DWORD PTR [eax], edx +$ACP_NoOptParam: + sub eax, eax + pop ebx + leave + ret 0 ; return STATUS_SUCCESS + +$ACP_JumpTable: + DD OFFSET FLAT:$ACP_SBAdjust1 + DD OFFSET FLAT:$ACP_SBAdjust2 + DD OFFSET FLAT:$ACP_SBAdjust3 + DD OFFSET FLAT:$ACP_SBAdjust4 + DD OFFSET FLAT:$ACP_SBAdjust5 + DD OFFSET FLAT:$ACP_SBAdjust6 + DD OFFSET FLAT:$ACP_SBAdjust7 + DD OFFSET FLAT:$ACP_SBAdjust8 + DD OFFSET FLAT:$ACP_SBAdjust9 + DD OFFSET FLAT:$ACP_SBAdjust10 + DD OFFSET FLAT:$ACP_SBAdjust11 + DD OFFSET FLAT:$ACP_SBAdjust12 + DD OFFSET FLAT:$ACP_SBAdjust13 + DD OFFSET FLAT:$ACP_SBAdjust14 + DD OFFSET FLAT:$ACP_SBAdjust15 + +_RtlUnicodeToMultiByteN ENDP + +_OemString$ equ 8 +_MaxBytesInOemString$ equ 12 +_BytesInOemString$ equ 16 +_UnicodeString$ equ 20 +_BytesInUnicodeString$ equ 24 +_LoopCount$ equ -4 +_OemStringAnchor$ equ -8 +_CharsInUnicodeString$ equ -12 + + public _RtlUnicodeToOemN + +; NTSTATUS +; RtlUnicodeToOemN( +; OUT PCH OemString, +; IN ULONG MaxBytesInOemString, +; OUT PULONG BytesInOemString OPTIONAL, +; IN PWCH UnicodeString, +; IN ULONG BytesInUnicodeString) +; +; /*++ +; +; Routine Description: +; +; This functions converts the specified unicode source string into an +; oem string. The translation is done with respect to the OEM Code +; Page (OCP) loaded at boot time. +; +; Arguments: +; +; OemString - Returns an oem string that is equivalent to the +; unicode source string. If the translation can not be done +; because a character in the unicode string does not map to an +; oem character in the OCP, an error is returned. +; +; MaxBytesInOemString - Supplies the maximum number of bytes to be +; written to OemString. If this causes OemString to be a +; truncated equivalent of UnicodeString, no error condition results. +; +; BytesInOemString - Returns the number of bytes in the returned +; oem string pointed to by OemString. +; +; UnicodeString - Supplies the unicode source string that is to be +; converted to oem. +; +; BytesInUnicodeString - The number of bytes in the the string pointed to by +; UnicodeString. +; +; Return Value: +; +; SUCCESS - The conversion was successful +; +; STATUS_BUFFER_OVERFLOW - MaxBytesInOemString was not enough to hold +; the whole Oem string. It was converted correct to the point though. +; +; --*/ +_RtlUnicodeToOemN proc + push ebp + mov ebp, esp + sub esp, 12 + push ebx + ; + ; Save beginning position of OemString ptr for later + ; use in calculating number of characters translated. + ; + mov eax, DWORD PTR _OemString$[ebp] + mov DWORD PTR _OemStringAnchor$[ebp], eax + ; + ; Convert BytesInUnicodeString to a character count and + ; compare against the maximum number of characters we have + ; room to translate. Use the minimum for the loop count. + ; + mov eax, DWORD PTR _BytesInUnicodeString$[ebp] + shr eax, 1 + mov ecx, DWORD PTR _MaxBytesInOemString$[ebp] + sub eax, ecx + sbb edx, edx + and eax, edx + add eax, ecx + mov DWORD PTR _LoopCount$[ebp], eax + ; + ; Set up registers such that: + ; ebx: UnicodeString + ; ecx: NlsUnicodeToOemData + ; edx: OemString + ; + mov edx, DWORD PTR _OemString$[ebp] + mov ebx, DWORD PTR _UnicodeString$[ebp] + mov ecx, DWORD PTR _NlsUnicodeToOemData + ; + ; Determine if we're dealing with SBCS or MBCS. + ; + cmp BYTE PTR _NlsMbOemCodePageTag, 0 ; 0 -> sbcs, 1 -> mbcs + jne $OEMCP_MBCS + ; + ; If the string to be translated does not contain a multiple + ; of 16 characters then figure out where to jump into the + ; translation loop to translate the left over characters first. + ; From then on the loop only deals with 16 characters at a time. + ; + and eax, 15 + je SHORT $OEMCP_TopOfSBLoop ; already a multiple of 16 chars. + + push eax ; save for indexing into jump table + sub DWORD PTR _LoopCount$[ebp], eax ; decrement LoopCount + add edx, eax ; increment OemString ptr + lea eax, DWORD PTR [eax*2] + add ebx, eax ; increment UnicodeString ptr + + ; + ; Use OEMCP_JumpTable to jump into the while loop at the appropriate + ; spot to take care of the *extra* characters. + ; + pop eax + dec eax + jmp DWORD PTR cs:$OEMCP_JumpTable[eax*4] + + ; + ; Main translation loop. Translates 16 characters on each iteration. + ; +$OEMCP_TopOfSBLoop: + cmp DWORD PTR _LoopCount$[ebp], 0 + jbe $OEMCP_FinishedTranslation + ; + ; Adjust pointers for next iteration + ; + add edx, 16 ; increment OemString ptr + add ebx, 32 ; increment UnicodeString ptr + sub DWORD PTR _LoopCount$[ebp], 16 ; decrement LoopCount + + ; + ; begin translation + ; + movzx eax, WORD PTR [ebx-32] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-16], al +$OEMCP_SBAdjust15: + movzx eax, WORD PTR [ebx-30] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-15], al +$OEMCP_SBAdjust14: + movzx eax, WORD PTR [ebx-28] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-14], al +$OEMCP_SBAdjust13: + movzx eax, WORD PTR [ebx-26] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-13], al +$OEMCP_SBAdjust12: + movzx eax, WORD PTR [ebx-24] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-12], al +$OEMCP_SBAdjust11: + movzx eax, WORD PTR [ebx-22] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-11], al +$OEMCP_SBAdjust10: + movzx eax, WORD PTR [ebx-20] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-10], al +$OEMCP_SBAdjust9: + movzx eax, WORD PTR [ebx-18] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-9], al +$OEMCP_SBAdjust8: + movzx eax, WORD PTR [ebx-16] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-8], al +$OEMCP_SBAdjust7: + movzx eax, WORD PTR [ebx-14] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-7], al +$OEMCP_SBAdjust6: + movzx eax, WORD PTR [ebx-12] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-6], al +$OEMCP_SBAdjust5: + movzx eax, WORD PTR [ebx-10] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-5], al +$OEMCP_SBAdjust4: + movzx eax, WORD PTR [ebx-8] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-4], al +$OEMCP_SBAdjust3: + movzx eax, WORD PTR [ebx-6] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-3], al +$OEMCP_SBAdjust2: + movzx eax, WORD PTR [ebx-4] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-2], al +$OEMCP_SBAdjust1: + movzx eax, WORD PTR [ebx-2] + mov al, BYTE PTR [eax+ecx] + mov BYTE PTR [edx-1], al + + jmp $OEMCP_TopOfSBLoop + + ; + ; The OEMCP is a multibyte code page. Translation is done here. + ; + ; WARNING!! WARNING!! No optimization has been done on this loop. + ; +$OEMCP_MBCS: + mov eax, DWORD PTR _BytesInUnicodeString$[ebp] + shr eax, 1 + mov DWORD PTR _CharsInUnicodeString$[ebp], eax + dec DWORD PTR _CharsInUnicodeString$[ebp] + or eax, eax + mov ecx, DWORD PTR _NlsUnicodeToMbOemData + je SHORT $OEMCP_FinishedTranslation +$OEMCP_TopOfMBLoop: + ; + ; Check to make sure we have room in the destination string. + ; + mov eax, DWORD PTR _MaxBytesInOemString$[ebp] + dec DWORD PTR _MaxBytesInOemString$[ebp] + or eax, eax + je SHORT $OEMCP_FinishedTranslation + ; + ; Grab the multibyte character(s) from the translation table + ; and increment the source string pointer. + ; + mov eax, DWORD PTR _UnicodeString$[ebp] + movzx eax, WORD PTR [eax] + mov dx, WORD PTR [ecx+eax*2] + add DWORD PTR _UnicodeString$[ebp], 2 + mov bl, dh + ; + ; Check for a lead byte. + ; + or bl, bl + je SHORT $OEMCP_NoLeadByte + ; + ; There is a lead byte. Make sure there's room in the + ; destination buffer for both the lead byte and trail byte. + ; + mov eax, DWORD PTR _MaxBytesInOemString$[ebp] + dec DWORD PTR _MaxBytesInOemString$[ebp] + or eax, eax + je SHORT $OEMCP_FinishedTranslation + ; + ; Store the lead byte in the destination buffer, increment + ; the destination pointer and decrement the count of remaining + ; space. + ; + mov eax, DWORD PTR _OemString$[ebp] + mov BYTE PTR [eax], bl + inc DWORD PTR _OemString$[ebp] + dec DWORD PTR _MaxBytesInOemString$[ebp] + ; + ; Store the single byte or trail byte. + ; +$OEMCP_NoLeadByte: + mov eax, DWORD PTR _OemString$[ebp] + mov BYTE PTR [eax], dl + inc DWORD PTR _OemString$[ebp] + ; + ; Check to see if there are any more characters to translate. + ; + mov eax, DWORD PTR _CharsInUnicodeString$[ebp] + dec DWORD PTR _CharsInUnicodeString$[ebp] + or eax, eax + jne SHORT $OEMCP_TopOfMBLoop + ; + ; We're finished translating for the multibyte case. + ; Set up edx so we can calculate the number of characters + ; written (if the user has requested it). + ; + mov edx, DWORD PTR _OemString$[ebp] + +$OEMCP_FinishedTranslation: + mov eax, DWORD PTR _BytesInOemString$[ebp] + or eax, eax + je SHORT $OEMCP_NoOptParam + sub edx, DWORD PTR _OemStringAnchor$[ebp] + mov DWORD PTR [eax], edx +$OEMCP_NoOptParam: + ; + ; If we ran out of space in the destination buffer before + ; translating all of the Unicode characters then return + ; STATUS_BUFFER_OVERFLOW. Check is done by looking at + ; # of chars in Unicode string left to translate. + ; +; +; WARNING! +; +; we can't check CharsInUnicodeString since we determined the loop +; count above and don't modify CharsInUnicodeString anymore... +; +; cmp DWORD PTR _CharsInUnicodeString$[ebp], 1 +; cmc +; sbb eax, eax +; and eax, -2147483643 ; STATUS_BUFFER_OVERFLOW (80000005H) + sub eax, eax ; return STATUS_SUCCESS + pop ebx + leave + ret 0 + +$OEMCP_JumpTable: + DD OFFSET FLAT:$OEMCP_SBAdjust1 + DD OFFSET FLAT:$OEMCP_SBAdjust2 + DD OFFSET FLAT:$OEMCP_SBAdjust3 + DD OFFSET FLAT:$OEMCP_SBAdjust4 + DD OFFSET FLAT:$OEMCP_SBAdjust5 + DD OFFSET FLAT:$OEMCP_SBAdjust6 + DD OFFSET FLAT:$OEMCP_SBAdjust7 + DD OFFSET FLAT:$OEMCP_SBAdjust8 + DD OFFSET FLAT:$OEMCP_SBAdjust9 + DD OFFSET FLAT:$OEMCP_SBAdjust10 + DD OFFSET FLAT:$OEMCP_SBAdjust11 + DD OFFSET FLAT:$OEMCP_SBAdjust12 + DD OFFSET FLAT:$OEMCP_SBAdjust13 + DD OFFSET FLAT:$OEMCP_SBAdjust14 + DD OFFSET FLAT:$OEMCP_SBAdjust15 + +_RtlUnicodeToOemN ENDP + +_TEXT ENDS + end diff --git a/private/ntos/rtl/i386/ntcurteb.asm b/private/ntos/rtl/i386/ntcurteb.asm new file mode 100644 index 000000000..1e59478ad --- /dev/null +++ b/private/ntos/rtl/i386/ntcurteb.asm @@ -0,0 +1,79 @@ + title "NtCurTeb.asm" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; NtCurTeb.asm +; +; Abstract: +; +; Efficient NtCurrentTeb code. +; +; Author: +; +; Bryan Willman (bryanwi) 28 feb 90 +; +; Environment: +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + + page ,132 + subttl "NtCurrentTeb" + +IFDEF NTOS_KERNEL_RUNTIME +.PAGE SEGMENT DWORD PUBLIC 'CODE' +ELSE +_TEXT SEGMENT DWORD PUBLIC 'CODE' +ENDIF + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +;++ +; +; PTEB +; NtCurrentTeb(); +; +; Routine Description: +; +; This routine returns the address of the current TEB. +; +; Arguments: +; +; None +; +; Return Value: +; +; Address of TEB. +; +;-- +cPublicProc _NtCurrentTeb ,0 +cPublicFpo 0,0 + +; +; How this works in both user and kernel mode. +; +; In user mode, TEB.TIB.Self is flat address of containing structure. +; In kernel mode, PCR.TIB.Self is flat address of the TEB. +; Same offset both places, so fs:PcTeb is always the flat address +; of the TEB. +; + + mov eax,fs:[PcTeb] + stdRET _NtCurrentTeb + +stdENDP _NtCurrentTeb +IFDEF NTOS_KERNEL_RUNTIME +.PAGE ENDS +ELSE +_TEXT ENDS +ENDIF + end diff --git a/private/ntos/rtl/i386/ntrtl386.h b/private/ntos/rtl/i386/ntrtl386.h new file mode 100644 index 000000000..88e69b505 --- /dev/null +++ b/private/ntos/rtl/i386/ntrtl386.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + ntrtl386.h + +Abstract: + + i386 specific parts of ntrtlp.h + +Author: + + Bryan Willman 10 April 90 + +Environment: + + These routines are statically linked in the caller's executable and + are callable in either kernel mode or user mode. + +Revision History: + +--*/ + +// +// Exception handling procedure prototypes. +// +VOID +RtlpCaptureContext ( + OUT PCONTEXT ContextRecord + ); + +VOID +RtlpUnlinkHandler ( + PEXCEPTION_REGISTRATION_RECORD UnlinkPointer + ); + +PEXCEPTION_REGISTRATION_RECORD +RtlpGetRegistrationHead ( + VOID + ); + +PVOID +RtlpGetReturnAddress ( + VOID + ); + + +// +// Record dump procedures. +// + +VOID +RtlpContextDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ); + +VOID +RtlpExceptionReportDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ); + +VOID +RtlpExceptionRegistrationDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ); diff --git a/private/ntos/rtl/i386/raise.asm b/private/ntos/rtl/i386/raise.asm new file mode 100644 index 000000000..18f928fed --- /dev/null +++ b/private/ntos/rtl/i386/raise.asm @@ -0,0 +1,181 @@ + title "Raise Exception" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; raise.asm +; +; Abstract: +; +; This module implements the function to raise a software exception. +; +; Author: +; +; Bryan Willman 11 april 90 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + + EXTRNP _ZwRaiseException,3 + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +; +; Context flags definition. +; + +CONTEXT_SETTING EQU CONTEXT_INTEGER OR CONTEXT_CONTROL OR CONTEXT_SEGMENTS + + +; +; Exception record length definition. +; + +EXCEPTION_RECORD_LENGTH EQU (ErExceptionInformation + 16) AND 0fffffff0H + + page + subttl "Raise Software Exception" +;++ +; +; VOID +; RtlRaiseException ( +; IN PEXCEPTION_RECORD ExceptionRecord +; ) +; +; Routine Description: +; +; This function raises a software exception by building a context record, +; establishing the stack limits of the current processor mode, and calling +; the exception dispatcher. If the exception dispatcher finds a handler +; to process the exception, then control is returned to the caller using +; the NtContinue system service. Otherwise the NtLastChance system service +; is called to provide default handing. +; +; N.B. On the 386, floating point state is not defined for non-fp +; exceptions. Therefore, this routine does not attempt to +; capture it. +; +; This means this routine cannot be used to report fp exceptions. +; +; Arguments: +; +; ExceptionRecord (ebp+8) - Supplies a pointer to an exception record. +; +; Return Value: +; +; None. +; +;-- + +cPublicProc _RtlRaiseException ,1 + + push ebp + mov ebp,esp + pushfd ; save flags before sub + sub esp,ContextFrameLength ; Allocate a context record + +; +; Save regs we use in context record +; + + mov [(ebp-ContextFrameLength-4)+CsEax],eax + mov [(ebp-ContextFrameLength-4)+CsEcx],ecx + +; +; Get pointer to exception report record, and set the exceptionaddress +; field to be our return address +; + + mov eax,[ebp+8] ; (eax) -> ExceptionReportRecord + + mov ecx,[ebp+4] + mov [eax.ErExceptionAddress],ecx + +; +; Copy machine context into the context record +; + + + lea eax,[ebp-ContextFrameLength-4] ; (eax) -> Context record + + mov [eax.CsEip],ecx + + mov [eax.CsEbx],ebx + mov [eax.CsEdx],edx + + mov [eax.CsEsi],esi + mov [eax.CsEdi],edi + +; +; context record's ESP must have the argument popped off the stack +; + + lea ecx,[ebp+12] + + mov [eax.CsEsp],ecx + + mov ecx,[ebp] + mov [eax.CsEbp],ecx + + mov ecx,[ebp-4] + mov [eax.CsEflags],ecx + + mov dword ptr [eax.CsSegCs],cs + mov dword ptr [eax.CsSegDs],ds + mov dword ptr [eax.CsSegEs],es + mov dword ptr [eax.CsSegFs],fs + mov dword ptr [eax.CsSegGs],gs + mov dword ptr [eax.CsSegSs],ss + +; +; Set Context flags, note that FLOATING_POINT is NOT set. +; + + mov dword ptr [eax.CsContextFlags],CONTEXT_SETTING + +; +; _ZwRaiseException(ExceptionRecord, ContextRecord, FirstChance=TRUE) +; + +; 1 - TRUE +; eax - Context Record +; [ebp+8] - Exception Report Record + + stdCall _ZwRaiseException,<[ebp+8],eax,1> + +; +; We came back, suggesting some sort of error in the call. Raise +; a status exception to report this, return from ZwRaiseException is type. +; + + sub esp,EXCEPTION_RECORD_LENGTH ; allocate record on stack, esp is base + mov [esp.ErExceptionCode],eax ; set exception type + or dword ptr [esp.ErExceptionFlags],EXCEPTION_NONCONTINUABLE + mov dword ptr [esp.ErNumberParameters],0 ; no parms + mov eax,[ebp+8] + mov [esp.ErExceptionRecord],eax ; point back to first exception + mov eax,esp + stdCall _RtlRaiseException,<eax> + +; +; We will never come here, because RtlRaiseException will not allow +; return if exception is non-continuable. +; + +stdENDP _RtlRaiseException + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/raisests.c b/private/ntos/rtl/i386/raisests.c new file mode 100644 index 000000000..d58f5f09d --- /dev/null +++ b/private/ntos/rtl/i386/raisests.c @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + raisests.c + +Abstract: + + This module implements the routine that raises an exception given a + specific status value. + +Author: + + David N. Cutler (davec) 8-Aug-1990 + +Environment: + + Any mode. + +Revision History: + +--*/ + +#include "ntrtlp.h" + +VOID +RtlRaiseStatus ( + IN NTSTATUS Status + ) + +/*++ + +Routine Description: + + This function raises an exception with the specified status value. The + exception is marked as continuable with no parameters. + +Arguments: + + Status - Supplies the status value to be used as the exception code + for the exception that is to be raised. + +Return Value: + + None. + +--*/ + +{ + + EXCEPTION_RECORD ExceptionRecord; + + // + // Construct an exception record. + // + + ExceptionRecord.ExceptionCode = Status; + ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + RtlRaiseException(&ExceptionRecord); + return; +} diff --git a/private/ntos/rtl/i386/rtldump.c b/private/ntos/rtl/i386/rtldump.c new file mode 100644 index 000000000..a75c27353 --- /dev/null +++ b/private/ntos/rtl/i386/rtldump.c @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + rtldump.c + +Abstract: + + This module implements dump procedures for: + + ContextRecords, + ExceptionReportRecords, + ExceptionRegistrationRecords + +Author: + + Bryan Willman (bryanwi) 12 April 90 + +Environment: + + Callable in any mode in which DbgPrint works. + +Revision History: + +--*/ + +#include "ntrtlp.h" + +VOID +RtlpContextDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ) +/*++ + +Routine Description: + + This function dumps the contents of a context record. + + Currently, it does not dump floating point context. + +Arguments: + + Object - Address of the record to dump. + + Control - Ignored, here so we look like a standard dump procedure. + +Return Value: + + none + +--*/ + +{ + PCONTEXT Context; + + Context = (PCONTEXT)Object; + + DbgPrint(" Record @ %lx\n", (ULONG)Context); + DbgPrint(" ContextFlags: %lx\n", Context->ContextFlags); + DbgPrint("\n"); + + DbgPrint(" SegGs: %lx\n", Context->SegGs); + DbgPrint(" SegFs: %lx\n", Context->SegFs); + DbgPrint(" SegEs: %lx\n", Context->SegEs); + DbgPrint(" SegDs: %lx\n", Context->SegDs); + DbgPrint("\n"); + + DbgPrint(" Edi: %lx\n", Context->Edi); + DbgPrint(" Esi: %lx\n", Context->Esi); + DbgPrint(" Ebx: %lx\n", Context->Ebx); + DbgPrint(" Edx: %lx\n", Context->Edx); + DbgPrint(" Ecx: %lx\n", Context->Ecx); + DbgPrint(" Eax: %lx\n", Context->Eax); + DbgPrint("\n"); + + DbgPrint(" Ebp: %lx\n", Context->Ebp); + DbgPrint(" Eip: %lx\n", Context->Eip); + DbgPrint(" SegCs: %lx\n", Context->SegCs); + DbgPrint(" EFlags: %lx\n", Context->EFlags); + DbgPrint(" Esp: %lx\n", Context->Esp); + DbgPrint(" SegSs: %lx\n", Context->SegSs); + DbgPrint("\n"); + + return; +} + + + +VOID +RtlpExceptionReportDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ) +/*++ + +Routine Description: + + This function dumps the contents of an Exception report record. + +Arguments: + + Object - Address of the record to dump. + + Control - Ignored, here so we look like a standard dump procedure. + +Return Value: + + none + +--*/ + +{ + ULONG i; + + PEXCEPTION_RECORD Exception; + + Exception = (PEXCEPTION_RECORD)Object; + + DbgPrint(" Record @ %lx\n", (ULONG)Exception); + DbgPrint(" ExceptionCode: %lx\n", Exception->ExceptionCode); + DbgPrint(" ExceptionFlags: %lx\n", Exception->ExceptionFlags); + DbgPrint(" ExceptionRecord: %lx\n", Exception->ExceptionRecord); + DbgPrint(" ExceptionAddress: %lx\n", Exception->ExceptionAddress); + DbgPrint(" NumberParameters: %lx\n", Exception->NumberParameters); + for (i = 0; i < Exception->NumberParameters; i++) + DbgPrint("ExceptionInformation[%d]: %lx\n", + i, Exception->ExceptionInformation[i]); + DbgPrint("\n"); + return; +} + + + +VOID +RtlpExceptionRegistrationDump( + IN PVOID Object, + IN ULONG Control OPTIONAL + ) +/*++ + +Routine Description: + + This function dumps the contents of an exception registration record, + unless Object == NULL, in which case it dumps the entire registration + chain. + + Currently, it does not dump floating point context. + +Arguments: + + Object - Address of the record to dump. + + Control - Ignored, here so we look like a standard dump procedure. + +Return Value: + + none + +--*/ + +{ + PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; + + RegistrationPointer = (PEXCEPTION_REGISTRATION_RECORD)Object; + + if (RegistrationPointer != EXCEPTION_CHAIN_END) { + DbgPrint("Record @ %lx\n", (ULONG)RegistrationPointer); + DbgPrint(" Next: %lx\n", RegistrationPointer->Next); + DbgPrint("Handler: %lx\n", RegistrationPointer->Handler); + DbgPrint("\n"); + } else { + RegistrationPointer = RtlpGetRegistrationHead(); + + while (RegistrationPointer != EXCEPTION_CHAIN_END) { + DbgPrint("Record @ %lx\n", (ULONG)RegistrationPointer); + DbgPrint(" Next: %lx\n", RegistrationPointer->Next); + DbgPrint("Handler: %lx\n", RegistrationPointer->Handler); + DbgPrint("\n"); + } + } + return; +} diff --git a/private/ntos/rtl/i386/stkwalk.asm b/private/ntos/rtl/i386/stkwalk.asm new file mode 100644 index 000000000..cf1ea134b --- /dev/null +++ b/private/ntos/rtl/i386/stkwalk.asm @@ -0,0 +1,221 @@ + TITLE "Capture Stack Back Trace" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; getcalr.s +; +; Abstract: +; +; This module implements the routine RtlCaptureStackBackTrace. It will +; walker the stack back trace and capture a portion of it. +; +; Author: +; +; Steve Wood (stevewo) 29-Jan-1992 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +IFDEF NTOS_KERNEL_RUNTIME + EXTRNP _MmIsAddressValid,1 + EXTRNP _KeGetCurrentIrql,0,IMPORT +ENDIF + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "RtlCaptureStackBackTrace" +;++ +; +; USHORT +; RtlCaptureStackBackTrace( +; IN ULONG FramesToSkip, +; IN ULONG FramesToCapture, +; OUT PVOID *BackTrace, +; OUT PULONG BackTraceHash +; ) +; +; Routine Description: +; +; This routine walks up the stack frames, capturing the return address from +; each frame requested. +; +; +; Arguments: +; +; OUT PVOID BackTrace (eps+0x10) - Returns the caller of the caller. +; +; +; Return Value: +; +; Number of return addresses returned in the BackTrace buffer. +; +; +;-- +RcbtFramesToSkip EQU [ebp+08h] +RcbtFramesToCapture EQU [ebp+0Ch] +RcbtBackTrace EQU [ebp+010h] +RcbtBackTraceHash EQU [ebp+014h] + +IFDEF NTOS_KERNEL_RUNTIME +RcbtInitialStack EQU [ebp-10h] +ENDIF + +cPublicProc _RtlCaptureStackBackTrace ,4 +IFDEF NTOS_KERNEL_RUNTIME +IF FPO + xor eax,eax + stdRET _RtlCaptureStackBackTrace +ENDIF + push ebp + mov ebp, esp + push ebx ; Save EBX + push esi ; Save ESI + push edi ; Save EDI + mov eax, PCR[PcPrcbData+PbCurrentThread] ; (eax)->current thread + push ThInitialStack[eax] ; RcbtInitialStack = base of kernel stack + mov esi,RcbtBackTraceHash ; (ESI) -> where to accumulate hash sum + mov edi,RcbtBackTrace ; (EDI) -> where to put backtrace + mov edx,ebp ; (EDX) = current frame pointer + mov ecx,RcbtFramesToSkip ; (ECX) = number of frames to skip + jecxz RcbtSkipLoopDone ; Done if nothing to skip +RcbtSkipLoop: + mov edx,[edx] ; (EDX) = next frame pointer + cmp edx,ebp ; If outside stack limits, + jbe RcbtCheckSkipU ; ...then exit + cmp edx,RcbtInitialStack + jae RcbtCheckSkipU + loop RcbtSkipLoop +RcbtSkipLoopDone: + mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture + jecxz RcbtExit ; Bail out if nothing to capture +RcbtCaptureLoop: + mov eax,[edx].4 ; Get next return address + stosd ; Store it in the callers buffer + add [esi],eax ; Accumulate hash sum + mov edx,[edx] ; (EDX) = next frame pointer + cmp edx,ebp ; If outside stack limits, + jbe RcbtCheckCaptureU ; ...then exit + cmp edx,RcbtInitialStack + jae RcbtCheckCaptureU + loop RcbtCaptureLoop ; Otherwise get next frame +RcbtExit: + mov eax,edi ; (EAX) -> next unused dword in buffer + sub eax,RcbtBackTrace ; (EAX) = number of bytes stored + shr eax,2 ; (EAX) = number of dwords stored + pop edi ; discard RcbtInitialStack + pop edi ; Restore EDI + pop esi ; Restore ESI + pop ebx ; Restore EBX + pop ebp + stdRET _RtlCaptureStackBackTrace + +RcbtCheckSkipU: + stdCall _KeGetCurrentIrql ; (al) = CurrentIrql + cmp al, 0 ; Bail out if not at IRQL 0 + ja RcbtExit + mov ebx, PCR[PcPrcbData+PbCurrentThread] ; (ebx)->current thread + cmp byte ptr ThApcStateIndex[ebx],1 ; Bail out if attached. + je RcbtExit + mov ebx, ThTeb[ebx] ; (EBX) -> User mode TEB + or ebx, ebx + jnz @F + jmp short RcbtExit +RcbtSkipLoopU: + mov edx,[edx] ; (EDX) = next frame pointer +@@: + cmp edx,PcStackLimit[ebx] ; If outside stack limits, + jbe RcbtExit ; ...then exit + cmp edx,PcInitialStack[ebx] + jae RcbtExit + loop RcbtSkipLoopU + mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture + jecxz RcbtExit ; Bail out if nothing to capture +RcbtCaptureLoopU: + mov eax,[edx].4 ; Get next return address + stosd ; Store it in the callers buffer + add [esi],eax ; Accumulate hash sum + mov edx,[edx] ; (EDX) = next frame pointer +@@: + cmp edx,PcStackLimit[ebx] ; If outside stack limits, + jbe RcbtExit ; ...then exit + cmp edx,PcInitialStack[ebx] + jae RcbtExit + loop RcbtCaptureLoopU ; Otherwise get next frame + jmp short RcbtExit + +RcbtCheckCaptureU: + stdCall _KeGetCurrentIrql ; (al) = CurrentIrql + cmp al, 0 ; Bail out if not at IRQL 0 + ja RcbtExit + mov ebx, PCR[PcPrcbData+PbCurrentThread] ; (ebx)->current thread + cmp byte ptr ThApcStateIndex[ebx],1 ; Bail out if attached. + je RcbtExit + mov ebx, ThTeb[ebx] ; (EBX) -> User mode TEB + or ebx, ebx + jnz @B + jmp RcbtExit ; Bail out if TEB == NULL + +ELSE +; +; This is defined always for user mode code, although it can be +; unreliable if called from code compiled with FPO enabled. +; + push ebp + mov ebp, esp + push esi ; Save ESI + push edi ; Save EDI + mov esi,RcbtBackTraceHash ; (ESI) -> where to accumulate hash sum + mov edi,RcbtBackTrace ; (EDI) -> where to put backtrace + mov edx,ebp ; (EDX) = current frame pointer + mov ecx,RcbtFramesToSkip ; (ECX) = number of frames to skip + jecxz RcbtSkipLoopDone ; Done if nothing to skip +RcbtSkipLoop: + mov edx,[edx] ; (EDX) = next frame pointer + cmp edx,fs:PcStackLimit ; If outside stack limits, + jbe RcbtExit ; ...then exit + cmp edx,fs:PcInitialStack + jae RcbtExit + loop RcbtSkipLoop +RcbtSkipLoopDone: + mov ecx,RcbtFramesToCapture ; (ECX) = number of frames to capture + jecxz RcbtExit ; Bail out if nothing to capture +RcbtCaptureLoop: + mov eax,[edx].4 ; Get next return address + stosd ; Store it in the callers buffer + add [esi],eax ; Accumulate hash sum + mov edx,[edx] ; (EDX) = next frame pointer + cmp edx,fs:PcStackLimit ; If outside stack limits, + jbe RcbtExit ; ...then exit + cmp edx,fs:PcInitialStack + jae RcbtExit + loop RcbtCaptureLoop ; Otherwise get next frame +RcbtExit: + mov eax,edi ; (EAX) -> next unused dword in buffer + sub eax,RcbtBackTrace ; (EAX) = number of bytes stored + shr eax,2 ; (EAX) = number of dwords stored + pop edi ; Restore EDI + pop esi ; Restore ESI + pop ebp + stdRET _RtlCaptureStackBackTrace +ENDIF + +stdENDP _RtlCaptureStackBackTrace + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/stringsp.asm b/private/ntos/rtl/i386/stringsp.asm new file mode 100644 index 000000000..e722f1808 --- /dev/null +++ b/private/ntos/rtl/i386/stringsp.asm @@ -0,0 +1,175 @@ + TITLE "String support routines" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; stringsup.asm +; +; Abstract: +; +; This module implements suplimentary routines for performing string +; operations. +; +; Author: +; +; Larry Osterman (larryo) 18-Sep-1991 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- + +.386p + +include callconv.inc ; calling convention macros + + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "RtlInitAnsiString" +;++ +; +; VOID +; RtlInitAnsiString( +; OUT PANSI_STRING DestinationString, +; IN PSZ SourceString OPTIONAL +; ) +; +; +; Routine Description: +; +; The RtlInitAnsiString function initializes an NT counted string. +; The DestinationString is initialized to point to the SourceString +; and the Length and MaximumLength fields of DestinationString are +; initialized to the length of the SourceString, which is zero if +; SourceString is not specified. +; +; Arguments: +; +; (TOS+4) = DestinationString - Pointer to the counted string to initialize +; +; (TOS+8) = SourceString - Optional pointer to a null terminated string that +; the counted string is to point to. +; +; +; Return Value: +; +; None. +; +; NOTE: +; This routine assumes that the string is less than 64K in size. +; +;-- + +cPublicProc _RtlInitString ,2 +cPublicFpo 2,2 + push edi + mov edi,[esp]+8+4 ; (edi)= SourceString + mov edx,[esp]+4+4 ; (esi)= DestinationString + mov DWORD PTR [edx], 0 ; (Destination).Length = (Destination).MaximumLength = 0 + mov DWORD PTR [edx]+4, edi ; (Destination).Buffer = 0 + or edi, edi + jz @f + or ecx, -1 + xor eax, eax + repne scasb + not ecx + mov [edx]+2, cx ; Save maximum length + dec ecx + mov [edx], cx ; Save length +@@: pop edi + stdRET _RtlInitString + +stdENDP _RtlInitString + + +cPublicProc _RtlInitAnsiString ,2 +cPublicFpo 2,2 + push edi + mov edi,[esp]+8+4 ; (edi)= SourceString + mov edx,[esp]+4+4 ; (esi)= DestinationString + mov DWORD PTR [edx], 0 ; (Destination).Length = (Destination).MaximumLength = 0 + mov DWORD PTR [edx]+4, edi ; (Destination).Buffer = 0 + or edi, edi + jz @f + or ecx, -1 + xor eax, eax + repne scasb + not ecx + mov [edx]+2, cx ; Save maximum length + dec ecx + mov [edx], cx ; Save length +@@: pop edi + stdRET _RtlInitAnsiString + +stdENDP _RtlInitAnsiString + + + page + subttl "RtlInitAnsiString" +;++ +; +; VOID +; RtlInitAnsiString( +; OUT PANSI_STRING DestinationString, +; IN PSZ SourceString OPTIONAL +; ) +; +; +; Routine Description: +; +; The RtlInitUnicodeString function initializes an NT counted string. +; The DestinationString is initialized to point to the SourceString +; and the Length and MaximumLength fields of DestinationString are +; initialized to the length of the SourceString, which is zero if +; SourceString is not specified. +; +; Arguments: +; +; (TOS+4) = DestinationString - Pointer to the counted string to initialize +; +; (TOS+8) = SourceString - Optional pointer to a null terminated string that +; the counted string is to point to. +; +; +; Return Value: +; +; None. +; +; NOTE: +; This routine assumes that the string is less than 64K in size. +; +;-- + +cPublicProc _RtlInitUnicodeString ,2 +cPublicFpo 2,2 + push edi + mov edi,[esp]+8+4 ; (edi)= SourceString + mov edx,[esp]+4+4 ; (esi)= DestinationString + mov DWORD PTR [edx], 0 ; (Destination).Length = (Destination).MaximumLength = 0 + mov DWORD PTR [edx]+4, edi ; (Destination).Buffer = 0 + or edi, edi + jz @f + or ecx, -1 + xor eax, eax + repne scasw + not ecx + shl ecx,1 + mov [edx]+2, cx ; Save maximum length + dec ecx + dec ecx + mov [edx], cx ; Save length +@@: pop edi + stdRET _RtlInitUnicodeString + +stdENDP _RtlInitUnicodeString + +_TEXT ends + end diff --git a/private/ntos/rtl/i386/userdisp.asm b/private/ntos/rtl/i386/userdisp.asm new file mode 100644 index 000000000..88871f0ee --- /dev/null +++ b/private/ntos/rtl/i386/userdisp.asm @@ -0,0 +1,324 @@ + title "User Mode Dispatcher Code" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; userdisp.asm +; +; Abstract: +; +; The module contains procedures to do user mode dispatching +; ("trampolining") of user apcs and user exceptions. +; +; Author: +; +; Bryan M Willman (bryanwi) 31-Aug-90 +; +; Environment: +; +; User mode. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +ifndef WX86_i386 + EXTRNP _ZwCallbackReturn,3 +endif + + EXTRNP _ZwContinue,2 + EXTRNP _RtlDispatchException,2 + EXTRNP _RtlRaiseStatus,1 + EXTRNP _ZwRaiseException,3 + EXTRNP _RtlRaiseException,1 +; +; Exception record size definition. +; + +ExceptionRecordSize = (ErNumberParameters + 4 + 3) AND 0fffffffcH ; + + page ,132 +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +ifndef WX86_i386 + page + subttl "User APC Dispatcher" +;++ +; +; VOID +; KiUserApcDispatcher ( +; IN PKNORMAL_ROUTINE NormalRoutine, +; IN PVOID NormalContext, +; IN PVOID SystemArgument1, +; IN PVOID SystemArgument2, +; IN CONTEXT ContinueContext +; ) +; +; Routine Description: +; +; This routine is entered on return from kernel mode to deliver an APC +; in user mode. The context frame for this routine was built when the +; APC interrupt was processed and contains the entire machine state of +; the current thread. The specified APC routine is called and then the +; machine state is restored and execution is continued. +; +; Arguments: +; +; NormalRoutine - Supplies that address of the function that is to be called. +; +; NormalContext] - Supplies the normal context parameter that was specified +; when the APC was initialized. +; +; SystemArgument1 - Supplies the first argument that was provied by the +; executive when the APC was queued. +; +; SystemArgument2 - Supplies the second argument that was provided by +; the executive when the APC was queued. +; +; ContinueContext - Context record to pass to Continue call. +; +; +; Return Value: +; +; None. +; +;-- +cPublicProc _KiUserApcDispatcher ,5 + + lea edi, [esp+16] ; (edi)->context frame + pop eax ; (eax)->specified function + call eax ; call the specified function + +; 1 - set alert argument true +; ebp - addr of context frame +; execute system service to continue + stdCall _ZwContinue, <edi, 1> + +stdENDP _KiUserApcDispatcher + + + page + subttl "User Callback Dispatcher" +;++ +; +; VOID +; KiUserCallbackDispatcher ( +; IN ULONG ApiNumber, +; IN PVOID InputBuffer, +; IN ULONG INputLength +; ) +; +; Routine Description: +; +; This routine is entered on a callout from kernel mode to execute a +; user mode callback function. All arguments for this function have +; been placed on the stack. +; +; Arguments: +; +; ApiNumber - Supplies the API number of the callback function that is +; executed. +; +; InputBuffer - Supplies a pointer to the input buffer. +; +; InputLength - Supplies the input buffer length. +; +; Return Value: +; +; This function returns to kernel mode. +; +;-- +cPublicProc _KiUserCallbackDispatcher, 3 +.FPO (0, 0, 0, 0, 0, 0) + + add esp,4 ; skip over return address + pop edx ; get address of callback function + + ; get peb pointer from teb + mov eax,fs:[PcTeb] + mov eax,[eax].TebPeb + mov eax,[eax].PebKernelCallbackTable ; get address of callback table + + call [eax+edx*4] ; call specified function + +; +; If a return from the callback function occurs, then the output buffer +; address and length are returned as NULL. +; + + xor ecx,ecx ; clear output buffer address + xor edx,edx ; clear output buffer length + int 02bH ; return from callback + int 3 ; break if return occurs + +stdENDP _KiUserCallbackDispatcher + +endif ;; ndef WX86_i386 + + page + subttl "User Exception Dispatcher" +;++ +; +; VOID +; KiUserExceptionDispatcher ( +; IN PEXCEPTION_RECORD ExceptionRecord, +; IN PCONTEXT ContextRecord +; ) +; +; Routine Description: +; +; This routine is entered on return from kernel mode to dispatch a user +; mode exception. If a frame based handler handles the exception, then +; the execution is continued. Else last chance processing is performed. +; +; NOTE: This procedure is not called, but rather dispatched to. +; It depends on there not being a return address on the stack +; (assumption w.r.t. argument offsets.) +; +; Arguments: +; +; ExceptionRecord (esp+0) - Supplies a pointer to an exception record. +; +; ContextRecord (esp+4) - Supplies a pointer to a context frame. +; +; Return Value: +; +; None. +; +;-- + +cPublicProc _KiUserExceptionDispatcher ,2 +.FPO (0, 2, 0, 0, 0, 0) + + mov ecx, [esp+4] ; (ecx)->context record + mov ebx, [esp] ; (ebx)->exception record + +; attempt to dispatch the exception + stdCall _RtlDispatchException, <ebx, ecx> + +; +; If the return status is TRUE, then the exception was handled and execution +; should be continued with the NtContinue service in case the context was +; changed. If the return statusn is FALSE, then the exception was not handled +; and ZwRaiseException is called to perform last chance exception processing. +; + + or al,al + je short kued10 + +; +; Continue execution. +; + + pop ebx ; (ebx)->exception record + pop ecx ; (ecx)->context record + +; continue execution + stdCall _ZwContinue, <ecx, 0> + jmp short kued20 ; join common code + +; +; Last chance processing. +; +; (esp+0) = ExceptionRecord +; (esp+4) = ContextRecord +; + +kued10: pop ebx ; (ebx)->exception record + pop ecx ; (ecx)->context record + +; ecx - context record +; ebx - exception record +; perform last chance processiong + stdCall _ZwRaiseException, <ebx, ecx, 0> + +; +; Common code for nonsuccessful completion of the continue or raiseexception +; services. Use the return status as the exception code, set noncontinuable +; exception and attempt to raise another exception. Note the stack grows +; and eventually this loop will end. +; + +.FPO(0, 0, 0, 0, 0, 0) + +kued20: add esp, -ExceptionRecordSize ; allocate stack space + mov [esp]+ErExceptionCode, eax ; set exception code + mov dword ptr [esp]+ErExceptionFlags, EXCEPTION_NONCONTINUABLE + mov [esp]+ErExceptionRecord,ebx ; set associated exception record + mov dword ptr [esp]+ErNumberParameters, 0 + ; set number of parameters +; esp - addr of exception record + stdCall _RtlRaiseException, <esp> +; never return + stdRET _KiUserExceptionDispatcher + +stdENDP _KiUserExceptionDispatcher + + page + subttl "Raise User Exception Dispatcher" +ifndef WX86_i386 +;++ +; +; NTSTATUS +; KiUserExceptionDispatcher ( +; IN PVOID ReturnAddress +; IN NTSTATUS ExceptionCode +; ) +; +; Routine Description: +; +; This routine is entered on return from kernel mode to raise a user +; mode exception. +; +; NOTE: This procedure is not called, but rather dispatched to. +; +; The address this routine must return to is passed in EAX. +; The exception code to be raised is passed in the TEB. +; +; Arguments: +; +; ReturnAddress (eax) - Supplies the address to return to +; +; ExceptionCode (TEB->ExceptionCode) - Supplies the exception code to be raised +; +; Return Value: +; +; The exception code that was raised. +; +;-- + +cPublicProc _KiRaiseUserExceptionDispatcher + + push eax ; push address to return to + push ebp ; make the debugger happy + mov ebp, esp + sub esp, ExceptionRecordLength ; allocate exception record + mov [esp].ErExceptionAddress, eax ; set exception address + mov eax,fs:[PcTeb] ; get exception code to be raised + mov eax,[eax].TbExceptionCode ; + mov [esp].ErExceptionCode, eax ; store exception code + mov [esp].ErExceptionFlags, 0 ; set exception flags + mov [esp].ErExceptionRecord, 0 ; set exception record + mov [esp].ErNumberParameters, 0 ; set number of parameters +; raise the exception + stdCall _RtlRaiseException, <esp> + mov eax, [esp].ErExceptionCode + mov esp,ebp + pop ebp ; restore return code + ret + +stdENDP _KiRaiseUserExceptionDispatcher +endif ;; ndef WX86_i386 + + +_TEXT ENDS + + END diff --git a/private/ntos/rtl/i386/xcptmisc.asm b/private/ntos/rtl/i386/xcptmisc.asm new file mode 100644 index 000000000..c4c0489c8 --- /dev/null +++ b/private/ntos/rtl/i386/xcptmisc.asm @@ -0,0 +1,612 @@ + title "Miscellaneous Exception Handling" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; xcptmisc.asm +; +; Abstract: +; +; This module implements miscellaneous routines that are required to +; support exception handling. Functions are provided to call an exception +; handler for an exception, call an exception handler for unwinding, get +; the caller's stack pointer, get the caller's frame pointer, get the +; caller's floating status, get the caller's processor state, get the +; caller's extended processor status, and get the current stack limits. +; +; Author: +; +; David N. Cutler (davec) 14-Aug-1989 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +; 6 April 90 bryanwi +; +; 386 version created +; +;-- +.386p + + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + +; +; Unwind flags. +; + +Unwind equ EXCEPTION_UNWINDING OR EXCEPTION_EXIT_UNWIND + +_TEXT$01 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page + subttl "Execute Handler for Exception" +;++ +; +; EXCEPTION_DISPOSITION +; RtlpExecuteHandlerForException ( +; IN PEXCEPTION_RECORD ExceptionRecord, +; IN PVOID EstablisherFrame, +; IN OUT PCONTEXT ContextRecord, +; IN OUT PVOID DispatcherContext, +; IN PEXCEPTION_ROUTINE ExceptionRoutine +; ) +; +; Routine Description: +; +; This function allocates a call frame, stores the handler address and +; establisher frame pointer in the frame, establishes an exception +; handler, and then calls the specified exception handler as an exception +; handler. If a nested exception occurs, then the exception handler of +; of this function is called and the handler address and establisher +; frame pointer are returned to the exception dispatcher via the dispatcher +; context parameter. If control is returned to this routine, then the +; frame is deallocated and the disposition status is returned to the +; exception dispatcher. +; +; Arguments: +; +; ExceptionRecord (ebp+8) - Supplies a pointer to an exception record. +; +; EstablisherFrame (ebp+12) - Supplies the frame pointer of the establisher +; of the exception handler that is to be called. +; +; ContextRecord (ebp+16) - Supplies a pointer to a context record. +; +; DispatcherContext (ebp+20) - Supplies a pointer to the dispatcher context +; record. +; +; ExceptionRoutine (ebp+24) - supplies a pointer to the exception handler +; that is to be called. +; +; Return Value: +; +; The disposition value returned by the specified exception handler is +; returned as the function value. +; +;-- + +cPublicProc _RtlpExecuteHandlerForException,5 + + mov edx,offset FLAT:ExceptionHandler ; Set who to register + jmp ExecuteHandler ; jump to common code + +stdENDP _RtlpExecuteHandlerForException + + + page + subttl "Execute Handler for Unwind" +;++ +; +; EXCEPTION_DISPOSITION +; RtlpExecuteHandlerForUnwind ( +; IN PEXCEPTION_RECORD ExceptionRecord, +; IN PVOID EstablisherFrame, +; IN OUT PCONTEXT ContextRecord, +; IN OUT PVOID DispatcherContext, +; IN PEXCEPTION_ROUTINE ExceptionRoutine +; ) +; +; Routine Description: +; +; This function allocates a call frame, stores the handler address and +; establisher frame pointer in the frame, establishes an exception +; handler, and then calls the specified exception handler as an unwind +; handler. If a collided unwind occurs, then the exception handler of +; of this function is called and the handler address and establisher +; frame pointer are returned to the unwind dispatcher via the dispatcher +; context parameter. If control is returned to this routine, then the +; frame is deallocated and the disposition status is returned to the +; unwind dispatcher. +; +; Arguments: +; +; ExceptionRecord (ebp+8) - Supplies a pointer to an exception record. +; +; EstablisherFrame (ebp+12) - Supplies the frame pointer of the establisher +; of the exception handler that is to be called. +; +; ContextRecord (ebp+16) - Supplies a pointer to a context record. +; +; DispatcherContext (ebp+20) - Supplies a pointer to the dispatcher context +; record. +; +; ExceptionRoutine (ebp+24) - supplies a pointer to the exception handler +; that is to be called. +; +; Return Value: +; +; The disposition value returned by the specified exception handler is +; returned as the function value. +; +;-- + +cPublicProc _RtlpExecuteHandlerForUnwind ,5 + + mov edx,offset FLAT:UnwindHandler + +;; N.B. - FALL into ExecuteHandler + +stdENDP _RtlpExecuteHandlerForUnwind + + + +; +; ExecuteHandler is the common tail for RtlpExecuteHandlerForException +; and RtlpExecuteHandlerForUnwind. +; +; (edx) = handler (Exception or Unwind) address +; + + +ExceptionRecord equ [ebp+8] +EstablisherFrame equ [ebp+12] +ContextRecord equ [ebp+16] +DispatcherContext equ [ebp+20] +ExceptionRoutine equ [ebp+24] + + +cPublicProc ExecuteHandler,5 + + push ebp + mov ebp,esp + + push EstablisherFrame ; Save context of exception handler + ; that we're about to call. + + .errnz ErrHandler-4 + push edx ; Set Handler address + + .errnz ErrNext-0 + push fs:PcExceptionList ; Set next pointer + + + mov fs:PcExceptionList,esp ; Link us on + +; Call the specified exception handler. + + push DispatcherContext + push ContextRecord + push EstablisherFrame + push ExceptionRecord + + mov ecx,ExceptionRoutine + call ecx + mov esp,fs:PcExceptionList + +; Don't clean stack here, code in front of ret will blow it off anyway + +; Disposition is in eax, so all we do is deregister handler and return + + .errnz ErrNext-0 + pop fs:PcExceptionList + + mov esp,ebp + pop ebp + stdRET ExecuteHandler + +stdENDP ExecuteHandler + + page + subttl "Local Exception Handler" +;++ +; +; EXCEPTION_DISPOSITION +; ExceptionHandler ( +; IN PEXCEPTION_RECORD ExceptionRecord, +; IN PVOID EstablisherFrame, +; IN OUT PCONTEXT ContextRecord, +; IN OUT PVOID DispatcherContext +; ) +; +; Routine Description: +; +; This function is called when a nested exception occurs. Its function +; is to retrieve the establisher frame pointer and handler address from +; its establisher's call frame, store this information in the dispatcher +; context record, and return a disposition value of nested exception. +; +; Arguments: +; +; ExceptionRecord (exp+4) - Supplies a pointer to an exception record. +; +; EstablisherFrame (esp+8) - Supplies the frame pointer of the establisher +; of this exception handler. +; +; ContextRecord (esp+12) - Supplies a pointer to a context record. +; +; DispatcherContext (esp+16) - Supplies a pointer to the dispatcher context +; record. +; +; Return Value: +; +; A disposition value ExceptionNestedException is returned if an unwind +; is not in progress. Otherwise a value of ExceptionContinueSearch is +; returned. +; +;-- + +stdPROC ExceptionHandler,4 + + mov ecx,dword ptr [esp+4] ; (ecx) -> ExceptionRecord + test dword ptr [ecx.ErExceptionFlags],Unwind + mov eax,ExceptionContinueSearch ; Assume unwind + jnz eh10 ; unwind, go return + +; +; Unwind is not in progress - return nested exception disposition. +; + + mov ecx,[esp+8] ; (ecx) -> EstablisherFrame + mov edx,[esp+16] ; (edx) -> DispatcherContext + mov eax,[ecx+8] ; (eax) -> EstablisherFrame for the + ; handler active when we + ; nested. + mov [edx],eax ; Set DispatcherContext field. + mov eax,ExceptionNestedException + +eh10: stdRET ExceptionHandler + +stdENDP ExceptionHandler + + page + subttl "Local Unwind Handler" +;++ +; +; EXCEPTION_DISPOSITION +; UnwindHandler ( +; IN PEXCEPTION_RECORD ExceptionRecord, +; IN PVOID EstablisherFrame, +; IN OUT PCONTEXT ContextRecord, +; IN OUT PVOID DispatcherContext +; ) +; +; Routine Description: +; +; This function is called when a collided unwind occurs. Its function +; is to retrieve the establisher frame pointer and handler address from +; its establisher's call frame, store this information in the dispatcher +; context record, and return a disposition value of nested unwind. +; +; Arguments: +; +; ExceptionRecord (esp+4) - Supplies a pointer to an exception record. +; +; EstablisherFrame (esp+8) - Supplies the frame pointer of the establisher +; of this exception handler. +; +; ContextRecord (esp+12) - Supplies a pointer to a context record. +; +; DispatcherContext (esp+16) - Supplies a pointer to the dispatcher context +; record. +; +; Return Value: +; +; A disposition value ExceptionCollidedUnwind is returned if an unwind is +; in progress. Otherwise a value of ExceptionContinueSearch is returned. +; +;-- + +stdPROC UnwindHandler,4 + + mov ecx,dword ptr [esp+4] ; (ecx) -> ExceptionRecord + test dword ptr [ecx.ErExceptionFlags],Unwind + mov eax,ExceptionContinueSearch ; Assume NOT unwind + jz uh10 ; not unwind, go return + + +; +; Unwind is in progress - return collided unwind disposition. +; + + mov ecx,[esp+8] ; (ecx) -> EstablisherFrame + mov edx,[esp+16] ; (edx) -> DispatcherContext + mov eax,[ecx+8] ; (eax) -> EstablisherFrame for the + ; handler active when we + ; nested. + mov [edx],eax ; Set DispatcherContext field. + mov eax,ExceptionCollidedUnwind + +uh10: stdRET UnwindHandler + +stdENDP UnwindHandler + + page + subttl "Unlink Exception Registration Record & Handler" +;++ +; +; VOID +; RtlpUnlinkHandler(PEXCEPTION_REGISTRATION_RECORD UnlinkPointer) +; +; Routine Description: +; +; This function removes the specified exception registration record +; (and thus the relevent handler) from the exception traversal +; chain. +; +; Arguments: +; +; UnlinkPointer (esp+4) - Address of registration record to unlink. +; +; Return Value: +; +; The caller's return address. +; +;-- + +cPublicProc _RtlpUnlinkHandler ,1 + + mov ecx,dword ptr [esp+4] + mov ecx,[ecx.ErrNext] + mov fs:PcExceptionList,ecx + stdRET _RtlpUnlinkHandler + +stdENDP _RtlpUnlinkHandler + + page + subttl "Capture Context" +;++ +; +; VOID +; RtlCaptureContext (PCONTEXT ContextRecord) +; RtlpCaptureContext (PCONTEXT ContextRecord) +; +; Routine Description: +; +; This fucntion fills in the specified context record with the +; current state of the machine, except that the values of EBP +; and ESP are computed to be those of the caller's caller. +; +; N.B. This function assumes it is called from a 'C' procedure with +; the old ebp at [ebp], the return address at [ebp+4], and +; old esp = ebp + 8. +; +; Certain 'C' optimizations may cause this to not be true. +; +; N.B. This function does NOT adjust ESP to pop the arguments off +; the caller's stack. In other words, it provides a __cdecl ESP, +; NOT a __stdcall ESP. This is mainly because we can't figure +; out how many arguments the caller takes. +; +; N.B. Floating point state is NOT captured. +; +; RtlpCaptureContext does not capture volitales. +; RtlCaptureContext captures volitales. +; +; Arguments: +; +; ContextRecord (esp+4) - Address of context record to fill in. +; +; Return Value: +; +; The caller's return address. +; +;-- + +cPublicProc _RtlCaptureContext ,1 + + push ebx + mov ebx,[esp+8] ; (ebx) -> ContextRecord + + mov dword ptr [ebx.CsEax],eax + mov dword ptr [ebx.CsEcx],ecx + mov dword ptr [ebx.CsEdx],edx + mov eax, [esp] + mov dword ptr [ebx.CsEbx],eax + + mov dword ptr [ebx.CsEsi],esi + mov dword ptr [ebx.CsEdi],edi + jmp RtlpCaptureCommon +stdENDP _RtlCaptureContext + +cPublicProc _RtlpCaptureContext ,1 + + push ebx + mov ebx,[esp+8] ; (ebx) -> ContextRecord + + mov dword ptr [ebx.CsEax],0 + mov dword ptr [ebx.CsEcx],0 + mov dword ptr [ebx.CsEdx],0 + mov dword ptr [ebx.CsEbx],0 + + mov dword ptr [ebx.CsEsi],0 + mov dword ptr [ebx.CsEdi],0 + +RtlpCaptureCommon: + mov [ebx.CsSegCs],cs + mov [ebx.CsSegDs],ds + mov [ebx.CsSegEs],es + mov [ebx.CsSegFs],fs + mov [ebx.CsSegGs],gs + mov [ebx.CsSegSs],ss + + pushfd + pop [ebx.CsEflags] + + mov eax,[ebp+4] + mov [ebx.CsEip],eax + + mov eax,[ebp] + mov [ebx.CsEbp],eax + + lea eax,[ebp+8] + mov [ebx.CsEsp],eax + + pop ebx + stdRET _RtlpCaptureContext + +stdENDP _RtlpCaptureContext + + page + subttl "Capture Context (private)" +;++ +; +; VOID +; RtlCaptureContext (PCONTEXT ContextRecord) +; +; Routine Description: +; +; This function is similiar too RtlpCaptureContext expect that +; volitales are captured as well. +; +; This fucntion fills in the specified context record with the +; current state of the machine, except that the values of EBP +; and ESP are computed to be those of the caller's caller. +; +; N.B. This function does NOT adjust ESP to pop the arguments off +; the caller's stack. In other words, it provides a __cdecl ESP, +; NOT a __stdcall ESP. This is mainly because we can't figure +; out how many arguments the caller takes. +; +; N.B. Floating point state is NOT captured. +; +; Arguments: +; +; ContextRecord (esp+4) - Address of context record to fill in. +; +; Return Value: +; +; The caller's return address. +; +;-- + + +ifndef WX86_i386 + page + subttl "Get Stack Limits" +;++ +; +; VOID +; RtlpGetStackLimits ( +; OUT PULONG LowLimit, +; OUT PULONG HighLimit +; ) +; +; Routine Description: +; +; This function returns the current stack limits based on the current +; processor mode. +; +; On the 386 we always store the stack limits in the PCR, and address +; both PCR and TEB the same way, so this code is mode independent. +; +; Arguments: +; +; LowLimit (esp+4) - Supplies a pointer to a variable that is to receive +; the low limit of the stack. +; +; HighLimit (esp+8) - Supplies a pointer to a variable that is to receive +; the high limit of the stack. +; +; Return Value: +; +; None. +; +;-- + +cPublicProc _RtlpGetStackLimits ,2 +;cPublicFpo 2,0 + + mov eax,fs:PcStackLimit + mov ecx,[esp+4] + mov [ecx],eax ; Save low limit + + mov eax,fs:PcInitialStack + mov ecx,[esp+8] + mov [ecx],eax ; Save high limit + + stdRET _RtlpGetStackLimits + +stdENDP _RtlpGetStackLimits + +endif + page + subttl "Get Exception Registration List Head" +;++ +; +; PVOID +; RtlpGetRegistrationHead() +; +; Routine Description: +; +; This function returns the address of the first Exception +; registration record for the current context. +; +; Arguments: +; +; None. +; +; Return Value: +; +; The address of the first registration record. +; +;-- + +cPublicProc _RtlpGetRegistrationHead ,0 +;cPublicFpo 0,0 + + mov eax,fs:PcExceptionList + stdRET _RtlpGetRegistrationHead + +stdENDP _RtlpGetRegistrationHead + + page + subttl "Get Return Address" +;++ +; +; PVOID +; RtlpGetReturnAddress() +; +; Routine Description: +; +; This function returns the caller's return address. It assumes +; that a standard 'C' entry sequence has been used, be warned +; that certain optimizations might invalidate that assumption. +; +; Arguments: +; +; None. +; +; Return Value: +; +; The address of the first registration record. +; +;-- + +cPublicProc _RtlpGetReturnAddress ,0 +;cPublicFpo 0,0 + + mov eax,[ebp+4] + stdRET _RtlpGetReturnAddress + +stdENDP _RtlpGetReturnAddress +_TEXT$01 ends + end |