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 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 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 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 341 HiKeyFastbootPlatformUnInit ( 342 VOID 343 ) 344 { 345 FreePartitionList (); 346 } 347 348 EFI_STATUS 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 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 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 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 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