summaryrefslogtreecommitdiffstats
path: root/private/ntos/rtl/i386
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/rtl/i386')
-rw-r--r--private/ntos/rtl/i386/context.c263
-rw-r--r--private/ntos/rtl/i386/debug2.asm65
-rw-r--r--private/ntos/rtl/i386/debug3.c121
-rw-r--r--private/ntos/rtl/i386/divlarge.c124
-rw-r--r--private/ntos/rtl/i386/exdsptch.c535
-rw-r--r--private/ntos/rtl/i386/exsup.asm15
-rw-r--r--private/ntos/rtl/i386/forceres.asm23
-rw-r--r--private/ntos/rtl/i386/halvprnt.c407
-rw-r--r--private/ntos/rtl/i386/ioaccess.asm423
-rw-r--r--private/ntos/rtl/i386/largeint.asm855
-rw-r--r--private/ntos/rtl/i386/lzntx86.asm445
-rw-r--r--private/ntos/rtl/i386/movemem.asm659
-rw-r--r--private/ntos/rtl/i386/nlssup.asm146
-rw-r--r--private/ntos/rtl/i386/nlstrans.asm668
-rw-r--r--private/ntos/rtl/i386/ntcurteb.asm79
-rw-r--r--private/ntos/rtl/i386/ntrtl386.h70
-rw-r--r--private/ntos/rtl/i386/raise.asm181
-rw-r--r--private/ntos/rtl/i386/raisests.c65
-rw-r--r--private/ntos/rtl/i386/rtldump.c185
-rw-r--r--private/ntos/rtl/i386/stkwalk.asm221
-rw-r--r--private/ntos/rtl/i386/stringsp.asm175
-rw-r--r--private/ntos/rtl/i386/userdisp.asm324
-rw-r--r--private/ntos/rtl/i386/xcptmisc.asm612
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