1 /** @file
2
3 Copyright (c) 2013-2014, 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 <Protocol/AndroidFastbootTransport.h>
16 #include <Protocol/AndroidFastbootPlatform.h>
17 #include <Protocol/SimpleTextOut.h>
18 #include <Protocol/SimpleTextIn.h>
19
20 #include <Library/AbootimgLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/UefiApplicationEntryPoint.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
27
28 #define ANDROID_FASTBOOT_VERSION "0.7"
29
30 #define SPARSE_HEADER_MAGIC 0xED26FF3A
31 #define CHUNK_TYPE_RAW 0xCAC1
32 #define CHUNK_TYPE_FILL 0xCAC2
33 #define CHUNK_TYPE_DONT_CARE 0xCAC3
34 #define CHUNK_TYPE_CRC32 0xCAC4
35
36 #define FILL_BUF_SIZE (16 * 1024 * 1024)
37 #define SPARSE_BLOCK_SIZE 4096
38
39 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
40
41 #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
42
43 typedef struct _SPARSE_HEADER {
44 UINT32 Magic;
45 UINT16 MajorVersion;
46 UINT16 MinorVersion;
47 UINT16 FileHeaderSize;
48 UINT16 ChunkHeaderSize;
49 UINT32 BlockSize;
50 UINT32 TotalBlocks;
51 UINT32 TotalChunks;
52 UINT32 ImageChecksum;
53 } SPARSE_HEADER;
54
55 typedef struct _CHUNK_HEADER {
56 UINT16 ChunkType;
57 UINT16 Reserved1;
58 UINT32 ChunkSize;
59 UINT32 TotalSize;
60 } CHUNK_HEADER;
61
62 /*
63 * UEFI Application using the FASTBOOT_TRANSPORT_PROTOCOL and
64 * FASTBOOT_PLATFORM_PROTOCOL to implement the Android Fastboot protocol.
65 */
66
67 STATIC FASTBOOT_TRANSPORT_PROTOCOL *mTransport;
68 STATIC FASTBOOT_PLATFORM_PROTOCOL *mPlatform;
69
70 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
71
72 typedef enum {
73 ExpectCmdState,
74 ExpectDataState,
75 FastbootStateMax
76 } ANDROID_FASTBOOT_STATE;
77
78 STATIC ANDROID_FASTBOOT_STATE mState = ExpectCmdState;
79
80 // When in ExpectDataState, the number of bytes of data to expect:
81 STATIC UINT64 mNumDataBytes;
82 // .. and the number of bytes so far received this data phase
83 STATIC UINT64 mBytesReceivedSoFar;
84 // .. and the buffer to save data into
85 STATIC UINT8 *mDataBuffer = NULL;
86
87 // Event notify functions, from which gBS->Exit shouldn't be called, can signal
88 // this event when the application should exit
89 STATIC EFI_EVENT mFinishedEvent;
90
91 STATIC EFI_EVENT mFatalSendErrorEvent;
92
93 // This macro uses sizeof - only use it on arrays (i.e. string literals)
94 #define SEND_LITERAL(Str) mTransport->Send ( \
95 sizeof (Str) - 1, \
96 Str, \
97 &mFatalSendErrorEvent \
98 )
99 #define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1)
100
101 #define IS_LOWERCASE_ASCII(Char) (Char >= 'a' && Char <= 'z')
102
103 #define FASTBOOT_STRING_MAX_LENGTH 256
104 #define FASTBOOT_COMMAND_MAX_LENGTH 64
105
106 STATIC
107 VOID
HandleGetVar(IN CHAR8 * CmdArg)108 HandleGetVar (
109 IN CHAR8 *CmdArg
110 )
111 {
112 CHAR8 Response[FASTBOOT_COMMAND_MAX_LENGTH + 1] = "OKAY";
113 EFI_STATUS Status;
114
115 // Respond to getvar:version with 0.4 (version of Fastboot protocol)
116 if (!AsciiStrnCmp ("version", CmdArg, sizeof ("version") - 1 )) {
117 SEND_LITERAL ("OKAY" ANDROID_FASTBOOT_VERSION);
118 } else {
119 // All other variables are assumed to be platform specific
120 Status = mPlatform->GetVar (CmdArg, Response + 4);
121 if (EFI_ERROR (Status)) {
122 SEND_LITERAL ("FAILSomething went wrong when looking up the variable");
123 } else {
124 mTransport->Send (AsciiStrLen (Response), Response, &mFatalSendErrorEvent);
125 }
126 }
127 }
128
129 STATIC
130 VOID
HandleDownload(IN CHAR8 * NumBytesString)131 HandleDownload (
132 IN CHAR8 *NumBytesString
133 )
134 {
135 CHAR8 Response[13];
136 CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
137
138 // Argument is 8-character ASCII string hex representation of number of bytes
139 // that will be sent in the data phase.
140 // Response is "DATA" + that same 8-character string.
141
142 // Replace any previously downloaded data
143 if (mDataBuffer != NULL) {
144 FreePool (mDataBuffer);
145 mDataBuffer = NULL;
146 }
147
148 // Parse out number of data bytes to expect
149 mNumDataBytes = AsciiStrHexToUint64 (NumBytesString);
150 if (mNumDataBytes == 0) {
151 mTextOut->OutputString (mTextOut, L"ERROR: Fail to get the number of bytes to download.\r\n");
152 SEND_LITERAL ("FAILFailed to get the number of bytes to download");
153 return;
154 }
155
156 UnicodeSPrint (OutputString, sizeof (OutputString), L"Downloading %d bytes\r\n", mNumDataBytes);
157 mTextOut->OutputString (mTextOut, OutputString);
158
159 mDataBuffer = AllocatePool (mNumDataBytes);
160 if (mDataBuffer == NULL) {
161 SEND_LITERAL ("FAILNot enough memory");
162 } else {
163 ZeroMem (Response, sizeof Response);
164 if (mTransport->RequestReceive) {
165 mTransport->RequestReceive (mNumDataBytes);
166 }
167 AsciiSPrint (Response, sizeof Response, "DATA%x",
168 (UINT32)mNumDataBytes);
169 mTransport->Send (sizeof Response - 1, Response, &mFatalSendErrorEvent);
170
171 mState = ExpectDataState;
172 mBytesReceivedSoFar = 0;
173 }
174 }
175
176 STATIC
177 EFI_STATUS
FlashSparseImage(IN CHAR8 * PartitionName,IN SPARSE_HEADER * SparseHeader)178 FlashSparseImage (
179 IN CHAR8 *PartitionName,
180 IN SPARSE_HEADER *SparseHeader
181 )
182 {
183 EFI_STATUS Status = EFI_SUCCESS;
184 UINTN Chunk, Offset = 0, Left, Count, FillBufSize;
185 VOID *Image;
186 CHUNK_HEADER *ChunkHeader;
187 VOID *FillBuf;
188 CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
189
190 Image = (VOID *)SparseHeader;
191 Image += SparseHeader->FileHeaderSize;
192
193 // allocate the fill buf with dynamic size
194 FillBufSize = FILL_BUF_SIZE;
195 while (FillBufSize >= SPARSE_BLOCK_SIZE) {
196 FillBuf = AllocatePool (FillBufSize);
197 if (FillBuf == NULL) {
198 FillBufSize = FillBufSize >> 1;
199 } else {
200 break;
201 }
202 };
203 if (FillBufSize < SPARSE_BLOCK_SIZE) {
204 UnicodeSPrint (
205 OutputString,
206 sizeof (OutputString),
207 L"Fail to allocate the fill buffer\n"
208 );
209 mTextOut->OutputString (mTextOut, OutputString);
210 return EFI_BUFFER_TOO_SMALL;
211 }
212
213 for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) {
214 ChunkHeader = (CHUNK_HEADER *)Image;
215 DEBUG ((DEBUG_INFO, "Chunk #%d - Type: 0x%x Size: %d TotalSize: %d Offset %d\n",
216 (Chunk+1), ChunkHeader->ChunkType, ChunkHeader->ChunkSize,
217 ChunkHeader->TotalSize, Offset));
218 Image += sizeof (CHUNK_HEADER);
219 switch (ChunkHeader->ChunkType) {
220 case CHUNK_TYPE_RAW:
221 Status = mPlatform->FlashPartitionEx (
222 PartitionName,
223 Offset,
224 ChunkHeader->ChunkSize * SparseHeader->BlockSize,
225 Image
226 );
227 if (EFI_ERROR (Status)) {
228 return Status;
229 }
230 Image += (UINTN)ChunkHeader->ChunkSize * SparseHeader->BlockSize;
231 Offset += (UINTN)ChunkHeader->ChunkSize * SparseHeader->BlockSize;
232 break;
233 case CHUNK_TYPE_FILL:
234 Left = (UINTN)ChunkHeader->ChunkSize * SparseHeader->BlockSize;
235 while (Left > 0) {
236 if (Left > FILL_BUF_SIZE) {
237 Count = FILL_BUF_SIZE;
238 } else {
239 Count = Left;
240 }
241 SetMem32 (FillBuf, Count, *(UINT32 *)Image);
242 Status = mPlatform->FlashPartitionEx (
243 PartitionName,
244 Offset,
245 Count,
246 FillBuf
247 );
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251 Offset += Count;
252 Left = Left - Count;
253 }
254 Image += sizeof (UINT32);
255 break;
256 case CHUNK_TYPE_DONT_CARE:
257 Offset += (UINTN)ChunkHeader->ChunkSize * SparseHeader->BlockSize;
258 break;
259 default:
260 UnicodeSPrint (
261 OutputString,
262 sizeof (OutputString),
263 L"Unsupported Chunk Type:0x%x\n",
264 ChunkHeader->ChunkType
265 );
266 mTextOut->OutputString (mTextOut, OutputString);
267 break;
268 }
269 }
270 FreePool ((VOID *)FillBuf);
271 return Status;
272 }
273
274 STATIC
275 VOID
HandleFlash(IN CHAR8 * PartitionName)276 HandleFlash (
277 IN CHAR8 *PartitionName
278 )
279 {
280 EFI_STATUS Status;
281 CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
282 SPARSE_HEADER *SparseHeader;
283
284 // Build output string
285 UnicodeSPrint (OutputString, sizeof (OutputString), L"Flashing partition %a\r\n", PartitionName);
286 mTextOut->OutputString (mTextOut, OutputString);
287
288 if (mDataBuffer == NULL) {
289 // Doesn't look like we were sent any data
290 SEND_LITERAL ("FAILNo data to flash");
291 return;
292 }
293
294 SparseHeader = (SPARSE_HEADER *)mDataBuffer;
295 if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {
296 DEBUG ((DEBUG_INFO, "Sparse Magic: 0x%x Major: %d Minor: %d fhs: %d chs: %d bs: %d tbs: %d tcs: %d checksum: %d \n",
297 SparseHeader->Magic, SparseHeader->MajorVersion, SparseHeader->MinorVersion, SparseHeader->FileHeaderSize,
298 SparseHeader->ChunkHeaderSize, SparseHeader->BlockSize, SparseHeader->TotalBlocks,
299 SparseHeader->TotalChunks, SparseHeader->ImageChecksum));
300 if (SparseHeader->MajorVersion != 1) {
301 DEBUG ((DEBUG_ERROR, "Sparse image version %d.%d not supported.\n",
302 SparseHeader->MajorVersion, SparseHeader->MinorVersion));
303 return;
304 }
305 Status = FlashSparseImage (PartitionName, SparseHeader);
306 } else {
307 Status = mPlatform->FlashPartition (
308 PartitionName,
309 mNumDataBytes,
310 mDataBuffer
311 );
312 }
313 switch (Status) {
314 case EFI_SUCCESS:
315 mTextOut->OutputString (mTextOut, L"Done.\r\n");
316 SEND_LITERAL ("OKAY");
317 break;
318 case EFI_NOT_FOUND:
319 SEND_LITERAL ("FAILNo such partition.");
320 mTextOut->OutputString (mTextOut, L"No such partition.\r\n");
321 break;
322 default:
323 SEND_LITERAL ("FAILError flashing partition.");
324 mTextOut->OutputString (mTextOut, L"Error flashing partition.\r\n");
325 DEBUG ((EFI_D_ERROR, "Couldn't flash image:\n"));
326 break;
327 }
328 }
329
330 STATIC
331 VOID
HandleErase(IN CHAR8 * PartitionName)332 HandleErase (
333 IN CHAR8 *PartitionName
334 )
335 {
336 EFI_STATUS Status;
337 CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
338
339 // Build output string
340 UnicodeSPrint (OutputString, sizeof (OutputString), L"Erasing partition %a\r\n", PartitionName);
341 mTextOut->OutputString (mTextOut, OutputString);
342
343 Status = mPlatform->ErasePartition (PartitionName);
344 if (EFI_ERROR (Status)) {
345 SEND_LITERAL ("FAILCheck device console.");
346 DEBUG ((EFI_D_ERROR, "Couldn't erase image: %r\n", Status));
347 } else {
348 SEND_LITERAL ("OKAY");
349 }
350 }
351
352 STATIC
353 VOID
HandleBoot(VOID)354 HandleBoot (
355 VOID
356 )
357 {
358 CHAR16 *BootPathStr;
359
360 mTextOut->OutputString (mTextOut, L"Booting downloaded image\r\n");
361
362 if (mDataBuffer == NULL) {
363 // Doesn't look like we were sent any data
364 SEND_LITERAL ("FAILNo image in memory");
365 return;
366 }
367
368 // We don't really have any choice but to report success, because once we
369 // boot we lose control of the system.
370 SEND_LITERAL ("OKAY");
371
372 BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath);
373 AbootimgBootRam (mDataBuffer, mNumDataBytes, BootPathStr, NULL);
374 // We shouldn't get here
375 }
376
377 STATIC
378 VOID
HandleOemCommand(IN CHAR8 * Command)379 HandleOemCommand (
380 IN CHAR8 *Command
381 )
382 {
383 EFI_STATUS Status;
384
385 Status = mPlatform->DoOemCommand (Command);
386 if (Status == EFI_NOT_FOUND) {
387 SEND_LITERAL ("FAILOEM Command not recognised.");
388 } else if (Status == EFI_DEVICE_ERROR) {
389 SEND_LITERAL ("FAILError while executing command");
390 } else if (EFI_ERROR (Status)) {
391 SEND_LITERAL ("FAIL");
392 } else {
393 SEND_LITERAL ("OKAY");
394 }
395 }
396
397 STATIC
398 VOID
AcceptCmd(IN UINTN Size,IN CONST CHAR8 * Data)399 AcceptCmd (
400 IN UINTN Size,
401 IN CONST CHAR8 *Data
402 )
403 {
404 EFI_STATUS Status;
405 CHAR8 Command[FASTBOOT_COMMAND_MAX_LENGTH + 1];
406
407 // Max command size is 64 bytes
408 if (Size > FASTBOOT_COMMAND_MAX_LENGTH) {
409 SEND_LITERAL ("FAILCommand too large");
410 return;
411 }
412
413 // Commands aren't null-terminated. Let's get a null-terminated version.
414 AsciiStrnCpyS (Command, sizeof Command, Data, Size);
415
416 // Parse command
417 if (MATCH_CMD_LITERAL ("getvar", Command)) {
418 HandleGetVar (Command + sizeof ("getvar"));
419 } else if (MATCH_CMD_LITERAL ("download", Command)) {
420 HandleDownload (Command + sizeof ("download"));
421 } else if (MATCH_CMD_LITERAL ("verify", Command)) {
422 SEND_LITERAL ("FAILNot supported");
423 } else if (MATCH_CMD_LITERAL ("flash", Command)) {
424 HandleFlash (Command + sizeof ("flash"));
425 } else if (MATCH_CMD_LITERAL ("erase", Command)) {
426 HandleErase (Command + sizeof ("erase"));
427 } else if (MATCH_CMD_LITERAL ("boot", Command)) {
428 HandleBoot ();
429 } else if (MATCH_CMD_LITERAL ("continue", Command)) {
430 SEND_LITERAL ("OKAY");
431 mTextOut->OutputString (mTextOut, L"Received 'continue' command. Exiting Fastboot mode\r\n");
432
433 gBS->SignalEvent (mFinishedEvent);
434 } else if (MATCH_CMD_LITERAL ("reboot", Command)) {
435 if (MATCH_CMD_LITERAL ("reboot-bootloader", Command)) {
436 Status = mPlatform->DoOemCommand ("reboot-bootloader");
437 if (EFI_ERROR (Status)) {
438 SEND_LITERAL ("INFOreboot-bootloader not supported, rebooting normally.");
439 }
440 }
441 SEND_LITERAL ("OKAY");
442 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
443
444 // Shouldn't get here
445 DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));
446 } else if (MATCH_CMD_LITERAL ("powerdown", Command)) {
447 SEND_LITERAL ("OKAY");
448 gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
449
450 // Shouldn't get here
451 DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n"));
452 } else if (MATCH_CMD_LITERAL ("oem", Command)) {
453 // The "oem" command isn't in the specification, but it was observed in the
454 // wild, followed by a space, followed by the actual command.
455 HandleOemCommand (Command + sizeof ("oem"));
456 } else if (IS_LOWERCASE_ASCII (Command[0])) {
457 // Commands starting with lowercase ASCII characters are reserved for the
458 // Fastboot protocol. If we don't recognise it, it's probably the future
459 // and there are new commmands in the protocol.
460 // (By the way, the "oem" command mentioned above makes this reservation
461 // redundant, but we handle it here to be spec-compliant)
462 SEND_LITERAL ("FAILCommand not recognised. Check Fastboot version.");
463 } else {
464 HandleOemCommand (Command);
465 }
466 }
467
468 STATIC
469 VOID
AcceptData(IN UINTN Size,IN VOID * Data)470 AcceptData (
471 IN UINTN Size,
472 IN VOID *Data
473 )
474 {
475 UINT32 RemainingBytes = mNumDataBytes - mBytesReceivedSoFar;
476 CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH];
477 STATIC UINTN Count = 0;
478
479 // Protocol doesn't say anything about sending extra data so just ignore it.
480 if (Size > RemainingBytes) {
481 Size = RemainingBytes;
482 }
483
484 CopyMem (&mDataBuffer[mBytesReceivedSoFar], Data, Size);
485
486 mBytesReceivedSoFar += Size;
487
488 // Show download progress. Don't do it for every packet as outputting text
489 // might be time consuming - do it on the last packet and on every 32nd packet
490 if ((Count++ % 32) == 0 || Size == RemainingBytes) {
491 // (Note no newline in format string - it will overwrite the line each time)
492 UnicodeSPrint (
493 OutputString,
494 sizeof (OutputString),
495 L"\r%8d / %8d bytes downloaded (%d%%)",
496 mBytesReceivedSoFar,
497 mNumDataBytes,
498 (mBytesReceivedSoFar * 100) / mNumDataBytes // percentage
499 );
500 mTextOut->OutputString (mTextOut, OutputString);
501 }
502
503 if (mBytesReceivedSoFar == mNumDataBytes) {
504 // Download finished.
505
506 mTextOut->OutputString (mTextOut, L"\r\n");
507 SEND_LITERAL ("OKAY");
508 mState = ExpectCmdState;
509 }
510 }
511
512 /*
513 This is the NotifyFunction passed to CreateEvent in the FastbootAppEntryPoint
514 It will be called by the UEFI event framework when the transport protocol
515 implementation signals that data has been received from the Fastboot host.
516 The parameters are ignored.
517 */
518 STATIC
519 VOID
DataReady(IN EFI_EVENT Event,IN VOID * Context)520 DataReady (
521 IN EFI_EVENT Event,
522 IN VOID *Context
523 )
524 {
525 UINTN Size;
526 VOID *Data;
527 EFI_STATUS Status;
528
529 do {
530 // Indicate lower layer driver that how much bytes are expected.
531 if (mState == ExpectDataState) {
532 Size = mNumDataBytes;
533 } else {
534 Size = 0;
535 }
536 Status = mTransport->Receive (&Size, &Data);
537 if (!EFI_ERROR (Status)) {
538 if (mState == ExpectCmdState) {
539 AcceptCmd (Size, (CHAR8 *) Data);
540 } else if (mState == ExpectDataState) {
541 AcceptData (Size, Data);
542 } else {
543 ASSERT (FALSE);
544 }
545 FreePool (Data);
546 }
547 } while (!EFI_ERROR (Status));
548
549 // Quit if there was a fatal error
550 if (Status != EFI_NOT_READY) {
551 ASSERT (Status == EFI_DEVICE_ERROR);
552 // (Put a newline at the beginning as we are probably in the data phase,
553 // so the download progress line, with no '\n' is probably on the console)
554 mTextOut->OutputString (mTextOut, L"\r\nFatal error receiving data. Exiting.\r\n");
555 gBS->SignalEvent (mFinishedEvent);
556 }
557 }
558
559 /*
560 Event notify for a fatal error in transmission.
561 */
562 STATIC
563 VOID
FatalErrorNotify(IN EFI_EVENT Event,IN VOID * Context)564 FatalErrorNotify (
565 IN EFI_EVENT Event,
566 IN VOID *Context
567 )
568 {
569 mTextOut->OutputString (mTextOut, L"Fatal error sending command response. Exiting.\r\n");
570 gBS->SignalEvent (mFinishedEvent);
571 }
572
573 EFI_STATUS
574 EFIAPI
FastbootAppEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)575 FastbootAppEntryPoint (
576 IN EFI_HANDLE ImageHandle,
577 IN EFI_SYSTEM_TABLE *SystemTable
578 )
579 {
580 EFI_STATUS Status;
581 EFI_EVENT ReceiveEvent;
582 EFI_EVENT WaitEventArray[2];
583 UINTN EventIndex;
584 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
585 EFI_INPUT_KEY Key;
586
587 mDataBuffer = NULL;
588
589 Status = gBS->LocateProtocol (
590 &gAndroidFastbootTransportProtocolGuid,
591 NULL,
592 (VOID **) &mTransport
593 );
594 if (EFI_ERROR (Status)) {
595 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Transport Protocol: %r\n", Status));
596 return Status;
597 }
598
599 Status = gBS->LocateProtocol (&gAndroidFastbootPlatformProtocolGuid, NULL, (VOID **) &mPlatform);
600 if (EFI_ERROR (Status)) {
601 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Platform Protocol: %r\n", Status));
602 return Status;
603 }
604
605 Status = mPlatform->Init ();
606 if (EFI_ERROR (Status)) {
607 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't initialise Fastboot Platform Protocol: %r\n", Status));
608 return Status;
609 }
610
611 Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut);
612 if (EFI_ERROR (Status)) {
613 DEBUG ((EFI_D_ERROR,
614 "Fastboot: Couldn't open Text Output Protocol: %r\n", Status
615 ));
616 return Status;
617 }
618
619 Status = gBS->LocateProtocol (&gEfiSimpleTextInProtocolGuid, NULL, (VOID **) &TextIn);
620 if (EFI_ERROR (Status)) {
621 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Text Input Protocol: %r\n", Status));
622 return Status;
623 }
624
625 // Disable watchdog
626 Status = gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);
627 if (EFI_ERROR (Status)) {
628 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't disable watchdog timer: %r\n", Status));
629 }
630
631 // Create event for receipt of data from the host
632 Status = gBS->CreateEvent (
633 EVT_NOTIFY_SIGNAL,
634 TPL_CALLBACK,
635 DataReady,
636 NULL,
637 &ReceiveEvent
638 );
639 ASSERT_EFI_ERROR (Status);
640
641 // Create event for exiting application when "continue" command is received
642 Status = gBS->CreateEvent (0, TPL_CALLBACK, NULL, NULL, &mFinishedEvent);
643 ASSERT_EFI_ERROR (Status);
644
645 // Create event to pass to FASTBOOT_TRANSPORT_PROTOCOL.Send, signalling a
646 // fatal error
647 Status = gBS->CreateEvent (
648 EVT_NOTIFY_SIGNAL,
649 TPL_CALLBACK,
650 FatalErrorNotify,
651 NULL,
652 &mFatalSendErrorEvent
653 );
654 ASSERT_EFI_ERROR (Status);
655
656
657 // Start listening for data
658 Status = mTransport->Start (
659 ReceiveEvent
660 );
661 if (EFI_ERROR (Status)) {
662 DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't start transport: %r\n", Status));
663 return Status;
664 }
665
666 // Talk to the user
667 mTextOut->OutputString (mTextOut,
668 L"Android Fastboot mode - version " ANDROID_FASTBOOT_VERSION ".\r\n");
669 mTextOut->OutputString (mTextOut, L"Press RETURN or SPACE key to quit.\r\n");
670
671 // Quit when the user presses any key, or mFinishedEvent is signalled
672 WaitEventArray[0] = mFinishedEvent;
673 WaitEventArray[1] = TextIn->WaitForKey;
674 while (1) {
675 gBS->WaitForEvent (2, WaitEventArray, &EventIndex);
676 if (EventIndex == 0) {
677 break;
678 }
679 Status = TextIn->ReadKeyStroke (gST->ConIn, &Key);
680 if (Key.ScanCode == SCAN_NULL) {
681 if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) || (Key.UnicodeChar == ' ')) {
682 break;
683 }
684 }
685 }
686
687 mTransport->Stop ();
688 if (EFI_ERROR (Status)) {
689 DEBUG ((EFI_D_ERROR, "Warning: Fastboot Transport Stop: %r\n", Status));
690 }
691 mPlatform->UnInit ();
692
693 return EFI_SUCCESS;
694 }
695