Home | History | Annotate | Download | only in CsmSupportLib
      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
     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
    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
    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
    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
    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
    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
    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
    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