• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
LegacyRegionManipulationInternal(IN UINT32 Start,IN UINT32 Length,IN BOOLEAN * ReadEnable,IN BOOLEAN * WriteEnable,OUT UINT32 * Granularity)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 < ARRAY_SIZE (mSectionArray); Index++) {
134     if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
135       StartIndex = Index;
136       break;
137     }
138   }
139   ASSERT (Index < ARRAY_SIZE (mSectionArray));
140 
141   //
142   // Program PAM until end PAM is encountered
143   //
144   for (Index = StartIndex; Index < ARRAY_SIZE (mSectionArray); 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 < ARRAY_SIZE (mSectionArray));
181 
182   return EFI_SUCCESS;
183 }
184 
185 STATIC
186 EFI_STATUS
LegacyRegionGetInfoInternal(OUT UINT32 * DescriptorCount,OUT LEGACY_MEMORY_SECTION_INFO ** Descriptor)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
LegacyRegion2Decode(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity,IN BOOLEAN * On)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
LegacyRegion2BootLock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)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
LegacyRegion2Lock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)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
LegacyRegion2Unlock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)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
LegacyRegionGetInfo(IN EFI_LEGACY_REGION2_PROTOCOL * This,OUT UINT32 * DescriptorCount,OUT EFI_LEGACY_REGION_DESCRIPTOR ** Descriptor)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
LegacyRegionInit(VOID)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 
505