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