336 lines
8.2 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
kernlini.c
Abstract:
This module contains the code to initialize the kernel data structures
and to initialize the idle thread, its process, and the processor control
block.
--*/
#include "ki.h"
VOID
KiSwapGDT (
VOID
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,KiSwapGDT)
#endif
#if DBG
const UCHAR MsgDpcTrashedEsp[] = "\n*** DPC routine %p trashed ESP\n";
const UCHAR MsgDpcFpuEnabled[] = "\n*** DPC routine %p returned with the FPU enabled\n";
const UCHAR MsgDpcTimeout[] = "\n*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n";
const UCHAR MsgISRTimeout[] = "\n*** ISR at %lx took over .5 second\n";
const UCHAR MsgISROverflow[] = "\n*** ISR at %lx - %d interrupts per .5 second\n";
ULONG KiDPCTimeout = 110;
ULONG KiISRTimeout = 55;
ULONG KiISROverflow = 5500;
#endif
extern KPCR KiPCR;
extern KTHREAD KiIdleThread;
extern UCHAR KiIdleThreadStackLimit[];
extern KGDTENTRY KiGDTEnd[];
extern KIDTENTRY KiIDTEnd[];
VOID
KiPreInitializeKernel(
VOID
)
/*++
Routine Description:
This function gains control before the kernel debugger has been initialized
in order to partially initialize static kernel data structures.
Arguments:
None.
Return Value:
None.
--*/
{
PKPCR Pcr;
Pcr = &KiPCR;
//
// Initialize the PCR. The stack base and limit are initialized in case we
// end up attempting to flush the NPX state before the KiInitializeKernel
// has completed initialization.
//
Pcr->SelfPcr = Pcr;
Pcr->Prcb = &Pcr->PrcbData;
Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
Pcr->NtTib.StackLimit = KiIdleThreadStackLimit;
Pcr->NtTib.StackBase = KiIdleThreadStackLimit + KERNEL_STACK_SIZE - sizeof(FX_SAVE_AREA);
Pcr->PrcbData.CurrentThread = &KiIdleThread;
//
// Mark the idle thread as not having a NPX state as well to further avoid
// attempting to flush the NPX state.
//
KiIdleThread.NpxState = NPX_STATE_NOT_LOADED;
KiIdleThread.StackLimit = KiIdleThreadStackLimit;
KiIdleThread.StackBase = KiIdleThreadStackLimit + KERNEL_STACK_SIZE;
}
VOID
KiInitializeKernel(
VOID
)
/*++
Routine Description:
This function gains control after the system has been bootstrapped and
before the system has been initialized. Its function is to initialize
the kernel data structures, initialize the idle thread and process objects,
initialize the processor control block, call the executive initialization
routine, and then return to the system startup routine. This routine is
also called to initialize the processor specific structures when a new
processor is brought on line.
Arguments:
None.
Return Value:
None.
--*/
{
PKPCR Pcr;
PKPRCB Prcb;
PFX_SAVE_AREA NpxFrame;
KIRQL OldIrql;
PVOID DpcStack;
Pcr = KeGetPcr();
Prcb = KeGetCurrentPrcb();
//
// Assert that NpxSaveArea is 16 byte aligned; KeSaveFloatingPointState will
// use the fxsave instruction with this buffer and the Intel architecture
// requires that the pointer be 16 byte aligned.
//
ASSERT((((ULONG_PTR)&Prcb->NpxSaveArea) % 16) == 0);
//
// Initialize DPC listhead and lock.
//
InitializeListHead(&Prcb->DpcListHead);
Prcb->DpcRoutineActive = 0;
//
// Lower IRQL to APC level.
//
KeLowerIrql(APC_LEVEL);
//
// Platform architecture independent initialization.
//
KiInitSystem();
//
// Initialize idle process object.
//
KeInitializeProcess(&KiIdleProcess, (KPRIORITY)0);
KiIdleProcess.ThreadQuantum = MAXCHAR;
//
// Initialize system process object.
//
KeInitializeProcess(&KiSystemProcess, NORMAL_BASE_PRIORITY);
KiSystemProcess.ThreadQuantum = THREAD_QUANTUM;
//
// Initialize idle thread object and then set:
//
// 1. the initial kernel stack to the specified idle stack.
// 2. the next processor number to the specified processor.
// 3. the thread priority to the highest possible value.
// 4. the state of the thread to running.
// 5. the thread affinity to the specified processor.
// 6. the specified processor member in the process active processors
// set.
//
KeInitializeThread(&KiIdleThread, KiIdleThreadStackLimit + KERNEL_STACK_SIZE,
KERNEL_STACK_SIZE, 0, (PKSYSTEM_ROUTINE)NULL,
(PKSTART_ROUTINE)NULL, (PVOID)NULL, &KiIdleProcess);
KiIdleThread.Priority = HIGH_PRIORITY;
KiIdleThread.State = Running;
KiIdleThread.WaitIrql = DISPATCH_LEVEL;
//
// Initialize the idle thread's NPX state to the same state used for normal
// threads.
//
NpxFrame = (PFX_SAVE_AREA)(((ULONG)(KiIdleThread.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
//
// Initialize the processor block. (Note that some fields have been
// initialized at KiPreInitializeKernel).
//
Prcb->CurrentThread = &KiIdleThread;
Prcb->NextThread = (PKTHREAD)NULL;
Prcb->IdleThread = &KiIdleThread;
Pcr->NtTib.StackBase = (PCHAR)KiIdleThread.StackBase - sizeof(FX_SAVE_AREA);
//
// call the executive initialization routine.
//
try {
ExpInitializeExecutive();
} except (EXCEPTION_EXECUTE_HANDLER) {
KeBugCheck (PHASE0_EXCEPTION);
}
//
// Processor 0's DPC stack was temporarily allocated on
// the Double Fault Stack, switch to a proper kernel
// stack now.
//
DpcStack = MmCreateKernelStack(KERNEL_STACK_SIZE, FALSE);
if (DpcStack == NULL) {
KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
}
Prcb->DpcStack = DpcStack;
//
// Set the priority of the specified idle thread to zero, set appropriate
// member in KiIdleSummary and return to the system start up routine.
//
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
KeSetPriorityThread(&KiIdleThread, (KPRIORITY)0);
//
// if a thread has not been selected to run on the current processors,
// check to see if there are any ready threads; otherwise add this
// processors to the IdleSummary
//
if (Prcb->NextThread == (PKTHREAD)NULL) {
SetMember(0, KiIdleSummary);
}
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
}
VOID
KiSwapGDT(
VOID
)
/*++
Routine Description:
This function is called to edit the GDT. It swaps words of the address
and access fields around into the format the part actually needs.
This allows for easy static init of the GDT.
Note that this procedure edits the current GDT.
Arguments:
None.
Return Value:
None.
--*/
{
PKGDTENTRY Entry;
UCHAR Temp;
//
// Rearrange the entries of GDT to match i386 structure
//
for (Entry = KiGDT; Entry < KiGDTEnd; Entry++) {
Temp = Entry->HighWord.Bytes.Flags1;
Entry->HighWord.Bytes.Flags1 = Entry->HighWord.Bytes.Flags2;
Entry->HighWord.Bytes.Flags2 = Entry->HighWord.Bytes.BaseHi;
Entry->HighWord.Bytes.BaseHi = Temp;
}
}
VOID
KiSwapIDT(
VOID
)
/*++
Routine Description:
This function is called to edit the IDT. It swaps words of the address
and access fields around into the format the part actually needs.
This allows for easy static init of the IDT.
Note that this procedure edits the current IDT.
Arguments:
None.
Return Value:
None.
--*/
{
PKIDTENTRY Entry;
USHORT Temp;
//
// Rearrange the entries of IDT to match i386 interrupt gate structure
//
for (Entry = KiIDT; Entry < KiIDTEnd; Entry++) {
Temp = Entry->Selector;
Entry->Selector = Entry->ExtendedOffset;
Entry->ExtendedOffset = Temp;
}
}