]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c
EmbeddedPkg/FdtLib: Added support to load Fdt from Semihosting
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / FdtConfigurationTable.c
1 /** @file
2 *
3 * Copyright (c) 2014, ARM Limited. All rights reserved.
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 <Uefi.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/SimpleFileSystem.h>
22
23 #include <Guid/Fdt.h>
24 #include <Guid/FileInfo.h>
25
26 #include <libfdt.h>
27
28 //
29 // Device path for SemiHosting
30 //
31 STATIC CONST struct {
32 VENDOR_DEVICE_PATH Guid;
33 EFI_DEVICE_PATH_PROTOCOL End;
34 } mSemihostingDevicePath = {
35 {
36 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },
37 { 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }
38 },
39 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
40 };
41
42
43 /**
44 This function declares the passed FDT into the UEFI Configuration Table
45
46 @param FdtBlob Base address of the Fdt Blob in System Memory
47 @param FdtSize Size of the Fdt Blob in System Memory
48
49 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
50 @return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()
51
52 **/
53 STATIC
54 EFI_STATUS
55 InstallFdtIntoConfigurationTable (
56 IN VOID* FdtBlob,
57 IN UINTN FdtSize
58 )
59 {
60 EFI_STATUS Status;
61
62 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
63 // production device and this ASSERT() becomes not valid.
64 ASSERT (fdt_check_header (FdtBlob) == 0);
65
66 // Ensure the Size of the Device Tree is smaller than the size of the read file
67 ASSERT ((UINTN)fdt_totalsize (FdtBlob) <= FdtSize);
68
69 // Install the FDT into the Configuration Table
70 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, FdtBlob);
71
72 return Status;
73 }
74
75
76 /**
77 Load and Install FDT from Semihosting
78
79 @param Filename Name of the file to load from semihosting
80
81 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
82 from semihosting
83 @return EFI_NOT_FOUND Fail to locate the file in semihosting
84 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
85 **/
86 EFI_STATUS
87 InstallFdtFromSemihosting (
88 IN CONST CHAR16* FileName
89 )
90 {
91 EFI_STATUS Status;
92 EFI_DEVICE_PATH* Remaining;
93 EFI_HANDLE Handle;
94 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SemihostingFs;
95 EFI_FILE_PROTOCOL *Fs;
96 EFI_FILE_PROTOCOL *File;
97 EFI_PHYSICAL_ADDRESS FdtBase;
98 EFI_FILE_INFO *FileInfo;
99 UINTN FdtSize;
100 UINTN FileInfoSize;
101
102 // Ensure the Semihosting driver is initialized
103 Remaining = (EFI_DEVICE_PATH*)&mSemihostingDevicePath;
104 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
105 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
106 // to point to the remaining part of the device path
107 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, &Handle);
108 if (EFI_ERROR (Status)) {
109 ASSERT_EFI_ERROR (Status);
110 return Status;
111 }
112
113 // Recursive = FALSE: We do not want to start the whole device tree
114 Status = gBS->ConnectController (Handle, NULL, Remaining, FALSE);
115 if (EFI_ERROR (Status)) {
116 return Status;
117 }
118
119 // Locate the FileSystem
120 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SemihostingFs);
121 if (EFI_ERROR (Status)) {
122 ASSERT_EFI_ERROR (Status);
123 return Status;
124 }
125
126 // Try to Open the volume and get root directory
127 Status = SemihostingFs->OpenVolume (SemihostingFs, &Fs);
128 if (EFI_ERROR (Status)) {
129 DEBUG ((EFI_D_WARN, "Warning: Fail to open semihosting filesystem that should contain FDT file.\n"));
130 return Status;
131 }
132
133 File = NULL;
134 Status = Fs->Open (Fs, &File, (CHAR16*)FileName, EFI_FILE_MODE_READ, 0);
135 if (EFI_ERROR (Status)) {
136 DEBUG ((EFI_D_WARN, "Warning: Fail to load FDT file '%s'.\n", FileName));
137 Fs->Close (Fs);
138 return Status;
139 }
140
141 FileInfoSize = 0;
142 File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, NULL);
143 FileInfo = AllocatePool (FileInfoSize);
144 if (FileInfo == NULL) {
145 Status = EFI_OUT_OF_RESOURCES;
146 goto CLOSE_FILES;
147 }
148 Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);
149 if (EFI_ERROR (Status)) {
150 FreePool (FileInfo);
151 goto CLOSE_FILES;
152 }
153
154 // Get the file size
155 FdtSize = FileInfo->FileSize;
156 FreePool (FileInfo);
157
158 // The FDT blob is attached to the Configuration Table. It is recommended to load it as Runtime Service Data
159 // to prevent the kernel to overwrite its data
160 Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (FdtSize), &FdtBase);
161 if (!EFI_ERROR (Status)) {
162 Status = File->Read (File, &FdtSize, (VOID*)(UINTN)(FdtBase));
163 if (EFI_ERROR (Status)) {
164 gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));
165 } else {
166 // Install the FDT as part of the UEFI Configuration Table
167 Status = InstallFdtIntoConfigurationTable ((VOID*)(UINTN)FdtBase, FdtSize);
168 if (EFI_ERROR (Status)) {
169 gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));
170 }
171 }
172 }
173
174 CLOSE_FILES:
175 File->Close (File);
176 Fs->Close (Fs);
177 return Status;
178 }