]>
Commit | Line | Data |
---|---|---|
f6755908 OM |
1 | /** @file\r |
2 | \r | |
3 | Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r | |
4 | \r | |
878b807a | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
f6755908 OM |
6 | \r |
7 | **/\r | |
8 | \r | |
9 | #include "AndroidFastbootApp.h"\r | |
10 | \r | |
11 | #include <Protocol/AndroidFastbootTransport.h>\r | |
12 | #include <Protocol/AndroidFastbootPlatform.h>\r | |
13 | #include <Protocol/SimpleTextOut.h>\r | |
14 | #include <Protocol/SimpleTextIn.h>\r | |
15 | \r | |
16 | #include <Library/PcdLib.h>\r | |
17 | #include <Library/UefiRuntimeServicesTableLib.h>\r | |
18 | #include <Library/BaseMemoryLib.h>\r | |
19 | #include <Library/UefiBootServicesTableLib.h>\r | |
20 | #include <Library/UefiApplicationEntryPoint.h>\r | |
21 | #include <Library/PrintLib.h>\r | |
22 | \r | |
23 | /*\r | |
24 | * UEFI Application using the FASTBOOT_TRANSPORT_PROTOCOL and\r | |
25 | * FASTBOOT_PLATFORM_PROTOCOL to implement the Android Fastboot protocol.\r | |
26 | */\r | |
27 | \r | |
e7108d0e MK |
28 | STATIC FASTBOOT_TRANSPORT_PROTOCOL *mTransport;\r |
29 | STATIC FASTBOOT_PLATFORM_PROTOCOL *mPlatform;\r | |
f6755908 | 30 | \r |
e7108d0e | 31 | STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;\r |
f6755908 OM |
32 | \r |
33 | typedef enum {\r | |
34 | ExpectCmdState,\r | |
35 | ExpectDataState,\r | |
36 | FastbootStateMax\r | |
37 | } ANDROID_FASTBOOT_STATE;\r | |
38 | \r | |
e7108d0e | 39 | STATIC ANDROID_FASTBOOT_STATE mState = ExpectCmdState;\r |
f6755908 OM |
40 | \r |
41 | // When in ExpectDataState, the number of bytes of data to expect:\r | |
e7108d0e | 42 | STATIC UINT64 mNumDataBytes;\r |
f6755908 | 43 | // .. and the number of bytes so far received this data phase\r |
e7108d0e | 44 | STATIC UINT64 mBytesReceivedSoFar;\r |
f6755908 | 45 | // .. and the buffer to save data into\r |
e7108d0e | 46 | STATIC UINT8 *mDataBuffer = NULL;\r |
f6755908 OM |
47 | \r |
48 | // Event notify functions, from which gBS->Exit shouldn't be called, can signal\r | |
49 | // this event when the application should exit\r | |
e7108d0e | 50 | STATIC EFI_EVENT mFinishedEvent;\r |
f6755908 | 51 | \r |
e7108d0e | 52 | STATIC EFI_EVENT mFatalSendErrorEvent;\r |
f6755908 OM |
53 | \r |
54 | // This macro uses sizeof - only use it on arrays (i.e. string literals)\r | |
e7108d0e | 55 | #define SEND_LITERAL(Str) mTransport->Send ( \\r |
f6755908 OM |
56 | sizeof (Str) - 1, \\r |
57 | Str, \\r | |
58 | &mFatalSendErrorEvent \\r | |
59 | )\r | |
e7108d0e | 60 | #define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1)\r |
f6755908 | 61 | \r |
e7108d0e | 62 | #define IS_LOWERCASE_ASCII(Char) (Char >= 'a' && Char <= 'z')\r |
f6755908 | 63 | \r |
e7108d0e MK |
64 | #define FASTBOOT_STRING_MAX_LENGTH 256\r |
65 | #define FASTBOOT_COMMAND_MAX_LENGTH 64\r | |
f6755908 OM |
66 | \r |
67 | STATIC\r | |
68 | VOID\r | |
69 | HandleGetVar (\r | |
e7108d0e | 70 | IN CHAR8 *CmdArg\r |
f6755908 OM |
71 | )\r |
72 | {\r | |
e7108d0e MK |
73 | CHAR8 Response[FASTBOOT_COMMAND_MAX_LENGTH + 1] = "OKAY";\r |
74 | EFI_STATUS Status;\r | |
f6755908 OM |
75 | \r |
76 | // Respond to getvar:version with 0.4 (version of Fastboot protocol)\r | |
e7108d0e | 77 | if (!AsciiStrnCmp ("version", CmdArg, sizeof ("version") - 1)) {\r |
f6755908 OM |
78 | SEND_LITERAL ("OKAY" ANDROID_FASTBOOT_VERSION);\r |
79 | } else {\r | |
80 | // All other variables are assumed to be platform specific\r | |
81 | Status = mPlatform->GetVar (CmdArg, Response + 4);\r | |
82 | if (EFI_ERROR (Status)) {\r | |
83 | SEND_LITERAL ("FAILSomething went wrong when looking up the variable");\r | |
84 | } else {\r | |
85 | mTransport->Send (AsciiStrLen (Response), Response, &mFatalSendErrorEvent);\r | |
86 | }\r | |
87 | }\r | |
88 | }\r | |
89 | \r | |
90 | STATIC\r | |
91 | VOID\r | |
92 | HandleDownload (\r | |
e7108d0e | 93 | IN CHAR8 *NumBytesString\r |
f6755908 OM |
94 | )\r |
95 | {\r | |
e7108d0e MK |
96 | CHAR8 Response[13];\r |
97 | CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];\r | |
f6755908 OM |
98 | \r |
99 | // Argument is 8-character ASCII string hex representation of number of bytes\r | |
100 | // that will be sent in the data phase.\r | |
101 | // Response is "DATA" + that same 8-character string.\r | |
102 | \r | |
103 | // Replace any previously downloaded data\r | |
104 | if (mDataBuffer != NULL) {\r | |
105 | FreePool (mDataBuffer);\r | |
106 | mDataBuffer = NULL;\r | |
107 | }\r | |
108 | \r | |
109 | // Parse out number of data bytes to expect\r | |
110 | mNumDataBytes = AsciiStrHexToUint64 (NumBytesString);\r | |
111 | if (mNumDataBytes == 0) {\r | |
112 | mTextOut->OutputString (mTextOut, L"ERROR: Fail to get the number of bytes to download.\r\n");\r | |
113 | SEND_LITERAL ("FAILFailed to get the number of bytes to download");\r | |
114 | return;\r | |
115 | }\r | |
116 | \r | |
117 | UnicodeSPrint (OutputString, sizeof (OutputString), L"Downloading %d bytes\r\n", mNumDataBytes);\r | |
118 | mTextOut->OutputString (mTextOut, OutputString);\r | |
119 | \r | |
120 | mDataBuffer = AllocatePool (mNumDataBytes);\r | |
121 | if (mDataBuffer == NULL) {\r | |
122 | SEND_LITERAL ("FAILNot enough memory");\r | |
123 | } else {\r | |
31090876 | 124 | ZeroMem (Response, sizeof Response);\r |
e7108d0e MK |
125 | AsciiSPrint (\r |
126 | Response,\r | |
127 | sizeof Response,\r | |
128 | "DATA%x",\r | |
129 | (UINT32)mNumDataBytes\r | |
130 | );\r | |
31090876 | 131 | mTransport->Send (sizeof Response - 1, Response, &mFatalSendErrorEvent);\r |
f6755908 | 132 | \r |
e7108d0e | 133 | mState = ExpectDataState;\r |
f6755908 OM |
134 | mBytesReceivedSoFar = 0;\r |
135 | }\r | |
136 | }\r | |
137 | \r | |
138 | STATIC\r | |
139 | VOID\r | |
140 | HandleFlash (\r | |
e7108d0e | 141 | IN CHAR8 *PartitionName\r |
f6755908 OM |
142 | )\r |
143 | {\r | |
144 | EFI_STATUS Status;\r | |
145 | CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];\r | |
146 | \r | |
147 | // Build output string\r | |
148 | UnicodeSPrint (OutputString, sizeof (OutputString), L"Flashing partition %a\r\n", PartitionName);\r | |
149 | mTextOut->OutputString (mTextOut, OutputString);\r | |
150 | \r | |
151 | if (mDataBuffer == NULL) {\r | |
152 | // Doesn't look like we were sent any data\r | |
153 | SEND_LITERAL ("FAILNo data to flash");\r | |
154 | return;\r | |
155 | }\r | |
156 | \r | |
157 | Status = mPlatform->FlashPartition (\r | |
158 | PartitionName,\r | |
159 | mNumDataBytes,\r | |
160 | mDataBuffer\r | |
161 | );\r | |
162 | if (Status == EFI_NOT_FOUND) {\r | |
163 | SEND_LITERAL ("FAILNo such partition.");\r | |
164 | mTextOut->OutputString (mTextOut, L"No such partition.\r\n");\r | |
165 | } else if (EFI_ERROR (Status)) {\r | |
166 | SEND_LITERAL ("FAILError flashing partition.");\r | |
167 | mTextOut->OutputString (mTextOut, L"Error flashing partition.\r\n");\r | |
a1878955 | 168 | DEBUG ((DEBUG_ERROR, "Couldn't flash image: %r\n", Status));\r |
f6755908 OM |
169 | } else {\r |
170 | mTextOut->OutputString (mTextOut, L"Done.\r\n");\r | |
171 | SEND_LITERAL ("OKAY");\r | |
172 | }\r | |
173 | }\r | |
174 | \r | |
175 | STATIC\r | |
176 | VOID\r | |
177 | HandleErase (\r | |
e7108d0e | 178 | IN CHAR8 *PartitionName\r |
f6755908 OM |
179 | )\r |
180 | {\r | |
181 | EFI_STATUS Status;\r | |
182 | CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];\r | |
183 | \r | |
184 | // Build output string\r | |
185 | UnicodeSPrint (OutputString, sizeof (OutputString), L"Erasing partition %a\r\n", PartitionName);\r | |
186 | mTextOut->OutputString (mTextOut, OutputString);\r | |
187 | \r | |
188 | Status = mPlatform->ErasePartition (PartitionName);\r | |
189 | if (EFI_ERROR (Status)) {\r | |
190 | SEND_LITERAL ("FAILCheck device console.");\r | |
a1878955 | 191 | DEBUG ((DEBUG_ERROR, "Couldn't erase image: %r\n", Status));\r |
f6755908 OM |
192 | } else {\r |
193 | SEND_LITERAL ("OKAY");\r | |
194 | }\r | |
195 | }\r | |
196 | \r | |
197 | STATIC\r | |
198 | VOID\r | |
199 | HandleBoot (\r | |
200 | VOID\r | |
201 | )\r | |
202 | {\r | |
e7108d0e | 203 | EFI_STATUS Status;\r |
f6755908 OM |
204 | \r |
205 | mTextOut->OutputString (mTextOut, L"Booting downloaded image\r\n");\r | |
206 | \r | |
207 | if (mDataBuffer == NULL) {\r | |
208 | // Doesn't look like we were sent any data\r | |
209 | SEND_LITERAL ("FAILNo image in memory");\r | |
210 | return;\r | |
211 | }\r | |
212 | \r | |
213 | // We don't really have any choice but to report success, because once we\r | |
214 | // boot we lose control of the system.\r | |
215 | SEND_LITERAL ("OKAY");\r | |
216 | \r | |
217 | Status = BootAndroidBootImg (mNumDataBytes, mDataBuffer);\r | |
218 | if (EFI_ERROR (Status)) {\r | |
a1878955 | 219 | DEBUG ((DEBUG_ERROR, "Failed to boot downloaded image: %r\n", Status));\r |
f6755908 | 220 | }\r |
e7108d0e | 221 | \r |
f6755908 OM |
222 | // We shouldn't get here\r |
223 | }\r | |
224 | \r | |
225 | STATIC\r | |
226 | VOID\r | |
227 | HandleOemCommand (\r | |
e7108d0e | 228 | IN CHAR8 *Command\r |
f6755908 OM |
229 | )\r |
230 | {\r | |
231 | EFI_STATUS Status;\r | |
232 | \r | |
233 | Status = mPlatform->DoOemCommand (Command);\r | |
234 | if (Status == EFI_NOT_FOUND) {\r | |
235 | SEND_LITERAL ("FAILOEM Command not recognised.");\r | |
236 | } else if (Status == EFI_DEVICE_ERROR) {\r | |
237 | SEND_LITERAL ("FAILError while executing command");\r | |
238 | } else if (EFI_ERROR (Status)) {\r | |
239 | SEND_LITERAL ("FAIL");\r | |
240 | } else {\r | |
241 | SEND_LITERAL ("OKAY");\r | |
242 | }\r | |
243 | }\r | |
244 | \r | |
245 | STATIC\r | |
246 | VOID\r | |
247 | AcceptCmd (\r | |
248 | IN UINTN Size,\r | |
e7108d0e | 249 | IN CONST CHAR8 *Data\r |
f6755908 OM |
250 | )\r |
251 | {\r | |
e7108d0e | 252 | CHAR8 Command[FASTBOOT_COMMAND_MAX_LENGTH + 1];\r |
f6755908 OM |
253 | \r |
254 | // Max command size is 64 bytes\r | |
255 | if (Size > FASTBOOT_COMMAND_MAX_LENGTH) {\r | |
256 | SEND_LITERAL ("FAILCommand too large");\r | |
257 | return;\r | |
258 | }\r | |
259 | \r | |
260 | // Commands aren't null-terminated. Let's get a null-terminated version.\r | |
31090876 | 261 | AsciiStrnCpyS (Command, sizeof Command, Data, Size);\r |
f6755908 OM |
262 | \r |
263 | // Parse command\r | |
264 | if (MATCH_CMD_LITERAL ("getvar", Command)) {\r | |
265 | HandleGetVar (Command + sizeof ("getvar"));\r | |
266 | } else if (MATCH_CMD_LITERAL ("download", Command)) {\r | |
267 | HandleDownload (Command + sizeof ("download"));\r | |
268 | } else if (MATCH_CMD_LITERAL ("verify", Command)) {\r | |
269 | SEND_LITERAL ("FAILNot supported");\r | |
270 | } else if (MATCH_CMD_LITERAL ("flash", Command)) {\r | |
271 | HandleFlash (Command + sizeof ("flash"));\r | |
272 | } else if (MATCH_CMD_LITERAL ("erase", Command)) {\r | |
273 | HandleErase (Command + sizeof ("erase"));\r | |
274 | } else if (MATCH_CMD_LITERAL ("boot", Command)) {\r | |
275 | HandleBoot ();\r | |
276 | } else if (MATCH_CMD_LITERAL ("continue", Command)) {\r | |
277 | SEND_LITERAL ("OKAY");\r | |
278 | mTextOut->OutputString (mTextOut, L"Received 'continue' command. Exiting Fastboot mode\r\n");\r | |
279 | \r | |
280 | gBS->SignalEvent (mFinishedEvent);\r | |
281 | } else if (MATCH_CMD_LITERAL ("reboot", Command)) {\r | |
282 | if (MATCH_CMD_LITERAL ("reboot-booloader", Command)) {\r | |
283 | // fastboot_protocol.txt:\r | |
284 | // "reboot-bootloader Reboot back into the bootloader."\r | |
285 | // I guess this means reboot back into fastboot mode to save the user\r | |
286 | // having to do whatever they did to get here again.\r | |
287 | // Here we just reboot normally.\r | |
288 | SEND_LITERAL ("INFOreboot-bootloader not supported, rebooting normally.");\r | |
289 | }\r | |
e7108d0e | 290 | \r |
f6755908 OM |
291 | SEND_LITERAL ("OKAY");\r |
292 | gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r | |
293 | \r | |
294 | // Shouldn't get here\r | |
a1878955 | 295 | DEBUG ((DEBUG_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));\r |
f6755908 OM |
296 | } else if (MATCH_CMD_LITERAL ("powerdown", Command)) {\r |
297 | SEND_LITERAL ("OKAY");\r | |
298 | gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r | |
299 | \r | |
300 | // Shouldn't get here\r | |
a1878955 | 301 | DEBUG ((DEBUG_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));\r |
f6755908 OM |
302 | } else if (MATCH_CMD_LITERAL ("oem", Command)) {\r |
303 | // The "oem" command isn't in the specification, but it was observed in the\r | |
304 | // wild, followed by a space, followed by the actual command.\r | |
305 | HandleOemCommand (Command + sizeof ("oem"));\r | |
306 | } else if (IS_LOWERCASE_ASCII (Command[0])) {\r | |
307 | // Commands starting with lowercase ASCII characters are reserved for the\r | |
308 | // Fastboot protocol. If we don't recognise it, it's probably the future\r | |
c6a72cd7 | 309 | // and there are new commands in the protocol.\r |
f6755908 OM |
310 | // (By the way, the "oem" command mentioned above makes this reservation\r |
311 | // redundant, but we handle it here to be spec-compliant)\r | |
312 | SEND_LITERAL ("FAILCommand not recognised. Check Fastboot version.");\r | |
313 | } else {\r | |
314 | HandleOemCommand (Command);\r | |
315 | }\r | |
316 | }\r | |
317 | \r | |
318 | STATIC\r | |
319 | VOID\r | |
320 | AcceptData (\r | |
321 | IN UINTN Size,\r | |
e7108d0e | 322 | IN VOID *Data\r |
f6755908 OM |
323 | )\r |
324 | {\r | |
e7108d0e MK |
325 | UINT32 RemainingBytes = mNumDataBytes - mBytesReceivedSoFar;\r |
326 | CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];\r | |
327 | STATIC UINTN Count = 0;\r | |
f6755908 OM |
328 | \r |
329 | // Protocol doesn't say anything about sending extra data so just ignore it.\r | |
330 | if (Size > RemainingBytes) {\r | |
331 | Size = RemainingBytes;\r | |
332 | }\r | |
333 | \r | |
334 | CopyMem (&mDataBuffer[mBytesReceivedSoFar], Data, Size);\r | |
335 | \r | |
336 | mBytesReceivedSoFar += Size;\r | |
337 | \r | |
338 | // Show download progress. Don't do it for every packet as outputting text\r | |
339 | // might be time consuming - do it on the last packet and on every 32nd packet\r | |
e7108d0e | 340 | if (((Count++ % 32) == 0) || (Size == RemainingBytes)) {\r |
f6755908 OM |
341 | // (Note no newline in format string - it will overwrite the line each time)\r |
342 | UnicodeSPrint (\r | |
343 | OutputString,\r | |
344 | sizeof (OutputString),\r | |
345 | L"\r%8d / %8d bytes downloaded (%d%%)",\r | |
346 | mBytesReceivedSoFar,\r | |
347 | mNumDataBytes,\r | |
348 | (mBytesReceivedSoFar * 100) / mNumDataBytes // percentage\r | |
349 | );\r | |
350 | mTextOut->OutputString (mTextOut, OutputString);\r | |
351 | }\r | |
352 | \r | |
353 | if (mBytesReceivedSoFar == mNumDataBytes) {\r | |
354 | // Download finished.\r | |
355 | \r | |
356 | mTextOut->OutputString (mTextOut, L"\r\n");\r | |
357 | SEND_LITERAL ("OKAY");\r | |
358 | mState = ExpectCmdState;\r | |
359 | }\r | |
360 | }\r | |
361 | \r | |
362 | /*\r | |
363 | This is the NotifyFunction passed to CreateEvent in the FastbootAppEntryPoint\r | |
364 | It will be called by the UEFI event framework when the transport protocol\r | |
365 | implementation signals that data has been received from the Fastboot host.\r | |
366 | The parameters are ignored.\r | |
367 | */\r | |
368 | STATIC\r | |
369 | VOID\r | |
370 | DataReady (\r | |
371 | IN EFI_EVENT Event,\r | |
e7108d0e | 372 | IN VOID *Context\r |
f6755908 OM |
373 | )\r |
374 | {\r | |
375 | UINTN Size;\r | |
e7108d0e | 376 | VOID *Data;\r |
f6755908 OM |
377 | EFI_STATUS Status;\r |
378 | \r | |
379 | do {\r | |
380 | Status = mTransport->Receive (&Size, &Data);\r | |
381 | if (!EFI_ERROR (Status)) {\r | |
382 | if (mState == ExpectCmdState) {\r | |
e7108d0e | 383 | AcceptCmd (Size, (CHAR8 *)Data);\r |
f6755908 OM |
384 | } else if (mState == ExpectDataState) {\r |
385 | AcceptData (Size, Data);\r | |
386 | } else {\r | |
387 | ASSERT (FALSE);\r | |
388 | }\r | |
e7108d0e | 389 | \r |
f6755908 OM |
390 | FreePool (Data);\r |
391 | }\r | |
392 | } while (!EFI_ERROR (Status));\r | |
393 | \r | |
394 | // Quit if there was a fatal error\r | |
395 | if (Status != EFI_NOT_READY) {\r | |
396 | ASSERT (Status == EFI_DEVICE_ERROR);\r | |
397 | // (Put a newline at the beginning as we are probably in the data phase,\r | |
398 | // so the download progress line, with no '\n' is probably on the console)\r | |
399 | mTextOut->OutputString (mTextOut, L"\r\nFatal error receiving data. Exiting.\r\n");\r | |
400 | gBS->SignalEvent (mFinishedEvent);\r | |
401 | }\r | |
402 | }\r | |
403 | \r | |
404 | /*\r | |
405 | Event notify for a fatal error in transmission.\r | |
406 | */\r | |
407 | STATIC\r | |
408 | VOID\r | |
409 | FatalErrorNotify (\r | |
410 | IN EFI_EVENT Event,\r | |
e7108d0e | 411 | IN VOID *Context\r |
f6755908 OM |
412 | )\r |
413 | {\r | |
414 | mTextOut->OutputString (mTextOut, L"Fatal error sending command response. Exiting.\r\n");\r | |
415 | gBS->SignalEvent (mFinishedEvent);\r | |
416 | }\r | |
417 | \r | |
418 | EFI_STATUS\r | |
419 | EFIAPI\r | |
420 | FastbootAppEntryPoint (\r | |
e7108d0e MK |
421 | IN EFI_HANDLE ImageHandle,\r |
422 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
f6755908 OM |
423 | )\r |
424 | {\r | |
425 | EFI_STATUS Status;\r | |
426 | EFI_EVENT ReceiveEvent;\r | |
427 | EFI_EVENT WaitEventArray[2];\r | |
428 | UINTN EventIndex;\r | |
e7108d0e | 429 | EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r |
68617659 | 430 | EFI_INPUT_KEY Key;\r |
f6755908 OM |
431 | \r |
432 | mDataBuffer = NULL;\r | |
433 | \r | |
434 | Status = gBS->LocateProtocol (\r | |
e7108d0e MK |
435 | &gAndroidFastbootTransportProtocolGuid,\r |
436 | NULL,\r | |
437 | (VOID **)&mTransport\r | |
438 | );\r | |
f6755908 | 439 | if (EFI_ERROR (Status)) {\r |
a1878955 | 440 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't open Fastboot Transport Protocol: %r\n", Status));\r |
f6755908 OM |
441 | return Status;\r |
442 | }\r | |
443 | \r | |
e7108d0e | 444 | Status = gBS->LocateProtocol (&gAndroidFastbootPlatformProtocolGuid, NULL, (VOID **)&mPlatform);\r |
f6755908 | 445 | if (EFI_ERROR (Status)) {\r |
a1878955 | 446 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't open Fastboot Platform Protocol: %r\n", Status));\r |
f6755908 OM |
447 | return Status;\r |
448 | }\r | |
449 | \r | |
450 | Status = mPlatform->Init ();\r | |
451 | if (EFI_ERROR (Status)) {\r | |
a1878955 | 452 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't initialise Fastboot Platform Protocol: %r\n", Status));\r |
f6755908 OM |
453 | return Status;\r |
454 | }\r | |
455 | \r | |
e7108d0e | 456 | Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **)&mTextOut);\r |
f6755908 | 457 | if (EFI_ERROR (Status)) {\r |
e7108d0e MK |
458 | DEBUG ((\r |
459 | DEBUG_ERROR,\r | |
460 | "Fastboot: Couldn't open Text Output Protocol: %r\n",\r | |
461 | Status\r | |
f6755908 OM |
462 | ));\r |
463 | return Status;\r | |
464 | }\r | |
465 | \r | |
e7108d0e | 466 | Status = gBS->LocateProtocol (&gEfiSimpleTextInProtocolGuid, NULL, (VOID **)&TextIn);\r |
f6755908 | 467 | if (EFI_ERROR (Status)) {\r |
a1878955 | 468 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't open Text Input Protocol: %r\n", Status));\r |
f6755908 OM |
469 | return Status;\r |
470 | }\r | |
471 | \r | |
472 | // Disable watchdog\r | |
473 | Status = gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);\r | |
474 | if (EFI_ERROR (Status)) {\r | |
a1878955 | 475 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't disable watchdog timer: %r\n", Status));\r |
f6755908 OM |
476 | }\r |
477 | \r | |
478 | // Create event for receipt of data from the host\r | |
479 | Status = gBS->CreateEvent (\r | |
480 | EVT_NOTIFY_SIGNAL,\r | |
481 | TPL_CALLBACK,\r | |
482 | DataReady,\r | |
483 | NULL,\r | |
484 | &ReceiveEvent\r | |
485 | );\r | |
486 | ASSERT_EFI_ERROR (Status);\r | |
487 | \r | |
488 | // Create event for exiting application when "continue" command is received\r | |
489 | Status = gBS->CreateEvent (0, TPL_CALLBACK, NULL, NULL, &mFinishedEvent);\r | |
490 | ASSERT_EFI_ERROR (Status);\r | |
491 | \r | |
492 | // Create event to pass to FASTBOOT_TRANSPORT_PROTOCOL.Send, signalling a\r | |
493 | // fatal error\r | |
494 | Status = gBS->CreateEvent (\r | |
e7108d0e MK |
495 | EVT_NOTIFY_SIGNAL,\r |
496 | TPL_CALLBACK,\r | |
497 | FatalErrorNotify,\r | |
498 | NULL,\r | |
499 | &mFatalSendErrorEvent\r | |
500 | );\r | |
f6755908 OM |
501 | ASSERT_EFI_ERROR (Status);\r |
502 | \r | |
f6755908 OM |
503 | // Start listening for data\r |
504 | Status = mTransport->Start (\r | |
e7108d0e MK |
505 | ReceiveEvent\r |
506 | );\r | |
f6755908 | 507 | if (EFI_ERROR (Status)) {\r |
a1878955 | 508 | DEBUG ((DEBUG_ERROR, "Fastboot: Couldn't start transport: %r\n", Status));\r |
f6755908 OM |
509 | return Status;\r |
510 | }\r | |
511 | \r | |
512 | // Talk to the user\r | |
e7108d0e MK |
513 | mTextOut->OutputString (\r |
514 | mTextOut,\r | |
515 | L"Android Fastboot mode - version " ANDROID_FASTBOOT_VERSION ". Press RETURN or SPACE key to quit.\r\n"\r | |
516 | );\r | |
f6755908 OM |
517 | \r |
518 | // Quit when the user presses any key, or mFinishedEvent is signalled\r | |
519 | WaitEventArray[0] = mFinishedEvent;\r | |
520 | WaitEventArray[1] = TextIn->WaitForKey;\r | |
68617659 HZ |
521 | while (1) {\r |
522 | gBS->WaitForEvent (2, WaitEventArray, &EventIndex);\r | |
523 | Status = TextIn->ReadKeyStroke (gST->ConIn, &Key);\r | |
524 | if (Key.ScanCode == SCAN_NULL) {\r | |
525 | if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||\r | |
e7108d0e MK |
526 | (Key.UnicodeChar == L' '))\r |
527 | {\r | |
68617659 HZ |
528 | break;\r |
529 | }\r | |
530 | }\r | |
531 | }\r | |
f6755908 OM |
532 | \r |
533 | mTransport->Stop ();\r | |
534 | if (EFI_ERROR (Status)) {\r | |
a1878955 | 535 | DEBUG ((DEBUG_ERROR, "Warning: Fastboot Transport Stop: %r\n", Status));\r |
f6755908 | 536 | }\r |
e7108d0e | 537 | \r |
f6755908 OM |
538 | mPlatform->UnInit ();\r |
539 | \r | |
540 | return EFI_SUCCESS;\r | |
541 | }\r |