1 /** @file 2 This is the driver that publishes the SMM Access Ppi 3 instance for the Quark SOC. 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 #include <PiPei.h> 17 #include <Ppi/SmmAccess.h> 18 #include <Guid/SmramMemoryReserve.h> 19 #include <Library/BaseMemoryLib.h> 20 #include <Library/MemoryAllocationLib.h> 21 #include <Library/DebugLib.h> 22 #include <Library/HobLib.h> 23 #include <Library/PciLib.h> 24 #include <Library/PeiServicesLib.h> 25 #include <Library/QNCSmmLib.h> 26 #include <QNCAccess.h> 27 28 #define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \ 29 CR ( \ 30 a, \ 31 SMM_ACCESS_PRIVATE_DATA, \ 32 SmmAccess, \ 33 SMM_ACCESS_PRIVATE_DATA_SIGNATURE \ 34 ) 35 36 #define MAX_CPU_SOCKET 1 37 #define MAX_SMRAM_RANGES 4 38 39 typedef struct { 40 UINTN Signature; 41 EFI_HANDLE Handle; 42 PEI_SMM_ACCESS_PPI SmmAccess; 43 UINTN NumberRegions; 44 EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES]; 45 UINT8 TsegSize; 46 UINT8 MaxBusNumber; 47 UINT8 SocketPopulated[MAX_CPU_SOCKET]; 48 UINT8 SocketBusNum[MAX_CPU_SOCKET]; 49 } SMM_ACCESS_PRIVATE_DATA; 50 51 #define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a') 52 53 54 EFI_STATUS 55 EFIAPI 56 Open ( 57 IN EFI_PEI_SERVICES **PeiServices, 58 IN PEI_SMM_ACCESS_PPI *This, 59 IN UINTN DescriptorIndex 60 ) 61 /*++ 62 63 Routine Description: 64 65 This routine accepts a request to "open" a region of SMRAM. The 66 region could be legacy ABSEG, HSEG, or TSEG near top of physical memory. 67 The use of "open" means that the memory is visible from all PEIM 68 and SMM agents. 69 70 Arguments: 71 72 PeiServices - General purpose services available to every PEIM. 73 This - Pointer to the SMM Access Interface. 74 DescriptorIndex - Region of SMRAM to Open. 75 76 Returns: 77 78 EFI_SUCCESS - The region was successfully opened. 79 EFI_DEVICE_ERROR - The region could not be opened because locked by 80 chipset. 81 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 82 83 --*/ 84 { 85 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 86 87 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 88 89 if (DescriptorIndex >= SmmAccess->NumberRegions) { 90 return EFI_INVALID_PARAMETER; 91 } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) { 92 return EFI_DEVICE_ERROR; 93 } 94 95 // 96 // Open TSEG 97 // 98 if (!QNCOpenSmramRegion ()) { 99 SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED; 100 return EFI_DEVICE_ERROR; 101 } 102 103 SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED); 104 SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN; 105 SmmAccess->SmmAccess.OpenState = TRUE; 106 107 return EFI_SUCCESS; 108 } 109 110 EFI_STATUS 111 EFIAPI 112 Close ( 113 IN EFI_PEI_SERVICES **PeiServices, 114 IN PEI_SMM_ACCESS_PPI *This, 115 IN UINTN DescriptorIndex 116 ) 117 /*++ 118 119 Routine Description: 120 121 This routine accepts a request to "close" a region of SMRAM. This is valid for 122 compatible SMRAM region. 123 124 Arguments: 125 126 PeiServices - General purpose services available to every PEIM. 127 This - Pointer to the SMM Access Interface. 128 DescriptorIndex - Region of SMRAM to Close. 129 130 Returns: 131 132 EFI_SUCCESS - The region was successfully closed. 133 EFI_DEVICE_ERROR - The region could not be closed because locked by 134 chipset. 135 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 136 137 --*/ 138 { 139 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 140 BOOLEAN OpenState; 141 UINTN Index; 142 143 144 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 145 146 if (DescriptorIndex >= SmmAccess->NumberRegions) { 147 return EFI_INVALID_PARAMETER; 148 } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) { 149 return EFI_DEVICE_ERROR; 150 } 151 152 if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) { 153 return EFI_DEVICE_ERROR; 154 } 155 156 // 157 // Close TSEG 158 // 159 if (!QNCCloseSmramRegion ()) { 160 SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED; 161 return EFI_DEVICE_ERROR; 162 } 163 164 SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN; 165 SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED); 166 167 // 168 // Find out if any regions are still open 169 // 170 OpenState = FALSE; 171 for (Index = 0; Index < SmmAccess->NumberRegions; Index++) { 172 if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) { 173 OpenState = TRUE; 174 } 175 } 176 177 SmmAccess->SmmAccess.OpenState = OpenState; 178 179 return EFI_SUCCESS; 180 } 181 182 EFI_STATUS 183 EFIAPI 184 Lock ( 185 IN EFI_PEI_SERVICES **PeiServices, 186 IN PEI_SMM_ACCESS_PPI *This, 187 IN UINTN DescriptorIndex 188 ) 189 /*++ 190 191 Routine Description: 192 193 This routine accepts a request to "lock" SMRAM. The 194 region could be legacy AB or TSEG near top of physical memory. 195 The use of "lock" means that the memory can no longer be opened 196 to PEIM. 197 198 Arguments: 199 200 PeiServices - General purpose services available to every PEIM. 201 This - Pointer to the SMM Access Interface. 202 DescriptorIndex - Region of SMRAM to Lock. 203 204 Returns: 205 206 EFI_SUCCESS - The region was successfully locked. 207 EFI_DEVICE_ERROR - The region could not be locked because at least 208 one range is still open. 209 EFI_INVALID_PARAMETER - The descriptor index was out of bounds. 210 211 --*/ 212 { 213 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 214 215 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 216 217 if (DescriptorIndex >= SmmAccess->NumberRegions) { 218 return EFI_INVALID_PARAMETER; 219 } else if (SmmAccess->SmmAccess.OpenState) { 220 return EFI_DEVICE_ERROR; 221 } 222 223 SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED; 224 SmmAccess->SmmAccess.LockState = TRUE; 225 226 // 227 // Lock TSEG 228 // 229 QNCLockSmramRegion (); 230 231 return EFI_SUCCESS; 232 } 233 234 EFI_STATUS 235 EFIAPI 236 GetCapabilities ( 237 IN EFI_PEI_SERVICES **PeiServices, 238 IN PEI_SMM_ACCESS_PPI *This, 239 IN OUT UINTN *SmramMapSize, 240 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap 241 ) 242 /*++ 243 244 Routine Description: 245 246 This routine services a user request to discover the SMRAM 247 capabilities of this platform. This will report the possible 248 ranges that are possible for SMRAM access, based upon the 249 memory controller capabilities. 250 251 Arguments: 252 253 PeiServices - General purpose services available to every PEIM. 254 This - Pointer to the SMRAM Access Interface. 255 SmramMapSize - Pointer to the variable containing size of the 256 buffer to contain the description information. 257 SmramMap - Buffer containing the data describing the Smram 258 region descriptors. 259 Returns: 260 261 EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer. 262 EFI_SUCCESS - The user provided a sufficiently-sized buffer. 263 264 --*/ 265 { 266 EFI_STATUS Status; 267 SMM_ACCESS_PRIVATE_DATA *SmmAccess; 268 UINTN BufferSize; 269 270 SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This); 271 BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR); 272 273 if (*SmramMapSize < BufferSize) { 274 Status = EFI_BUFFER_TOO_SMALL; 275 } else { 276 CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize); 277 Status = EFI_SUCCESS; 278 } 279 280 *SmramMapSize = BufferSize; 281 282 return Status; 283 } 284 285 286 EFI_STATUS 287 EFIAPI 288 SmmAccessPeiEntryPoint ( 289 IN EFI_PEI_FILE_HANDLE FileHandle, 290 IN CONST EFI_PEI_SERVICES **PeiServices 291 ) 292 /*++ 293 294 Routine Description: 295 296 This is the constructor for the SMM Access Ppi 297 298 Arguments: 299 300 FfsHeader - FfsHeader. 301 PeiServices - General purpose services available to every PEIM. 302 303 Returns: 304 305 EFI_SUCCESS - Protocol successfully started and installed. 306 EFI_UNSUPPORTED - Protocol can't be started. 307 --*/ 308 { 309 310 EFI_STATUS Status; 311 UINTN Index; 312 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; 313 SMM_ACCESS_PRIVATE_DATA *SmmAccessPrivate; 314 EFI_PEI_PPI_DESCRIPTOR *PpiList; 315 EFI_HOB_GUID_TYPE *GuidHob; 316 317 // 318 // Initialize private data 319 // 320 SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate)); 321 ASSERT(SmmAccessPrivate); 322 323 PpiList = AllocatePool (sizeof(*PpiList)); 324 ASSERT (PpiList); 325 326 // 327 // Build SMM related information 328 // 329 SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE; 330 331 // 332 // Get Hob list 333 // 334 GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid); 335 DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); 336 ASSERT (DescriptorBlock); 337 338 // Get CPU Max bus number 339 340 SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC; 341 for (Index = 0; Index < MAX_CPU_SOCKET; Index++) { 342 SmmAccessPrivate->SocketPopulated[Index] = TRUE; 343 SmmAccessPrivate->SocketBusNum[Index] = PCI_BUS_NUMBER_QNC; 344 } 345 346 // 347 // Use the hob to publish SMRAM capabilities 348 // 349 ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES); 350 for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) { 351 SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart; 352 SmmAccessPrivate->SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart; 353 SmmAccessPrivate->SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize; 354 SmmAccessPrivate->SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState; 355 } 356 357 SmmAccessPrivate->NumberRegions = Index; 358 SmmAccessPrivate->SmmAccess.Open = Open; 359 SmmAccessPrivate->SmmAccess.Close = Close; 360 SmmAccessPrivate->SmmAccess.Lock = Lock; 361 SmmAccessPrivate->SmmAccess.GetCapabilities = GetCapabilities; 362 SmmAccessPrivate->SmmAccess.LockState = FALSE; 363 SmmAccessPrivate->SmmAccess.OpenState = FALSE; 364 365 PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); 366 PpiList->Guid = &gPeiSmmAccessPpiGuid; 367 PpiList->Ppi = &SmmAccessPrivate->SmmAccess; 368 369 Status = (**PeiServices).InstallPpi (PeiServices, PpiList); 370 ASSERT_EFI_ERROR(Status); 371 372 DEBUG ( 373 (EFI_D_INFO, "SMM Base:Size %08X:%08X\n", 374 (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart), 375 (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize) 376 )); 377 378 SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize); 379 380 return EFI_SUCCESS; 381 } 382 383