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