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