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