1 /** @file 2 3 Copyright (c) 2014, ARM Ltd. All rights reserved.<BR> 4 Copyright (c) 2015-2017, Linaro. All rights reserved. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 /* 17 Implementation of the Android Fastboot Platform protocol, to be used by the 18 Fastboot UEFI application, for Hisilicon HiKey platform. 19 */ 20 21 #include <Protocol/AndroidFastbootPlatform.h> 22 #include <Protocol/BlockIo.h> 23 #include <Protocol/DiskIo.h> 24 #include <Protocol/EraseBlock.h> 25 #include <Protocol/SimpleTextOut.h> 26 27 #include <Library/BaseLib.h> 28 #include <Library/BaseMemoryLib.h> 29 #include <Library/CacheMaintenanceLib.h> 30 #include <Library/DebugLib.h> 31 #include <Library/DevicePathLib.h> 32 #include <Library/MemoryAllocationLib.h> 33 #include <Library/IoLib.h> 34 #include <Library/UefiBootServicesTableLib.h> 35 #include <Library/UefiRuntimeServicesTableLib.h> 36 #include <Library/UsbSerialNumberLib.h> 37 #include <Library/PrintLib.h> 38 #include <Library/TimerLib.h> 39 40 #define PARTITION_NAME_MAX_LENGTH (72/2) 41 42 #define SERIAL_NUMBER_LBA 1024 43 #define RANDOM_MAX 0x7FFFFFFFFFFFFFFF 44 #define RANDOM_MAGIC 0x9A4DBEAF 45 46 #define ADB_REBOOT_ADDRESS 0x05F01000 47 #define ADB_REBOOT_BOOTLOADER 0x77665500 48 49 #define MMC_BLOCK_SIZE 512 50 #define HIKEY_ERASE_SIZE 4096 51 52 typedef struct _FASTBOOT_PARTITION_LIST { 53 LIST_ENTRY Link; 54 CHAR16 PartitionName[PARTITION_NAME_MAX_LENGTH]; 55 EFI_LBA StartingLBA; 56 EFI_LBA EndingLBA; 57 } FASTBOOT_PARTITION_LIST; 58 59 STATIC LIST_ENTRY mPartitionListHead; 60 STATIC EFI_HANDLE mFlashHandle; 61 STATIC EFI_BLOCK_IO_PROTOCOL *mFlashBlockIo; 62 STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut; 63 64 /* 65 Helper to free the partition list 66 */ 67 STATIC 68 VOID 69 FreePartitionList ( 70 VOID 71 ) 72 { 73 FASTBOOT_PARTITION_LIST *Entry; 74 FASTBOOT_PARTITION_LIST *NextEntry; 75 76 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead); 77 while (!IsNull (&mPartitionListHead, &Entry->Link)) { 78 NextEntry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link); 79 80 RemoveEntryList (&Entry->Link); 81 FreePool (Entry); 82 83 Entry = NextEntry; 84 } 85 } 86 87 /* 88 Read the PartitionName fields from the GPT partition entries, putting them 89 into an allocated array that should later be freed. 90 */ 91 STATIC 92 EFI_STATUS 93 ReadPartitionEntries ( 94 IN EFI_BLOCK_IO_PROTOCOL *BlockIo, 95 OUT EFI_PARTITION_ENTRY **PartitionEntries, 96 OUT UINTN *PartitionNumbers 97 ) 98 { 99 EFI_STATUS Status; 100 UINT32 MediaId; 101 UINTN BlockSize; 102 UINTN PageCount; 103 UINTN Count, EndLBA; 104 EFI_PARTITION_TABLE_HEADER *GptHeader; 105 EFI_PARTITION_ENTRY *Entry; 106 VOID *Buffer; 107 108 if ((PartitionEntries == NULL) || (PartitionNumbers == NULL)) { 109 return EFI_INVALID_PARAMETER; 110 } 111 112 MediaId = BlockIo->Media->MediaId; 113 BlockSize = BlockIo->Media->BlockSize; 114 115 // 116 // Read size of Partition entry and number of entries from GPT header 117 // 118 119 PageCount = EFI_SIZE_TO_PAGES (34 * BlockSize); 120 Buffer = AllocatePages (PageCount); 121 if (Buffer == NULL) { 122 return EFI_OUT_OF_RESOURCES; 123 } 124 125 Status = BlockIo->ReadBlocks (BlockIo, MediaId, 0, PageCount * EFI_PAGE_SIZE, Buffer); 126 if (EFI_ERROR (Status)) { 127 return Status; 128 } 129 GptHeader = (EFI_PARTITION_TABLE_HEADER *)(Buffer + BlockSize); 130 131 // Check there is a GPT on the media 132 if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID || 133 GptHeader->MyLBA != 1) { 134 DEBUG ((EFI_D_ERROR, 135 "Fastboot platform: No GPT on flash. " 136 "Fastboot on HiKey does not support MBR.\n" 137 )); 138 return EFI_DEVICE_ERROR; 139 } 140 141 Entry = (EFI_PARTITION_ENTRY *)(Buffer + (2 * BlockSize)); 142 EndLBA = GptHeader->FirstUsableLBA - 1; 143 Count = 0; 144 while (1) { 145 if ((Entry->StartingLBA > EndLBA) && (Entry->EndingLBA <= GptHeader->LastUsableLBA)) { 146 Count++; 147 EndLBA = Entry->EndingLBA; 148 Entry++; 149 } else { 150 break; 151 } 152 } 153 if (Count == 0) { 154 return EFI_INVALID_PARAMETER; 155 } 156 if (Count > GptHeader->NumberOfPartitionEntries) { 157 Count = GptHeader->NumberOfPartitionEntries; 158 } 159 160 *PartitionEntries = (EFI_PARTITION_ENTRY *)((UINTN)Buffer + (2 * BlockSize)); 161 *PartitionNumbers = Count; 162 return EFI_SUCCESS; 163 } 164 165 EFI_STATUS 166 LoadPtable ( 167 VOID 168 ) 169 { 170 EFI_STATUS Status; 171 EFI_DEVICE_PATH_PROTOCOL *FlashDevicePath; 172 EFI_DEVICE_PATH_PROTOCOL *FlashDevicePathDup; 173 UINTN PartitionNumbers = 0; 174 UINTN LoopIndex; 175 EFI_PARTITION_ENTRY *PartitionEntries = NULL; 176 FASTBOOT_PARTITION_LIST *Entry; 177 178 InitializeListHead (&mPartitionListHead); 179 180 Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut); 181 if (EFI_ERROR (Status)) { 182 DEBUG ((DEBUG_ERROR, 183 "Fastboot platform: Couldn't open Text Output Protocol: %r\n", Status 184 )); 185 return Status; 186 } 187 188 // 189 // Get EFI_HANDLES for all the partitions on the block devices pointed to by 190 // PcdFastbootFlashDevicePath, also saving their GPT partition labels. 191 // There's no way to find all of a device's children, so we get every handle 192 // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones 193 // that don't represent partitions on the flash device. 194 // 195 FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdAndroidFastbootNvmDevicePath)); 196 197 // Create another device path pointer because LocateDevicePath will modify it. 198 FlashDevicePathDup = FlashDevicePath; 199 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &mFlashHandle); 200 if (EFI_ERROR (Status)) { 201 DEBUG ((DEBUG_ERROR, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status)); 202 // Failing to locate partitions should not prevent to do other Android FastBoot actions 203 return EFI_SUCCESS; 204 } 205 206 207 Status = gBS->OpenProtocol ( 208 mFlashHandle, 209 &gEfiBlockIoProtocolGuid, 210 (VOID **) &mFlashBlockIo, 211 gImageHandle, 212 NULL, 213 EFI_OPEN_PROTOCOL_GET_PROTOCOL 214 ); 215 if (EFI_ERROR (Status)) { 216 DEBUG ((DEBUG_ERROR, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status)); 217 return EFI_DEVICE_ERROR; 218 } 219 220 // Read the GPT partition entry array into memory so we can get the partition names 221 Status = ReadPartitionEntries (mFlashBlockIo, &PartitionEntries, &PartitionNumbers); 222 if (EFI_ERROR (Status)) { 223 DEBUG ((DEBUG_ERROR, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status)); 224 // Failing to locate partitions should not prevent to do other Android FastBoot actions 225 return EFI_SUCCESS; 226 } 227 for (LoopIndex = 0; LoopIndex < PartitionNumbers; LoopIndex++) { 228 // Create entry 229 Entry = AllocatePool (sizeof (FASTBOOT_PARTITION_LIST)); 230 if (Entry == NULL) { 231 Status = EFI_BUFFER_TOO_SMALL; 232 FreePartitionList (); 233 goto Exit; 234 } 235 StrnCpy ( 236 Entry->PartitionName, 237 PartitionEntries[LoopIndex].PartitionName, 238 PARTITION_NAME_MAX_LENGTH 239 ); 240 Entry->StartingLBA = PartitionEntries[LoopIndex].StartingLBA; 241 Entry->EndingLBA = PartitionEntries[LoopIndex].EndingLBA; 242 InsertTailList (&mPartitionListHead, &Entry->Link); 243 } 244 Exit: 245 FreePages ( 246 (VOID *)((UINTN)PartitionEntries - (2 * mFlashBlockIo->Media->BlockSize)), 247 EFI_SIZE_TO_PAGES (34 * mFlashBlockIo->Media->BlockSize) 248 ); 249 return Status; 250 } 251 252 /* 253 Initialise: Open the Android NVM device and find the partitions on it. Save them in 254 a list along with the "PartitionName" fields for their GPT entries. 255 We will use these partition names as the key in 256 HiKeyFastbootPlatformFlashPartition. 257 */ 258 EFI_STATUS 259 HiKeyFastbootPlatformInit ( 260 VOID 261 ) 262 { 263 return LoadPtable (); 264 } 265 266 VOID 267 HiKeyFastbootPlatformUnInit ( 268 VOID 269 ) 270 { 271 FreePartitionList (); 272 } 273 274 EFI_STATUS 275 HiKeyFlashPtable ( 276 IN UINTN Size, 277 IN VOID *Image 278 ) 279 { 280 EFI_STATUS Status; 281 EFI_DISK_IO_PROTOCOL *DiskIo; 282 UINT32 MediaId; 283 VOID *Buffer; 284 UINT32 EntrySize, EntryOffset; 285 UINTN BlockSize; 286 287 MediaId = mFlashBlockIo->Media->MediaId; 288 BlockSize = mFlashBlockIo->Media->BlockSize; 289 Status = gBS->OpenProtocol ( 290 mFlashHandle, 291 &gEfiDiskIoProtocolGuid, 292 (VOID **) &DiskIo, 293 gImageHandle, 294 NULL, 295 EFI_OPEN_PROTOCOL_GET_PROTOCOL 296 ); 297 if (EFI_ERROR (Status)) { 298 return Status; 299 } 300 Buffer = Image; 301 if (AsciiStrnCmp (Buffer, "ENTRYHDR", 8) != 0) { 302 DEBUG ((EFI_D_ERROR, "It should be raw ptable image\n")); 303 Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image); 304 if (EFI_ERROR (Status)) { 305 return Status; 306 } 307 } else { 308 /* ptable with entry header */ 309 Buffer += 8; 310 if (AsciiStrnCmp (Buffer, "primary", 7) != 0) { 311 DEBUG ((EFI_D_ERROR, "unknown ptable imag\n")); 312 return EFI_UNSUPPORTED; 313 } 314 Buffer += 8; 315 EntryOffset = *(UINT32 *)Buffer * BlockSize; 316 Buffer += 4; 317 EntrySize = *(UINT32 *)Buffer * BlockSize; 318 if ((EntrySize + BlockSize) > Size) { 319 DEBUG ((DEBUG_ERROR, "Entry size doesn't match\n")); 320 return EFI_UNSUPPORTED; 321 } 322 Buffer = Image + BlockSize; 323 Status = DiskIo->WriteDisk (DiskIo, MediaId, EntryOffset, EntrySize, Buffer); 324 if (EFI_ERROR (Status)) { 325 return Status; 326 } 327 } 328 FreePartitionList (); 329 Status = LoadPtable (); 330 return Status; 331 } 332 333 EFI_STATUS 334 HiKeyFastbootPlatformFlashPartition ( 335 IN CHAR8 *PartitionName, 336 IN UINTN Size, 337 IN VOID *Image 338 ) 339 { 340 EFI_STATUS Status; 341 UINTN PartitionSize; 342 FASTBOOT_PARTITION_LIST *Entry; 343 CHAR16 PartitionNameUnicode[60]; 344 BOOLEAN PartitionFound; 345 EFI_DISK_IO_PROTOCOL *DiskIo; 346 UINTN BlockSize; 347 348 // Support the pseudo partition name, such as "ptable". 349 if (AsciiStrCmp (PartitionName, "ptable") == 0) { 350 return HiKeyFlashPtable (Size, Image); 351 } 352 353 AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode); 354 PartitionFound = FALSE; 355 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead)); 356 while (!IsNull (&mPartitionListHead, &Entry->Link)) { 357 // Search the partition list for the partition named by PartitionName 358 if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { 359 PartitionFound = TRUE; 360 break; 361 } 362 363 Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link); 364 } 365 if (!PartitionFound) { 366 return EFI_NOT_FOUND; 367 } 368 369 // Check image will fit on device 370 BlockSize = mFlashBlockIo->Media->BlockSize; 371 PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * BlockSize; 372 if (PartitionSize < Size) { 373 DEBUG ((DEBUG_ERROR, "Partition not big enough.\n")); 374 DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size)); 375 376 return EFI_VOLUME_FULL; 377 } 378 Status = gBS->OpenProtocol ( 379 mFlashHandle, 380 &gEfiDiskIoProtocolGuid, 381 (VOID **) &DiskIo, 382 gImageHandle, 383 NULL, 384 EFI_OPEN_PROTOCOL_GET_PROTOCOL 385 ); 386 ASSERT_EFI_ERROR (Status); 387 388 Status = DiskIo->WriteDisk ( 389 DiskIo, 390 mFlashBlockIo->Media->MediaId, 391 Entry->StartingLBA * BlockSize, 392 Size, 393 Image 394 ); 395 if (EFI_ERROR (Status)) { 396 DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize, Status)); 397 return Status; 398 } 399 400 mFlashBlockIo->FlushBlocks(mFlashBlockIo); 401 MicroSecondDelay (50000); 402 403 return Status; 404 } 405 406 EFI_STATUS 407 HiKeyErasePtable ( 408 VOID 409 ) 410 { 411 EFI_STATUS Status; 412 EFI_ERASE_BLOCK_PROTOCOL *EraseBlockProtocol; 413 414 Status = gBS->OpenProtocol ( 415 mFlashHandle, 416 &gEfiEraseBlockProtocolGuid, 417 (VOID **) &EraseBlockProtocol, 418 gImageHandle, 419 NULL, 420 EFI_OPEN_PROTOCOL_GET_PROTOCOL 421 ); 422 if (EFI_ERROR (Status)) { 423 DEBUG ((DEBUG_ERROR, "Fastboot platform: could not open Erase Block IO: %r\n", Status)); 424 return EFI_DEVICE_ERROR; 425 } 426 Status = EraseBlockProtocol->EraseBlocks ( 427 EraseBlockProtocol, 428 mFlashBlockIo->Media->MediaId, 429 0, 430 NULL, 431 34 * mFlashBlockIo->Media->BlockSize 432 ); 433 if (EFI_ERROR (Status)) { 434 return Status; 435 } 436 FreePartitionList (); 437 return Status; 438 } 439 440 EFI_STATUS 441 HiKeyFastbootPlatformErasePartition ( 442 IN CHAR8 *PartitionName 443 ) 444 { 445 EFI_STATUS Status; 446 EFI_ERASE_BLOCK_PROTOCOL *EraseBlockProtocol; 447 UINTN Size; 448 BOOLEAN PartitionFound; 449 CHAR16 PartitionNameUnicode[60]; 450 FASTBOOT_PARTITION_LIST *Entry; 451 452 AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode); 453 454 // Support the pseudo partition name, such as "ptable". 455 if (AsciiStrCmp (PartitionName, "ptable") == 0) { 456 return HiKeyErasePtable (); 457 } 458 459 PartitionFound = FALSE; 460 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&mPartitionListHead); 461 while (!IsNull (&mPartitionListHead, &Entry->Link)) { 462 // Search the partition list for the partition named by PartitionName 463 if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { 464 PartitionFound = TRUE; 465 break; 466 } 467 Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link); 468 } 469 if (!PartitionFound) { 470 return EFI_NOT_FOUND; 471 } 472 473 Status = gBS->OpenProtocol ( 474 mFlashHandle, 475 &gEfiEraseBlockProtocolGuid, 476 (VOID **) &EraseBlockProtocol, 477 gImageHandle, 478 NULL, 479 EFI_OPEN_PROTOCOL_GET_PROTOCOL 480 ); 481 if (EFI_ERROR (Status)) { 482 return Status; 483 } 484 Size = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize; 485 Status = EraseBlockProtocol->EraseBlocks ( 486 EraseBlockProtocol, 487 mFlashBlockIo->Media->MediaId, 488 Entry->StartingLBA, 489 NULL, 490 Size 491 ); 492 return Status; 493 } 494 495 EFI_STATUS 496 HiKeyFastbootPlatformGetVar ( 497 IN CHAR8 *Name, 498 OUT CHAR8 *Value 499 ) 500 { 501 EFI_STATUS Status; 502 UINT64 PartitionSize; 503 FASTBOOT_PARTITION_LIST *Entry; 504 CHAR16 PartitionNameUnicode[60]; 505 BOOLEAN PartitionFound; 506 CHAR16 UnicodeSN[SERIAL_NUMBER_SIZE]; 507 508 if (!AsciiStrCmp (Name, "max-download-size")) { 509 AsciiStrCpy (Value, FixedPcdGetPtr (PcdArmFastbootFlashLimit)); 510 } else if (!AsciiStrCmp (Name, "product")) { 511 AsciiStrCpy (Value, FixedPcdGetPtr (PcdFirmwareVendor)); 512 } else if (!AsciiStrCmp (Name, "serialno")) { 513 Status = LoadSNFromBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN); 514 if (EFI_ERROR (Status)) { 515 *Value = '\0'; 516 return Status; 517 } 518 UnicodeStrToAsciiStr (UnicodeSN, Value); 519 } else if ( !AsciiStrnCmp (Name, "partition-size", 14)) { 520 AsciiStrToUnicodeStr ((Name + 15), PartitionNameUnicode); 521 PartitionFound = FALSE; 522 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead)); 523 while (!IsNull (&mPartitionListHead, &Entry->Link)) { 524 // Search the partition list for the partition named by PartitionName 525 if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { 526 PartitionFound = TRUE; 527 break; 528 } 529 530 Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link); 531 } 532 if (!PartitionFound) { 533 *Value = '\0'; 534 return EFI_NOT_FOUND; 535 } 536 537 PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize; 538 DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-size:%a 0X%llx\n", Name, PartitionSize)); 539 AsciiSPrint (Value, 12, "0x%llx", PartitionSize); 540 } else if ( !AsciiStrnCmp (Name, "partition-type", 14)) { 541 DEBUG ((DEBUG_ERROR, "Fastboot platform: check for partition-type:%a\n", (Name + 15))); 542 if ( !AsciiStrnCmp ( (Name + 15) , "system", 6) || !AsciiStrnCmp ( (Name + 15) , "userdata", 8) 543 || !AsciiStrnCmp ( (Name + 15) , "cache", 5)) { 544 AsciiStrCpy (Value, "ext4"); 545 } else { 546 AsciiStrCpy (Value, "raw"); 547 } 548 } else if ( !AsciiStrCmp (Name, "erase-block-size")) { 549 AsciiSPrint (Value, 12, "0x%llx", HIKEY_ERASE_SIZE); 550 } else if ( !AsciiStrCmp (Name, "logical-block-size")) { 551 AsciiSPrint (Value, 12, "0x%llx", HIKEY_ERASE_SIZE); 552 } else { 553 *Value = '\0'; 554 } 555 return EFI_SUCCESS; 556 } 557 558 EFI_STATUS 559 HiKeyFastbootPlatformOemCommand ( 560 IN CHAR8 *Command 561 ) 562 { 563 EFI_STATUS Status; 564 CHAR16 UnicodeSN[SERIAL_NUMBER_SIZE]; 565 566 if (AsciiStrCmp (Command, "Demonstrate") == 0) { 567 DEBUG ((DEBUG_ERROR, "ARM OEM Fastboot command 'Demonstrate' received.\n")); 568 return EFI_SUCCESS; 569 } else if (AsciiStrCmp (Command, "serialno") == 0) { 570 Status = GenerateUsbSN (UnicodeSN); 571 if (EFI_ERROR (Status)) { 572 DEBUG ((DEBUG_ERROR, "Failed to generate USB Serial Number.\n")); 573 return Status; 574 } 575 Status = StoreSNToBlock (mFlashHandle, SERIAL_NUMBER_LBA, UnicodeSN); 576 return Status; 577 } else if (AsciiStrCmp (Command, "reboot-bootloader") == 0) { 578 MmioWrite32 (ADB_REBOOT_ADDRESS, ADB_REBOOT_BOOTLOADER); 579 WriteBackInvalidateDataCacheRange ((VOID *)ADB_REBOOT_ADDRESS, 4); 580 return EFI_SUCCESS; 581 } else { 582 DEBUG ((DEBUG_ERROR, 583 "HiKey: Unrecognised Fastboot OEM command: %s\n", 584 Command 585 )); 586 return EFI_NOT_FOUND; 587 } 588 } 589 590 EFI_STATUS 591 HiKeyFastbootPlatformFlashPartitionEx ( 592 IN CHAR8 *PartitionName, 593 IN UINTN Offset, 594 IN UINTN Size, 595 IN VOID *Image 596 ) 597 { 598 EFI_STATUS Status; 599 UINTN PartitionSize; 600 FASTBOOT_PARTITION_LIST *Entry; 601 CHAR16 PartitionNameUnicode[60]; 602 BOOLEAN PartitionFound; 603 UINTN BlockSize; 604 EFI_DISK_IO_PROTOCOL *DiskIo; 605 606 AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode); 607 PartitionFound = FALSE; 608 Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead)); 609 while (!IsNull (&mPartitionListHead, &Entry->Link)) { 610 // Search the partition list for the partition named by PartitionName 611 if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { 612 PartitionFound = TRUE; 613 break; 614 } 615 616 Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link); 617 } 618 if (!PartitionFound) { 619 return EFI_NOT_FOUND; 620 } 621 622 // Check image will fit on device 623 PartitionSize = (Entry->EndingLBA - Entry->StartingLBA + 1) * mFlashBlockIo->Media->BlockSize; 624 if (PartitionSize < Size) { 625 DEBUG ((DEBUG_ERROR, "Partition not big enough.\n")); 626 DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size)); 627 628 return EFI_VOLUME_FULL; 629 } 630 631 BlockSize = mFlashBlockIo->Media->BlockSize; 632 Status = gBS->OpenProtocol ( 633 mFlashHandle, 634 &gEfiDiskIoProtocolGuid, 635 (VOID **) &DiskIo, 636 gImageHandle, 637 NULL, 638 EFI_OPEN_PROTOCOL_GET_PROTOCOL 639 ); 640 if (EFI_ERROR (Status)) { 641 return Status; 642 } 643 644 Status = DiskIo->WriteDisk ( 645 DiskIo, 646 mFlashBlockIo->Media->MediaId, 647 Entry->StartingLBA * BlockSize + Offset, 648 Size, 649 Image 650 ); 651 if (EFI_ERROR (Status)) { 652 DEBUG ((DEBUG_ERROR, "Failed to write %d bytes into 0x%x, Status:%r\n", Size, Entry->StartingLBA * BlockSize + Offset, Status)); 653 return Status; 654 } 655 return Status; 656 } 657 658 FASTBOOT_PLATFORM_PROTOCOL mPlatformProtocol = { 659 HiKeyFastbootPlatformInit, 660 HiKeyFastbootPlatformUnInit, 661 HiKeyFastbootPlatformFlashPartition, 662 HiKeyFastbootPlatformErasePartition, 663 HiKeyFastbootPlatformGetVar, 664 HiKeyFastbootPlatformOemCommand, 665 HiKeyFastbootPlatformFlashPartitionEx 666 }; 667 668 EFI_STATUS 669 EFIAPI 670 HiKeyFastbootPlatformEntryPoint ( 671 IN EFI_HANDLE ImageHandle, 672 IN EFI_SYSTEM_TABLE *SystemTable 673 ) 674 { 675 return gBS->InstallProtocolInterface ( 676 &ImageHandle, 677 &gAndroidFastbootPlatformProtocolGuid, 678 EFI_NATIVE_INTERFACE, 679 &mPlatformProtocol 680 ); 681 } 682