From 6c272b873425166c7c090bc075f531f0322e5f6a Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Thu, 2 Jun 2016 13:09:54 +0800 Subject: ChvRefCodePkg: Add CPU S3 code. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.asm | 143 +++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.s | 137 +++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.asm | 161 +++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.s | 175 ++++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Htequ.inc | 41 ++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Microcode.c | 311 ++++++++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpCommon.h | 210 +++++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.c | 678 ++++++++++++++++++++++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.inf | 50 ++ ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MtrrSync.c | 239 ++++++++ 10 files changed, 2145 insertions(+) create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.asm create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.s create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.asm create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.s create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Htequ.inc create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Microcode.c create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpCommon.h create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.c create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.inf create mode 100644 ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MtrrSync.c diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.asm b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.asm new file mode 100644 index 0000000000..30cd5c205f --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.asm @@ -0,0 +1,143 @@ +;; @file +; This is the code that supports IA32 CPU architectural protocol +; +; Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+; +; 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 +; +;; + +include Htequ.inc + +.686p +.model flat +.code + +PAUSE32 MACRO + DB 0F3h + DB 090h + ENDM + +EnableMCE proc near C public + + mov eax, cr4 + or eax, 40h + mov cr4, eax + + ret + +EnableMCE endp + +MpMtrrSynchUpEntry PROC NEAR C PUBLIC + ; + ; Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) + ; + mov eax, cr0 + and eax, 0DFFFFFFFh + or eax, 040000000h + mov cr0, eax + ; + ; Flush cache + ; + wbinvd + ; + ; Clear PGE flag Bit 7 + ; + mov eax, cr4 + mov edx, eax + and eax, 0FFFFFF7Fh + mov cr4, eax + ; + ; Flush all TLBs + ; + mov eax, cr3 + mov cr3, eax + + mov eax, edx + + ret + +MpMtrrSynchUpEntry ENDP + +MpMtrrSynchUpExit PROC NEAR C PUBLIC + + push ebp ; C prolog + mov ebp, esp + ; + ; Flush all TLBs the second time + ; + mov eax, cr3 + mov cr3, eax + ; + ; Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) + ; + mov eax, cr0 + and eax, 09FFFFFFFh + mov cr0, eax + ; + ; Set PGE Flag in CR4 if set + ; + mov eax, dword ptr [ebp + 8] + mov cr4, eax + + pop ebp + + ret + +MpMtrrSynchUpExit ENDP + +;------------------------------------------------------------------------------- +; AsmAcquireMPLock (&Lock); +;------------------------------------------------------------------------------- +AsmAcquireMPLock PROC near C PUBLIC + + pushad + mov ebp,esp + + mov al, NotVacantFlag + mov ebx, dword ptr [ebp+24h] +TryGetLock: + db 0f0h ; opcode for lock instruction + xchg al, byte ptr [ebx] + cmp al, VacantFlag + jz LockObtained + + PAUSE32 + jmp TryGetLock + +LockObtained: + popad + ret +AsmAcquireMPLock ENDP + +;------------------------------------------------------------------------------- +; AsmReleaseMPLock (&Lock); +;------------------------------------------------------------------------------------- +AsmReleaseMPLock PROC near C PUBLIC + + pushad + mov ebp,esp + + mov al, VacantFlag + mov ebx, dword ptr [ebp+24h] + db 0f0h ; opcode for lock instruction + xchg al, byte ptr [ebx] + + popad + ret +AsmReleaseMPLock ENDP + +CpuPause PROC NEAR C PUBLIC + + PAUSE32 + ret + +CpuPause ENDP + +END diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.s b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.s new file mode 100644 index 0000000000..8a973e785d --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/CpuAsm.s @@ -0,0 +1,137 @@ +## @file +# +# This is the code that supports IA32 CPU architectural protocol. +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# +# 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 +# +## +.equ VacantFlag, 0x00 +.equ NotVacantFlag, 0x0ff + +.equ LockLocation, 0x1000 - 0x0200 +.equ StackStartAddressLocation, LockLocation + 0x04 +.equ StackSizeLocation, LockLocation + 0x08 +.equ CProcedureLocation, LockLocation + 0x0C +.equ GdtrLocation, LockLocation + 0x10 +.equ IdtrLocation, LockLocation + 0x16 +.equ BufferStartLocation, LockLocation + 0x1C +.equ PmodeOffsetLocation, LockLocation + 0x20 +.equ AcpiCpuDataAddressLocatio, LockLocation + 0x24 +.equ MtrrValuesAddressLocation, LockLocation + 0x28 +.equ FinishedCountAddressLocation, LockLocation + 0x2C +.equ SerializeLockAddressLocation, LockLocation + 0x30 +.equ MicrocodeAddressLocation, LockLocation + 0x34 +.equ BootScriptAddressLocation, LockLocation + 0x38 +.equ StartStateLocation, LockLocation + 0x3C + + +ASM_GLOBAL ASM_PFX(EnableMCE) +ASM_PFX(EnableMCE): + movl %cr4, %eax + orl $0x40, %eax + movl %eax, %cr4 + ret +#EnableMCE endp + +ASM_GLOBAL ASM_PFX(MpMtrrSynchUpEntry) +ASM_PFX(MpMtrrSynchUpEntry): + # + # Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29) + # + movl %cr0, %eax + andl 0x0DFFFFFFF, %eax + orl 0x040000000, %eax + movl %eax, %cr0 + # + # Flush cache + # + wbinvd + # + # Clear PGE flag Bit 7 + # + movl %cr4, %eax + movl %eax, %edx + andl 0x0FFFFFF7F, %eax + movl %eax, %cr4 + # + # Flush all TLBs + # + movl %cr3, %eax + movl %eax, %cr3 + + movl %edx, %eax + ret +#MpMtrrSynchUpEntry ENDP + +ASM_GLOBAL ASM_PFX(MpMtrrSynchUpExit) +ASM_PFX(MpMtrrSynchUpExit): + push %ebp # C prolog + movl %esp, %ebp + # + # Flush all TLBs the second time + # + movl %cr3, %eax + movl %eax, %cr3 + # + # Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29) + # + movl %cr0, %eax + andl 0x09FFFFFFF, %eax + movl %eax, %cr0 + # + # Set PGE Flag in CR4 if set + # + movl 8(%ebp), %eax + movl %eax, %cr4 + + pop %ebp + ret +#MpMtrrSynchUpExit ENDP + +#------------------------------------------------------------------------------- +# AsmAcquireMPLock (&Lock) +#------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmAcquireMPLock) +ASM_PFX(AsmAcquireMPLock): + pushal + movl %esp, %ebp + + movb $NotVacantFlag, %al + movl 0x24(%ebp), %ebx +TryGetLock: + lock xchgb (%ebx), %al + cmpb $VacantFlag, %al + jz LockObtained + + .byte 0xf3, 0x90 # PAUSE32 + + jmp TryGetLock + +LockObtained: + popal + ret +#AsmAcquireMPLock ENDP + +#------------------------------------------------------------------------------- +# AsmReleaseMPLock (&Lock) +#------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmReleaseMPLock) +ASM_PFX(AsmReleaseMPLock): + pushal + movl %esp, %ebp + + movb $VacantFlag, %al + movl 0x24(%ebp), %ebx + lock xchgb (%ebx), %al + + popal + ret +#AsmReleaseMPLock ENDP diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.asm b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.asm new file mode 100644 index 0000000000..3d5a9fa203 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.asm @@ -0,0 +1,161 @@ +;; @file +; +; This is the equates file for HT (Hyper-threading) support +; +; Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+; +; 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 +; +;; +include Htequ.inc + +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc procedure follows. All APs execute their procedure. This +;procedure serializes all the AP processors through an Init sequence. It must be +;noted that APs arrive here very raw...ie: real mode, no stack. +;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +;IS IN MACHINE CODE. +;------------------------------------------------------------------------------------- +;RendezvousFunnelProc (&WakeUpBuffer,MemAddress); + +.686p +.model flat +.code + + +RendezvousFunnelProc PROC PUBLIC +RendezvousFunnelProcStart:: + +;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0. + + db 8ch,0c8h ; mov ax,cs + db 8eh,0d8h ; mov ds,ax + db 8eh,0c0h ; mov es,ax + db 8eh,0d0h ; mov ss,ax + db 33h,0c0h ; xor ax,ax + db 8eh,0e0h ; mov fs,ax + db 8eh,0e8h ; mov gs,ax + + db 0BEh, 1Ch, 0Eh ; mov si, BufferStartLocation + db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si] + + db 0BFh, 20h, 0Eh ; mov di, PmodeOffsetLocation + db 66h, 8Bh, 05h ; mov eax,dword ptr [di] + db 8Bh, 0F8h ; mov di, ax + db 83h, 0EFh,06h ; sub di, 06h + db 66h, 03h, 0C3h ; add eax, ebx + db 66h, 89h, 05h ; mov dword ptr [di],eax + + db 0BEh, 10h, 0Eh ; mov si, GdtrProfile + db 66h ; db 66h + db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si] + + db 33h, 0C0h ; xor ax, ax + db 8Eh, 0D8h ; mov ds, ax + + db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0 + db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP + db 0Fh, 22h, 0C0h ; mov cr0, eax + + db 66h, 67h, 0EAh ; far jump + dd 0h ; 32-bit offset + dw 20h ; 16-bit selector + +NemInit:: ; protected mode entry point + + db 66h, 0B8h, 18h, 00h ; mov ax, 18h + db 66h, 8Eh, 0D8h ; mov ds, ax + db 66h, 8Eh, 0C0h ; mov es, ax + db 66h, 8Eh, 0E0h ; mov fs, ax + db 66h, 8Eh, 0E8h ; mov gs, ax + db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup. + + mov esi, ebx + + mov edi, esi + add edi, StartStateLocation + mov eax, 1 + mov dword ptr [edi], eax + + mov edi, esi + add edi, LockLocation + mov eax, NotVacantFlag +TestLock:: + xchg dword ptr [edi], eax + cmp eax, NotVacantFlag + jz TestLock + +ProgramStack:: + + mov edi, esi + add edi, StackSizeLocation + mov eax, dword ptr [edi] + mov edi, esi + add edi, StackStartAddressLocation + add eax, dword ptr [edi] + mov esp, eax + mov dword ptr [edi], eax + +Releaselock:: + + mov eax, VacantFlag + mov edi, esi + add edi, LockLocation + xchg dword ptr [edi], eax + +CProcedureInvoke:: + + mov edi, esi + add edi, MtrrValuesAddressLocation + mov eax, dword ptr [edi] + push eax + + mov eax, esi + add eax, LockLocation + push eax + + mov edi, esi + add edi, CProcedureLocation + mov eax, dword ptr [edi] + + call eax + add esp, 8 + + cli + hlt + jmp $-2 + +RendezvousFunnelProc ENDP +RendezvousFunnelProcEnd:: + + +;------------------------------------------------------------------------------------- +; AsmGetAddressMap (&AddressMap); +;------------------------------------------------------------------------------------- +AsmGetAddressMap PROC near C PUBLIC + + mov eax, RendezvousFunnelProcStart + ret + +AsmGetAddressMap ENDP + +AsmGetPmodeOffset PROC near C PUBLIC + + mov eax, NemInit - RendezvousFunnelProcStart + ret + +AsmGetPmodeOffset ENDP + +AsmCliHltLoop PROC near C PUBLIC + cli + hlt + jmp $-2 +AsmCliHltLoop ENDP + +END diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.s b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.s new file mode 100644 index 0000000000..a8a0686040 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/HtFuncs.s @@ -0,0 +1,175 @@ +## @file +# This is the assembly code for HT (Hyper-threading) support +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# +# 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 +# +## +.equ VacantFlag, 0x00 +.equ NotVacantFlag, 0x0ff + +.equ LockLocation, 0x1000 - 0x0200 +.equ StackStartAddressLocation, LockLocation + 0x04 +.equ StackSizeLocation, LockLocation + 0x08 +.equ CProcedureLocation, LockLocation + 0x0C +.equ GdtrLocation, LockLocation + 0x10 +.equ IdtrLocation, LockLocation + 0x16 +.equ BufferStartLocation, LockLocation + 0x1C +.equ PmodeOffsetLocation, LockLocation + 0x20 +.equ AcpiCpuDataAddressLocatio, LockLocation + 0x24 +.equ MtrrValuesAddressLocation, LockLocation + 0x28 +.equ FinishedCountAddressLocation, LockLocation + 0x2C +.equ SerializeLockAddressLocation, LockLocation + 0x30 +.equ MicrocodeAddressLocation, LockLocation + 0x34 +.equ BootScriptAddressLocation, LockLocation + 0x38 +.equ StartStateLocation, LockLocation + 0x3C + +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc procedure follows. All APs execute their procedure. This +#procedure serializes all the AP processors through an Init sequence. It must be +#noted that APs arrive here very raw...ie: real mode, no stack. +#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC +#IS IN MACHINE CODE. +#------------------------------------------------------------------------------------- +#RendezvousFunnelProc (&WakeUpBuffer,MemAddress) + +ASM_GLOBAL ASM_PFX(RendezvousFunnelProc) +ASM_PFX(RendezvousFunnelProc): +RendezvousFunnelProcStart: + +#Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0. + .byte 0x8c,0xc8 # mov ax,cs + .byte 0x8e,0xd8 # mov ds,ax + .byte 0x8e,0xc0 # mov es,ax + .byte 0x8e,0xd0 # mov ss,ax + .byte 0x33,0xc0 # xor ax,ax + .byte 0x8e,0xe0 # mov fs,ax + .byte 0x8e,0xe8 # mov gs,ax + + .byte 0xBE, 0x1C, 0x0E # mov si, BufferStartLocation + .byte 0x66, 0x8B, 0x1C # mov ebx,dword ptr [si] + + .byte 0xBF, 0x20, 0x0E # mov di, PmodeOffsetLocation + .byte 0x66, 0x8B, 0x05 # mov eax,dword ptr [di] + .byte 0x8B, 0xF8 # mov di, ax + .byte 0x83, 0xEF, 0x06 # sub di, 06h + .byte 0x66, 0x03, 0xC3 # add eax, ebx + .byte 0x66, 0x89, 0x05 # mov dword ptr [di],eax + + .byte 0xBE, 0x10, 0x0E # mov si, GdtrProfile + .byte 0x66 # db 66h + .byte 0x2E, 0x0F, 0x01, 0x14 # lgdt fword ptr cs:[si] + + .byte 0x33, 0xC0 # xor ax, ax + .byte 0x8E, 0xD8 # mov ds, ax + + .byte 0x0F, 0x20, 0xC0 # mov eax, cr0 #Get control register 0 + .byte 0x66, 0x83, 0xC8, 0x03 # or eax, 000000003h #Set PE bit (bit #0) & MP + .byte 0x0F, 0x22, 0xC0 # mov cr0, eax + + .byte 0x66, 0x67, 0xEA # far jump + .word 0x0, 0x0 # 32-bit offset + .word 0x20 # 16-bit selector + +NemInit: # protected mode entry point + + .byte 0x66, 0xB8, 0x18, 0x00 # mov ax, 18h + .byte 0x66, 0x8E, 0xD8 # mov ds, ax + .byte 0x66, 0x8E, 0xC0 # mov es, ax + .byte 0x66, 0x8E, 0xE0 # mov fs, ax + .byte 0x66, 0x8E, 0xE8 # mov gs, ax + .byte 0x66, 0x8E, 0xD0 # mov ss, ax # Flat mode setup. + + movl %ebx, %esi + + movl %esi, %edi + addl $StartStateLocation, %edi + movl $1, %eax + movl %eax, (%edi) + + movl %esi, %edi + addl $LockLocation, %edi + movl $NotVacantFlag, %eax +TestLock: + xchgl %eax, (%edi) + cmpl $NotVacantFlag, %eax + jz TestLock + +ProgramStack: + + movl %esi, %edi + addl $StackSizeLocation, %edi + movl (%edi), %eax + movl %esi, %edi + addl $StackStartAddressLocation, %edi + addl (%edi), %eax + movl %eax, %esp + movl %eax, (%edi) + +Releaselock: + + movl $VacantFlag, %eax + movl %esi, %edi + addl $LockLocation, %edi + xchgl %eax, (%edi) + +CProcedureInvoke: + + movl %esi, %edi + addl $MtrrValuesAddressLocation, %edi + movl (%edi), %eax + push %eax + + movl %esi, %eax + addl $LockLocation, %eax + push %eax + + movl %esi, %edi + addl $CProcedureLocation, %edi + movl (%edi), %eax + + call %eax + addl $8, %esp + + cli + hlt + jmp .-2 + +#RendezvousFunnelProc ENDP +RendezvousFunnelProcEnd: + + +#------------------------------------------------------------------------------------- +# AsmGetAddressMap (&AddressMap) +#------------------------------------------------------------------------------------- +ASM_GLOBAL ASM_PFX(AsmGetAddressMap) +ASM_PFX(AsmGetAddressMap): + + movl $RendezvousFunnelProcStart, %eax + ret + +#AsmGetAddressMap ENDP + +ASM_GLOBAL ASM_PFX(AsmGetPmodeOffset) +ASM_PFX(AsmGetPmodeOffset): + + + movl $NemInit, %eax + subl $RendezvousFunnelProcStart, %eax + ret + +#AsmGetPmodeOffset ENDP + +ASM_GLOBAL ASM_PFX(AsmCliHltLoop) +ASM_PFX(AsmCliHltLoop): + cli + hlt + jmp .-2 +#AsmCliHltLoop ENDP diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Htequ.inc b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Htequ.inc new file mode 100644 index 0000000000..5ec0137311 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Htequ.inc @@ -0,0 +1,41 @@ +;; @file +; +; This is the equates file for HT (Hyper-threading) support +; +; Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.
+; +; 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 +; +;; + +VacantFlag Equ 00h +NotVacantFlag Equ 0ffh + +LockLocation equ 1000h - 0200h +StackStartAddressLocation equ LockLocation + 04h +StackSizeLocation equ LockLocation + 08h +CProcedureLocation equ LockLocation + 0Ch +GdtrLocation equ LockLocation + 10h +IdtrLocation equ LockLocation + 16h +BufferStartLocation equ LockLocation + 1Ch +PmodeOffsetLocation equ LockLocation + 20h +AcpiCpuDataAddressLocation equ LockLocation + 24h +MtrrValuesAddressLocation equ LockLocation + 28h +FinishedCountAddressLocation equ LockLocation + 2Ch +SerializeLockAddressLocation equ LockLocation + 30h +MicrocodeAddressLocation equ LockLocation + 34h +BootScriptAddressLocation equ LockLocation + 38h +StartStateLocation equ LockLocation + 3Ch + +PAUSE32 MACRO + DB 0F3h + DB 090h + ENDM + +;------------------------------------------------------------------------------- diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Microcode.c b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Microcode.c new file mode 100644 index 0000000000..40feaf4fec --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/Microcode.c @@ -0,0 +1,311 @@ +/** @file + Functions for loading Microcode. + + Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#include "MpCommon.h" + +// +// Array of pointers which each points to 1 microcode update binary (in memory) +// +EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer; + +// +// Function declarations +// +EFI_STATUS +FindLoadMicrocode ( + IN UINT32 Cpuid, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + IN OUT UINT32 *Revision, + IN OUT BOOLEAN *VerifyMicrocodeChecksum + ); + +#ifdef __GNUC__ // GCC compiler +UINT32 +GetCpuUcodeRevision ( + VOID + ) +{ + AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0); + AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); + return (UINT32) RShiftU64 (AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID), 32); +} +#else // MSFT compiler + +/** + + @todo add description + +**/ +UINT32 +GetCpuUcodeRevision ( + VOID + ) +{ + UINT32 registers[4]; + __writemsr (EFI_MSR_IA32_BIOS_SIGN_ID, 0); + __cpuid (registers, EFI_CPUID_VERSION_INFO); + return (UINT32) (__readmsr (EFI_MSR_IA32_BIOS_SIGN_ID) >> 32); +} +#endif + +/** + + This will locate a processor microcode and if it finds a newer revision, it will + load it to the processor. + + @param[in] + + MicrocodePointerBuffer - The Array of pointers which each points to 1 microcode update binary (in memory) + + FailedRevision - The microcode revision that fails to be loaded + + @retval + + EFI_SUCCESS - A new microcode update is loaded + Other - Due to some reason, no new microcode update is loaded + +**/ +EFI_STATUS +InitializeMicrocode ( + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + OUT UINT32 *FailedRevision, + IN BOOLEAN IsBsp, + IN OUT BOOLEAN *VerifyMicrocodeChecksum + ) + +{ + EFI_STATUS Status; + UINT32 UcodeRevision; + UINT32 RegEax; + + AsmCpuid (EFI_CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL); + + if (IsBsp) { + // + // Force Microcode to be loaded for BSP anyway + // + UcodeRevision = 0; + } else { + UcodeRevision = GetCpuUcodeRevision (); + } + + Status = FindLoadMicrocode (RegEax, MicrocodePointerBuffer, &UcodeRevision, VerifyMicrocodeChecksum); + *FailedRevision = UcodeRevision; + return Status; +} + +/** + + This will load the microcode to all the processors. + + @param[in] + MicrocodeEntryPoint - The microcode update pointer + Revision - The current (before load this microcode update) microcode revision + + @retval + + EFI_SUCCESS - Microcode loaded + EFI_LOAD_ERROR - Microcode not loaded + +**/ +EFI_STATUS +LoadMicrocode ( + IN EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint, + IN UINT32 *Revision + ) + +{ + // + // Load the Processor Microcode + // + AsmWriteMsr64 ( + EFI_MSR_IA32_BIOS_UPDT_TRIG, + (UINT64) ((UINTN) MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER)) + ); + + // + // Verify that the microcode has been loaded + // + if (GetCpuUcodeRevision () == *Revision) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Verify the DWORD type checksum + + @param[in] *ChecksumAddr - The start address to be checkumed + + @param[in] ChecksumType - The type of data to be checksumed + + @retval EFI_SUCCESS - Checksum correct + @retval EFI_CRC_ERROR - Checksum incorrect + +**/ +EFI_STATUS +Checksum32Verify ( + IN UINT32 *ChecksumAddr, + IN UINT32 ChecksumLen + ) + +{ + UINT32 Checksum; + UINT32 Index; + + Checksum = 0; + + for (Index = 0; Index < ChecksumLen; Index ++) { + Checksum += ChecksumAddr[Index]; + } + + return (Checksum == 0) ? EFI_SUCCESS : EFI_CRC_ERROR; +} + +/** + + This will locate a processor microcode and if it finds a newer revision, it will + load it to the processor. + + @param[in] Cpuid - Data returned by cpuid instruction + + @param[in] MicrocodePointerBuffer - The Array of pointers which each points to 1 microcode update binary (in memory) + + @param[in] Revision - As input parameter, the current microcode revision; + as output parameter, the microcode revision after microcode update is loaded + + @retval EFI_SUCCESS - A new microcode update is loaded + @retval Other - Due to some reason, no new microcode update is loaded + +**/ +EFI_STATUS +FindLoadMicrocode ( + IN UINT32 Cpuid, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + IN OUT UINT32 *Revision, + IN OUT BOOLEAN *VerifyMicrocodeChecksum + ) + +{ + EFI_STATUS Status; + EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINT8 Index; + UINT8 MsrPlatform; + UINT32 ExtendedTableLength; + UINT32 ExtendedTableCount; + BOOLEAN CorrectMicrocode; + EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + UINT8 IndexStep; + + Status = EFI_NOT_FOUND; + ExtendedTableLength = 0; + + // + // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID + // + MsrPlatform = (UINT8) (RShiftU64 ((AsmReadMsr64 (EFI_MSR_IA32_PLATFORM_ID) & B_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS_MASK), \ + N_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS)); + + IndexStep = (UINT32) (MicrocodePointerBuffer [1]) == 0 ? 2 : 1; + + Index = 0; + while (MicrocodePointerBuffer[Index] != NULL) { + MicrocodeEntryPoint = MicrocodePointerBuffer[Index]; + CorrectMicrocode = FALSE; + // + // Check if the microcode is for the Cpu and the version is newer + // and the update can be processed on the platform + // + if (MicrocodeEntryPoint->HeaderVersion == 0x00000001) { + if ((MicrocodeEntryPoint->ProcessorId == Cpuid) && + (MicrocodeEntryPoint->UpdateRevision > *Revision) && + (MicrocodeEntryPoint->ProcessorFlags & (1 << MsrPlatform)) ) { + if (*VerifyMicrocodeChecksum == TRUE) { + if (MicrocodeEntryPoint->DataSize == 0) { + Status = Checksum32Verify ((UINT32 *)MicrocodeEntryPoint, 2048 / sizeof(UINT32)); + } else { + Status = Checksum32Verify ((UINT32 *)MicrocodeEntryPoint, (MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER)) / sizeof(UINT32)); + } + if (!EFI_ERROR (Status)) { + *VerifyMicrocodeChecksum = FALSE; + CorrectMicrocode = TRUE; + } + } else { + CorrectMicrocode = TRUE; + } + } else if ((MicrocodeEntryPoint->DataSize !=0) && (MicrocodeEntryPoint->UpdateRevision > *Revision)) { + // + // Check the Extended Signature if the entended signature exist + // Only the data size != 0 the extended signature may exist + // + ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER)); + if (ExtendedTableLength != 0) { + // + // Extended Table exist, check if the CPU in support list + // + ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + 48); + // + // Calulate Extended Checksum + // + if ((ExtendedTableLength % 4) == 0) { + Status = Checksum32Verify ((UINT32 *)ExtendedTableHeader, ExtendedTableLength / sizeof(UINT32)); + if (!EFI_ERROR (Status)) { + // + // Checksum correct + // + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1); + for (Index = 0; Index < ExtendedTableCount; Index ++) { + Status = Checksum32Verify ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE) / sizeof(UINT32)); + if (!EFI_ERROR (Status)) { + // + // Verify Header + // + if ((ExtendedTable->ProcessorSignature == Cpuid) && + (ExtendedTable->ProcessorFlag & (1 << MsrPlatform)) ) { + // + // Find one + // + CorrectMicrocode = TRUE; + break; + } + } + ExtendedTable ++; + } + } + } + } + } + } + + if (CorrectMicrocode) { + Status = LoadMicrocode (MicrocodeEntryPoint, Revision); + *Revision = MicrocodeEntryPoint->UpdateRevision; + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Increase table index, 32-bit : 1, 64-bit : 2 + // + Index += IndexStep; + + } + + return Status; +} diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpCommon.h b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpCommon.h new file mode 100644 index 0000000000..ec5f73cdd7 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpCommon.h @@ -0,0 +1,210 @@ +/** @file + Definitions for MP and HT driver. + + Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _MP_COMMON_ +#define _MP_COMMON_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../Include/CpuRegs.h" +#include "../Include/CpuDataStruct.h" + + +#define TRIGGER_MODE_EDGE 0x0 +#define TRIGGER_MODE_LEVEL 0x1 +#define DELIVERY_MODE_INIT 0x5 +#define DELIVERY_MODE_SIPI 0x6 + +#define VacantFlag 0x00 +#define NotVacantFlag 0xff + +#define MICROSECOND 10 + +#define MAXIMUM_CPU_NUMBER 0x40 +#define STACK_SIZE_PER_PROC 0x8000 + +#define MAXIMUM_CPU_S3_TABLE_SIZE 0x1000 + +#define IO_APIC_INDEX_REGISTER 0xFEC00000 +#define IO_APIC_DATA_REGISTER 0xFEC00010 + +extern UINTN FixedMtrrNumber; +extern UINTN MtrrDefTypeNumber; +extern UINTN VariableMtrrNumber; + +/** + + @todo add description + +**/ +typedef struct { + UINT8 APSerializeLock; + + UINT8 Tm2Core2BusRatio; + UINT8 Tm2Vid; + BOOLEAN LimitCpuidMaximumValue; + BOOLEAN IsC1eSupported; + BOOLEAN IsXapicSupported; + BOOLEAN IsCCxSupported; + + UINT32 ApicID[MAXIMUM_CPU_NUMBER]; + + UINT64 NumberOfCPUs; + UINT64 NumberOfEnabledCPUs; + UINT64 MaximumCPUsForThisSystem; + + UINTN mFinishedCount; +} HT_SYSTEM_DATA; + +/** + + @todo add description + +**/ +typedef struct { + UINT16 Index; + UINT64 Value; +} EFI_MTRR_VALUES; + +/** + + @todo add description + +**/ +typedef struct { + UINT32 ApicId; + UINT32 MsrIndex; + UINT64 MsrValue; +} MP_CPU_S3_SCRIPT_DATA; + +/** + + @todo add description + +**/ +typedef struct { + UINT32 S3BootScriptTable; + UINT32 S3BspMtrrTable; + UINT32 VirtualWireMode; +} MP_CPU_S3_DATA_POINTER; + +/** + + @todo add description + +**/ +typedef struct { + UINT32 Lock; + UINT32 StackStart; + UINT32 StackSize; + UINT32 ApFunction; + IA32_DESCRIPTOR GdtrProfile; + IA32_DESCRIPTOR IdtrProfile; + UINT32 BufferStart; + UINT32 PmodeOffset; + UINT32 AcpiCpuDataAddress; + UINT32 MtrrValuesAddress; + UINT32 FinishedCount; + UINT32 SerializeLock; + UINT32 MicrocodePointer; + MP_CPU_S3_SCRIPT_DATA *S3BootScriptTable; + UINT32 StartState; + UINT32 VirtualWireMode; + BOOLEAN VerifyMicrocodeChecksum; +} MP_CPU_EXCHANGE_INFO; + +VOID * +AsmGetPmodeOffset ( + ); + +VOID +ReadMtrrRegisters ( + UINT64 *MtrrValues + ); + +VOID +MpMtrrSynchUp ( + UINT64 *MtrrValues + ); + +VOID +SetBspMtrrRegisters ( + IN EFI_MTRR_VALUES *MtrrArray + ); + +EFI_STATUS +InitializeMicrocode ( + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + OUT UINT32 *FailedRevision, + IN BOOLEAN IsBsp, + IN OUT BOOLEAN *VerifyMicrocodeChecksum + ); + +// +// Functions shared in MP/HT drivers +// +EFI_STATUS +SendInterrupt ( + IN UINT32 BroadcastMode, + IN UINT32 ApicID, + IN UINT32 VectorNumber, + IN UINT32 DeliveryMode, + IN UINT32 TriggerMode, + IN BOOLEAN Assert, + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STALL_PPI *PeiStall + ); + +UINT32 +GetApicID ( + VOID + ); + +VOID +ProgramVirtualWireMode ( + BOOLEAN BSP, + UINT32 VirtualWireMode + ); + +VOID +AsmAcquireMPLock ( + IN UINT8 *Lock + ); + +VOID +AsmReleaseMPLock ( + IN UINT8 *Lock + ); + +VOID * +AsmGetAddressMap ( + ); + +VOID +AsmCliHltLoop ( + ); + +VOID +CpuPause ( + VOID + ); + +#endif diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.c b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.c new file mode 100644 index 0000000000..94fe13f0ef --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.c @@ -0,0 +1,678 @@ +/** @file + Cpu driver running on S3 boot path. + + Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#include "MpCommon.h" + +EFI_GUID mSmramCpuNvsHeaderGuid = EFI_SMRAM_CPU_NVS_HEADER_GUID; + +/** + + @todo add description + +**/ +UINT32 +GetApicID ( + VOID +) +{ + UINT32 RegEbx; + + AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); + return (UINT32)(RegEbx >> 24); +} + +/** + + @todo Add function description + + @param[in] BroadcastMode - @todo add argument description + @param[in] ApicID - @todo add argument description + @param[in] VectorNumber - @todo add argument description + @param[in] DeliveryMode - @todo add argument description + @param[in] TriggerMode - @todo add argument description + @param[in] Assert - @todo add argument description + + @retval EFI_INVALID_PARAMETER - @todo Add description for return value + @retval EFI_NOT_READY - @todo Add description for return value + @retval EFI_SUCCESS - @todo Add description for return value + +**/ + +EFI_STATUS +SendInterrupt ( + IN UINT32 BroadcastMode, + IN UINT32 ApicID, + IN UINT32 VectorNumber, + IN UINT32 DeliveryMode, + IN UINT32 TriggerMode, + IN BOOLEAN Assert, + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STALL_PPI *PeiStall + ) +{ + UINT64 ApicBaseReg; + EFI_PHYSICAL_ADDRESS ApicBase; + UINT32 ICRLow; + UINT32 ICRHigh; + + // + // Initialze ICR high dword, since P6 family processor needs + // the destination field to be 0x0F when it is a broadcast + // + ICRHigh = 0x0f000000; + ICRLow = VectorNumber | (DeliveryMode << 8); + + if (TriggerMode == TRIGGER_MODE_LEVEL) { + ICRLow |= 0x8000; + } + + if (Assert) { + ICRLow |= 0x4000; + } + + switch (BroadcastMode) { + case BROADCAST_MODE_SPECIFY_CPU: + ICRHigh = ApicID << 24; + break; + + case BROADCAST_MODE_ALL_INCLUDING_SELF: + ICRLow |= 0x80000; + break; + + case BROADCAST_MODE_ALL_EXCLUDING_SELF: + ICRLow |= 0xC0000; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + ApicBaseReg = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE); + ApicBase = ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS; + + *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET) = ICRHigh; + *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET) = ICRLow; + + PeiStall->Stall( + PeiServices, + PeiStall, + 10 + ); + + ICRLow = *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET); + if (ICRLow & 0x1000) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +/** + + @todo Add function description + + @param[in] BSP - @todo add argument description + @param[in] VirtualWireMode - @todo add argument description + + @retval @todo add return values + +**/ +VOID +ProgramVirtualWireMode ( + BOOLEAN BSP, + UINT32 VirtualWireMode + ) +{ + UINT64 ApicBaseReg; + EFI_PHYSICAL_ADDRESS ApicBase; + volatile UINT32 *EntryAddress; + UINT32 EntryValue; + + ApicBaseReg = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE); + ApicBase = ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS; + + // + // Program the Spurious Vectore entry + // + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET); + EntryValue = *EntryAddress; + EntryValue &= 0xFFFFFD0F; + EntryValue |= 0x10F; + *EntryAddress = EntryValue; + + // + // Program the LINT1 vector entry as extINT + // + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET); + EntryValue = *EntryAddress; + if (VirtualWireMode != 0) { + EntryValue |= 0x10000; + } else { + if (BSP) { + EntryValue &= 0xFFFE00FF; + EntryValue |= 0x700; + } else { + EntryValue |= 0x10000; + } + } + *EntryAddress = EntryValue; + + // + // Program the LINT1 vector entry as NMI + // + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT1_VECTOR_OFFSET); + EntryValue = *EntryAddress; + EntryValue &= 0xFFFE00FF; + if (BSP) { + EntryValue |= 0x400; + } else { + EntryValue |= 0x10400; + } + *EntryAddress = EntryValue; + + if (VirtualWireMode && BSP) { + // + // Initialize the I0XApic RT table for virtual wire B + // + *(volatile UINT8 *)(UINTN)IO_APIC_INDEX_REGISTER = 0x10; + *(volatile UINT32 *)(UINTN)IO_APIC_DATA_REGISTER = 0x0700; + *(volatile UINT8 *)(UINTN)IO_APIC_INDEX_REGISTER = 0x11; + *(volatile UINT32 *)(UINTN)IO_APIC_DATA_REGISTER = (GetApicID () << 24); + } + +} + +/** + + @todo Add description + +**/ +VOID +InitializeFeatures ( + IN MP_CPU_S3_SCRIPT_DATA *ScriptTable + ) +{ + UINT32 RegEbx; + UINT32 ApicId; + UINT8 SkipMsr; + // + // Restore all the MSRs for processor + // + AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); + ApicId = (RegEbx >> 24); + + while (ScriptTable->MsrIndex != 0) { + if (ApicId == ScriptTable->ApicId) { + SkipMsr = 0; + if ( (ScriptTable->MsrIndex == EFI_MSR_PMG_CST_CONFIG) && + (AsmReadMsr64(EFI_MSR_PMG_CST_CONFIG) & B_EFI_MSR_PMG_CST_CONFIG_CST_CONTROL_LOCK) ) { + SkipMsr = 1; + } + if (SkipMsr == 0) { + AsmWriteMsr64 (ScriptTable->MsrIndex, ScriptTable->MsrValue); + } + } + ScriptTable++; + } +} + +/** + + @todo Add description + +**/ +VOID +MPRendezvousProcedure ( + MP_CPU_EXCHANGE_INFO *ExchangeInfo, + UINT64 *MtrrValues + ) +{ + UINT32 FailedRevision; + BOOLEAN VerifyMicrocodeChecksum; + + ProgramVirtualWireMode (FALSE, ExchangeInfo->VirtualWireMode); + VerifyMicrocodeChecksum = ExchangeInfo->VerifyMicrocodeChecksum; + InitializeMicrocode ((EFI_CPU_MICROCODE_HEADER **)(UINTN)ExchangeInfo->MicrocodePointer, &FailedRevision, FALSE, &VerifyMicrocodeChecksum); + // TODO: InitializeFeatures (ExchangeInfo->S3BootScriptTable); + MpMtrrSynchUp (MtrrValues); + + AsmAcquireMPLock ((UINT8 *)&(ExchangeInfo->SerializeLock)); + ExchangeInfo->FinishedCount++; + AsmReleaseMPLock ((UINT8 *)&(ExchangeInfo->SerializeLock)); +} + +/** + + Wake up all the application processors + + @param[in] ImageHandle - Image handle of the loaded driver + + @retval EFI_SUCCESS - APs are successfully waked up + +**/ +EFI_STATUS +WakeUpAPs ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STALL_PPI *PeiStall, + ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData, + UINT64 *MtrrValues, + IN BOOLEAN VerifyMicrocodeChecksum + ) +{ + EFI_PHYSICAL_ADDRESS WakeUpBuffer; + MP_CPU_EXCHANGE_INFO *ExchangeInfo; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + + WakeUpBuffer = mAcpiCpuData->WakeUpBuffer; + CopyMem ((VOID *) (UINTN) WakeUpBuffer, AsmGetAddressMap(), 0x1000 - 0x200); + + ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + (0x1000 - 0x200)); + + ExchangeInfo->Lock = 0; + ExchangeInfo->StackStart = (UINTN) mAcpiCpuData->StackAddress; + ExchangeInfo->StackSize = STACK_SIZE_PER_PROC; + ExchangeInfo->ApFunction = (UINT32) MPRendezvousProcedure; + ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer; + ExchangeInfo->PmodeOffset = (UINT32) (AsmGetPmodeOffset ()); + ExchangeInfo->AcpiCpuDataAddress = (UINT32) mAcpiCpuData; + ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues; + ExchangeInfo->FinishedCount = (UINT32) 0; + ExchangeInfo->SerializeLock = (UINT32) 0; + ExchangeInfo->MicrocodePointer = (UINT32) (UINTN)mAcpiCpuData->MicrocodePointerBuffer; + ExchangeInfo->StartState = (UINT32) 0; + + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *)(UINTN)mAcpiCpuData->CpuPrivateData; + ExchangeInfo->S3BootScriptTable = (MP_CPU_S3_SCRIPT_DATA *)(UINTN)CpuS3DataPtr->S3BootScriptTable; + ExchangeInfo->VirtualWireMode = CpuS3DataPtr->VirtualWireMode; + ExchangeInfo->VerifyMicrocodeChecksum = VerifyMicrocodeChecksum; + + CopyMem ((VOID *) (UINTN) &ExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR)); + CopyMem ((VOID *) (UINTN) &ExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR)); + + DEBUG ((DEBUG_ERROR, "Cpu S3 Bootscript at %08X\n", (UINT32)ExchangeInfo->S3BootScriptTable)); + + // + // Don't touch MPCPU private data + // Here we use ExchangeInfo instead + // + + // + // Send INIT IPI - SIPI to all APs + // + SendInterrupt ( + BROADCAST_MODE_ALL_EXCLUDING_SELF, + 0, + 0, + DELIVERY_MODE_INIT, + TRIGGER_MODE_EDGE, + TRUE, + PeiServices, + PeiStall + ); + + SendInterrupt ( + BROADCAST_MODE_ALL_EXCLUDING_SELF, + 0, + (UINT32) RShiftU64 (WakeUpBuffer, 12), + DELIVERY_MODE_SIPI, + TRIGGER_MODE_EDGE, + TRUE, + PeiServices, + PeiStall + ); + while (ExchangeInfo->FinishedCount < mAcpiCpuData->NumberOfCpus - 1) { + CpuPause (); + } + + return EFI_SUCCESS; +} + +/** + + This routine is used to search SMRAM and get SmramCpuData point. + + @param[in] PeiServices - PEI services global pointer + @param[in] SmmAccessPpi - SmmAccess PPI instance + +@returns SmramCpuData - The pointer of CPU information in SMRAM. + +**/ +STATIC +SMRAM_CPU_DATA * +GetSmmCpuData ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_SMM_ACCESS_PPI *SmmAccessPpi + ) +{ + EFI_SMRAM_DESCRIPTOR *SmramRanges; + UINTN SmramRangeCount; + UINTN Size; + EFI_STATUS Status; + UINT32 Address; + SMRAM_CPU_DATA *SmramCpuData; + + // + // Get all SMRAM range + // + Size = 0; + Status = SmmAccessPpi->GetCapabilities (PeiServices, SmmAccessPpi, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + Status = PeiServicesAllocatePool ( + Size, + (VOID **)&SmramRanges + ); + ASSERT_EFI_ERROR (Status); + + Status = SmmAccessPpi->GetCapabilities (PeiServices, SmmAccessPpi, &Size, SmramRanges); + ASSERT_EFI_ERROR (Status); + + Size /= sizeof (*SmramRanges); + SmramRangeCount = Size; + + // + // BUGBUG: We assume TSEG is the last range of SMRAM in SmramRanges + // + SmramRanges += SmramRangeCount - 1; + + DEBUG (( DEBUG_ERROR, "TsegBase - %x\n", SmramRanges->CpuStart)); + DEBUG (( DEBUG_ERROR, "TsegTop - %x\n", SmramRanges->CpuStart + SmramRanges->PhysicalSize)); + + // + // Search SMRAM on page alignment for the SMMNVS signature + // + for (Address = (UINT32)(SmramRanges->CpuStart + SmramRanges->PhysicalSize - EFI_PAGE_SIZE); + Address >= (UINT32)SmramRanges->CpuStart; + Address -= EFI_PAGE_SIZE) { + SmramCpuData = (SMRAM_CPU_DATA *)(UINTN)Address; + if (CompareGuid (&SmramCpuData->HeaderGuid, &mSmramCpuNvsHeaderGuid)) { + // + // Find it + // + return SmramCpuData; + } + } + + ASSERT (FALSE); + + return NULL; +} + +/** + + This routine is restore the CPU information from SMRAM to original reserved memory region. + + @param[in] PeiServices - PEI services global pointer + + @returns AcpiCpuData - The pointer of CPU information in reserved memory. + +**/ +ACPI_CPU_DATA_COMPATIBILITY * +RestoreSmramCpuData ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + PEI_SMM_ACCESS_PPI *SmmAccessPpi; + SMRAM_CPU_DATA *SmramCpuData; + EFI_STATUS Status; + ACPI_CPU_DATA_COMPATIBILITY *AcpiCpuData; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + IA32_DESCRIPTOR *Idtr; + IA32_DESCRIPTOR *Gdtr; + UINTN MicrocodeSize; + EFI_CPU_MICROCODE_HEADER **Microcode; + EFI_CPU_MICROCODE_HEADER *LockBoxMicrocode; + UINTN Index; + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **)&SmmAccessPpi + ); + ASSERT_EFI_ERROR (Status); + + // + // Open all SMM regions + // + Index = 0; + do { + Status = SmmAccessPpi->Open ((EFI_PEI_SERVICES**)PeiServices, SmmAccessPpi, Index); + Index++; + } while (!EFI_ERROR (Status)); + + SmramCpuData = GetSmmCpuData ((EFI_PEI_SERVICES**)PeiServices, SmmAccessPpi); + if (SmramCpuData == NULL) { + ASSERT(SmramCpuData != NULL); + return NULL; + } + + DEBUG ((DEBUG_ERROR, "CpuS3 SmramCpuData - 0x%x \n", SmramCpuData)); + + DEBUG ((DEBUG_ERROR, "SmramCpuData->GdtrProfileSize - %x\n", SmramCpuData->GdtrProfileSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->GdtSize - %x\n", SmramCpuData->GdtSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->IdtrProfileSize - %x\n", SmramCpuData->IdtrProfileSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->IdtSize - %x\n", SmramCpuData->IdtSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->CpuPrivateDataSize - %x\n", SmramCpuData->CpuPrivateDataSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->S3BootScriptTableSize - %x\n", SmramCpuData->S3BootScriptTableSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->S3BspMtrrTableSize - %x\n", SmramCpuData->S3BspMtrrTableSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->MicrocodePointerBufferSize - %x\n", SmramCpuData->MicrocodePointerBufferSize)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->MicrocodeDataBufferSize - %x\n", SmramCpuData->MicrocodeDataBufferSize)); + + DEBUG ((DEBUG_ERROR, "SmramCpuData->GdtrProfileOffset - %x\n", SmramCpuData->GdtrProfileOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->GdtOffset - %x\n", SmramCpuData->GdtOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->IdtrProfileOffset - %x\n", SmramCpuData->IdtrProfileOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->IdtOffset - %x\n", SmramCpuData->IdtOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->CpuPrivateDataOffset - %x\n", SmramCpuData->CpuPrivateDataOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->S3BootScriptTableOffset - %x\n", SmramCpuData->S3BootScriptTableOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->S3BspMtrrTableOffset - %x\n", SmramCpuData->S3BspMtrrTableOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->MicrocodePointerBufferOffset - %x\n", SmramCpuData->MicrocodePointerBufferOffset)); + DEBUG ((DEBUG_ERROR, "SmramCpuData->MicrocodeDataBufferOffset - %x\n", SmramCpuData->MicrocodeDataBufferOffset)); + + // + // Start restore data to NVS + // + AcpiCpuData = (ACPI_CPU_DATA_COMPATIBILITY *)(UINTN)SmramCpuData->AcpiCpuPointer; + CopyMem (AcpiCpuData, &SmramCpuData->AcpiCpuData, sizeof (ACPI_CPU_DATA_COMPATIBILITY)); + + DEBUG ((DEBUG_ERROR, "AcpiCpuData->WakeUpBuffer - %x\n", AcpiCpuData->WakeUpBuffer)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->GdtrProfile - %x\n", AcpiCpuData->GdtrProfile)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->IdtrProfile - %x\n", AcpiCpuData->IdtrProfile)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->CpuPrivateData - %x\n", AcpiCpuData->CpuPrivateData)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->StackAddress - %x\n", AcpiCpuData->StackAddress)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->MicrocodePointerBuffer - %x\n", AcpiCpuData->MicrocodePointerBuffer)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->SmramBase - %x\n", AcpiCpuData->SmramBase)); + DEBUG ((DEBUG_ERROR, "AcpiCpuData->SmmStartImageBase - %x\n", AcpiCpuData->SmmStartImageBase)); + + CopyMem ( + (VOID *)(UINTN)AcpiCpuData->GdtrProfile, + (UINT8 *)SmramCpuData + SmramCpuData->GdtrProfileOffset, + SmramCpuData->GdtrProfileSize + ); + Gdtr = (IA32_DESCRIPTOR *)(UINTN)AcpiCpuData->GdtrProfile; + CopyMem ( + (VOID *)(UINTN)Gdtr->Base, + (UINT8 *)SmramCpuData + SmramCpuData->GdtOffset, + SmramCpuData->GdtSize + ); + DEBUG ((DEBUG_ERROR, "Gdtr->Base - %x\n", (UINT32) (Gdtr->Base))); + CopyMem ( + (VOID *)(UINTN)AcpiCpuData->IdtrProfile, + (UINT8 *)SmramCpuData + SmramCpuData->IdtrProfileOffset, + SmramCpuData->IdtrProfileSize + ); + Idtr = (IA32_DESCRIPTOR *)(UINTN)AcpiCpuData->IdtrProfile; + CopyMem ( + (VOID *)(UINTN)Idtr->Base, + (UINT8 *)SmramCpuData + SmramCpuData->IdtOffset, + SmramCpuData->IdtSize + ); + DEBUG ((DEBUG_ERROR, "Idtr->Base - %x\n", (UINT32) (Idtr->Base))); + CopyMem ( + (VOID *)(UINTN)AcpiCpuData->CpuPrivateData, + (UINT8 *)SmramCpuData + SmramCpuData->CpuPrivateDataOffset, + SmramCpuData->CpuPrivateDataSize + ); + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *)(UINTN)AcpiCpuData->CpuPrivateData; + + // + // TODO: + // CopyMem ( + // (VOID *)(UINTN)CpuS3DataPtr->S3BootScriptTable, + // (UINT8 *)SmramCpuData + SmramCpuData->S3BootScriptTableOffset, + // SmramCpuData->S3BootScriptTableSize + // ); + // + DEBUG ((DEBUG_ERROR, "CpuS3DataPtr->S3BootScriptTable - %x\n", (UINT32) (CpuS3DataPtr->S3BootScriptTable))); + + // + // TODO: BSP MTRRs are initialized by FSP. + // CopyMem ( + // (VOID *)(UINTN)CpuS3DataPtr->S3BspMtrrTable, + // (UINT8 *)SmramCpuData + SmramCpuData->S3BspMtrrTableOffset, + // SmramCpuData->S3BspMtrrTableSize + // ); + DEBUG ((DEBUG_ERROR, "CpuS3DataPtr->S3BspMtrrTable - %x\n", (UINT32) (CpuS3DataPtr->S3BspMtrrTable))); + CopyMem ( + (VOID *)(UINTN)AcpiCpuData->MicrocodePointerBuffer, + (UINT8 *)SmramCpuData + SmramCpuData->MicrocodePointerBufferOffset, + SmramCpuData->MicrocodePointerBufferSize + ); + + // + // Restore Microcode Data + // + Microcode = (VOID *)(UINTN)AcpiCpuData->MicrocodePointerBuffer; + LockBoxMicrocode = (EFI_CPU_MICROCODE_HEADER *)((UINT8 *)SmramCpuData + SmramCpuData->MicrocodeDataBufferOffset); + if (Microcode != NULL) { + Index = 0; + MicrocodeSize = 0; + while (Microcode[Index] != NULL) { + if (LockBoxMicrocode->DataSize == 0) { + MicrocodeSize = 2048; + } else { + MicrocodeSize = LockBoxMicrocode->TotalSize; + } + CopyMem (Microcode[Index], LockBoxMicrocode, MicrocodeSize); + LockBoxMicrocode = (EFI_CPU_MICROCODE_HEADER *)((UINT8 *)LockBoxMicrocode + MicrocodeSize); + Index ++; + } + } + + // + // Close all SMM regions + // + Index = 0; + do { + Status = SmmAccessPpi->Close ((EFI_PEI_SERVICES**)PeiServices, SmmAccessPpi, Index); + Index++; + } while (!EFI_ERROR (Status)); + + return AcpiCpuData; +} + +/** + + Initialize multiple processors. + + @param[in] ImageHandle - Image handle of the loaded driver + @param[in] SystemTable - Pointer to the System Table + + @retval EFI_SUCCESS - Multiple processors are intialized successfully + +**/ +EFI_STATUS +InitializeCpu ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PEI_STALL_PPI *PeiStall; + ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData; + EFI_BOOT_MODE BootMode; + UINT32 FailedRevision; + UINT64 *MtrrValues; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + BOOLEAN VerifyMicrocodeChecksum; + + DEBUG ((DEBUG_ERROR, "Cpu S3 dispatch\n")); + + Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); + if (EFI_ERROR (Status)) { + // + // If not in S3 boot path. do nothing + // + return EFI_SUCCESS; + } + + if (BootMode != BOOT_ON_S3_RESUME) { + return EFI_SUCCESS; + } + + // + // Restore ACPI Nvs data from SMRAM + // + + mAcpiCpuData = RestoreSmramCpuData (PeiServices); + + DEBUG ((DEBUG_ERROR, "CpuS3 RestoreSmramCpuData - 0x%x \n", mAcpiCpuData)); + if (mAcpiCpuData == NULL) { + ASSERT(mAcpiCpuData != NULL); + return EFI_NOT_READY; + } + + mAcpiCpuData->S3BootPath = TRUE; + + Status = PeiServicesLocatePpi ( + &gEfiPeiStallPpiGuid, + 0, + NULL, + (VOID **)&PeiStall + ); + ASSERT_EFI_ERROR (Status); + + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *)(UINTN)mAcpiCpuData->CpuPrivateData; + + // + // Program virtual wire mode for BSP + // + ProgramVirtualWireMode (TRUE, CpuS3DataPtr->VirtualWireMode); + VerifyMicrocodeChecksum = TRUE; + InitializeMicrocode ((EFI_CPU_MICROCODE_HEADER **)(UINTN) mAcpiCpuData->MicrocodePointerBuffer, &FailedRevision, TRUE, &VerifyMicrocodeChecksum); + + // + // Restore features for BSP + // + // TODO: InitializeFeatures ((MP_CPU_S3_SCRIPT_DATA *)CpuS3DataPtr->S3BootScriptTable); + + Status = PeiServicesAllocatePool ( + (FixedMtrrNumber + MtrrDefTypeNumber + VariableMtrrNumber) * sizeof (UINT64), + (VOID **) &MtrrValues + ); + // + // TODO: This has been done by FSP. + // SetBspMtrrRegisters ((EFI_MTRR_VALUES *)CpuS3DataPtr->S3BspMtrrTable); + // + ReadMtrrRegisters (MtrrValues); + + // + // Restore configuration for APs and synch up Ap's MTRRs with BSP + // + WakeUpAPs ((CONST EFI_PEI_SERVICES**)PeiServices, PeiStall, mAcpiCpuData, MtrrValues, VerifyMicrocodeChecksum); + + return EFI_SUCCESS; +} + diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.inf b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.inf new file mode 100644 index 0000000000..d8f6e2c094 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MpS3.inf @@ -0,0 +1,50 @@ +## @file +# Component description file for CPU S3 module. +# +# Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+# +# 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. +# +## + +[defines] + INF_VERSION = 0x00010005 + BASE_NAME = MpS3 + FILE_GUID = C866BD71-7C79-4BF1-A93B-066B830D8F9A + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeCpu + +[sources] + MpS3.c + MtrrSync.c + Microcode.c + HtFuncs.asm | MSFT + HtFuncs.s | GCC + CpuAsm.asm | MSFT + CpuAsm.s | GCC + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ChvRefCodePkg/ChvRefCodePkg.dec + +[LibraryClasses] + BaseMemoryLib + PeimEntryPoint + DebugLib + PeiServicesLib + +[Ppis] + gEfiPeiStallPpiGuid # CONSUMES + gPeiSmmAccessPpiGuid # CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid AND gPeiSmmAccessPpiGuid + diff --git a/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MtrrSync.c b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MtrrSync.c new file mode 100644 index 0000000000..70aaa36ee2 --- /dev/null +++ b/ChvRefCodePkg/CherryViewSoc/CPU/CpuS3/MtrrSync.c @@ -0,0 +1,239 @@ +/** @file + Synchronization of MTRRs on S3 boot path. + + Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#include "MpCommon.h" + +UINTN +MpMtrrSynchUpEntry ( + VOID + ) +; + +VOID +MpMtrrSynchUpExit ( + UINTN Cr4 + ) +; + +UINT16 mFixedMtrrIndex[] = { + EFI_MSR_IA32_MTRR_FIX64K_00000, + EFI_MSR_IA32_MTRR_FIX16K_80000, + EFI_MSR_IA32_MTRR_FIX16K_A0000, + EFI_MSR_IA32_MTRR_FIX4K_C0000, + EFI_MSR_IA32_MTRR_FIX4K_C8000, + EFI_MSR_IA32_MTRR_FIX4K_D0000, + EFI_MSR_IA32_MTRR_FIX4K_D8000, + EFI_MSR_IA32_MTRR_FIX4K_E0000, + EFI_MSR_IA32_MTRR_FIX4K_E8000, + EFI_MSR_IA32_MTRR_FIX4K_F0000, + EFI_MSR_IA32_MTRR_FIX4K_F8000, +}; + +UINT16 mMtrrDefType[] = {EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE}; + +UINT16 mVariableMtrrIndex[] = { + EFI_MSR_CACHE_VARIABLE_MTRR_BASE, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 1, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 2, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 3, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 4, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 5, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 6, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 7, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 8, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 9, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 10, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 11, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 12, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 13, + EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 14, + EFI_MSR_CACHE_VARIABLE_MTRR_END, +}; + +UINTN FixedMtrrNumber = sizeof (mFixedMtrrIndex) / sizeof (UINT16); +UINTN MtrrDefTypeNumber = sizeof (mMtrrDefType) / sizeof (UINT16); +UINTN VariableMtrrNumber = sizeof (mVariableMtrrIndex) / sizeof (UINT16); + +/** + + @todo Add function description + + @retval EFI_SUCCESS - @todo Add description for return value + +**/ +VOID +DisableCacheAsRam ( + ) +{ + UINT64 CacheAsRamMsr; + + CacheAsRamMsr = AsmReadMsr64 (0x000002E0); + + // + // Per Pineview BWG section 3.21, BIOS must set the Disable FERR Assertion + // +// CacheAsRamMsr |= B_EFI_MSR_NO_EVICT_MODE_DISABLE_FERR; +// AsmWriteMsr64 (0x000002E0, CacheAsRamMsr); + + // + // Step 3: Disable No-Eviction Mode Run State by clearing + // NO_EVICT_MODE MSR 2E0h bit [1] = 0 + CacheAsRamMsr &= (~(UINT64)BIT1); + AsmWriteMsr64 (0x000002E0, CacheAsRamMsr); + + // Step 4: Disable No-Eviction Mode Setup State by clearing + // NO_EVICT_MODE MSR 2E0h bit [0] = 0 + CacheAsRamMsr &= (~(UINT64)BIT0); + AsmWriteMsr64 (0x000002E0, CacheAsRamMsr); +} + +/** + + Save the MTRR registers to global variables + +**/ +VOID +ReadMtrrRegisters ( + UINT64 *MtrrValues + ) +{ + UINT32 Index, IndexEnd; + // + // Read all Mtrrs + // + for (Index = 0; Index < FixedMtrrNumber; Index++) { + *MtrrValues = AsmReadMsr64 (mFixedMtrrIndex[Index]); + MtrrValues++; + } + + for (Index = 0; Index < MtrrDefTypeNumber; Index++) { + *MtrrValues = AsmReadMsr64 (mMtrrDefType[Index]); + MtrrValues++; + } + + IndexEnd = 2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT); + for (Index = 0; Index < IndexEnd; Index++) { + if (Index < (sizeof (mVariableMtrrIndex) / sizeof (UINT16))) { + *MtrrValues = AsmReadMsr64 (mVariableMtrrIndex[Index]); + MtrrValues++; + } + } +} + +/** + + Synch up the MTRR values for all processors + +**/ +// @todo Buffer - add argument and description to function comment +VOID +MpMtrrSynchUp ( + UINT64 *MtrrValues + ) +{ + UINT32 Index, IndexEnd; + UINTN Cr4; + UINT64 *FixedMtrr; + UINT64 *MtrrDefType; + UINT64 *VariableMtrr; + UINT64 ValidMtrrAddressMask; + UINT8 PhysicalAddressBits; + UINT32 RegEax; + + // + // Get physical CPU MTRR width in case of difference from BSP + // + AsmCpuid (EFI_CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = 36; + if (RegEax >= EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE) { + AsmCpuid (EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } + + ValidMtrrAddressMask = (LShiftU64(1, PhysicalAddressBits) - 1) & 0xfffffffffffff000; + + FixedMtrr = MtrrValues; + MtrrDefType = MtrrValues + FixedMtrrNumber; + VariableMtrr = MtrrValues + FixedMtrrNumber + MtrrDefTypeNumber; + + // + // ASM code to setup processor register before synching up the MTRRs + // + Cr4 = MpMtrrSynchUpEntry (); + + // + // Make sure all threads has FERR disabled per Pineview BWG section 3.21 + // + //DisableCacheAsRam (); + + // + // Disable Fixed Mtrrs + // + AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0] & 0xFFFFF7FF); + + // + // Update Fixed Mtrrs + // + for (Index = 0; Index < FixedMtrrNumber; Index++) { + AsmWriteMsr64 (mFixedMtrrIndex[Index], FixedMtrr[Index]); + } + + // + // Synchup Base Variable Mtrr + // + IndexEnd = 2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT); + for (Index = 0; Index < IndexEnd; Index ++) { + if ((Index < (sizeof (mVariableMtrrIndex) / sizeof (UINT16))) && (Index < VariableMtrrNumber ) ) { + AsmWriteMsr64 (mVariableMtrrIndex[Index], (VariableMtrr[Index] & 0x0FFF) | (VariableMtrr[Index] & ValidMtrrAddressMask)); + } + } + + // + // Synchup def type Fixed Mtrrs + // + AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0]); + + // + // ASM code to setup processor register after synching up the MTRRs + // + MpMtrrSynchUpExit (Cr4); + + return ; +} + +VOID +SetBspMtrrRegisters ( + IN EFI_MTRR_VALUES *MtrrArray + ) +{ + UINT32 Index; + UINTN Cr4; + + // + // ASM code to setup processor register before synching up the MTRRs + // + Cr4 = MpMtrrSynchUpEntry (); + + Index = 0; + while (MtrrArray[Index].Index != 0) { + AsmWriteMsr64 (MtrrArray[Index].Index, MtrrArray[Index].Value); + Index++; + } + + // + // ASM code to setup processor register after synching up the MTRRs + // + MpMtrrSynchUpExit (Cr4); +} -- cgit v1.2.3