文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

高通 UEFI:ABL(一)

2023-09-02 07:04

关注

高通平台下的UEFI由XBL+ABL组成,主要完成各种客制化的需求实现,例如通过拉特定的gpio进入fastboot/recovery模式,读取ufs寿命,LCD兼容框架的实现等,想要实现客制化首先要搞明白源码种的框架组成,这篇文章先剖析一下abl阶段主要做了什么事情。

要分析abl框架,首先我们需要找到整个框架的入口,根据LinuxLoader.inf内的描述可以得到,abl的入口就在LinuxLoader.c内的LinuxLoaderEntry函数

文件路径:bootable/bootloader/edk2/QcomModulePkg/Application/LinuxLoader/LinuxLoader.inf

[Defines]        INF_VERSION                    = 0x00010006        BASE_NAME                      = LinuxLoader        FILE_GUID                      = f536d559-459f-48fa-8bbc-43b554ecae8d        MODULE_TYPE                    = UEFI_APPLICATION        VERSION_STRING                 = 0.1        ENTRY_POINT                    = LinuxLoaderEntry[Sources]        LinuxLoader.c...

那么就从入口函数LinuxLoaderEntry开始代码分析,分析内容直接附在代码注释中。

文件路径

bootable/bootloader/edk2/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c

EFI_STATUS EFIAPI  __attribute__ ( (no_sanitize ("safe-stack")))LinuxLoaderEntry (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable){  EFI_STATUS Status;  UINT32 BootReason = NORMAL_MODE;  UINT32 KeyPressed = SCAN_NULL;    BOOLEAN MultiSlotBoot;  DEBUG ((EFI_D_INFO, "Loader Build Info: %a %a\n", __DATE__, __TIME__));  DEBUG ((EFI_D_VERBOSE, "LinuxLoader Load Address to debug ABL: 0x%llx\n",         (UINTN)LinuxLoaderEntry & (~ (0xFFF))));  DEBUG ((EFI_D_VERBOSE, "LinuxLoaderEntry Address: 0x%llx\n",         (UINTN)LinuxLoaderEntry));  Status = AllocateUnSafeStackPtr ();  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Unable to Allocate memory for Unsafe Stack: %r\n",            Status));    goto stack_guard_update_default;  }  StackGuardChkSetup ();    //获取内核启动地址以及打印时间等  BootStatsSetTimeStamp (BS_BL_START);  //获取设备信息,涉及到oem unlock功能等  Status = DeviceInfoInit ();  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Initialize the device info failed: %r\n", Status));    goto stack_guard_update_default;  }  //枚举分区,根据provision文件内分配的lun卷进行枚举  Status = EnumeratePartitions ();  if (EFI_ERROR (Status)) {    DEBUG ((EFI_D_ERROR, "LinuxLoader: Could not enumerate partitions: %r\n",            Status));    goto stack_guard_update_default;  }  UpdatePartitionEntries ();  //判断本次启动是从slot_a还是slot_b启动  MultiSlotBoot = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");  if (MultiSlotBoot) {    DEBUG ((EFI_D_VERBOSE, "Multi Slot boot is supported\n"));    FindPtnActiveSlot ();  }    //判断是否此时存在按键事件选择进入不同模式  Status = GetKeyPress (&KeyPressed);  if (Status == EFI_SUCCESS) {    if (KeyPressed == SCAN_DOWN)      BootIntoFastboot = TRUE;    if (KeyPressed == SCAN_UP)      BootIntoRecovery = TRUE;    if (KeyPressed == SCAN_ESC)      RebootDevice (EMERGENCY_DLOAD);  } else if (Status == EFI_DEVICE_ERROR) {    DEBUG ((EFI_D_ERROR, "Error reading key status: %r\n", Status));    goto stack_guard_update_default;  }  //获取重启原因并根据原因决定设备进入的模式  Status = GetRebootReason (&BootReason);  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Failed to get Reboot reason: %r\n", Status));    goto stack_guard_update_default;  }  switch (BootReason) {  case FASTBOOT_MODE:    BootIntoFastboot = TRUE;    break;  case RECOVERY_MODE:    BootIntoRecovery = TRUE;    break;  case ALARM_BOOT:    BootReasonAlarm = TRUE;    break;  case DM_VERITY_ENFORCING:    // write to device info    Status = EnableEnforcingMode (TRUE);    if (Status != EFI_SUCCESS)      goto stack_guard_update_default;    break;  case DM_VERITY_LOGGING:        Status = MdtpDisable ();    if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {      DEBUG ((EFI_D_ERROR, "MdtpDisable Returned error: %r\n", Status));      goto stack_guard_update_default;    }    // write to device info    Status = EnableEnforcingMode (FALSE);    if (Status != EFI_SUCCESS)      goto stack_guard_update_default;    break;  case DM_VERITY_KEYSCLEAR:    Status = ResetDeviceState ();    if (Status != EFI_SUCCESS) {      DEBUG ((EFI_D_ERROR, "VB Reset Device State error: %r\n", Status));      goto stack_guard_update_default;    }    break;  default:    if (BootReason != NORMAL_MODE) {      DEBUG ((EFI_D_ERROR,             "Boot reason: 0x%x not handled, defaulting to Normal Boot\n",             BootReason));    }    break;  }    //recovery模式初始化  Status = RecoveryInit (&BootIntoRecovery);  if (Status != EFI_SUCCESS)    DEBUG ((EFI_D_VERBOSE, "RecoveryInit failed ignore: %r\n", Status));    Status = BoardInit ();  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Error finding board information: %r\n", Status));    return Status;  }  DEBUG ((EFI_D_INFO, "KeyPress:%u, BootReason:%u\n", KeyPressed, BootReason));  DEBUG ((EFI_D_INFO, "Fastboot=%d, Recovery:%d\n",              BootIntoFastboot, BootIntoRecovery));  if (!GetVmData ()) {    DEBUG ((EFI_D_ERROR, "VM Hyp calls not present\n"));  }  //选择正常启动,开始加载镜像  if (!BootIntoFastboot) {    BootInfo Info = {0};    Info.MultiSlotBoot = MultiSlotBoot;    Info.BootIntoRecovery = BootIntoRecovery;    Info.BootReasonAlarm = BootReasonAlarm;    Status = LoadImageAndAuth (&Info);    if (Status != EFI_SUCCESS) {      DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed: %r\n", Status));      goto fastboot;    }    BootLinux (&Info);  }fastboot:  DEBUG ((EFI_D_INFO, "Launching fastboot\n"));  Status = FastbootInitialize ();  if (EFI_ERROR (Status)) {    DEBUG ((EFI_D_ERROR, "Failed to Launch Fastboot App: %d\n", Status));    goto stack_guard_update_default;  }stack_guard_update_default:    __stack_chk_guard = DEFAULT_STACK_CHK_GUARD;  return Status;}

LinuxLoader.c作为整个abl的入口,要完成的事情有点多,对于uefi功能开发,我们不需要把全部代码都记住,但是必须要了解其中与客制化开发关系较为紧密的部分。下面进行几个重要函数的代码剖析

  1. DeviceInfoInit

DeviceInfoInit函数根据使用的DevInfo内部成员就知道,与设备locked功能,verity_mode,user_public_key有关,事实上DeviceInfoInit会去读取devcfg分区内的数据,并且会对unlocked功能进行初始化设定,对于不是专门做于设备安全的朋友来说,了解个大概就好了。

typedef struct device_info {  CHAR8 magic[DEVICE_MAGIC_SIZE];  BOOLEAN is_unlocked;  BOOLEAN is_unlock_critical;  BOOLEAN is_charger_screen_enabled;  CHAR8 bootloader_version[MAX_VERSION_LEN];  CHAR8 radio_version[MAX_VERSION_LEN];  BOOLEAN verity_mode; // TRUE = enforcing, FALSE = logging  UINT32 user_public_key_length;  CHAR8 user_public_key[MAX_USER_KEY_SIZE];  UINT64 rollback_index[MAX_VB_PARTITIONS];  struct usb_composition usb_comp;} DeviceInfo;EFI_STATUS DeviceInfoInit (VOID){  EFI_STATUS Status = EFI_SUCCESS;  if (FirstReadDevInfo) {    Status =        ReadWriteDeviceInfo (READ_CONFIG, (VOID *)&DevInfo, sizeof (DevInfo));    if (Status != EFI_SUCCESS) {      DEBUG ((EFI_D_ERROR, "Unable to Read Device Info: %r\n", Status));      return Status;    }    FirstReadDevInfo = FALSE;  }  if (CompareMem (DevInfo.magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE)) {    DEBUG ((EFI_D_ERROR, "Device Magic does not match\n"));    gBS->SetMem (&DevInfo, sizeof (DevInfo), 0);    gBS->CopyMem (DevInfo.magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);    DevInfo.user_public_key_length = 0;    gBS->SetMem (DevInfo.rollback_index, sizeof (DevInfo.rollback_index), 0);    gBS->SetMem (DevInfo.user_public_key, sizeof (DevInfo.user_public_key), 0);        if (IsSecureBootEnabled ()) {      DevInfo.is_unlocked = FALSE;      DevInfo.is_unlock_critical = FALSE;    } else {      DevInfo.is_unlocked = TRUE;      DevInfo.is_unlock_critical = TRUE;    }    DevInfo.is_charger_screen_enabled = FALSE;    DevInfo.verity_mode = TRUE;    Status =        ReadWriteDeviceInfo (WRITE_CONFIG, (VOID *)&DevInfo, sizeof (DevInfo));    if (Status != EFI_SUCCESS) {      DEBUG ((EFI_D_ERROR, "Unable to Write Device Info: %r\n", Status));      return Status;    }  }  return Status;}

  1. FindPtnActiveSlot&&GetActiveSlot

FindPtnActiveSlot函数只是设定了一个默认启动slot为0,真正的工作都是放在GetActiveSlot内完成的,GetActiveSlot会查找当前寄存器内哪个slot是active状态,从而选择加载对应的slot镜像。

GetActiveSlot会获取当前系统启动槽(slot)为0,0表示slot_a,1表示slot_b。由于高通soc平台存在的a/b系统的设计,因此abl阶段会判断当前系统会从哪个slot启动。GetActiveSlot会去读取寄

存器内存放slot_a/b的active状态,默认是slot_a启动,正常情况下只有ota后才会设置为slot_b启动。

STATIC EFI_STATUSGetActiveSlot (Slot *ActiveSlot){  EFI_STATUS Status = EFI_SUCCESS;  Slot Slots[] = {{L"_a"}, {L"_b"}};  UINT64 Priority = 0;  if (ActiveSlot == NULL) {    DEBUG ((EFI_D_ERROR, "GetActiveSlot: bad parameter\n"));    return EFI_INVALID_PARAMETER;  }  for (UINTN SlotIndex = 0; SlotIndex < ARRAY_SIZE (Slots); SlotIndex++) {    //这里只需要知道PartitionEntry结构体内的成员EFI_PARTITION_ENTRY为分区入口地址,lun为启动分区对应的lun卷即可    struct PartitionEntry *BootPartition =        GetBootPartitionEntry (&Slots[SlotIndex]);    UINT64 BootPriority = 0;    if (BootPartition == NULL) {      DEBUG ((EFI_D_ERROR, "GetActiveSlot: No boot partition "                           "entry for slot %s\n",              Slots[SlotIndex].Suffix));      return EFI_NOT_FOUND;    }    //各种寄存器计算    BootPriority =        (BootPartition->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>        PART_ATT_PRIORITY_BIT;    if ((BootPartition->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) &&        (BootPriority > Priority)) {      GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),                       Slots[SlotIndex].Suffix,                       StrLen (Slots[SlotIndex].Suffix)));      Priority = BootPriority;    }  }  DEBUG ((EFI_D_VERBOSE, "GetActiveSlot: found active slot %s, priority %d\n",          ActiveSlot->Suffix, Priority));  if (IsSuffixEmpty (ActiveSlot) == TRUE) {            UINT64 BootPriority = 0;    UINT64 RetryCount = 0;    struct PartitionEntry *SlotA = GetBootPartitionEntry (&Slots[0]);    if (SlotA == NULL) {      DEBUG ((EFI_D_ERROR, "GetActiveSlot: First Boot: No boot partition "                           "entry for slot %s\n",              Slots[0].Suffix));      return EFI_NOT_FOUND;    }    BootPriority = (SlotA->PartEntry.Attributes & PART_ATT_PRIORITY_VAL) >>                   PART_ATT_PRIORITY_BIT;    RetryCount = (SlotA->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>                 PART_ATT_MAX_RETRY_CNT_BIT;    if ((SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) == 0 &&        (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) == 0 &&        (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) == 0 &&        BootPriority == 0) {      DEBUG ((EFI_D_INFO, "GetActiveSlot: First boot: set "                          "default slot _a\n"));      SlotA->PartEntry.Attributes &=          (~PART_ATT_SUCCESSFUL_VAL & ~PART_ATT_UNBOOTABLE_VAL);      SlotA->PartEntry.Attributes |=          (PART_ATT_PRIORITY_VAL | PART_ATT_ACTIVE_VAL |           PART_ATT_MAX_RETRY_COUNT_VAL);      GUARD (StrnCpyS (ActiveSlot->Suffix, ARRAY_SIZE (ActiveSlot->Suffix),                       Slots[0].Suffix, StrLen (Slots[0].Suffix)));      UpdatePartitionAttributes (PARTITION_ATTRIBUTES);      FirstBoot = TRUE;      return EFI_SUCCESS;    }    DEBUG ((EFI_D_ERROR, "GetActiveSlot: No active slot found\n"));    DEBUG ((EFI_D_ERROR, "GetActiveSlot: Slot attr: Priority %ld, Retry "                         "%ld, Active %ld, Success %ld, unboot %ld\n",            BootPriority, RetryCount,            (SlotA->PartEntry.Attributes & PART_ATT_ACTIVE_VAL) >>                PART_ATT_ACTIVE_BIT,            (SlotA->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL),            (SlotA->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL)));    return EFI_NOT_FOUND;  }  return EFI_SUCCESS;}
  1. GetRebootReason

GetRebootReason根据函数名称就能猜到,是获取本次重启的原因,并且会对读取重启原因变量BootReason进行判断,如果是进入fastboot或者recovery的话那么就会将对应的属性值设置为true,

这里我们只需要知道:如果进行客制化需求实现,例如判断reboot reason从而执行某些操作,可以利用GetRebootReason (&BootReason)这个函数即可。

STATIC UINT8GetRebootReason (UINT32 *ResetReason){  EFI_RESETREASON_PROTOCOL *RstReasonIf;  EFI_STATUS Status;  Status = gBS->LocateProtocol (&gEfiResetReasonProtocolGuid, NULL,    (VOID **)&RstReasonIf);  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Error locating the reset reason protocol\n"));    return Status;  }  RstReasonIf->GetResetReason (RstReasonIf, ResetReason, NULL, NULL);  if (RstReasonIf->Revision >= EFI_RESETREASON_PROTOCOL_REVISION)    RstReasonIf->ClearResetReason (RstReasonIf);  return Status;}
  1. RecoveryInit

RecoveryInit 会对misc分区内的数据进行解析,如果解析到的misc分区字段存在boot-recovery的话,会将BootIntoRecovery标志设置为TRUE,在LoadImageAndAuth内会对这个标志进行判断。

struct RecoveryMessage {  CHAR8 command[32];  CHAR8 status[32];  CHAR8 recovery[1024];};EFI_STATUSRecoveryInit (BOOLEAN *BootIntoRecovery){  EFI_STATUS Status;  struct RecoveryMessage *Msg = NULL;  //misc分区的guid地址  EFI_GUID Ptype = gEfiMiscPartitionGuid;  MemCardType CardType = UNKNOWN;  VOID *PartitionData = NULL;  UINT32 PageSize;  CardType = CheckRootDeviceType ();  if (CardType == NAND) {    Status = GetNandMiscPartiGuid (&Ptype);    if (Status != EFI_SUCCESS) {      return Status;    }  }  GetPageSize (&PageSize);    Status = ReadFromPartition (&Ptype, (VOID **)&PartitionData, (PageSize * 2));  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "Error Reading from misc partition: %r\n", Status));    return Status;  }  if (!PartitionData) {    DEBUG ((EFI_D_ERROR, "Error in loading Data from misc partition\n"));    return EFI_INVALID_PARAMETER;  }  Msg = (CardType == NAND) ?           (struct RecoveryMessage *) ((CHAR8 *) PartitionData + PageSize) :           (struct RecoveryMessage *) PartitionData;  // Ensure NULL termination  Msg->command[sizeof (Msg->command) - 1] = '\0';  if (Msg->command[0] != 0 && Msg->command[0] != 255)    DEBUG ((EFI_D_VERBOSE, "Recovery command: %d %a\n", sizeof (Msg->command),            Msg->command));    //判断msg内的command属性值,如果为boot-recovery的话,那么BootIntoRecovery为true  if (!AsciiStrnCmp (Msg->command, RECOVERY_BOOT_RECOVERY,                       AsciiStrLen (RECOVERY_BOOT_RECOVERY))) {    *BootIntoRecovery = TRUE;  }    //判断设备是否打开了动态分区,并且判断misc分区内的command是否为boot-fastboot,是的话则设定为进入recovery模式,而后在进入fastboot模式(后者是假设)    if ( IsDynamicPartitionSupport () &&       !AsciiStrnCmp (Msg->command, RECOVERY_BOOT_FASTBOOT,                          AsciiStrLen (RECOVERY_BOOT_FASTBOOT))) {    *BootIntoRecovery = TRUE;  }  FreePool (PartitionData);  PartitionData = NULL;  Msg = NULL;  return Status;}
  1. LoadImageAndAuth

LoadImageAndAuth 会传入一个BootInfo类型的变量&Info,Info内的MultiSlotBoot、BootIntoRecovery以及BootReasonAlarm,并且会查找可启动slot、进行avb校验等。由于代码量大,因此选择对每个函数进行截取单独分析

5.1 FindBootableSlot

FindBootableSlot针对可启动slot进行各种寄存器值的判断,以及通过设定一个retry count来统计slot启动次数,厂商可以通过判断retry count来进行功能添加,如重启超过多少次则判定为slot无法起订,另外添加切换slot功能,让系统继续尝试重启等。

EFI_STATUSFindBootableSlot (Slot *BootableSlot){  EFI_STATUS Status = EFI_SUCCESS;  struct PartitionEntry *BootEntry = NULL;  UINT64 Unbootable = 0;  UINT64 BootSuccess = 0;  UINT64 RetryCount = 0;  if (BootableSlot == NULL) {    DEBUG ((EFI_D_ERROR, "FindBootableSlot: input parameter invalid\n"));    return EFI_INVALID_PARAMETER;  }  //获取当前被激活的slot,默认为a  GUARD (GetActiveSlot (BootableSlot));  //根据GetActiveSlot返回的激活slot,去寻找对应的boot分区索引    BootEntry = GetBootPartitionEntry (BootableSlot);  if (BootEntry == NULL) {    DEBUG ((EFI_D_ERROR, "FindBootableSlot: No boot partition entry "                         "for slot %s\n",            BootableSlot->Suffix));    return EFI_NOT_FOUND;  }  //gpt分区内的寄存器值获取  Unbootable = (BootEntry->PartEntry.Attributes & PART_ATT_UNBOOTABLE_VAL) >>               PART_ATT_UNBOOTABLE_BIT;  BootSuccess = (BootEntry->PartEntry.Attributes & PART_ATT_SUCCESSFUL_VAL) >>                PART_ATT_SUCCESS_BIT;  RetryCount =      (BootEntry->PartEntry.Attributes & PART_ATT_MAX_RETRY_COUNT_VAL) >>      PART_ATT_MAX_RETRY_CNT_BIT;  //如果当前slot之前没有被设置过unbootable标志,并且已经成功启动过了。那么就不需要做后续判断  if (Unbootable == 0 && BootSuccess == 1) {    DEBUG (        (EFI_D_VERBOSE, "Active Slot %s is bootable\n", BootableSlot->Suffix));  } else if (Unbootable == 0 && BootSuccess == 0 && RetryCount > 0) {    //判断是否打开了ab分区计数切换宏AB_RETRYCOUNT_DISABLE,有些厂商会在这里进行系统异常后自行切换slot的功能添加    if ((!IsABRetryCountDisabled () &&        !IsBootDevImage ()) &&      IsABRetryCountUpdateRequired ()) {      RetryCount--;      BootEntry->PartEntry.Attributes &= ~PART_ATT_MAX_RETRY_COUNT_VAL;      BootEntry->PartEntry.Attributes |= RetryCount             << PART_ATT_MAX_RETRY_CNT_BIT;      UpdatePartitionAttributes (PARTITION_ATTRIBUTES);      DEBUG ((EFI_D_INFO, "Active Slot %s is bootable, retry count %ld\n",              BootableSlot->Suffix, RetryCount));    } else {      DEBUG ((EFI_D_INFO, "A/B retry count NOT decremented\n"));    }  } else {    DEBUG ((EFI_D_INFO, "Slot %s is unbootable, trying alternate slot\n",            BootableSlot->Suffix));    //当前slot尝试重启次数已经超过了设定的retry count,将当前slot设置为unbootable    GUARD_OUT (HandleActiveSlotUnbootable ());  }    if (Status == EFI_SUCCESS) {    GUARD_OUT (ValidateSlotGuids (BootableSlot));  }  MarkPtnActive (BootableSlot->Suffix);out:  if (Status != EFI_SUCCESS) {        BootableSlot->Suffix[0] = '\0';  }  return Status;}     

5.2 LoadImageAndAuthVB2

LoadImageAndAuthxxx,这个xxx主要取决于GetAVBVersion返回的结果,通过switch函数判断当前系统应该进行那种类型的avb校验,当前我用的是android 10,默认为avb2,那么就进入LoadImageAndAuthVB2。由于avb部分不是专门做系统安全的朋友一般不会接触,因此这里我们简单介绍一下android的avb即可。

android avb分为两个阶段:
1.bootloader阶段:bootloader阶段会对vbmeta、vbmeta_system、boot、dtbo等镜像进行安全性校验,其中vbmeta、vbmeta_system内,这部分是在镜像编译的时候,编译脚本会将待校验的分区的hash值写到分区内,同时也会写到vbmeta分区内,在avb校验的时候vbmeta会根据记录的hash值与待校验分区的进行比较,如果不一致那么就会报错。
2.init阶段:init阶段会对vendor、system、product(实际上就是super分区)进行校验,也可以认为就是hash值。原理应该同bootloader阶段的一样,如果在init阶段校验失败的话,内核会出现dm-verity failed的打印

对于avb我们需要了解的应该就是如下几点:

  1. 编译启动开关:

android/device/qcom/qssi/qssi.mk# Enable AVB 2.0BOARD_AVB_ENABLE := true
  1. 对于hash值的计算方式:

andrioid/build/core/Makefile# vbmeta imageifeq ($(BOARD_AVB_ENABLE),true)BUILT_VBMETAIMAGE_TARGET := $(PRODUCT_OUT)/vbmeta.imgAVB_CHAIN_KEY_DIR := $(TARGET_OUT_INTERMEDIATES)/avb_chain_keysifdef BOARD_AVB_KEY_PATH$(if $(BOARD_AVB_ALGORITHM),,$(error BOARD_AVB_ALGORITHM is not defined))else# If key path isn't specified, use the 4096-bit test key.BOARD_AVB_ALGORITHM := SHA256_RSA4096BOARD_AVB_KEY_PATH := external/avb/test/data/testkey_rsa4096.pemendif
  1. 了解当前系统运行的是安全熔丝版本还是非熔丝版本,avb对于非熔丝版本的话,即使校验失败也不会影响系统启动。

  1. FastbootInitialize

最后一个主要功能函数就是FastbootInitialize,主函数内如果存在BootIntoFastboot=TRUE的语句的话,那么就会执行goto fastboot,进入fastboot的初始化。

EFI_STATUS FastbootInitialize (VOID){  EFI_STATUS Status = EFI_SUCCESS;  DEBUG ((EFI_D_INFO, "Fastboot Build Info: %a %a\n", __DATE__, __TIME__));  BootStatsSetTimeStamp (BS_BL_START);  //枚举usb设备     Status = FastbootUsbDeviceStart ();  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "couldnt Start fastboot usb device, exiting"));    return Status;  }  //屏幕显示fastboot菜单  DisplayFastbootMenu ();  //等待usb事件响应,进入fastboot时,需要通过usb进行指令发送,直到我们发送fastboot reboot这个指令,才会退出fastboot模式  while (1) {    Status = HandleUsbEvents ();    if (EFI_ERROR (Status) && (Status != EFI_ABORTED)) {      DEBUG ((EFI_D_ERROR, "Error, failed to handle USB event\n"));      break;    }    if (FastbootFatal ()) {      DEBUG ((EFI_D_ERROR, "Continue detected, Exiting App...\n"));      break;    }  }  //关闭usb时间,退出fastboot模式  Status = FastbootCmdsUnInit ();  if (Status != EFI_SUCCESS) {    DEBUG ((EFI_D_ERROR, "couldnt uninit fastboot\n"));    return Status;  }  ExitMenuKeysDetection ();  Status = FastbootUsbDeviceStop ();  return Status;}

这篇的文章目的就是简单的介绍一下bootloader内的各个重要api,对于里面的一些框架本人还不是特别熟,例如avb解析逻辑、fastboot模式的usb枚举、事件上报等,另外还有一些重要的例如cmdline的构成,如何通过cmdline完成内核驱动的选择性加载,这些后续会更新在abl第二篇文章内。

如有不对,欢迎指出,谢谢

来源地址:https://blog.csdn.net/weixin_43453149/article/details/129587539

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯