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