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
;
118 EndAddress
= Start
+ Length
- 1;
119 if ((Start
< PAM_BASE_ADDRESS
) || EndAddress
> PAM_LIMIT_ADDRESS
) {
120 return EFI_INVALID_PARAMETER
;
124 // Loop to find the start PAM.
127 for (Index
= 0; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
128 if ((Start
>= mSectionArray
[Index
].Start
) && (Start
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
133 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
136 // Program PAM until end PAM is encountered
138 for (Index
= StartIndex
; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
139 if (ReadEnable
!= NULL
) {
142 mRegisterValues
[Index
].PAMRegPciLibAddress
,
143 mRegisterValues
[Index
].ReadEnableData
147 mRegisterValues
[Index
].PAMRegPciLibAddress
,
148 (UINT8
) (~mRegisterValues
[Index
].ReadEnableData
)
152 if (WriteEnable
!= NULL
) {
155 mRegisterValues
[Index
].PAMRegPciLibAddress
,
156 mRegisterValues
[Index
].WriteEnableData
160 mRegisterValues
[Index
].PAMRegPciLibAddress
,
161 (UINT8
) (~mRegisterValues
[Index
].WriteEnableData
)
167 // If the end PAM is encountered, record its length as granularity and jump out.
169 if ((EndAddress
>= mSectionArray
[Index
].Start
) && (EndAddress
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
170 *Granularity
= mSectionArray
[Index
].Length
;
174 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
181 LegacyRegionGetInfoInternal (
182 OUT UINT32
*DescriptorCount
,
183 OUT LEGACY_MEMORY_SECTION_INFO
**Descriptor
190 // Check input parameters
192 if (DescriptorCount
== NULL
|| Descriptor
== NULL
) {
193 return EFI_INVALID_PARAMETER
;
197 // Fill in current status of legacy region.
199 *DescriptorCount
= sizeof(mSectionArray
) / sizeof (mSectionArray
[0]);
200 for (Index
= 0; Index
< *DescriptorCount
; Index
++) {
201 PamValue
= PciRead8 (mRegisterValues
[Index
].PAMRegPciLibAddress
);
202 mSectionArray
[Index
].ReadEnabled
= FALSE
;
203 if ((PamValue
& mRegisterValues
[Index
].ReadEnableData
) != 0) {
204 mSectionArray
[Index
].ReadEnabled
= TRUE
;
206 mSectionArray
[Index
].WriteEnabled
= FALSE
;
207 if ((PamValue
& mRegisterValues
[Index
].WriteEnableData
) != 0) {
208 mSectionArray
[Index
].WriteEnabled
= TRUE
;
212 *Descriptor
= mSectionArray
;
217 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
219 If the On parameter evaluates to TRUE, this function enables memory reads in the address range
220 Start to (Start + Length - 1).
221 If the On parameter evaluates to FALSE, this function disables memory reads in the address range
222 Start to (Start + Length - 1).
224 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
225 @param Start[in] The beginning of the physical address of the region whose attributes
227 @param Length[in] The number of bytes of memory whose attributes should be modified.
228 The actual number of bytes modified may be greater than the number
230 @param Granularity[out] The number of bytes in the last region affected. This may be less
231 than the total number of bytes affected if the starting address
232 was not aligned to a region's starting address or if the length
233 was greater than the number of bytes in the first region.
234 @param On[in] Decode / Non-Decode flag.
236 @retval EFI_SUCCESS The region's attributes were successfully modified.
237 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
242 LegacyRegion2Decode (
243 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
246 OUT UINT32
*Granularity
,
250 return LegacyRegionManipulationInternal (Start
, Length
, On
, NULL
, Granularity
);
255 Modify the hardware to disallow memory attribute changes in a region.
257 This function makes the attributes of a region read only. Once a region is boot-locked with this
258 function, the read and write attributes of that region cannot be changed until a power cycle has
259 reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
261 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
262 @param Start[in] The beginning of the physical address of the region whose
263 attributes should be modified.
264 @param Length[in] The number of bytes of memory whose attributes should be modified.
265 The actual number of bytes modified may be greater than the number
267 @param Granularity[out] The number of bytes in the last region affected. This may be less
268 than the total number of bytes affected if the starting address was
269 not aligned to a region's starting address or if the length was
270 greater than the number of bytes in the first region.
272 @retval EFI_SUCCESS The region's attributes were successfully modified.
273 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
274 @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
275 a way that will not affect memory regions outside the legacy memory
281 LegacyRegion2BootLock (
282 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
285 OUT UINT32
*Granularity
288 if ((Start
< 0xC0000) || ((Start
+ Length
- 1) > 0xFFFFF)) {
289 return EFI_INVALID_PARAMETER
;
292 return EFI_UNSUPPORTED
;
297 Modify the hardware to disallow memory writes in a region.
299 This function changes the attributes of a memory range to not allow writes.
301 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
302 @param Start[in] The beginning of the physical address of the region whose
303 attributes should be modified.
304 @param Length[in] The number of bytes of memory whose attributes should be modified.
305 The actual number of bytes modified may be greater than the number
307 @param Granularity[out] The number of bytes in the last region affected. This may be less
308 than the total number of bytes affected if the starting address was
309 not aligned to a region's starting address or if the length was
310 greater than the number of bytes in the first region.
312 @retval EFI_SUCCESS The region's attributes were successfully modified.
313 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
319 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
322 OUT UINT32
*Granularity
328 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
333 Modify the hardware to allow memory writes in a region.
335 This function changes the attributes of a memory range to allow writes.
337 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
338 @param Start[in] The beginning of the physical address of the region whose
339 attributes should be modified.
340 @param Length[in] The number of bytes of memory whose attributes should be modified.
341 The actual number of bytes modified may be greater than the number
343 @param Granularity[out] The number of bytes in the last region affected. This may be less
344 than the total number of bytes affected if the starting address was
345 not aligned to a region's starting address or if the length was
346 greater than the number of bytes in the first region.
348 @retval EFI_SUCCESS The region's attributes were successfully modified.
349 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
354 LegacyRegion2Unlock (
355 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
358 OUT UINT32
*Granularity
364 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
368 Get region information for the attributes of the Legacy Region.
370 This function is used to discover the granularity of the attributes for the memory in the legacy
371 region. Each attribute may have a different granularity and the granularity may not be the same
372 for all memory ranges in the legacy region.
374 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
375 @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
377 @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
378 region information is deposited. This buffer will contain a list of
379 DescriptorCount number of region descriptors. This function will
380 provide the memory for the buffer.
382 @retval EFI_SUCCESS The region's attributes were successfully modified.
383 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
388 LegacyRegionGetInfo (
389 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
390 OUT UINT32
*DescriptorCount
,
391 OUT EFI_LEGACY_REGION_DESCRIPTOR
**Descriptor
394 LEGACY_MEMORY_SECTION_INFO
*SectionInfo
;
396 EFI_LEGACY_REGION_DESCRIPTOR
*DescriptorArray
;
398 UINTN DescriptorIndex
;
401 // Get section numbers and information
403 LegacyRegionGetInfoInternal (&SectionCount
, &SectionInfo
);
406 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
408 DescriptorArray
= AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR
) * SectionCount
* 3);
409 if (DescriptorArray
== NULL
) {
410 return EFI_OUT_OF_RESOURCES
;
414 for (Index
= 0; Index
< SectionCount
; Index
++) {
415 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
416 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
417 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
418 if (SectionInfo
[Index
].ReadEnabled
) {
419 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionDecoded
;
421 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotDecoded
;
426 // Create descriptor for writeability, according to lock status
428 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
429 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
430 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
431 if (SectionInfo
[Index
].WriteEnabled
) {
432 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteEnabled
;
434 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteDisabled
;
439 // Chipset does not support bootlock.
441 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
442 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
443 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
444 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotLocked
;
448 *DescriptorCount
= (UINT32
) DescriptorIndex
;
449 *Descriptor
= DescriptorArray
;
455 Initialize Legacy Region support
457 @retval EFI_SUCCESS Successfully initialized
466 UINT16 HostBridgeDevId
;
469 // Query Host Bridge DID to determine platform type
471 HostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
472 switch (HostBridgeDevId
) {
473 case INTEL_82441_DEVICE_ID
:
474 mRegisterValues
= mRegisterValues440
;
476 case INTEL_Q35_MCH_DEVICE_ID
:
477 mRegisterValues
= mRegisterValuesQ35
;
480 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
481 __FUNCTION__
, HostBridgeDevId
));
483 return RETURN_UNSUPPORTED
;
487 // Install the Legacy Region Protocol on a new handle
489 Status
= gBS
->InstallMultipleProtocolInterfaces (
491 &gEfiLegacyRegion2ProtocolGuid
, &mLegacyRegion2
,
494 ASSERT_EFI_ERROR (Status
);