1 /** @file 2 This is the driver that publishes the SMM Access Protocol 3 instance for the Tylersburg chipset. 4 5 Copyright (c) 2013-2015 Intel Corporation. 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "SmmAccessDriver.h" 18 19 20 21 SMM_ACCESS_PRIVATE_DATA mSmmAccess; 22 23 VOID 24 SmmAccessOnBoot ( 25 IN EFI_EVENT Event, 26 IN VOID *Context 27 ); 28 29 EFI_STATUS 30 EFIAPI 31 SmmAccessDriverEntryPoint ( 32 IN EFI_HANDLE ImageHandle, 33 IN EFI_SYSTEM_TABLE *SystemTable 34 ) 35 /*++ 36 37 Routine Description: 38 39 Installs an SMM Access Protocol. 40 41 Arguments: 42 43 ImageHandle - Handle for the image of this driver. 44 SystemTable - Pointer to the EFI System Table. 45 46 Returns: 47 48 EFI_SUCCESS - Protocol successfully started and installed. 49 EFI_UNSUPPORTED - Protocol can't be started. 50 EFI_NOT_FOUND - Protocol not found. 51 --*/ 52 { 53 54 EFI_STATUS Status; 55 EFI_EVENT BootEvent; 56 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 57 UINTN Index; 58 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; 59 EFI_HOB_GUID_TYPE *GuidHob; 60 61 62 // 63 // Initialize private data 64 // 65 ZeroMem (&mSmmAccess, sizeof (mSmmAccess)); 66 67 Status = gBS->LocateProtocol ( 68 &gEfiPciRootBridgeIoProtocolGuid, 69 NULL, 70 (VOID **) &PciRootBridgeIo 71 ); 72 ASSERT_EFI_ERROR (Status); 73 74 // 75 // Build SMM related information 76 // 77 mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE; 78 mSmmAccess.Handle = NULL; 79 mSmmAccess.PciRootBridgeIo = PciRootBridgeIo; 80 81 // 82 // Get Hob list 83 // 84 GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid); 85 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); 86 ASSERT (DescriptorBlock); 87 88 89 // 90 // Get CPU Max bus number 91 // 92 mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC; 93 for (Index = 0; Index < MAX_CPU_SOCKET; Index++) { 94 mSmmAccess.SocketPopulated[Index] = TRUE; 95 } 96 97 // 98 // Use the hob to publish SMRAM capabilities 99 // 100 ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES); 101 for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) { 102 mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart; 103 mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart; 104 mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize; 105 mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState; 106 DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart, 107 mSmmAccess.SmramDesc[Index].PhysicalSize)); 108 } 109 110 mSmmAccess.NumberRegions = Index; 111 mSmmAccess.SmmAccess.Open = Open; 112 mSmmAccess.SmmAccess.Close = Close; 113 mSmmAccess.SmmAccess.Lock = Lock; 114 mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities; 115 mSmmAccess.SmmAccess.LockState = FALSE; 116 mSmmAccess.SmmAccess.OpenState = FALSE; 117 mSmmAccess.SMMRegionState = EFI_SMRAM_CLOSED; 118 119 // 120 // Install our protocol interfaces on the device's handle 121 // 122 Status = gBS->InstallMultipleProtocolInterfaces ( 123 &mSmmAccess.Handle, 124 &gEfiSmmAccess2ProtocolGuid, 125 &mSmmAccess.SmmAccess, 126 NULL 127 ); 128 ASSERT_EFI_ERROR (Status); 129 130 DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart))); 131 DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize))); 132 133 mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize); 134 // 135 // T Seg setting done in QPI RC 136 // 137 138 // 139 // Prior ReadyToBoot, lock CSEG 140 // 141 Status = EfiCreateEventReadyToBootEx( 142 TPL_NOTIFY, 143 SmmAccessOnBoot, 144 NULL, 145 &BootEvent ); 146 ASSERT (!EFI_ERROR (Status)); 147 return EFI_SUCCESS; 148 } 149 150 EFI_STATUS 151 EFIAPI 152 Open ( 153 IN EFI_SMM_ACCESS2_PROTOCOL *This 154 ) 155 /*++ 156 157 Routine Description: 158 159 This routine accepts a request to "open" a region of SMRAM. The 160 region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. 161 The use of "open" means that the memory is visible from all boot-service 162 and SMM agents. 163 164 Arguments: 165 166 This - Pointer to the SMM Access Interface. 167 DescriptorIndex - Region of SMRAM to Open. 168 169 Returns: 170 171 EFI_SUCCESS - The region was successfully opened. 172 EFI_DEVICE_ERROR - The region could not be opened because locked by 173 chipset. 174 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 175 176 --*/ 177 { 178 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 179 180 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 181 182 if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) { 183 DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n")); 184 return EFI_DEVICE_ERROR; 185 } 186 187 // 188 // Open TSEG 189 // 190 if (!QNCOpenSmramRegion ()) { 191 mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; 192 return EFI_DEVICE_ERROR; 193 } 194 195 mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED); 196 SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED))); 197 mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN; 198 SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN); 199 SmmAccess->SmmAccess.OpenState = TRUE; 200 201 return EFI_SUCCESS; 202 } 203 204 EFI_STATUS 205 EFIAPI 206 Close ( 207 IN EFI_SMM_ACCESS2_PROTOCOL *This 208 ) 209 /*++ 210 211 Routine Description: 212 213 This routine accepts a request to "close" a region of SMRAM. This is valid for 214 compatible SMRAM region. 215 216 Arguments: 217 218 This - Pointer to the SMM Access Interface. 219 DescriptorIndex - Region of SMRAM to Close. 220 221 Returns: 222 223 EFI_SUCCESS - The region was successfully closed. 224 EFI_DEVICE_ERROR - The region could not be closed because locked by 225 chipset. 226 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 227 228 --*/ 229 { 230 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 231 BOOLEAN OpenState; 232 UINTN Index; 233 234 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 235 236 if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) { 237 // 238 // Cannot close a "locked" region 239 // 240 DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n")); 241 return EFI_DEVICE_ERROR; 242 } 243 244 if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) { 245 return EFI_DEVICE_ERROR; 246 } 247 248 // 249 // Close TSEG 250 // 251 if (!QNCCloseSmramRegion ()) { 252 mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; 253 return EFI_DEVICE_ERROR; 254 } 255 256 mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN; 257 SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN)); 258 mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED); 259 SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED); 260 261 // 262 // Find out if any regions are still open 263 // 264 OpenState = FALSE; 265 for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { 266 if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) { 267 OpenState = TRUE; 268 } 269 } 270 271 SmmAccess->SmmAccess.OpenState = OpenState; 272 273 return EFI_SUCCESS; 274 } 275 276 EFI_STATUS 277 EFIAPI 278 Lock ( 279 IN EFI_SMM_ACCESS2_PROTOCOL *This 280 ) 281 /*++ 282 283 Routine Description: 284 285 This routine accepts a request to "lock" SMRAM. The 286 region could be legacy AB or TSEG near top of physical memory. 287 The use of "lock" means that the memory can no longer be opened 288 to BS state.. 289 290 Arguments: 291 292 This - Pointer to the SMM Access Interface. 293 DescriptorIndex - Region of SMRAM to Lock. 294 295 Returns: 296 297 EFI_SUCCESS - The region was successfully locked. 298 EFI_DEVICE_ERROR - The region could not be locked because at least 299 one range is still open. 300 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 301 302 --*/ 303 { 304 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 305 306 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 307 308 if (SmmAccess->SmmAccess.OpenState) { 309 return EFI_DEVICE_ERROR; 310 } 311 312 mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED; 313 SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED); 314 SmmAccess->SmmAccess.LockState = TRUE; 315 316 // 317 // Lock TSEG 318 // 319 QNCLockSmramRegion (); 320 321 return EFI_SUCCESS; 322 } 323 324 EFI_STATUS 325 EFIAPI 326 GetCapabilities ( 327 IN CONST EFI_SMM_ACCESS2_PROTOCOL *This, 328 IN OUT UINTN *SmramMapSize, 329 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap 330 ) 331 /*++ 332 333 Routine Description: 334 335 This routine services a user request to discover the SMRAM 336 capabilities of this platform. This will report the possible 337 ranges that are possible for SMRAM access, based upon the 338 memory controller capabilities. 339 340 Arguments: 341 342 This - Pointer to the SMRAM Access Interface. 343 SmramMapSize - Pointer to the variable containing size of the 344 buffer to contain the description information. 345 SmramMap - Buffer containing the data describing the Smram 346 region descriptors. 347 Returns: 348 349 EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer. 350 EFI_SUCCESS - The user provided a sufficiently-sized buffer. 351 352 --*/ 353 { 354 EFI_STATUS Status; 355 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 356 UINTN BufferSize; 357 358 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 359 BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR); 360 361 if (*SmramMapSize < BufferSize) { 362 Status = EFI_BUFFER_TOO_SMALL; 363 } else { 364 CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize); 365 Status = EFI_SUCCESS; 366 } 367 *SmramMapSize = BufferSize; 368 369 return Status; 370 } 371 372 VOID 373 SmmAccessOnBoot ( 374 IN EFI_EVENT Event, 375 IN VOID *Context 376 ) 377 { 378 379 } 380 VOID 381 SyncRegionState2SmramDesc( 382 IN BOOLEAN OrAnd, 383 IN UINT64 Value 384 ) 385 { 386 UINT32 Index; 387 388 for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) { 389 if (OrAnd) { 390 mSmmAccess.SmramDesc[Index].RegionState |= Value; 391 } else { 392 mSmmAccess.SmramDesc[Index].RegionState &= Value; 393 } 394 } 395 } 396