summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm')
-rw-r--r--ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm1387
1 files changed, 1387 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm b/ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm
new file mode 100644
index 0000000..066aedc
--- /dev/null
+++ b/ReferenceCode/Haswell/Txt/TxtInit/Pei/Ia32/TxtPeiBsp.asm
@@ -0,0 +1,1387 @@
+;/*++
+; This file contains an 'Intel Peripheral Driver' and uniquely
+; identified as "Intel Reference Module" and is
+; licensed for Intel CPUs and chipsets under the terms of your
+; license agreement with Intel or your vendor. This file may
+; be modified by the user, subject to additional terms of the
+; license agreement
+;--*/
+;
+;/*++
+;
+; Copyright (c) 1999 - 2011 Intel Corporation. All rights reserved
+; This software and associated documentation (if any) is furnished
+; under a license and may only be used or copied in accordance
+; with the terms of the license. Except as permitted by such
+; license, no part of this software or documentation may be
+; reproduced, stored in a retrieval system, or transmitted in any
+; form or by any means without the express written consent of
+; Intel Corporation.
+;
+;
+; Module Name:
+;
+; TxtPeiBsp.asm
+;
+; Abstract:
+;
+; This file contains the code to launch BIOS ACM functions in PEI phase
+;
+;--*/
+
+ .XLIST
+ include txt.inc
+ .LIST
+
+ .686P
+ .MMX
+ .XMM
+ .MODEL FLAT,C
+ .CODE
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: LaunchBiosAcmSclean
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Setup GETSEC environment (protected mode, mtrrs, etc) and
+; invoke GETSEC:ENTERACCS with requested BIOS ACM entry point.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+LaunchBiosAcmSclean PROC PUBLIC
+ ;
+ ; Tell where we are
+ ;
+ mov eax, 11110000h
+ in ax, 80h
+ mov ah, PORT80_CODE_PREFIX + TXT_LAUNCH_SCLEAN
+ out 80h, eax
+
+ ;
+ ; Enable SMXE, SSE and debug extensions always.
+ ;
+ mov eax, CR4
+ or eax, CR4_OSFXSR + CR4_DE + CR4_SMXE
+ mov CR4, eax
+
+ ;
+ ; Prepare cache of BSP
+ ;
+ mov esi, TXT_PUBLIC_BASE + BIOACM_ADDR
+ mov edi, 0
+
+ CALL_NS PrepareCacheForAcModuleRetNS
+
+ CALL_NS CleanMcaRetNS
+
+ifdef MKF_TXT_RLP_INIT
+ if MKF_TXT_RLP_INIT
+ CALL_NS InitializeApsRetNS
+ endif
+endif
+
+
+ ;
+ ; Call GETSEC[ENTERACCS]
+ ;
+ cli
+ mov eax, ENTERACCS ; eax = ENTERACCS
+ mov ebx, TXT_PUBLIC_BASE + BIOACM_ADDR
+ mov ebx, [ebx]
+ mov ecx, [ebx].ACM_HEADER.AcmSize
+ shl ecx, 2
+ xor edx, edx
+ xor edi, edi
+ mov esi, 0
+
+ _GETSEC
+
+ jmp DoPowerCycleReset
+LaunchBiosAcmSclean ENDP
+
+DoGlobalReset PROC PUBLIC
+ mov dx, 0CF8h ; Make warm system reset through port 0CF9h
+ mov eax, 8000F8ACh ; to be global system reset - set bit 20
+ out dx, eax ; of device 1F
+ mov dx, 0CFCh
+ in eax, dx
+ or eax, (1 SHL 20)
+ out dx, eax
+
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 0 ; system must be reset.
+ out dx, al
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 6 ; system must be reset.
+ out dx, al
+ cli
+ hlt
+ jmp $
+
+DoGlobalReset ENDP
+
+DoPowerCycleReset PROC PUBLIC
+ mov dx, 0CF8h ; Make warm system reset through port 0CF9h
+ mov eax, 8000F8ACh ; to be global system reset - set bit 20
+ out dx, eax ; of device 1F
+ mov dx, 0CFCh
+ in eax, dx
+ and eax, NOT (1 SHL 20)
+ out dx, eax
+
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 0 ; system must be reset.
+ out dx, al
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 0Eh ; system must be reset.
+ out dx, al
+ cli
+ hlt
+ jmp $
+
+DoPowerCycleReset ENDP
+
+DoHostReset PROC PUBLIC
+ mov dx, 0CF8h ; Make warm system reset through port 0CF9h
+ mov eax, 8000F8ACh ; to be global system reset - set bit 20
+ out dx, eax ; of device 1F
+ mov dx, 0CFCh
+ in eax, dx
+ and eax, NOT (1 SHL 20)
+ out dx, eax
+
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 0 ; system must be reset.
+ out dx, al
+ mov dx, 0CF9h ; After return from SCLEAN function
+ mov al, 6 ; system must be reset.
+ out dx, al
+ cli
+ hlt
+ jmp $
+
+DoHostReset ENDP
+
+DoCpuReset PROC PUBLIC
+ mov dx, 0CF8h ; Make warm system reset through port 0CF9h
+ mov eax, 8000F8ACh ; to be global system reset - clear bit 20
+ out dx, eax ; of device 1F
+ mov dx, 0CFCh
+ in eax, dx
+ and eax, NOT (1 SHL 20)
+ out dx, eax
+
+ mov dx, 0CF9h ; Issue a CPU only reset by CF9h
+ mov al, 0 ; toggle bit2 from 0 to 1
+ out dx, al
+ mov dx, 0CF9h ; Issue a CPU only reset by CF9h
+ mov al, 4 ;
+ out dx, al
+ cli
+ hlt
+ jmp $
+
+DoCpuReset ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: PrepareCacheForAcModuleRetNS
+;
+; Input: esi - bios acm address
+; edi - in memory flag
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: MTRRs are set per BIOS spec
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+PrepareCacheForAcModuleRetNS PROC FAR PUBLIC
+ ;
+ ; Enable local APIC
+ ;
+ mov ecx, IA32_APIC_BASE
+ rdmsr ; Get APIC Base
+ and eax, BASE_ADDR_MASK ; Just need the address
+ mov DWORD PTR [eax+SPURIOUS_VECTOR_1], 1FFh ; Enable APIC, keep spurious vector
+ ;
+ ; Disable cache
+ ;
+ mov eax, cr0 ; set CR0:CD and CR0:NE, clear CR0:NW
+ or eax, CR0_CD_MASK OR CR0_NE_MASK
+ and eax, NOT CR0_NW_MASK
+ mov cr0, eax
+ cmp edi, 0
+ je @F ; JIf stackless environment
+ wbinvd ; Invalidate the cache
+ jmp disableMtrrs
+
+@@:
+ invd
+
+disableMtrrs:
+ ;
+ ; Disable all MTRRs
+ ;
+ xor eax, eax
+ xor edx, edx
+ mov ecx, IA32_MTRR_DEF_TYPE
+ wrmsr
+
+ ;
+ ; Disable NEM
+ ;
+ mov ecx, NO_EVICT_MODE
+ rdmsr
+ and eax, NOT (BIT1)
+ wrmsr ; Clear No-Eviction Mode Run bit
+ mov ecx, NO_EVICT_MODE
+ rdmsr
+ and eax, NOT (BIT0)
+ wrmsr ; Clear No-Eviction Mode SETUP bit
+
+ invd
+
+ ;
+ ; Clear all variable MTRRs
+ ;
+ mov ecx, IA32_MTRR_CAP
+ rdmsr
+ and eax, 0FFh
+ shl eax, 1
+ mov ecx, eax
+ xor eax, eax
+ xor edx, edx
+@@:
+ add ecx, IA32_MTRR_PHYSBASE0 - 1
+ wrmsr
+ sub ecx, IA32_MTRR_PHYSBASE0 - 1
+ loop @B
+
+ ;
+ ; Determine size of AC module
+ ;
+ mov esi, [esi]
+ mov eax, [esi].ACM_HEADER.AcmSize
+ shl eax, 2 ; ...in bytes (ACM header has size in dwords)
+ ;
+ ; Round up to page size
+ ;
+ mov ecx, eax ; Save
+ and ecx, 0FFFFF000h ; Number of pages in AC module
+ and eax, 0FFFh ; Number of "less-than-page" bytes
+ jz rounded
+ mov eax, 1000h ; Add the whole page size
+
+rounded:
+ add eax, ecx ; eax - rounded up AC module size
+
+ ;
+ ; Define "local" vars for this routine
+ ;
+ ACM_SIZE_TO_CACHE TEXTEQU <mm0>
+ ACM_BASE_TO_CACHE TEXTEQU <mm1>
+ NEXT_MTRR_INDEX TEXTEQU <mm2>
+ NEXT_MTRR_SIZE TEXTEQU <mm3>
+ ;
+ ; Initialize "locals"
+ ;
+ sub ecx, ecx
+ movd NEXT_MTRR_INDEX, ecx ; Start from MTRR0
+
+ ;
+ ; Save remaining size to cache
+ ;
+ movd ACM_SIZE_TO_CACHE, eax ; Size of ACM that must be cached
+ movd ACM_BASE_TO_CACHE, esi ; Base ACM address
+
+nextMtrr:
+ ;
+ ; Get remaining size to cache
+ ;
+ movd eax, ACM_SIZE_TO_CACHE
+ and eax, eax
+ jz done ; If no left size - we are done
+ ;
+ ; Determine next size to cache.
+ ; We start from bottom up. Use the following algorythm:
+ ; 1. Get our own alignment. Max size we can cache equals to our alignment
+ ; 2. Determine what is bigger - alignment or remaining size to cache.
+ ; If aligment is bigger - cache it.
+ ; Adjust remaing size to cache and base address
+ ; Loop to 1.
+ ; If remaining size to cache is bigger
+ ; Determine the biggest 2^N part of it and cache it.
+ ; Adjust remaing size to cache and base address
+ ; Loop to 1.
+ ; 3. End when there is no left size to cache or no left MTRRs
+ ;
+ movd esi, ACM_BASE_TO_CACHE
+ bsf ecx, esi ; Get index of lowest bit set in base address
+ ;
+ ; Convert index into size to be cached by next MTRR
+ ;
+ mov edx, 1h
+ shl edx, cl ; Alignment is in edx
+ cmp edx, eax ; What is bigger, alignment or remaining size?
+ jbe gotSize ; JIf aligment is less
+ ;
+ ; Remaining size is bigger. Get the biggest part of it, 2^N in size
+ ;
+ bsr ecx, eax ; Get index of highest set bit
+ ;
+ ; Convert index into size to be cached by next MTRR
+ ;
+ mov edx, 1
+ shl edx, cl ; Size to cache
+
+gotSize:
+ mov eax, edx
+ movd NEXT_MTRR_SIZE, eax ; Save
+
+ ;
+ ; Compute MTRR mask value: Mask = NOT (Size - 1)
+ ;
+ dec eax ; eax - size to cache less one byte
+ not eax ; eax contains low 32 bits of mask
+ or eax, MTRR_VALID ; Set valid bit
+
+ ;
+ ; Program mask register
+ ;
+ mov ecx, IA32_MTRR_PHYSMASK0 ; setup variable mtrr
+ movd ebx, NEXT_MTRR_INDEX
+ add ecx, ebx
+
+ mov edx, 0Fh ; 8K range (FFFFFFE800)
+ wrmsr
+ ;
+ ; Program base register
+ ;
+ sub edx, edx
+ mov ecx, IA32_MTRR_PHYSBASE0 ; setup variable mtrr
+ add ecx, ebx ; ebx is still NEXT_MTRR_INDEX
+
+ movd eax, ACM_BASE_TO_CACHE
+ or eax, WB ; set type to write back
+ wrmsr
+ ;
+ ; Advance and loop
+ ; Reduce remaining size to cache
+ ;
+ movd ebx, ACM_SIZE_TO_CACHE
+ movd eax, NEXT_MTRR_SIZE
+ sub ebx, eax
+ movd ACM_SIZE_TO_CACHE, ebx
+
+ ;
+ ; Increment MTRR index
+ ;
+ movd ebx, NEXT_MTRR_INDEX
+ add ebx, 2
+ movd NEXT_MTRR_INDEX, ebx
+ ;
+ ; Increment base address to cache
+ ;
+ movd ebx, ACM_BASE_TO_CACHE
+ movd eax, NEXT_MTRR_SIZE
+ add ebx, eax
+ movd ACM_BASE_TO_CACHE, ebx
+
+ jmp nextMtrr
+
+done:
+ ;
+ ; Enable variable MTRRs
+ ;
+ xor edx, edx
+ mov eax, MTRR_ENABLE; enable mtrrs (but not fixed ones)
+ mov ecx, IA32_MTRR_DEF_TYPE
+ wrmsr
+ ;
+ ; Enable cache
+ ;
+ mov eax, cr0 ; Enable caching - WB (NW stays clear)
+ and eax, NOT CR0_CD_MASK
+ mov cr0, eax
+
+ RET_NS
+PrepareCacheForAcModuleRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: CleanMcaRetNS
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Setup GETSEC environment (protected mode, mtrrs, etc)
+; invoke GETSEC:ENTERACCS with requested module
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+CleanMcaRetNS PROC NEAR PUBLIC
+
+ ;
+ ; Clean all MCi_STATUS MSR registers
+ ; SCLEAN will generate GPF otherwise
+ ;
+ mov ecx, MCG_CAP
+ rdmsr
+ movzx ebx, al ; Bank count to ebx
+ sub eax, eax ; Write 0 into all MCi_STATUS registers
+ sub edx, edx
+ mov ecx, MC0_STATUS
+
+McaErrorCleanLoopStart:
+ wrmsr
+ dec ebx
+ jz exit
+ add ecx, 4 ; Number of MSRs per bank
+ jmp McaErrorCleanLoopStart
+
+exit:
+ RET_NS
+CleanMcaRetNS ENDP
+
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: InitializeApsRetNS
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description:
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+InitializeApsRetNS PROC NEAR
+ mov eax, 1
+ cpuid
+ shr ebx, 16 ; Total Logical Proc Count in BL
+ cmp bl, 1 ; If 1 thread - nothing to do
+ je exit
+
+ ;
+ ; Init Timer 1
+ ;
+ mov al, 54h
+ out 43h, al
+ mov al, 12h
+ out 41h, al
+
+ ;
+ ; More than one thread
+ ; Get APIC address
+ ;
+ mov ecx, IA32_APIC_BASE
+ rdmsr ; Get APIC Base
+ and eax, BASE_ADDR_MASK ; Just need the address
+ mov edi, eax ; edi points to APIC base
+
+ mov esi, TXT_PUBLIC_BASE ; esi points to public space
+
+ ;
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+
+ ;
+ ; Broadcast INIT message to put all APs into Wait for SIPI state
+ ; C0500 -> Destination = All excl self, Delivery = INIT
+ ;
+ mov DWORD PTR ICR_LOW[edi], 000C0500h
+ mov edx, NeverStatusRetNS
+ mov ecx, 667
+ CALL_NS ltWaitStatusRetNS ; Wait full 10ms
+ ;
+ ; Create vector used in the following SIPI message
+ ; Below address is the real mode address of AP code in Boot Block
+ ; LTCACHE.BIN containg AP thread code must be placed at the above address
+ ; in Boot block (FFFF0000h). See file LTCACHE.ASM
+ ;
+
+ mov ebx, [esi+APINIT_ADDR]
+ shr ebx, 12
+ and ebx, 0FFh
+ or ebx, 0C0600h ; This is message
+
+ ;
+ ; Broadcast SIPI message with our vector
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov ICR_LOW[edi], ebx
+ ;
+ ; Wait 200us as recommended
+ ;
+ mov edx, NeverStatusRetNS
+ mov ecx, 14
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Broadcast second SIPI message with our vector
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov ICR_LOW[edi], ebx
+ ;
+ ; Wait for semaphore reflect number of CPUs
+ ;
+ mov eax, 1
+ cpuid
+ shr ebx, 16 ; Total Logical Proc Count in BL
+ dec bl ; bl is number of APs
+
+ mov edx, SemaphoreStatusRetNS
+ mov ecx, 6670
+ CALL_NS ltWaitStatusRetNS ; Wait for up to 100ms
+
+ ;
+ ; Broadcast INIT message to put all APs back into Wait for SIPI state
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov DWORD PTR ICR_LOW[edi], 000C0500h
+
+ mov edx, NeverStatusRetNS
+ mov ecx, 667
+ CALL_NS ltWaitStatusRetNS ; Wait full 10ms
+
+exit:
+ RET_NS
+InitializeApsRetNS ENDP
+
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: SaveApConfig
+;
+; Input: ApCfg - pointer to save area
+;
+; Output: None
+;
+; Registers: All are preserved
+;
+; Description: Function is called in memory present environment on S3 resume
+; path. Saves contents of all MTRRs into table plus some registers.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+SaveApConfig PROC NEAR PUBLIC, ApCfg:PTR QWORD
+
+ pushad
+
+ mov esi, ApCfg
+ mov ecx, IA32_MTRR_CAP
+ rdmsr
+ and eax, 0FFh
+ shl eax, 1
+ mov ecx, eax
+
+@@:
+ add ecx, IA32_MTRR_PHYSBASE0 - 1
+ rdmsr
+ mov [esi], eax
+ mov [esi+4], edx
+ add esi, SIZEOF QWORD
+ sub ecx, IA32_MTRR_PHYSBASE0 - 1
+ loop @B
+
+ mov ecx, IA32_MTRR_DEF_TYPE
+ rdmsr
+ mov [esi], eax
+ mov [esi+4], edx
+
+ sidt [esi+8]
+
+ mov ecx, IA32_MISC_ENABLE_MSR
+ rdmsr
+ mov [esi+010h], eax
+ mov [esi+014h], edx
+
+ popad
+ ret
+SaveApConfig ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: StartupAllAPs
+;
+; Input: pFunction - pointer to function to execute on AP
+; pParam - pointre to pFunction parameters
+;
+; Output: None
+;
+; Registers: All are preserved
+;
+; Description: Procedure is called in memmory present enironment on S3
+; resume path and is executed on BSP
+; It saves memory at address 1000h into buffer
+; It then copies AP start-up code into address 1000h
+; Then variables in the 1000h area are updated and APs are started
+; After APs finish execution of function passed as parameter they
+; are halted. BSP restores contents 1000h area from buffer and
+; returns.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+Func TYPEDEF PROTO
+
+PFUNC TYPEDEF PTR Func
+
+StartUp STRUCT
+ db 0FAh ; cli
+ db 066h, 0BBh ; mov ebx, OFFSET gdtLim
+ db StartUp.gdtLim, 0,0,0
+ db 066h
+ db 067h, 02Eh, 00Fh, 001h, 013h ; lgdt FWORD PTR cs:[ebx]
+ db 00Fh, 020h, 0C0h ; mov eax, CR0
+ db 00Ch, 001h ; or al, 01
+ db 00Fh, 022h, 0C0h ; mov CR0, eax
+ ;
+ ; 32 bit jump to 32 bit Function handler
+ ;
+ db 066h
+ db 0eah
+fOff dd 0
+fCs dw 0
+
+ ALIGN 16
+fDs dw 0
+gdtLim dw ? ; Size of LT GDT in bytes
+gdtBas dd ? ; Physical address of LT GDT
+fParam dd ?
+smphr dd ?
+StartUp ENDS
+
+
+StartupAllAPs PROC NEAR, pFunction:PFUNC, pParam:PTR QWORD
+ LOCAL buffer:StartUp
+ LOCAL savedESP:DWORD
+
+ pushad
+ mov savedESP, esp
+ mov eax, 1
+ cpuid
+ shr ebx, 16 ; Total Logical Proc Count in BL
+ cmp bl, 1 ; If 1 thread - nothing to do
+ je exit
+
+ ;
+ ; Init Timer 1
+ ;
+ mov al, 54h
+ out 43h, al
+ mov al, 12h
+ out 41h, al
+
+ ;
+ ; More than one thread. Prepare Startup area
+ ;
+ mov esi, 1000h ; Source
+ lea edi, buffer ; Destination
+ mov ecx, sizeof StartUp / 4
+ CALL_NS MemCopyRetNS
+
+ mov esi, offset ApHandler16 ; Source
+ mov edi, 1000h ; Destination
+ mov ecx, sizeof StartUp / 4
+ CALL_NS MemCopyRetNS
+ ;
+ ; Update Srartup area variables
+ ;
+ mov edi, 1000h
+ mov ds:[edi].StartUp.fCs, cs
+ mov ds:[edi].StartUp.fDs, ds
+ mov eax, pFunction
+ mov ds:[edi].StartUp.fOff, eax
+ sub eax, eax
+ mov ds:[edi].StartUp.smphr, eax
+ mov eax, pParam
+ mov ds:[edi].StartUp.fParam, eax
+ sgdt ds:[edi].StartUp.gdtLim
+
+ ;
+ ; Get APIC address
+ ;
+ mov ecx, IA32_APIC_BASE
+ rdmsr ; Get APIC Base
+ and eax, BASE_ADDR_MASK ; Just need the address
+ mov edi, eax ; edi points to APIC base
+
+ ;
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+
+ ;
+ ; Broadcast INIT message to put all APs into Wait for SIPI state
+ ; C0500 -> Destination = All excl self, Delivery = INIT
+ ;
+ mov DWORD PTR ICR_LOW[edi], 000C0500h
+ mov edx, NeverStatusRetNS
+ mov ecx, 667
+ CALL_NS ltWaitStatusRetNS ; Wait full 10ms
+ ;
+ ; Create vector used in the following SIPI message
+ ;
+ mov ebx, 0C0600h + (1000h SHR 12)
+ ;
+ ; Broadcast SIPI message with our vector
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov ICR_LOW[edi], ebx
+ ;
+ ; Wait 200us as recommended
+ ;
+ mov edx, NeverStatusRetNS
+ mov ecx, 14
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Broadcast second SIPI message with our vector
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov ICR_LOW[edi], ebx
+ ;
+ ; Wait for semaphore reflect number of CPUs
+ ;
+ mov eax, 1
+ cpuid
+ shr ebx, 16 ; Total Logical Proc Count in BL
+ dec bl ; bl is number of APs
+
+ mov edx, SemaphoreStatus2RetNS
+ mov ecx, 6670
+ CALL_NS ltWaitStatusRetNS ; Wait for up to 100ms
+ ;
+ ; Restore StartUp area
+ ;
+ lea esi, buffer ; Source
+ mov edi, 1000h ; Destination
+ mov ecx, sizeof StartUp / 4
+ CALL_NS MemCopyRetNS
+
+exit:
+ mov esp, savedESP
+ popad
+ ret
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Section: ApHandler16
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: Irrelevant
+;
+; Description: This code is copied over address 0:1000. After recieving SIPI
+; AP is directed to this address where it starts execution in real mode.
+; AP first switches to protected mode, loads the same GDT which is used
+; by BSP and jumps to Procedure at fCs:fOff
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+ ALIGN 16
+ ;
+ ; Note After coppying this code must be aligned on page boundary!
+ ;
+
+ApHandler16 StartUp <>
+
+StartupAllAPs ENDP
+
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: PutApsInWfs
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: All are preserved
+;
+; Description: Procedure is called in memory present environment on S3 resume path.
+; INIT SIPI message is sent to all APs.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+PutApsInWfs PROC PUBLIC
+ LOCAL savedESP:DWORD
+ pushad
+ mov savedESP, esp
+
+ mov eax, 1
+ cpuid
+ shr ebx, 16 ; Total Logical Proc Count in BL
+ cmp bl, 1 ; If 1 thread - nothing to do
+ je exit
+
+ ;
+ ; Get APIC address
+ ;
+ mov ecx, IA32_APIC_BASE
+ rdmsr ; Get APIC Base
+ and eax, BASE_ADDR_MASK ; Just need the address
+ mov edi, eax ; edi points to APIC base
+ ;
+ ; Broadcast INIT message to put all APs back into Wait for SIPI state
+ ; Wait for APIC ready
+ ;
+ mov edx, IcrStatusRetNs
+ mov ecx, 15
+ CALL_NS ltWaitStatusRetNS
+ ;
+ ; Send message
+ ;
+ mov DWORD PTR ICR_LOW[edi], 000C0500h
+
+ mov edx, NeverStatusRetNS
+ mov ecx, 667
+ CALL_NS ltWaitStatusRetNS ; Wait full 10ms
+
+exit:
+ mov esp, savedESP
+ popad
+ ret
+PutApsInWfs ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: LaunchBiosAcmScheck
+;
+; Input: None
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Setup GETSEC environment (protected mode, mtrrs, etc) and
+; invoke GETSEC:ENTERACCS with requested BIOS ACM entry point.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+LaunchBiosAcmScheck PROC PUBLIC, BiosAcAddr:PTR QWORD
+
+ LOCAL SavedGdtr:QWORD
+ LOCAL SavedSS:dword
+ LOCAL SavedESP:dword
+ LOCAL SavedCS:dword
+ LOCAL SavedCR3:dword
+ pushf
+ cli
+ pushad
+ ;
+ ; Tell where we are
+ ;
+ in ax, 80h
+ mov ah, PORT80_CODE_PREFIX + TXT_LAUNCH_SCHECK
+ out 80h, ax
+ ;
+ ; Save control registers
+ ;
+ mov eax, cr4
+ push eax
+ mov eax, cr0
+ push eax
+ ;
+ ; Save segment registers
+ ;
+ push ds
+ push es
+ push gs
+ push fs
+ ;
+ ; Save CS
+ ;
+ sub eax, eax ; Clean upper word
+ mov ax, cs
+ mov SavedCS, eax
+ ;
+ ; Save stack at this level
+ ;
+ mov ax, ss
+ mov SavedSS, eax
+ mov SavedESP, esp
+ mov eax, cr3
+ mov SavedCR3, eax
+
+ ;
+ ; Save GDT
+ ;
+ sgdt SavedGdtr ; save value of gdtr in local variable
+ ;
+ ; Define "local" vars for this routine
+ ;
+ SAVED_EBP TEXTEQU <mm4>
+ ;
+ ; Save ebp in MMX register
+ ;
+ movd SAVED_EBP, ebp ; Size of ACM that must be cached
+
+ ;
+ ; Enable SMXE, SSE and debug extensions always.
+ ;
+ mov eax, CR4
+ or eax, CR4_OSFXSR + CR4_DE + CR4_SMXE
+ mov CR4, eax
+ ;
+ ; Prepare cache of BSP
+ ;
+ mov esi, BiosAcAddr
+ mov edi, 1
+
+ CALL_NS PrepareCacheForAcModuleRetNS
+
+ CALL_NS CleanMcaRetNS
+
+ ;
+ ; Call GETSEC[ENTERACCS]
+ ;
+ mov eax, ENTERACCS ; eax = ENTERACCS
+ mov ebx, BiosAcAddr
+ mov ebx, [ebx]
+ mov ecx, [ebx].ACM_HEADER.AcmSize
+ shl ecx, 2
+ xor edx, edx
+ mov edi, S3_RESUME_PATH
+ mov esi, 4
+
+ _GETSEC
+
+ ;
+ ; Return point after ACEXIT.
+ ;
+ movd ebp, SAVED_EBP
+ lea eax, SavedGdtr
+ lgdt FWORD PTR [eax]
+ mov eax, SavedSS
+ mov ss, ax
+ mov esp, SavedESP
+ mov eax, SavedCR3
+ mov cr3, eax
+ ;
+ ; Restore segment registers
+ ;
+ pop fs
+ pop gs
+ pop es
+ pop ds
+ ;
+ ; Restore control registers
+ ;
+ pop eax
+ ;
+ ;remain cache disabled until MTRRs restored
+ ;
+ or eax, CR0_CD_MASK
+ and eax, NOT CR0_NW_MASK
+ wbinvd
+;
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ ;
+ ; Restore CS
+ ;
+ mov eax, SavedCS
+ push eax
+ push OFFSET ReloadCS
+ retf
+
+ReloadCS:
+ popad
+ popf
+ emms
+
+ ret
+LaunchBiosAcmScheck ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: RestoreMtrrProgramming
+;
+; Input: ApMtrrTab - pointer to save area
+;
+; Output: None
+;
+; Registers: All are preserved
+;
+; Description: Function is executed on BSP in memory present environment on S3
+; resume path. Restores contents of all MTRRs from table
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+RestoreMtrrProgramming PROC NEAR PUBLIC, ApMtrrTab:PTR QWORD
+ LOCAL savedESP:DWORD
+ pushad
+ mov savedESP, esp
+
+ mov esi, ApMtrrTab
+ CALL_NS RestoreMtrrProgrammingRetNS
+
+ mov esp, savedESP
+ popad
+ ret
+RestoreMtrrProgramming ENDP
+
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: RestoreMtrrProgrammingRetNS
+;
+; Input: esi - pointer to save area
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Restores contents of all MTRRs from table
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+RestoreMtrrProgrammingRetNS PROC NEAR PUBLIC
+ mov eax, cr0 ; set CR0:CD and CR0:NE, clear CR0:NW
+ or eax, CR0_CD_MASK OR CR0_NE_MASK
+ and eax, NOT CR0_NW_MASK
+ mov cr0, eax
+ wbinvd ; flush and invalidate the cache
+
+ xor edx, edx
+ mov eax, MTRR_ENABLE + MTRR_FIXED_ENABLE ; enable mtrrs
+ mov ecx, 2FFh
+ wrmsr
+
+ mov ecx, IA32_MTRR_CAP
+ rdmsr
+ and eax, 0FFh
+ shl eax, 1
+ mov ecx, eax
+
+@@:
+ add ecx, IA32_MTRR_PHYSBASE0 - 1
+ mov eax, [esi]
+ mov edx, [esi+4]
+ wrmsr
+ add esi, SIZEOF QWORD
+ sub ecx, IA32_MTRR_PHYSBASE0 - 1
+ loop @B
+
+ mov ecx, IA32_MTRR_DEF_TYPE
+ mov eax, [esi]
+ mov edx, [esi+4]
+ wrmsr
+ mov ecx, IA32_MISC_ENABLE_MSR
+ mov eax, [esi+010h]
+ mov edx, [esi+014h]
+ wrmsr
+
+ mov eax, cr0 ; Enable caching - WB (NW stays clear)
+ and eax, NOT CR0_CD_MASK
+ mov cr0, eax
+
+ RET_NS
+RestoreMtrrProgrammingRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: RestoreApConfig
+;
+; Input: esi - pointer to save area
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Function is executed on AP in memory present environment on S3
+; resume path. Restores contents of all MTRRs from table
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+RestoreApConfig PROC NEAR PUBLIC
+ mov eax, CR4
+ or eax, CR4_OSFXSR + CR4_DE
+ mov CR4, eax
+
+ mov esi, 1000h
+ mov ds, cs:[esi].StartUp.fDs
+ mov es, cs:[esi].StartUp.fDs
+ mov fs, cs:[esi].StartUp.fDs
+ mov gs, cs:[esi].StartUp.fDs
+ mov ss, cs:[esi].StartUp.fDs
+
+ mov esi, [esi].StartUp.fParam
+
+ CALL_NS RestoreMtrrProgrammingRetNS
+
+ lidt FWORD PTR [esi+8]
+
+ jmp updateSemaphore
+
+RestoreApConfig ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: DoApInit
+;
+; Input: Contents of startup area at 1000h
+;
+; Output: None
+;
+; Registers: None are preserved
+;
+; Description: Executed on AP. Persforms CPU initialization for running
+; of GETSEC
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+DoApInit PROC NEAR PUBLIC
+ mov eax, CR4
+ or eax, CR4_OSFXSR + CR4_DE + CR4_SMXE
+ mov CR4, eax
+
+ mov esi, 1000h
+ mov ds, cs:[esi].StartUp.fDs
+
+ mov esi, [esi].StartUp.fParam
+ mov edi, 1
+
+ CALL_NS PrepareCacheForAcModuleRetNS
+
+ CALL_NS CleanMcaRetNS
+
+updateSemaphore::
+ mov ecx, 1000h + StartUp.smphr
+ lock inc DWORD PTR [ecx]
+
+hltLoop:
+ cli
+ hlt
+ jmp hltLoop
+
+DoApInit ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: MemCopyRetNS
+;
+; Input: esi - from linear address
+; edi - to linear address
+; ecx - swap size in dwords
+; ds - flat segment
+;
+; Output: None
+;
+; Registers: None
+;
+; Description: Swaps contents of two input buffers.
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+
+MemCopyRetNS PROC NEAR
+
+start:
+ mov eax, ds:[esi] ; source
+ mov ds:[edi], eax
+ add esi, 4
+ add edi, 4
+ loop start
+ RET_NS
+MemCopyRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: ltWaitStatusRetNS
+;
+; Input: cx - Refresh bit Toggle count
+; 750000us = 50000 toggles
+; edx - offset of Status procedure
+;
+; Output: Z if status is met
+; NZ - timeout occured
+; NC - always
+;
+; Stack: Not available
+;
+; Registers: cx, ax, esp
+;
+; Description: Calls status procedure. If status is met - returns Z and
+; NZ otherwise.
+; Status procedure is required to return Z if status is met and
+; NZ if not
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+ltWaitStatusRetNS PROC NEAR
+
+ in al, PORTB ; Read initial setting.
+ and al, PORTBMASK ; Keep what we care about.
+ mov ah, al ; Keep a copy of the data.
+
+waitLoop:
+ CALL_NS edx ; Call status procedure.
+ jz exit ; Z - status met
+
+waitLoop0:
+ in al, PORTB
+ and al, PORTBMASK
+ cmp al, ah ; Refresh bit changed ?
+ je waitLoop0
+
+ mov ah, al
+ loop waitLoop
+ or ax, 1 ; Clear the ZERO flag - timeout.
+ ; This also clears C flag
+exit:
+ RET_NS
+ltWaitStatusRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: IcrStatusRetNS
+;
+; Input: ds: Flat, edi - xAPIC Base Address
+;
+; Output: Z if status is met
+;
+; Stack: Not available
+;
+; Registers: all are preserved
+;
+; Description: Returns Z if ICR is idle
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+IcrStatusRetNS PROC NEAR PUBLIC
+ test DWORD PTR ICR_LOW[edi], BIT12
+ RET_NS
+IcrStatusRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: SemaphoreStatusRetNS
+;
+; Input: ds: Flat
+;
+; Output: Z if status is met
+;
+; Stack: Not available
+;
+; Registers: all are preserved
+;
+; Description: Returns Z if semaphore is 0
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+SemaphoreStatusRetNS PROC NEAR PUBLIC
+ bswap eax
+ mov al, BYTE PTR [esi+SEMAPHORE]
+ cmp al, bl
+ bswap eax
+ RET_NS
+SemaphoreStatusRetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: SemaphoreStatus2RetNS
+;
+; Input: ds: Flat
+;
+; Output: Z if status is met
+;
+; Stack: Not available
+;
+; Registers: Upper byte of eax is modified
+;
+; Description: Returns Z if semaphore is 0
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+SemaphoreStatus2RetNS PROC NEAR PUBLIC
+ bswap eax
+ mov al, BYTE PTR [esi].StartUp.smphr
+ cmp al, bl
+ bswap eax
+ RET_NS
+SemaphoreStatus2RetNS ENDP
+
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+; Procedure: NeverStatusRetNS
+;
+; Input:
+;
+; Output: Z if status is met
+;
+; Stack: Not available
+;
+; Registers: All are preserved
+;
+; Description: Returns Z if ICR is idle
+;
+;-----------------------------------------------------------------------------
+;-----------------------------------------------------------------------------
+NeverStatusRetNS PROC NEAR PUBLIC
+ or dx, dx ; dx is never 0 so return is NZ
+ RET_NS
+NeverStatusRetNS ENDP
+
+
+
+END