]>
Commit | Line | Data |
---|---|---|
1d5d0ae9 | 1 | /** @file |
2 | * | |
3 | * Copyright (c) 2011, 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 <PiDxe.h> | |
1d5d0ae9 | 16 | #include <Library/UefiBootServicesTableLib.h> |
17 | #include <Library/DebugLib.h> | |
18 | #include <Library/MemoryAllocationLib.h> | |
19 | #include <Library/UefiLib.h> | |
20 | #include <Library/PerformanceLib.h> | |
21 | #include <Library/UefiRuntimeServicesTableLib.h> | |
22 | #include <Library/PcdLib.h> | |
3e070763 | 23 | #include <Library/BdsUnixLib.h> |
1d5d0ae9 | 24 | |
25 | #include <Protocol/Bds.h> | |
26 | #include <Protocol/DevicePathToText.h> | |
27 | ||
28 | #include <Guid/GlobalVariable.h> | |
29 | ||
30 | #define MAX_CMD_LINE 256 | |
31 | ||
32 | VOID | |
33 | EFIAPI | |
34 | BdsEntry ( | |
35 | IN EFI_BDS_ARCH_PROTOCOL *This | |
36 | ); | |
37 | ||
38 | EFI_HANDLE mBdsImageHandle = NULL; | |
39 | EFI_BDS_ARCH_PROTOCOL gBdsProtocol = { | |
40 | BdsEntry, | |
41 | }; | |
42 | ||
43 | EFI_STATUS GetEnvironmentVariable ( | |
44 | IN CONST CHAR16* VariableName, | |
45 | IN VOID* DefaultValue, | |
46 | IN UINTN DefaultSize, | |
47 | OUT VOID** Value) | |
48 | { | |
49 | EFI_STATUS Status; | |
50 | UINTN Size; | |
51 | ||
52 | // Try to get the variable size. | |
53 | *Value = NULL; | |
54 | Size = 0; | |
55 | Status = gRT->GetVariable ((CHAR16 *) VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value); | |
56 | if (Status == EFI_NOT_FOUND) { | |
57 | // If the environment variable does not exist yet then set it with the default value | |
58 | Status = gRT->SetVariable ( | |
59 | (CHAR16*)VariableName, | |
60 | &gEfiGlobalVariableGuid, | |
61 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, | |
62 | DefaultSize, | |
63 | DefaultValue | |
64 | ); | |
65 | *Value = DefaultValue; | |
66 | } else if (Status == EFI_BUFFER_TOO_SMALL) { | |
67 | // Get the environment variable value | |
68 | *Value = AllocatePool (Size); | |
69 | if (*Value == NULL) { | |
70 | return EFI_OUT_OF_RESOURCES; | |
71 | } | |
72 | ||
73 | Status = gRT->GetVariable ((CHAR16 *)VariableName, &gEfiGlobalVariableGuid, NULL, &Size, *Value); | |
74 | if (EFI_ERROR (Status)) { | |
75 | FreePool(*Value); | |
76 | return EFI_INVALID_PARAMETER; | |
77 | } | |
78 | } else { | |
79 | *Value = DefaultValue; | |
80 | return Status; | |
81 | } | |
82 | ||
83 | return EFI_SUCCESS; | |
84 | } | |
85 | ||
09eb2dc3 | 86 | EFI_STATUS |
87 | InitializeConsole ( | |
1d5d0ae9 | 88 | VOID |
89 | ) | |
90 | { | |
91 | EFI_STATUS Status; | |
92 | UINTN NoHandles; | |
93 | EFI_HANDLE *Buffer; | |
09eb2dc3 | 94 | BOOLEAN AllDriversConnected; |
95 | ||
96 | AllDriversConnected = FALSE; | |
1d5d0ae9 | 97 | |
98 | // | |
99 | // Now we need to setup the EFI System Table with information about the console devices. | |
100 | // This code is normally in the console spliter driver on platforms that support multiple | |
101 | // consoles at the same time | |
102 | // | |
103 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer); | |
09eb2dc3 | 104 | if (EFI_ERROR (Status)) { |
105 | BdsConnectAllDrivers(); | |
106 | AllDriversConnected = TRUE; | |
107 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer); | |
108 | } | |
109 | ||
1d5d0ae9 | 110 | if (!EFI_ERROR (Status)) { |
111 | // Use the first SimpleTextOut we find and update the EFI System Table | |
112 | gST->ConsoleOutHandle = Buffer[0]; | |
113 | gST->StandardErrorHandle = Buffer[0]; | |
114 | Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextOutProtocolGuid, (VOID **)&gST->ConOut); | |
115 | ASSERT_EFI_ERROR (Status); | |
116 | ||
117 | gST->StdErr = gST->ConOut; | |
118 | ||
119 | FreePool (Buffer); | |
09eb2dc3 | 120 | } else { |
121 | return Status; | |
122 | } | |
1d5d0ae9 | 123 | |
124 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer); | |
09eb2dc3 | 125 | if (EFI_ERROR (Status) && !AllDriversConnected) { |
126 | BdsConnectAllDrivers(); | |
127 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer); | |
128 | } | |
129 | ||
1d5d0ae9 | 130 | if (!EFI_ERROR (Status)) { |
131 | // Use the first SimpleTextIn we find and update the EFI System Table | |
132 | gST->ConsoleInHandle = Buffer[0]; | |
133 | Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextInProtocolGuid, (VOID **)&gST->ConIn); | |
134 | ASSERT_EFI_ERROR (Status); | |
135 | ||
136 | FreePool (Buffer); | |
09eb2dc3 | 137 | } else { |
138 | return Status; | |
1d5d0ae9 | 139 | } |
09eb2dc3 | 140 | |
141 | return EFI_SUCCESS; | |
1d5d0ae9 | 142 | } |
143 | ||
144 | EFI_STATUS | |
145 | GetHIInputAscii ( | |
146 | CHAR8 *CmdLine, | |
147 | UINTN MaxCmdLine | |
148 | ) { | |
149 | UINTN CmdLineIndex; | |
150 | UINTN WaitIndex; | |
151 | CHAR8 Char; | |
152 | EFI_INPUT_KEY Key; | |
153 | EFI_STATUS Status; | |
154 | ||
155 | CmdLine[0] = '\0'; | |
156 | ||
157 | for (CmdLineIndex = 0; CmdLineIndex < MaxCmdLine; ) { | |
158 | Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex); | |
159 | ASSERT_EFI_ERROR (Status); | |
160 | ||
161 | Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
162 | ASSERT_EFI_ERROR (Status); | |
163 | ||
164 | Char = (CHAR8)Key.UnicodeChar; | |
165 | if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) { | |
166 | CmdLine[CmdLineIndex] = '\0'; | |
167 | AsciiPrint ("\n"); | |
168 | return EFI_SUCCESS; | |
169 | } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){ | |
170 | if (CmdLineIndex != 0) { | |
171 | CmdLineIndex--; | |
172 | AsciiPrint ("\b \b"); | |
173 | } | |
174 | } else { | |
175 | CmdLine[CmdLineIndex++] = Char; | |
176 | AsciiPrint ("%c", Char); | |
177 | } | |
178 | } | |
179 | ||
180 | return EFI_SUCCESS; | |
181 | } | |
182 | ||
183 | VOID | |
184 | ListDevicePaths ( | |
185 | IN BOOLEAN AllDrivers | |
186 | ) { | |
187 | EFI_STATUS Status; | |
188 | UINTN HandleCount; | |
189 | EFI_HANDLE *HandleBuffer; | |
190 | UINTN Index; | |
191 | EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol; | |
192 | CHAR16* String; | |
193 | EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* EfiDevicePathToTextProtocol; | |
194 | ||
195 | if (AllDrivers) { | |
196 | BdsConnectAllDrivers(); | |
197 | } | |
198 | ||
199 | Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&EfiDevicePathToTextProtocol); | |
200 | if (EFI_ERROR (Status)) { | |
201 | AsciiPrint ("Did not find the DevicePathToTextProtocol.\n"); | |
202 | return; | |
203 | } | |
204 | ||
205 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleCount, &HandleBuffer); | |
206 | if (EFI_ERROR (Status)) { | |
207 | AsciiPrint ("No device path found\n"); | |
208 | return; | |
209 | } | |
210 | ||
211 | for (Index = 0; Index < HandleCount; Index++) { | |
212 | Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); | |
213 | String = EfiDevicePathToTextProtocol->ConvertDevicePathToText(DevicePathProtocol,TRUE,TRUE); | |
214 | Print (L"\t- [%d] %s\n",Index, String); | |
215 | } | |
216 | } | |
217 | ||
218 | INTN BdsComparefile ( | |
219 | IN CHAR16 *DeviceFilePath1, | |
220 | IN CHAR16 *DeviceFilePath2, | |
221 | VOID **FileImage1,VOID **FileImage2,UINTN* FileSize | |
222 | ); | |
223 | ||
224 | /** | |
225 | This function uses policy data from the platform to determine what operating | |
226 | system or system utility should be loaded and invoked. This function call | |
227 | also optionally make the use of user input to determine the operating system | |
228 | or system utility to be loaded and invoked. When the DXE Core has dispatched | |
229 | all the drivers on the dispatch queue, this function is called. This | |
230 | function will attempt to connect the boot devices required to load and invoke | |
231 | the selected operating system or system utility. During this process, | |
232 | additional firmware volumes may be discovered that may contain addition DXE | |
233 | drivers that can be dispatched by the DXE Core. If a boot device cannot be | |
234 | fully connected, this function calls the DXE Service Dispatch() to allow the | |
235 | DXE drivers from any newly discovered firmware volumes to be dispatched. | |
236 | Then the boot device connection can be attempted again. If the same boot | |
237 | device connection operation fails twice in a row, then that boot device has | |
238 | failed, and should be skipped. This function should never return. | |
239 | ||
240 | @param This The EFI_BDS_ARCH_PROTOCOL instance. | |
241 | ||
242 | @return None. | |
243 | ||
244 | **/ | |
245 | VOID | |
246 | EFIAPI | |
247 | BdsEntry ( | |
248 | IN EFI_BDS_ARCH_PROTOCOL *This | |
249 | ) | |
250 | { | |
251 | EFI_STATUS Status; | |
252 | CHAR8 CmdLine[MAX_CMD_LINE]; | |
253 | VOID* DefaultVariableValue; | |
254 | UINTN DefaultVariableSize; | |
255 | CHAR16 *LinuxKernelDP; | |
256 | CHAR8 *LinuxAtag; | |
257 | CHAR16 *FdtDP; | |
258 | ||
259 | PERF_END (NULL, "DXE", NULL, 0); | |
260 | PERF_START (NULL, "BDS", NULL, 0); | |
261 | ||
09eb2dc3 | 262 | Status = InitializeConsole(); |
263 | ASSERT_EFI_ERROR(Status); | |
1d5d0ae9 | 264 | |
265 | while (1) { | |
266 | // Get the Linux Kernel Device Path from Environment Variable | |
267 | DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxKernelDP); | |
268 | DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue); | |
269 | GetEnvironmentVariable(L"LinuxKernelDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxKernelDP); | |
270 | ||
271 | // Get the Linux ATAG from Environment Variable | |
272 | DefaultVariableValue = (VOID*)PcdGetPtr(PcdLinuxAtag); | |
273 | DefaultVariableSize = AsciiStrSize((CHAR8*)DefaultVariableValue); | |
274 | GetEnvironmentVariable(L"LinuxAtag",DefaultVariableValue,DefaultVariableSize,(VOID**)&LinuxAtag); | |
275 | ||
276 | // Get the FDT Device Path from Environment Variable | |
277 | DefaultVariableValue = (VOID*)PcdGetPtr(PcdFdtDP); | |
278 | DefaultVariableSize = StrSize((CHAR16*)DefaultVariableValue); | |
279 | GetEnvironmentVariable(L"FdtDP",DefaultVariableValue,DefaultVariableSize,(VOID**)&FdtDP); | |
280 | ||
281 | AsciiPrint ("1. Start EBL\n\r"); | |
282 | AsciiPrint ("2. List Device Paths of all the drivers\n"); | |
283 | AsciiPrint ("3. Start Linux\n"); | |
284 | Print (L"\t- Kernel: %s\n", LinuxKernelDP); | |
285 | AsciiPrint ("\t- Atag: %a\n", LinuxAtag); | |
286 | Print (L"\t- Fdt: %s\n", FdtDP); | |
287 | AsciiPrint ("Choice: "); | |
288 | ||
289 | Status = GetHIInputAscii(CmdLine,MAX_CMD_LINE); | |
290 | ASSERT_EFI_ERROR (Status); | |
291 | if (AsciiStrCmp(CmdLine,"1") == 0) { | |
292 | // Start EBL | |
293 | Status = BdsLoadApplication(L"Ebl"); | |
294 | if (Status == EFI_NOT_FOUND) { | |
295 | AsciiPrint ("Error: EFI Application not found.\n"); | |
296 | } else { | |
297 | AsciiPrint ("Error: Status Code: 0x%X\n",(UINT32)Status); | |
298 | } | |
299 | } else if (AsciiStrCmp(CmdLine,"2") == 0) { | |
300 | ListDevicePaths (TRUE); | |
301 | } else if (AsciiStrCmp(CmdLine,"3") == 0) { | |
302 | // Start Linux Kernel | |
303 | Status = BdsBootLinux(LinuxKernelDP,LinuxAtag,FdtDP); | |
304 | if (EFI_ERROR(Status)) { | |
305 | AsciiPrint ("Error: Fail to start Linux (0x%X)\n",(UINT32)Status); | |
306 | } | |
307 | } else { | |
308 | AsciiPrint ("Error: Invalid choice.\n"); | |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | EFI_STATUS | |
314 | EFIAPI | |
315 | BdsInitialize ( | |
316 | IN EFI_HANDLE ImageHandle, | |
317 | IN EFI_SYSTEM_TABLE *SystemTable | |
318 | ) | |
319 | { | |
320 | EFI_STATUS Status; | |
321 | ||
322 | mBdsImageHandle = ImageHandle; | |
323 | ||
324 | Status = gBS->InstallMultipleProtocolInterfaces ( | |
325 | &mBdsImageHandle, | |
326 | &gEfiBdsArchProtocolGuid, &gBdsProtocol, | |
327 | NULL | |
328 | ); | |
329 | ASSERT_EFI_ERROR (Status); | |
330 | ||
331 | return Status; | |
332 | } |