summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm')
-rw-r--r--ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm1490
1 files changed, 1490 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm b/ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm
new file mode 100644
index 0000000..3b973d8
--- /dev/null
+++ b/ReferenceCode/Haswell/SampleCode/SecCore/Sec/Ia32/Flat32.asm
@@ -0,0 +1,1490 @@
+;
+; This file contains a 'Sample Driver' and is licensed as such
+; under the terms of your license agreement with Intel or your
+; vendor. This file may be modified by the user, subject to
+; the additional terms of the license agreement
+;
+;------------------------------------------------------------------------------
+;
+; Copyright (c) 1999 - 2013, Intel Corporation. All rights reserved.<BR>
+; 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:
+;
+; Flat32.asm
+;
+; Abstract:
+;
+; This is the code that goes from real-mode to protected mode.
+; It consumes the reset vector.
+;
+;------------------------------------------------------------------------------
+ INCLUDE Platform.inc
+ INCLUDE Ia32.inc
+ INCLUDE Chipset.inc
+ INCLUDE SecCore.inc
+
+.686p
+.xmm
+.model small, c
+
+EXTRN SecStartup:NEAR
+
+; ECP porting
+EXTRN PcdGet32 (PcdFlashMicrocodeFvBase):DWORD
+EXTRN PcdGet32 (PcdFlashMicrocodeFvSize):DWORD
+EXTRN PcdGet32 (PcdNemCodeCacheSize):DWORD
+EXTRN PcdGet32 (PcdNemCodeCacheBase):DWORD
+EXTRN PcdGet32 (PcdFlashAreaBaseAddress):DWORD
+EXTRN PcdGet32 (PcdTemporaryRamBase):DWORD
+EXTRN PcdGet32 (PcdTemporaryRamSize):DWORD
+EXTRN PcdGet64 (PcdPciExpressBaseAddress):QWORD
+
+_TEXT_REALMODE SEGMENT PARA PUBLIC USE16 'CODE'
+ ASSUME CS:_TEXT_REALMODE, DS:_TEXT_REALMODE
+
+;------------------------------------------------------------------------------
+;
+; SEC "Security" Code module.
+;
+; Transition to non-paged flat-model protected mode from a
+; hard-coded GDT that provides exactly two descriptors.
+; This is a bare bones transition to protected mode only
+; used for while in PEI and possibly DXE.
+;
+; IA32 specific cache as RAM modules
+;
+; After enabling protected mode, a far jump is executed to
+; TransferToPEI using the newly loaded GDT.
+; This code also enables the Cache-as-RAM
+;
+; RETURNS: none
+;
+; MMX Usage:
+; MM0 = BIST State
+; MM1 = Current Package Physical Info
+; [7:0] = Cluster ID
+; [15:8] = Total Prossor pacakge detected in system
+; [16] = BAD CMOS Flag
+; [17] = AuburnDale or ClarksField
+; [0] = AuburnDale
+; [1] = ClarksField
+; [18] = Contain SEC reset flag
+; CPU Only Reset Flag
+; [19] = Contain SEC reset flag
+; Power Good Reset Flag
+; [23:20] = Reserved
+; [31:24] = Reserved
+; MM2 = store common MAX & MIN ratio
+; MM3 = Patch Revision
+; MM4 = Patch Pointer
+; MM5 = Save time-stamp counter value high32bit
+; MM6 = Save time-stamp counter value low32bit.
+; MM7 = Used in CALL_MMX & RET_ESI micaro
+;
+;------------------------------------------------------------------------------
+
+; Nehalem Reset Boot Flow Start
+
+align 4
+_ModuleEntryPoint PROC NEAR C PUBLIC
+ ;
+ ; Save BIST state in MM0
+ ;
+ fninit ; clear any pending Floating point exceptions
+ movd mm0, eax
+
+ ;
+ ; Save time-stamp counter value
+ ; rdtsc load 64bit time-stamp counter to EDX:EAX
+ ;
+ rdtsc
+ movd mm5, edx
+ movd mm6, eax
+;----------------------------------------------------------------------------------------
+; "Merlin" support
+;----------------------------------------------------------------------------------------
+ xor eax, eax
+ mov es, ax
+ mov ax, cs
+ mov ds, ax
+
+;******************************************************************************
+; BEGIN WARM-START CHANGE
+;******************************************************************************
+;
+; PLATFORM-SPECIFIC EQUATES!
+; These equates define an address which has the following requirements
+; on the target platform:
+; 1. After booting DOS, the memory is not used by other DOS applications
+; or drivers (thus very platform/configuration specific).
+; Minimum of roughly 8 bytes required.
+; 2. The memory contents and address range are not affected by an INIT
+; 3. By default, after booting DOS, the first 4 bytes at this address
+; contain either 0 (cleared memory) or 0xFFFFFFFF.
+; 4. After booting DOS, the memory is writable
+;
+; It's expected that a manual inspection (using ITP) is performed to ensure
+; that the requirements are met. If the manual inspection fails, then a
+; different address must be identified, the below two equates must be
+; changed accordingly, and the platform firmware must be rebuilt.
+; Note that simply changing the platform hardware configuration could
+; break this firmware because drivers may be loaded differently in
+; memory, potentially using the address arbitrarily chosen here.
+;
+ ;
+ ; Check if value in magic address contains non-zero/non-FF value.
+ ; It should actually contain executable code, typically a jmp
+ ; instruction.
+ ;
+ mov ax, MAGIC_SEG
+ mov es, ax
+ mov al, BYTE PTR es:[MAGIC_ADDRESS_IN_SEG]
+
+ ; Check for zero value
+ cmp al, 0EAh ; EA is the FAR JMP opcode that Merlin inserts
+ jz LegacyBiosWarmStart
+
+ ; Check INIT# is asserted by port 0xCF9
+ mov dx, 0CF9h
+ in al, dx
+ cmp al, 04h
+ jnz NotWarmStart
+
+ ;
+ ; Issue hard reset due to client silicon limitations, CPU Only Reset is not supported.
+ ;
+ mov dx, 0CF9h
+ mov al, 06h
+ out dx, al
+
+LegacyBiosWarmStart:
+
+ ;
+ ; Check APIC_BASE_MSR.BIT8 to see if we're the BSP
+ ;
+ mov cx, MSR_APIC_BASE
+ rdmsr
+ test ah, 1
+ jz TightLoop
+ ;
+ ; We're the BSP, so jump to the magic address.
+ ;
+ DB 0EAh
+ DW MAGIC_ADDRESS_IN_SEG
+ DW MAGIC_SEG
+
+ ; Not reached
+NotWarmStart:
+
+;******************************************************************************
+; END WARM-START CHANGE
+;******************************************************************************
+
+ ;
+ ; Enter Protected mode.
+ ;
+ STATUS_CODE (01h) ; BSP_PROTECTED_MODE_START
+ mov esi, OFFSET GdtDesc
+ DB 66h
+ lgdt fword ptr cs:[si]
+ mov eax, cr0 ; Get control register 0
+ or eax, 00000003h ; Set PE bit (bit #0) & MP bit (bit #1)
+ mov cr0, eax ; Activate protected mode
+ mov eax, cr4 ; Get control register 4
+ or eax, 00000600h ; Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
+ mov cr4, eax
+
+ ;
+ ; Now we're in Protected16
+ ; Set up the selectors for protected mode entry
+ ;
+ mov ax, SYS_DATA_SEL
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ ;
+ ; Go to Protected32
+ ;
+ mov esi, offset NemInitLinearAddress
+ jmp fword ptr cs:[si]
+
+TightLoop:
+ cli
+ hlt
+ jmp TightLoop
+
+_ModuleEntryPoint ENDP
+_TEXT_REALMODE ENDS
+
+_TEXT_PROTECTED_MODE SEGMENT PARA PUBLIC USE32 'CODE'
+ ASSUME CS:_TEXT_PROTECTED_MODE, DS:_TEXT_PROTECTED_MODE
+
+CALL_MMX macro RoutineLabel
+
+ local ReturnAddress
+ mov esi, offset ReturnAddress
+ movd mm7, esi ; save ReturnAddress into MM7
+ jmp RoutineLabel
+ReturnAddress:
+
+endm
+
+RET_ESI macro
+
+ movd esi, mm7 ; restore ESP from MM7
+ jmp esi
+
+endm
+
+CALL_EBP macro RoutineLabel
+
+ local ReturnAddress
+ mov ebp, offset ReturnAddress
+ jmp RoutineLabel
+ReturnAddress:
+
+endm
+
+RET_EBP macro
+
+ jmp ebp ; restore ESP from EBP
+
+endm
+
+align 4
+ProtectedModeSECStart PROC NEAR PUBLIC
+
+ STATUS_CODE (02h)
+ CALL_MMX EnableAccessCSR
+
+ STATUS_CODE (03h)
+ CALL_EBP VeryEarlyMicrocodeUpdate
+
+ STATUS_CODE (04h)
+ CALL_MMX DetectNumOfCPUSocket
+
+ STATUS_CODE (05h)
+ CALL_MMX PlatformInitialization
+
+ STATUS_CODE (06h)
+ CALL_MMX InitializeNEM
+
+ STATUS_CODE (07h)
+ CALL_MMX EstablishStack
+
+ STATUS_CODE (08h)
+ jmp CallPeiCoreEntryPoint
+
+ProtectedModeSECStart ENDP
+
+EnableAccessCSR PROC NEAR PRIVATE
+ ;
+ ; get Bus number from CPUID[1] EBX[31:24]
+ ;
+
+ mov eax, 0Bh
+ mov ecx, 1
+ cpuid
+ mov esi, eax
+
+ mov eax, 1 ; bus 0
+ cpuid
+ bswap ebx
+ movzx eax, bl
+ movzx ebx, bl
+ shl eax, BSPApicIDSaveStart ; Save current BSP APIC ID in MM1[31:24]
+ mov cx, si
+ shr bl, cl ; get Bus number in BL
+ or eax, ebx
+ movd mm1, eax ; save Bus number MM1[7:0]
+
+ ;
+ ; Enable MM PCI-E Config Space
+ ; --cr-- use register symbol name; should upper 32 bit be cleared
+ ;
+ mov eax, 080000060h ; MCHBAR
+ mov dx, 0CF8h
+ out dx, eax
+ mov dx, 0CFCh
+ mov eax, 04h
+ out dx, eax
+ in eax, dx
+ or eax, MMCFG_BASE OR ENABLE
+ out dx, eax
+
+ ; Clear reset flag
+ movd eax, mm1
+ and eax, NOT BIT18+BIT19
+ movd mm1, eax
+
+ ;
+ ; Enable SPI prefetching and caching
+ ;
+ mov esi, PCH_LPC_BIOS_CNTL_PCI_ADDR ; Bus0:Dev31:Func0:RegDCh
+ and BYTE PTR es:[esi], NOT (11b SHL 2)
+ or BYTE PTR es:[esi], (10b SHL 2) ; D31:F0:RegDCh[3:2] = 10b
+
+ RET_ESI
+
+EnableAccessCSR ENDP
+
+; STATUS_CODE (03h)
+PlatformInitialization PROC NEAR PRIVATE
+
+ ;
+ ; Program PCI Express base address
+ ;
+
+ mov eax, 80000060h ; 0:0:0:60
+ mov dx, 0CF8h
+ out dx, eax
+ mov dx, 0CFCh
+ ;using Pcd instead
+ ;mov eax, 0e0000000h OR 00h OR 1
+; mov eax, DWORD PTR PcdGet64 (PcdPciExpressBaseAddress)
+ mov eax, DWORD PTR PCIEXPRESS_BASE_ADDRESS
+ or eax, (PCIEX_LENGTH_BIT_SETTING OR 1)
+ out dx, eax
+
+ ;
+ ; Enable Mch Bar
+ ;
+ mov esi, MCHBAR_REG
+ mov eax, (MCH_BASE_ADDRESS + 1)
+ mov Dword Ptr [esi], eax
+
+ ;
+ ; Enable RCRB in PCH.
+ ;
+ mov esi, PCH_LPC_RCRB_PCI_ADDR
+ mov eax, PCH_RCRB_BASE + 1
+ mov Dword Ptr [esi], eax
+
+ ;
+ ; Configure GPIO to be able to initiate LVL change for GPIO48 for S3 resume time calculation.
+ ;
+ ; Enable GPIO BASE I/O registers
+ ;
+ mov eax, PCI_LPC_BASE + 48h
+ mov dx, 0CF8h
+ out dx, eax
+ mov eax, GPIO_BASE_ADDRESS
+ add dx, 4
+ out dx, eax
+
+ mov eax, PCI_LPC_BASE + 4Ch
+ mov dx, 0CF8h
+ out dx, eax
+ add dx, 4
+ in al, dx
+ or al, BIT4 ; GPIOBASE Enable
+ out dx, al
+
+ ;GPIO_USE_SEL2 Register -> 1 = GPIO 0 = Native
+ mov dx, GPIO_BASE_ADDRESS + R_GPIO_USE_SEL2
+ in eax, dx
+ or eax, 010000h ;Enable GPIO48
+ out dx, eax
+
+ ;GP_IO_SEL2 Register -> 1 = Input 0 = Output (if Native Mode don't care)
+ mov dx, GPIO_BASE_ADDRESS + R_GPIO_IO_SEL2
+ in eax, dx
+ and eax, 0FFFEFFFFh ;Configure GPIO48 as Output
+ out dx, eax
+
+ mov dx, GPIO_BASE_ADDRESS + R_GPIO_LVL2
+ in eax, dx
+ or eax, 010000h ;Configure GPIO48 as High
+ out dx, eax
+
+ ;
+ ; Program and Enable ACPI PM Base.
+ ;
+ mov esi, PCH_LPC_PMBASE_PCI_ADDR
+ mov eax, PCH_ACPI_BASE_ADDRESS + 1
+ mov Dword Ptr [esi], eax
+ mov esi, PCH_LPC_ACPICNTL_PCI_ADDR
+ or Dword Ptr [esi], 00000080h
+
+ ;
+ ; PCH BIOS Spec Rev 0.5.0 Section 12.9
+ ; Additional Programming Requirements for USB Support
+ ; Step 2.b
+ ; Clear RCBA + 3598h [0] to 0b
+ ;
+ mov esi, PCH_RCRB_BASE + 3598h
+ mov eax, 0
+ mov Dword Ptr [esi], eax
+
+ ;
+ ; Enable HPET decode in PCH.
+ ;
+ mov esi, PCH_RCRB_BASE + PCH_RCRB_HPET
+ mov eax, PCH_RCRB_HPET_DECODE
+ mov Dword Ptr [esi], eax
+ mov eax, Dword ptr [esi]
+ xor eax, eax
+ mov esi, HPET_COMP_1
+ mov Dword Ptr [esi], eax
+ mov esi, HPET_COMP_2
+ mov Dword ptr [esi], eax
+
+ ;
+ ; Enable the upper 128-byte bank of RTC RAM.
+ ;
+ mov esi, PCH_RCRB_BASE + PCH_RCRB_RTC_CONF
+ mov eax, Dword Ptr [esi]
+ or eax, PCH_RCRB_RTC_CONF_UCMOS_EN
+ mov Dword Ptr [esi], eax
+
+ ;
+ ; Choose Port80 Route
+ ;
+ mov esi, PCH_RCRB_BASE + PCH_RCRB_GCS
+ mov ebx, Dword Ptr [esi]
+ or bl, BIT5
+
+ ;
+ ; check SETUP option - PchPort80Route
+ ; 0 = LPC {Default]; 1 = PCI
+ ;
+; mov al, CMOS_PCH_PORT80_OFFSET ; CMOS Offset = 17h
+; mov dx, RTC_UPPER_INDEX
+; out dx, al
+; inc dx
+; in al, dx
+; test al, BIT0
+; jnz @F
+ and bl, NOT (BIT2) ; Port80h to LPC
+;@@:
+ mov Dword Ptr [esi], ebx
+
+ ;
+ ; Halt TCO Timer
+ ;
+ mov dx, 0468h
+ in ax, dx
+ or ax, BIT11
+ out dx, ax
+
+ ;
+ ; Clear the Second TO status bit
+ ;
+ mov dx, 0466h
+ in ax, dx
+ or ax, BIT1
+ out dx, ax
+
+ RET_ESI
+
+PlatformInitialization ENDP
+
+; STATUS_CODE (03h)
+DetectNumOfCPUSocket PROC NEAR PRIVATE
+
+ ; only one socket
+ movd eax, mm1 ; get MM1 value into EAX
+ mov ah, 01
+ movd mm1, eax ; save CPU pkg count into MM1[15:8]
+
+ RET_ESI
+
+DetectNumOfCPUSocket ENDP
+
+; STATUS_CODE (07h)
+VeryEarlyMicrocodeUpdate PROC NEAR PRIVATE
+
+IF EARLY_MICROCODE_SUPPORT
+ mov ecx, IA32_BIOS_SIGN_ID
+ rdmsr ; CPU PatchID -> EDX
+ cmp edx, 0 ; If microcode has been updated
+ jnz luExit ; Skip if patch already loaded
+
+ mov ecx, IA32_PLATFORM_ID ; To get Platform ID.
+ rdmsr
+ shr edx, 18 ; EDX[0-2] = Platform ID.
+ and dx, 07h ; DX = Platform ID.
+ mov si, dx ; Save Platform ID in FS.
+ mov eax, 01h ; To get CPU signature.
+ cpuid ; EAX = CPU signature.
+ mov cx, si ; CX = Platform ID
+ xor edx, edx
+ bts dx, cx ; EDX = Platform ID bit.
+
+; mov esi, PcdGet32 (PcdFlashMicrocodeFvBase)
+ mov esi, MICROCODE_FV_BASE_ADDRESS
+
+ mov ebx, esi
+ mov bx, FVHEADER_LEN_OFF
+ movzx ebx, WORD PTR [ebx]
+ add esi, ebx
+ add si, FFSHEADER_LEN ; add FFS header
+
+; mov edi, PcdGet32 (PcdFlashMicrocodeFvBase)
+; mov ebx, PcdGet32 (PcdFlashMicrocodeFvSize)
+ mov edi, MICROCODE_FV_BASE_ADDRESS
+ mov ebx, MICROCODE_FV_SIZE
+ add edi, ebx ;End addr of uCodes.
+
+ ; EAX = CPU signature.
+ ; EDX = Platform ID bit.
+ ; ESI = Abs addr of contiguous uCode blocks.
+ ; EDI = Abs addr of contiguous uCode blocks end.
+
+luCheckPatch:
+ cmp (UpdateHeaderStruc PTR ds:[esi]).dProcessorSignature, eax;Sig matched?
+ jnz luCheckUnprogrammed ; No.
+ test (UpdateHeaderStruc PTR ds:[esi]).dProcessorFlags, edx;Platform matched?
+ jnz luFoundMatch ; Yes.
+
+luCheckUnprogrammed:
+ mov ebx, (UpdateHeaderStruc PTR ds:[esi]).dDataSize
+ cmp ebx, 0FFFFFFFFh
+ je luUnprogrammed
+ cmp (UpdateHeaderStruc PTR ds:[esi]).dLoaderRevision, 1
+ je luCheckExtdHdrs
+
+luUnprogrammed:
+ mov ebx, 1024 ; Unprogrammed space, 1KB checks
+ jmp luPoinToNextBlock ; for backword compatibility.
+
+luCheckExtdHdrs:
+ add ebx, SIZEOF(UpdateHeaderStruc)
+ cmp ebx, (UpdateHeaderStruc PTR ds:[esi]).dTotalSize
+ jae luTryNextPatch ; No extd hdrs.
+
+ mov ecx, DWORD PTR ds:[esi + ebx]
+ jcxz luTryNextPatch ; No extd hdrs. (OK to use CX instead of ECX).
+ add ebx, 20 ; Point to the first Extd Sig.
+luNextSig:
+ cmp eax, DWORD PTR ds:[esi + ebx] ;Sig matched?
+ jne lu_00
+ test edx, DWORD PTR ds:[esi + ebx + 4] ;Platform matched?
+ jnz luFoundMatch
+lu_00:
+ add ebx, 12
+ loop luNextSig
+
+luTryNextPatch:
+ mov ebx, (UpdateHeaderStruc PTR ds:[esi]).dTotalSize
+ or ebx, ebx
+ jnz luPoinToNextBlock ; Variable size uCode format.
+ mov ebx, BLOCK_LENGTH_BYTES ; Fixed size uCode format.
+
+;
+; Add alignment check - begin
+;
+ test ebx, 0400h
+ jz @F
+ add ebx, 0400h
+@@:
+;
+; Add alignment check - end
+;
+
+luPoinToNextBlock:
+ add esi, ebx
+ cmp esi, edi
+ jb luCheckPatch ; Check with all patches.
+
+ ; Check possible multiple patch
+ movd eax, mm3
+ movd esi, mm4
+ or eax, eax
+ jnz luLoadPatch
+ jmp luExit ; No matching patch found.
+
+luFoundMatch:
+; MM3 = Patch Revision
+; MM4 = Patch Pointer
+ movd ebx, mm3
+ cmp (UpdateHeaderStruc PTR ds:[esi]).dUpdateRevision, ebx
+ jb luTryNextPatch
+
+ mov ebx, (UpdateHeaderStruc PTR ds:[esi]).dUpdateRevision
+
+luStoreRevPtr:
+ movd mm3, ebx ; save Patch Revision
+ movd mm4, esi ; save Patch Pointer
+ jmp luTryNextPatch
+
+luLoadPatch:
+ mov ecx, IA32_BIOS_UPDT_TRIG
+ mov eax, esi ; EAX - Abs addr of uCode patch.
+ add eax, SIZEOF(UpdateHeaderStruc) ; EAX - Abs addr of uCode data.
+ xor edx, edx ; EDX:EAX - Abs addr of uCode data.
+ wrmsr ; Trigger uCode load.
+
+luExit:
+
+ENDIF
+
+ RET_EBP
+VeryEarlyMicrocodeUpdate ENDP
+
+
+; STATUS_CODE (09h)
+;************************************************************
+; Description:
+;
+; This function initializes the Cache for Data, Stack, and Code
+; as specified in the BIOS Writer's Guide.
+;************************************************************
+InitializeNEM PROC NEAR PRIVATE
+IFDEF BOOT_GUARD_SUPPORT_FLAG
+ ;
+ ; Detect Boot Guard Boot
+ ;
+ mov ecx, MSR_BOOT_GUARD_SACM_INFO ;
+ rdmsr
+ and eax, 01h
+ jnz BootGuardNemSetup
+ENDIF
+
+ ;
+ ; Enable cache for use as stack and for caching code
+ ; The algorithm is specified in the processor BIOS writer's guide
+ ;
+
+ ;
+ ; Ensure that the system is in flat 32 bit protected mode.
+ ;
+ ; Platform Specific - configured earlier
+ ;
+ ; Ensure that only one logical processor in the system is the BSP.
+ ; (Required step for clustered systems).
+ ;
+ ; Platform Specific - configured earlier
+
+ ; Ensure all APs are in the Wait for SIPI state.
+ ; This includes all other logical processors in the same physical processor
+ ; as the BSP and all logical processors in other physical processors.
+ ; If any APs are awake, the BIOS must put them back into the Wait for
+ ; SIPI state by issuing a broadcast INIT IPI to all excluding self.
+ ;
+ mov edi, APIC_ICR_LO ; 0FEE00300h - Send INIT IPI to all excluding self
+ mov eax, ORAllButSelf + ORSelfINIT ; 0000C4500h
+ mov [edi], eax
+
+@@:
+ mov eax, [edi]
+ bt eax, 12 ; Check if send is in progress
+ jc @B ; Loop until idle
+
+ ;
+ ; Load microcode update into BSP.
+ ;
+ ; Ensure that all variable-range MTRR valid flags are clear and
+ ; IA32_MTRR_DEF_TYPE MSR E flag is clear. Note: This is the default state
+ ; after hardware reset.
+ ;
+ ; Platform Specific - MTRR are usually in default state.
+ ;
+
+ ;
+ ; Initialize all fixed-range and variable-range MTRR register fields to 0.
+ ;
+ mov ecx, IA32_MTRR_CAP ; get variable MTRR support
+ rdmsr
+ movzx ebx, al ; EBX = number of variable MTRR pairs
+ shl ebx, 2 ; *4 for Base/Mask pair and WORD size
+ add ebx, MtrrCountFixed * 2 ; EBX = size of Fixed and Variable MTRRs
+
+ xor eax, eax ; Clear the low dword to write
+ xor edx, edx ; Clear the high dword to write
+ ;;;mov ebx, MtrrCount * 2 ; ebx <- sizeof MtrrInitTable
+InitMtrrLoop:
+ add ebx, -2
+ movzx ecx, WORD PTR cs:MtrrInitTable[ebx] ; ecx <- address of mtrr to zero
+ wrmsr
+ jnz InitMtrrLoop ; loop through the whole table
+
+ ;
+ ; Configure the default memory type to un-cacheable (UC) in the
+ ; IA32_MTRR_DEF_TYPE MSR.
+ ;
+ mov ecx, MTRR_DEF_TYPE ; Load the MTRR default type index
+ rdmsr
+ and eax, NOT (00000CFFh) ; Clear the enable bits and def type UC.
+ wrmsr
+
+ ; Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB
+ ; based on the physical address size supported for this processor
+ ; This is based on read from CPUID EAX = 080000008h, EAX bits [7:0]
+ ;
+ ; Examples:
+ ; MTRR_PHYS_MASK_HIGH = 00000000Fh For 36 bit addressing
+ ; MTRR_PHYS_MASK_HIGH = 0000000FFh For 40 bit addressing
+ ;
+ mov eax, 80000008h ; Address sizes leaf
+ cpuid
+ sub al, 32
+ movzx eax, al
+ xor esi, esi
+ bts esi, eax
+ dec esi ; esi <- MTRR_PHYS_MASK_HIGH
+
+ ;
+ ; Configure the DataStack region as write-back (WB) cacheable memory type
+ ; using the variable range MTRRs.
+ ;
+
+ ;
+ ; Set the base address of the DataStack cache range
+ ;
+; mov eax, PcdGet32 (PcdTemporaryRamBase)
+ mov eax, TEMPORARY_RAM_BASE_ADDRESS
+ or eax, MTRR_MEMORY_TYPE_WB
+ ; Load the write-back cache value
+ xor edx, edx ; clear upper dword
+ mov ecx, MTRR_PHYS_BASE_0 ; Load the MTRR index
+ wrmsr ; the value in MTRR_PHYS_BASE_0
+
+ ;
+ ; Set the mask for the DataStack cache range
+ ; Compute MTRR mask value: Mask = NOT (Size - 1)
+ ;
+; mov eax, PcdGet32 (PcdTemporaryRamSize)
+ mov eax, TEMPORARY_RAM_SIZE
+ dec eax
+ not eax
+ or eax, MTRR_PHYS_MASK_VALID
+ ; turn on the Valid flag
+ mov edx, esi ; edx <- MTRR_PHYS_MASK_HIGH
+ mov ecx, MTRR_PHYS_MASK_0 ; For proper addressing above 4GB
+ wrmsr ; the value in MTRR_PHYS_BASE_0
+
+ ;
+ ; Configure the BIOS code region as write-protected (WP) cacheable
+ ; memory type using a single variable range MTRR.
+ ;
+ ; Platform Specific - ensure region to cache meets MTRR requirements for
+ ; size and alignment.
+ ;
+
+ ;
+ ; Save MM5 into ESP before program MTRR, because program MTRR will use MM5 as the local variable.
+ ; And, ESP is not initialized before CAR is enabled. So, it is safe ot use ESP here.
+ ;
+ movd esp, mm5
+
+ ;
+ ; Get total size of cache from PCD if it need fix value
+ ;
+; mov eax, PcdGet32 (PcdNemCodeCacheSize)
+ mov eax, CODE_CACHE_SIZE
+ ;
+ ; Calculate NEM size
+ ; Determine LLC size by following RS - Haswell Processor Family BIOS Writer's Guide (BWG) 0.3.0
+ ; Section 4.4.5 - The size of the code region and data region combined must not exceed the size
+ ; of the (Last Level Cache - 0.5MB).
+ ;
+ ; Determine Cache Parameter by CPUID Function 04h
+ ;
+ xor ecx, ecx
+ xor edi, edi
+
+Find_LLC_parameter:
+ mov ecx, edi
+ mov eax, 4
+ cpuid
+ inc edi
+ and eax, 01Fh ; If EAX[4:0]=0, which indicates no more caches, then we can get LLC parameters
+ jnz Find_LLC_parameter
+ ;
+ ; LLC configuration is pointed to edi-2
+ ;
+ dec edi
+ dec edi
+ mov ecx, edi
+ mov eax, 4
+ cpuid
+ ;
+ ; Got LLC parameters
+ ;
+ ; This Cache Size in Bytes = (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1)
+ ; = (EBX[31:22] + 1) * (EBX[21:12] + 1) * (EBX[11:0] + 1) * (ECX + 1)
+ ;
+ mov eax, ecx
+ inc eax
+ mov edi, ebx
+ shr ebx, 22
+ inc ebx
+ mul ebx
+ mov ebx, edi
+ and ebx, NOT 0FFC00FFFh
+ shr ebx, 12
+ inc ebx
+ mul ebx
+ mov ebx, edi
+ and ebx, 0FFFh
+ inc ebx
+ mul ebx
+ ;
+ ; Maximum NEM size <= (Last Level Cache - 0.5MB)
+ ;
+ sub eax, 512*1024
+Got_NEM_size:
+ ;
+ ; Code cache size = Total NEM size - DataStack size
+ ;
+; sub eax, PcdGet32 (PcdTemporaryRamSize)
+ sub eax, TEMPORARY_RAM_SIZE
+ ;
+ ; Set the base address of the CodeRegion cache range from PCD
+ ; PcdNemCodeCacheBase is set to the offset to flash base,
+ ; so add PcdFlashAreaBaseAddress to get the real code base address.
+ ;
+; mov edi, PcdGet32 (PcdNemCodeCacheBase)
+; add edi, PcdGet32 (PcdFlashAreaBaseAddress)
+ mov edi, CODE_CACHE_BASE_ADDRESS
+ add edi, FLASH_AREA_BASE_ADDRESS
+
+ ;
+ ; Round up to page size
+ ;
+ mov ecx, eax ; Save
+ and ecx, 0FFFF0000h ; Number of pages in 64K
+ and eax, 0FFFFh ; Number of "less-than-page" bytes
+ jz Rounded
+ mov eax, 10000h ; Add the whole page size
+
+Rounded:
+ add eax, ecx ; eax - rounded up code cache size
+
+ ;
+ ; Define "local" vars for this routine
+ ; Note that mm0 is used to store BIST result for BSP,
+ ; mm1 is used to store the number of processor and BSP APIC ID,
+ ; mm6 is used to save time-stamp counter value.
+ ;
+ CODE_SIZE_TO_CACHE TEXTEQU <mm3>
+ CODE_BASE_TO_CACHE TEXTEQU <mm4>
+ NEXT_MTRR_INDEX TEXTEQU <mm5>
+ NEXT_MTRR_SIZE TEXTEQU <mm2>
+ ;
+ ; Initialize "locals"
+ ;
+ sub ecx, ecx
+ movd NEXT_MTRR_INDEX, ecx ; Count from 0 but start from MTRR_PHYS_BASE_1
+
+ ;
+ ; Save remaining size to cache
+ ;
+ movd CODE_SIZE_TO_CACHE, eax ; Size of code cache region that must be cached
+ movd CODE_BASE_TO_CACHE, edi ; Base code cache address
+
+NextMtrr:
+ ;
+ ; Get remaining size to cache
+ ;
+ movd eax, CODE_SIZE_TO_CACHE
+ and eax, eax
+ jz CodeRegionMtrrdone ; 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 edi, CODE_BASE_TO_CACHE
+ bsf ecx, edi ; 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_PHYS_MASK_VALID ; Set valid bit
+
+ ;
+ ; Program mask register
+ ;
+ mov ecx, MTRR_PHYS_MASK_1 ; setup variable mtrr
+ movd ebx, NEXT_MTRR_INDEX
+ add ecx, ebx
+
+ mov edx, esi ; edx <- MTRR_PHYS_MASK_HIGH
+ wrmsr
+ ;
+ ; Program base register
+ ;
+ sub edx, edx
+ mov ecx, MTRR_PHYS_BASE_1 ; setup variable mtrr
+ add ecx, ebx ; ebx is still NEXT_MTRR_INDEX
+
+ movd eax, CODE_BASE_TO_CACHE
+ or eax, MTRR_MEMORY_TYPE_WP ; set type to write protect
+ wrmsr
+ ;
+ ; Advance and loop
+ ; Reduce remaining size to cache
+ ;
+ movd ebx, CODE_SIZE_TO_CACHE
+ movd eax, NEXT_MTRR_SIZE
+ sub ebx, eax
+ movd CODE_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, CODE_BASE_TO_CACHE
+ movd eax, NEXT_MTRR_SIZE
+ add ebx, eax
+ ;
+ ; if carry happens, means NEM base + size over 4G
+ ;
+ jc CodeRegionMtrrdone
+ movd CODE_BASE_TO_CACHE, ebx
+
+ jmp NextMtrr
+
+CodeRegionMtrrdone:
+ ; Program the variable MTRR's MASK register for WDB
+ ; (Write Data Buffer, used in MRC, must be WC type)
+ ;
+ mov ecx, MTRR_PHYS_MASK_1
+ movd ebx, NEXT_MTRR_INDEX
+ add ecx, ebx
+ mov edx, esi ; edx <- MTRR_PHYS_MASK_HIGH
+ mov eax, WDB_REGION_SIZE_MASK OR MTRR_PHYS_MASK_VALID ; turn on the Valid flag
+ wrmsr
+
+ ;
+ ; Program the variable MTRR's BASE register for WDB
+ ;
+ dec ecx
+ xor edx, edx
+ mov eax, WDB_REGION_BASE_ADDRESS OR MTRR_MEMORY_TYPE_WC
+ wrmsr
+
+ ;
+ ; Enable the MTRRs by setting the IA32_MTRR_DEF_TYPE MSR E flag.
+ ;
+ mov ecx, MTRR_DEF_TYPE ; Load the MTRR default type index
+ rdmsr
+ or eax, MTRR_DEF_TYPE_E ; Enable variable range MTRRs
+ wrmsr
+
+ ;
+ ; Enable the logical processor's (BSP) cache: execute INVD and set
+ ; CR0.CD = 0, CR0.NW = 0.
+ ;
+ mov eax, cr0
+ and eax, NOT (CR0_CACHE_DISABLE + CR0_NO_WRITE)
+ invd
+ mov cr0, eax
+ ;
+ ; Enable No-Eviction Mode Setup State by setting
+ ; NO_EVICT_MODE MSR 2E0h bit [0] = '1'.
+ ;
+ mov ecx, NO_EVICT_MODE
+ rdmsr
+ or eax, 1
+ wrmsr
+
+ ;
+ ; Restore MM5 from ESP after program MTRR
+ ;
+ movd mm5, esp
+
+ ;
+ ; One location in each 64-byte cache line of the DataStack region
+ ; must be written to set all cache values to the modified state.
+ ;
+; mov edi, PcdGet32 (PcdTemporaryRamBase)
+; mov ecx, PcdGet32 (PcdTemporaryRamSize)
+ mov edi, TEMPORARY_RAM_BASE_ADDRESS
+ mov ecx, TEMPORARY_RAM_SIZE
+ shr ecx, 6
+ mov eax, CACHE_INIT_VALUE
+@@:
+ mov [edi], eax
+ sfence
+ add edi, 64
+ loopd @b
+
+ ;
+ ; Enable No-Eviction Mode Run State by setting
+ ; NO_EVICT_MODE MSR 2E0h bit [1] = '1'.
+ ;
+ mov ecx, NO_EVICT_MODE
+ rdmsr
+ or eax, 2
+ wrmsr
+
+IFDEF BOOT_GUARD_SUPPORT_FLAG
+ jmp FinishedCacheConfig
+
+ ;
+ ; Jump to here when Boot Guard boot and NEM is initialized by Boot Guard ACM
+ ;
+BootGuardNemSetup:
+ ;
+ ; Finished with cache configuration
+ ;
+ ; Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB
+ ; based on the physical address size supported for this processor
+ ; This is based on read from CPUID EAX = 080000008h, EAX bits [7:0]
+ ;
+ ; Examples:
+ ; MTRR_PHYS_MASK_HIGH = 00000000Fh For 36 bit addressing
+ ; MTRR_PHYS_MASK_HIGH = 0000000FFh For 40 bit addressing
+ ;
+ mov eax, 80000008h ; Address sizes leaf
+ cpuid
+ sub al, 32
+ movzx eax, al
+ xor esi, esi
+ bts esi, eax
+ dec esi ; esi <- MTRR_PHYS_MASK_HIGH
+
+ ;
+ ; Configure the DataStack region as write-back (WB) cacheable memory type
+ ; using the variable range MTRRs.
+ ;
+ ;
+ ; Find available MTRR
+ ;
+ CALL_EBP FindFreeMtrr
+
+ ;
+ ; Set the base address of the DataStack cache range
+ ;
+; mov eax, PcdGet32 (PcdTemporaryRamBase)
+ mov eax, TEMPORARY_RAM_BASE_ADDRESS
+ or eax, MTRR_MEMORY_TYPE_WB
+ ; Load the write-back cache value
+ xor edx, edx ; clear upper dword
+ wrmsr ; the value in MTRR_PHYS_BASE_0
+
+ ;
+ ; Set the mask for the DataStack cache range
+ ; Compute MTRR mask value: Mask = NOT (Size - 1)
+ ;
+; mov eax, PcdGet32 (PcdTemporaryRamSize)
+ mov eax, TEMPORARY_RAM_SIZE
+ dec eax
+ not eax
+ or eax, MTRR_PHYS_MASK_VALID
+ ; turn on the Valid flag
+ mov edx, esi ; edx <- MTRR_PHYS_MASK_HIGH
+ inc ecx
+ wrmsr ; the value in MTRR_PHYS_BASE_0
+
+ ;
+ ; Program the variable MTRR's MASK register for WDB
+ ; (Write Data Buffer, used in MRC, must be WC type)
+ ;
+
+ ;
+ ; Find available MTRR
+ ;
+ CALL_EBP FindFreeMtrr
+
+FoundAvailableMtrr:
+ ;
+ ; Program the variable MTRR's BASE register for WDB
+ ;
+ xor edx, edx
+ mov eax, WDB_REGION_BASE_ADDRESS OR MTRR_MEMORY_TYPE_WC
+ wrmsr
+
+ inc ecx
+ mov edx, esi ; edx <- MTRR_PHYS_MASK_HIGH
+ mov eax, WDB_REGION_SIZE_MASK OR MTRR_PHYS_MASK_VALID ; turn on the Valid flag
+ wrmsr
+
+ ;
+ ; One location in each 64-byte cache line of the DataStack region
+ ; must be written to set all cache values to the modified state.
+ ;
+; mov edi, PcdGet32 (PcdTemporaryRamBase)
+; mov ecx, PcdGet32 (PcdTemporaryRamSize)
+ mov edi, TEMPORARY_RAM_BASE_ADDRESS
+ mov ecx, TEMPORARY_RAM_SIZE
+ shr ecx, 6
+ mov eax, CACHE_INIT_VALUE
+@@:
+ mov [edi], eax
+ sfence
+ add edi, 64
+ loopd @b
+ENDIF
+
+ ;
+ ; Finished with cache configuration
+ ;
+FinishedCacheConfig:
+
+ ;
+ ; Optionally Test the Region...
+ ;
+
+ ;
+ ; Test area by writing and reading
+ ;
+ cld
+; mov edi, PcdGet32 (PcdTemporaryRamBase)
+; mov ecx, PcdGet32 (PcdTemporaryRamSize)
+ mov edi, TEMPORARY_RAM_BASE_ADDRESS
+ mov ecx, TEMPORARY_RAM_SIZE
+ shr ecx, 2
+ mov eax, CACHE_TEST_VALUE
+TestDataStackArea:
+ stosd
+ cmp eax, DWORD PTR [edi-4]
+ jnz DataStackTestFail
+ loop TestDataStackArea
+ jmp DataStackTestPass
+
+ ;
+ ; Cache test failed
+ ;
+DataStackTestFail:
+ STATUS_CODE (0D0h)
+ jmp $
+
+ ;
+ ; Configuration test failed
+ ;
+ConfigurationTestFailed:
+ STATUS_CODE (0D1h)
+ jmp $
+
+DataStackTestPass:
+
+ ;
+ ; At this point you may continue normal execution. Typically this would include
+ ; reserving stack, initializing the stack pointer, etc.
+ ;
+
+ ;
+ ; After memory initialization is complete, please follow the algorithm in the BIOS
+ ; Writer's Guide to properly transition to a normal system configuration.
+ ; The algorithm covers the required sequence to properly exit this mode.
+ ;
+
+ RET_ESI
+
+InitializeNEM ENDP
+
+; STATUS_CODE (09h)
+EstablishStack PROC NEAR PRIVATE
+
+ ;
+ ; Enable STACK
+ ;
+ RET_ESI
+
+EstablishStack ENDP
+
+FindFreeMtrr PROC NEAR PRIVATE
+ mov ecx, MTRR_PHYS_MASK_0
+
+@@:
+ rdmsr
+ test eax, 800h
+ jz FoundFreeMtrr
+ add ecx, 2
+ cmp ecx, MTRR_PHYS_MASK_9
+ jbe @b
+ ;
+ ; No available MTRR, halt system
+ ;
+ jmp $
+
+FoundFreeMtrr:
+ dec ecx
+
+ RET_EBP
+
+FindFreeMtrr ENDP
+
+; STATUS_CODE (0Bh)
+CallPeiCoreEntryPoint PROC NEAR PRIVATE
+ ;
+ ; Set stack top pointer
+ ;
+; mov esp, PcdGet32 (PcdTemporaryRamBase)
+; add esp, PcdGet32 (PcdTemporaryRamSize)
+ mov esp, TEMPORARY_RAM_BASE_ADDRESS
+ add esp, TEMPORARY_RAM_SIZE
+
+ ;
+ ; Push CPU count to stack first, then AP's (if there is one)
+ ; BIST status, and then BSP's
+ ;
+
+ ;
+ ; Here work around for BIST
+ ;
+ ; Get number of BSPs
+ movd ecx, mm1
+ movzx ecx, ch
+
+ ; Save number of BSPs
+ push ecx
+
+GetSBSPBist:
+ ; Save SBSP BIST
+ movd eax, mm0
+ push eax
+
+ ; Save SBSP APIC ID
+ movd eax, mm1
+ shr eax, BSPApicIDSaveStart ; Resume APIC ID
+ push eax
+
+ ; Save Time-Stamp Counter
+ movd eax, mm5
+ push eax
+
+ movd eax, mm6
+ push eax
+
+TransferToSecStartup:
+
+
+
+ ; Switch to "C" code
+ STATUS_CODE (0Ch)
+ ;
+ ; Pass entry point of the PEI core
+ ;
+ mov edi, PEI_CORE_ENTRY_BASE ; 0FFFFFFE0h
+ push DWORD PTR ds:[edi]
+
+ ;
+ ; Pass BFV into the PEI Core
+ ;
+ mov edi, FV_MAIN_BASE ; 0FFFFFFFCh
+ push DWORD PTR ds:[edi]
+
+ ; ECPoverride: SecStartup entry point needs 4 parameters
+; push PcdGet32 (PcdTemporaryRamBase)
+ push TEMPORARY_RAM_BASE_ADDRESS
+
+ ;
+ ; Pass stack size into the PEI Core
+ ;
+; push PcdGet32 (PcdTemporaryRamSize)
+ push TEMPORARY_RAM_SIZE
+
+ ;
+ ; Pass Control into the PEI Core
+ ;
+ call SecStartup
+CallPeiCoreEntryPoint ENDP
+
+StartUpAp PROC NEAR
+
+ mov esi, HPET_COMP_2
+ lock inc byte ptr [esi]
+
+ DISABLE_CACHE
+;
+; Halt the AP and wait for the next SIPI
+;
+Ap_Halt:
+ cli
+@@:
+ hlt
+ jmp @B
+ ret
+StartUpAp ENDP
+
+
+CheckValidCMOS PROC NEAR PRIVATE
+ ;
+ ; Check CMOS Status
+ ;
+ mov esi, PCH_LPC_GEN_PMCON_3_ADDR
+ mov eax, es:[esi]
+
+ ; check PWR_FLR and RTC_PWR_STS status
+ and eax, BIT2 + BIT1
+
+ RET_EBP
+CheckValidCMOS ENDP
+
+MtrrInitTable LABEL BYTE
+ DW MTRR_DEF_TYPE
+ DW MTRR_FIX_64K_00000
+ DW MTRR_FIX_16K_80000
+ DW MTRR_FIX_16K_A0000
+ DW MTRR_FIX_4K_C0000
+ DW MTRR_FIX_4K_C8000
+ DW MTRR_FIX_4K_D0000
+ DW MTRR_FIX_4K_D8000
+ DW MTRR_FIX_4K_E0000
+ DW MTRR_FIX_4K_E8000
+ DW MTRR_FIX_4K_F0000
+ DW MTRR_FIX_4K_F8000
+
+MtrrCountFixed EQU (($ - MtrrInitTable) / 2)
+
+ DW MTRR_PHYS_BASE_0
+ DW MTRR_PHYS_MASK_0
+ DW MTRR_PHYS_BASE_1
+ DW MTRR_PHYS_MASK_1
+ DW MTRR_PHYS_BASE_2
+ DW MTRR_PHYS_MASK_2
+ DW MTRR_PHYS_BASE_3
+ DW MTRR_PHYS_MASK_3
+ DW MTRR_PHYS_BASE_4
+ DW MTRR_PHYS_MASK_4
+ DW MTRR_PHYS_BASE_5
+ DW MTRR_PHYS_MASK_5
+ DW MTRR_PHYS_BASE_6
+ DW MTRR_PHYS_MASK_6
+ DW MTRR_PHYS_BASE_7
+ DW MTRR_PHYS_MASK_7
+ DW MTRR_PHYS_BASE_8
+ DW MTRR_PHYS_MASK_8
+ DW MTRR_PHYS_BASE_9
+ DW MTRR_PHYS_MASK_9
+MtrrCount EQU (($ - MtrrInitTable) / 2)
+
+align 10h
+PUBLIC BootGDTtable
+
+;
+; GDT[0]: 0x00: Null entry, never used.
+;
+NULL_SEL EQU $ - GDT_BASE ; Selector [0]
+GDT_BASE:
+BootGDTtable DD 0
+ DD 0
+;
+; Linear data segment descriptor
+;
+LINEAR_SEL EQU $ - GDT_BASE ; Selector [0x8]
+ DW 0FFFFh ; limit 0xFFFFF
+ DW 0 ; base 0
+ DB 0
+ DB 092h ; present, ring 0, data, expand-up, writable
+ DB 0CFh ; page-granular, 32-bit
+ DB 0
+;
+; Linear code segment descriptor
+;
+LINEAR_CODE_SEL EQU $ - GDT_BASE ; Selector [0x10]
+ DW 0FFFFh ; limit 0xFFFFF
+ DW 0 ; base 0
+ DB 0
+ DB 09Bh ; present, ring 0, data, expand-up, not-writable
+ DB 0CFh ; page-granular, 32-bit
+ DB 0
+;
+; System data segment descriptor
+;
+SYS_DATA_SEL EQU $ - GDT_BASE ; Selector [0x18]
+ DW 0FFFFh ; limit 0xFFFFF
+ DW 0 ; base 0
+ DB 0
+ DB 093h ; present, ring 0, data, expand-up, not-writable
+ DB 0CFh ; page-granular, 32-bit
+ DB 0
+
+;
+; System code segment descriptor
+;
+SYS_CODE_SEL EQU $ - GDT_BASE ; Selector [0x20]
+ DW 0FFFFh ; limit 0xFFFFF
+ DW 0 ; base 0
+ DB 0
+ DB 09Ah ; present, ring 0, data, expand-up, writable
+ DB 0CFh ; page-granular, 32-bit
+ DB 0
+;
+; Spare segment descriptor
+;
+SYS16_CODE_SEL EQU $ - GDT_BASE ; Selector [0x28]
+ DW 0FFFFh ; limit 0xFFFFF
+ DW 0 ; base 0
+ DB 0Eh ; Changed from F000 to E000.
+ DB 09Bh ; present, ring 0, code, expand-up, writable
+ DB 00h ; byte-granular, 16-bit
+ DB 0
+;
+; Spare segment descriptor
+;
+SYS16_DATA_SEL EQU $ - GDT_BASE ; Selector [0x30]
+ DW 0FFFFh ; limit 0xFFFF
+ DW 0 ; base 0
+ DB 0
+ DB 093h ; present, ring 0, data, expand-up, not-writable
+ DB 00h ; byte-granular, 16-bit
+ DB 0
+
+;
+; Spare segment descriptor
+;
+SPARE5_SEL EQU $ - GDT_BASE ; Selector [0x38]
+ DW 0 ; limit 0
+ DW 0 ; base 0
+ DB 0
+ DB 0 ; present, ring 0, data, expand-up, writable
+ DB 0 ; page-granular, 32-bit
+ DB 0
+GDT_SIZE EQU $ - BootGDTtable ; Size, in bytes
+
+GdtDesc: ; GDT descriptor
+OffsetGDTDesc EQU $ - _ModuleEntryPoint
+ DW GDT_SIZE - 1 ; GDT limit
+ DD OFFSET BootGDTtable ; GDT base address
+
+NemInitLinearAddress LABEL FWORD
+NemInitLinearOffset LABEL DWORD
+ DD OFFSET ProtectedModeSECStart ; Offset of our 32 bit code
+ DW LINEAR_CODE_SEL
+
+TopOfCar DD TEMPORARY_RAM_BASE_ADDRESS + TEMPORARY_RAM_SIZE
+
+_TEXT_PROTECTED_MODE ENDS
+END