1 /** @file
2
3 Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
4
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 "ArmVExpressInternal.h"
16
17 #include <PiDxe.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/VirtioMmioDeviceLib.h>
20 #include <Library/ArmShellCmdLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/DevicePathLib.h>
23
24 #include <Protocol/FirmwareVolume2.h>
25
26 #define ARM_FVP_BASE_VIRTIO_BLOCK_BASE 0x1c130000
27
28 #pragma pack(1)
29 typedef struct {
30 VENDOR_DEVICE_PATH Vendor;
31 EFI_DEVICE_PATH_PROTOCOL End;
32 } VIRTIO_BLK_DEVICE_PATH;
33 #pragma pack()
34
35 VIRTIO_BLK_DEVICE_PATH mVirtioBlockDevicePath =
36 {
37 {
38 {
39 HARDWARE_DEVICE_PATH,
40 HW_VENDOR_DP,
41 {
42 (UINT8)( sizeof(VENDOR_DEVICE_PATH) ),
43 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)
44 }
45 },
46 EFI_CALLER_ID_GUID,
47 },
48 {
49 END_DEVICE_PATH_TYPE,
50 END_ENTIRE_DEVICE_PATH_SUBTYPE,
51 {
52 sizeof (EFI_DEVICE_PATH_PROTOCOL),
53 0
54 }
55 }
56 };
57
58 STATIC
59 EFI_STATUS
InternalFindFdtByGuid(IN OUT EFI_DEVICE_PATH ** FdtDevicePath,IN CONST EFI_GUID * FdtGuid)60 InternalFindFdtByGuid (
61 IN OUT EFI_DEVICE_PATH **FdtDevicePath,
62 IN CONST EFI_GUID *FdtGuid
63 )
64 {
65 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileDevicePath;
66 EFI_HANDLE *HandleBuffer;
67 UINTN HandleCount;
68 UINTN Index;
69 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
70 EFI_GUID NameGuid;
71 UINTN Size;
72 VOID *Key;
73 EFI_FV_FILETYPE FileType;
74 EFI_FV_FILE_ATTRIBUTES Attributes;
75 EFI_DEVICE_PATH *FvDevicePath;
76 EFI_STATUS Status;
77
78 if (FdtGuid == NULL) {
79 return EFI_NOT_FOUND;
80 }
81
82 EfiInitializeFwVolDevicepathNode (&FileDevicePath, FdtGuid);
83
84 HandleBuffer = NULL;
85 Status = gBS->LocateHandleBuffer (
86 ByProtocol,
87 &gEfiFirmwareVolume2ProtocolGuid,
88 NULL,
89 &HandleCount,
90 &HandleBuffer
91 );
92 if (EFI_ERROR (Status)) {
93 return Status;
94 }
95
96 for (Index = 0; Index < HandleCount; Index++) {
97 Status = gBS->HandleProtocol (
98 HandleBuffer[Index],
99 &gEfiFirmwareVolume2ProtocolGuid,
100 (VOID **) &FvProtocol
101 );
102 if (EFI_ERROR (Status)) {
103 return Status;
104 }
105
106 // Allocate Key
107 Key = AllocatePool (FvProtocol->KeySize);
108 ASSERT (Key != NULL);
109 ZeroMem (Key, FvProtocol->KeySize);
110
111 do {
112 FileType = EFI_FV_FILETYPE_RAW;
113 Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size);
114 if (Status == EFI_NOT_FOUND) {
115 break;
116 }
117 if (EFI_ERROR (Status)) {
118 return Status;
119 }
120
121 //
122 // Check whether this file is the one we are looking for. If so,
123 // create a device path for it and return it to the caller.
124 //
125 if (CompareGuid (&NameGuid, FdtGuid)) {
126 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
127 if (!EFI_ERROR (Status)) {
128 *FdtDevicePath = AppendDevicePathNode (FvDevicePath,
129 (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath);
130 }
131 goto Done;
132 }
133 } while (TRUE);
134 FreePool (Key);
135 }
136
137 if (Index == HandleCount) {
138 Status = EFI_NOT_FOUND;
139 }
140 return Status;
141
142 Done:
143 FreePool (Key);
144 return Status;
145 }
146
147 /**
148 * Generic UEFI Entrypoint for 'ArmFvpDxe' driver
149 * See UEFI specification for the details of the parameters
150 */
151 EFI_STATUS
152 EFIAPI
ArmFvpInitialise(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)153 ArmFvpInitialise (
154 IN EFI_HANDLE ImageHandle,
155 IN EFI_SYSTEM_TABLE *SystemTable
156 )
157 {
158 CONST ARM_VEXPRESS_PLATFORM* Platform;
159 EFI_STATUS Status;
160 CHAR16 *TextDevicePath;
161 UINTN TextDevicePathSize;
162 VOID *Buffer;
163 EFI_DEVICE_PATH *FdtDevicePath;
164
165 Status = gBS->InstallProtocolInterface (&ImageHandle,
166 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
167 &mVirtioBlockDevicePath);
168 if (EFI_ERROR (Status)) {
169 return Status;
170 }
171
172 Status = ArmVExpressGetPlatform (&Platform);
173 if (!EFI_ERROR (Status)) {
174 FdtDevicePath = NULL;
175 Status = InternalFindFdtByGuid (&FdtDevicePath, Platform->FdtGuid);
176 if (!EFI_ERROR (Status)) {
177 TextDevicePath = ConvertDevicePathToText (FdtDevicePath, FALSE, FALSE);
178 if (TextDevicePath != NULL) {
179 TextDevicePathSize = StrSize (TextDevicePath);
180 }
181 FreePool (FdtDevicePath);
182 } else {
183 TextDevicePathSize = StrSize ((CHAR16*)PcdGetPtr (PcdFvpFdtDevicePathsBase)) - sizeof (CHAR16);
184 TextDevicePathSize += StrSize (Platform->FdtName);
185
186 TextDevicePath = AllocatePool (TextDevicePathSize);
187 if (TextDevicePath != NULL) {
188 StrCpy (TextDevicePath, ((CHAR16*)PcdGetPtr (PcdFvpFdtDevicePathsBase)));
189 StrCat (TextDevicePath, Platform->FdtName);
190 }
191 }
192 if (TextDevicePath != NULL) {
193 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);
194 if (Buffer == NULL) {
195 DEBUG ((
196 EFI_D_ERROR,
197 "ArmFvpDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", EFI_BUFFER_TOO_SMALL
198 ));
199 }
200 FreePool (TextDevicePath);
201 }
202 }
203
204 // Declare the Virtio BlockIo device
205 Status = VirtioMmioInstallDevice (ARM_FVP_BASE_VIRTIO_BLOCK_BASE, ImageHandle);
206 if (EFI_ERROR (Status)) {
207 DEBUG ((EFI_D_ERROR, "ArmFvpDxe: Failed to install Virtio block device\n"));
208 }
209
210 // Install dynamic Shell command to run baremetal binaries.
211 Status = ShellDynCmdRunAxfInstall (ImageHandle);
212 if (EFI_ERROR (Status)) {
213 DEBUG ((EFI_D_ERROR, "ArmFvpDxe: Failed to install ShellDynCmdRunAxf\n"));
214 }
215
216 return Status;
217 }
218