]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
ff95f20329e74aa8c0e7aee3345be793cd7b2567
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / DevicePath.c
1 /** @file
2 The device path help function.
3
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 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 "NvmExpressPei.h"
18
19 //
20 // Template for an Nvm Express Device Path node
21 //
22 NVME_NAMESPACE_DEVICE_PATH mNvmeDevicePathNodeTemplate = {
23 { // Header
24 MESSAGING_DEVICE_PATH,
25 MSG_NVME_NAMESPACE_DP,
26 {
27 (UINT8) (sizeof (NVME_NAMESPACE_DEVICE_PATH)),
28 (UINT8) ((sizeof (NVME_NAMESPACE_DEVICE_PATH)) >> 8)
29 }
30 },
31 0x0, // NamespaceId
32 0x0 // NamespaceUuid
33 };
34
35 //
36 // Template for an End of entire Device Path node
37 //
38 EFI_DEVICE_PATH_PROTOCOL mNvmeEndDevicePathNodeTemplate = {
39 END_DEVICE_PATH_TYPE,
40 END_ENTIRE_DEVICE_PATH_SUBTYPE,
41 {
42 (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
43 (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
44 }
45 };
46
47 /**
48 Returns the 16-bit Length field of a device path node.
49
50 Returns the 16-bit Length field of the device path node specified by Node.
51 Node is not required to be aligned on a 16-bit boundary, so it is recommended
52 that a function such as ReadUnaligned16() be used to extract the contents of
53 the Length field.
54
55 If Node is NULL, then ASSERT().
56
57 @param Node A pointer to a device path node data structure.
58
59 @return The 16-bit Length field of the device path node specified by Node.
60
61 **/
62 UINTN
63 DevicePathNodeLength (
64 IN CONST VOID *Node
65 )
66 {
67 ASSERT (Node != NULL);
68 return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
69 }
70
71 /**
72 Returns a pointer to the next node in a device path.
73
74 If Node is NULL, then ASSERT().
75
76 @param Node A pointer to a device path node data structure.
77
78 @return a pointer to the device path node that follows the device path node
79 specified by Node.
80
81 **/
82 EFI_DEVICE_PATH_PROTOCOL *
83 NextDevicePathNode (
84 IN CONST VOID *Node
85 )
86 {
87 ASSERT (Node != NULL);
88 return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));
89 }
90
91 /**
92 Get the size of the current device path instance.
93
94 @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
95 structure.
96 @param[out] InstanceSize The size of the current device path instance.
97 @param[out] EntireDevicePathEnd Indicate whether the instance is the last
98 one in the device path strucure.
99
100 @retval EFI_SUCCESS The size of the current device path instance is fetched.
101 @retval Others Fails to get the size of the current device path instance.
102
103 **/
104 EFI_STATUS
105 GetDevicePathInstanceSize (
106 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
107 OUT UINTN *InstanceSize,
108 OUT BOOLEAN *EntireDevicePathEnd
109 )
110 {
111 EFI_DEVICE_PATH_PROTOCOL *Walker;
112
113 if (DevicePath == NULL || InstanceSize == NULL || EntireDevicePathEnd == NULL) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117 //
118 // Find the end of the device path instance
119 //
120 Walker = DevicePath;
121 while (Walker->Type != END_DEVICE_PATH_TYPE) {
122 Walker = NextDevicePathNode (Walker);
123 }
124
125 //
126 // Check if 'Walker' points to the end of an entire device path
127 //
128 if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
129 *EntireDevicePathEnd = TRUE;
130 } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
131 *EntireDevicePathEnd = FALSE;
132 } else {
133 return EFI_INVALID_PARAMETER;
134 }
135
136 //
137 // Compute the size of the device path instance
138 //
139 *InstanceSize = ((UINTN) Walker - (UINTN) (DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
140
141 return EFI_SUCCESS;
142 }
143
144 /**
145 Check the validity of the device path of a NVM Express host controller.
146
147 @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL
148 structure.
149 @param[in] DevicePathLength The length of the device path.
150
151 @retval EFI_SUCCESS The device path is valid.
152 @retval EFI_INVALID_PARAMETER The device path is invalid.
153
154 **/
155 EFI_STATUS
156 NvmeIsHcDevicePathValid (
157 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
158 IN UINTN DevicePathLength
159 )
160 {
161 EFI_DEVICE_PATH_PROTOCOL *Start;
162 UINTN Size;
163
164 if (DevicePath == NULL) {
165 return EFI_INVALID_PARAMETER;
166 }
167
168 //
169 // Validate the DevicePathLength is big enough to touch the first node.
170 //
171 if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
172 return EFI_INVALID_PARAMETER;
173 }
174
175 Start = DevicePath;
176 while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&
177 DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {
178 DevicePath = NextDevicePathNode (DevicePath);
179
180 //
181 // Prevent overflow and invalid zero in the 'Length' field of a device path
182 // node.
183 //
184 if ((UINTN) DevicePath <= (UINTN) Start) {
185 return EFI_INVALID_PARAMETER;
186 }
187
188 //
189 // Prevent touching memory beyond given DevicePathLength.
190 //
191 if ((UINTN) DevicePath - (UINTN) Start >
192 DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
193 return EFI_INVALID_PARAMETER;
194 }
195 }
196
197 //
198 // Check if the device path and its size match exactly with each other.
199 //
200 Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
201 if (Size != DevicePathLength) {
202 return EFI_INVALID_PARAMETER;
203 }
204
205 return EFI_SUCCESS;
206 }
207
208 /**
209 Build the device path for an Nvm Express device with given namespace identifier
210 and namespace extended unique identifier.
211
212 @param[in] Private A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA
213 data structure.
214 @param[in] NamespaceId The given namespace identifier.
215 @param[in] NamespaceUuid The given namespace extended unique identifier.
216 @param[out] DevicePathLength The length of the device path in bytes specified
217 by DevicePath.
218 @param[out] DevicePath The device path of Nvm Express device.
219
220 @retval EFI_SUCCESS The operation succeeds.
221 @retval EFI_INVALID_PARAMETER The parameters are invalid.
222 @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
223
224 **/
225 EFI_STATUS
226 NvmeBuildDevicePath (
227 IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,
228 IN UINT32 NamespaceId,
229 IN UINT64 NamespaceUuid,
230 OUT UINTN *DevicePathLength,
231 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
232 )
233 {
234 EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
235 NVME_NAMESPACE_DEVICE_PATH *NvmeDeviceNode;
236
237 if (DevicePathLength == NULL || DevicePath == NULL) {
238 return EFI_INVALID_PARAMETER;
239 }
240
241 *DevicePathLength = Private->DevicePathLength + sizeof (NVME_NAMESPACE_DEVICE_PATH);
242 *DevicePath = AllocatePool (*DevicePathLength);
243 if (*DevicePath == NULL) {
244 *DevicePathLength = 0;
245 return EFI_OUT_OF_RESOURCES;
246 }
247
248 //
249 // Construct the host controller part device nodes
250 //
251 DevicePathWalker = *DevicePath;
252 CopyMem (
253 DevicePathWalker,
254 Private->DevicePath,
255 Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)
256 );
257
258 //
259 // Construct the Nvm Express device node
260 //
261 DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
262 (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
263 CopyMem (
264 DevicePathWalker,
265 &mNvmeDevicePathNodeTemplate,
266 sizeof (mNvmeDevicePathNodeTemplate)
267 );
268 NvmeDeviceNode = (NVME_NAMESPACE_DEVICE_PATH *)DevicePathWalker;
269 NvmeDeviceNode->NamespaceId = NamespaceId;
270 NvmeDeviceNode->NamespaceUuid = NamespaceUuid;
271
272 //
273 // Construct the end device node
274 //
275 DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +
276 sizeof (NVME_NAMESPACE_DEVICE_PATH));
277 CopyMem (
278 DevicePathWalker,
279 &mNvmeEndDevicePathNodeTemplate,
280 sizeof (mNvmeEndDevicePathNodeTemplate)
281 );
282
283 return EFI_SUCCESS;
284 }