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