2 The realization of EFI_RAM_DISK_PROTOCOL.
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
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.
15 #include "RamDiskImpl.h"
17 RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate
= {
18 RAM_DISK_PRIVATE_DATA_SIGNATURE
,
22 MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate
= {
27 (UINT8
) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH
)),
28 (UINT8
) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH
)) >> 8)
35 Initialize the RAM disk device node.
37 @param[in] PrivateData Points to RAM disk private data.
38 @param[in, out] RamDiskDevNode Points to the RAM disk device node.
42 RamDiskInitDeviceNode (
43 IN RAM_DISK_PRIVATE_DATA
*PrivateData
,
44 IN OUT MEDIA_RAM_DISK_DEVICE_PATH
*RamDiskDevNode
48 (UINT64
*) &(RamDiskDevNode
->StartingAddr
[0]),
49 (UINT64
) PrivateData
->StartingAddr
52 (UINT64
*) &(RamDiskDevNode
->EndingAddr
[0]),
53 (UINT64
) PrivateData
->StartingAddr
+ PrivateData
->Size
55 CopyGuid (&RamDiskDevNode
->TypeGuid
, &PrivateData
->TypeGuid
);
56 RamDiskDevNode
->Instance
= PrivateData
->InstanceNumber
;
61 Register a RAM disk with specified address, size and type.
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
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().
81 @retval EFI_SUCCESS The RAM disk is registered successfully.
82 @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
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
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
101 RAM_DISK_PRIVATE_DATA
*PrivateData
;
102 RAM_DISK_PRIVATE_DATA
*RegisteredPrivateData
;
103 MEDIA_RAM_DISK_DEVICE_PATH
*RamDiskDevNode
;
104 UINTN DevicePathSize
;
107 if ((0 == RamDiskSize
) || (NULL
== RamDiskType
) || (NULL
== DevicePath
)) {
108 return EFI_INVALID_PARAMETER
;
112 // Add check to prevent data read across the memory boundary
114 if (RamDiskBase
+ RamDiskSize
> ((UINTN
) -1) - RAM_DISK_BLOCK_SIZE
+ 1) {
115 return EFI_INVALID_PARAMETER
;
118 RamDiskDevNode
= NULL
;
121 // Create a new RAM disk instance and initialize its private data
123 PrivateData
= AllocateCopyPool (
124 sizeof (RAM_DISK_PRIVATE_DATA
),
125 &mRamDiskPrivateDataTemplate
127 if (NULL
== PrivateData
) {
128 return EFI_OUT_OF_RESOURCES
;
131 PrivateData
->StartingAddr
= RamDiskBase
;
132 PrivateData
->Size
= RamDiskSize
;
133 CopyGuid (&PrivateData
->TypeGuid
, RamDiskType
);
134 InitializeListHead (&PrivateData
->ThisInstance
);
137 // Generate device path information for the registered RAM disk
139 RamDiskDevNode
= AllocateCopyPool (
140 sizeof (MEDIA_RAM_DISK_DEVICE_PATH
),
141 &mRamDiskDeviceNodeTemplate
143 if (NULL
== RamDiskDevNode
) {
144 Status
= EFI_OUT_OF_RESOURCES
;
148 RamDiskInitDeviceNode (PrivateData
, RamDiskDevNode
);
150 *DevicePath
= AppendDevicePathNode (
152 (EFI_DEVICE_PATH_PROTOCOL
*) RamDiskDevNode
154 if (NULL
== *DevicePath
) {
155 Status
= EFI_OUT_OF_RESOURCES
;
159 PrivateData
->DevicePath
= *DevicePath
;
162 // Check whether the created device path is already present in the handle
165 if (!IsListEmpty(&RegisteredRamDisks
)) {
166 DevicePathSize
= GetDevicePathSize (PrivateData
->DevicePath
);
168 EFI_LIST_FOR_EACH (Entry
, &RegisteredRamDisks
) {
169 RegisteredPrivateData
= RAM_DISK_PRIVATE_FROM_THIS (Entry
);
170 if (DevicePathSize
== GetDevicePathSize (RegisteredPrivateData
->DevicePath
)) {
172 // Compare device path
175 PrivateData
->DevicePath
,
176 RegisteredPrivateData
->DevicePath
,
177 DevicePathSize
)) == 0) {
179 Status
= EFI_ALREADY_STARTED
;
187 // Fill Block IO protocol informations for the RAM disk
189 RamDiskInitBlockIo (PrivateData
);
192 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
195 Status
= gBS
->InstallMultipleProtocolInterfaces (
196 &PrivateData
->Handle
,
197 &gEfiBlockIoProtocolGuid
,
198 &PrivateData
->BlockIo
,
199 &gEfiBlockIo2ProtocolGuid
,
200 &PrivateData
->BlockIo2
,
201 &gEfiDevicePathProtocolGuid
,
202 PrivateData
->DevicePath
,
205 if (EFI_ERROR (Status
)) {
210 // Insert the newly created one to the registered RAM disk list
212 InsertTailList (&RegisteredRamDisks
, &PrivateData
->ThisInstance
);
215 gBS
->ConnectController (PrivateData
->Handle
, NULL
, NULL
, TRUE
);
217 FreePool (RamDiskDevNode
);
222 if (RamDiskDevNode
!= NULL
) {
223 FreePool (RamDiskDevNode
);
226 if (PrivateData
!= NULL
) {
227 if (PrivateData
->DevicePath
) {
228 FreePool (PrivateData
->DevicePath
);
231 FreePool (PrivateData
);
239 Unregister a RAM disk specified by DevicePath.
241 @param[in] DevicePath A pointer to the device path that describes a RAM
244 @retval EFI_SUCCESS The RAM disk is unregistered successfully.
245 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
246 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
247 valid ramdisk device path and not supported
249 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
256 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
260 LIST_ENTRY
*NextEntry
;
264 EFI_DEVICE_PATH_PROTOCOL
*Header
;
265 MEDIA_RAM_DISK_DEVICE_PATH
*RamDiskDevNode
;
266 RAM_DISK_PRIVATE_DATA
*PrivateData
;
268 if (NULL
== DevicePath
) {
269 return EFI_INVALID_PARAMETER
;
273 // Locate the RAM disk device node.
275 RamDiskDevNode
= NULL
;
279 // Test if the current device node is a RAM disk.
281 if ((MEDIA_DEVICE_PATH
== Header
->Type
) &&
282 (MEDIA_RAM_DISK_DP
== Header
->SubType
)) {
283 RamDiskDevNode
= (MEDIA_RAM_DISK_DEVICE_PATH
*) Header
;
288 Header
= NextDevicePathNode (Header
);
289 } while ((Header
->Type
!= END_DEVICE_PATH_TYPE
));
291 if (NULL
== RamDiskDevNode
) {
292 return EFI_UNSUPPORTED
;
296 StartingAddr
= ReadUnaligned64 ((UINT64
*) &(RamDiskDevNode
->StartingAddr
[0]));
297 EndingAddr
= ReadUnaligned64 ((UINT64
*) &(RamDiskDevNode
->EndingAddr
[0]));
299 if (!IsListEmpty(&RegisteredRamDisks
)) {
300 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &RegisteredRamDisks
) {
301 PrivateData
= RAM_DISK_PRIVATE_FROM_THIS (Entry
);
304 // Unregister the RAM disk given by its starting address, ending address
307 if ((StartingAddr
== PrivateData
->StartingAddr
) &&
308 (EndingAddr
== PrivateData
->StartingAddr
+ PrivateData
->Size
) &&
309 (CompareGuid (&RamDiskDevNode
->TypeGuid
, &PrivateData
->TypeGuid
))) {
311 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
313 gBS
->UninstallMultipleProtocolInterfaces (
315 &gEfiBlockIoProtocolGuid
,
316 &PrivateData
->BlockIo
,
317 &gEfiBlockIo2ProtocolGuid
,
318 &PrivateData
->BlockIo2
,
319 &gEfiDevicePathProtocolGuid
,
320 (EFI_DEVICE_PATH_PROTOCOL
*) PrivateData
->DevicePath
,
324 RemoveEntryList (&PrivateData
->ThisInstance
);
326 if (RamDiskCreateHii
== PrivateData
->CreateMethod
) {
328 // If a RAM disk is created within HII, then the RamDiskDxe driver
329 // driver is responsible for freeing the allocated memory for the
332 FreePool ((VOID
*)(UINTN
) PrivateData
->StartingAddr
);
335 FreePool (PrivateData
->DevicePath
);
336 FreePool (PrivateData
);
348 return EFI_NOT_FOUND
;