1 /** @file
2   Legacy Region Support
3 
4   Copyright (c) 2006 - 2011, 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 PAM map.
20 //
21 // PAM Range       Offset  Bits  Operation
22 // =============== ======  ====  ===============================================================
23 // 0xC0000-0xC3FFF  0x5a   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
24 // 0xC4000-0xC7FFF  0x5a   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
25 // 0xC8000-0xCBFFF  0x5b   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
26 // 0xCC000-0xCFFFF  0x5b   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
27 // 0xD0000-0xD3FFF  0x5c   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
28 // 0xD4000-0xD7FFF  0x5c   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
29 // 0xD8000-0xDBFFF  0x5d   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
30 // 0xDC000-0xDFFFF  0x5d   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
31 // 0xE0000-0xE3FFF  0x5e   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
32 // 0xE4000-0xE7FFF  0x5e   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
33 // 0xE8000-0xEBFFF  0x5f   1:0   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
34 // 0xEC000-0xEFFFF  0x5f   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
35 // 0xF0000-0xFFFFF  0x59   5:4   00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal
36 //
37 STATIC LEGACY_MEMORY_SECTION_INFO   mSectionArray[] = {
38   {0xC0000, SIZE_16KB, FALSE, FALSE},
39   {0xC4000, SIZE_16KB, FALSE, FALSE},
40   {0xC8000, SIZE_16KB, FALSE, FALSE},
41   {0xCC000, SIZE_16KB, FALSE, FALSE},
42   {0xD0000, SIZE_16KB, FALSE, FALSE},
43   {0xD4000, SIZE_16KB, FALSE, FALSE},
44   {0xD8000, SIZE_16KB, FALSE, FALSE},
45   {0xDC000, SIZE_16KB, FALSE, FALSE},
46   {0xE0000, SIZE_16KB, FALSE, FALSE},
47   {0xE4000, SIZE_16KB, FALSE, FALSE},
48   {0xE8000, SIZE_16KB, FALSE, FALSE},
49   {0xEC000, SIZE_16KB, FALSE, FALSE},
50   {0xF0000, SIZE_64KB, FALSE, FALSE}
51 };
52 
53 STATIC PAM_REGISTER_VALUE  mRegisterValues[] = {
54   {REG_PAM1_OFFSET, 0x01, 0x02},
55   {REG_PAM1_OFFSET, 0x10, 0x20},
56   {REG_PAM2_OFFSET, 0x01, 0x02},
57   {REG_PAM2_OFFSET, 0x10, 0x20},
58   {REG_PAM3_OFFSET, 0x01, 0x02},
59   {REG_PAM3_OFFSET, 0x10, 0x20},
60   {REG_PAM4_OFFSET, 0x01, 0x02},
61   {REG_PAM4_OFFSET, 0x10, 0x20},
62   {REG_PAM5_OFFSET, 0x01, 0x02},
63   {REG_PAM5_OFFSET, 0x10, 0x20},
64   {REG_PAM6_OFFSET, 0x01, 0x02},
65   {REG_PAM6_OFFSET, 0x10, 0x20},
66   {REG_PAM0_OFFSET, 0x10, 0x20}
67 };
68 
69 //
70 // Handle used to install the Legacy Region Protocol
71 //
72 STATIC EFI_HANDLE  mHandle = NULL;
73 
74 //
75 // Instance of the Legacy Region Protocol to install into the handle database
76 //
77 STATIC EFI_LEGACY_REGION2_PROTOCOL  mLegacyRegion2 = {
78   LegacyRegion2Decode,
79   LegacyRegion2Lock,
80   LegacyRegion2BootLock,
81   LegacyRegion2Unlock,
82   LegacyRegionGetInfo
83 };
84 
85 STATIC
86 EFI_STATUS
LegacyRegionManipulationInternal(IN UINT32 Start,IN UINT32 Length,IN BOOLEAN * ReadEnable,IN BOOLEAN * WriteEnable,OUT UINT32 * Granularity)87 LegacyRegionManipulationInternal (
88   IN  UINT32                  Start,
89   IN  UINT32                  Length,
90   IN  BOOLEAN                 *ReadEnable,
91   IN  BOOLEAN                 *WriteEnable,
92   OUT UINT32                  *Granularity
93   )
94 {
95   UINT32                        EndAddress;
96   UINTN                         Index;
97   UINTN                         StartIndex;
98 
99   //
100   // Validate input parameters.
101   //
102   if (Length == 0 || Granularity == NULL) {
103     return EFI_INVALID_PARAMETER;
104   }
105   EndAddress = Start + Length - 1;
106   if ((Start < PAM_BASE_ADDRESS) || EndAddress > PAM_LIMIT_ADDRESS) {
107     return EFI_INVALID_PARAMETER;
108   }
109 
110   //
111   // Loop to find the start PAM.
112   //
113   StartIndex = 0;
114   for (Index = 0; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) {
115     if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
116       StartIndex = Index;
117       break;
118     }
119   }
120   ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])));
121 
122   //
123   // Program PAM until end PAM is encountered
124   //
125   for (Index = StartIndex; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) {
126     if (ReadEnable != NULL) {
127       if (*ReadEnable) {
128         PciOr8 (
129           PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),
130           mRegisterValues[Index].ReadEnableData
131           );
132       } else {
133         PciAnd8 (
134           PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),
135           (UINT8) (~mRegisterValues[Index].ReadEnableData)
136           );
137       }
138     }
139     if (WriteEnable != NULL) {
140       if (*WriteEnable) {
141         PciOr8 (
142           PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),
143           mRegisterValues[Index].WriteEnableData
144           );
145       } else {
146         PciAnd8 (
147           PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),
148           (UINT8) (~mRegisterValues[Index].WriteEnableData)
149           );
150       }
151     }
152 
153     //
154     // If the end PAM is encountered, record its length as granularity and jump out.
155     //
156     if ((EndAddress >= mSectionArray[Index].Start) && (EndAddress < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {
157       *Granularity = mSectionArray[Index].Length;
158       break;
159     }
160   }
161   ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])));
162 
163   return EFI_SUCCESS;
164 }
165 
166 STATIC
167 EFI_STATUS
LegacyRegionGetInfoInternal(OUT UINT32 * DescriptorCount,OUT LEGACY_MEMORY_SECTION_INFO ** Descriptor)168 LegacyRegionGetInfoInternal (
169   OUT UINT32                        *DescriptorCount,
170   OUT LEGACY_MEMORY_SECTION_INFO    **Descriptor
171   )
172 {
173   UINTN    Index;
174   UINT8    PamValue;
175 
176   //
177   // Check input parameters
178   //
179   if (DescriptorCount == NULL || Descriptor == NULL) {
180     return EFI_INVALID_PARAMETER;
181   }
182 
183   //
184   // Fill in current status of legacy region.
185   //
186   *DescriptorCount = sizeof(mSectionArray) / sizeof (mSectionArray[0]);
187   for (Index = 0; Index < *DescriptorCount; Index++) {
188     PamValue = PciRead8 (PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset));
189     mSectionArray[Index].ReadEnabled = FALSE;
190     if ((PamValue & mRegisterValues[Index].ReadEnableData) != 0) {
191       mSectionArray[Index].ReadEnabled = TRUE;
192     }
193     mSectionArray[Index].WriteEnabled = FALSE;
194     if ((PamValue & mRegisterValues[Index].WriteEnableData) != 0) {
195       mSectionArray[Index].WriteEnabled = TRUE;
196     }
197   }
198 
199   *Descriptor = mSectionArray;
200   return EFI_SUCCESS;
201 }
202 
203 /**
204   Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
205 
206   If the On parameter evaluates to TRUE, this function enables memory reads in the address range
207   Start to (Start + Length - 1).
208   If the On parameter evaluates to FALSE, this function disables memory reads in the address range
209   Start to (Start + Length - 1).
210 
211   @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
212   @param  Start[in]             The beginning of the physical address of the region whose attributes
213                                 should be modified.
214   @param  Length[in]            The number of bytes of memory whose attributes should be modified.
215                                 The actual number of bytes modified may be greater than the number
216                                 specified.
217   @param  Granularity[out]      The number of bytes in the last region affected. This may be less
218                                 than the total number of bytes affected if the starting address
219                                 was not aligned to a region's starting address or if the length
220                                 was greater than the number of bytes in the first region.
221   @param  On[in]                Decode / Non-Decode flag.
222 
223   @retval EFI_SUCCESS           The region's attributes were successfully modified.
224   @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
225 
226 **/
227 EFI_STATUS
228 EFIAPI
LegacyRegion2Decode(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity,IN BOOLEAN * On)229 LegacyRegion2Decode (
230   IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
231   IN  UINT32                       Start,
232   IN  UINT32                       Length,
233   OUT UINT32                       *Granularity,
234   IN  BOOLEAN                      *On
235   )
236 {
237   return LegacyRegionManipulationInternal (Start, Length, On, NULL, Granularity);
238 }
239 
240 
241 /**
242   Modify the hardware to disallow memory attribute changes in a region.
243 
244   This function makes the attributes of a region read only. Once a region is boot-locked with this
245   function, the read and write attributes of that region cannot be changed until a power cycle has
246   reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
247 
248   @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
249   @param  Start[in]             The beginning of the physical address of the region whose
250                                 attributes should be modified.
251   @param  Length[in]            The number of bytes of memory whose attributes should be modified.
252                                 The actual number of bytes modified may be greater than the number
253                                 specified.
254   @param  Granularity[out]      The number of bytes in the last region affected. This may be less
255                                 than the total number of bytes affected if the starting address was
256                                 not aligned to a region's starting address or if the length was
257                                 greater than the number of bytes in the first region.
258 
259   @retval EFI_SUCCESS           The region's attributes were successfully modified.
260   @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
261   @retval EFI_UNSUPPORTED       The chipset does not support locking the configuration registers in
262                                 a way that will not affect memory regions outside the legacy memory
263                                 region.
264 
265 **/
266 EFI_STATUS
267 EFIAPI
LegacyRegion2BootLock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)268 LegacyRegion2BootLock (
269   IN  EFI_LEGACY_REGION2_PROTOCOL         *This,
270   IN  UINT32                              Start,
271   IN  UINT32                              Length,
272   OUT UINT32                              *Granularity
273   )
274 {
275   if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
276     return EFI_INVALID_PARAMETER;
277   }
278 
279   return EFI_UNSUPPORTED;
280 }
281 
282 
283 /**
284   Modify the hardware to disallow memory writes in a region.
285 
286   This function changes the attributes of a memory range to not allow writes.
287 
288   @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
289   @param  Start[in]             The beginning of the physical address of the region whose
290                                 attributes should be modified.
291   @param  Length[in]            The number of bytes of memory whose attributes should be modified.
292                                 The actual number of bytes modified may be greater than the number
293                                 specified.
294   @param  Granularity[out]      The number of bytes in the last region affected. This may be less
295                                 than the total number of bytes affected if the starting address was
296                                 not aligned to a region's starting address or if the length was
297                                 greater than the number of bytes in the first region.
298 
299   @retval EFI_SUCCESS           The region's attributes were successfully modified.
300   @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
301 
302 **/
303 EFI_STATUS
304 EFIAPI
LegacyRegion2Lock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)305 LegacyRegion2Lock (
306   IN  EFI_LEGACY_REGION2_PROTOCOL *This,
307   IN  UINT32                      Start,
308   IN  UINT32                      Length,
309   OUT UINT32                      *Granularity
310   )
311 {
312   BOOLEAN  WriteEnable;
313 
314   WriteEnable = FALSE;
315   return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
316 }
317 
318 
319 /**
320   Modify the hardware to allow memory writes in a region.
321 
322   This function changes the attributes of a memory range to allow writes.
323 
324   @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
325   @param  Start[in]             The beginning of the physical address of the region whose
326                                 attributes should be modified.
327   @param  Length[in]            The number of bytes of memory whose attributes should be modified.
328                                 The actual number of bytes modified may be greater than the number
329                                 specified.
330   @param  Granularity[out]      The number of bytes in the last region affected. This may be less
331                                 than the total number of bytes affected if the starting address was
332                                 not aligned to a region's starting address or if the length was
333                                 greater than the number of bytes in the first region.
334 
335   @retval EFI_SUCCESS           The region's attributes were successfully modified.
336   @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
337 
338 **/
339 EFI_STATUS
340 EFIAPI
LegacyRegion2Unlock(IN EFI_LEGACY_REGION2_PROTOCOL * This,IN UINT32 Start,IN UINT32 Length,OUT UINT32 * Granularity)341 LegacyRegion2Unlock (
342   IN  EFI_LEGACY_REGION2_PROTOCOL  *This,
343   IN  UINT32                       Start,
344   IN  UINT32                       Length,
345   OUT UINT32                       *Granularity
346   )
347 {
348   BOOLEAN  WriteEnable;
349 
350   WriteEnable = TRUE;
351   return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);
352 }
353 
354 /**
355   Get region information for the attributes of the Legacy Region.
356 
357   This function is used to discover the granularity of the attributes for the memory in the legacy
358   region. Each attribute may have a different granularity and the granularity may not be the same
359   for all memory ranges in the legacy region.
360 
361   @param  This[in]              Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
362   @param  DescriptorCount[out]  The number of region descriptor entries returned in the Descriptor
363                                 buffer.
364   @param  Descriptor[out]       A pointer to a pointer used to return a buffer where the legacy
365                                 region information is deposited. This buffer will contain a list of
366                                 DescriptorCount number of region descriptors.  This function will
367                                 provide the memory for the buffer.
368 
369   @retval EFI_SUCCESS           The region's attributes were successfully modified.
370   @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
371 
372 **/
373 EFI_STATUS
374 EFIAPI
LegacyRegionGetInfo(IN EFI_LEGACY_REGION2_PROTOCOL * This,OUT UINT32 * DescriptorCount,OUT EFI_LEGACY_REGION_DESCRIPTOR ** Descriptor)375 LegacyRegionGetInfo (
376   IN  EFI_LEGACY_REGION2_PROTOCOL   *This,
377   OUT UINT32                        *DescriptorCount,
378   OUT EFI_LEGACY_REGION_DESCRIPTOR  **Descriptor
379   )
380 {
381   LEGACY_MEMORY_SECTION_INFO   *SectionInfo;
382   UINT32                       SectionCount;
383   EFI_LEGACY_REGION_DESCRIPTOR *DescriptorArray;
384   UINTN                        Index;
385   UINTN                        DescriptorIndex;
386 
387   //
388   // Get section numbers and information
389   //
390   LegacyRegionGetInfoInternal (&SectionCount, &SectionInfo);
391 
392   //
393   // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.
394   //
395   DescriptorArray = AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR) * SectionCount * 3);
396   if (DescriptorArray == NULL) {
397     return EFI_OUT_OF_RESOURCES;
398   }
399 
400   DescriptorIndex = 0;
401   for (Index = 0; Index < SectionCount; Index++) {
402     DescriptorArray[DescriptorIndex].Start       = SectionInfo[Index].Start;
403     DescriptorArray[DescriptorIndex].Length      = SectionInfo[Index].Length;
404     DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length;
405     if (SectionInfo[Index].ReadEnabled) {
406       DescriptorArray[DescriptorIndex].Attribute   = LegacyRegionDecoded;
407     } else {
408       DescriptorArray[DescriptorIndex].Attribute   = LegacyRegionNotDecoded;
409     }
410     DescriptorIndex++;
411 
412     //
413     // Create descriptor for writeability, according to lock status
414     //
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].WriteEnabled) {
419       DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteEnabled;
420     } else {
421       DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteDisabled;
422     }
423     DescriptorIndex++;
424 
425     //
426     // Chipset does not support bootlock.
427     //
428     DescriptorArray[DescriptorIndex].Start       = SectionInfo[Index].Start;
429     DescriptorArray[DescriptorIndex].Length      = SectionInfo[Index].Length;
430     DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length;
431     DescriptorArray[DescriptorIndex].Attribute   = LegacyRegionNotLocked;
432     DescriptorIndex++;
433   }
434 
435   *DescriptorCount = (UINT32) DescriptorIndex;
436   *Descriptor      = DescriptorArray;
437 
438   return EFI_SUCCESS;
439 }
440 
441 /**
442   Initialize Legacy Region support
443 
444   @retval EFI_SUCCESS   Successfully initialized
445 
446 **/
447 EFI_STATUS
LegacyRegionInit(VOID)448 LegacyRegionInit (
449   VOID
450   )
451 {
452   EFI_STATUS  Status;
453 
454   //
455   // Install the Legacy Region Protocol on a new handle
456   //
457   Status = gBS->InstallMultipleProtocolInterfaces (
458                   &mHandle,
459                   &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,
460                   NULL
461                   );
462   ASSERT_EFI_ERROR (Status);
463 
464   return Status;
465 }
466 
467