ESP should be set to top of eSRAM range that aligns with Flat32.asm. Because CPU BIST data will be located at top of STACK, this issue leads Platform Sec Lib cannot get the correct CPU BIST information. This fix is to address below issue: https://tianocore.acgmultimedia.com/show_bug.cgi?id=123 Cc: Steven Shi <Steven.shi@intel.com> Cc: Michael Kinney <michael.d.kinney@intel.com> Cc: Kelly Steele <kelly.steele@intel.com> Cc: Feng Tian <feng.tian@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
		
			
				
	
	
		
			803 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			803 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| #------------------------------------------------------------------------------
 | |
| #
 | |
| # Copyright (c) 2013 - 2016 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.S
 | |
| #
 | |
| # Abstract:
 | |
| #
 | |
| #  This is the code that goes from real-mode to protected mode.
 | |
| #  It consumes the reset vector, configures the stack.
 | |
| #
 | |
| #
 | |
| #------------------------------------------------------------------------------
 | |
| 
 | |
| .macro RET32
 | |
|     jmp    *%esp
 | |
| .endm
 | |
| 
 | |
| #
 | |
| # ROM/SPI/MEMORY Definitions
 | |
| #
 | |
| .equ  QUARK_DDR3_MEM_BASE_ADDRESS, (0x000000000)    # Memory Base Address = 0
 | |
| .equ  QUARK_MAX_DDR3_MEM_SIZE_BYTES, (0x80000000)    # DDR3 Memory Size = 2GB
 | |
| .equ  QUARK_ESRAM_MEM_SIZE_BYTES, (0x00080000)    # eSRAM Memory Size = 512K
 | |
| .equ  QUARK_STACK_SIZE_BYTES, (0x008000)      # Quark stack size = 32K
 | |
| 
 | |
| #
 | |
| # RTC/CMOS definitions
 | |
| #
 | |
| .equ  RTC_INDEX, (0x70)
 | |
| .equ    NMI_DISABLE, (0x80)  # Bit7=1 disables NMI
 | |
| .equ    NMI_ENABLE, (0x00)  # Bit7=0 disables NMI
 | |
| .equ  RTC_DATA, (0x71)
 | |
| 
 | |
| #
 | |
| # PCI Configuration definitions
 | |
| #
 | |
| .equ  PCI_CFG, (0x80000000) # PCI configuration access mechanism
 | |
| .equ  PCI_ADDRESS_PORT, (0xCF8)
 | |
| .equ  PCI_DATA_PORT, (0xCFC)
 | |
| 
 | |
| #
 | |
| # Quark PCI devices
 | |
| #
 | |
| .equ  HOST_BRIDGE_PFA, (0x0000)   # B0:D0:F0 (Host Bridge)
 | |
| .equ  ILB_PFA, (0x00F8)      # B0:D31:F0 (Legacy Block)
 | |
| 
 | |
| #
 | |
| # ILB PCI Config Registers
 | |
| #
 | |
| .equ  BDE, (0x0D4)                                # BIOS Decode Enable register
 | |
| .equ    DECODE_ALL_REGIONS_ENABLE, (0xFF000000)    # Decode all BIOS decode ranges
 | |
| 
 | |
| #
 | |
| # iLB Reset Register
 | |
| #
 | |
| .equ  ILB_RESET_REG, (0x0CF9)
 | |
| .equ    CF9_WARM_RESET, (0x02)
 | |
| .equ    CF9_COLD_RESET, (0x08)
 | |
| 
 | |
| #
 | |
| # Host Bridge PCI Config Registers
 | |
| #
 | |
| .equ  MESSAGE_BUS_CONTROL_REG, (0xD0)       # Message Bus Control Register
 | |
| .equ    SB_OPCODE_FIELD, (0x18)              # Bit location of Opcode field
 | |
| .equ      OPCODE_SIDEBAND_REG_READ, (0x10)  # Read opcode
 | |
| .equ      OPCODE_SIDEBAND_REG_WRITE, (0x11) # Write opcode
 | |
| .equ      OPCODE_SIDEBAND_ALT_REG_READ, (0x06)  # Alternate Read opcode
 | |
| .equ      OPCODE_SIDEBAND_ALT_REG_WRITE, (0x07) # Alternate Write opcode
 | |
| .equ      OPCODE_WARM_RESET_REQUEST, (0xF4)  # Reset Warm
 | |
| .equ      OPCODE_COLD_RESET_REQUEST, (0xF5) # Reset Cold
 | |
| .equ    SB_PORT_FIELD, (0x10)               # Bit location of Port ID field
 | |
| .equ      MEMORY_ARBITER_PORT_ID, (0x00)
 | |
| .equ      HOST_BRIDGE_PORT_ID, (0x03)
 | |
| .equ      RMU_PORT_ID, (0x04)
 | |
| .equ      MEMORY_MANAGER_PORT_ID, (0x05)
 | |
| .equ      SOC_UNIT_PORT_ID, (0x31)
 | |
| .equ    SB_ADDR_FIELD, (0x08)               # Bit location of Register field
 | |
| .equ    SB_BE_FIELD, (0x04)                  # Bit location of Byte Enables field
 | |
| .equ      ALL_BYTE_EN, (0x0F)                # All Byte Enables
 | |
| .equ  MESSAGE_DATA_REG, (0xD4)              # Message Data Register
 | |
| 
 | |
| #
 | |
| # Memory Arbiter Config Registers
 | |
| #
 | |
| .equ  AEC_CTRL_OFFSET, (0x00)
 | |
| 
 | |
| #
 | |
| # Host Bridge Config Registers
 | |
| #
 | |
| .equ  HMISC2_OFFSET, (0x03) # PCI configuration access mechanism
 | |
| .equ    OR_PM_FIELD, (0x10)
 | |
| .equ      SMI_EN, (0x00080000)
 | |
| 
 | |
| .equ  HMBOUND_OFFSET, (0x08)
 | |
| .equ    HMBOUND_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS + QUARK_MAX_DDR3_MEM_SIZE_BYTES + QUARK_ESRAM_MEM_SIZE_BYTES)
 | |
| .equ    HMBOUND_LOCK, (0x01)
 | |
| .equ  HECREG_OFFSET, (0x09)
 | |
| .equ    EC_BASE, (0xE0000000)
 | |
| .equ    EC_ENABLE, (0x01)
 | |
| .equ  HLEGACY_OFFSET, (0x0A)
 | |
| .equ    NMI, (0x00004000)
 | |
| .equ    SMI, (0x00001000)
 | |
| .equ    INTR, (0x00000400)
 | |
| 
 | |
| #
 | |
| # Memory Manager Config Registers
 | |
| #
 | |
| .equ  ESRAMPGCTRL_BLOCK_OFFSET, (0x82)
 | |
| .equ    BLOCK_ENABLE_PG, (0x10000000)
 | |
| .equ  BIMRVCTL_OFFSET, (0x19)
 | |
| .equ    ENABLE_IMR_INTERRUPT, (0x80000000)
 | |
| 
 | |
| #
 | |
| # SOC UNIT Debug Registers
 | |
| #
 | |
| .equ  CFGSTICKY_W1_OFFSET, (0x50)
 | |
| .equ    FORCE_COLD_RESET, (0x00000001)
 | |
| .equ  CFGSTICKY_RW_OFFSET, (0x51)
 | |
| .equ    RESET_FOR_ESRAM_LOCK, (0x00000020)
 | |
| .equ    RESET_FOR_HMBOUND_LOCK, (0x00000040)
 | |
| .equ  CFGNONSTICKY_W1_OFFSET, (0x52)
 | |
| .equ    FORCE_WARM_RESET, (0x00000001)
 | |
| 
 | |
| #
 | |
| # CR0 cache control bit definition
 | |
| #
 | |
| .equ                    CR0_CACHE_DISABLE, 0x040000000
 | |
| .equ                    CR0_NO_WRITE,      0x020000000
 | |
| 
 | |
| ASM_GLOBAL  ASM_PFX(PcdGet32(PcdEsramStage1Base))
 | |
| 
 | |
| 
 | |
| #
 | |
| # Contrary to the name, this file contains 16 bit code as well.
 | |
| #
 | |
| .text
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # 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
 | |
| #
 | |
| #----------------------------------------------------------------------------
 | |
| ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
 | |
| ASM_PFX(_ModuleEntryPoint):
 | |
| 
 | |
|   #
 | |
|   # Warm Reset (INIT#) check.
 | |
|   #
 | |
|   .byte   0xbe,0x00,0xf0   #movw    $0xF000, %si
 | |
|   .byte   0x8e,0xde        #movw    %si, %ds
 | |
|   .byte   0xbe,0xf0,0xff   #movw    $0xFFF0, %si
 | |
|   .byte   0x80,0x3c,0xea   #cmpb    $0xEA, (%si)          # Is it warm reset ?
 | |
|   jne     NotWarmReset     # Jump if not.
 | |
|   .byte   0xb0,0x08        #movb    $0x08, %al
 | |
|   .byte   0xba,0xf9,0x0c   #movw    $0xcf9, %dx
 | |
|   .byte   0xee             #outb    %al, %dx
 | |
|   .byte   0xb0,0x55        #movb    $0x55, %al
 | |
|   .byte   0xe6,0x80        #outb    %al, $0x80
 | |
|   jmp     .
 | |
| NotWarmReset:
 | |
|   .byte   0x66,0x8b,0xe8   #movl    %eax, %ebp
 | |
| 
 | |
|   #
 | |
|   # Load the GDT table in GdtDesc
 | |
|   #
 | |
|   .byte   0x66,0xbe        #movl    $GdtDesc, %esi
 | |
|   .long   GdtDesc
 | |
| 
 | |
|   .byte   0x66,0x2e,0x0f,0x01,0x14   #lgdt    %cs:(%si)
 | |
| 
 | |
|   #
 | |
|   # Transition to 16 bit protected mode
 | |
|   #
 | |
|   .byte   0x0f,0x20,0xc0       #movl    %cr0, %eax                  # Get control register 0
 | |
|   .byte   0x66,0x83,0xc8,0x03  #orl     $0x0000003, %eax           # Set PE bit (bit #0) & MP bit (bit #1)
 | |
|   .byte   0x0f,0x22,0xc0       #movl    %eax, %cr0                  # Activate protected mode
 | |
| 
 | |
|   #
 | |
|   # Now we're in 16 bit protected mode
 | |
|   # Set up the selectors for 32 bit protected mode entry
 | |
|   #
 | |
|   .byte   0xb8                 #movw    SYS_DATA_SEL, %ax
 | |
|   .word   SYS_DATA_SEL
 | |
| 
 | |
|   .byte   0x8e,0xd8            #movw    %ax, %ds
 | |
|   .byte   0x8e,0xc0            #movw    %ax, %es
 | |
|   .byte   0x8e,0xe0            #movw    %ax, %fs
 | |
|   .byte   0x8e,0xe8            #movw    %ax, %gs
 | |
|   .byte   0x8e,0xd0            #movw    %ax, %ss
 | |
| 
 | |
|   #
 | |
|   # Transition to Flat 32 bit protected mode
 | |
|   # The jump to a far pointer causes the transition to 32 bit mode
 | |
|   #
 | |
|   .byte   0x66,0xbe            #movl   ProtectedModeEntryLinearAddress, %esi
 | |
|   .long   ProtectedModeEntryLinearAddress
 | |
|   .byte   0x66,0x2e,0xff,0x2c  #jmp    %cs:(%esi)
 | |
| 
 | |
| #
 | |
| # 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
 | |
| #               Transfer control to EDKII code in eSRAM
 | |
| #
 | |
| #----------------------------------------------------------------------------
 | |
| ProtectedModeEntryPoint:
 | |
|   leal  L0, %esp
 | |
|   jmp  stackless_EarlyPlatformInit
 | |
| L0:
 | |
| 
 | |
|   #
 | |
|   # Set up stack pointer
 | |
|   #
 | |
|   movl    ASM_PFX(PcdGet32(PcdEsramStage1Base)), %esp
 | |
|   movl    $QUARK_ESRAM_MEM_SIZE_BYTES, %esi
 | |
|   addl    %esi, %esp                          # ESP = top of stack (stack grows downwards).
 | |
| 
 | |
|   #
 | |
|   # Store the the BIST value in EBP
 | |
|   #
 | |
|   movl    $0, %ebp    # No processor BIST on Quark
 | |
| 
 | |
|   #
 | |
|   # Push processor count to stack first, then BIST status (AP then BSP)
 | |
|   #
 | |
|   movl    $1, %eax
 | |
|   cpuid
 | |
|   shrl    $16, %ebx
 | |
|   andl    $0x000000FF, %ebx
 | |
|   cmpb    $1, %bl
 | |
|   jae     PushProcessorCount
 | |
| 
 | |
|   #
 | |
|   # Some processors report 0 logical processors.  Effectively 0 = 1.
 | |
|   # So we fix up the processor count
 | |
|   #
 | |
|   incl    %ebx
 | |
| 
 | |
| PushProcessorCount:
 | |
|   pushl   %ebx
 | |
| 
 | |
|   #
 | |
|   # We need to implement a long-term solution for BIST capture.  For now, we just copy BSP BIST
 | |
|   # for all processor threads
 | |
|   #
 | |
|   xorl    %ecx, %ecx
 | |
|   movb    %bl, %cl
 | |
| 
 | |
| PushBist:
 | |
|   pushl   %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     .
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # Procedure:    stackless_EarlyPlatformInit
 | |
| #
 | |
| # Input:        esp - Return address
 | |
| #
 | |
| # Output:       None
 | |
| #
 | |
| # Destroys:     Assume all registers
 | |
| #
 | |
| # Description:
 | |
| #        Any early platform initialisation required
 | |
| #
 | |
| # Return:
 | |
| #      None
 | |
| #
 | |
| #----------------------------------------------------------------------------
 | |
| stackless_EarlyPlatformInit:
 | |
| 
 | |
|   #
 | |
|   # Save return address
 | |
|   #
 | |
|   movl  %esp, %ebp
 | |
| 
 | |
|   #
 | |
|   # Ensure cache is disabled.
 | |
|   #
 | |
|   movl %cr0, %eax
 | |
|   orl $(CR0_CACHE_DISABLE + CR0_NO_WRITE), %eax
 | |
|   invd
 | |
|   movl    %eax, %cr0
 | |
| 
 | |
|   #
 | |
|   # Disable NMI operation
 | |
|   # Good convention suggests you should read back RTC data port after
 | |
|   # accessing the RTC index port.
 | |
|   #
 | |
|   movb $(NMI_DISABLE), %al
 | |
|   movw $(RTC_INDEX), %dx
 | |
|   outb %al, %dx
 | |
|   movw $(RTC_DATA), %dx
 | |
|   inb  %dx, %al
 | |
| 
 | |
|   #
 | |
|   # Disable SMI (Disables SMI wire, not SMI messages)
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L1, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L1:
 | |
|   andl $(~SMI_EN), %eax
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L2, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L2:
 | |
| 
 | |
|   #
 | |
|   # Before we get going, check SOC Unit Registers to see if we are required to issue a warm/cold reset
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L3, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L3:
 | |
|   andl $(FORCE_WARM_RESET), %eax
 | |
|   jz TestForceColdReset    # Zero means bit clear, we're not requested to warm reset so continue as normal
 | |
|   jmp IssueWarmReset
 | |
| 
 | |
| TestForceColdReset:
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L4, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L4:
 | |
|   andl $(FORCE_COLD_RESET), %eax
 | |
|   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:
 | |
|   movl  $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L5, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L5:
 | |
|   andl $(HMBOUND_LOCK), %eax
 | |
|   jz ConfigHmbound  # Zero means bit clear, we have the config we want so continue as normal
 | |
|   #
 | |
|   # Failed to config - store sticky bit debug
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L6, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L6:
 | |
|   orl $(RESET_FOR_HMBOUND_LOCK), %eax
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L7, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L7:
 | |
|   jmp IssueWarmReset
 | |
| 
 | |
|   #
 | |
|   # Set up the HMBOUND register
 | |
|   #
 | |
| ConfigHmbound:
 | |
|   movl $(HMBOUND_ADDRESS), %eax      # Data (Set HMBOUND location)
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L8, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L8:
 | |
| 
 | |
|   #
 | |
|   # Enable interrupts to Remote Management Unit when a IMR/SMM/HMBOUND violation occurs.
 | |
|   #
 | |
|   movl $(ENABLE_IMR_INTERRUPT), %eax      # Data (Set interrupt enable mask)
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (BIMRVCTL_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L9, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L9:
 | |
| 
 | |
|   #
 | |
|   # Set eSRAM address
 | |
|   #
 | |
|   movl    ASM_PFX(PcdGet32(PcdEsramStage1Base)), %eax   # Data (Set eSRAM location)
 | |
|   shr   $(0x18), %eax
 | |
|   addl  $(BLOCK_ENABLE_PG), %eax
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L10, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L10:
 | |
| 
 | |
|   #
 | |
|   # Check that we're not blocked from setting the config that we want.
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L11, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L11:
 | |
|   andl $(BLOCK_ENABLE_PG), %eax
 | |
|   jnz ConfigPci  # Non-zero means bit set, we have the config we want so continue as normal
 | |
|   #
 | |
|   # Failed to config - store sticky bit debug
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L12, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L12:
 | |
|   orl $(RESET_FOR_ESRAM_LOCK), %eax     # Set the bit we're interested in
 | |
|   movl  $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L13, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L13:
 | |
|   jmp IssueWarmReset
 | |
| 
 | |
|   #
 | |
|   # Enable PCIEXBAR
 | |
|   #
 | |
| ConfigPci:
 | |
|   movl $(EC_BASE + EC_ENABLE), %eax      # Data
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_ARBITER_PORT_ID << SB_PORT_FIELD) | (AEC_CTRL_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L14, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L14:
 | |
| 
 | |
|   movl $(EC_BASE + EC_ENABLE), %eax      # Data
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HECREG_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L15, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L15:
 | |
| 
 | |
|   #
 | |
|   #  Open up full 8MB SPI decode
 | |
|   #
 | |
|   movl  $(PCI_CFG | (ILB_PFA << 8) | BDE), %ebx  # PCI Configuration address
 | |
|   movl $(DECODE_ALL_REGIONS_ENABLE), %eax
 | |
|   leal  L16, %esp
 | |
|   jmp  stackless_PCIConfig_Write
 | |
| L16:
 | |
| 
 | |
|   #
 | |
|   # Enable NMI operation
 | |
|   # Good convention suggests you should read back RTC data port after
 | |
|   # accessing the RTC index port.
 | |
|   #
 | |
|   movb $(NMI_ENABLE), %al
 | |
|   movw $(RTC_INDEX), %dx
 | |
|   outb %al, %dx
 | |
|   movw $(RTC_DATA), %dx
 | |
|   inb  %dx, %al
 | |
| 
 | |
|   #
 | |
|   # Clear Host Bridge SMI, NMI, INTR fields
 | |
|   #
 | |
|   movl  $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HLEGACY_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L21, %esp
 | |
|   jmp  stackless_SideBand_Read
 | |
| L21:
 | |
|   andl $~(NMI + SMI + INTR), %eax      # Clear NMI, SMI, INTR fields
 | |
|   movl  $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HLEGACY_OFFSET << SB_ADDR_FIELD)), %ecx
 | |
|   leal  L22, %esp
 | |
|   jmp  stackless_SideBand_Write
 | |
| L22:
 | |
| 
 | |
|   #
 | |
|   # Restore return address
 | |
|   #
 | |
|   movl  %ebp, %esp
 | |
|   RET32
 | |
| 
 | |
| IssueWarmReset:
 | |
|   #
 | |
|   # Issue Warm Reset request to Remote Management Unit via iLB
 | |
|   #
 | |
|   movw  $(CF9_WARM_RESET), %ax
 | |
|   movw  $(ILB_RESET_REG), %dx
 | |
|   outw  %ax, %dx
 | |
|   jmp  .  # Stay here until we are reset.
 | |
| 
 | |
| IssueColdReset:
 | |
|   #
 | |
|   # Issue Cold Reset request to Remote Management Unit via iLB
 | |
|   #
 | |
|   movw  $(CF9_COLD_RESET), %ax
 | |
|   movw  $(ILB_RESET_REG), %dx
 | |
|   outw  %ax, %dx
 | |
|   jmp  .  # Stay here until we are reset.
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # 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:
 | |
| 
 | |
|   movl  %esp, %esi      # Save the return address
 | |
| 
 | |
|   #
 | |
|   # Load the SideBand Packet Register to generate the transaction
 | |
|   #
 | |
|   movl  $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx   # PCI Configuration address
 | |
|   movb  $(ALL_BYTE_EN << SB_BE_FIELD), %cl      # Set all Byte Enable bits
 | |
|   xchgl  %ecx, %eax
 | |
|   leal  L17, %esp
 | |
|   jmp  stackless_PCIConfig_Write
 | |
| L17:
 | |
|   xchgl  %ecx, %eax
 | |
| 
 | |
|   #
 | |
|   # Read the SideBand Data Register
 | |
|   #
 | |
|   movl  $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx   # PCI Configuration address
 | |
|   leal  L18, %esp
 | |
|   jmp  stackless_PCIConfig_Read
 | |
| L18:
 | |
| 
 | |
|   movl  %esi, %esp      # Restore the return address
 | |
|   RET32
 | |
| 
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # 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:
 | |
| 
 | |
|   movl  %esp, %esi      # Save the return address
 | |
| 
 | |
|   #
 | |
|   # Load the SideBand Data Register with the data
 | |
|   #
 | |
|   movl  $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx   # PCI Configuration address
 | |
|   leal  L19, %esp
 | |
|   jmp  stackless_PCIConfig_Write
 | |
| L19:
 | |
| 
 | |
|   #
 | |
|   # Load the SideBand Packet Register to generate the transaction
 | |
|   #
 | |
|   movl  $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx   # PCI Configuration address
 | |
|   movb  $(ALL_BYTE_EN << SB_BE_FIELD), %cl      # Set all Byte Enable bits
 | |
|   xchgl  %ecx, %eax
 | |
|   leal  L20, %esp
 | |
|   jmp  stackless_PCIConfig_Write
 | |
| L20:
 | |
|   xchgl  %ecx, %eax
 | |
| 
 | |
|   movl  %esi, %esp      # Restore the return address
 | |
|   RET32
 | |
| 
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # 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:
 | |
| 
 | |
|   #
 | |
|   # Write the PCI Config Address to the address port
 | |
|   #
 | |
|   xchgl  %ebx, %eax
 | |
|   movw  $(PCI_ADDRESS_PORT), %dx
 | |
|   outl  %eax, %dx
 | |
|   xchgl  %ebx, %eax
 | |
| 
 | |
|   #
 | |
|   # Write the PCI DWORD Data to the data port
 | |
|   #
 | |
|   movw  $(PCI_DATA_PORT), %dx
 | |
|   outl  %eax, %dx
 | |
| 
 | |
|   RET32
 | |
| 
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| #
 | |
| # 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:
 | |
| 
 | |
|   #
 | |
|   # Write the PCI Config Address to the address port
 | |
|   #
 | |
|   xchgl  %ebx, %eax
 | |
|   movw  $(PCI_ADDRESS_PORT), %dx
 | |
|   outl  %eax, %dx
 | |
|   xchgl  %ebx, %eax
 | |
| 
 | |
|   #
 | |
|   # Read the PCI DWORD Data from the data port
 | |
|   #
 | |
|   movw  $(PCI_DATA_PORT), %dx
 | |
|   inl  %dx, %eax
 | |
| 
 | |
|   RET32
 | |
| 
 | |
| 
 | |
| #
 | |
| # ROM-based Global-Descriptor Table for the Tiano PEI Phase
 | |
| #
 | |
| .align 16
 | |
| #
 | |
| # GDT[0]: 000h: Null entry, never used.
 | |
| #
 | |
| 
 | |
| GDT_BASE:
 | |
| BootGdtTable:
 | |
| # null descriptor
 | |
| .equ                NULL_SEL, . - GDT_BASE # Selector [0]
 | |
|         .word 0         # limit 15:0
 | |
|         .word 0         # base 15:0
 | |
|         .byte 0         # base 23:16
 | |
|         .byte 0         # type
 | |
|         .byte 0         # limit 19:16, flags
 | |
|         .byte 0         # base 31:24
 | |
| 
 | |
| # linear data segment descriptor
 | |
| .equ            LINEAR_SEL, . - GDT_BASE # Selector [0x8]
 | |
|         .word 0xFFFF    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0x92      # present, ring 0, data, expand-up, writable
 | |
|         .byte 0xCF              # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # linear code segment descriptor
 | |
| .equ            LINEAR_CODE_SEL, . - GDT_BASE # Selector [0x10]
 | |
|         .word 0xFFFF    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0x9A      # present, ring 0, data, expand-up, writable
 | |
|         .byte 0xCF              # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # system data segment descriptor
 | |
| .equ            SYS_DATA_SEL, . - GDT_BASE # Selector [0x18]
 | |
|         .word 0xFFFF    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0x92      # present, ring 0, data, expand-up, writable
 | |
|         .byte 0xCF              # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # system code segment descriptor
 | |
| .equ            SYS_CODE_SEL, . - GDT_BASE
 | |
|         .word 0xFFFF    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0x9A      # present, ring 0, data, expand-up, writable
 | |
|         .byte 0xCF              # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # spare segment descriptor
 | |
| .equ        SYS16_CODE_SEL, . - GDT_BASE
 | |
|         .word 0xffff    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0x0f
 | |
|         .byte 0x9b      # present, ring 0, data, expand-up, writable
 | |
|         .byte 0         # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # spare segment descriptor
 | |
| .equ        SYS16_DATA_SEL, . - GDT_BASE
 | |
|         .word 0xffff    # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0x93      # present, ring 0, data, expand-up, not-writable
 | |
|         .byte 0         # page-granular, 32-bit
 | |
|         .byte 0
 | |
| 
 | |
| # spare segment descriptor
 | |
| .equ        SPARE5_SEL, . - GDT_BASE
 | |
|         .word 0         # limit 0xFFFFF
 | |
|         .word 0         # base 0
 | |
|         .byte 0
 | |
|         .byte 0         # present, ring 0, data, expand-up, writable
 | |
|         .byte 0         # page-granular, 32-bit
 | |
|         .byte 0
 | |
| .equ        GDT_SIZE, . - GDT_BASE
 | |
| 
 | |
| #
 | |
| # GDT Descriptor
 | |
| #
 | |
| GdtDesc:                                     # GDT descriptor
 | |
|        .word    GDT_SIZE - 1
 | |
|        .long    BootGdtTable
 | |
| 
 | |
| ProtectedModeEntryLinearAddress:
 | |
| ProtectedModeEntryLinearOffset:
 | |
|        .long    ProtectedModeEntryPoint
 | |
|        .word    LINEAR_CODE_SEL
 |