1 #------------------------------------------------------------------------------
3 # Copyright (c) 2013 - 2016 Intel Corporation.
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
13 # This is the code that goes from real-mode to protected mode.
14 # It consumes the reset vector, configures the stack.
17 #------------------------------------------------------------------------------
24 # ROM/SPI/MEMORY Definitions
26 .equ QUARK_DDR3_MEM_BASE_ADDRESS, (0x000000000) # Memory Base Address = 0
27 .equ QUARK_MAX_DDR3_MEM_SIZE_BYTES, (0x80000000) # DDR3 Memory Size = 2GB
28 .equ QUARK_ESRAM_MEM_SIZE_BYTES, (0x00080000) # eSRAM Memory Size = 512K
29 .equ QUARK_STACK_SIZE_BYTES, (0x008000) # Quark stack size = 32K
32 # RTC/CMOS definitions
34 .equ RTC_INDEX, (0x70)
35 .equ NMI_DISABLE, (0x80) # Bit7=1 disables NMI
36 .equ NMI_ENABLE, (0x00) # Bit7=0 disables NMI
40 # PCI Configuration definitions
42 .equ PCI_CFG, (0x80000000) # PCI configuration access mechanism
43 .equ PCI_ADDRESS_PORT, (0xCF8)
44 .equ PCI_DATA_PORT, (0xCFC)
49 .equ HOST_BRIDGE_PFA, (0x0000) # B0:D0:F0 (Host Bridge)
50 .equ ILB_PFA, (0x00F8) # B0:D31:F0 (Legacy Block)
53 # ILB PCI Config Registers
55 .equ BDE, (0x0D4) # BIOS Decode Enable register
56 .equ DECODE_ALL_REGIONS_ENABLE, (0xFF000000) # Decode all BIOS decode ranges
61 .equ ILB_RESET_REG, (0x0CF9)
62 .equ CF9_WARM_RESET, (0x02)
63 .equ CF9_COLD_RESET, (0x08)
66 # Host Bridge PCI Config Registers
68 .equ MESSAGE_BUS_CONTROL_REG, (0xD0) # Message Bus Control Register
69 .equ SB_OPCODE_FIELD, (0x18) # Bit location of Opcode field
70 .equ OPCODE_SIDEBAND_REG_READ, (0x10) # Read opcode
71 .equ OPCODE_SIDEBAND_REG_WRITE, (0x11) # Write opcode
72 .equ OPCODE_SIDEBAND_ALT_REG_READ, (0x06) # Alternate Read opcode
73 .equ OPCODE_SIDEBAND_ALT_REG_WRITE, (0x07) # Alternate Write opcode
74 .equ OPCODE_WARM_RESET_REQUEST, (0xF4) # Reset Warm
75 .equ OPCODE_COLD_RESET_REQUEST, (0xF5) # Reset Cold
76 .equ SB_PORT_FIELD, (0x10) # Bit location of Port ID field
77 .equ MEMORY_ARBITER_PORT_ID, (0x00)
78 .equ HOST_BRIDGE_PORT_ID, (0x03)
79 .equ RMU_PORT_ID, (0x04)
80 .equ MEMORY_MANAGER_PORT_ID, (0x05)
81 .equ SOC_UNIT_PORT_ID, (0x31)
82 .equ SB_ADDR_FIELD, (0x08) # Bit location of Register field
83 .equ SB_BE_FIELD, (0x04) # Bit location of Byte Enables field
84 .equ ALL_BYTE_EN, (0x0F) # All Byte Enables
85 .equ MESSAGE_DATA_REG, (0xD4) # Message Data Register
88 # Memory Arbiter Config Registers
90 .equ AEC_CTRL_OFFSET, (0x00)
93 # Host Bridge Config Registers
95 .equ HMISC2_OFFSET, (0x03) # PCI configuration access mechanism
96 .equ OR_PM_FIELD, (0x10)
97 .equ SMI_EN, (0x00080000)
99 .equ HMBOUND_OFFSET, (0x08)
100 .equ HMBOUND_ADDRESS, (QUARK_DDR3_MEM_BASE_ADDRESS + QUARK_MAX_DDR3_MEM_SIZE_BYTES + QUARK_ESRAM_MEM_SIZE_BYTES)
101 .equ HMBOUND_LOCK, (0x01)
102 .equ HECREG_OFFSET, (0x09)
103 .equ EC_BASE, (0xE0000000)
104 .equ EC_ENABLE, (0x01)
105 .equ HLEGACY_OFFSET, (0x0A)
106 .equ NMI, (0x00004000)
107 .equ SMI, (0x00001000)
108 .equ INTR, (0x00000400)
111 # Memory Manager Config Registers
113 .equ ESRAMPGCTRL_BLOCK_OFFSET, (0x82)
114 .equ BLOCK_ENABLE_PG, (0x10000000)
115 .equ BIMRVCTL_OFFSET, (0x19)
116 .equ ENABLE_IMR_INTERRUPT, (0x80000000)
119 # SOC UNIT Debug Registers
121 .equ CFGSTICKY_W1_OFFSET, (0x50)
122 .equ FORCE_COLD_RESET, (0x00000001)
123 .equ CFGSTICKY_RW_OFFSET, (0x51)
124 .equ RESET_FOR_ESRAM_LOCK, (0x00000020)
125 .equ RESET_FOR_HMBOUND_LOCK, (0x00000040)
126 .equ CFGNONSTICKY_W1_OFFSET, (0x52)
127 .equ FORCE_WARM_RESET, (0x00000001)
130 # CR0 cache control bit definition
132 .equ CR0_CACHE_DISABLE, 0x040000000
133 .equ CR0_NO_WRITE, 0x020000000
135 ASM_GLOBAL ASM_PFX(PcdGet32(PcdEsramStage1Base))
139 # Contrary to the name, this file contains 16 bit code as well.
142 #----------------------------------------------------------------------------
144 # Procedure: _ModuleEntryPoint
150 # Destroys: Assume all registers
154 # Transition to non-paged flat-model protected mode from a
155 # hard-coded GDT that provides exactly two descriptors.
156 # This is a bare bones transition to protected mode only
157 # used for a while in PEI and possibly DXE.
159 # After enabling protected mode, a far jump is executed to
160 # transfer to PEI using the newly loaded GDT.
164 #----------------------------------------------------------------------------
165 ASM_GLOBAL ASM_PFX(_ModuleEntryPoint)
166 ASM_PFX(_ModuleEntryPoint):
169 # Warm Reset (INIT#) check.
171 .byte 0xbe,0x00,0xf0 #movw $0xF000, %si
172 .byte 0x8e,0xde #movw %si, %ds
173 .byte 0xbe,0xf0,0xff #movw $0xFFF0, %si
174 .byte 0x80,0x3c,0xea #cmpb $0xEA, (%si) # Is it warm reset ?
175 jne NotWarmReset # Jump if not.
176 .byte 0xb0,0x08 #movb $0x08, %al
177 .byte 0xba,0xf9,0x0c #movw $0xcf9, %dx
178 .byte 0xee #outb %al, %dx
179 .byte 0xb0,0x55 #movb $0x55, %al
180 .byte 0xe6,0x80 #outb %al, $0x80
183 .byte 0x66,0x8b,0xe8 #movl %eax, %ebp
186 # Load the GDT table in GdtDesc
188 .byte 0x66,0xbe #movl $GdtDesc, %esi
191 .byte 0x66,0x2e,0x0f,0x01,0x14 #lgdt %cs:(%si)
194 # Transition to 16 bit protected mode
196 .byte 0x0f,0x20,0xc0 #movl %cr0, %eax # Get control register 0
197 .byte 0x66,0x83,0xc8,0x03 #orl $0x0000003, %eax # Set PE bit (bit #0) & MP bit (bit #1)
198 .byte 0x0f,0x22,0xc0 #movl %eax, %cr0 # Activate protected mode
201 # Now we're in 16 bit protected mode
202 # Set up the selectors for 32 bit protected mode entry
204 .byte 0xb8 #movw SYS_DATA_SEL, %ax
207 .byte 0x8e,0xd8 #movw %ax, %ds
208 .byte 0x8e,0xc0 #movw %ax, %es
209 .byte 0x8e,0xe0 #movw %ax, %fs
210 .byte 0x8e,0xe8 #movw %ax, %gs
211 .byte 0x8e,0xd0 #movw %ax, %ss
214 # Transition to Flat 32 bit protected mode
215 # The jump to a far pointer causes the transition to 32 bit mode
217 .byte 0x66,0xbe #movl ProtectedModeEntryLinearAddress, %esi
218 .long ProtectedModeEntryLinearAddress
219 .byte 0x66,0x2e,0xff,0x2c #jmp %cs:(%esi)
222 # Protected mode portion initializes stack, configures cache, and calls C entry point
225 #----------------------------------------------------------------------------
227 # Procedure: ProtectedModeEntryPoint
229 # Input: Executing in 32 Bit Protected (flat) mode
237 # Output: This function never returns
246 # Perform any essential early platform initilaisation
248 # Transfer control to EDKII code in eSRAM
250 #----------------------------------------------------------------------------
251 ProtectedModeEntryPoint:
253 jmp stackless_EarlyPlatformInit
257 # Set up stack pointer
259 movl ASM_PFX(PcdGet32(PcdEsramStage1Base)), %esp
260 movl $QUARK_ESRAM_MEM_SIZE_BYTES, %esi
261 addl %esi, %esp # ESP = top of stack (stack grows downwards).
264 # Store the the BIST value in EBP
266 movl $0, %ebp # No processor BIST on Quark
269 # Push processor count to stack first, then BIST status (AP then BSP)
274 andl $0x000000FF, %ebx
276 jae PushProcessorCount
279 # Some processors report 0 logical processors. Effectively 0 = 1.
280 # So we fix up the processor count
288 # We need to implement a long-term solution for BIST capture. For now, we just copy BSP BIST
289 # for all processor threads
299 # Pass Control into the PEI Core
301 call PlatformSecLibStartup
304 # PEI Core should never return to here, this is just to capture an invalid return.
308 #----------------------------------------------------------------------------
310 # Procedure: stackless_EarlyPlatformInit
312 # Input: esp - Return address
316 # Destroys: Assume all registers
319 # Any early platform initialisation required
324 #----------------------------------------------------------------------------
325 stackless_EarlyPlatformInit:
328 # Save return address
333 # Ensure cache is disabled.
336 orl $(CR0_CACHE_DISABLE + CR0_NO_WRITE), %eax
341 # Disable NMI operation
342 # Good convention suggests you should read back RTC data port after
343 # accessing the RTC index port.
345 movb $(NMI_DISABLE), %al
346 movw $(RTC_INDEX), %dx
348 movw $(RTC_DATA), %dx
352 # Disable SMI (Disables SMI wire, not SMI messages)
354 movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx
356 jmp stackless_SideBand_Read
358 andl $(~SMI_EN), %eax
359 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMISC2_OFFSET << SB_ADDR_FIELD)), %ecx
361 jmp stackless_SideBand_Write
365 # Before we get going, check SOC Unit Registers to see if we are required to issue a warm/cold reset
367 movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx
369 jmp stackless_SideBand_Read
371 andl $(FORCE_WARM_RESET), %eax
372 jz TestForceColdReset # Zero means bit clear, we're not requested to warm reset so continue as normal
376 movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGNONSTICKY_W1_OFFSET << SB_ADDR_FIELD)), %ecx
378 jmp stackless_SideBand_Read
380 andl $(FORCE_COLD_RESET), %eax
381 jz TestHmboundLock # Zero means bit clear, we're not requested to cold reset so continue as normal
385 # Before setting HMBOUND, check it's not locked
388 movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx
390 jmp stackless_SideBand_Read
392 andl $(HMBOUND_LOCK), %eax
393 jz ConfigHmbound # Zero means bit clear, we have the config we want so continue as normal
395 # Failed to config - store sticky bit debug
397 movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
399 jmp stackless_SideBand_Read
401 orl $(RESET_FOR_HMBOUND_LOCK), %eax
402 movl $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
404 jmp stackless_SideBand_Write
409 # Set up the HMBOUND register
412 movl $(HMBOUND_ADDRESS), %eax # Data (Set HMBOUND location)
413 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HMBOUND_OFFSET << SB_ADDR_FIELD)), %ecx
415 jmp stackless_SideBand_Write
419 # Enable interrupts to Remote Management Unit when a IMR/SMM/HMBOUND violation occurs.
421 movl $(ENABLE_IMR_INTERRUPT), %eax # Data (Set interrupt enable mask)
422 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (BIMRVCTL_OFFSET << SB_ADDR_FIELD)), %ecx
424 jmp stackless_SideBand_Write
430 movl ASM_PFX(PcdGet32(PcdEsramStage1Base)), %eax # Data (Set eSRAM location)
432 addl $(BLOCK_ENABLE_PG), %eax
433 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx
435 jmp stackless_SideBand_Write
439 # Check that we're not blocked from setting the config that we want.
441 movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (MEMORY_MANAGER_PORT_ID << SB_PORT_FIELD) | (ESRAMPGCTRL_BLOCK_OFFSET << SB_ADDR_FIELD)), %ecx
443 jmp stackless_SideBand_Read
445 andl $(BLOCK_ENABLE_PG), %eax
446 jnz ConfigPci # Non-zero means bit set, we have the config we want so continue as normal
448 # Failed to config - store sticky bit debug
450 movl $((OPCODE_SIDEBAND_ALT_REG_READ << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
452 jmp stackless_SideBand_Read
454 orl $(RESET_FOR_ESRAM_LOCK), %eax # Set the bit we're interested in
455 movl $((OPCODE_SIDEBAND_ALT_REG_WRITE << SB_OPCODE_FIELD) | (SOC_UNIT_PORT_ID << SB_PORT_FIELD) | (CFGSTICKY_RW_OFFSET << SB_ADDR_FIELD)), %ecx
457 jmp stackless_SideBand_Write
465 movl $(EC_BASE + EC_ENABLE), %eax # Data
466 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (MEMORY_ARBITER_PORT_ID << SB_PORT_FIELD) | (AEC_CTRL_OFFSET << SB_ADDR_FIELD)), %ecx
468 jmp stackless_SideBand_Write
471 movl $(EC_BASE + EC_ENABLE), %eax # Data
472 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HECREG_OFFSET << SB_ADDR_FIELD)), %ecx
474 jmp stackless_SideBand_Write
478 # Open up full 8MB SPI decode
480 movl $(PCI_CFG | (ILB_PFA << 8) | BDE), %ebx # PCI Configuration address
481 movl $(DECODE_ALL_REGIONS_ENABLE), %eax
483 jmp stackless_PCIConfig_Write
487 # Enable NMI operation
488 # Good convention suggests you should read back RTC data port after
489 # accessing the RTC index port.
491 movb $(NMI_ENABLE), %al
492 movw $(RTC_INDEX), %dx
494 movw $(RTC_DATA), %dx
498 # Clear Host Bridge SMI, NMI, INTR fields
500 movl $((OPCODE_SIDEBAND_REG_READ << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HLEGACY_OFFSET << SB_ADDR_FIELD)), %ecx
502 jmp stackless_SideBand_Read
504 andl $~(NMI + SMI + INTR), %eax # Clear NMI, SMI, INTR fields
505 movl $((OPCODE_SIDEBAND_REG_WRITE << SB_OPCODE_FIELD) | (HOST_BRIDGE_PORT_ID << SB_PORT_FIELD) | (HLEGACY_OFFSET << SB_ADDR_FIELD)), %ecx
507 jmp stackless_SideBand_Write
511 # Restore return address
518 # Issue Warm Reset request to Remote Management Unit via iLB
520 movw $(CF9_WARM_RESET), %ax
521 movw $(ILB_RESET_REG), %dx
523 jmp . # Stay here until we are reset.
527 # Issue Cold Reset request to Remote Management Unit via iLB
529 movw $(CF9_COLD_RESET), %ax
530 movw $(ILB_RESET_REG), %dx
532 jmp . # Stay here until we are reset.
534 #----------------------------------------------------------------------------
536 # Procedure: stackless_SideBand_Read
538 # Input: esp - return address
539 # ecx[15:8] - Register offset
540 # ecx[23:16] - Port ID
541 # ecx[31:24] - Opcode
543 # Output: eax - Data read
552 # Perform requested sideband read
554 #----------------------------------------------------------------------------
555 stackless_SideBand_Read:
557 movl %esp, %esi # Save the return address
560 # Load the SideBand Packet Register to generate the transaction
562 movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx # PCI Configuration address
563 movb $(ALL_BYTE_EN << SB_BE_FIELD), %cl # Set all Byte Enable bits
566 jmp stackless_PCIConfig_Write
571 # Read the SideBand Data Register
573 movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx # PCI Configuration address
575 jmp stackless_PCIConfig_Read
578 movl %esi, %esp # Restore the return address
582 #----------------------------------------------------------------------------
584 # Procedure: stackless_SideBand_Write
586 # Input: esp - return address
588 # ecx[15:8] - Register offset
589 # ecx[23:16] - Port ID
590 # ecx[31:24] - Opcode
600 # Perform requested sideband write
603 #----------------------------------------------------------------------------
604 stackless_SideBand_Write:
606 movl %esp, %esi # Save the return address
609 # Load the SideBand Data Register with the data
611 movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_DATA_REG)), %ebx # PCI Configuration address
613 jmp stackless_PCIConfig_Write
617 # Load the SideBand Packet Register to generate the transaction
619 movl $((PCI_CFG) | (HOST_BRIDGE_PFA << 8) | (MESSAGE_BUS_CONTROL_REG)), %ebx # PCI Configuration address
620 movb $(ALL_BYTE_EN << SB_BE_FIELD), %cl # Set all Byte Enable bits
623 jmp stackless_PCIConfig_Write
627 movl %esi, %esp # Restore the return address
631 #----------------------------------------------------------------------------
633 # Procedure: stackless_PCIConfig_Write
635 # Input: esp - return address
636 # eax - Data to write
637 # ebx - PCI Config Address
645 # Perform a DWORD PCI Configuration write
647 #----------------------------------------------------------------------------
648 stackless_PCIConfig_Write:
651 # Write the PCI Config Address to the address port
654 movw $(PCI_ADDRESS_PORT), %dx
659 # Write the PCI DWORD Data to the data port
661 movw $(PCI_DATA_PORT), %dx
667 #----------------------------------------------------------------------------
669 # Procedure: stackless_PCIConfig_Read
671 # Input: esp - return address
672 # ebx - PCI Config Address
674 # Output: eax - Data read
681 # Perform a DWORD PCI Configuration read
683 #----------------------------------------------------------------------------
684 stackless_PCIConfig_Read:
687 # Write the PCI Config Address to the address port
690 movw $(PCI_ADDRESS_PORT), %dx
695 # Read the PCI DWORD Data from the data port
697 movw $(PCI_DATA_PORT), %dx
704 # ROM-based Global-Descriptor Table for the Tiano PEI Phase
708 # GDT[0]: 000h: Null entry, never used.
714 .equ NULL_SEL, . - GDT_BASE # Selector [0]
719 .byte 0 # limit 19:16, flags
722 # linear data segment descriptor
723 .equ LINEAR_SEL, . - GDT_BASE # Selector [0x8]
724 .word 0xFFFF # limit 0xFFFFF
727 .byte 0x92 # present, ring 0, data, expand-up, writable
728 .byte 0xCF # page-granular, 32-bit
731 # linear code segment descriptor
732 .equ LINEAR_CODE_SEL, . - GDT_BASE # Selector [0x10]
733 .word 0xFFFF # limit 0xFFFFF
736 .byte 0x9A # present, ring 0, data, expand-up, writable
737 .byte 0xCF # page-granular, 32-bit
740 # system data segment descriptor
741 .equ SYS_DATA_SEL, . - GDT_BASE # Selector [0x18]
742 .word 0xFFFF # limit 0xFFFFF
745 .byte 0x92 # present, ring 0, data, expand-up, writable
746 .byte 0xCF # page-granular, 32-bit
749 # system code segment descriptor
750 .equ SYS_CODE_SEL, . - GDT_BASE
751 .word 0xFFFF # limit 0xFFFFF
754 .byte 0x9A # present, ring 0, data, expand-up, writable
755 .byte 0xCF # page-granular, 32-bit
758 # spare segment descriptor
759 .equ SYS16_CODE_SEL, . - GDT_BASE
760 .word 0xffff # limit 0xFFFFF
763 .byte 0x9b # present, ring 0, data, expand-up, writable
764 .byte 0 # page-granular, 32-bit
767 # spare segment descriptor
768 .equ SYS16_DATA_SEL, . - GDT_BASE
769 .word 0xffff # limit 0xFFFFF
772 .byte 0x93 # present, ring 0, data, expand-up, not-writable
773 .byte 0 # page-granular, 32-bit
776 # spare segment descriptor
777 .equ SPARE5_SEL, . - GDT_BASE
778 .word 0 # limit 0xFFFFF
781 .byte 0 # present, ring 0, data, expand-up, writable
782 .byte 0 # page-granular, 32-bit
784 .equ GDT_SIZE, . - GDT_BASE
789 GdtDesc: # GDT descriptor
793 ProtectedModeEntryLinearAddress:
794 ProtectedModeEntryLinearOffset:
795 .long ProtectedModeEntryPoint
796 .word LINEAR_CODE_SEL