/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    thredini.c

Abstract:

    This module implements the machine dependent function to set the initial
    context and data alignment handling mode for a process or thread object.

Author:

    David N. Cutler (davec) 31-Mar-1990

Environment:

    Kernel mode only.

Revision History:

    3 April 90  bryan willman

        This version ported to 386.

--*/

#include "ki.h"

VOID
KiInitializeContextThread (
    IN PKTHREAD Thread,
    IN SIZE_T TlsDataSize,
    IN PKSYSTEM_ROUTINE SystemRoutine,
    IN PKSTART_ROUTINE StartRoutine OPTIONAL,
    IN PVOID StartContext OPTIONAL
    )

/*++

Routine Description:

    This function initializes the machine dependent context of a thread object.

Arguments:

    Thread - Supplies a pointer to a dispatcher object of type thread.

    TlsDataSize - Supplies the number of bytes reserved from the kernel stack
        for thread local storage.

    SystemRoutine - Supplies a pointer to the system function that is to be
        called when the thread is first scheduled for execution.

    StartRoutine - Supplies an optional pointer to a function that is to be
        called after the system has finished initializing the thread. This
        parameter is specified if the thread is a system thread and will
        execute totally in kernel mode.

    StartContext - Supplies an optional pointer to an arbitrary data structure
        which will be passed to the StartRoutine as a parameter. This
        parameter is specified if the thread is a system thread and will
        execute totally in kernel mode.

Return Value:

    None.

--*/

{
    PFX_SAVE_AREA NpxFrame;
    PVOID TlsData;
    PKSWITCHFRAME SwitchFrame;
    PULONG PSystemRoutine;
    PULONG PStartRoutine;
    PULONG PStartContext;

    //
    // Load up an initial NPX state.
    //

    NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->StackBase) -
                sizeof(FX_SAVE_AREA)));

    RtlZeroMemory((PVOID)NpxFrame, sizeof(FX_SAVE_AREA));

    NpxFrame->FloatSave.ControlWord = 0x27f;     //like fpinit but 64bit mode
    NpxFrame->FloatSave.MXCsr       = 0x1f80;    // mask all the exceptions

    //
    // Thread's NPX state is not in the coprocessor.
    //

    Thread->NpxState = NPX_STATE_NOT_LOADED;

    //
    // Zero the thread local storage area.
    //

    TlsDataSize = ALIGN_UP(TlsDataSize, ULONG);
    TlsData = ((PUCHAR)(ULONG)NpxFrame) - TlsDataSize;

    if (TlsDataSize != 0) {
        Thread->TlsData = TlsData;
        RtlZeroMemory(TlsData, TlsDataSize);
    } else {
        Thread->TlsData = NULL;
    }

    //
    // Space for arguments to KiThreadStartup.  Order of fields in the
    // switchframe is important, since args are passed on stack through
    // KiThreadStartup to PStartRoutine with PStartContext as an argument.
    //

    PStartContext = (PULONG)((ULONG)TlsData) - 1;
    PStartRoutine = PStartContext - 1;
    PSystemRoutine = PStartRoutine - 1;

    SwitchFrame = (PKSWITCHFRAME)((PUCHAR)PSystemRoutine - sizeof(KSWITCHFRAME));

    //
    // Set up thread start parameters.
    //

    *PStartContext = (ULONG)StartContext;
    *PStartRoutine = (ULONG)StartRoutine;
    *PSystemRoutine = (ULONG)SystemRoutine;

    //
    // Set up switch frame.
    //

    SwitchFrame->RetAddr = (ULONG)KiThreadStartup;

    SwitchFrame->Eflags = EFLAGS_INTERRUPT_MASK;

    SwitchFrame->ExceptionList = (ULONG)(EXCEPTION_CHAIN_END);

    //
    // Set the initial kernel stack pointer.
    //

    Thread->KernelStack = (PVOID)SwitchFrame;
    return;
}
