;------------------------------------------------------------------------------ ; ; Copyright (c) 2013-2015 Intel Corporation. ; ; This program and the accompanying materials ; are licensed and made available under the terms and conditions of the BSD License ; which accompanies this distribution. The full text of the license may be found at ; http://opensource.org/licenses/bsd-license.php ; ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ; ; Module Name: ; ; Flat32.asm ; ; Abstract: ; ; This is the code that goes from real-mode to protected mode. ; It consumes the reset vector, configures the stack. ; ; ;------------------------------------------------------------------------------ ; ; Define assembler characteristics ; .586p .model flat, c ; ; Include processor definitions ; INCLUDE Platform.inc ; ; CR0 cache control bit definition ; CR0_CACHE_DISABLE EQU 040000000h CR0_NO_WRITE EQU 020000000h ; ; External and public declarations ; TopOfStack is used by C code ; SecStartup is the entry point to the C code ; Neither of these names can be modified without ; updating the C code. ; EXTRN PlatformSecLibStartup: NEAR EXTERNDEF C PcdGet32 (PcdEsramStage1Base):DWORD ; ; Contrary to the name, this file contains 16 bit code as well. ; _TEXT_REALMODE SEGMENT PARA PUBLIC USE16 'CODE' ASSUME CS:_TEXT_REALMODE, DS:_TEXT_REALMODE ;---------------------------------------------------------------------------- ; ; Procedure: _ModuleEntryPoint ; ; Input: None ; ; Output: None ; ; Destroys: Assume all registers ; ; Description: ; ; 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 a while in PEI and possibly DXE. ; ; After enabling protected mode, a far jump is executed to ; transfer to PEI using the newly loaded GDT. ; ; Return: None ; ;---------------------------------------------------------------------------- align 16 _ModuleEntryPoint PROC C PUBLIC ; ; Warm Reset (INIT#) check. ; mov si, 0F000h mov ds, si mov si, 0FFF0h cmp BYTE PTR [si], 0EAh ; Is it warm reset ? jne NotWarmReset ; JIf not. mov al, 08 mov dx, 0cf9h out dx, al mov al, 055h out 080h, al; jmp $ NotWarmReset: ; ; Load the GDT table in GdtDesc ; mov esi, OFFSET GdtDesc db 66h lgdt fword ptr cs:[si] ; ; Transition to 16 bit protected mode ; 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 ; ; Now we're in 16 bit protected mode ; Set up the selectors for 32 bit protected mode entry ; mov ax, SYS_DATA_SEL mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; ; Transition to Flat 32 bit protected mode ; The jump to a far pointer causes the transition to 32 bit mode ; mov esi, offset ProtectedModeEntryLinearAddress jmp fword ptr cs:[si] _ModuleEntryPoint ENDP _TEXT_REALMODE ENDS .code ; ; Protected mode portion initializes stack, configures cache, and calls C entry point ; ;---------------------------------------------------------------------------- ; ; Procedure: ProtectedModeEntryPoint ; ; Input: Executing in 32 Bit Protected (flat) mode ; cs: 0-4GB ; ds: 0-4GB ; es: 0-4GB ; fs: 0-4GB ; gs: 0-4GB ; ss: 0-4GB ; ; Output: This function never returns ; ; Destroys: ; ecx ; edi ; esi ; esp ; ; Description: ; Perform any essential early platform initilaisation ; Setup a stack ; Call the main EDKII Sec C code ; ;---------------------------------------------------------------------------- ProtectedModeEntryPoint PROC NEAR C PUBLIC JMP32 stackless_EarlyPlatformInit ; ; Set up stack pointer ; mov esp, PcdGet32(PcdEsramStage1Base) mov esi, QUARK_ESRAM_MEM_SIZE_BYTES add esp, esi ; ESP = top of stack (stack grows downwards). ; ; Store the the BIST value in EBP ; mov ebp, 00h ; No processor BIST on Quark ; ; Push processor count to stack first, then BIST status (AP then BSP) ; mov eax, 1 cpuid shr ebx, 16 and ebx, 0000000FFh cmp bl, 1 jae PushProcessorCount ; ; Some processors report 0 logical processors. Effectively 0 = 1. ; So we fix up the processor count ; inc ebx PushProcessorCount: push ebx ; ; We need to implement a long-term solution for BIST capture. For now, we just copy BSP BIST ; for all processor threads ; xor ecx, ecx mov cl, bl PushBist: push ebp loop PushBist ; ; Pass Control into the PEI Core ; call PlatformSecLibStartup ; ; PEI Core should never return to here, this is just to capture an invalid return. ; jmp $ ProtectedModeEntryPoint ENDP ;---------------------------------------------------------------------------- ; ; Procedure: stackless_EarlyPlatformInit ; ; Input: esp - Return address ; ; Output: None ; ; Destroys: ; eax ; ecx ; dx ; ebp ; ; Description: ; Any essential early platform initialisation required: ; (1) Disable Cache ; (2) Disable NMI's/SMI's ; (3) Setup HMBOUND (defines what memory accesses go to MMIO/RAM) ; (4) Setup eSRAM (provide early memory to the system) ; (5) Setup PCIEXBAR access mechanism ; (6) Open up full SPI flash decode ; ;---------------------------------------------------------------------------- stackless_EarlyPlatformInit PROC NEAR C PUBLIC ; ; Save return address ; mov ebp, esp ; ; Ensure cache is disabled. ; mov eax, cr0 or eax, CR0_CACHE_DISABLE + CR0_NO_WRITE invd mov cr0, eax ; ; Disable NMI ; Good convention suggests you should read back RTC data port after ; accessing the RTC index port. ; mov al, NMI_DISABLE mov dx, RTC_INDEX out dx, al mov dx, RTC_DATA in al, dx ; ; Disable SMI (Disables SMI wire, not SMI messages) ; mov ecx, (OPCODE_SIDEBAND_REG_READ SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HMISC2_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, NOT (SMI_EN) mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HMISC2_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Before we get going, check SOC Unit Registers to see if we are required to issue a warm/cold reset ; mov ecx, (OPCODE_SIDEBAND_ALT_REG_READ SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGNONSTICKY_W1_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, FORCE_WARM_RESET jz TestForceColdReset ; Zero means bit clear, we're not requested to warm reset so continue as normal jmp IssueWarmReset TestForceColdReset: mov ecx, (OPCODE_SIDEBAND_ALT_REG_READ SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGSTICKY_W1_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, FORCE_COLD_RESET jz TestHmboundLock ; Zero means bit clear, we're not requested to cold reset so continue as normal jmp IssueColdReset ; ; Before setting HMBOUND, check it's not locked ; TestHmboundLock: mov ecx, (OPCODE_SIDEBAND_REG_READ SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HMBOUND_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, HMBOUND_LOCK jz ConfigHmbound ; Zero means bit clear, we have the config we want so continue as normal ; ; Failed to config - store sticky bit debug ; mov ecx, (OPCODE_SIDEBAND_ALT_REG_READ SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGSTICKY_RW_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read or eax, RESET_FOR_HMBOUND_LOCK ; Set the bit we're interested in mov ecx, (OPCODE_SIDEBAND_ALT_REG_WRITE SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGSTICKY_RW_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write jmp IssueWarmReset ; ; Set up the HMBOUND register ; ConfigHmbound: mov eax, HMBOUND_ADDRESS ; Data (Set HMBOUND location) mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HMBOUND_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Enable interrupts to Remote Management Unit when a IMR/SMM/HMBOUND violation occurs. ; mov eax, ENABLE_IMR_INTERRUPT ; Data (Set interrupt enable mask) mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (MEMORY_MANAGER_PORT_ID SHL SB_PORT_FIELD) OR (BIMRVCTL_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Set eSRAM address ; mov eax, PcdGet32 (PcdEsramStage1Base) ; Data (Set eSRAM location) shr eax, 18h ; Data (Set eSRAM location) add eax, BLOCK_ENABLE_PG mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (MEMORY_MANAGER_PORT_ID SHL SB_PORT_FIELD) OR (ESRAMPGCTRL_BLOCK_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Check that we're not blocked from setting the config that we want. ; mov ecx, (OPCODE_SIDEBAND_REG_READ SHL SB_OPCODE_FIELD) OR (MEMORY_MANAGER_PORT_ID SHL SB_PORT_FIELD) OR (ESRAMPGCTRL_BLOCK_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, BLOCK_ENABLE_PG jnz ConfigPci ; Non-zero means bit set, we have the config we want so continue as normal ; ; Failed to config - store sticky bit debug ; mov ecx, (OPCODE_SIDEBAND_ALT_REG_READ SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGSTICKY_RW_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read or eax, RESET_FOR_ESRAM_LOCK ; Set the bit we're interested in mov ecx, (OPCODE_SIDEBAND_ALT_REG_WRITE SHL SB_OPCODE_FIELD) OR (SOC_UNIT_PORT_ID SHL SB_PORT_FIELD) OR (CFGSTICKY_RW_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write jmp IssueWarmReset ; ; Enable PCIEXBAR ; ConfigPci: mov eax, (EC_BASE + EC_ENABLE) ; Data mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (MEMORY_ARBITER_PORT_ID SHL SB_PORT_FIELD) OR (AEC_CTRL_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write mov eax, (EC_BASE + EC_ENABLE) ; Data mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HECREG_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Open up full 8MB SPI decode ; mov ebx, PCI_CFG OR (ILB_PFA SHL 8) OR BDE ; PCI Configuration address mov eax, DECODE_ALL_REGIONS_ENABLE JMP32 stackless_PCIConfig_Write ; ; Enable NMI operation ; Good convention suggests you should read back RTC data port after ; accessing the RTC index port. ; mov al, NMI_ENABLE mov dx, RTC_INDEX out dx, al mov dx, RTC_DATA in al, dx ; ; Clear Host Bridge SMI, NMI, INTR fields ; mov ecx, (OPCODE_SIDEBAND_REG_READ SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HLEGACY_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Read and eax, NOT(NMI + SMI + INTR) ; Clear NMI, SMI, INTR fields mov ecx, (OPCODE_SIDEBAND_REG_WRITE SHL SB_OPCODE_FIELD) OR (HOST_BRIDGE_PORT_ID SHL SB_PORT_FIELD) OR (HLEGACY_OFFSET SHL SB_ADDR_FIELD) JMP32 stackless_SideBand_Write ; ; Restore return address ; mov esp, ebp RET32 IssueWarmReset: ; ; Issue Warm Reset request to Remote Management Unit via iLB ; mov ax, CF9_WARM_RESET mov dx, ILB_RESET_REG out dx, ax jmp $ ; Stay here until we are reset. IssueColdReset: ; ; Issue Cold Reset request to Remote Management Unit via iLB ; mov ax, CF9_COLD_RESET mov dx, ILB_RESET_REG out dx, ax jmp $ ; Stay here until we are reset. stackless_EarlyPlatformInit ENDP ;---------------------------------------------------------------------------- ; ; Procedure: stackless_SideBand_Read ; ; Input: esp - return address ; ecx[15:8] - Register offset ; ecx[23:16] - Port ID ; ecx[31:24] - Opcode ; ; Output: eax - Data read ; ; Destroys: ; eax ; ebx ; cl ; esi ; ; Description: ; Perform requested sideband read ; ;---------------------------------------------------------------------------- stackless_SideBand_Read PROC NEAR C PUBLIC mov esi, esp ; Save the return address ; ; Load the SideBand Packet Register to generate the transaction ; mov ebx, PCI_CFG OR (HOST_BRIDGE_PFA SHL 8) OR MESSAGE_BUS_CONTROL_REG ; PCI Configuration address mov cl, (ALL_BYTE_EN SHL SB_BE_FIELD) ; Set all Byte Enable bits xchg eax, ecx JMP32 stackless_PCIConfig_Write xchg eax, ecx ; ; Read the SideBand Data Register ; mov ebx, PCI_CFG OR (HOST_BRIDGE_PFA SHL 8) OR MESSAGE_DATA_REG ; PCI Configuration address JMP32 stackless_PCIConfig_Read mov esp, esi ; Restore the return address RET32 stackless_SideBand_Read ENDP ;---------------------------------------------------------------------------- ; ; Procedure: stackless_SideBand_Write ; ; Input: esp - return address ; eax - Data ; ecx[15:8] - Register offset ; ecx[23:16] - Port ID ; ecx[31:24] - Opcode ; ; Output: None ; ; Destroys: ; ebx ; cl ; esi ; ; Description: ; Perform requested sideband write ; ; ;---------------------------------------------------------------------------- stackless_SideBand_Write PROC NEAR C PUBLIC mov esi, esp ; Save the return address ; ; Load the SideBand Data Register with the data ; mov ebx, PCI_CFG OR (HOST_BRIDGE_PFA SHL 8) OR MESSAGE_DATA_REG ; PCI Configuration address JMP32 stackless_PCIConfig_Write ; ; Load the SideBand Packet Register to generate the transaction ; mov ebx, PCI_CFG OR (HOST_BRIDGE_PFA SHL 8) OR MESSAGE_BUS_CONTROL_REG ; PCI Configuration address mov cl, (ALL_BYTE_EN SHL SB_BE_FIELD) ; Set all Byte Enable bits xchg eax, ecx JMP32 stackless_PCIConfig_Write xchg eax, ecx mov esp, esi ; Restore the return address RET32 stackless_SideBand_Write ENDP ;---------------------------------------------------------------------------- ; ; Procedure: stackless_PCIConfig_Write ; ; Input: esp - return address ; eax - Data to write ; ebx - PCI Config Address ; ; Output: None ; ; Destroys: ; dx ; ; Description: ; Perform a DWORD PCI Configuration write ; ;---------------------------------------------------------------------------- stackless_PCIConfig_Write PROC NEAR C PUBLIC ; ; Write the PCI Config Address to the address port ; xchg eax, ebx mov dx, PCI_ADDRESS_PORT out dx, eax xchg eax, ebx ; ; Write the PCI DWORD Data to the data port ; mov dx, PCI_DATA_PORT out dx, eax RET32 stackless_PCIConfig_Write ENDP ;---------------------------------------------------------------------------- ; ; Procedure: stackless_PCIConfig_Read ; ; Input: esp - return address ; ebx - PCI Config Address ; ; Output: eax - Data read ; ; Destroys: ; eax ; dx ; ; Description: ; Perform a DWORD PCI Configuration read ; ;---------------------------------------------------------------------------- stackless_PCIConfig_Read PROC NEAR C PUBLIC ; ; Write the PCI Config Address to the address port ; xchg eax, ebx mov dx, PCI_ADDRESS_PORT out dx, eax xchg eax, ebx ; ; Read the PCI DWORD Data from the data port ; mov dx, PCI_DATA_PORT in eax, dx RET32 stackless_PCIConfig_Read ENDP ; ; ROM-based Global-Descriptor Table for the Tiano PEI Phase ; align 16 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 0xFFFF 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 0xFFFF 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 0xFFFF 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 0xFFFF 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 0xFFFF DW 0 ; base 0 DB 0Fh 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 0xFFFF 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 ; ; GDT Descriptor ; GdtDesc: ; GDT descriptor DW GDT_SIZE - 1 ; GDT limit DD OFFSET BootGdtTable ; GDT base address ProtectedModeEntryLinearAddress LABEL FWORD ProtectedModeEntryLinearOffset LABEL DWORD DD OFFSET ProtectedModeEntryPoint ; Offset of our 32 bit code DW LINEAR_CODE_SEL END