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