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