|
|
title "System Startup" ;++ ; ; Copyright (c) 1989, 2000 Microsoft Corporation ; ; Module Name: ; ; systembg.asm ; ; Abstract: ; ; This module implements the code necessary to initially startup the ; NT system. ; ; Author: ; ; Shie-Lin Tzong (shielint) 07-Mar-1990 ; ; Environment: ; ; Kernel mode only. ; ; Revision History: ; ; John Vert (jvert) 25-Jun-1991 ; Major overhaul in order to move into new osloader architecture ; Removed old debugger hacks ; ;-- .386p .xlist include ks386.inc include i386\kimacro.inc include mac386.inc include callconv.inc include irqli386.inc .list
option segment:flat
extrn _KiBootFeatureBits:DWORD EXTRNP _KdInitSystem,2 EXTRNP _KdPollBreakIn,0 EXTRNP _KiInitializeKernel,6 EXTRNP GetMachineBootPointers EXTRNP KiIdleLoop,0,,FASTCALL EXTRNP _KiInitializePcr,7 EXTRNP _KiSwapIDT EXTRNP _KiInitializeTSS,1 EXTRNP _KiInitializeTSS2,2 extrn _KiTrap08:PROC extrn _KiTrap02:PROC EXTRNP _KiInitializeAbios,1 EXTRNP _KiInitializeMachineType EXTRNP _HalInitializeProcessor,2,IMPORT
if NT_INST EXTRNP _KiAcquireSpinLock, 1 EXTRNP _KiReleaseSpinLock, 1 endif extrn _KiFreezeExecutionLock:DWORD extrn _IDT:BYTE extrn _IDTLEN:BYTE ; NOTE - really an ABS, linker problems extrn _KeNumberProcessors:BYTE extrn _KeActiveProcessors:DWORD extrn _KeLoaderBlock:DWORD extrn _KiIdleProcess:BYTE extrn _KiIdleThread0:BYTE
ifndef NT_UP extrn _KiBarrierWait:DWORD EXTRNP _KiProcessorStart endif
; ; Constants for various variables ;
_DATA SEGMENT PARA PUBLIC 'DATA'
; ; Statically allocated structures for Bootstrap processor ; double fault stack for P0 ; idle thread stack for P0 ;
align 16 public _KiDoubleFaultStack db DOUBLE_FAULT_STACK_SIZE dup (?) _KiDoubleFaultStack label byte
public P0BootStack db KERNEL_STACK_SIZE dup (?) P0BootStack label byte
; ; Double fault task stack ;
MINIMUM_TSS_SIZE EQU TssIoMaps
align 16
public _KiDoubleFaultTSS _KiDoubleFaultTSS label byte db MINIMUM_TSS_SIZE dup(0)
public _KiNMITSS _KiNMITSS label byte db MINIMUM_TSS_SIZE dup(0)
; ; Abios specific definitions ;
public _KiCommonDataArea, _KiAbiosPresent _KiCommonDataArea dd 0 _KiAbiosPresent dd 0
_DATA ends
page ,132 subttl "System Startup" INIT SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++ ; ; For processor 0, Routine Description: ; ; This routine is called when the NT system begins execution. ; Its function is to initialize system hardware state, call the ; kernel initialization routine, and then fall into code that ; represents the idle thread for all processors. ; ; Entry state created by the boot loader: ; A short-form IDT (0-1f) exists and is active. ; A complete GDT is set up and loaded. ; A complete TSS is set up and loaded. ; Page map is set up with minimal start pages loaded ; The lower 4Mb of virtual memory are directly mapped into ; physical memory. ; ; The system code (ntoskrnl.exe) is mapped into virtual memory ; as described by its memory descriptor. ; DS=ES=SS = flat ; ESP->a usable boot stack ; Interrupts OFF ; ; For processor > 0, Routine Description: ; ; This routine is called when each additional processor begins execution. ; The entry state for the processor is: ; IDT, GDT, TSS, stack, selectors, PCR = all valid ; Page directory is set to the current running directory ; LoaderBlock - parameters for this processor ; ; Arguments: ; ; PLOADER_PARAMETER_BLOCK LoaderBlock ; ; Return Value: ; ; None. ; ;-- ; ; Arguments for KiSystemStartupPx ;
KissLoaderBlock equ [ebp+8]
; ; Local variables ;
KissGdt equ [ebp-4] KissPcr equ [ebp-8] KissTss equ [ebp-12] KissIdt equ [ebp-16] KissIrql equ [ebp-20] KissPbNumber equ [ebp-24] KissIdleStack equ [ebp-28] KissIdleThread equ [ebp-32]
cPublicProc _KiSystemStartup ,1
push ebp mov ebp, esp sub esp, 32 ; Reserve space for local variables
mov ebx, dword ptr KissLoaderBlock mov _KeLoaderBlock, ebx ; Get loader block param
movzx ecx, _KeNumberProcessors ; get number of processors mov KissPbNumber, ecx or ecx, ecx ; Is the the boot processor? jnz @f ; no
; P0 uses static memory for these mov dword ptr [ebx].LpbThread, offset _KiIdleThread0 mov dword ptr [ebx].LpbKernelStack, offset P0BootStack
push KGDT_R0_PCR ; P0 needs FS set pop fs
; Save processornumber in Prcb mov byte ptr PCR[PcPrcbData+PbNumber], cl @@: mov eax, dword ptr [ebx].LpbThread mov dword ptr KissIdleThread, eax
lea ecx, [eax].ThApcState.AsApcListHead ; initialize kernel APC list head mov [eax].ThApcState.AsApcListHead, ecx ; mov [eax].ThApcState.AsApcListHead+4, ecx ;
mov eax, dword ptr [ebx].LpbKernelStack mov dword ptr KissIdleStack, eax
stdCall _KiInitializeMachineType cmp byte ptr KissPbNumber, 0 ; if not p0, then jne kiss_notp0 ; skip a bunch
; ;+++++++++++++++++++++++ ; ; Initialize the PCR ;
stdCall GetMachineBootPointers ; ; Upon return: ; (edi) -> gdt ; (esi) -> pcr ; (edx) -> tss ; (eax) -> idt ; Now, save them in our local variables ;
mov KissGdt, edi mov KissPcr, esi mov KissTss, edx mov KissIdt, eax
; ; edit TSS to be 32bits. loader gives us a tss, but it's 16bits! ; lea ecx,[edi]+KGDT_TSS ; (ecx) -> TSS descriptor mov byte ptr [ecx+5],089h ; 32bit, dpl=0, present, TSS32, not busy
; KiInitializeTSS2( ; Linear address of TSS ; Linear address of TSS descriptor ; ); stdCall _KiInitializeTSS2, <KissTss, ecx>
stdCall _KiInitializeTSS, <KissTss>
mov cx,KGDT_TSS ltr cx
; ; set up 32bit double fault task gate to catch double faults. ;
mov eax,KissIdt lea ecx,[eax]+40h ; Descriptor 8 mov byte ptr [ecx+5],085h ; dpl=0, present, taskgate
mov word ptr [ecx+2],KGDT_DF_TSS
lea ecx,[edi]+KGDT_DF_TSS mov byte ptr [ecx+5],089h ; 32bit, dpl=0, present, TSS32, not busy
mov edx,offset FLAT:_KiDoubleFaultTSS mov eax,edx mov [ecx+KgdtBaseLow],ax shr eax,16 mov [ecx+KgdtBaseHi],ah mov [ecx+KgdtBaseMid],al mov eax, MINIMUM_TSS_SIZE mov [ecx+KgdtLimitLow],ax
; KiInitializeTSS( ; address of double fault TSS ; ); push edx stdCall _KiInitializeTSS, <edx> pop edx
mov eax,cr3 mov [edx+TssCr3],eax
mov eax, offset FLAT:_KiDoubleFaultStack mov dword ptr [edx+TssEsp],eax mov dword ptr [edx+TssEsp0],eax
mov dword ptr [edx+020h],offset FLAT:_KiTrap08 mov dword ptr [edx+024h],0 ; eflags mov word ptr [edx+04ch],KGDT_R0_CODE ; set value for CS mov word ptr [edx+058h],KGDT_R0_PCR ; set value for FS mov [edx+050h],ss mov word ptr [edx+048h],KGDT_R3_DATA OR RPL_MASK ; Es mov word ptr [edx+054h],KGDT_R3_DATA OR RPL_MASK ; Ds
; ; set up 32bit NMI task gate to catch NMI faults. ;
mov eax,KissIdt lea ecx,[eax]+10h ; Descriptor 2 mov byte ptr [ecx+5],085h ; dpl=0, present, taskgate
mov word ptr [ecx+2],KGDT_NMI_TSS
lea ecx,[edi]+KGDT_NMI_TSS mov byte ptr [ecx+5],089h ; 32bit, dpl=0, present, TSS32, not busy
mov edx,offset FLAT:_KiNMITSS mov eax,edx mov [ecx+KgdtBaseLow],ax shr eax,16 mov [ecx+KgdtBaseHi],ah mov [ecx+KgdtBaseMid],al mov eax, MINIMUM_TSS_SIZE mov [ecx+KgdtLimitLow],ax
push edx stdCall _KiInitializeTSS,<edx> ; KiInitializeTSS( ; address TSS ; ); pop edx
; ; We are using the DoubleFault stack as the DoubleFault stack and the ; NMI Task Gate stack and briefly, it is the DPC stack for the first ; processor. ;
mov eax,cr3 mov [edx+TssCr3],eax
mov eax, offset FLAT:_KiDoubleFaultTSS mov eax, dword ptr [eax+038h] ; get DF stack mov dword ptr [edx+TssEsp0],eax ; use it for NMI stack mov dword ptr [edx+038h],eax
mov dword ptr [edx+020h],offset FLAT:_KiTrap02 mov dword ptr [edx+024h],0 ; eflags mov word ptr [edx+04ch],KGDT_R0_CODE ; set value for CS mov word ptr [edx+058h],KGDT_R0_PCR ; set value for FS mov [edx+050h],ss mov word ptr [edx+048h],KGDT_R3_DATA OR RPL_MASK ; Es mov word ptr [edx+054h],KGDT_R3_DATA OR RPL_MASK ; Ds
stdCall _KiInitializePcr, <KissPbNumber,KissPcr,KissIdt,KissGdt,KissTss,KissIdleThread,offset FLAT:_KiDoubleFaultStack>
; ; set current process pointer in current thread object ; mov edx, KissIdleThread mov ecx, offset FLAT:_KiIdleProcess ; (ecx)-> idle process obj mov [edx]+ThApcState+AsProcess, ecx ; set addr of thread's process
; ; set up PCR: Teb, Prcb pointers. The PCR:InitialStack, and various fields ; of Prcb will be set up in _KiInitializeKernel ;
mov dword ptr PCR[PcTeb], 0 ; PCR->Teb = 0
; ; Initialize KernelDr7 and KernelDr6 to 0. This must be done before ; the debugger is called. ;
mov dword ptr PCR[PcPrcbData+PbProcessorState+PsSpecialRegisters+SrKernelDr6],0 mov dword ptr PCR[PcPrcbData+PbProcessorState+PsSpecialRegisters+SrKernelDr7],0
; ; Since the entries of Kernel IDT have their Selector and Extended Offset ; fields set up in the wrong order, we need to swap them back to the order ; which i386 recognizes. ; This is only done by the bootup processor. ;
stdCall _KiSwapIDT ; otherwise, do the work
; ; Switch to R3 flat selectors that we want loaded so lazy segment ; loading will work. ; mov eax,KGDT_R3_DATA OR RPL_MASK ; Set RPL = ring 3 mov ds,ax mov es,ax
; ; Now copy our trap handlers to replace kernel debugger's handlers. ;
mov eax, KissIdt ; (eax)-> Idt push dword ptr [eax+40h] ; save double fault's descriptor push dword ptr [eax+44h] push dword ptr [eax+10h] ; save nmi fault's descriptor push dword ptr [eax+14h]
mov edi,KissIdt mov esi,offset FLAT:_IDT mov ecx,offset FLAT:_IDTLEN ; _IDTLEN is really an abs, we use shr ecx,2
rep movsd pop dword ptr [eax+14h] ; restore nmi fault's descriptor pop dword ptr [eax+10h] pop dword ptr [eax+44h] ; restore double fault's descriptor pop dword ptr [eax+40h]
ifdef QLOCK_STAT_GATHER
EXTRNP KiCaptureQueuedSpinlockRoutines,0,,FASTCALL
fstCall KiCaptureQueuedSpinlockRoutines
endif
kiss_notp0:
ifndef NT_UP
; ; Let the boot processor know this processor is starting. ;
stdCall _KiProcessorStart
endif
; ; A new processor can't come online while execution is frozen ; Take freezelock while adding a processor to the system ; NOTE: don't use SPINLOCK macro - it has debugger stuff in it ;
if NT_INST lea eax, _KiFreezeExecutionLock stdCall _KiAcquireSpinLock, <eax> else @@: test _KiFreezeExecutionLock, 1 jnz short @b
lock bts _KiFreezeExecutionLock, 0 jc short @b endif
; ; Add processor to active summary, and update BroadcastMasks ; mov ecx, dword ptr KissPbNumber ; mark this processor as active mov byte ptr PCR[PcNumber], cl mov eax, 1 shl eax, cl ; our affinity bit mov PCR[PcSetMember], eax mov PCR[PcSetMemberCopy], eax mov PCR[PcPrcbData.PbSetMember], eax
; ; Initialize the interprocessor interrupt vector and increment ready ; processor count to enable kernel debugger. ; stdCall _HalInitializeProcessor, <dword ptr KissPbNumber, KissLoaderBlock>
ifdef _APIC_TPR_
; ; Record the IRQL tables passed to us by the hal ;
mov eax, KissLoaderBlock mov eax, [eax]+LpbExtension mov ecx, [eax]+LpeHalpIRQLToTPR mov _HalpIRQLToTPR, ecx mov ecx, [eax]+LpeHalpVectorToIRQL mov _HalpVectorToIRQL, ecx
endif
mov eax, PCR[PcSetMember] or _KeActiveProcessors, eax ; New affinity of active processors
; ; Initialize ABIOS data structure if present. ; Note, the KiInitializeAbios MUST be called after the KeLoaderBlock is ; initialized. ; stdCall _KiInitializeAbios, <dword ptr KissPbNumber>
inc _KeNumberProcessors ; One more processor now active
if NT_INST lea eax, _KiFreezeExecutionLock stdCall _KiReleaseSpinLock, <eax> else xor eax, eax ; release the executionlock mov _KiFreezeExecutionLock, eax endif
cmp byte ptr KissPbNumber, 0 jnz @f
; don't stop in debugger stdCall _KdInitSystem, <0,_KeLoaderBlock>
if DEVL ; ; Give the debugger an opportunity to gain control. ;
POLL_DEBUGGER endif ; DEVL @@: nop ; leave a spot for int-3 patch ; ; Set initial IRQL = HIGH_LEVEL for init ;
RaiseIrql HIGH_LEVEL mov KissIrql, al or _KiBootFeatureBits, KF_CMPXCHG8B ; We're committed to using
; ; Initialize ebp, esp, and argument registers for initializing the kernel. ;
mov ebx, KissIdleThread mov edx, KissIdleStack mov eax, KissPbNumber and edx, NOT 3h ; align stack to 4 byte boundary
xor ebp, ebp ; (ebp) = 0. No more stack frame mov esp, edx
; ; Reserve space for idle thread stack NPX_SAVE_AREA and initialization ;
sub esp, NPX_FRAME_LENGTH+KTRAP_FRAME_LENGTH+KTRAP_FRAME_ALIGN push CR0_EM+CR0_TS+CR0_MP ; make space for Cr0NpxState
; arg6 - LoaderBlock ; arg5 - processor number ; arg4 - addr of prcb ; arg3 - idle thread's stack ; arg2 - addr of current thread obj ; arg1 - addr of current process obj
; initialize system data structures ; and HAL.
stdCall _KiInitializeKernel,<offset _KiIdleProcess,ebx,edx,dword ptr PCR[PcPrcb],eax,_KeLoaderBlock>
; ; Set idle thread priority. ;
mov ebx,PCR[PcPrcbData+PbCurrentThread] ; get idle thread address mov byte ptr [ebx]+ThPriority, 0 ; set idle thread priority
; ; Control is returned to the idle thread with IRQL at HIGH_LEVEL. Lower IRQL ; to DISPATCH_LEVEL and set wait IRQL of idle thread. ;
sti LowerIrql DISPATCH_LEVEL mov byte ptr [ebx]+ThWaitIrql, DISPATCH_LEVEL
; ; The following code represents the idle thread for a processor. The idle ; thread executes at IRQL DISPATCH_LEVEL and continually polls for work to ; do. Control may be given to this loop either as a result of a return from ; the system initialization routine or as the result of starting up another ; processor in a multiprocessor configuration. ;
mov ebx, PCR[PcSelfPcr] ; get address of PCR
; ; In a multiprocessor system the boot processor proceeds directly into ; the idle loop. As other processors start executing, however, they do ; not directly enter the idle loop - they spin until all processors have ; been started and the boot master allows them to proceed. ;
ifndef NT_UP
@@: cmp _KiBarrierWait, 0 ; check if barrier set YIELD jnz short @b ; if nz, barrier set
endif
push 0 ; terminate KD traceback 0 RA. jmp @KiIdleLoop@0 ; enter idle loop
stdENDP _KiSystemStartup
page ,132 subttl "Set up 80387, or allow for emulation" ;++ ; ; Routine Description: ; ; This routine is called during kernel initialization once for each ; processor. It sets EM+TS+MP whether we are emulating or not. ; ; If the 387 hardware exists, EM+TS+MP will all be cleared on the ; first trap 07. Thereafter, EM will never be seen for this thread. ; MP+TS will only be set when an error is detected (via IRQ 13), and ; it will be cleared by the trap 07 that will occur on the next FP ; instruction. ; ; If we're emulating, EM+TS+MP are all always set to ensure that all ; FP instructions trap to the emulator (the trap 07 handler is edited ; to point to the emulator, rather than KiTrap07). ; ; Arguments: ; ; None. ; ; Return Value: ; ; None. ; ;--
cPublicProc _KiSetCR0Bits ,0
mov eax, cr0 ; ; There are two useful bits in CR0 that we want to turn on if the processor ; is a 486 or above. (They don't exist on the 386) ; ; CR0_AM - Alignment mask (so we can turn on alignment faults) ; ; CR0_WP - Write protect (so we get page faults if we write to a ; write-protected page from kernel mode) ; cmp byte ptr PCR[PcPrcbData.PbCpuType], 3h jbe @f ; ; The processor is not a 386, (486 or greater) so we assume it is ok to ; turn on these bits. ;
or eax, CR0_WP
@@: mov cr0, eax stdRET _KiSetCR0Bits
stdENDP _KiSetCR0Bits
ifdef DBGMP cPublicProc _KiPollDebugger,0 cPublicFpo 0,3 push eax push ecx push edx POLL_DEBUGGER pop edx pop ecx pop eax stdRET _KiPollDebugger stdENDP _KiPollDebugger
endif
INIT ends
end
|