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
;
108 if ((0 == RamDiskSize
) || (NULL
== RamDiskType
) || (NULL
== DevicePath
)) {
109 return EFI_INVALID_PARAMETER
;
113 // Add check to prevent data read across the memory boundary
115 if (RamDiskBase
+ RamDiskSize
> ((UINTN
) -1) - RAM_DISK_BLOCK_SIZE
+ 1) {
116 return EFI_INVALID_PARAMETER
;
119 RamDiskDevNode
= NULL
;
122 // Create a new RAM disk instance and initialize its private data
124 PrivateData
= AllocateCopyPool (
125 sizeof (RAM_DISK_PRIVATE_DATA
),
126 &mRamDiskPrivateDataTemplate
128 if (NULL
== PrivateData
) {
129 return EFI_OUT_OF_RESOURCES
;
132 PrivateData
->StartingAddr
= RamDiskBase
;
133 PrivateData
->Size
= RamDiskSize
;
134 CopyGuid (&PrivateData
->TypeGuid
, RamDiskType
);
135 InitializeListHead (&PrivateData
->ThisInstance
);
138 // Generate device path information for the registered RAM disk
140 RamDiskDevNode
= AllocateCopyPool (
141 sizeof (MEDIA_RAM_DISK_DEVICE_PATH
),
142 &mRamDiskDeviceNodeTemplate
144 if (NULL
== RamDiskDevNode
) {
145 Status
= EFI_OUT_OF_RESOURCES
;
149 RamDiskInitDeviceNode (PrivateData
, RamDiskDevNode
);
151 *DevicePath
= AppendDevicePathNode (
153 (EFI_DEVICE_PATH_PROTOCOL
*) RamDiskDevNode
155 if (NULL
== *DevicePath
) {
156 Status
= EFI_OUT_OF_RESOURCES
;
160 PrivateData
->DevicePath
= *DevicePath
;
163 // Check whether the created device path is already present in the handle
166 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
167 if (!IsListEmpty(&RegisteredRamDisks
)) {
168 DevicePathSize
= GetDevicePathSize (PrivateData
->DevicePath
);
170 EFI_LIST_FOR_EACH (Entry
, &RegisteredRamDisks
) {
171 RegisteredPrivateData
= RAM_DISK_PRIVATE_FROM_THIS (Entry
);
172 if (DevicePathSize
== GetDevicePathSize (RegisteredPrivateData
->DevicePath
)) {
174 // Compare device path
177 PrivateData
->DevicePath
,
178 RegisteredPrivateData
->DevicePath
,
179 DevicePathSize
)) == 0) {
181 Status
= EFI_ALREADY_STARTED
;
187 gBS
->RestoreTPL (OldTpl
);
190 // Fill Block IO protocol informations for the RAM disk
192 RamDiskInitBlockIo (PrivateData
);
195 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
198 Status
= gBS
->InstallMultipleProtocolInterfaces (
199 &PrivateData
->Handle
,
200 &gEfiBlockIoProtocolGuid
,
201 &PrivateData
->BlockIo
,
202 &gEfiBlockIo2ProtocolGuid
,
203 &PrivateData
->BlockIo2
,
204 &gEfiDevicePathProtocolGuid
,
205 PrivateData
->DevicePath
,
208 if (EFI_ERROR (Status
)) {
213 // Insert the newly created one to the registered RAM disk list
215 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
216 InsertTailList (&RegisteredRamDisks
, &PrivateData
->ThisInstance
);
218 gBS
->RestoreTPL (OldTpl
);
220 gBS
->ConnectController (PrivateData
->Handle
, NULL
, NULL
, TRUE
);
222 FreePool (RamDiskDevNode
);
227 if (RamDiskDevNode
!= NULL
) {
228 FreePool (RamDiskDevNode
);
231 if (PrivateData
!= NULL
) {
232 if (PrivateData
->DevicePath
) {
233 FreePool (PrivateData
->DevicePath
);
236 FreePool (PrivateData
);
244 Unregister a RAM disk specified by DevicePath.
246 @param[in] DevicePath A pointer to the device path that describes a RAM
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
254 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
261 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
265 LIST_ENTRY
*NextEntry
;
269 EFI_DEVICE_PATH_PROTOCOL
*Header
;
270 MEDIA_RAM_DISK_DEVICE_PATH
*RamDiskDevNode
;
271 RAM_DISK_PRIVATE_DATA
*PrivateData
;
274 if (NULL
== DevicePath
) {
275 return EFI_INVALID_PARAMETER
;
279 // Locate the RAM disk device node.
281 RamDiskDevNode
= NULL
;
285 // Test if the current device node is a RAM disk.
287 if ((MEDIA_DEVICE_PATH
== Header
->Type
) &&
288 (MEDIA_RAM_DISK_DP
== Header
->SubType
)) {
289 RamDiskDevNode
= (MEDIA_RAM_DISK_DEVICE_PATH
*) Header
;
294 Header
= NextDevicePathNode (Header
);
295 } while ((Header
->Type
!= END_DEVICE_PATH_TYPE
));
297 if (NULL
== RamDiskDevNode
) {
298 return EFI_UNSUPPORTED
;
302 StartingAddr
= ReadUnaligned64 ((UINT64
*) &(RamDiskDevNode
->StartingAddr
[0]));
303 EndingAddr
= ReadUnaligned64 ((UINT64
*) &(RamDiskDevNode
->EndingAddr
[0]));
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
);
311 // Unregister the RAM disk given by its starting address, ending address
314 if ((StartingAddr
== PrivateData
->StartingAddr
) &&
315 (EndingAddr
== PrivateData
->StartingAddr
+ PrivateData
->Size
) &&
316 (CompareGuid (&RamDiskDevNode
->TypeGuid
, &PrivateData
->TypeGuid
))) {
318 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
320 gBS
->UninstallMultipleProtocolInterfaces (
322 &gEfiBlockIoProtocolGuid
,
323 &PrivateData
->BlockIo
,
324 &gEfiBlockIo2ProtocolGuid
,
325 &PrivateData
->BlockIo2
,
326 &gEfiDevicePathProtocolGuid
,
331 RemoveEntryList (&PrivateData
->ThisInstance
);
333 if (RamDiskCreateHii
== PrivateData
->CreateMethod
) {
335 // If a RAM disk is created within HII, then the RamDiskDxe driver
336 // driver is responsible for freeing the allocated memory for the
339 FreePool ((VOID
*)(UINTN
) PrivateData
->StartingAddr
);
342 FreePool (PrivateData
->DevicePath
);
343 FreePool (PrivateData
);
351 gBS
->RestoreTPL (OldTpl
);
356 return EFI_NOT_FOUND
;