mirror of https://github.com/acidanthera/audk.git
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
|