4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials are
7 licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "LegacyRegion.h"
21 // PAM Range Offset Bits Operation
23 // =============== ==== ==== ==== ===============================================================
24 // 0xC0000-0xC3FFF 0x5a 0x91 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
25 // 0xC4000-0xC7FFF 0x5a 0x91 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
26 // 0xC8000-0xCBFFF 0x5b 0x92 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
27 // 0xCC000-0xCFFFF 0x5b 0x92 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
28 // 0xD0000-0xD3FFF 0x5c 0x93 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
29 // 0xD4000-0xD7FFF 0x5c 0x93 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
30 // 0xD8000-0xDBFFF 0x5d 0x94 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
31 // 0xDC000-0xDFFFF 0x5d 0x94 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
32 // 0xE0000-0xE3FFF 0x5e 0x95 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
33 // 0xE4000-0xE7FFF 0x5e 0x95 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
34 // 0xE8000-0xEBFFF 0x5f 0x96 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
35 // 0xEC000-0xEFFFF 0x5f 0x96 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
36 // 0xF0000-0xFFFFF 0x59 0x90 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
38 STATIC LEGACY_MEMORY_SECTION_INFO mSectionArray
[] = {
39 {0xC0000, SIZE_16KB
, FALSE
, FALSE
},
40 {0xC4000, SIZE_16KB
, FALSE
, FALSE
},
41 {0xC8000, SIZE_16KB
, FALSE
, FALSE
},
42 {0xCC000, SIZE_16KB
, FALSE
, FALSE
},
43 {0xD0000, SIZE_16KB
, FALSE
, FALSE
},
44 {0xD4000, SIZE_16KB
, FALSE
, FALSE
},
45 {0xD8000, SIZE_16KB
, FALSE
, FALSE
},
46 {0xDC000, SIZE_16KB
, FALSE
, FALSE
},
47 {0xE0000, SIZE_16KB
, FALSE
, FALSE
},
48 {0xE4000, SIZE_16KB
, FALSE
, FALSE
},
49 {0xE8000, SIZE_16KB
, FALSE
, FALSE
},
50 {0xEC000, SIZE_16KB
, FALSE
, FALSE
},
51 {0xF0000, SIZE_64KB
, FALSE
, FALSE
}
54 STATIC PAM_REGISTER_VALUE mRegisterValues440
[] = {
55 {REG_PAM1_OFFSET_440
, 0x01, 0x02},
56 {REG_PAM1_OFFSET_440
, 0x10, 0x20},
57 {REG_PAM2_OFFSET_440
, 0x01, 0x02},
58 {REG_PAM2_OFFSET_440
, 0x10, 0x20},
59 {REG_PAM3_OFFSET_440
, 0x01, 0x02},
60 {REG_PAM3_OFFSET_440
, 0x10, 0x20},
61 {REG_PAM4_OFFSET_440
, 0x01, 0x02},
62 {REG_PAM4_OFFSET_440
, 0x10, 0x20},
63 {REG_PAM5_OFFSET_440
, 0x01, 0x02},
64 {REG_PAM5_OFFSET_440
, 0x10, 0x20},
65 {REG_PAM6_OFFSET_440
, 0x01, 0x02},
66 {REG_PAM6_OFFSET_440
, 0x10, 0x20},
67 {REG_PAM0_OFFSET_440
, 0x10, 0x20}
70 STATIC PAM_REGISTER_VALUE mRegisterValuesQ35
[] = {
71 {REG_PAM1_OFFSET_Q35
, 0x01, 0x02},
72 {REG_PAM1_OFFSET_Q35
, 0x10, 0x20},
73 {REG_PAM2_OFFSET_Q35
, 0x01, 0x02},
74 {REG_PAM2_OFFSET_Q35
, 0x10, 0x20},
75 {REG_PAM3_OFFSET_Q35
, 0x01, 0x02},
76 {REG_PAM3_OFFSET_Q35
, 0x10, 0x20},
77 {REG_PAM4_OFFSET_Q35
, 0x01, 0x02},
78 {REG_PAM4_OFFSET_Q35
, 0x10, 0x20},
79 {REG_PAM5_OFFSET_Q35
, 0x01, 0x02},
80 {REG_PAM5_OFFSET_Q35
, 0x10, 0x20},
81 {REG_PAM6_OFFSET_Q35
, 0x01, 0x02},
82 {REG_PAM6_OFFSET_Q35
, 0x10, 0x20},
83 {REG_PAM0_OFFSET_Q35
, 0x10, 0x20}
86 STATIC PAM_REGISTER_VALUE
*mRegisterValues
;
89 // Handle used to install the Legacy Region Protocol
91 STATIC EFI_HANDLE mHandle
= NULL
;
94 // Instance of the Legacy Region Protocol to install into the handle database
96 STATIC EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2
= {
99 LegacyRegion2BootLock
,
106 LegacyRegionManipulationInternal (
109 IN BOOLEAN
*ReadEnable
,
110 IN BOOLEAN
*WriteEnable
,
111 OUT UINT32
*Granularity
119 // Validate input parameters.
121 if (Length
== 0 || Granularity
== NULL
) {
122 return EFI_INVALID_PARAMETER
;
124 EndAddress
= Start
+ Length
- 1;
125 if ((Start
< PAM_BASE_ADDRESS
) || EndAddress
> PAM_LIMIT_ADDRESS
) {
126 return EFI_INVALID_PARAMETER
;
130 // Loop to find the start PAM.
133 for (Index
= 0; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
134 if ((Start
>= mSectionArray
[Index
].Start
) && (Start
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
139 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
142 // Program PAM until end PAM is encountered
144 for (Index
= StartIndex
; Index
< ARRAY_SIZE (mSectionArray
); Index
++) {
145 if (ReadEnable
!= NULL
) {
148 PCI_LIB_ADDRESS(PAM_PCI_BUS
, PAM_PCI_DEV
, PAM_PCI_FUNC
, mRegisterValues
[Index
].PAMRegOffset
),
149 mRegisterValues
[Index
].ReadEnableData
153 PCI_LIB_ADDRESS(PAM_PCI_BUS
, PAM_PCI_DEV
, PAM_PCI_FUNC
, mRegisterValues
[Index
].PAMRegOffset
),
154 (UINT8
) (~mRegisterValues
[Index
].ReadEnableData
)
158 if (WriteEnable
!= NULL
) {
161 PCI_LIB_ADDRESS(PAM_PCI_BUS
, PAM_PCI_DEV
, PAM_PCI_FUNC
, mRegisterValues
[Index
].PAMRegOffset
),
162 mRegisterValues
[Index
].WriteEnableData
166 PCI_LIB_ADDRESS(PAM_PCI_BUS
, PAM_PCI_DEV
, PAM_PCI_FUNC
, mRegisterValues
[Index
].PAMRegOffset
),
167 (UINT8
) (~mRegisterValues
[Index
].WriteEnableData
)
173 // If the end PAM is encountered, record its length as granularity and jump out.
175 if ((EndAddress
>= mSectionArray
[Index
].Start
) && (EndAddress
< (mSectionArray
[Index
].Start
+ mSectionArray
[Index
].Length
))) {
176 *Granularity
= mSectionArray
[Index
].Length
;
180 ASSERT (Index
< ARRAY_SIZE (mSectionArray
));
187 LegacyRegionGetInfoInternal (
188 OUT UINT32
*DescriptorCount
,
189 OUT LEGACY_MEMORY_SECTION_INFO
**Descriptor
196 // Check input parameters
198 if (DescriptorCount
== NULL
|| Descriptor
== NULL
) {
199 return EFI_INVALID_PARAMETER
;
203 // Fill in current status of legacy region.
205 *DescriptorCount
= sizeof(mSectionArray
) / sizeof (mSectionArray
[0]);
206 for (Index
= 0; Index
< *DescriptorCount
; Index
++) {
207 PamValue
= PciRead8 (PCI_LIB_ADDRESS(PAM_PCI_BUS
, PAM_PCI_DEV
, PAM_PCI_FUNC
, mRegisterValues
[Index
].PAMRegOffset
));
208 mSectionArray
[Index
].ReadEnabled
= FALSE
;
209 if ((PamValue
& mRegisterValues
[Index
].ReadEnableData
) != 0) {
210 mSectionArray
[Index
].ReadEnabled
= TRUE
;
212 mSectionArray
[Index
].WriteEnabled
= FALSE
;
213 if ((PamValue
& mRegisterValues
[Index
].WriteEnableData
) != 0) {
214 mSectionArray
[Index
].WriteEnabled
= TRUE
;
218 *Descriptor
= mSectionArray
;
223 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
225 If the On parameter evaluates to TRUE, this function enables memory reads in the address range
226 Start to (Start + Length - 1).
227 If the On parameter evaluates to FALSE, this function disables memory reads in the address range
228 Start to (Start + Length - 1).
230 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
231 @param Start[in] The beginning of the physical address of the region whose attributes
233 @param Length[in] The number of bytes of memory whose attributes should be modified.
234 The actual number of bytes modified may be greater than the number
236 @param Granularity[out] The number of bytes in the last region affected. This may be less
237 than the total number of bytes affected if the starting address
238 was not aligned to a region's starting address or if the length
239 was greater than the number of bytes in the first region.
240 @param On[in] Decode / Non-Decode flag.
242 @retval EFI_SUCCESS The region's attributes were successfully modified.
243 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
248 LegacyRegion2Decode (
249 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
252 OUT UINT32
*Granularity
,
256 return LegacyRegionManipulationInternal (Start
, Length
, On
, NULL
, Granularity
);
261 Modify the hardware to disallow memory attribute changes in a region.
263 This function makes the attributes of a region read only. Once a region is boot-locked with this
264 function, the read and write attributes of that region cannot be changed until a power cycle has
265 reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
267 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
268 @param Start[in] The beginning of the physical address of the region whose
269 attributes should be modified.
270 @param Length[in] The number of bytes of memory whose attributes should be modified.
271 The actual number of bytes modified may be greater than the number
273 @param Granularity[out] The number of bytes in the last region affected. This may be less
274 than the total number of bytes affected if the starting address was
275 not aligned to a region's starting address or if the length was
276 greater than the number of bytes in the first region.
278 @retval EFI_SUCCESS The region's attributes were successfully modified.
279 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
280 @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
281 a way that will not affect memory regions outside the legacy memory
287 LegacyRegion2BootLock (
288 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
291 OUT UINT32
*Granularity
294 if ((Start
< 0xC0000) || ((Start
+ Length
- 1) > 0xFFFFF)) {
295 return EFI_INVALID_PARAMETER
;
298 return EFI_UNSUPPORTED
;
303 Modify the hardware to disallow memory writes in a region.
305 This function changes the attributes of a memory range to not allow writes.
307 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
308 @param Start[in] The beginning of the physical address of the region whose
309 attributes should be modified.
310 @param Length[in] The number of bytes of memory whose attributes should be modified.
311 The actual number of bytes modified may be greater than the number
313 @param Granularity[out] The number of bytes in the last region affected. This may be less
314 than the total number of bytes affected if the starting address was
315 not aligned to a region's starting address or if the length was
316 greater than the number of bytes in the first region.
318 @retval EFI_SUCCESS The region's attributes were successfully modified.
319 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
325 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
328 OUT UINT32
*Granularity
334 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
339 Modify the hardware to allow memory writes in a region.
341 This function changes the attributes of a memory range to allow writes.
343 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
344 @param Start[in] The beginning of the physical address of the region whose
345 attributes should be modified.
346 @param Length[in] The number of bytes of memory whose attributes should be modified.
347 The actual number of bytes modified may be greater than the number
349 @param Granularity[out] The number of bytes in the last region affected. This may be less
350 than the total number of bytes affected if the starting address was
351 not aligned to a region's starting address or if the length was
352 greater than the number of bytes in the first region.
354 @retval EFI_SUCCESS The region's attributes were successfully modified.
355 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
360 LegacyRegion2Unlock (
361 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
364 OUT UINT32
*Granularity
370 return LegacyRegionManipulationInternal (Start
, Length
, NULL
, &WriteEnable
, Granularity
);
374 Get region information for the attributes of the Legacy Region.
376 This function is used to discover the granularity of the attributes for the memory in the legacy
377 region. Each attribute may have a different granularity and the granularity may not be the same
378 for all memory ranges in the legacy region.
380 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
381 @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
383 @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
384 region information is deposited. This buffer will contain a list of
385 DescriptorCount number of region descriptors. This function will
386 provide the memory for the buffer.
388 @retval EFI_SUCCESS The region's attributes were successfully modified.
389 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
394 LegacyRegionGetInfo (
395 IN EFI_LEGACY_REGION2_PROTOCOL
*This
,
396 OUT UINT32
*DescriptorCount
,
397 OUT EFI_LEGACY_REGION_DESCRIPTOR
**Descriptor
400 LEGACY_MEMORY_SECTION_INFO
*SectionInfo
;
402 EFI_LEGACY_REGION_DESCRIPTOR
*DescriptorArray
;
404 UINTN DescriptorIndex
;
407 // Get section numbers and information
409 LegacyRegionGetInfoInternal (&SectionCount
, &SectionInfo
);
412 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
414 DescriptorArray
= AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR
) * SectionCount
* 3);
415 if (DescriptorArray
== NULL
) {
416 return EFI_OUT_OF_RESOURCES
;
420 for (Index
= 0; Index
< SectionCount
; Index
++) {
421 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
422 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
423 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
424 if (SectionInfo
[Index
].ReadEnabled
) {
425 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionDecoded
;
427 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotDecoded
;
432 // Create descriptor for writeability, according to lock status
434 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
435 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
436 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
437 if (SectionInfo
[Index
].WriteEnabled
) {
438 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteEnabled
;
440 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionWriteDisabled
;
445 // Chipset does not support bootlock.
447 DescriptorArray
[DescriptorIndex
].Start
= SectionInfo
[Index
].Start
;
448 DescriptorArray
[DescriptorIndex
].Length
= SectionInfo
[Index
].Length
;
449 DescriptorArray
[DescriptorIndex
].Granularity
= SectionInfo
[Index
].Length
;
450 DescriptorArray
[DescriptorIndex
].Attribute
= LegacyRegionNotLocked
;
454 *DescriptorCount
= (UINT32
) DescriptorIndex
;
455 *Descriptor
= DescriptorArray
;
461 Initialize Legacy Region support
463 @retval EFI_SUCCESS Successfully initialized
472 UINT16 HostBridgeDevId
;
475 // Query Host Bridge DID to determine platform type
477 HostBridgeDevId
= PcdGet16 (PcdOvmfHostBridgePciDevId
);
478 switch (HostBridgeDevId
) {
479 case INTEL_82441_DEVICE_ID
:
480 mRegisterValues
= mRegisterValues440
;
482 case INTEL_Q35_MCH_DEVICE_ID
:
483 mRegisterValues
= mRegisterValuesQ35
;
486 DEBUG ((EFI_D_ERROR
, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
487 __FUNCTION__
, HostBridgeDevId
));
489 return RETURN_UNSUPPORTED
;
493 // Install the Legacy Region Protocol on a new handle
495 Status
= gBS
->InstallMultipleProtocolInterfaces (
497 &gEfiLegacyRegion2ProtocolGuid
, &mLegacyRegion2
,
500 ASSERT_EFI_ERROR (Status
);