]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
MdeModulePkg: Add a check for metadata size in NvmExpress Driver
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / NvmExpressPei.c
CommitLineData
b8b69433
HW
1/** @file\r
2 The NvmExpressPei driver is used to manage non-volatile memory subsystem\r
3 which follows NVM Express specification at PEI phase.\r
4\r
4104423a 5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
b8b69433 6\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
b8b69433
HW
8\r
9**/\r
10\r
11#include "NvmExpressPei.h"\r
12\r
13EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate = {\r
14 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
15 &gEfiPeiVirtualBlockIoPpiGuid,\r
16 NULL\r
17};\r
18\r
19EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate = {\r
2e15b750 20 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
b8b69433
HW
21 &gEfiPeiVirtualBlockIo2PpiGuid,\r
22 NULL\r
23};\r
24\r
2e15b750
HW
25EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate = {\r
26 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
27 &gEdkiiPeiStorageSecurityCommandPpiGuid,\r
28 NULL\r
29};\r
30\r
ba3aa1c4
MC
31EFI_PEI_PPI_DESCRIPTOR mNvmePassThruPpiListTemplate = {\r
32 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
33 &gEdkiiPeiNvmExpressPassThruPpiGuid,\r
34 NULL\r
35};\r
36\r
b8b69433
HW
37EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = {\r
38 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
39 &gEfiEndOfPeiSignalPpiGuid,\r
40 NvmePeimEndOfPei\r
41};\r
42\r
43/**\r
44 Check if the specified Nvm Express device namespace is active, and then get the Identify\r
45 Namespace data.\r
46\r
47 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
48 @param[in] NamespaceId The specified namespace identifier.\r
49\r
50 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.\r
51 @return Others Error occurs when enumerating the namespace.\r
52\r
53**/\r
54EFI_STATUS\r
55EnumerateNvmeDevNamespace (\r
1436aea4
MK
56 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
57 IN UINT32 NamespaceId\r
b8b69433
HW
58 )\r
59{\r
1436aea4
MK
60 EFI_STATUS Status;\r
61 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
62 PEI_NVME_NAMESPACE_INFO *NamespaceInfo;\r
63 UINT32 DeviceIndex;\r
64 UINT32 Lbads;\r
65 UINT32 Flbas;\r
66 UINT32 LbaFmtIdx;\r
67\r
68 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
b8b69433
HW
69 if (NamespaceData == NULL) {\r
70 return EFI_OUT_OF_RESOURCES;\r
71 }\r
72\r
73 //\r
74 // Identify Namespace\r
75 //\r
76 Status = NvmeIdentifyNamespace (\r
77 Private,\r
78 NamespaceId,\r
79 NamespaceData\r
80 );\r
81 if (EFI_ERROR (Status)) {\r
82 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));\r
83 goto Exit;\r
84 }\r
85\r
86 //\r
87 // Validate Namespace\r
88 //\r
89 if (NamespaceData->Ncap == 0) {\r
90 DEBUG ((DEBUG_INFO, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__, NamespaceId));\r
91 Status = EFI_DEVICE_ERROR;\r
92 goto Exit;\r
93 }\r
94\r
1436aea4
MK
95 DeviceIndex = Private->ActiveNamespaceNum;\r
96 NamespaceInfo = &Private->NamespaceInfo[DeviceIndex];\r
b8b69433
HW
97 NamespaceInfo->NamespaceId = NamespaceId;\r
98 NamespaceInfo->NamespaceUuid = NamespaceData->Eui64;\r
99 NamespaceInfo->Controller = Private;\r
100 Private->ActiveNamespaceNum++;\r
101\r
102 //\r
103 // Build BlockIo media structure\r
104 //\r
105 Flbas = NamespaceData->Flbas;\r
106 LbaFmtIdx = Flbas & 0xF;\r
79f2734e
MH
107\r
108 //\r
109 // Currently this NVME driver only suport Metadata Size == 0\r
110 //\r
111 if (NamespaceData->LbaFormat[LbaFmtIdx].Ms != 0) {\r
112 DEBUG ((\r
113 DEBUG_ERROR,\r
114 "NVME IDENTIFY NAMESPACE [%d] Ms(%d) is not supported.\n",\r
115 NamespaceId,\r
116 NamespaceData->LbaFormat[LbaFmtIdx].Ms\r
117 ));\r
118 Status = EFI_UNSUPPORTED;\r
119 goto Exit;\r
120 }\r
121\r
122 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
b8b69433
HW
123\r
124 NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP;\r
125 NamespaceInfo->Media.RemovableMedia = FALSE;\r
126 NamespaceInfo->Media.MediaPresent = TRUE;\r
127 NamespaceInfo->Media.ReadOnly = FALSE;\r
1436aea4
MK
128 NamespaceInfo->Media.BlockSize = (UINT32)1 << Lbads;\r
129 NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA)NamespaceData->Nsze - 1;\r
b8b69433
HW
130 DEBUG ((\r
131 DEBUG_INFO,\r
132 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",\r
133 __FUNCTION__,\r
134 NamespaceId,\r
135 NamespaceInfo->Media.BlockSize,\r
136 NamespaceInfo->Media.LastBlock\r
137 ));\r
138\r
139Exit:\r
140 if (NamespaceData != NULL) {\r
141 FreePool (NamespaceData);\r
142 }\r
143\r
144 return Status;\r
145}\r
146\r
147/**\r
148 Discover all Nvm Express device active namespaces.\r
149\r
150 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
151\r
152 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
153 @return EFI_NOT_FOUND No active namespaces can be found.\r
154\r
155**/\r
156EFI_STATUS\r
157NvmeDiscoverNamespaces (\r
1436aea4 158 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
b8b69433
HW
159 )\r
160{\r
1436aea4 161 UINT32 NamespaceId;\r
b8b69433
HW
162\r
163 Private->ActiveNamespaceNum = 0;\r
164 Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));\r
165\r
166 //\r
167 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify\r
168 // controller data defines the number of valid namespaces present for the\r
169 // controller. Namespaces shall be allocated in order (starting with 1) and\r
170 // packed sequentially.\r
171 //\r
172 for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {\r
173 //\r
174 // For now, we do not care the return status. Since if a valid namespace is inactive,\r
175 // error status will be returned. But we continue to enumerate other valid namespaces.\r
176 //\r
177 EnumerateNvmeDevNamespace (Private, NamespaceId);\r
178 }\r
1436aea4 179\r
b8b69433
HW
180 if (Private->ActiveNamespaceNum == 0) {\r
181 return EFI_NOT_FOUND;\r
182 }\r
183\r
184 return EFI_SUCCESS;\r
185}\r
186\r
187/**\r
188 One notified function to cleanup the allocated resources at the end of PEI.\r
189\r
190 @param[in] PeiServices Pointer to PEI Services Table.\r
191 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
192 event that caused this function to execute.\r
193 @param[in] Ppi Pointer to the PPI data associated with this function.\r
194\r
195 @retval EFI_SUCCESS The function completes successfully\r
196\r
197**/\r
198EFI_STATUS\r
199EFIAPI\r
200NvmePeimEndOfPei (\r
201 IN EFI_PEI_SERVICES **PeiServices,\r
202 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
203 IN VOID *Ppi\r
204 )\r
205{\r
1436aea4 206 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
b8b69433
HW
207\r
208 Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);\r
2e15b750 209 NvmeFreeDmaResource (Private);\r
b8b69433
HW
210\r
211 return EFI_SUCCESS;\r
212}\r
213\r
214/**\r
215 Entry point of the PEIM.\r
216\r
217 @param[in] FileHandle Handle of the file being invoked.\r
218 @param[in] PeiServices Describes the list of possible PEI Services.\r
219\r
220 @retval EFI_SUCCESS PPI successfully installed.\r
221\r
222**/\r
223EFI_STATUS\r
224EFIAPI\r
225NvmExpressPeimEntry (\r
1436aea4
MK
226 IN EFI_PEI_FILE_HANDLE FileHandle,\r
227 IN CONST EFI_PEI_SERVICES **PeiServices\r
b8b69433
HW
228 )\r
229{\r
1436aea4
MK
230 EFI_STATUS Status;\r
231 EFI_BOOT_MODE BootMode;\r
232 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;\r
233 UINT8 Controller;\r
234 UINTN MmioBase;\r
235 UINTN DevicePathLength;\r
236 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
237 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
238 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
b8b69433 239\r
2e15b750
HW
240 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
241\r
05fd2a92
HW
242 //\r
243 // Get the current boot mode.\r
244 //\r
245 Status = PeiServicesGetBootMode (&BootMode);\r
246 if (EFI_ERROR (Status)) {\r
247 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));\r
248 return Status;\r
249 }\r
250\r
b8b69433
HW
251 //\r
252 // Locate the NVME host controller PPI\r
253 //\r
254 Status = PeiServicesLocatePpi (\r
255 &gEdkiiPeiNvmExpressHostControllerPpiGuid,\r
256 0,\r
257 NULL,\r
1436aea4 258 (VOID **)&NvmeHcPpi\r
b8b69433
HW
259 );\r
260 if (EFI_ERROR (Status)) {\r
261 DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__));\r
262 return EFI_UNSUPPORTED;\r
263 }\r
264\r
b8b69433
HW
265 Controller = 0;\r
266 MmioBase = 0;\r
267 while (TRUE) {\r
268 Status = NvmeHcPpi->GetNvmeHcMmioBar (\r
269 NvmeHcPpi,\r
270 Controller,\r
271 &MmioBase\r
272 );\r
273 //\r
274 // When status is error, meant no controller is found\r
275 //\r
276 if (EFI_ERROR (Status)) {\r
277 break;\r
278 }\r
279\r
2e15b750
HW
280 Status = NvmeHcPpi->GetNvmeHcDevicePath (\r
281 NvmeHcPpi,\r
282 Controller,\r
283 &DevicePathLength,\r
284 &DevicePath\r
285 );\r
286 if (EFI_ERROR (Status)) {\r
287 DEBUG ((\r
1436aea4
MK
288 DEBUG_ERROR,\r
289 "%a: Fail to allocate get the device path for Controller %d.\n",\r
290 __FUNCTION__,\r
291 Controller\r
2e15b750
HW
292 ));\r
293 return Status;\r
294 }\r
295\r
296 //\r
297 // Check validity of the device path of the NVM Express controller.\r
298 //\r
299 Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);\r
300 if (EFI_ERROR (Status)) {\r
301 DEBUG ((\r
1436aea4
MK
302 DEBUG_ERROR,\r
303 "%a: The device path is invalid for Controller %d.\n",\r
304 __FUNCTION__,\r
305 Controller\r
2e15b750
HW
306 ));\r
307 Controller++;\r
308 continue;\r
309 }\r
310\r
05fd2a92
HW
311 //\r
312 // For S3 resume performance consideration, not all NVM Express controllers\r
313 // will be initialized. The driver consumes the content within\r
314 // S3StorageDeviceInitList LockBox to see if a controller will be skipped\r
315 // during S3 resume.\r
316 //\r
317 if ((BootMode == BOOT_ON_S3_RESUME) &&\r
1436aea4
MK
318 (NvmeS3SkipThisController (DevicePath, DevicePathLength)))\r
319 {\r
05fd2a92 320 DEBUG ((\r
1436aea4
MK
321 DEBUG_ERROR,\r
322 "%a: Controller %d is skipped during S3.\n",\r
323 __FUNCTION__,\r
324 Controller\r
05fd2a92
HW
325 ));\r
326 Controller++;\r
327 continue;\r
328 }\r
329\r
b8b69433
HW
330 //\r
331 // Memory allocation for controller private data\r
332 //\r
333 Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));\r
334 if (Private == NULL) {\r
335 DEBUG ((\r
1436aea4
MK
336 DEBUG_ERROR,\r
337 "%a: Fail to allocate private data for Controller %d.\n",\r
338 __FUNCTION__,\r
339 Controller\r
b8b69433
HW
340 ));\r
341 return EFI_OUT_OF_RESOURCES;\r
342 }\r
343\r
344 //\r
345 // Memory allocation for transfer-related data\r
346 //\r
347 Status = IoMmuAllocateBuffer (\r
348 NVME_MEM_MAX_PAGES,\r
349 &Private->Buffer,\r
350 &DeviceAddress,\r
351 &Private->BufferMapping\r
352 );\r
353 if (EFI_ERROR (Status)) {\r
354 DEBUG ((\r
1436aea4
MK
355 DEBUG_ERROR,\r
356 "%a: Fail to allocate DMA buffers for Controller %d.\n",\r
357 __FUNCTION__,\r
358 Controller\r
b8b69433 359 ));\r
b8b69433
HW
360 return Status;\r
361 }\r
1436aea4
MK
362\r
363 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS)(UINTN)Private->Buffer));\r
b8b69433
HW
364 DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));\r
365\r
366 //\r
367 // Initialize controller private data\r
368 //\r
2e15b750
HW
369 Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
370 Private->MmioBase = MmioBase;\r
371 Private->DevicePathLength = DevicePathLength;\r
372 Private->DevicePath = DevicePath;\r
b8b69433
HW
373\r
374 //\r
375 // Initialize the NVME controller\r
376 //\r
377 Status = NvmeControllerInit (Private);\r
378 if (EFI_ERROR (Status)) {\r
379 DEBUG ((\r
380 DEBUG_ERROR,\r
381 "%a: Controller initialization fail for Controller %d with Status - %r.\n",\r
1436aea4
MK
382 __FUNCTION__,\r
383 Controller,\r
384 Status\r
b8b69433 385 ));\r
2e15b750 386 NvmeFreeDmaResource (Private);\r
b8b69433
HW
387 Controller++;\r
388 continue;\r
389 }\r
390\r
391 //\r
392 // Enumerate the NVME namespaces on the controller\r
393 //\r
394 Status = NvmeDiscoverNamespaces (Private);\r
395 if (EFI_ERROR (Status)) {\r
396 //\r
397 // No active namespace was found on the controller\r
398 //\r
399 DEBUG ((\r
400 DEBUG_ERROR,\r
401 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",\r
1436aea4
MK
402 __FUNCTION__,\r
403 Controller,\r
404 Status\r
b8b69433 405 ));\r
2e15b750 406 NvmeFreeDmaResource (Private);\r
b8b69433
HW
407 Controller++;\r
408 continue;\r
409 }\r
410\r
dc254af6
MC
411 //\r
412 // Nvm Express Pass Thru PPI\r
413 //\r
1436aea4
MK
414 Private->PassThruMode.Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
415 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |\r
416 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM;\r
417 Private->PassThruMode.IoAlign = sizeof (UINTN);\r
418 Private->PassThruMode.NvmeVersion = EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI_REVISION;\r
419 Private->NvmePassThruPpi.Mode = &Private->PassThruMode;\r
420 Private->NvmePassThruPpi.GetDevicePath = NvmePassThruGetDevicePath;\r
421 Private->NvmePassThruPpi.GetNextNameSpace = NvmePassThruGetNextNameSpace;\r
422 Private->NvmePassThruPpi.PassThru = NvmePassThru;\r
dc254af6
MC
423 CopyMem (\r
424 &Private->NvmePassThruPpiList,\r
425 &mNvmePassThruPpiListTemplate,\r
426 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
427 );\r
1436aea4 428 Private->NvmePassThruPpiList.Ppi = &Private->NvmePassThruPpi;\r
dc254af6
MC
429 PeiServicesInstallPpi (&Private->NvmePassThruPpiList);\r
430\r
431 //\r
432 // Block Io PPI\r
433 //\r
1436aea4
MK
434 Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;\r
435 Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;\r
436 Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;\r
2e15b750
HW
437 CopyMem (\r
438 &Private->BlkIoPpiList,\r
439 &mNvmeBlkIoPpiListTemplate,\r
440 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
441 );\r
1436aea4 442 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;\r
2e15b750
HW
443\r
444 Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;\r
445 Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;\r
446 Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;\r
447 Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2;\r
448 CopyMem (\r
449 &Private->BlkIo2PpiList,\r
450 &mNvmeBlkIo2PpiListTemplate,\r
451 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
452 );\r
1436aea4 453 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;\r
b8b69433 454 PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
2e15b750
HW
455\r
456 //\r
457 // Check if the NVME controller supports the Security Receive/Send commands\r
458 //\r
459 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
460 DEBUG ((\r
461 DEBUG_INFO,\r
462 "%a: Security Security Command PPI will be produced for Controller %d.\n",\r
1436aea4
MK
463 __FUNCTION__,\r
464 Controller\r
2e15b750
HW
465 ));\r
466 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;\r
467 Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;\r
468 Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath;\r
469 Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData;\r
470 Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData;\r
471 CopyMem (\r
472 &Private->StorageSecurityPpiList,\r
473 &mNvmeStorageSecurityPpiListTemplate,\r
474 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
475 );\r
1436aea4 476 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;\r
2e15b750
HW
477 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);\r
478 }\r
479\r
480 CopyMem (\r
481 &Private->EndOfPeiNotifyList,\r
482 &mNvmeEndOfPeiNotifyListTemplate,\r
483 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)\r
484 );\r
1436aea4 485 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);\r
2e15b750 486\r
b8b69433 487 DEBUG ((\r
1436aea4
MK
488 DEBUG_INFO,\r
489 "%a: Controller %d has been successfully initialized.\n",\r
490 __FUNCTION__,\r
491 Controller\r
b8b69433
HW
492 ));\r
493 Controller++;\r
494 }\r
495\r
496 return EFI_SUCCESS;\r
497}\r