]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c
OvmfPkg/LegacyBios: set NumberBbsEntries to the size of BbsTable
[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 EndAddress = Start + Length - 1;
119 if ((Start < PAM_BASE_ADDRESS) || EndAddress > PAM_LIMIT_ADDRESS) {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 //
124 // Loop to find the start PAM.
125 //
126 StartIndex = 0;
127 for (Index = 0; Index < ARRAY_SIZE (mSectionArray); Index++) {
128 if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
129 StartIndex = Index;
130 break;
131 }
132 }
133 ASSERT (Index < ARRAY_SIZE (mSectionArray));
134
135 //
136 // Program PAM until end PAM is encountered
137 //
138 for (Index = StartIndex; Index < ARRAY_SIZE (mSectionArray); Index++) {
139 if (ReadEnable != NULL) {
140 if (*ReadEnable) {
141 PciOr8 (
142 mRegisterValues[Index].PAMRegPciLibAddress,
143 mRegisterValues[Index].ReadEnableData
144 );
145 } else {
146 PciAnd8 (
147 mRegisterValues[Index].PAMRegPciLibAddress,
148 (UINT8) (~mRegisterValues[Index].ReadEnableData)
149 );
150 }
151 }
152 if (WriteEnable != NULL) {
153 if (*WriteEnable) {
154 PciOr8 (
155 mRegisterValues[Index].PAMRegPciLibAddress,
156 mRegisterValues[Index].WriteEnableData
157 );
158 } else {
159 PciAnd8 (
160 mRegisterValues[Index].PAMRegPciLibAddress,
161 (UINT8) (~mRegisterValues[Index].WriteEnableData)
162 );
163 }
164 }
165
166 //
167 // If the end PAM is encountered, record its length as granularity and jump out.
168 //
169 if ((EndAddress >= mSectionArray[Index].Start) && (EndAddress < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
170 *Granularity = mSectionArray[Index].Length;
171 break;
172 }
173 }
174 ASSERT (Index < ARRAY_SIZE (mSectionArray));
175
176 return EFI_SUCCESS;
177 }
178
179 STATIC
180 EFI_STATUS
181 LegacyRegionGetInfoInternal (
182 OUT UINT32 *DescriptorCount,
183 OUT LEGACY_MEMORY_SECTION_INFO **Descriptor
184 )
185 {
186 UINTN Index;
187 UINT8 PamValue;
188
189 //
190 // Check input parameters
191 //
192 if (DescriptorCount == NULL || Descriptor == NULL) {
193 return EFI_INVALID_PARAMETER;
194 }
195
196 //
197 // Fill in current status of legacy region.
198 //
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;
205 }
206 mSectionArray[Index].WriteEnabled = FALSE;
207 if ((PamValue & mRegisterValues[Index].WriteEnableData) != 0) {
208 mSectionArray[Index].WriteEnabled = TRUE;
209 }
210 }
211
212 *Descriptor = mSectionArray;
213 return EFI_SUCCESS;
214 }
215
216 /**
217 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
218
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).
223
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
226 should be modified.
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
229 specified.
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.
235
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.
238
239 **/
240 EFI_STATUS
241 EFIAPI
242 LegacyRegion2Decode (
243 IN EFI_LEGACY_REGION2_PROTOCOL *This,
244 IN UINT32 Start,
245 IN UINT32 Length,
246 OUT UINT32 *Granularity,
247 IN BOOLEAN *On
248 )
249 {
250 return LegacyRegionManipulationInternal (Start, Length, On, NULL, Granularity);
251 }
252
253
254 /**
255 Modify the hardware to disallow memory attribute changes in a region.
256
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.
260
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
266 specified.
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.
271
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
276 region.
277
278 **/
279 EFI_STATUS
280 EFIAPI
281 LegacyRegion2BootLock (
282 IN EFI_LEGACY_REGION2_PROTOCOL *This,
283 IN UINT32 Start,
284 IN UINT32 Length,
285 OUT UINT32 *Granularity
286 )
287 {
288 if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 return EFI_UNSUPPORTED;
293 }
294
295
296 /**
297 Modify the hardware to disallow memory writes in a region.
298
299 This function changes the attributes of a memory range to not allow writes.
300
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
306 specified.
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.
311
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.
314
315 **/
316 EFI_STATUS
317 EFIAPI
318 LegacyRegion2Lock (
319 IN EFI_LEGACY_REGION2_PROTOCOL *This,
320 IN UINT32 Start,
321 IN UINT32 Length,
322 OUT UINT32 *Granularity
323 )
324 {
325 BOOLEAN WriteEnable;
326
327 WriteEnable = FALSE;
328 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
329 }
330
331
332 /**
333 Modify the hardware to allow memory writes in a region.
334
335 This function changes the attributes of a memory range to allow writes.
336
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
342 specified.
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.
347
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.
350
351 **/
352 EFI_STATUS
353 EFIAPI
354 LegacyRegion2Unlock (
355 IN EFI_LEGACY_REGION2_PROTOCOL *This,
356 IN UINT32 Start,
357 IN UINT32 Length,
358 OUT UINT32 *Granularity
359 )
360 {
361 BOOLEAN WriteEnable;
362
363 WriteEnable = TRUE;
364 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
365 }
366
367 /**
368 Get region information for the attributes of the Legacy Region.
369
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.
373
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
376 buffer.
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.
381
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.
384
385 **/
386 EFI_STATUS
387 EFIAPI
388 LegacyRegionGetInfo (
389 IN EFI_LEGACY_REGION2_PROTOCOL *This,
390 OUT UINT32 *DescriptorCount,
391 OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
392 )
393 {
394 LEGACY_MEMORY_SECTION_INFO *SectionInfo;
395 UINT32 SectionCount;
396 EFI_LEGACY_REGION_DESCRIPTOR *DescriptorArray;
397 UINTN Index;
398 UINTN DescriptorIndex;
399
400 //
401 // Get section numbers and information
402 //
403 LegacyRegionGetInfoInternal (&SectionCount, &SectionInfo);
404
405 //
406 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
407 //
408 DescriptorArray = AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR) * SectionCount * 3);
409 if (DescriptorArray == NULL) {
410 return EFI_OUT_OF_RESOURCES;
411 }
412
413 DescriptorIndex = 0;
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;
420 } else {
421 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotDecoded;
422 }
423 DescriptorIndex++;
424
425 //
426 // Create descriptor for writeability, according to lock status
427 //
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;
433 } else {
434 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteDisabled;
435 }
436 DescriptorIndex++;
437
438 //
439 // Chipset does not support bootlock.
440 //
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;
445 DescriptorIndex++;
446 }
447
448 *DescriptorCount = (UINT32) DescriptorIndex;
449 *Descriptor = DescriptorArray;
450
451 return EFI_SUCCESS;
452 }
453
454 /**
455 Initialize Legacy Region support
456
457 @retval EFI_SUCCESS Successfully initialized
458
459 **/
460 EFI_STATUS
461 LegacyRegionInit (
462 VOID
463 )
464 {
465 EFI_STATUS Status;
466 UINT16 HostBridgeDevId;
467
468 //
469 // Query Host Bridge DID to determine platform type
470 //
471 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
472 switch (HostBridgeDevId) {
473 case INTEL_82441_DEVICE_ID:
474 mRegisterValues = mRegisterValues440;
475 break;
476 case INTEL_Q35_MCH_DEVICE_ID:
477 mRegisterValues = mRegisterValuesQ35;
478 break;
479 default:
480 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
481 __FUNCTION__, HostBridgeDevId));
482 ASSERT (FALSE);
483 return RETURN_UNSUPPORTED;
484 }
485
486 //
487 // Install the Legacy Region Protocol on a new handle
488 //
489 Status = gBS->InstallMultipleProtocolInterfaces (
490 &mHandle,
491 &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,
492 NULL
493 );
494 ASSERT_EFI_ERROR (Status);
495
496 return Status;
497 }
498