10. Запись boot0 и U-Boot, завершение операций
После записи содержимого разделов eMMC происходит запись в неразмеченную область,
расположенную в самом начале загрузочной памяти eMMC.
Для записи U-Boot и boot_psckage используется функция sunxi_sprite_deal_uboot(),
для записи boot0 используется функция sunxi_sprite_deal_boot0().
Их исходные тексты приведены ниже.
typedef enum _SUNXI_BOOT_FILE_MODE
{ SUNXI_BOOT_FILE_NORMAL= 0,
SUNXI_BOOT_FILE_TOC = 1,
SUNXI_BOOT_FILE_RES0 = 2,
SUNXI_BOOT_FILE_RES1 = 3,
SUNXI_BOOT_FILE_PKG = 4
} SUNXI_BOOT_FILE_MODE;
//---------------
int sunxi_sprite_deal_uboot(int production_media)
{
char *buffer;
buffer = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE,
ALIGN(4*1024*1024, CONFIG_SYS_CACHELINE_SIZE));
uint item_original_size;
if (gd->bootfile_mode == SUNXI_BOOT_FILE_NORMAL)
imgitemhd = Img_OpenItem(imghd, "12345678", "UBOOT_0000000000");
else if (gd->bootfile_mode == SUNXI_BOOT_FILE_PKG)
{ if (get_boot_storage_type() != STORAGE_NOR)
imgitemhd = Img_OpenItem(imghd, "12345678","BOOTPKG-00000000");
else
imgitemhd = Img_OpenItem(imghd, "12345678","BOOTPKG-NOR00000");
}
else
imgitemhd = Img_OpenItem(imghd, "12345678", "TOC1_00000000000");
if (!imgitemhd)
{ printf("sprite update error: fail to open uboot item");
return -1;
}
item_original_size = Img_GetItemSize(imghd, imgitemhd);
if (!item_original_size)
{ printf("sprite update error: fail to get uboot item size");
return -1;
}
if (!Img_ReadItem(imghd, imgitemhd, (void *)buffer, 4*1024*1024)) // 4 Mbyte
{ printf("update error: fail to read data from for uboot");
return -1;
}
Img_CloseItem(imghd, imgitemhd);
imgitemhd = NULL;
if (sunxi_sprite_download_uboot(buffer, production_media, 0))
{ printf("update error: fail to write uboot");
return -1;
}
printf("sunxi_sprite_deal_uboot ok");
free(buffer);
return 0;
}
Запись вторичного загрузчика Boot0 (SPL) выполняется функцией
sunxi_sprite_deal_boot0()
int sunxi_sprite_deal_boot0(int production_media)
{ char *buffer = NULL;
uint item_original_size;
buffer = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, ALIGN(1*1024*1024,
CONFIG_SYS_CACHELINE_SIZE));
if (!buffer)
{ printf("err: unable to malloc memory");
return -1;
}
if (gd->bootfile_mode == SUNXI_BOOT_FILE_NORMAL ||
gd->bootfile_mode == SUNXI_BOOT_FILE_PKG)
{ if (production_media == STORAGE_NAND)
imgitemhd = Img_OpenItem(imghd, "BOOT", "BOOT0_0000000000");
else if (production_media == STORAGE_NOR)
imgitemhd = Img_OpenItem(imghd, "12345678","1234567890BNOR_0");
else
imgitemhd = Img_OpenItem(imghd, "12345678", "1234567890BOOT_0");
}
}
else
imgitemhd = Img_OpenItem(imghd, "12345678", "TOC0_00000000000");
if (!imgitemhd)
{ printf("sprite update error: fail to open boot0 item");
goto sprite_boot0_fail;
}
// размер boot0
item_original_size = Img_GetItemSize(imghd, imgitemhd);
if (!item_original_size)
{ printf("sprite update error: fail to get boot0 item size");
goto sprite_boot0_fail;
}
// Получить данные boot0
if (!Img_ReadItem(imghd, imgitemhd, (void *)buffer, 1 * 1024 * 1024))
{ printf("update error: fail to read data from for boot0");
goto sprite_boot0_fail;
}
Img_CloseItem(imghd, imgitemhd);
imgitemhd = NULL;
if (sunxi_sprite_download_boot0(buffer, production_media))
{ printf("update error: fail to write boot0");
goto sprite_boot0_fail;
}
return 0;
sprite_boot0_fail:
free(buffer);
return -1;
}
Заметим, что обе эти функции практически идентичны и отличаются лишь одной строкой:
sunxi_sprite_download_uboot или sunxi_sprite_download_boot0
//--------------------------------
int sunxi_sprite_download_uboot(void *buffer, int production_media,
int generate_checksum)
{ u32 length = 0;
sbrom_toc1_head_info_t *toc1 = (sbrom_toc1_head_info_t *)buffer;
if(toc1->magic != TOC_MAIN_INFO_MAGIC)
{ printf("sunxi sprite: toc magic is error");
printf("need %s image",
gd->bootfile_mode == SUNXI_BOOT_FILE_TOC ? "secure" : "normal");
return -1;
}
length = toc1->valid_len;
if(generate_checksum)
{ toc1->add_sum = sunxi_sprite_generate_checksum(buffer,
toc1->valid_len,toc1->add_sum);
}
printf("uboot size = 0x%x", length);
printf("storage type = %d", production_media);
#ifdef CONFIG_SUNXI_BURN_ROTPK_ON_SPRITE
sunxi_verify_preserve_toc1(buffer);
#endif
return sunxi_sprite_download_toc(buffer, length, production_media);
}
//-------------------------------------
int sunxi_sprite_download_boot0(void *buffer, int production_media)
{
if(gd->bootfile_mode == SUNXI_BOOT_FILE_NORMAL ||
gd->bootfile_mode == SUNXI_BOOT_FILE_PKG)
return download_normal_boot0(buffer, production_media);
else
return download_secure_boot0(buffer, production_media);
/* usb dma recv time out maybe enter usb product twice
* brom enter fel mode or boot0 enter fel mode
*/
rtc_set_bootmode_flag(0);
}
В сообщениях лога присутствуют строки:
dram para[0] = 288
dram para[1] = 3
...........
dram para[30] = 6041
dram para[31] = 0
storage type = 2
Эти сообщения - результат выполнения функции
download_normal_boot0
//---------------------------------
int download_normal_boot0(void *buffer, int production_media)
{ boot0_file_head_t *boot0 = (boot0_file_head_t *)buffer;
debug("%s", boot0->boot_head.magic);
if(strncmp((const char *)boot0->boot_head.magic, BOOT0_MAGIC, MAGIC_SIZE))
{ printf("sunxi sprite: boot0 magic is error");
return -1;
}
if(sunxi_sprite_verify_checksum(buffer,
boot0->boot_head.length,
boot0->boot_head.check_sum))
{ printf("sunxi sprite: boot0 checksum is error");
return -1;
}
if(!production_media)
{ if (production_media == STORAGE_EMMC)
{ if (mmc_write_info(2, (void *)boot0->prvt_head.storage_data,
STORAGE_BUFFER_SIZE))
{ printf("add sdmmc2 private info fail!");
return -1;
}
}
if (uboot_spare_head.boot_data.work_mode == WORK_MODE_CARD_PRODUCT)
{ memcpy((void *)&boot0->prvt_head.dram_para,
(void *)(uboot_spare_head.boot_data.dram_para), 32 * 4);
/*update dram flag*/
set_boot_dram_update_flag(boot0->prvt_head.dram_para);
}
else if (uboot_spare_head.boot_data.work_mode == WORK_MODE_UDISK_UPDATE ||
uboot_spare_head.boot_data.work_mode == WORK_MODE_CARD_UPDATE ||
uboot_spare_head.boot_data.work_mode == WORK_MODE_SPRITE_RECOVERY ||
uboot_spare_head.boot_data.work_mode == WORK_MODE_BOOT)
{ printf("skip memcpy dram para for work_mode: %d ",
uboot_spare_head.boot_data.work_mode);
}
else
{ memcpy((void *)boot0->prvt_head.dram_para,
(void *)CONFIG_DRAM_PARA_ADDR, 32 * 4);
/*update dram flag*/
set_boot_dram_update_flag(boot0->prvt_head.dram_para);
}
dump_dram_para(boot0->prvt_head.dram_para,32);
/* regenerate check sum */
boot0->boot_head.check_sum = sunxi_sprite_generate_checksum(buffer,
boot0->boot_head.length,
boot0->boot_head.check_sum);
if(sunxi_sprite_verify_checksum(buffer, boot0->boot_head.length, boot0->boot_head.check_sum)) {
printf("sunxi sprite: boot0 checksum is error");
return -1;
}
printf("storage type = %d", production_media);
return sunxi_sprite_download_spl(buffer, boot0->boot_head.length, production_media);
}
//---------------------------------------
static void dump_dram_para(void* dram, uint size)
{ int i;
uint *addr = (uint *)dram;
for(i = 0; i < size; i++) {
printf("dram para[%d] = %x", i, addr[i]);
}
}
Появление сообщений:
CARD OK и sprite success
означает нормальное завершение процедуры записи прошивки в eMMC
Завершающие действия после записи прошивки определяются установленным параметром
sprite_next_work, которое может принимать значения:
#define SUNXI_UPDATE_NEXT_ACTION_NORMAL (1)
#define SUNXI_UPDATE_NEXT_ACTION_REBOOT (2)
#define SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN (3)
#define SUNXI_UPDATE_NEXT_ACTION_REUPDATE (4)
#define SUNXI_UPDATE_NEXT_ACTION_BOOT (5)
#define SUNXI_UPDATA_NEXT_ACTION_SPRITE_TEST (6)
В данном случае устанавливается значение SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN, равное 3,
которое означает переход к выключению питания.
if (fdt_getprop_u32(working_fdt, nodeoffset, "next_work",
(uint32_t *)&sprite_next_work) < 0)
sprite_next_work = SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN;
printf("sprite_next_work=%d", sprite_next_work);
sunxi_update_subsequent_processing(sprite_next_work);
return 0;
}
Вызов функции проверяет в дереве устройств FDT наличие узла
с имененем "next_work", результат (= -13 < 0) означет его отсутствие.
//------------------------------------------------------------
Найти узел и вернуть его свойство или значение по умолчанию.
// fdt: указатель для дерева устройств
// nodeoffset: с помощью функции fdt_path_offset()
// prop: имя свойства
// val: возвращаемое значение, если свойство найдено
// Примечание. возвращаемое значение — это элемент u32.
//------------------------------------------------------------
#define FDT_ERR_INTERNAL 13
nt fdt_getprop_u32(const void *fdt, int nodeoffset,
const char *prop, uint32_t *val)
{ int len;
const fdt32_t* data=NULL;
data = fdt_getprop(fdt, nodeoffset, prop, &len);
if((data == NULL) || (len ==0) || (len % 4 != 0))
return -FDT_ERR_INTERNAL;
if(val != NULL)
{ const uint32_t *p = data;
int j ;
for (j = 0, p = data; j < len/4; j++)
{ *val = fdt32_to_cpu(p[j]);
val++;
}
}
return len/4;
}
Лог: Запись boot0 и U-Boot, завершение операций
uboot size = 0x134000
storage type = 2
sunxi_sprite_deal_uboot ok
[374.669]successed in downloading uboot
[374.680][mmc]: write mmc 2 info ok
dram para[0] = 288
dram para[1] = 3
dram para[2] = 3030303
dram para[3] = e0e0e0e
dram para[4] = 1c12
dram para[5] = 1
dram para[6] = 30fb
dram para[7] = 8000000
dram para[8] = 1f14
dram para[9] = 4
dram para[10] = 20
dram para[11] = 0
dram para[12] = 0
dram para[13] = 0
dram para[14] = 0
dram para[15] = 0
dram para[16] = 0
dram para[17] = 0
dram para[18] = 0
dram para[19] = 0
dram para[20] = 0
dram para[21] = 0
dram para[22] = c0000c05
dram para[23] = 80000000
dram para[24] = 0
dram para[25] = 0
dram para[26] = 33808080
dram para[27] = 2f0007
dram para[28] = ffffdddd
dram para[29] = fedf7557
dram para[30] = 6041
dram para[31] = 0
storage type = 2
[374.746]successed in downloading boot0
current bitmap buffer size is 0 and new bitmap size is 483.
pitch abs is 21 and glyph rows is 23.
current bitmap buffer size is 483 and new bitmap size is 529.
pitch abs is 23 and glyph rows is 23.
CARD OK
[374.768]sprite success
sprite_next_work=3
next work 3
SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN
[377.776][mmc]: mmc exit start
[377.793][mmc]: mmc 2 exit ok