4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "LegacyRegion.h"
15 // PAM Range Offset Bits Operation
17 // =============== ==== ==== ==== ===============================================================
18 // 0xC0000-0xC3FFF 0x5a 0x91 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
19 // 0xC4000-0xC7FFF 0x5a 0x91 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
20 // 0xC8000-0xCBFFF 0x5b 0x92 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
21 // 0xCC000-0xCFFFF 0x5b 0x92 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
22 // 0xD0000-0xD3FFF 0x5c 0x93 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
23 // 0xD4000-0xD7FFF 0x5c 0x93 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
24 // 0xD8000-0xDBFFF 0x5d 0x94 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
25 // 0xDC000-0xDFFFF 0x5d 0x94 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
26 // 0xE0000-0xE3FFF 0x5e 0x95 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
27 // 0xE4000-0xE7FFF 0x5e 0x95 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
28 // 0xE8000-0xEBFFF 0x5f 0x96 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
29 // 0xEC000-0xEFFFF 0x5f 0x96 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
30 // 0xF0000-0xFFFFF 0x59 0x90 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
32 STATIC LEGACY_MEMORY_SECTION_INFO mSectionArray
[] = {
33 { 0xC0000, SIZE_16KB
, FALSE
, FALSE
},
34 { 0xC4000, SIZE_16KB
, FALSE
, FALSE
},
35 { 0xC8000, SIZE_16KB
, FALSE
, FALSE
},
36 { 0xCC000, SIZE_16KB
, FALSE
, FALSE
},
37 { 0xD0000, SIZE_16KB
, FALSE
, FALSE
},
38 { 0xD4000, SIZE_16KB
, FALSE
, FALSE
},
39 { 0xD8000, SIZE_16KB
, FALSE
, FALSE
},
40 { 0xDC000, SIZE_16KB
, FALSE
, FALSE
},
41 { 0xE0000, SIZE_16KB
, FALSE
, FALSE
},
42 { 0xE4000, SIZE_16KB
, FALSE
, FALSE
},
43 { 0xE8000, SIZE_16KB
, FALSE
, FALSE
},
44 { 0xEC000, SIZE_16KB
, FALSE
, FALSE
},
45 { 0xF0000, SIZE_64KB
, FALSE
, FALSE
}
48 STATIC PAM_REGISTER_VALUE mRegisterValues440
[] = {
49 { PMC_REGISTER_PIIX4 (PIIX4_PAM1
), 0x01, 0x02 },
50 { PMC_REGISTER_PIIX4 (PIIX4_PAM1
), 0x10, 0x20 },
51 { PMC_REGISTER_PIIX4 (PIIX4_PAM2
), 0x01, 0x02 },
52 { PMC_REGISTER_PIIX4 (PIIX4_PAM2
), 0x10, 0x20 },
53 { PMC_REGISTER_PIIX4 (PIIX4_PAM3
), 0x01, 0x02 },
54 { PMC_REGISTER_PIIX4 (PIIX4_PAM3
), 0x10, 0x20 },
55 { PMC_REGISTER_PIIX4 (PIIX4_PAM4
), 0x01, 0x02 },
56 { PMC_REGISTER_PIIX4 (PIIX4_PAM4
), 0x10, 0x20 },
57 { PMC_REGISTER_PIIX4 (PIIX4_PAM5
), 0x01, 0x02 },
58 { PMC_REGISTER_PIIX4 (PIIX4_PAM5
), 0x10, 0x20 },
59 { PMC_REGISTER_PIIX4 (PIIX4_PAM6
), 0x01, 0x02 },
60 { PMC_REGISTER_PIIX4 (PIIX4_PAM6
), 0x10, 0x20 },
61 { PMC_REGISTER_PIIX4 (PIIX4_PAM0
), 0x10, 0x20 }
64 STATIC PAM_REGISTER_VALUE mRegisterValuesQ35
[] = {
65 { DRAMC_REGISTER_Q35 (MCH_PAM1
), 0x01, 0x02 },
66 { DRAMC_REGISTER_Q35 (MCH_PAM1
), 0x10, 0x20 },
67 { DRAMC_REGISTER_Q35 (MCH_PAM2
), 0x01, 0x02 },
68 { DRAMC_REGISTER_Q35 (MCH_PAM2
), 0x10, 0x20 },
69 { DRAMC_REGISTER_Q35 (MCH_PAM3
), 0x01, 0x02 },
70 { DRAMC_REGISTER_Q35 (MCH_PAM3
), 0x10, 0x20 },
71 { DRAMC_REGISTER_Q35 (MCH_PAM4
), 0x01, 0x02 },
72 { DRAMC_REGISTER_Q35 (MCH_PAM4
), 0x10, 0x20 },
73 { DRAMC_REGISTER_Q35 (MCH_PAM5
), 0x01, 0x02 },
74 { DRAMC_REGISTER_Q35 (MCH_PAM5
), 0x10, 0x20 },
75 { DRAMC_REGISTER_Q35 (MCH_PAM6
), 0x01, 0x02 },
76 { DRAMC_REGISTER_Q35 (MCH_PAM6
), 0x10, 0x20 },
77 { DRAMC_REGISTER_Q35 (MCH_PAM0
), 0x10, 0x20 }
80 STATIC PAM_REGISTER_VALUE
*mRegisterValues
;
83 // Handle used to install the Legacy Region Protocol
85 STATIC EFI_HANDLE mHandle
= NULL
;
88 // Instance of the Legacy Region Protocol to install into the handle database
90 STATIC EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2
= {
93 LegacyRegion2BootLock
,
100 LegacyRegionManipulationInternal (
103 IN BOOLEAN
*ReadEnable
,
104 IN BOOLEAN
*WriteEnable
,
105 OUT UINT32
*Granularity
113 // Validate input parameters.
115 if ((Length
== 0) || (Granularity
== NULL
)) {
116 return EFI_INVALID_PARAMETER
;
119 EndAddress
= Start
+ Length
- 1;
120 if ((Start
< PAM_BASE_ADDRESS
) || (EndAddress
> PAM_LIMIT_ADDRESS
)) {
121 return EFI_INVALID_PARAMETER
;
125 // Loop to find the start PAM.
128 for (Index
= 0; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
129 if ((Start
>= mSectionArray
[Index
].Start
) && (Start
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
135 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
138 // Program PAM until end PAM is encountered
140 for (Index
= StartIndex
; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
141 if (ReadEnable
!= NULL
) {
144 mRegisterValues
[Index
].PAMRegPciLibAddress
,
145 mRegisterValues
[Index
].ReadEnableData
149 mRegisterValues
[Index
].PAMRegPciLibAddress
,
150 (UINT8
)(~mRegisterValues
[Index
].ReadEnableData
)
155 if (WriteEnable
!= NULL
) {
158 mRegisterValues
[Index
].PAMRegPciLibAddress
,
159 mRegisterValues
[Index
].WriteEnableData
163 mRegisterValues
[Index
].PAMRegPciLibAddress
,
164 (UINT8
)(~mRegisterValues
[Index
].WriteEnableData
)
170 // If the end PAM is encountered, record its length as granularity and jump out.
172 if ((EndAddress
>= mSectionArray
[Index
].Start
) && (EndAddress
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
173 *Granularity
= mSectionArray
[Index
].Length
;
178 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
185 LegacyRegionGetInfoInternal (
186 OUT UINT32
*DescriptorCount
,
187 OUT LEGACY_MEMORY_SECTION_INFO
**Descriptor
194 // Check input parameters
196 if ((DescriptorCount
== NULL
) || (Descriptor
== NULL
)) {
197 return EFI_INVALID_PARAMETER
;
201 // Fill in current status of legacy region.
203 *DescriptorCount
= sizeof (mSectionArray
) / sizeof (mSectionArray
[0]);
204 for (Index
= 0; Index
< *DescriptorCount
; Index
++) {
205 PamValue
= PciRead8 (mRegisterValues
[Index
].PAMRegPciLibAddress
);
206 mSectionArray
[Index
].ReadEnabled
= FALSE
;
207 if ((PamValue
& mRegisterValues
[Index
].ReadEnableData
) != 0) {
208 mSectionArray
[Index
].ReadEnabled
= TRUE
;
211 mSectionArray
[Index
].WriteEnabled
= FALSE
;
212 if ((PamValue
& mRegisterValues
[Index
].WriteEnableData
) != 0) {
213 mSectionArray
[Index
].WriteEnabled
= TRUE
;
217 *Descriptor
= mSectionArray
;
222 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
224 If the On parameter evaluates to TRUE, this function enables memory reads in the address range
225 Start to (Start + Length - 1).
226 If the On parameter evaluates to FALSE, this function disables memory reads in the address range
227 Start to (Start + Length - 1).
229 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
230 @param Start[in] The beginning of the physical address of the region whose attributes
232 @param Length[in] The number of bytes of memory whose attributes should be modified.
233 The actual number of bytes modified may be greater than the number
235 @param Granularity[out] The number of bytes in the last region affected. This may be less
236 than the total number of bytes affected if the starting address
237 was not aligned to a region's starting address or if the length
238 was greater than the number of bytes in the first region.
239 @param On[in] Decode / Non-Decode flag.
241 @retval EFI_SUCCESS The region's attributes were successfully modified.
242 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
247 LegacyRegion2Decode (
248 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
251 OUT UINT32
*Granularity
,
255 return LegacyRegionManipulationInternal (Start
, Length
, On
, NULL
, Granularity
);
259 Modify the hardware to disallow memory attribute changes in a region.
261 This function makes the attributes of a region read only. Once a region is boot-locked with this
262 function, the read and write attributes of that region cannot be changed until a power cycle has
263 reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
265 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
266 @param Start[in] The beginning of the physical address of the region whose
267 attributes should be modified.
268 @param Length[in] The number of bytes of memory whose attributes should be modified.
269 The actual number of bytes modified may be greater than the number
271 @param Granularity[out] The number of bytes in the last region affected. This may be less
272 than the total number of bytes affected if the starting address was
273 not aligned to a region's starting address or if the length was
274 greater than the number of bytes in the first region.
276 @retval EFI_SUCCESS The region's attributes were successfully modified.
277 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
278 @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
279 a way that will not affect memory regions outside the legacy memory
285 LegacyRegion2BootLock (
286 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
289 OUT UINT32
*Granularity
292 if ((Start
< 0xC0000) || ((Start
+ Length
- 1) > 0xFFFFF)) {
293 return EFI_INVALID_PARAMETER
;
296 return EFI_UNSUPPORTED
;
300 Modify the hardware to disallow memory writes in a region.
302 This function changes the attributes of a memory range to not allow writes.
304 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
305 @param Start[in] The beginning of the physical address of the region whose
306 attributes should be modified.
307 @param Length[in] The number of bytes of memory whose attributes should be modified.
308 The actual number of bytes modified may be greater than the number
310 @param Granularity[out] The number of bytes in the last region affected. This may be less
311 than the total number of bytes affected if the starting address was
312 not aligned to a region's starting address or if the length was
313 greater than the number of bytes in the first region.
315 @retval EFI_SUCCESS The region's attributes were successfully modified.
316 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
322 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
325 OUT UINT32
*Granularity
331 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
335 Modify the hardware to allow memory writes in a region.
337 This function changes the attributes of a memory range to allow writes.
339 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
340 @param Start[in] The beginning of the physical address of the region whose
341 attributes should be modified.
342 @param Length[in] The number of bytes of memory whose attributes should be modified.
343 The actual number of bytes modified may be greater than the number
345 @param Granularity[out] The number of bytes in the last region affected. This may be less
346 than the total number of bytes affected if the starting address was
347 not aligned to a region's starting address or if the length was
348 greater than the number of bytes in the first region.
350 @retval EFI_SUCCESS The region's attributes were successfully modified.
351 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
356 LegacyRegion2Unlock (
357 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
360 OUT UINT32
*Granularity
366 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
370 Get region information for the attributes of the Legacy Region.
372 This function is used to discover the granularity of the attributes for the memory in the legacy
373 region. Each attribute may have a different granularity and the granularity may not be the same
374 for all memory ranges in the legacy region.
376 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
377 @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
379 @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
380 region information is deposited. This buffer will contain a list of
381 DescriptorCount number of region descriptors. This function will
382 provide the memory for the buffer.
384 @retval EFI_SUCCESS The region's attributes were successfully modified.
385 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
390 LegacyRegionGetInfo (
391 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
392 OUT UINT32
*DescriptorCount
,
393 OUT EFI_LEGACY_REGION_DESCRIPTOR
**Descriptor
396 LEGACY_MEMORY_SECTION_INFO
*SectionInfo
;
398 EFI_LEGACY_REGION_DESCRIPTOR
*DescriptorArray
;
400 UINTN DescriptorIndex
;
403 // Get section numbers and information
405 LegacyRegionGetInfoInternal (&SectionCount
, &SectionInfo
);
408 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
410 DescriptorArray
= AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR
) * SectionCount
* 3);
411 if (DescriptorArray
== NULL
) {
412 return EFI_OUT_OF_RESOURCES
;
416 for (Index
= 0; Index
< SectionCount
; Index
++) {
417 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
418 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
419 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
420 if (SectionInfo
[Index
].ReadEnabled
) {
421 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionDecoded
;
423 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotDecoded
;
429 // Create descriptor for writeability, according to lock status
431 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
432 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
433 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
434 if (SectionInfo
[Index
].WriteEnabled
) {
435 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteEnabled
;
437 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteDisabled
;
443 // Chipset does not support bootlock.
445 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
446 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
447 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
448 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotLocked
;
452 *DescriptorCount
= (UINT32
)DescriptorIndex
;
453 *Descriptor
= DescriptorArray
;
459 Initialize Legacy Region support
461 @retval EFI_SUCCESS Successfully initialized
470 UINT16 HostBridgeDevId
;
473 // Query Host Bridge DID to determine platform type
475 HostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
476 switch (HostBridgeDevId
) {
477 case INTEL_82441_DEVICE_ID
:
478 mRegisterValues
= mRegisterValues440
;
480 case INTEL_Q35_MCH_DEVICE_ID
:
481 mRegisterValues
= mRegisterValuesQ35
;
486 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
491 return RETURN_UNSUPPORTED
;
495 // Install the Legacy Region Protocol on a new handle
497 Status
= gBS
->InstallMultipleProtocolInterfaces (
499 &gEfiLegacyRegion2ProtocolGuid
,
503 ASSERT_EFI_ERROR (Status
);