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