]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Csm / CsmSupportLib / LegacyRegion.c
1 /** @file
2 Legacy Region Support
3
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "LegacyRegion.h"
11
12 //
13 // 440/Q35 PAM map.
14 //
15 // PAM Range Offset Bits Operation
16 // 440 Q35
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
31 //
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 }
46 };
47
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 }
62 };
63
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 }
78 };
79
80 STATIC PAM_REGISTER_VALUE *mRegisterValues;
81
82 //
83 // Handle used to install the Legacy Region Protocol
84 //
85 STATIC EFI_HANDLE mHandle = NULL;
86
87 //
88 // Instance of the Legacy Region Protocol to install into the handle database
89 //
90 STATIC EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = {
91 LegacyRegion2Decode,
92 LegacyRegion2Lock,
93 LegacyRegion2BootLock,
94 LegacyRegion2Unlock,
95 LegacyRegionGetInfo
96 };
97
98 STATIC
99 EFI_STATUS
100 LegacyRegionManipulationInternal (
101 IN UINT32 Start,
102 IN UINT32 Length,
103 IN BOOLEAN *ReadEnable,
104 IN BOOLEAN *WriteEnable,
105 OUT UINT32 *Granularity
106 )
107 {
108 UINT32 EndAddress;
109 UINTN Index;
110 UINTN StartIndex;
111
112 //
113 // Validate input parameters.
114 //
115 if ((Length == 0) || (Granularity == NULL)) {
116 return EFI_INVALID_PARAMETER;
117 }
118
119 EndAddress = Start + Length - 1;
120 if ((Start < PAM_BASE_ADDRESS) || (EndAddress > PAM_LIMIT_ADDRESS)) {
121 return EFI_INVALID_PARAMETER;
122 }
123
124 //
125 // Loop to find the start PAM.
126 //
127 StartIndex = 0;
128 for (Index = 0; Index < ARRAY_SIZE (mSectionArray); Index++) {
129 if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
130 StartIndex = Index;
131 break;
132 }
133 }
134
135 ASSERT (Index < ARRAY_SIZE (mSectionArray));
136
137 //
138 // Program PAM until end PAM is encountered
139 //
140 for (Index = StartIndex; Index < ARRAY_SIZE (mSectionArray); Index++) {
141 if (ReadEnable != NULL) {
142 if (*ReadEnable) {
143 PciOr8 (
144 mRegisterValues[Index].PAMRegPciLibAddress,
145 mRegisterValues[Index].ReadEnableData
146 );
147 } else {
148 PciAnd8 (
149 mRegisterValues[Index].PAMRegPciLibAddress,
150 (UINT8)(~mRegisterValues[Index].ReadEnableData)
151 );
152 }
153 }
154
155 if (WriteEnable != NULL) {
156 if (*WriteEnable) {
157 PciOr8 (
158 mRegisterValues[Index].PAMRegPciLibAddress,
159 mRegisterValues[Index].WriteEnableData
160 );
161 } else {
162 PciAnd8 (
163 mRegisterValues[Index].PAMRegPciLibAddress,
164 (UINT8)(~mRegisterValues[Index].WriteEnableData)
165 );
166 }
167 }
168
169 //
170 // If the end PAM is encountered, record its length as granularity and jump out.
171 //
172 if ((EndAddress >= mSectionArray[Index].Start) && (EndAddress < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
173 *Granularity = mSectionArray[Index].Length;
174 break;
175 }
176 }
177
178 ASSERT (Index < ARRAY_SIZE (mSectionArray));
179
180 return EFI_SUCCESS;
181 }
182
183 STATIC
184 EFI_STATUS
185 LegacyRegionGetInfoInternal (
186 OUT UINT32 *DescriptorCount,
187 OUT LEGACY_MEMORY_SECTION_INFO **Descriptor
188 )
189 {
190 UINTN Index;
191 UINT8 PamValue;
192
193 //
194 // Check input parameters
195 //
196 if ((DescriptorCount == NULL) || (Descriptor == NULL)) {
197 return EFI_INVALID_PARAMETER;
198 }
199
200 //
201 // Fill in current status of legacy region.
202 //
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;
209 }
210
211 mSectionArray[Index].WriteEnabled = FALSE;
212 if ((PamValue & mRegisterValues[Index].WriteEnableData) != 0) {
213 mSectionArray[Index].WriteEnabled = TRUE;
214 }
215 }
216
217 *Descriptor = mSectionArray;
218 return EFI_SUCCESS;
219 }
220
221 /**
222 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
223
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).
228
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
231 should be modified.
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
234 specified.
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.
240
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.
243
244 **/
245 EFI_STATUS
246 EFIAPI
247 LegacyRegion2Decode (
248 IN EFI_LEGACY_REGION2_PROTOCOL *This,
249 IN UINT32 Start,
250 IN UINT32 Length,
251 OUT UINT32 *Granularity,
252 IN BOOLEAN *On
253 )
254 {
255 return LegacyRegionManipulationInternal (Start, Length, On, NULL, Granularity);
256 }
257
258 /**
259 Modify the hardware to disallow memory attribute changes in a region.
260
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.
264
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
270 specified.
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.
275
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
280 region.
281
282 **/
283 EFI_STATUS
284 EFIAPI
285 LegacyRegion2BootLock (
286 IN EFI_LEGACY_REGION2_PROTOCOL *This,
287 IN UINT32 Start,
288 IN UINT32 Length,
289 OUT UINT32 *Granularity
290 )
291 {
292 if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 return EFI_UNSUPPORTED;
297 }
298
299 /**
300 Modify the hardware to disallow memory writes in a region.
301
302 This function changes the attributes of a memory range to not allow writes.
303
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
309 specified.
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.
314
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.
317
318 **/
319 EFI_STATUS
320 EFIAPI
321 LegacyRegion2Lock (
322 IN EFI_LEGACY_REGION2_PROTOCOL *This,
323 IN UINT32 Start,
324 IN UINT32 Length,
325 OUT UINT32 *Granularity
326 )
327 {
328 BOOLEAN WriteEnable;
329
330 WriteEnable = FALSE;
331 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
332 }
333
334 /**
335 Modify the hardware to allow memory writes in a region.
336
337 This function changes the attributes of a memory range to allow writes.
338
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
344 specified.
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.
349
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.
352
353 **/
354 EFI_STATUS
355 EFIAPI
356 LegacyRegion2Unlock (
357 IN EFI_LEGACY_REGION2_PROTOCOL *This,
358 IN UINT32 Start,
359 IN UINT32 Length,
360 OUT UINT32 *Granularity
361 )
362 {
363 BOOLEAN WriteEnable;
364
365 WriteEnable = TRUE;
366 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
367 }
368
369 /**
370 Get region information for the attributes of the Legacy Region.
371
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.
375
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
378 buffer.
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.
383
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.
386
387 **/
388 EFI_STATUS
389 EFIAPI
390 LegacyRegionGetInfo (
391 IN EFI_LEGACY_REGION2_PROTOCOL *This,
392 OUT UINT32 *DescriptorCount,
393 OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
394 )
395 {
396 LEGACY_MEMORY_SECTION_INFO *SectionInfo;
397 UINT32 SectionCount;
398 EFI_LEGACY_REGION_DESCRIPTOR *DescriptorArray;
399 UINTN Index;
400 UINTN DescriptorIndex;
401
402 //
403 // Get section numbers and information
404 //
405 LegacyRegionGetInfoInternal (&SectionCount, &SectionInfo);
406
407 //
408 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
409 //
410 DescriptorArray = AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR) * SectionCount * 3);
411 if (DescriptorArray == NULL) {
412 return EFI_OUT_OF_RESOURCES;
413 }
414
415 DescriptorIndex = 0;
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;
422 } else {
423 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotDecoded;
424 }
425
426 DescriptorIndex++;
427
428 //
429 // Create descriptor for writeability, according to lock status
430 //
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;
436 } else {
437 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteDisabled;
438 }
439
440 DescriptorIndex++;
441
442 //
443 // Chipset does not support bootlock.
444 //
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;
449 DescriptorIndex++;
450 }
451
452 *DescriptorCount = (UINT32)DescriptorIndex;
453 *Descriptor = DescriptorArray;
454
455 return EFI_SUCCESS;
456 }
457
458 /**
459 Initialize Legacy Region support
460
461 @retval EFI_SUCCESS Successfully initialized
462
463 **/
464 EFI_STATUS
465 LegacyRegionInit (
466 VOID
467 )
468 {
469 EFI_STATUS Status;
470 UINT16 HostBridgeDevId;
471
472 //
473 // Query Host Bridge DID to determine platform type
474 //
475 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
476 switch (HostBridgeDevId) {
477 case INTEL_82441_DEVICE_ID:
478 mRegisterValues = mRegisterValues440;
479 break;
480 case INTEL_Q35_MCH_DEVICE_ID:
481 mRegisterValues = mRegisterValuesQ35;
482 break;
483 default:
484 DEBUG ((
485 DEBUG_ERROR,
486 "%a: Unknown Host Bridge Device ID: 0x%04x\n",
487 __FUNCTION__,
488 HostBridgeDevId
489 ));
490 ASSERT (FALSE);
491 return RETURN_UNSUPPORTED;
492 }
493
494 //
495 // Install the Legacy Region Protocol on a new handle
496 //
497 Status = gBS->InstallMultipleProtocolInterfaces (
498 &mHandle,
499 &gEfiLegacyRegion2ProtocolGuid,
500 &mLegacyRegion2,
501 NULL
502 );
503 ASSERT_EFI_ERROR (Status);
504
505 return Status;
506 }