Changeset 58459 in vbox for trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
- Timestamp:
- Oct 28, 2015 8:17:18 PM (9 years ago)
- Location:
- trunk/src/VBox/Devices/EFI/Firmware
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/EFI/Firmware
-
Property svn:mergeinfo
set to (toggle deleted branches)
/vendor/edk2/current 103735-103757
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
r48674 r58459 3 3 for transferring into long mode in IA32 capsule PEI. 4 4 5 Copyright (c) 2011 , Intel Corporation. All rights reserved.<BR>5 Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> 6 6 This program and the accompanying materials 7 7 are licensed and made available under the terms and conditions of the BSD License … … 18 18 #include <Protocol/Capsule.h> 19 19 #include <Protocol/DxeSmmReadyToLock.h> 20 #include <Protocol/VariableLock.h> 20 21 21 22 #include <Guid/CapsuleVendor.h> … … 28 29 #include <Library/UefiRuntimeLib.h> 29 30 #include <Library/BaseLib.h> 30 #include <Library/LockBoxLib.h>31 31 #include <Library/UefiLib.h> 32 32 #include <Library/BaseMemoryLib.h> … … 34 34 35 35 /** 36 Allocate Efi ACPIMemoryNVSbelow 4G memory address.37 38 This function allocates Efi ACPIMemoryNVSbelow 4G memory address.39 40 @param Size 41 42 @return Allocated address for output.36 Allocate EfiReservedMemoryType below 4G memory address. 37 38 This function allocates EfiReservedMemoryType below 4G memory address. 39 40 @param Size Size of memory to allocate. 41 42 @return Allocated Address for output. 43 43 44 44 **/ 45 45 VOID* 46 Allocate AcpiNvsMemoryBelow4G (46 AllocateReservedMemoryBelow4G ( 47 47 IN UINTN Size 48 48 ) … … 58 58 Status = gBS->AllocatePages ( 59 59 AllocateMaxAddress, 60 Efi ACPIMemoryNVS,60 EfiReservedMemoryType, 61 61 Pages, 62 62 &Address … … 71 71 72 72 /** 73 DxeSmmReadyToLock Protocol notification event handler. 74 We reuse S3 ACPI NVS reserved memory to do capsule process 75 after reset. 73 Register callback function upon VariableLockProtocol 74 to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it. 76 75 77 76 @param[in] Event Event whose notification function is being invoked. … … 80 79 VOID 81 80 EFIAPI 82 DxeSmmReadyToLockNotification(83 IN EFI_EVENTEvent,84 IN VOID*Context81 VariableLockCapsuleLongModeBufferVariable ( 82 IN EFI_EVENT Event, 83 IN VOID *Context 85 84 ) 86 85 { 87 86 EFI_STATUS Status; 88 VOID *DxeSmmReadyToLock; 89 UINTN VarSize; 90 EFI_PHYSICAL_ADDRESS TempAcpiS3Context; 91 ACPI_S3_CONTEXT *AcpiS3Context; 92 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer; 93 UINTN TotalPagesNum; 94 UINT8 PhysicalAddressBits; 95 VOID *Hob; 96 UINT32 NumberOfPml4EntriesNeeded; 97 UINT32 NumberOfPdpEntriesNeeded; 98 BOOLEAN LockBoxFound; 99 100 Status = gBS->LocateProtocol ( 101 &gEfiDxeSmmReadyToLockProtocolGuid, 102 NULL, 103 &DxeSmmReadyToLock 104 ); 105 if (EFI_ERROR (Status)) { 106 return ; 107 } 108 109 // 110 // Get the ACPI NVS pages reserved by AcpiS3Save 111 // 112 LockBoxFound = FALSE; 113 VarSize = sizeof (EFI_PHYSICAL_ADDRESS); 114 Status = RestoreLockBox ( 115 &gEfiAcpiVariableGuid, 116 &TempAcpiS3Context, 117 &VarSize 118 ); 87 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; 88 // 89 // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists 90 // 91 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); 119 92 if (!EFI_ERROR (Status)) { 120 AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context; 121 ASSERT (AcpiS3Context != NULL); 122 123 Status = RestoreLockBox ( 124 &gEfiAcpiS3ContextGuid, 125 NULL, 126 NULL 127 ); 128 if (!EFI_ERROR (Status)) { 129 LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress; 130 LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase; 131 LongModeBuffer.StackSize = AcpiS3Context->BootScriptStackSize; 132 LockBoxFound = TRUE; 133 } 134 } 135 136 if (!LockBoxFound) { 137 // 138 // Page table base address and stack base address can not be found in lock box, 139 // allocate both here. 140 // 141 142 // 143 // Get physical address bits supported from CPU HOB. 144 // 145 PhysicalAddressBits = 36; 146 93 Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid); 94 ASSERT_EFI_ERROR (Status); 95 } 96 } 97 98 /** 99 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping. 100 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode. 101 102 **/ 103 VOID 104 EFIAPI 105 PrepareContextForCapsulePei ( 106 VOID 107 ) 108 { 109 UINT32 RegEax; 110 UINT32 RegEdx; 111 UINTN TotalPagesNum; 112 UINT8 PhysicalAddressBits; 113 VOID *Hob; 114 UINT32 NumberOfPml4EntriesNeeded; 115 UINT32 NumberOfPdpEntriesNeeded; 116 BOOLEAN Page1GSupport; 117 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer; 118 EFI_STATUS Status; 119 VOID *Registration; 120 121 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdIdentifyMappingPageTablePtr); 122 123 if (LongModeBuffer.PageTableAddress == 0x0) { 124 // 125 // Calculate the size of page table, allocate the memory, and set PcdIdentifyMappingPageTablePtr. 126 // 127 Page1GSupport = FALSE; 128 if (PcdGetBool(PcdUse1GPageTable)) { 129 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 130 if (RegEax >= 0x80000001) { 131 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); 132 if ((RegEdx & BIT26) != 0) { 133 Page1GSupport = TRUE; 134 } 135 } 136 } 137 138 // 139 // Get physical address bits supported. 140 // 147 141 Hob = GetFirstHob (EFI_HOB_TYPE_CPU); 148 142 if (Hob != NULL) { 149 143 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; 144 } else { 145 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 146 if (RegEax >= 0x80000008) { 147 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); 148 PhysicalAddressBits = (UINT8) RegEax; 149 } else { 150 PhysicalAddressBits = 36; 151 } 150 152 } 151 153 … … 159 161 160 162 // 161 // Calculate page table size and allocate memory for it.163 // Calculate the table entries needed. 162 164 // 163 165 if (PhysicalAddressBits <= 39 ) { 164 166 NumberOfPml4EntriesNeeded = 1; 165 NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);167 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30)); 166 168 } else { 167 NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);169 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39)); 168 170 NumberOfPdpEntriesNeeded = 512; 169 171 } 170 172 171 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1; 172 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum)); 173 if (!Page1GSupport) { 174 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1; 175 } else { 176 TotalPagesNum = NumberOfPml4EntriesNeeded + 1; 177 } 178 179 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum)); 173 180 ASSERT (LongModeBuffer.PageTableAddress != 0); 174 175 // 176 // Allocate stack 177 // 178 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize); 179 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize)); 180 ASSERT (LongModeBuffer.StackBaseAddress != 0); 181 } 182 181 PcdSet64 (PcdIdentifyMappingPageTablePtr, LongModeBuffer.PageTableAddress); 182 } 183 184 // 185 // Allocate stack 186 // 187 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize); 188 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize)); 189 ASSERT (LongModeBuffer.StackBaseAddress != 0); 190 183 191 Status = gRT->SetVariable ( 184 192 EFI_CAPSULE_LONG_MODE_BUFFER_NAME, 185 193 &gEfiCapsuleVendorGuid, 186 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,194 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 187 195 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER), 188 196 &LongModeBuffer 189 197 ); 190 ASSERT_EFI_ERROR (Status); 191 192 // 193 // Close event, so it will not be invoked again. 194 // 195 gBS->CloseEvent (Event); 196 197 return ; 198 if (!EFI_ERROR (Status)) { 199 // 200 // Register callback function upon VariableLockProtocol 201 // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it. 202 // 203 EfiCreateProtocolNotifyEvent ( 204 &gEdkiiVariableLockProtocolGuid, 205 TPL_CALLBACK, 206 VariableLockCapsuleLongModeBufferVariable, 207 NULL, 208 &Registration 209 ); 210 } else { 211 DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status)); 212 gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize)); 213 } 198 214 } 199 215 … … 207 223 ) 208 224 { 209 VOID *Registration;210 211 225 if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) { 212 226 // 213 // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by 214 // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB. 215 // 216 EfiCreateProtocolNotifyEvent ( 217 &gEfiDxeSmmReadyToLockProtocolGuid, 218 TPL_CALLBACK, 219 DxeSmmReadyToLockNotification, 220 NULL, 221 &Registration 222 ); 223 } 224 } 227 // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB. 228 // 229 PrepareContextForCapsulePei (); 230 } 231 }
Note:
See TracChangeset
for help on using the changeset viewer.