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