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