Как происходит запись прошивки Android с карты Product


   1       2       3       4       5       6       7       8         9         10   

9. Запись содержимого разделов

Запись таблицы GPT выполняется функцией sunxi_sprite_download_mbr


#define  GPT_BUFF_SIZE   (8*1024)
#define  GPT_ENTRY_OFFSET 1024
#define  GPT_HEAD_OFFSET   512
#define  GPT_HEADER_SIGNATURE 0x5452415020494645ULL // это строка 'EFI PART'
// суффикс ULL превращает строку в тип unsigned long long

int sunxi_sprite_download_mbr(void *buffer, uint buffer_size)
{
   typedef int (*FLASH_WIRTE)(uint start_block, uint nblock, void *buffer);
   FLASH_WIRTE flash_write_pt = NULL;
   int ret = 0;
   int storage_type = 0;
   gpt_header *gpt_head  = (gpt_header*)(buffer + GPT_HEAD_OFFSET);

   storage_type = get_boot_storage_type();
   if(sunxi_flash_init())
      return -1;

   if (buffer_size != GPT_BUFF_SIZE)
   {   printf("the GPT size is bad");
       return -1;
   }
   if(gpt_head->signature != GPT_HEADER_SIGNATURE)
   {  printf("gpt magic error, %llx != %llx",gpt_head->signature,
           GPT_HEADER_SIGNATURE);
       return 0;
   }

   gpt_fix_flash_size(buffer, storage_type);

   /*write to logic addr for uboot use*/
   ret = sunxi_flash_write(0, (buffer_size+511)>>9, buffer);
   if(!ret) {
       debug("%s:write gpt sectors fail",__func__);
       goto __err_end;
   }
   // write to phy addr for kernel use
   if(STORAGE_EMMC == storage_type || STORAGE_EMMC3 == storage_type)
   { ret = sunxi_flash_phywrite(0, buffer_size>>9, buffer);
     if(!ret)
         goto __err_end;
   }

   printf("write primary GPT success");
   prepare_backup_gpt_header(gpt_head);

   if(STORAGE_EMMC == storage_type || STORAGE_EMMC3 == storage_type
       || STORAGE_NOR == storage_type)
       flash_write_pt  = sunxi_flash_phywrite;
   else
       flash_write_pt  = sunxi_flash_write;

   //  write back-up gpt PTE
   ret = flash_write_pt(gpt_head->last_usable_lba + 1,
       (GPT_BUFF_SIZE-GPT_ENTRY_OFFSET)/512,
       buffer+GPT_ENTRY_OFFSET);

   if(!ret)
       goto __err_end;


   // write back-up gpt HEAD
   ret = flash_write_pt(gpt_head->my_lba, 1,
       buffer+GPT_HEAD_OFFSET);
if(!ret) {
	goto __err_end;
}
printf("write Backup GPT success");
return 0;

__err_end:
return -1;
}

Запись содержимого разделов выполняется функцией sunxi_sprite_deal_part(dl_map)

Это отражается в логе сообщением: begin to download part


//------------------------------------------
int sunxi_sprite_deal_part(sunxi_download_info *dl_map)
{   dl_one_part_info *part_info;
    int ret = -1;
    int ret1;
    int i = 0;
    uchar *down_buff = NULL;

    if (!dl_map->download_count)
    { printf("sunxi sprite: no part need to write");
     return 0;
    }

    down_buff = (uchar *)memalign(CONFIG_SYS_CACHELINE_SIZE,
        ALIGN(SPRITE_CARD_ONCE_DATA_DEAL +  SPRITE_CARD_HEAD_BUFF,
        CONFIG_SYS_CACHELINE_SIZE));

    if (!down_buff)
    { printf("sunxi sprite err: unable to malloc memory for sunxi_sprite_deal_part");
      goto __sunxi_sprite_deal_part_err1;
    }

    //---------- В цикле по всем разделам ---------------------
    for (part_info = dl_map->one_part_info, i = 0;
         i < dl_map->download_count; i++, part_info++)
    { // ------- один раздел --------------
      tick_printf("begin to download part %s", part_info->name);

      if (!strncmp("UDISK", (char *)part_info->name, strlen("UDISK")))
       { ret1 = __download_udisk(part_info, down_buff);
         if (ret1 < 0)
         { printf("sunxi sprite err: sunxi_sprite_deal_part,
                download_udisk failed");
           goto __sunxi_sprite_deal_part_err2;
         }
         else if (ret1 > 0)
          printf("do NOT need download UDISK");
       } // Если это раздел sysrecovery, запиcать полный образ раздела.

      else if (!strncmp("sysrecovery",(char *)part_info->name,strlen("sysrecovery")))
       { ret1 = __download_sysrecover_part(part_info, down_buff);
         if (ret1 != 0)
         { printf("sunxi sprite err: sunxi_sprite_deal_part,
                     download sysrecovery failed");
           goto __sunxi_sprite_deal_part_err2;
         }
       } // Если это раздел private, проверьте, требуется ли запись

      else if (!strncmp("private",(char *)part_info->name, strlen("private")))
       {  if (1)  // видимо, здесь раньше была проверка какого-то значения
          //Нужно записать этот раздел
          {  printf("NEED down private part");
             ret1 = __download_normal_part(part_info,
                                  down_buff);
             if (ret1 != 0)
             { printf("line:%d sunxi sprite err:
               sunxi_sprite_deal_part, download private failed", __LINE__);
               goto __sunxi_sprite_deal_part_err2;
             }
          }
         else
             printf("IGNORE private part");
       }
       else  // любой другой раздел
       {  ret1 = __download_normal_part(part_info, down_buff);
          if (ret1 != 0)
          { printf("line:%d sunxi sprite err: sunxi_sprite_deal_part,
                   download private failed", __LINE__);
            goto __sunxi_sprite_deal_part_err2;
          }
       }
       tick_printf("successed in download part %s",
                      part_info->name);
    }
    // ---------- цикл закончен --------------
    ret = 0;

__sunxi_sprite_deal_part_err1:
    sunxi_sprite_exit(1);

__sunxi_sprite_deal_part_err2:

 if (down_buff)
    free(down_buff);

  return ret;
}

Запись содержимого десяти разделов можно условно разбить на три этапа:

  1. записываются первые четыре раздела (bootloader_a, env_a, boot_a, vendor_boot_a )

  2. записывается раздел Super

  3. записываются остальные пять разделов ( misc, vbmeta_a, vbmeta_system_a, vbmeta_vendor_a, dtbo_a )

Раздел Super имеет огромный размер и хранится в образе прошивки в сжатом (sparse) формате. Потому его запись имеет особенности, которые отражены в сообщениях лога:

chunk 0, chunk 1 ... и т.д. .... chunk 3840 chunk 3841 

Весь распакованный файл разбивается на 3842 куска (chunk), и запись идет последовательно по одному куску.

Для проверки sparce-формата используется функция unsparse_probe:


#define SPARSE_HEADER_MAGIC 0xed26ff3a
#define ANDROID_FORMAT_UNKNOW (0)
#define ANDROID_FORMAT_BAD (-1)
#define ANDROID_FORMAT_DETECT (1)

int unsparse_probe(char *source, uint length, uint android_format_flash_start)
{  sparse_header_t *header = (sparse_header_t *)source;

	if (header->magic != SPARSE_HEADER_MAGIC)
	{ printf("sparse: bad magic");
      return ANDROID_FORMAT_BAD; // = -1
	}

	if ((header->major_version != SPARSE_HEADER_MAJOR_VER) ||
	    (header->file_hdr_sz != sizeof(sparse_header_t)) ||
	    (header->chunk_hdr_sz != sizeof(chunk_header_t)))
	{  printf("sparse: incompatible format");
       return ANDROID_FORMAT_BAD;  // = -1
	}

	android_format_checksum = 0;
	last_rest_size = 0;
	chunk_count = 0;
	chunk_length = 0;
	sparse_format_type = SPARSE_FORMAT_TYPE_TOTAL_HEAD;
	flash_start = android_format_flash_start;
	total_chunks = header->total_chunks;

	return ANDROID_FORMAT_DETECT;   // =1
}

Об отсутствии sparse-формата у содержимого всех разделов, кроме super, свидетельствует сообщение лога: sparse: bad magic




Лог: Запись содержимого разделов



write primary GPT success
write Backup GPT success
[08.232]update partition map

[08.239]begin to download part

[08.242]begin to download part bootloader_a
partdata hi 0x0
partdata lo 0x724c00
sparse: bad magic
[08.622]successed in writting part bootloader_a
origin_verify value = c88ada1c, active_verify value = c88ada1c
[08.684]successed in verify part bootloader_a
[08.688]successed in download part bootloader_a

[08.692]begin to download part env_a
partdata hi 0x0
partdata lo 0x20000
sparse: bad magic
[08.709]successed in writting part env_a
origin_verify value = 9ece546b, active_verify value = 9ece546b
[08.720]successed in verify part env_a
[08.723]successed in download part env_a

[08.727]begin to download part boot_a
partdata hi 0x0
partdata lo 0x4000000
sparse: bad magic
[12.059]successed in writting part boot_a
origin_verify value = 5730d9b, active_verify value = 5730d9b
[12.528]successed in verify part boot_a
[12.532]successed in download part boot_a

[12.536]begin to download part vendor_boot_a
partdata hi 0x0
partdata lo 0x2000000
sparse: bad magic
[14.200]successed in writting part vendor_boot_a
origin_verify value = f4e2c683, active_verify value = f4e2c683
[14.446]successed in verify part vendor_boot_a
[14.450]successed in download part vendor_boot_a

// ----------- Запись Super --------------------
[14.454]begin to download part super
partdata hi 0x0
partdata lo 0x5f17023c
chunk 0(3842)
chunk 1(3842)
chunk 2(3842)
chunk 3(3842)
chunk 4(3842)
chunk 5(3842)
chunk 6(3842)
chunk 7(3842)
chunk 8(3842)
chunk 9(3842)
chunk 10(3842)
chunk 11(3842)
chunk 12(3842)
chunk 13(3842)
chunk 14(3842)
chunk 15(3842)
chunk 16(3842)
chunk 17(3842)
chunk 18(3842)
chunk 19(3842)
chunk 20(3842)
......................
......................
chunk 3825(3842)
chunk 3826(3842)
chunk 3827(3842)
chunk 3828(3842)
chunk 3829(3842)
chunk 3830(3842)
chunk 3831(3842)
chunk 3832(3842)
chunk 3833(3842)
chunk 3834(3842)
chunk 3835(3842)
chunk 3836(3842)
chunk 3837(3842)
chunk 3838(3842)
chunk 3839(3842)
chunk 3840(3842)
chunk 3841(3842)

[372.946]successed in writting part super
origin_verify value = 1ed2310, active_verify value = 1ed2310
[372.959]successed in verify part super
[372.962]successed in download part super
//-------------------
[372.966]begin to download part misc
partdata hi 0x0
partdata lo 0x1000000
sparse: bad magic
[374.106]successed in writting part misc
origin_verify value = b961f417, active_verify value = b961f417
[374.229]successed in verify part misc
[374.233]successed in download part misc

[374.236]begin to download part vbmeta_a
partdata hi 0x0
partdata lo 0x2000
sparse: bad magic
[374.249]successed in writting part vbmeta_a
origin_verify value = dbf7471e, active_verify value = dbf7471e
[374.259]successed in verify part vbmeta_a
[374.263]successed in download part vbmeta_a

[374.267]begin to download part vbmeta_system_a
partdata hi 0x0
partdata lo 0x1000
sparse: bad magic
[374.278]successed in writting part vbmeta_system_a
origin_verify value = fc0dd60d, active_verify value = fc0dd60d
[374.289]successed in verify part vbmeta_system_a
[374.293]successed in download part vbmeta_system_a

[374.298]begin to download part vbmeta_vendor_a
partdata hi 0x0
partdata lo 0x1000
sparse: bad magic
[374.308]successed in writting part vbmeta_vendor_a
origin_verify value = 6eac8c8f, active_verify value = 6eac8c8f
[374.319]successed in verify part vbmeta_vendor_a
[374.324]successed in download part vbmeta_vendor_a

[374.328]begin to download part dtbo_a
partdata hi 0x0
partdata lo 0x200000
sparse: bad magic
[374.441]successed in writting part dtbo_a
origin_verify value = 6f6ab67a, active_verify value = 6f6ab67a
[374.466]successed in verify part dtbo_a
[374.470]successed in download part dtbo_a
[374.474]successed in downloading part






   1       2       3       4       5       6       7       8         9         10