MTK 驱动部分双分区升级原理

在8.0之后MTK平台将tee lk preloder 等分区设置为双分区,升级的时候会将两个分区都进行升级,我们对这一部分做一个简单的分析和了解

 

一、升级包语句

ota_from_target_files

def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file):
  target_info = BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts)
  source_info = BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts)
  ......
  ......
  # Do device-specific installation (eg, write radio image).
  # 执行驱动部分的升级部分,基本上所有平台都会基于该方法进行自己驱动部分升级的定制
  device_specific.IncrementalOTA_InstallEnd()

 

releasetools.py

def IncrementalOTA_InstallEnd(self):
  script = self.script
  source_version = self.source_version
  source_zip = self.source_zip
  target_zip = self.target_zip
  target_version = self.target_version
  output_zip = self.output_zip
  script = self.script
  metadata = self.metadata
  info_dict= self.info_dict

  tgt_info_dict = common.LoadInfoDict(target_zip)

  # add OTA information 添加ota信息
  AddOTA_Items(target_zip, output_zip, 0)

  # Check bootloader path by property in porp.defaut 检查bootloader的地址
  check_bootloader_path(target_zip)

  # add extra images to upgrade 添加额外升级的image
  AddOTAImage_Items(source_zip, target_zip, output_zip, tgt_info_dict, script)

 

def AddOTA_Items(input_zip, output_zip, isFullOTA):
  //根据是否是整包 如果是整包type.txt中写入为1 如果是差分,type.txt写入为0
  common.ZipWriteStr(output_zip, "type.txt", str(isFullOTA))
  ota_scatter = input_zip.read("OTA/ota_scatter.txt")
  //将中间包里的scatter.txt文件放入升级包中,作为升级之后校验分区表
  common.ZipWriteStr(output_zip, "scatter.txt", ota_scatter)

 

def check_bootloader_path(input_zip):
  """check bootloader path by prop.default."""
  //根据device类型,确定preloader的节点
  prop_default = input_zip.read("RECOVERY/RAMDISK/prop.default")
  if "ro.vendor.mtk_ufs_support=1" in prop_default:
    print "device type is ufs, modify bootloader path"
    part_dev_map["preloader"] = "/dev/block/sda"
    part_dev_map["preloader2"] ="/dev/block/sdb"

 

def AddOTAImage_Items(source_zip, target_zip, output_zip, info_dict, script):
  try:
    //首先从中间包中查询ota_update_list 这里面存储了需要升级的分区和img文件
    //odmdtbo.img odmdtbo
    //tee.img tee1 tee2   
    //这个文件的生成在之前文档MTK驱动部分升级中分析过
    output = target_zip.read("OTA/ota_update_list.txt")
  except:
    print "update_img_list not found"
    return
  //定义存储类型为EMMC
  storage_type="EMMC"
  td_pair = common.GetTypeAndDevice("/boot", info_dict)
  if not td_pair:
    return
  storage_type = td_pair[0]

  isBackupImgExist = 0
  isFirstRun = 0
  part_list = []
  //通用img升级的列表
  general_img_list = []
  //加载部分img升级的列表
  loader_img_list = []
  //最后升级的img裂变
  last_update_img_list = []
  //以空格进行分割
  for line in output.split("\n"):
    if not line: continue
    //对行进行分割
    columns = line.split()
    try:
      //过去IMAGE下的打包进需要升级的img驱动文件
      img_read = target_zip.read("IMAGES/%s" % columns[0])
    except:
      print "read image %s fail, remove from update list" % columns[0]
      continue
    //单分区比如 odmdtbo.img odmdtbo
    if len(columns) == 2:
      //如果在post_update_img_list = ["vbmeta"]中
      if columns[1] in post_update_img_list:
        print "Move update %s.img to the last" % columns[1]
        common.ZipWriteStr(output_zip, columns[0], img_read)
        //加入到last_update_img_list类表中
        last_update_img_list.append(columns[1])
      //如果是在incremental_update_raw_img_list = ["md1img" , "md1dsp"]中
      //将使用差分升级,并放入到general_img_list列表中
      elif source_zip is not None and columns[1] in incremental_update_raw_img_list:
        print "%s uses incremental update" % columns[1]
        general_img_list.append(columns[:2])
      else: 
        //其他单分区也放入general_img_list
        general_img_list.append(columns[:2])
        common.ZipWriteStr(output_zip, columns[0], img_read)
    //双分区 比如 tee.img tee1 tee2  
    elif len(columns) == 3:
      //加入到loader_img_list列表中
      loader_img_list.append(columns[:3])
      common.ZipWriteStr(output_zip, columns[0], img_read)
    else:
      print "incorrect format in ota_update_list.txt"
      return

  script.AppendExtra('show_mtupdate_stage("%s");' % mtStageFile)
  //单分区文件加入升级包文件和升级脚本
  for img_name, mount_point in general_img_list:
    if general_img_list.index([img_name, mount_point]) == 0:
      script.AppendExtra('ifelse (\nless_than_int(get_mtupdate_stage("%s"), "1") ,\n(' % mtStageFile)
      script.AppendExtra('ui_print("start to update general image");');
    //针对incremental_update_raw_img_list 将使用差分升级 
    if source_zip is not None and mount_point in incremental_update_raw_img_list:
      print ("Handle update incremental raw %s.img img_name %s" % (mount_point,img_name))
      Inremental_raw_img(source_zip, target_zip,output_zip, mount_point, img_name, info_dict, script)
    else:
      //其他img整个放入差分包
      WriteRawImage2(script, mount_point, img_name, info_dict)
  if len(general_img_list) > 0:
    SwitchStage(script, "1")
    script.AppendExtra('),\nui_print("general images are already updated");\n);')

  //双分区加入升级包文件和升级脚本
  if len(loader_img_list) > 0:
    //首先写入2分区 并且通过SwitchActive写入脚本 变更当前活动分区
    for img_name, mount_point, backup_mount_point in loader_img_list:
      if loader_img_list.index([img_name, mount_point, backup_mount_point]) == 0:
        script.AppendExtra('ifelse (\nless_than_int(get_mtupdate_stage("%s"), "3") ,\n(' % mtStageFile)
        script.AppendExtra('if less_than_int(get_mtupdate_stage("%s"), "2") then\n' % mtStageFile)
        script.AppendExtra('ui_print("start to update alt loader image");');
      WriteRawImage2(script, backup_mount_point, img_name, info_dict)
    SwitchStage(script, "2")
    script.AppendExtra('endif;\n')
    for img_name, mount_point, backup_mount_point in loader_img_list:
      SwitchActive(script, mount_point, backup_mount_point)
    SwitchStage(script, "3")
    script.AppendExtra('),\nui_print("alt loder images are already updated");\n);')
    //写入1分区 并且通过SwitchActive写入脚本 变更当前活动分区
    for img_name, mount_point, backup_mount_point in loader_img_list:
      if loader_img_list.index([img_name, mount_point, backup_mount_point]) == 0:
        script.AppendExtra('ifelse (\nless_than_int(get_mtupdate_stage("%s"), "5") ,\n(' % mtStageFile)
        script.AppendExtra('if less_than_int(get_mtupdate_stage("%s"), "4") then\n' % mtStageFile)
        script.AppendExtra('ui_print("start to update main loader image");');
      WriteRawImage2(script, mount_point, img_name, info_dict)
    SwitchStage(script, "4")
    script.AppendExtra('endif;\n')
    for img_name, mount_point, backup_mount_point in loader_img_list:
      SwitchActive(script, backup_mount_point, mount_point)
    script.AppendExtra('),\nui_print("main loader images are already updated");\n);')

  script.AppendExtra('delete("%s");' % mtStageFile)
  for mount_point in last_update_img_list:
    WriteRawImage2(script, mount_point, mount_point+".img", info_dict)
  script.AppendExtra('set_ota_result_for_dm_verity();')

 

//写入升级语句
def WriteRawImage2(script, partition, fn, info_dict, mapfn=None):
  """Write the given package file into the given MTD partition."""
  //首先处理preloader的升级
  if partition in part_dev_map.keys():
    partition_type = "EMMC"
    if script.fstab:
      try:
        p = script.fstab["/boot"]
      except:
        print "%s not exists in fstab, try fstab of info_dict" % mount_point
        p = info_dict["fstab"]["/boot"]
      partition_type = common.PARTITION_TYPES[p.fs_type]
      args = {'device': p.device, 'fn': fn}
    if partition_type == "MTD":
      script.AppendExtra(
          'write_raw_image(package_extract_file("%(fn)s"), "/dev/preloader");'
          % args)
    else:
      if p.fs_type.upper() == "EMMC":
        script.AppendExtra(
          ('assert(set_emmc_writable("%(force_ro)s"),\n'
           '       package_extract_file("%(fn)s", "%(partition)s"));')
          % {'partition': part_dev_map[partition], 'fn': fn, 'force_ro': force_ro_dev_map[partition]})
      else:
        raise ValueError(
            "Preloader don't know how to write \"%s\" partitions" % p.fs_type)
  else:
    //处理其他image
    mount_point = "/"+partition
    if script.fstab:
      try:
        p = script.fstab[mount_point]
      except:
        print "%s not exists in fstab, try fstab of info_dict" % mount_point
        p = info_dict["fstab"][mount_point]
      partition_type = common.PARTITION_TYPES[p.fs_type]
      args = {'device': p.device, 'fn': fn}
      if partition_type == "EMMC" or partition_type == "MTD":
        if mapfn:
          args["map"] = mapfn
          script.AppendExtra(
              'package_extract_file("%(fn)s", "%(device)s", "%(map)s");' % args)
        else:
          script.AppendExtra(
              'package_extract_file("%(fn)s", "%(device)s");' % args)
      else:
        raise ValueError(
            "don't know how to write \"%s\" partitions" % p.fs_type)

 

 

//选取活跃分区
def SwitchActive(script, from_part, to_part):
  """switch current active partition."""
  partition_type = "EMMC"
  if script.fstab:
    try:
      p = script.fstab["/boot"]
    except:
      print "%s not exists in fstab, try fstab of info_dict" % mount_point
      p = info_dict["fstab"]["/boot"]
    partition_type = common.PARTITION_TYPES[p.fs_type]
  //如果是EMMC 写入语句 从1分区到2分区和从2分区到1分区
  if partition_type == "EMMC":
    script.AppendExtra(('switch_active("%(partition)s", "%(to_part)s");')
        % {'partition':from_part.replace("bootloader","lk"), 'to_part':to_part.replace("bootloader","lk")})
  if partition_type == "MTD":
    script.AppendExtra(('switch_active("%(partition)s", "%(to_part)s");')
        % {'partition':from_part.replace("bootloader","uboot"), 'to_part':to_part.replace("bootloader","uboot")})

 

 

生成差分包中updater-scrypt相关内容如下:

以下是升级驱动相关的所有语句

ui_print("start to update general image");
ui_print("Patching md1dsp image...");
show_progress(0.100000, 10);
//通用部分升级,除md1dsp.img md1img.img 使用查分外,其他使用整包升级到对应分区节点
apply_patch("EMMC:/dev/block/platform/bootdevice/by-name/md1dsp:6574480:54b9873602bd776655e6fe128b2e498294d27951:6574480:8b7922a855c149bcdba64c8f3bfaf36486410c36",
            "-", 8b7922a855c149bcdba64c8f3bfaf36486410c36, 6574480,
            54b9873602bd776655e6fe128b2e498294d27951,
            package_extract_file("patch/md1dsp.img.p")) ||
    abort("E3008: Failed to apply patch to EMMC:/dev/block/platform/bootdevice/by-name/md1dsp:6574480:54b9873602bd776655e6fe128b2e498294d27951:6574480:8b7922a855c149bcdba64c8f3bfaf36486410c36");
package_extract_file("dtbo.img", "/dev/block/platform/bootdevice/by-name/dtbo");
package_extract_file("mcupmfw.img", "/dev/block/platform/bootdevice/by-name/mcupmfw");
ui_print("Patching md1img image...");
show_progress(0.100000, 10);
apply_patch("EMMC:/dev/block/platform/bootdevice/by-name/md1img:18290944:2e698b9873440c730f060c659221a27c5183ea6e:18290944:5469c6d12bc44244b4d2877f92295b9ad7dc649c",
            "-", 5469c6d12bc44244b4d2877f92295b9ad7dc649c, 18290944,
            2e698b9873440c730f060c659221a27c5183ea6e,
            package_extract_file("patch/md1img.img.p")) ||
    abort("E3008: Failed to apply patch to EMMC:/dev/block/platform/bootdevice/by-name/md1img:18290944:2e698b9873440c730f060c659221a27c5183ea6e:18290944:5469c6d12bc44244b4d2877f92295b9ad7dc649c");
package_extract_file("spmfw.img", "/dev/block/platform/bootdevice/by-name/spmfw");
set_mtupdate_stage("/cache/recovery/last_mtupdate_stage", "1");
),
ui_print("general images are already updated");
);
ifelse (
less_than_int(get_mtupdate_stage("/cache/recovery/last_mtupdate_stage"), "3") ,
(
if less_than_int(get_mtupdate_stage("/cache/recovery/last_mtupdate_stage"), "2") then
//升级双分区部分
ui_print("start to update alt loader image");
//将新版本tee写入到2分区
package_extract_file("tee.img", "/dev/block/platform/bootdevice/by-name/tee2");
set_mtupdate_stage("/cache/recovery/last_mtupdate_stage", "2");
endif;
//选取活动分区从1到2
switch_active("tee1", "tee2");
set_mtupdate_stage("/cache/recovery/last_mtupdate_stage", "3");
),
ui_print("alt loder images are already updated");
);
ifelse (
less_than_int(get_mtupdate_stage("/cache/recovery/last_mtupdate_stage"), "5") ,
(
if less_than_int(get_mtupdate_stage("/cache/recovery/last_mtupdate_stage"), "4") then
//再次升级双分区
ui_print("start to update main loader image");
//将新版本tee写入1分区
package_extract_file("tee.img", "/dev/block/platform/bootdevice/by-name/tee1");
set_mtupdate_stage("/cache/recovery/last_mtupdate_stage", "4");
endif;
//选取激活分区从2到1 
switch_active("tee2", "tee1");
),
ui_print("main loader images are already updated");
);
delete("/cache/recovery/last_mtupdate_stage");

 

二、写入部分代码

语句是制作好了,具体写入我们要看下update-binary 也就是updater是如何执行的

这里重点关注switch_active方法

mt_install.cpp

void mt_RegisterInstallFunctions(void)
{
    mt_init_partition_type();

    RegisterFunction("get_mtupdate_stage", mtGetUpdateStageFn);
    RegisterFunction("set_mtupdate_stage", mtSetUpdateStageFn);
    RegisterFunction("show_mtupdate_stage", mtShowUpdateStageFn);
    //选择活动分区真正执行的地方
    RegisterFunction("switch_active", mtSwitchActiveFn);
    RegisterFunction("delete", mtDeleteFn);
    RegisterFunction("set_emmc_writable", mtSetEmmcWR);
    RegisterFunction("set_ota_result_for_dm_verity", mtSetOTAResultForDMVerity);
}

 

mt_install.cpp
Value* mtSwitchActiveFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
    if (argv.size() != 2)
        return ErrorAbort(state, kArgsParsingFailure,"%s() expects 2 arg, got %zu", name, argv.size());

    std::vector<std::string> args;
    if (!ReadArgs(state, argv, &args))
         return NULL;
    //定义传入的第一个参数为from_partition
    const std::string& from_partition = args[0];
    //定义传入的第二个参数为to_partition
    const std::string& to_partition = args[1];
    //更新活跃分区
    mt_update_active_part(state, from_partition.c_str(), to_partition.c_str());
    printf("Switch %s active to %s\n", from_partition.c_str(), to_partition.c_str());
    return StringValue(from_partition);
}

 

mt_install.cpp
static int mt_update_active_part(State* state, const char* from_partition, const char *to_partition)
{
    if (((mt_get_phone_type() == FS_TYPE_MTD) && (!strncasecmp(from_partition, "preloader", strlen("preloader"))))  // preloader on NAND not use active bit
        ) {
        if (!strcasecmp(from_partition, "preloader")) // only do erase when main partition to alt partition
            return mt_update_erase_part(state, from_partition);
    } else if((mt_get_phone_type() == FS_TYPE_UFS) && !strncasecmp(from_partition, "preloader", strlen("preloader")))  {  // preloader on UFS
        unsigned int bootpart = 0;
        if (!strcmp(to_partition, "preloader"))
            bootpart = 1;
        else
            bootpart = 2;
        return ufs_set_active_boot_part(bootpart);
    //优先处理preloader的情况
    } else if ((mt_get_phone_type() == FS_TYPE_EMMC) && !strncasecmp(from_partition, "preloader", strlen("preloader"))) { // preloader on EMMC just switch register
        struct msdc_ioctl st_ioctl_arg;
        unsigned int bootpart = 0;
        int fd = open("/dev/misc-sd", O_RDWR);
        if (fd >= 0) {
            memset(&st_ioctl_arg,0,sizeof(struct msdc_ioctl));
            st_ioctl_arg.host_num = 0;
            st_ioctl_arg.opcode = MSDC_SET_BOOTPART;
            st_ioctl_arg.total_size = 1;
            if (!strcmp(to_partition, "preloader"))
                bootpart = EMMC_BOOT1_EN;
            else
                bootpart = EMMC_BOOT2_EN;
            st_ioctl_arg.buffer = &bootpart;
            int ret = ioctl(fd, MSDC_SET_BOOTPART, &st_ioctl_arg);
            if (ret < 0)
                printf("set boot_part fail: %s\n", strerror(errno));
            printf("switch bootpart to  = %d, ret = %d\n", bootpart, ret);
            close(fd);
        } else {
            uiPrintf(state, "set boot part fail, can not open misc-sd\n");
        }
    } else if ((mt_get_phone_type() == FS_TYPE_MNTL) || (mt_get_phone_type() == FS_TYPE_MTD)) {
        // need to set to_partition active bit to 1 and then set from_partition active bit to 0
        int ret = mt_pmt_update_active_part(to_partition, 1) | mt_pmt_update_active_part(from_partition, 0);
        return ret;
    //更新gpt分区标志位
    } else if (support_gpt()) {
        // need to set to_partition active bit to 1 and then set from_partition active bit to 0
        int ret = mt_gpt_update_active_part(to_partition, 1) | mt_gpt_update_active_part(from_partition, 0);
        return ret;
    } else {
        // TODO: pmt type active bit switch
    }
    return 1;
}

 

mt_gpt.cpp
int mt_gpt_update_active_part(const char* partition_name, int is_active)
{
    char *part_entry = NULL;
    GuidPartitionTableHeader_t pgpt_header;
    GuidPartitionEntry_t *pe;
    int sector_size = 0;
    unsigned int i = 0;

    // initial path
    set_blk_device_path();
    set_hw_sector_size_path();

    // get sector size
    if (mt_get_sector_size(&sector_size) != 0) {
        printf("Get sector size fail!\n");
        return 1;
    }

    // read partition entry
    if (mt_gpt_get_part_entry(&pgpt_header, &part_entry, sector_size) > 0) {
        printf("Get partition entry fail!\n");
        return 1;
    }
    // Set active bit for corresponding partition entry
    pe = (GuidPartitionEntry_t *)part_entry;
    for (i = 0; i < pgpt_header.NumberOfPartitionEntries; i++, pe++) {
        unsigned int j;
        char name[37];
#ifdef GPT_DEBUG
        printf("Partition Entry %d\n", i + 1);
        printf("\tFirst LBA=%ju\n", pe->StartingLBA);
        printf("\tLast LBA=%ju\n", pe->EndingLBA);
#endif
        for (j = 0; j < 72 / sizeof(efi_char16_t); j++) {
            name[j] = (uint16_t)pe->PartitionName[j];
        }
        name[j] = 0;
#ifdef GPT_DEBUG
        printf("\tName=%s\n", name);
#endif

        if (!strcmp(name, partition_name))
            break;
    }

    if (i >= pgpt_header.NumberOfPartitionEntries) {
        printf("partition %s not found!\n", partition_name);
        if (part_entry)
            free(part_entry);
        return 1;
    }
    printf("set %s active bit to %d\n", partition_name, is_active);
    printf("Original active: %d, new active: %d\n", (unsigned int)pe->Attributes.LegacyBIOSBootable, is_active);
    pe->Attributes.LegacyBIOSBootable = is_active;

    // Write partition entry to gpt 将对应分区写入gpt分区标志位
    mt_gpt_update_part_entry(&pgpt_header, &part_entry, sector_size);

    // resource release
    if (part_entry)
        free(part_entry);
    return 0;
}

 

mt_gpt.cpp 将当前活跃分区写入到gpt
static int mt_gpt_update_part_entry(GuidPartitionTableHeader_t *pgpt_header, char** part_entry, int sector_size)
{
    int fd = 0;
    int write_len = 0;
    GuidPartitionTableHeader_t sgpt_header;

    if (pgpt_header == NULL) {
        printf("invalid gpt partition table header!\n");
        return 1;
    }

    fd = open(blk_device, O_RDWR | O_SYNC);
    if (fd < 0) {
        printf("open %s fail\n", blk_device);
        return 1;
    }

    uint64_t len = (uint64_t)pgpt_header->NumberOfPartitionEntries * (uint64_t)pgpt_header->SizeOfPartitionEntry;
    pgpt_header->PartitionEntryArrayCRC32 = efi_crc32(*part_entry, len);
#ifdef GPT_DEBUG
    printf("PE CRC changed=0x%08x\n", pgpt_header->PartitionEntryArrayCRC32);
#endif

    pgpt_header->HeaderCRC32 = 0;
    pgpt_header->HeaderCRC32 = efi_crc32(pgpt_header, pgpt_header->HeaderSize);
#ifdef GPT_DEBUG
    printf("PGTP Header CRC changed=0x%08x\n", pgpt_header->HeaderCRC32);
#endif

    //SGPT
    if (lseek64(fd, pgpt_header->AlternateLBA * sector_size, SEEK_SET) == -1) {
        printf("leesk %ju fail\n", pgpt_header->AlternateLBA * sector_size);
        close(fd);
        return 1;
    }

    if (read(fd, &sgpt_header, sizeof(sgpt_header)) != sizeof(sgpt_header)) {
        printf("read SGPT header fail\n");
        close(fd);
        return 1;
    }

#ifdef GPT_DEBUG
    printf("SGPT:\n");
    printf("Header CRC=0x%08x\n", sgpt_header.HeaderCRC32);
    printf("Current LBA=%ju\n", sgpt_header.MyLBA);
    printf("Backup LBA=%ju\n", sgpt_header.AlternateLBA);
    printf("First usable LBA=%ju\n", sgpt_header.FirstUsableLBA);
    printf("Last usable LBA=%ju\n", sgpt_header.LastUsableLBA);
    printf("Starting PE LBA=%ju\n", sgpt_header.PartitionEntryLBA);
    printf("Number of PE=%d\n", sgpt_header.NumberOfPartitionEntries);
    printf("Size of PE=%d\n", sgpt_header.SizeOfPartitionEntry);
    printf("PE CRC=0x%08x\n", sgpt_header.PartitionEntryArrayCRC32);
#endif
    sgpt_header.PartitionEntryArrayCRC32 = pgpt_header->PartitionEntryArrayCRC32;

    sgpt_header.HeaderCRC32 = 0;
    sgpt_header.HeaderCRC32 = efi_crc32(&sgpt_header, sgpt_header.HeaderSize);
#ifdef GPT_DEBUG
    printf("SGTP Header CRC changed=0x%08x\n", sgpt_header.HeaderCRC32);
#endif

    //update PGPT header
    if (lseek64(fd, pgpt_header->MyLBA * sector_size, SEEK_SET) == -1) {
        printf("leesk %ju fail\n", pgpt_header->MyLBA * sector_size);
        close(fd);
        return 1;
    }

    if ((write_len = write(fd, pgpt_header, pgpt_header->HeaderSize)) != (int)pgpt_header->HeaderSize) {
        printf("write PGPT fail %d (%s)\n", write_len, strerror(errno));
        close(fd);
        return 1;
    }

    //update PPE
    if (lseek64(fd, pgpt_header->PartitionEntryLBA * sector_size, SEEK_SET) == -1) {
        printf("leesk %ju fail\n", pgpt_header->PartitionEntryLBA * sector_size);
        close(fd);
        return 1;
    }

    if ((write_len = write(fd, *part_entry, (ssize_t)len)) != (ssize_t)len) {
        printf("write PPE fail %d (%s)\n", write_len, strerror(errno));
        close(fd);
        return 1;
    }

    //update SPE
    if (lseek64(fd, sgpt_header.PartitionEntryLBA * sector_size, SEEK_SET) == -1) {
        printf("leesk %ju fail\n", sgpt_header.PartitionEntryLBA * sector_size);
        close(fd);
        return 1;
    }

    if ((write_len = write(fd, *part_entry, (ssize_t)len)) != (ssize_t)len) {
        printf("write SPE fail %d (%s)\n", write_len, strerror(errno));
        close(fd);
        return 1;
    }

    //update SGPT header
    if (lseek64(fd, sgpt_header.MyLBA * sector_size, SEEK_SET) == -1) {
        printf("leesk %ju fail\n", sgpt_header.MyLBA * sector_size);
        close(fd);
        return 1;
    }

    if ((write_len = write(fd, &sgpt_header, sgpt_header.HeaderSize)) != (int)sgpt_header.HeaderSize) {
        printf("write SGPT fail %d (%s)\n", write_len, strerror(errno));
        close(fd);
        return 1;
    }
    close(fd);
    sync();
    return 0;
}

 

三、总结

1、对于单分区部分 直接进行写入

2、双分区部分 首先写入2分区

3、将2分区标志位写入PGPT分区

4、再次写入1分区

5、将1分区标志位写入PGPT分区

6、可以是出去安全考虑,双分区大部分为tee  lk preloader,开机引导加载重要固件,采用双分区,一旦写入出现问题,PGPT分区会选择正常的活跃分区进行启动

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值