2 Memory Detection for Virtual Machines.
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 // The package level header files this module uses
25 // The Library classes this module consumes
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/HobLib.h>
30 #include <Library/IoLib.h>
31 #include <Library/PcdLib.h>
32 #include <Library/PeimEntryPoint.h>
33 #include <Library/ResourcePublicationLib.h>
34 #include <Library/MtrrLib.h>
39 UINT8 mPhysMemAddressWidth
;
42 GetSystemMemorySizeBelow4gb (
50 // CMOS 0x34/0x35 specifies the system memory above 16 MB.
51 // * CMOS(0x35) is the high byte
52 // * CMOS(0x34) is the low byte
53 // * The size is specified in 64kb chunks
54 // * Since this is memory above 16MB, the 16MB must be added
55 // into the calculation to get the total memory size.
58 Cmos0x34
= (UINT8
) CmosRead8 (0x34);
59 Cmos0x35
= (UINT8
) CmosRead8 (0x35);
61 return (UINT32
) (((UINTN
)((Cmos0x35
<< 8) + Cmos0x34
) << 16) + SIZE_16MB
);
67 GetSystemMemorySizeAbove4gb (
74 // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
75 // * CMOS(0x5d) is the most significant size byte
76 // * CMOS(0x5c) is the middle size byte
77 // * CMOS(0x5b) is the least significant size byte
78 // * The size is specified in 64kb chunks
82 for (CmosIndex
= 0x5d; CmosIndex
>= 0x5b; CmosIndex
--) {
83 Size
= (UINT32
) (Size
<< 8) + (UINT32
) CmosRead8 (CmosIndex
);
86 return LShiftU64 (Size
, 16);
91 Return the highest address that DXE could possibly use, plus one.
99 UINT64 FirstNonAddress
;
101 FirstNonAddress
= BASE_4GB
+ GetSystemMemorySizeAbove4gb ();
102 return FirstNonAddress
;
107 Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
110 AddressWidthInitialization (
114 UINT64 FirstNonAddress
;
117 // As guest-physical memory size grows, the permanent PEI RAM requirements
118 // are dominated by the identity-mapping page tables built by the DXE IPL.
119 // The DXL IPL keys off of the physical address bits advertized in the CPU
120 // HOB. To conserve memory, we calculate the minimum address width here.
122 FirstNonAddress
= GetFirstNonAddress ();
123 mPhysMemAddressWidth
= (UINT8
)HighBitSet64 (FirstNonAddress
);
126 // If FirstNonAddress is not an integral power of two, then we need an
129 if ((FirstNonAddress
& (FirstNonAddress
- 1)) != 0) {
130 ++mPhysMemAddressWidth
;
134 // The minimum address width is 36 (covers up to and excluding 64 GB, which
135 // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
136 // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
137 // can simply assert that here, since 48 bits are good enough for 256 TB.
139 if (mPhysMemAddressWidth
<= 36) {
140 mPhysMemAddressWidth
= 36;
142 ASSERT (mPhysMemAddressWidth
<= 48);
147 Calculate the cap for the permanent PEI memory.
155 BOOLEAN Page1GSupport
;
163 // If DXE is 32-bit, then just return the traditional 64 MB cap.
166 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode
)) {
172 // Dependent on physical address width, PEI memory allocations can be
173 // dominated by the page tables built for 64-bit DXE. So we key the cap off
174 // of those. The code below is based on CreateIdentityMappingPageTables() in
175 // "MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c".
177 Page1GSupport
= FALSE
;
178 if (PcdGetBool (PcdUse1GPageTable
)) {
179 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
180 if (RegEax
>= 0x80000001) {
181 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
182 if ((RegEdx
& BIT26
) != 0) {
183 Page1GSupport
= TRUE
;
188 if (mPhysMemAddressWidth
<= 39) {
190 PdpEntries
= 1 << (mPhysMemAddressWidth
- 30);
191 ASSERT (PdpEntries
<= 0x200);
193 Pml4Entries
= 1 << (mPhysMemAddressWidth
- 39);
194 ASSERT (Pml4Entries
<= 0x200);
198 TotalPages
= Page1GSupport
? Pml4Entries
+ 1 :
199 (PdpEntries
+ 1) * Pml4Entries
+ 1;
200 ASSERT (TotalPages
<= 0x40201);
203 // Add 64 MB for miscellaneous allocations. Note that for
204 // mPhysMemAddressWidth values close to 36, the cap will actually be
205 // dominated by this increment.
207 return (UINT32
)(EFI_PAGES_TO_SIZE (TotalPages
) + SIZE_64MB
);
212 Publish PEI core memory
214 @return EFI_SUCCESS The PEIM initialized successfully.
223 EFI_PHYSICAL_ADDRESS MemoryBase
;
225 UINT64 LowerMemorySize
;
228 if (mBootMode
== BOOT_ON_S3_RESUME
) {
229 MemoryBase
= PcdGet32 (PcdS3AcpiReservedMemoryBase
);
230 MemorySize
= PcdGet32 (PcdS3AcpiReservedMemorySize
);
232 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
233 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
235 // TSEG is chipped from the end of low RAM
237 LowerMemorySize
-= FixedPcdGet8 (PcdQ35TsegMbytes
) * SIZE_1MB
;
240 PeiMemoryCap
= GetPeiMemoryCap ();
241 DEBUG ((EFI_D_INFO
, "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
242 __FUNCTION__
, mPhysMemAddressWidth
, PeiMemoryCap
>> 10));
245 // Determine the range of memory to use during PEI
247 // Technically we could lay the permanent PEI RAM over SEC's temporary
248 // decompression and scratch buffer even if "secure S3" is needed, since
249 // their lifetimes don't overlap. However, PeiFvInitialization() will cover
250 // RAM up to PcdOvmfDecompressionScratchEnd with an EfiACPIMemoryNVS memory
251 // allocation HOB, and other allocations served from the permanent PEI RAM
252 // shouldn't overlap with that HOB.
254 MemoryBase
= mS3Supported
&& FeaturePcdGet (PcdSmmSmramRequire
) ?
255 PcdGet32 (PcdOvmfDecompressionScratchEnd
) :
256 PcdGet32 (PcdOvmfDxeMemFvBase
) + PcdGet32 (PcdOvmfDxeMemFvSize
);
257 MemorySize
= LowerMemorySize
- MemoryBase
;
258 if (MemorySize
> PeiMemoryCap
) {
259 MemoryBase
= LowerMemorySize
- PeiMemoryCap
;
260 MemorySize
= PeiMemoryCap
;
265 // Publish this memory to the PEI Core
267 Status
= PublishSystemMemory(MemoryBase
, MemorySize
);
268 ASSERT_EFI_ERROR (Status
);
275 Peform Memory Detection for QEMU / KVM
284 UINT64 LowerMemorySize
;
285 UINT64 UpperMemorySize
;
286 MTRR_SETTINGS MtrrSettings
;
289 DEBUG ((EFI_D_INFO
, "%a called\n", __FUNCTION__
));
292 // Determine total memory size available
294 LowerMemorySize
= GetSystemMemorySizeBelow4gb ();
295 UpperMemorySize
= GetSystemMemorySizeAbove4gb ();
297 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
299 // Create memory HOBs
301 AddMemoryRangeHob (0, BASE_512KB
+ BASE_128KB
);
303 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
306 TsegSize
= FixedPcdGet8 (PcdQ35TsegMbytes
) * SIZE_1MB
;
307 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
- TsegSize
);
308 AddReservedMemoryBaseSizeHob (LowerMemorySize
- TsegSize
, TsegSize
,
311 AddMemoryRangeHob (BASE_1MB
, LowerMemorySize
);
314 if (UpperMemorySize
!= 0) {
315 AddUntestedMemoryBaseSizeHob (BASE_4GB
, UpperMemorySize
);
320 // We'd like to keep the following ranges uncached:
322 // - [LowerMemorySize, 4 GB)
324 // Everything else should be WB. Unfortunately, programming the inverse (ie.
325 // keeping the default UC, and configuring the complement set of the above as
326 // WB) is not reliable in general, because the end of the upper RAM can have
327 // practically any alignment, and we may not have enough variable MTRRs to
330 if (IsMtrrSupported ()) {
331 MtrrGetAllMtrrs (&MtrrSettings
);
334 // MTRRs disabled, fixed MTRRs disabled, default type is uncached
336 ASSERT ((MtrrSettings
.MtrrDefType
& BIT11
) == 0);
337 ASSERT ((MtrrSettings
.MtrrDefType
& BIT10
) == 0);
338 ASSERT ((MtrrSettings
.MtrrDefType
& 0xFF) == 0);
341 // flip default type to writeback
343 SetMem (&MtrrSettings
.Fixed
, sizeof MtrrSettings
.Fixed
, 0x06);
344 ZeroMem (&MtrrSettings
.Variables
, sizeof MtrrSettings
.Variables
);
345 MtrrSettings
.MtrrDefType
|= BIT11
| BIT10
| 6;
346 MtrrSetAllMtrrs (&MtrrSettings
);
349 // Set memory range from 640KB to 1MB to uncacheable
351 Status
= MtrrSetMemoryAttribute (BASE_512KB
+ BASE_128KB
,
352 BASE_1MB
- (BASE_512KB
+ BASE_128KB
), CacheUncacheable
);
353 ASSERT_EFI_ERROR (Status
);
356 // Set memory range from the "top of lower RAM" (RAM below 4GB) to 4GB as
359 Status
= MtrrSetMemoryAttribute (LowerMemorySize
,
360 SIZE_4GB
- LowerMemorySize
, CacheUncacheable
);
361 ASSERT_EFI_ERROR (Status
);
366 Publish system RAM and reserve memory regions
370 InitializeRamRegions (
375 QemuInitializeRam ();
377 XenPublishRamRegions ();
380 if (mS3Supported
&& mBootMode
!= BOOT_ON_S3_RESUME
) {
382 // This is the memory range that will be used for PEI on S3 resume
384 BuildMemoryAllocationHob (
385 (EFI_PHYSICAL_ADDRESS
)(UINTN
) PcdGet32 (PcdS3AcpiReservedMemoryBase
),
386 (UINT64
)(UINTN
) PcdGet32 (PcdS3AcpiReservedMemorySize
),
391 // Cover the initial RAM area used as stack and temporary PEI heap.
393 // This is reserved as ACPI NVS so it can be used on S3 resume.
395 BuildMemoryAllocationHob (
396 PcdGet32 (PcdOvmfSecPeiTempRamBase
),
397 PcdGet32 (PcdOvmfSecPeiTempRamSize
),
402 // SEC stores its table of GUIDed section handlers here.
404 BuildMemoryAllocationHob (
405 PcdGet64 (PcdGuidedExtractHandlerTableAddress
),
406 PcdGet32 (PcdGuidedExtractHandlerTableSize
),
412 // Reserve the initial page tables built by the reset vector code.
414 // Since this memory range will be used by the Reset Vector on S3
415 // resume, it must be reserved as ACPI NVS.
417 BuildMemoryAllocationHob (
418 (EFI_PHYSICAL_ADDRESS
)(UINTN
) PcdGet32 (PcdOvmfSecPageTablesBase
),
419 (UINT64
)(UINTN
) PcdGet32 (PcdOvmfSecPageTablesSize
),
425 if (mBootMode
!= BOOT_ON_S3_RESUME
) {
426 if (!FeaturePcdGet (PcdSmmSmramRequire
)) {
428 // Reserve the lock box storage area
430 // Since this memory range will be used on S3 resume, it must be
431 // reserved as ACPI NVS.
433 // If S3 is unsupported, then various drivers might still write to the
434 // LockBox area. We ought to prevent DXE from serving allocation requests
435 // such that they would overlap the LockBox storage.
438 (VOID
*)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageBase
),
439 (UINTN
) PcdGet32 (PcdOvmfLockBoxStorageSize
)
441 BuildMemoryAllocationHob (
442 (EFI_PHYSICAL_ADDRESS
)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageBase
),
443 (UINT64
)(UINTN
) PcdGet32 (PcdOvmfLockBoxStorageSize
),
444 mS3Supported
? EfiACPIMemoryNVS
: EfiBootServicesData
448 if (FeaturePcdGet (PcdSmmSmramRequire
)) {
452 // Make sure the TSEG area that we reported as a reserved memory resource
453 // cannot be used for reserved memory allocations.
455 TsegSize
= FixedPcdGet8 (PcdQ35TsegMbytes
) * SIZE_1MB
;
456 BuildMemoryAllocationHob (
457 GetSystemMemorySizeBelow4gb() - TsegSize
,
459 EfiReservedMemoryType