]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
MdeModulePkg RamDiskDxe: Fix incorrect RAM disk memory address calculation
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / RamDiskDxe / RamDiskProtocol.c
CommitLineData
20752cb8
HW
1/** @file\r
2 The realization of EFI_RAM_DISK_PROTOCOL.\r
3\r
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5eae4ff0 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
20752cb8
HW
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "RamDiskImpl.h"\r
17\r
18RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {\r
19 RAM_DISK_PRIVATE_DATA_SIGNATURE,\r
20 NULL\r
21};\r
22\r
23MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {\r
24 {\r
25 MEDIA_DEVICE_PATH,\r
26 MEDIA_RAM_DISK_DP,\r
27 {\r
28 (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),\r
29 (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)\r
30 }\r
31 }\r
32};\r
33\r
34\r
35/**\r
36 Initialize the RAM disk device node.\r
37\r
38 @param[in] PrivateData Points to RAM disk private data.\r
39 @param[in, out] RamDiskDevNode Points to the RAM disk device node.\r
40\r
41**/\r
42VOID\r
43RamDiskInitDeviceNode (\r
44 IN RAM_DISK_PRIVATE_DATA *PrivateData,\r
45 IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode\r
46 )\r
47{\r
48 WriteUnaligned64 (\r
49 (UINT64 *) &(RamDiskDevNode->StartingAddr[0]),\r
50 (UINT64) PrivateData->StartingAddr\r
51 );\r
52 WriteUnaligned64 (\r
53 (UINT64 *) &(RamDiskDevNode->EndingAddr[0]),\r
5eae4ff0 54 (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1\r
20752cb8
HW
55 );\r
56 CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);\r
57 RamDiskDevNode->Instance = PrivateData->InstanceNumber;\r
58}\r
59\r
60\r
61/**\r
62 Register a RAM disk with specified address, size and type.\r
63\r
64 @param[in] RamDiskBase The base address of registered RAM disk.\r
65 @param[in] RamDiskSize The size of registered RAM disk.\r
66 @param[in] RamDiskType The type of registered RAM disk. The GUID can be\r
67 any of the values defined in section 9.3.6.9, or a\r
68 vendor defined GUID.\r
69 @param[in] ParentDevicePath\r
70 Pointer to the parent device path. If there is no\r
71 parent device path then ParentDevicePath is NULL.\r
72 @param[out] DevicePath On return, points to a pointer to the device path\r
73 of the RAM disk device.\r
74 If ParentDevicePath is not NULL, the returned\r
75 DevicePath is created by appending a RAM disk node\r
76 to the parent device path. If ParentDevicePath is\r
77 NULL, the returned DevicePath is a RAM disk device\r
78 path without appending. This function is\r
79 responsible for allocating the buffer DevicePath\r
80 with the boot service AllocatePool().\r
81\r
82 @retval EFI_SUCCESS The RAM disk is registered successfully.\r
83 @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.\r
84 RamDiskSize is 0.\r
85 @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created\r
86 is already present in the handle database.\r
87 @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to\r
88 resource limitation.\r
89\r
90**/\r
91EFI_STATUS\r
92EFIAPI\r
93RamDiskRegister (\r
94 IN UINT64 RamDiskBase,\r
95 IN UINT64 RamDiskSize,\r
96 IN EFI_GUID *RamDiskType,\r
97 IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,\r
98 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
99 )\r
100{\r
101 EFI_STATUS Status;\r
102 RAM_DISK_PRIVATE_DATA *PrivateData;\r
103 RAM_DISK_PRIVATE_DATA *RegisteredPrivateData;\r
104 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;\r
105 UINTN DevicePathSize;\r
106 LIST_ENTRY *Entry;\r
20752cb8
HW
107\r
108 if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {\r
109 return EFI_INVALID_PARAMETER;\r
110 }\r
111\r
112 //\r
113 // Add check to prevent data read across the memory boundary\r
114 //\r
115 if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) {\r
116 return EFI_INVALID_PARAMETER;\r
117 }\r
118\r
119 RamDiskDevNode = NULL;\r
120\r
121 //\r
122 // Create a new RAM disk instance and initialize its private data\r
123 //\r
124 PrivateData = AllocateCopyPool (\r
125 sizeof (RAM_DISK_PRIVATE_DATA),\r
126 &mRamDiskPrivateDataTemplate\r
127 );\r
128 if (NULL == PrivateData) {\r
129 return EFI_OUT_OF_RESOURCES;\r
130 }\r
131\r
132 PrivateData->StartingAddr = RamDiskBase;\r
133 PrivateData->Size = RamDiskSize;\r
134 CopyGuid (&PrivateData->TypeGuid, RamDiskType);\r
135 InitializeListHead (&PrivateData->ThisInstance);\r
136\r
137 //\r
138 // Generate device path information for the registered RAM disk\r
139 //\r
140 RamDiskDevNode = AllocateCopyPool (\r
141 sizeof (MEDIA_RAM_DISK_DEVICE_PATH),\r
142 &mRamDiskDeviceNodeTemplate\r
143 );\r
144 if (NULL == RamDiskDevNode) {\r
145 Status = EFI_OUT_OF_RESOURCES;\r
146 goto ErrorExit;\r
147 }\r
148\r
149 RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);\r
150\r
151 *DevicePath = AppendDevicePathNode (\r
152 ParentDevicePath,\r
153 (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode\r
154 );\r
155 if (NULL == *DevicePath) {\r
156 Status = EFI_OUT_OF_RESOURCES;\r
157 goto ErrorExit;\r
158 }\r
159\r
160 PrivateData->DevicePath = *DevicePath;\r
161\r
162 //\r
163 // Check whether the created device path is already present in the handle\r
164 // database\r
165 //\r
20752cb8
HW
166 if (!IsListEmpty(&RegisteredRamDisks)) {\r
167 DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);\r
168\r
169 EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {\r
170 RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
171 if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {\r
172 //\r
173 // Compare device path\r
174 //\r
175 if ((CompareMem (\r
176 PrivateData->DevicePath,\r
177 RegisteredPrivateData->DevicePath,\r
178 DevicePathSize)) == 0) {\r
179 *DevicePath = NULL;\r
180 Status = EFI_ALREADY_STARTED;\r
181 goto ErrorExit;\r
182 }\r
183 }\r
184 }\r
185 }\r
20752cb8
HW
186\r
187 //\r
188 // Fill Block IO protocol informations for the RAM disk\r
189 //\r
190 RamDiskInitBlockIo (PrivateData);\r
191\r
192 //\r
216fefa3 193 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new\r
20752cb8
HW
194 // handle\r
195 //\r
196 Status = gBS->InstallMultipleProtocolInterfaces (\r
197 &PrivateData->Handle,\r
198 &gEfiBlockIoProtocolGuid,\r
199 &PrivateData->BlockIo,\r
216fefa3
HW
200 &gEfiBlockIo2ProtocolGuid,\r
201 &PrivateData->BlockIo2,\r
20752cb8
HW
202 &gEfiDevicePathProtocolGuid,\r
203 PrivateData->DevicePath,\r
204 NULL\r
205 );\r
206 if (EFI_ERROR (Status)) {\r
207 goto ErrorExit;\r
208 }\r
209\r
210 //\r
211 // Insert the newly created one to the registered RAM disk list\r
212 //\r
20752cb8
HW
213 InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);\r
214 ListEntryNum++;\r
20752cb8
HW
215\r
216 gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);\r
217\r
218 FreePool (RamDiskDevNode);\r
219\r
220 return EFI_SUCCESS;\r
221\r
222ErrorExit:\r
223 if (RamDiskDevNode != NULL) {\r
224 FreePool (RamDiskDevNode);\r
225 }\r
226\r
227 if (PrivateData != NULL) {\r
228 if (PrivateData->DevicePath) {\r
229 FreePool (PrivateData->DevicePath);\r
230 }\r
231\r
232 FreePool (PrivateData);\r
233 }\r
234\r
235 return Status;\r
236}\r
237\r
238\r
239/**\r
240 Unregister a RAM disk specified by DevicePath.\r
241\r
242 @param[in] DevicePath A pointer to the device path that describes a RAM\r
243 Disk device.\r
244\r
245 @retval EFI_SUCCESS The RAM disk is unregistered successfully.\r
246 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
247 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a\r
248 valid ramdisk device path and not supported\r
249 by the driver.\r
250 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't\r
251 exist.\r
252\r
253**/\r
254EFI_STATUS\r
255EFIAPI\r
256RamDiskUnregister (\r
257 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
258 )\r
259{\r
260 LIST_ENTRY *Entry;\r
261 LIST_ENTRY *NextEntry;\r
262 BOOLEAN Found;\r
263 UINT64 StartingAddr;\r
264 UINT64 EndingAddr;\r
265 EFI_DEVICE_PATH_PROTOCOL *Header;\r
266 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;\r
267 RAM_DISK_PRIVATE_DATA *PrivateData;\r
20752cb8
HW
268\r
269 if (NULL == DevicePath) {\r
270 return EFI_INVALID_PARAMETER;\r
271 }\r
272\r
273 //\r
274 // Locate the RAM disk device node.\r
275 //\r
276 RamDiskDevNode = NULL;\r
277 Header = DevicePath;\r
278 do {\r
279 //\r
280 // Test if the current device node is a RAM disk.\r
281 //\r
282 if ((MEDIA_DEVICE_PATH == Header->Type) &&\r
283 (MEDIA_RAM_DISK_DP == Header->SubType)) {\r
284 RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;\r
285\r
286 break;\r
287 }\r
288\r
289 Header = NextDevicePathNode (Header);\r
290 } while ((Header->Type != END_DEVICE_PATH_TYPE));\r
291\r
292 if (NULL == RamDiskDevNode) {\r
293 return EFI_UNSUPPORTED;\r
294 }\r
295\r
296 Found = FALSE;\r
297 StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));\r
298 EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));\r
299\r
20752cb8
HW
300 if (!IsListEmpty(&RegisteredRamDisks)) {\r
301 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {\r
302 PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);\r
303\r
304 //\r
305 // Unregister the RAM disk given by its starting address, ending address\r
306 // and type guid.\r
307 //\r
308 if ((StartingAddr == PrivateData->StartingAddr) &&\r
5eae4ff0 309 (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&\r
20752cb8
HW
310 (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {\r
311 //\r
216fefa3 312 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL\r
20752cb8
HW
313 //\r
314 gBS->UninstallMultipleProtocolInterfaces (\r
315 PrivateData->Handle,\r
316 &gEfiBlockIoProtocolGuid,\r
317 &PrivateData->BlockIo,\r
216fefa3
HW
318 &gEfiBlockIo2ProtocolGuid,\r
319 &PrivateData->BlockIo2,\r
20752cb8 320 &gEfiDevicePathProtocolGuid,\r
28620e60 321 (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,\r
20752cb8
HW
322 NULL\r
323 );\r
324\r
325 RemoveEntryList (&PrivateData->ThisInstance);\r
326\r
327 if (RamDiskCreateHii == PrivateData->CreateMethod) {\r
328 //\r
329 // If a RAM disk is created within HII, then the RamDiskDxe driver\r
330 // driver is responsible for freeing the allocated memory for the\r
331 // RAM disk.\r
332 //\r
333 FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);\r
334 }\r
335\r
20752cb8
HW
336 FreePool (PrivateData->DevicePath);\r
337 FreePool (PrivateData);\r
338 ListEntryNum--;\r
339 Found = TRUE;\r
340\r
341 break;\r
342 }\r
343 }\r
344 }\r
20752cb8
HW
345\r
346 if (TRUE == Found) {\r
347 return EFI_SUCCESS;\r
348 } else {\r
349 return EFI_NOT_FOUND;\r
350 }\r
351}\r