1 /** @file
2 
3   Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
4   Copyright (c) 2015, Linaro Ltd. All rights reserved.
5   Copyright (c) 2015, Hisilicon Ltd. All rights reserved.
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 /*
18   Implementation of the Android Fastboot Platform protocol, to be used by the
19   Fastboot UEFI application, for Hisilicon HiKey platform.
20 */
21 
22 #include <Protocol/AndroidFastbootPlatform.h>
23 #include <Protocol/BlockIo.h>
24 #include <Protocol/DiskIo.h>
25 #include <Protocol/EraseBlock.h>
26 #include <Protocol/SimpleTextOut.h>
27 
28 #include <Library/BaseLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/DevicePathLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/UefiRuntimeServicesTableLib.h>
35 #include <Library/PrintLib.h>
36 #include <Library/TimerLib.h>
37 
38 #include <Guid/HiKeyVariable.h>
39 
40 #define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \
41                                             sizeof (EFI_DEVICE_PATH_PROTOCOL))
42 
43 #define PARTITION_NAME_MAX_LENGTH 72/2
44 
45 #define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \
46                         ((Char) <= L'Z' && (Char) >= L'Z'))
47 #define IS_HEXCHAR(Char) (((Char) <= L'9' && (Char) >= L'0') || \
48                           IS_ALPHA(Char))
49 
50 #define SERIAL_NUMBER_LENGTH      16
51 #define BOOT_DEVICE_LENGTH        16
52 
53 #define HIKEY_ERASE_SIZE          (16 * 1024 * 1024)
54 #define HIKEY_ERASE_BLOCKS        (HIKEY_ERASE_SIZE / EFI_PAGE_SIZE)
55 
56 typedef struct _FASTBOOT_PARTITION_LIST {
57   LIST_ENTRY  Link;
58   CHAR16      PartitionName[PARTITION_NAME_MAX_LENGTH];
59   EFI_HANDLE  PartitionHandle;
60   EFI_LBA     Lba;
61 } FASTBOOT_PARTITION_LIST;
62 
63 STATIC LIST_ENTRY mPartitionListHead;
64 
65 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
66 
67 /*
68   Helper to free the partition list
69 */
70 STATIC
71 VOID
FreePartitionList(VOID)72 FreePartitionList (
73   VOID
74   )
75 {
76   FASTBOOT_PARTITION_LIST *Entry;
77   FASTBOOT_PARTITION_LIST *NextEntry;
78 
79   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead);
80   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
81     NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link);
82 
83     RemoveEntryList (&Entry->Link);
84     FreePool (Entry);
85 
86     Entry = NextEntry;
87   }
88 }
89 /*
90   Read the PartitionName fields from the GPT partition entries, putting them
91   into an allocated array that should later be freed.
92 */
93 STATIC
94 EFI_STATUS
ReadPartitionEntries(IN EFI_BLOCK_IO_PROTOCOL * BlockIo,OUT EFI_PARTITION_ENTRY ** PartitionEntries)95 ReadPartitionEntries (
96   IN  EFI_BLOCK_IO_PROTOCOL *BlockIo,
97   OUT EFI_PARTITION_ENTRY  **PartitionEntries
98   )
99 {
100   UINTN                       EntrySize;
101   UINTN                       NumEntries;
102   UINTN                       BufferSize;
103   UINT32                      MediaId;
104   EFI_PARTITION_TABLE_HEADER *GptHeader;
105   EFI_STATUS                  Status;
106 
107   MediaId = BlockIo->Media->MediaId;
108 
109   //
110   // Read size of Partition entry and number of entries from GPT header
111   //
112 
113   GptHeader = AllocatePool (BlockIo->Media->BlockSize);
114   if (GptHeader == NULL) {
115     return EFI_OUT_OF_RESOURCES;
116   }
117 
118   Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, (VOID *) GptHeader);
119   if (EFI_ERROR (Status)) {
120     return Status;
121   }
122 
123   // Check there is a GPT on the media
124   if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID ||
125       GptHeader->MyLBA != 1) {
126     DEBUG ((EFI_D_ERROR,
127       "Fastboot platform: No GPT on flash. "
128       "Fastboot on Versatile Express does not support MBR.\n"
129       ));
130     return EFI_DEVICE_ERROR;
131   }
132 
133   EntrySize = GptHeader->SizeOfPartitionEntry;
134   NumEntries = GptHeader->NumberOfPartitionEntries;
135 
136   FreePool (GptHeader);
137 
138   ASSERT (EntrySize != 0);
139   ASSERT (NumEntries != 0);
140 
141   BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize);
142   *PartitionEntries = AllocatePool (BufferSize);
143   if (PartitionEntries == NULL) {
144     return EFI_OUT_OF_RESOURCES;
145   }
146 
147   Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries);
148   if (EFI_ERROR (Status)) {
149     FreePool (PartitionEntries);
150     return Status;
151   }
152 
153   return Status;
154 }
155 
156 
157 /*
158   Initialise: Open the Android NVM device and find the partitions on it. Save them in
159   a list along with the "PartitionName" fields for their GPT entries.
160   We will use these partition names as the key in
161   HiKeyFastbootPlatformFlashPartition.
162 */
163 EFI_STATUS
HiKeyFastbootPlatformInit(VOID)164 HiKeyFastbootPlatformInit (
165   VOID
166   )
167 {
168   EFI_STATUS                          Status;
169   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePath;
170   EFI_DEVICE_PATH_PROTOCOL           *FlashDevicePathDup;
171   EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
172   EFI_DEVICE_PATH_PROTOCOL           *NextNode;
173   HARDDRIVE_DEVICE_PATH              *PartitionNode;
174   UINTN                               NumHandles;
175   EFI_HANDLE                         *AllHandles;
176   UINTN                               LoopIndex;
177   EFI_HANDLE                          FlashHandle;
178   EFI_BLOCK_IO_PROTOCOL              *FlashBlockIo;
179   EFI_PARTITION_ENTRY                *PartitionEntries;
180   FASTBOOT_PARTITION_LIST            *Entry;
181 
182   InitializeListHead (&mPartitionListHead);
183 
184   Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut);
185   if (EFI_ERROR (Status)) {
186     DEBUG ((EFI_D_ERROR,
187       "Fastboot platform: Couldn't open Text Output Protocol: %r\n", Status
188       ));
189     return Status;
190   }
191 
192   //
193   // Get EFI_HANDLES for all the partitions on the block devices pointed to by
194   // PcdFastbootFlashDevicePath, also saving their GPT partition labels.
195   // There's no way to find all of a device's children, so we get every handle
196   // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones
197   // that don't represent partitions on the flash device.
198   //
199 
200   FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath));
201 
202   //
203   // Open the Disk IO protocol on the flash device - this will be used to read
204   // partition names out of the GPT entries
205   //
206   // Create another device path pointer because LocateDevicePath will modify it.
207   FlashDevicePathDup = FlashDevicePath;
208   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle);
209   if (EFI_ERROR (Status)) {
210     DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status));
211     // Failing to locate partitions should not prevent to do other Android FastBoot actions
212     return EFI_SUCCESS;
213   }
214 
215   Status = gBS->OpenProtocol (
216                   FlashHandle,
217                   &gEfiBlockIoProtocolGuid,
218                   (VOID **) &FlashBlockIo,
219                   gImageHandle,
220                   NULL,
221                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
222                   );
223   if (EFI_ERROR (Status)) {
224     DEBUG ((EFI_D_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status));
225     return EFI_DEVICE_ERROR;
226   }
227 
228   // Read the GPT partition entry array into memory so we can get the partition names
229   Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries);
230   if (EFI_ERROR (Status)) {
231     DEBUG ((EFI_D_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status));
232     // Failing to locate partitions should not prevent to do other Android FastBoot actions
233     return EFI_SUCCESS;
234   }
235 
236   // Get every Block IO protocol instance installed in the system
237   Status = gBS->LocateHandleBuffer (
238                   ByProtocol,
239                   &gEfiBlockIoProtocolGuid,
240                   NULL,
241                   &NumHandles,
242                   &AllHandles
243                   );
244   ASSERT_EFI_ERROR (Status);
245 
246   // Filter out handles that aren't children of the flash device
247   for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) {
248     // Get the device path for the handle
249     Status = gBS->OpenProtocol (
250                     AllHandles[LoopIndex],
251                     &gEfiDevicePathProtocolGuid,
252                     (VOID **) &DevicePath,
253                     gImageHandle,
254                     NULL,
255                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
256                     );
257     ASSERT_EFI_ERROR (Status);
258 
259     // Check if it is a sub-device of the flash device
260     if (!CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) {
261       // Device path starts with path of flash device. Check it isn't the flash
262       // device itself.
263       NextNode = NextDevicePathNode (DevicePath);
264       if (IsDevicePathEndType (NextNode)) {
265         // Create entry
266         Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
267         if (Entry == NULL) {
268           Status = EFI_OUT_OF_RESOURCES;
269           FreePartitionList ();
270           goto Exit;
271         }
272 
273         // Copy handle and partition name
274         Entry->PartitionHandle = AllHandles[LoopIndex];
275         StrCpy (Entry->PartitionName, L"ptable");
276         InsertTailList (&mPartitionListHead, &Entry->Link);
277         continue;
278       }
279 
280       // Assert that this device path node represents a partition.
281       ASSERT (NextNode->Type == MEDIA_DEVICE_PATH &&
282               NextNode->SubType == MEDIA_HARDDRIVE_DP);
283 
284       PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode;
285 
286       // Assert that the partition type is GPT. ReadPartitionEntries checks for
287       // presence of a GPT, so we should never find MBR partitions.
288       // ("MBRType" is a misnomer - this field is actually called "Partition
289       //  Format")
290       ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER);
291 
292       // The firmware may install a handle for "partition 0", representing the
293       // whole device. Ignore it.
294       if (PartitionNode->PartitionNumber == 0) {
295         continue;
296       }
297 
298       //
299       // Add the partition handle to the list
300       //
301 
302       // Create entry
303       Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST));
304       if (Entry == NULL) {
305         Status = EFI_OUT_OF_RESOURCES;
306         FreePartitionList ();
307         goto Exit;
308       }
309 
310       // Copy handle and partition name
311       Entry->PartitionHandle = AllHandles[LoopIndex];
312       StrnCpy (
313         Entry->PartitionName,
314         PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1.
315         PARTITION_NAME_MAX_LENGTH
316         );
317       Entry->Lba = PartitionEntries[PartitionNode->PartitionNumber - 1].StartingLBA;
318       InsertTailList (&mPartitionListHead, &Entry->Link);
319 
320       // Print a debug message if the partition label is empty or looks like
321       // garbage.
322       if (!IS_ALPHA (Entry->PartitionName[0])) {
323         DEBUG ((EFI_D_ERROR,
324           "Warning: Partition %d doesn't seem to have a GPT partition label. "
325           "You won't be able to flash it with Fastboot.\n",
326           PartitionNode->PartitionNumber
327           ));
328       }
329     }
330   }
331 
332 Exit:
333   FreePool (PartitionEntries);
334   FreePool (FlashDevicePath);
335   FreePool (AllHandles);
336   return Status;
337 
338 }
339 
340 VOID
HiKeyFastbootPlatformUnInit(VOID)341 HiKeyFastbootPlatformUnInit (
342   VOID
343   )
344 {
345   FreePartitionList ();
346 }
347 
348 EFI_STATUS
HiKeyFastbootPlatformFlashPartition(IN CHAR8 * PartitionName,IN UINTN Size,IN VOID * Image)349 HiKeyFastbootPlatformFlashPartition (
350   IN CHAR8  *PartitionName,
351   IN UINTN   Size,
352   IN VOID   *Image
353   )
354 {
355   EFI_STATUS               Status;
356   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
357   EFI_DISK_IO_PROTOCOL    *DiskIo;
358   UINT32                   MediaId;
359   UINTN                    PartitionSize;
360   FASTBOOT_PARTITION_LIST *Entry;
361   CHAR16                   PartitionNameUnicode[60];
362   BOOLEAN                  PartitionFound;
363   SPARSE_HEADER           *SparseHeader;
364   CHUNK_HEADER            *ChunkHeader;
365   UINTN                    Offset = 0;
366   UINT32                   Chunk, EntrySize, EntryOffset;
367   UINT32                  *FillVal, TmpCount, FillBuf[1024];
368   VOID                    *Buffer;
369 
370 
371   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
372 
373   PartitionFound = FALSE;
374   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
375   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
376     // Search the partition list for the partition named by PartitionName
377     if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
378       PartitionFound = TRUE;
379       break;
380     }
381 
382    Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
383   }
384   if (!PartitionFound) {
385     return EFI_NOT_FOUND;
386   }
387 
388   Status = gBS->OpenProtocol (
389                   Entry->PartitionHandle,
390                   &gEfiBlockIoProtocolGuid,
391                   (VOID **) &BlockIo,
392                   gImageHandle,
393                   NULL,
394                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
395                   );
396   if (EFI_ERROR (Status)) {
397     DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
398     return EFI_NOT_FOUND;
399   }
400 
401   SparseHeader=(SPARSE_HEADER *)Image;
402 
403   if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {
404     DEBUG ((EFI_D_INFO, "Sparse Magic: 0x%x Major: %d Minor: %d fhs: %d chs: %d bs: %d tbs: %d tcs: %d checksum: %d \n",
405                 SparseHeader->Magic, SparseHeader->MajorVersion, SparseHeader->MinorVersion,  SparseHeader->FileHeaderSize,
406                 SparseHeader->ChunkHeaderSize, SparseHeader->BlockSize, SparseHeader->TotalBlocks,
407                 SparseHeader->TotalChunks, SparseHeader->ImageChecksum));
408     if (SparseHeader->MajorVersion != 1) {
409         DEBUG ((EFI_D_ERROR, "Sparse image version %d.%d not supported.\n",
410                     SparseHeader->MajorVersion, SparseHeader->MinorVersion));
411         return EFI_INVALID_PARAMETER;
412     }
413 
414     Size = SparseHeader->BlockSize * SparseHeader->TotalBlocks;
415   }
416 
417   // Check image will fit on device
418   PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
419   if (PartitionSize < Size) {
420     DEBUG ((EFI_D_ERROR, "Partition not big enough.\n"));
421     DEBUG ((EFI_D_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size));
422 
423     return EFI_VOLUME_FULL;
424   }
425 
426   MediaId = BlockIo->Media->MediaId;
427 
428   Status = gBS->OpenProtocol (
429                   Entry->PartitionHandle,
430                   &gEfiDiskIoProtocolGuid,
431                   (VOID **) &DiskIo,
432                   gImageHandle,
433                   NULL,
434                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
435                   );
436   ASSERT_EFI_ERROR (Status);
437 
438   if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) {
439     CHAR16 OutputString[64];
440     UINTN ChunkPrintDensity =
441         SparseHeader->TotalChunks > 1600 ? SparseHeader->TotalChunks / 200 : 32;
442 
443     Image += SparseHeader->FileHeaderSize;
444     for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) {
445       UINTN WriteSize;
446       ChunkHeader = (CHUNK_HEADER *)Image;
447 
448       // Show progress. Don't do it for every packet as outputting text
449       // might be time consuming. ChunkPrintDensity is calculated to
450       // provide an update every half percent change for large
451       // downloads.
452       if (Chunk % ChunkPrintDensity == 0) {
453         UnicodeSPrint(OutputString, sizeof(OutputString),
454                       L"\r%5d / %5d chunks written (%d%%)", Chunk,
455                       SparseHeader->TotalChunks,
456                      (Chunk * 100) / SparseHeader->TotalChunks);
457         mTextOut->OutputString(mTextOut, OutputString);
458       }
459 
460       DEBUG ((EFI_D_INFO, "Chunk #%d - Type: 0x%x Size: %d TotalSize: %d Offset %d\n",
461                   (Chunk+1), ChunkHeader->ChunkType, ChunkHeader->ChunkSize,
462                   ChunkHeader->TotalSize, Offset));
463       Image += sizeof(CHUNK_HEADER);
464       WriteSize=(SparseHeader->BlockSize) * ChunkHeader->ChunkSize;
465       switch (ChunkHeader->ChunkType) {
466         case CHUNK_TYPE_RAW:
467           DEBUG ((EFI_D_INFO, "Writing %d at Offset %d\n", WriteSize, Offset));
468           Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset, WriteSize, Image);
469           if (EFI_ERROR (Status)) {
470             return Status;
471           }
472           Image+=WriteSize;
473           break;
474         case CHUNK_TYPE_FILL:
475           //Assume fillVal is 0, and we can skip here
476           FillVal = (UINT32 *)Image;
477           Image += sizeof(UINT32);
478           if (*FillVal != 0){
479             mTextOut->OutputString(mTextOut, OutputString);
480             for(TmpCount = 0; TmpCount < 1024; TmpCount++){
481                 FillBuf[TmpCount] = *FillVal;
482             }
483             for (TmpCount= 0; TmpCount < WriteSize; TmpCount += sizeof(FillBuf)) {
484                 if ((WriteSize - TmpCount) < sizeof(FillBuf)) {
485                   Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset + TmpCount, WriteSize - TmpCount, FillBuf);
486                 } else {
487                   Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset + TmpCount, sizeof(FillBuf), FillBuf);
488                 }
489                 if (EFI_ERROR (Status)) {
490                     return Status;
491                 }
492             }
493           }
494           break;
495         case CHUNK_TYPE_DONT_CARE:
496           break;
497         case CHUNK_TYPE_CRC32:
498           break;
499         default:
500           DEBUG ((EFI_D_ERROR, "Unknown Chunk Type: 0x%x", ChunkHeader->ChunkType));
501           return EFI_PROTOCOL_ERROR;
502       }
503       Offset += WriteSize;
504     }
505 
506     UnicodeSPrint(OutputString, sizeof(OutputString),
507                   L"\r%5d / %5d chunks written (100%%)\r\n",
508                   SparseHeader->TotalChunks, SparseHeader->TotalChunks);
509     mTextOut->OutputString(mTextOut, OutputString);
510   } else {
511     if (AsciiStrCmp (PartitionName, "ptable") == 0) {
512       Buffer = Image;
513       if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) {
514         DEBUG ((EFI_D_ERROR, "unknown ptable image\n"));
515         return EFI_UNSUPPORTED;
516       }
517       Buffer += 8;
518       if (AsciiStrnCmp (Buffer, "primary", 7) != 0) {
519         DEBUG ((EFI_D_ERROR, "unknown ptable image\n"));
520         return EFI_UNSUPPORTED;
521       }
522       Buffer += 8;
523       EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
524       Buffer += 4;
525       EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
526       if ((EntrySize + 512) > Size) {
527         DEBUG ((EFI_D_ERROR, "Entry size doesn't match\n"));
528         return EFI_UNSUPPORTED;
529       }
530       Buffer = Image + 512;
531       Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);
532       if (EFI_ERROR (Status)) {
533         return Status;
534       }
535 
536       Buffer = Image + 16 + 12;
537       if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0)
538         return Status;
539       Buffer += 8;
540       if (AsciiStrnCmp (Buffer, "second", 6) != 0)
541         return Status;
542       Buffer += 8;
543       EntryOffset = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
544       Buffer += 4;
545       EntrySize = *(UINT32 *)Buffer * BlockIo->Media->BlockSize;
546       if ((EntrySize + 512) > Size) {
547         DEBUG ((EFI_D_ERROR, "Entry size doesn't match\n"));
548         return EFI_UNSUPPORTED;
549       }
550       Buffer = Image + 512;
551       Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer);
552     } else {
553       Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image);
554     }
555     if (EFI_ERROR (Status)) {
556       return Status;
557     }
558   }
559 
560   BlockIo->FlushBlocks(BlockIo);
561   MicroSecondDelay (50000);
562 
563   return Status;
564 }
565 
566 EFI_STATUS
HiKeyFastbootPlatformErasePartition(IN CHAR8 * PartitionName)567 HiKeyFastbootPlatformErasePartition (
568   IN CHAR8 *PartitionName
569   )
570 {
571   EFI_STATUS                Status;
572   EFI_BLOCK_IO_PROTOCOL    *BlockIo;
573   EFI_BLOCK_IO_PROTOCOL    *MmcBlockIo;
574   EFI_ERASE_BLOCK_PROTOCOL *EraseBlockProtocol;
575   UINT32                    MediaId;
576 //  UINTN                    PartitionSize;
577   FASTBOOT_PARTITION_LIST  *Entry;
578   CHAR16                    PartitionNameUnicode[60];
579   BOOLEAN                   PartitionFound;
580   UINTN                     NumHandles;
581   EFI_HANDLE               *BufferHandle;
582 
583   AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode);
584 
585   PartitionFound = FALSE;
586   Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
587   while (!IsNull (&mPartitionListHead, &Entry->Link)) {
588     // Search the partition list for the partition named by PartitionName
589     if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
590       PartitionFound = TRUE;
591       break;
592     }
593 
594    Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
595   }
596   if (!PartitionFound) {
597     return EFI_NOT_FOUND;
598   }
599 
600   Status = gBS->OpenProtocol (
601                   Entry->PartitionHandle,
602                   &gEfiBlockIoProtocolGuid,
603                   (VOID **) &BlockIo,
604                   gImageHandle,
605                   NULL,
606                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
607                   );
608   if (EFI_ERROR (Status)) {
609     DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
610     return EFI_NOT_FOUND;
611   }
612 
613   Status = gBS->LocateProtocol (&gEfiEraseBlockProtocolGuid, NULL, (VOID **) &EraseBlockProtocol);
614   ASSERT_EFI_ERROR (Status);
615 
616   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiEraseBlockProtocolGuid, NULL, &NumHandles, &BufferHandle);
617   ASSERT_EFI_ERROR (Status);
618 
619   Status = gBS->HandleProtocol (
620                   BufferHandle[0],
621                   &gEfiBlockIoProtocolGuid,
622                   (VOID **) &MmcBlockIo
623                   );
624   if (EFI_ERROR (Status)) {
625     DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for MMC device: %r\n", Status));
626     return EFI_NOT_FOUND;
627   }
628 
629   MediaId = BlockIo->Media->MediaId;
630 
631 
632 //  PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
633 //  if (AsciiStrnCmp (PartitionName, "ptable", 6) == 0) {
634     // partition table (GPT) cost 34 blocks
635 //    PartitionSize = 34 * BlockIo->Media->BlockSize;
636 //  }
637 
638   Status = EraseBlockProtocol->EraseBlocks (MmcBlockIo, MediaId, Entry->Lba, NULL, BlockIo->Media->LastBlock);
639     if (EFI_ERROR (Status)) {
640       DEBUG ((EFI_D_ERROR, "%a: Fail to erase at address 0x%x\n", __func__, Entry->Lba));
641     }
642   return Status;
643 }
644 
645 EFI_STATUS
HiKeyFastbootPlatformGetVar(IN CHAR8 * Name,OUT CHAR8 * Value)646 HiKeyFastbootPlatformGetVar (
647   IN  CHAR8   *Name,
648   OUT CHAR8   *Value
649   )
650 {
651   EFI_STATUS               Status;
652   EFI_BLOCK_IO_PROTOCOL   *BlockIo;
653   UINT64                   PartitionSize;
654   FASTBOOT_PARTITION_LIST *Entry;
655   CHAR16                   PartitionNameUnicode[60];
656   BOOLEAN                  PartitionFound;
657   CHAR16                   DataUnicode[17];
658   UINTN                    VariableSize;
659 
660   if (!AsciiStrCmp (Name, "max-download-size")) {
661     AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit));
662   } else if (!AsciiStrCmp (Name, "product")) {
663     AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor));
664   } else if (!AsciiStrCmp (Name, "serialno")) {
665     VariableSize = 17 * sizeof (CHAR16);
666     Status = gRT->GetVariable (
667                     (CHAR16 *)L"SerialNo",
668                     &gHiKeyVariableGuid,
669                     NULL,
670                     &VariableSize,
671                     &DataUnicode
672                     );
673     if (EFI_ERROR (Status)) {
674       *Value = '\0';
675       return EFI_NOT_FOUND;
676     }
677     DataUnicode[(VariableSize / sizeof(CHAR16)) - 1] = '\0';
678     UnicodeStrToAsciiStr (DataUnicode, Value);
679   } else if ( !AsciiStrnCmp (Name, "partition-size", 14)) {
680     AsciiStrToUnicodeStr ((Name + 15), PartitionNameUnicode);
681     PartitionFound = FALSE;
682     Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead));
683     while (!IsNull (&mPartitionListHead, &Entry->Link)) {
684       // Search the partition list for the partition named by PartitionName
685       if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) {
686         PartitionFound = TRUE;
687         break;
688       }
689 
690      Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link);
691     }
692     if (!PartitionFound) {
693       *Value = '\0';
694       return EFI_NOT_FOUND;
695     }
696 
697     Status = gBS->OpenProtocol (
698                     Entry->PartitionHandle,
699                     &gEfiBlockIoProtocolGuid,
700                     (VOID **) &BlockIo,
701                     gImageHandle,
702                     NULL,
703                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
704                     );
705     if (EFI_ERROR (Status)) {
706       DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status));
707       *Value = '\0';
708       return EFI_NOT_FOUND;
709     }
710 
711     PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
712     DEBUG ((EFI_D_ERROR, "Fastboot platform: check for partition-size:%a 0X%llx\n", Name, PartitionSize ));
713     AsciiSPrint (Value, 12, "0x%llx", PartitionSize);
714   } else if ( !AsciiStrnCmp (Name, "partition-type", 14)) {
715       DEBUG ((EFI_D_ERROR, "Fastboot platform: check for partition-type:%a\n", (Name + 15) ));
716     if ( !AsciiStrnCmp  ( (Name + 15) , "system", 6) || !AsciiStrnCmp  ( (Name + 15) , "userdata", 8)
717             || !AsciiStrnCmp  ( (Name + 15) , "cache", 5)) {
718       AsciiStrCpy (Value, "ext4");
719     } else {
720       AsciiStrCpy (Value, "raw");
721     }
722   } else {
723     *Value = '\0';
724   }
725   return EFI_SUCCESS;
726 }
727 
728 EFI_STATUS
HiKeyFastbootPlatformOemCommand(IN CHAR8 * Command)729 HiKeyFastbootPlatformOemCommand (
730   IN  CHAR8   *Command
731   )
732 {
733   CHAR16     CommandUnicode[65];
734   UINTN      Index = 0, VariableSize;
735   UINT16     AutoBoot, Data;
736   EFI_STATUS Status;
737 
738   if (AsciiStrCmp (Command, "Demonstrate") == 0) {
739     DEBUG ((EFI_D_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n"));
740     return EFI_SUCCESS;
741   } else if (AsciiStrnCmp (Command, "autoboot", AsciiStrLen ("autoboot")) == 0) {
742     Index += sizeof ("autoboot");
743     while (TRUE) {
744       if (Command[Index] == '\0')
745         goto out;
746       else if (Command[Index] == ' ')
747         Index++;
748       else
749         break;
750     }
751     Data = AsciiStrDecimalToUintn (Command + Index);
752 
753     VariableSize = sizeof (UINT16);
754     Status = gRT->GetVariable (
755                     (CHAR16 *)L"HiKeyAutoBoot",
756                     &gHiKeyVariableGuid,
757                     NULL,
758                     &VariableSize,
759                     &AutoBoot
760                     );
761     if ((EFI_ERROR (Status) == 0) && (AutoBoot == Data)) {
762       return EFI_SUCCESS;
763     }
764     AutoBoot = Data;
765     Status = gRT->SetVariable (
766                     (CHAR16*)L"HiKeyAutoBoot",
767                     &gHiKeyVariableGuid,
768                     EFI_VARIABLE_NON_VOLATILE       |
769                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
770                     EFI_VARIABLE_RUNTIME_ACCESS,
771                     sizeof (UINT16),
772                     &AutoBoot
773                     );
774     return Status;
775   } else {
776     AsciiStrToUnicodeStr (Command + Index, CommandUnicode);
777     DEBUG ((EFI_D_ERROR,
778       "HiKey: Unrecognised Fastboot OEM command: %s\n",
779       CommandUnicode
780       ));
781     return EFI_NOT_FOUND;
782   }
783 out:
784   return EFI_NOT_FOUND;
785 }
786 
787 FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = {
788   HiKeyFastbootPlatformInit,
789   HiKeyFastbootPlatformUnInit,
790   HiKeyFastbootPlatformFlashPartition,
791   HiKeyFastbootPlatformErasePartition,
792   HiKeyFastbootPlatformGetVar,
793   HiKeyFastbootPlatformOemCommand
794 };
795 
796 EFI_STATUS
797 EFIAPI
HiKeyFastbootPlatformEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)798 HiKeyFastbootPlatformEntryPoint (
799   IN EFI_HANDLE                            ImageHandle,
800   IN EFI_SYSTEM_TABLE                      *SystemTable
801   )
802 {
803   return gBS->InstallProtocolInterface (
804                 &ImageHandle,
805                 &gAndroidFastbootPlatformProtocolGuid,
806                 EFI_NATIVE_INTERFACE,
807                 &mPlatformProtocol
808                 );
809 }
810