windows-nt/Source/XPSP1/NT/base/ntos/ke/amd64/start.asm

282 lines
8.9 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
title "System Startup"
;++
;
; Copyright (c) 2000 Microsoft Corporation
;
; Module Name:
;
; start.asm
;
; Abstract:
;
; This module implements the code necessary to initially startup the NT
; system on an AMD64 system.
;
; Author:
;
; David N. Cutler (davec) 22-Sep-2000
;
; Environment:
;
; Kernel mode only.
;
;--
include ksamd64.inc
extern KdInitSystem:proc
extern KeLoaderBlock:qword
extern KiBarrierWait:dword
extern KiIdleLoop:proc
extern KiInitializeBootStructures:proc
extern KiInitializeKernel:proc
extern KiInitialPCR:byte
TotalFrameLength EQU (LEGACY_SAVE_AREA_LENGTH + KEXCEPTION_FRAME_LENGTH + KSWITCH_FRAME_LENGTH)
subttl "System Startup"
;++
;
; Routine Description:
;
; This routine is called at system startup to perform early initialization
; and to inititialize the kernel debugger. This allows breaking into the
; kernel debugger very early during system startup. After kernel debugger
; initialization, kernel initialization is performed. On return from kernel
; initialization the idle loop is entered. The idle loop begins execution
; and immediately finds the system startup (phase 1) thread ready to run.
; Phase 1 initialization is performed and all other processors are started.
; As each process starts it also passes through the system startup code, but
; it does not initialization the kernel debugger.
;
; Arguments:
;
; LoaderBlock (rcx) - Supplies a pointer to the loader block.
;
; Implicit Arguments:
;
; When the system starts up the loader has done some initialization. In
; particular all structures have at least been zeroed and the GDT and
; TSS have been completely initialized.
;
; The loader block has been reformatted by the loader into a 64-bit loader
; block and all pertinent fields have been filled in.
;
; The address of the PRCB is passed in the loader block (only for processors
; other than zero).
;
; The address of the idle thread and idle process are passed in the loader
; block (only for processors other than zero).
;
; The GDT and IDT address and limits are contained in the gdtr and idtr
; registers.
;
; The address of the TSS must be extraced from the appropriate GDT entry
; and stored in the PCR.
;
; The stack register (RSP) is loaded with the idle thread stack and the
; kernel stack field of the loader block contains the address of the DPC
; stack.
;
; Return Value:
;
; None - function does not return.
;
;--
SsFrame struct
P1Home dq ? ;
P2Home dq ? ;
P3Home dq ? ;
P4Home dq ? ;
P5 dq ? ; parameter 5
P6 dq ? ; parameter 6
Fill dq ? ; fill to 8 mode 16
SsFrame ends
NESTED_ENTRY KiSystemStartup, INIT
alloc_stack (sizeof SsFrame) ; allocate stack frame
END_PROLOGUE
;
; Save the address of the loader block.
;
; N.B. This is the same address for all processors.
;
mov KeLoaderBlock, rcx ; save loader block address
;
; Initialize PCR self address and the current PRCB address.
;
mov rdx, LpbPrcb[rcx] ; get specified PRCB address
lea rax, KiInitialPCR + PcPrcb ; get builtin PRCB address
test rdx, rdx ; test if PRCB address specified
cmovz rdx, rax ; if z, set builtin PRCB address
mov LpbPrcb[rcx], rdx ; set loader block PRCB address
mov r8, rdx ; copy PRCB address
sub rdx, PcPrcb ; compute PCR address
mov PcSelf[rdx], rdx ; set PCR self address
mov PcCurrentPrcb[rdx], r8 ; set current PRCB address
;
; Initialize kernel special registers and the address of the GDT, TSS, and
; IDT in the PRCB and PCR.
;
; N.B. The debug registers are zeroed in the PRCB.
;
mov r8, cr0 ; save CR0
mov PcCr0[rdx], r8 ;
mov r8, cr2 ; save CR2
mov PcCr2[rdx], r8 ;
mov r8, cr3 ; save CR3
mov PcCr3[rdx], r8 ;
mov r8, cr4 ; save CR4
mov PcCr4[rdx], r8 ;
sgdt PcGdtrLimit[rdx] ; save GDT limit and base
mov r8, PcGdtrBase[rdx] ; set GDT base address
mov PcGdt[rdx], r8 ;
sidt PcIdtrLimit[rdx] ; save IDT limit and base
mov r9, PcIdtrBase[rdx] ; set IDT base address
mov PcIdt[rdx], r9 ;
str word ptr PcTr[rdx] ; save TR selector
sldt word ptr PcLdtr[rdx] ; save LDT selector
mov dword ptr PcMxCsr[rdx], INITIAL_MXCSR ; set initial MXCSR
;
; Set connical selector values (note CS, GS, and SS are already set).
;
mov ax, KGDT64_R3_DATA or RPL_MASK ;
mov ds, ax ;
mov es, ax ;
mov ax, KGDT64_R3_CMTEB or RPL_MASK ;
mov fs, ax ;
;
; Load a NULL selector into the LDT.
;
xor eax, eax ; set NULL selector for LDT
lldt ax ;
;
; Extract TSS address from GDT entry and store in PCR.
;
mov ax, KGDT64_SYS_TSS + KgdtBaseLow[r8] ; set low 16-bits
mov PcTss[rdx], ax ;
mov al, KGDT64_SYS_TSS + KgdtBaseMiddle[r8] ; set middle 8-bits
mov PcTss + 2[rdx], al ;
mov al, KGDT64_SYS_TSS + KgdtBaseHigh[r8] ; set high 8-bits
mov PcTss + 3[rdx], al ;
mov eax, KGDT64_SYS_TSS +KgdtBaseUpper[r8] ; set upper 32-bits
mov PcTss + 4[rdx], eax ;
;
; Initialize the GS base and swap addresses.
;
mov eax, edx ; set low 32-bits of address
shr rdx, 32 ; set high 32-bits of address
mov ecx, MSR_GS_BASE ; get GS base address MSR number
wrmsr ; write GS base address
mov ecx, MSR_GS_SWAP ; get GS swap base MSR number
wrmsr ; write GS swap base address
;
; Initialize boot structures.
;
mov rcx, KeLoaderBlock ; set loader block address
call KiInitializeBootStructures ; initialize boot structures
;
; Initialize the kernel debugger if this is processor zero.
;
xor ecx, ecx ; set phase to 0
mov rdx, KeLoaderBlock ; set loader block address
call KdInitSystem ; initialize debugger
;
; Raise IRQL to high level and initialize the kernel.
;
KiSS10: mov ecx, HIGH_LEVEL ; set high IRQL
SetIrql ;
;
; Reserve space for idle thread stack initialization.
;
; N.B. This reservation ensures that the initialization of the thread stack
; does not overwrite any information on the current stack which is the
; same stack.
;
sub rsp, TotalFrameLength ; allocate stack
;
; Initialize kernel.
;
mov rax, KeLoaderBlock ; set loader block address
mov rcx, LpbProcess[rax] ; set idle process address
mov rdx, LpbThread[rax] ; set idle thread address
mov r8, gs:[PcTss] ; set idle stack address
mov r8, TssRsp0[r8] ;
mov r9, LpbPrcb[rax] ; set PRCB address
mov r10b, PbNumber[r9] ; set processor number
mov SsFrame.P5[rsp], r10 ;
mov SsFrame.P6[rsp], rax ; set loader block address
call KiInitializeKernel ; Initialize kernel
;
; Reset stack to include only the space for the legacy NPX state.
;
mov rcx, gs:[PcTss] ; get TSS address
mov rcx, TssRsp0[rcx] ; get idle stack address
lea rsp, (-LEGACY_SAVE_AREA_LENGTH)[rcx] ; deallocate stack space
;
; Enable interrupts, lower IRQL to dispatch level, and set the wait IRQL for
; the idle thread.
;
sti ; enable interrupts
mov ecx, DISPATCH_LEVEL ; set dispatch IRQL
SetIrql ;
mov rcx, gs:[PcCurrentThread] ; get current thread address
mov byte ptr ThWaitIrql[rcx], DISPATCH_LEVEL ; set wait IRQL
;
; In a multiprocessor system the boot processor proceeds directly into the
; idle loop. As other processors start executing, however, they do not enter
; the idle loop directly - they spin until all processors have been started
; and the boot master allows them to proceed.
;
ifndef NT_UP
KiSS20: cmp KiBarrierWait, 0 ; check if barrier set
jnz short KiSS20 ; if nz, barrier set
endif
call KiIdleLoop ; enter idle loop - no return
NESTED_END KisystemStartup, INIT
end