======================================================================
fastboot分析:
---------------------------------
int do_fastboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {//设置u-boot,kernel,ramdisk ,system,userdata,cache空间地址 if (set_partition_table()) ----------------------------------------> // set_partition_table //主要设置bootloader ramdisk kernel 和fdisk所分的区的起始地址和大小,保存在ptable里面。 /* Bootloader */ strcpy(ptable[pcount].name, "bootloader"); ptable[pcount].start = 0; ptable[pcount].length = 0; ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; pcount++; /* Kernel */ strcpy(ptable[pcount].name, "kernel"); ptable[pcount].start = 0; ptable[pcount].length = 0; ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; pcount++; /* Ramdisk 3M */ strcpy(ptable[pcount].name, "ramdisk"); ptable[pcount].start = 0; ptable[pcount].length = 0x300000; //3MB,初始值,如果文件大于3M,则会使用文件大小 //写ramdisk的命令类型标志,这里用movi命令来写 ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD; pcount++; ----------------------- /* System */ get_mmc_part_info("0", 2, &start, &count, &pid); ------------------------- if (pid != 0x83) goto part_type_error; strcpy(ptable[pcount].name, "system"); /* decode_partitionInfo(&mbr[0x1CE], &partInfo); *block_start = partInfo.block_start; *block_count = partInfo.block_count; *part_Id = partInfo.partitionId; */ //system 开始的地址 ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; //大小,256M ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; //写system数据类型的标志,这里用MMC命令来写 ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; pcount++; /* Data 350M*/ get_mmc_part_info("0", 3, &start, &count, &pid); if (pid != 0x83) goto part_type_error; strcpy(ptable[pcount].name, "userdata"); ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; pcount++; /* Cache 100 M */ get_mmc_part_info("0", 4, &start, &count, &pid); if (pid != 0x83) goto part_type_error; strcpy(ptable[pcount].name, "cache"); ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; pcount++; /* fat 剩余空间分区,剩余空间分区格式fat?标志为 0c*/ get_mmc_part_info("0", 1, &start, &count, &pid); if (pid != 0xc) goto part_type_error; strcpy(ptable[pcount].name, "fat"); ptable[pcount].start = start * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].length = count * CFG_FASTBOOT_SDMMC_BLOCKSIZE; ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD; pcount++; -------------->----------------------------> //获取fdisk 对system userdata cache分区的大小 int get_mmc_part_info(char *device_name, int part_num, int *block_start, int *block_count, unsigned char *part_Id) { int rv; PartitionInfo partInfo; unsigned char mbr[512]; //从设备0中读取MBR主分区目录,里面定义了各个分区的信息,和起始,结束扇区 rv = get_mmc_mbr(device_name, mbr); if(rv !=0) return -1; switch(part_num) { //剩余容量空间 case 1: decode_partitionInfo(&mbr[0x1BE], &partInfo); *block_start = partInfo.block_start; *block_count = partInfo.block_count; *part_Id = partInfo.partitionId; break; //system 分区表2。fdisk给system分了256M大小 case 2: decode_partitionInfo(&mbr[0x1CE], &partInfo); *block_start = partInfo.block_start; *block_count = partInfo.block_count; *part_Id = partInfo.partitionId; //83 break; //userdata 分区 case 3: decode_partitionInfo(&mbr[0x1DE], &partInfo); *block_start = partInfo.block_start; *block_count = partInfo.block_count; *part_Id = partInfo.partitionId; break; //cache分区 case 4: decode_partitionInfo(&mbr[0x1EE], &partInfo); *block_start = partInfo.block_start; *block_count = partInfo.block_count; *part_Id = partInfo.partitionId; break; default: return -1; } return 0; } ---------------------------->
=================================================================
设置完分区地址空间后,继续
=================================================================
主要初始化usb接口,来等待数据传输。
fastboot_init(&interface)
fastboot_interface = interface;
fastboot_interface->product_name = device_strings[DEVICE_STRING_PRODUCT_INDEX];
fastboot_interface->serial_no = device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX];
fastboot_interface->nand_block_size = CFG_FASTBOOT_PAGESIZE * 64; //2046*64
fastboot_interface->transfer_buffer = (unsigned char *) CFG_FASTBOOT_TRANSFER_BUFFER;//0x40000000
fastboot_interface->transfer_buffer_size = CFG_FASTBOOT_TRANSFER_BUFFER_SIZE; //272MB
/* Fastboot variables */
#define CFG_FASTBOOT_TRANSFER_BUFFER (0x40000000) //
#define CFG_FASTBOOT_TRANSFER_BUFFER_SIZE (0x11000000) /* 272MB ,大于烧录文件就行*/
#define CFG_FASTBOOT_ADDR_KERNEL (0xC0008000)
#define CFG_FASTBOOT_ADDR_RAMDISK (0x30A00000)
#define CFG_FASTBOOT_PAGESIZE (2048) // Page size of booting device
#define CFG_FASTBOOT_SDMMC_BLOCKSIZE (512) // Block size of sdmmc
==================================
static struct cmd_fastboot_interface interface =
{
.rx_handler = rx_handler, //通过此接口烧写
.reset_handler = reset_handler,
.product_name = NULL,
.serial_no = NULL,
.nand_block_size = 0,
.transfer_buffer = (unsigned char *)0xffffffff,
.transfer_buffer_size = 0,
};
================================================================
--------------------------------------------- cmd_fastboot.c ----------------------------- //擦除接口 fastboot erase if (memcmp(cmdbuf, "erase:", 6) == 0) { struct fastboot_ptentry *ptn; ptn = fastboot_flash_find_ptn(cmdbuf + 6); if (ptn == 0) ------------------------------------------------------------ //获取fat system userdata cache 分区名字 fastboot_ptentry *fastboot_flash_find_ptn(const char *name) { unsigned int n; for (n = 0; n < pcount; n++) { /* Make sure a substring is not accepted */ if (strlen(name) == strlen(ptable[n].name)) { if (0 == strcmp(ptable[n].name, name)) return ptable + n; } } return 0; } ------------------------------------------------------- //只有擦除userdata cache fat 这几个功能,kernel u-boot ramdisk 不能擦除 //其实就是调用ext3format fatmot等格式命令 ,需要添加system 擦除命令 char run_cmd[80]; status = 1; if (!strcmp(ptn->name, "sytem")) { sprintf(run_cmd, "ext3format mmc 0:2"); status = run_command(run_cmd, 0); } Else if (!strcmp(ptn->name, "userdata")) { sprintf(run_cmd, "ext3format mmc 0:3"); status = run_command(run_cmd, 0); } else if (!strcmp(ptn->name, "cache")) { sprintf(run_cmd, "ext3format mmc 0:4"); status = run_command(run_cmd, 0); } else if (!strcmp(ptn->name, "fat")) { sprintf(run_cmd, "fatformat mmc 0:1"); status = run_command(run_cmd, 0); } =======================================================
Flash what was downloaded */ if (memcmp(cmdbuf, "flash:", 6) == 0) { if (download_bytes == 0) { sprintf(response, "FAILno image downloaded"); ret = 0; goto send_tx_status; } //从此句开始判断 kernel。 ramdisk system,获取ptable ptn = fastboot_flash_find_ptn(cmdbuf + 6); ---------------------- if ((download_bytes > ptn->length) && (ptn->length != 0) && !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { //注意。system写,会出现这个信息。注意检查 //分析,只有当system文件大小小于分区大小时,是不会进入的 sprintf(response, "FAILimage too large for partition"); /* TODO : Improve check for yaffs write */ } else { /* Normal case */ if (write_to_ptn(ptn, (unsigned int)interface.transfer_buffer, download_bytes)) { printf("flashing '%s' failed\n", ptn->name); sprintf(response, "FAILfailed to flash partition"); } else { printf("partition '%s' flashed\n", ptn->name); sprintf(response, "OKAY"); } } -------------------------------------------
/* Kernel */
strcpy(ptable[pcount].name, "kernel");
ptable[pcount].start = 0;
ptable[pcount].length = 0;
ptable[pcount].flags = FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD;
pcount++;
#######################################################################
static int write_to_ptn(struct fastboot_ptentry *ptn, unsigned int addr, unsigned int size) { #elif defined(CFG_FASTBOOT_SDMMCBSP) { int ret = 1; char device[32], part[32]; char start[32], length[32], buffer[32]; char *argv[6] = { NULL, "write", NULL, NULL, NULL, NULL, }; int argc = 0; //区别出kernel u-boot ,当ramdisk,system等文件大于分区大小时。 if ((ptn->length != 0) && (size > ptn->length)) { printf("Error: Image size is larger than partition size!\n"); return 1; }//add by xiao@2012-04-16 : 只获取实际文件大小,因下面烧写文件时,是根据分区大小来烧写文件。对于几百MB的空间来说实在是太大和耗时间。 real_len = (size /CFG_FASTBOOT_SDMMC_BLOCKSIZE + 1); //写system userdata cache fat 接口 if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_USE_MMC_CMD) { argv[2] = device; argv[3] = buffer; argv[4] = start; argv[5] = length; sprintf(device, "mmc %d", 1); sprintf(buffer, "0x%x", addr); sprintf(start, "0x%x", (ptn->start / CFG_FASTBOOT_SDMMC_BLOCKSIZE)); //sprintf(length, "0x%x", (ptn->length / CFG_FASTBOOT_SDMMC_BLOCKSIZE)); //add by xiao@2012-04-16 : #ifndef CONFIG_EMMC_INAND sprintf(length, "0x%x", (ptn->length / CFG_FASTBOOT_SDMMC_BLOCKSIZE)); #else sprintf(length, "0x%x", real_len); #endif //mmc 命令 ret = do_mmcops(NULL, 0, 6, argv); }//写u-boot kernel ramdisk接口 else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_USE_MOVI_CMD) { argv[2] = part; //指向part argv[3] = buffer; //指向buffer argc = 4; /* use the partition name that can be understood by a command, movi */ if (!strcmp(ptn->name, "bootloader")) { // part 改为 u-boot 名称 ,为movi 读写作区别 strncpy(part, "u-boot", 7); } else if (!strcmp(ptn->name, "ramdisk")) { //改为rootfs 名称,为movi 读写作区别 strncpy(part, "rootfs", 7); //指向length, argv[4] = length; //此时,ramdisk 大小为下载的文件实际大小。 download_bytes sprintf(length, "0x%x", ((size + CFG_FASTBOOT_SDMMC_BLOCKSIZE - 1) / CFG_FASTBOOT_SDMMC_BLOCKSIZE ) * CFG_FASTBOOT_SDMMC_BLOCKSIZE); argc++; } else /* kernel, fwbl1 */ { //kernel 名称 argv[2] = ptn->name; } //把DRAM1 = 0x40000000 地址给buffer sprintf(buffer, "0x%x", addr); //用movi命令写kernel ,ramdisk u-boot数据 ret = do_movi(NULL, 0, argc, argv); /* the return value of do_movi is different from usual commands. Hence the followings. */ ret = 1 - ret; } return ret; }===========================
cmd_mmc.c
====================
注意:此命令 movi也会调用,mmc也调用。所以u-boot
kernel ramdisk system等多是调用此接口
也就是do_movi调用 do_mmcops命令来读写
int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int rc = 0; switch (argc) { default: /* at least 5 args */ if (strcmp(argv[1], "write") == 0) { int dev = simple_strtoul(argv[2], NULL, 10); void *addr = (void *)simple_strtoul(argv[3], NULL, 16); u32 cnt = simple_strtoul(argv[5], NULL, 10); int blk = simple_strtoul(argv[4], NULL, 10); u32 n; u32 written_cnt; u32 cnt_to_write; void *addr_to_write = addr; struct mmc *mmc = find_mmc_device(dev); if (!mmc) return 1; //重新初始化设备。 rc = mmc_init(mmc); if(rc) return rc; n = 0; addr_to_write = addr; do { if (cnt - n > MAXIMUM_BLOCK_COUNT) cnt_to_write = MAXIMUM_BLOCK_COUNT; else cnt_to_write = cnt - n; written_cnt = mmc->block_dev.block_write(dev, blk, cnt_to_write, addr_to_write); n += written_cnt; blk += written_cnt; addr_to_write += written_cnt * 512; if(cnt_to_write != written_cnt) { printf("%d blocks written: %s\n", n, "ERROR"); return -1; } } while(cnt > n); printf("%d blocks written: %s\n", n, "OK"); return 0; } else { printf("Usage:\n%s\n", cmdtp->usage); rc = 1; } return rc; } } ---------------------------------------------
---------------------------------------------
分析 ret = do_movi(NULL, 0, argc, argv);
分析 u-boot kernel ramdisk 烧写!!!
---------------------------------------
int do_movi(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { char *cmd; ulong addr, start_blk, blkcnt; uint rfs_size; char run_cmd[100]; uint rw = 0, attribute = 0; int i; member_t *image; struct mmc *mmc; //此处节点为 0 int dev_num = 0; cmd = argv[1]; switch (cmd[0]) { case 'r': rw = 0; /* read case */ break; case 'w': rw = 1; /* write case */ break; default: goto usage; } //获取,文件名称 cmd = argv[2]; switch (cmd[0]) { //u-boot case 'u': if (argc != 4) goto usage; attribute = 0x2; //地址为DRAM1 = 0x40000000 此处的地址 addr = simple_strtoul(argv[3], NULL, 16); break; //kernel case 'k': if (argc != 4) goto usage; attribute = 0x4; //地址为DRAM1 = 0x40000000 此处的地址 addr = simple_strtoul(argv[3], NULL, 16); break; //rootfs case 'r': if (argc != 5) goto usage; attribute = 0x8; //地址为DRAM1 = 0x40000000 此处的地址 addr = simple_strtoul(argv[3], NULL, 16); break; default: goto usage; } //此处查找节点 0 mmc = find_mmc_device(dev_num); //重新注册 mmc_init(mmc); /* u-boot r/w */ //bl2 后半部分区域: u-boot 大小 512K if (attribute == 0x2) { //rw =1 表示写。0:表示读 if (rw) { //先去写BL1部分 start_blk = raw_area_control.image[1].start_blk; blkcnt = raw_area_control.image[1].used_blk; printf("Writing BL1 to sector %ld (%ld sectors).. ", start_blk, blkcnt); //16M + 1K -- 16M + 1K + 8K //从dram1 上吧数据写入BL1 区域 movi_write_bl1(addr); } //找到BL2后半部分位置。 for (i=0, image = raw_area_control.image; i<15; i++) { if (image[i].attribute == attribute) break; } //image[3] 大小512k start_blk = image[i].start_blk; blkcnt = image[i].used_blk; printf("%s bootloader.. %ld, %ld ", rw ? "writing":"reading", start_blk, blkcnt); //使用mmc 命令来烧写 bl2 后半部分 sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx", rw ? "write":"read", addr, start_blk, blkcnt); //mmc write 0 0x40000000 star len //do_mmcops 写的时候,会根据argv[2]来获取设备号。 //这里 mmc write 0 指定了设备号了。 //16M + 9K +16K -- 16M + 25K +512K run_command(run_cmd, 0); printf("completed\n"); return 1; } //烧写内核 16M + 25K +512K -- 16M + 25K +512K + 4MB /* kernel r/w */ if (attribute == 0x4) { //找到内核区域 image[4] for (i=0, image = raw_area_control.image; i<15; i++) { if (image[i].attribute == attribute) break; } // start_blk = image[i].start_blk; //大小为4MB blkcnt = image[i].used_blk; printf("%s kernel.. %ld, %ld ", rw ? "writing" : "reading", start_blk, blkcnt); //命令 mmc write 0 0x40000000 star len sprintf(run_cmd, "mmc %s 0 0x%lx 0x%lx 0x%lx", rw ? "write" : "read", addr, start_blk, blkcnt); //写入到设备 0中 run_command(run_cmd, 0); printf("completed\n"); return 1; } //根文件系统烧写 16M + 25K +512K + 4MB - 16M + 25K +512K + 4MB +26MB /* root file system r/w */ if (attribute == 0x8) { //获取rootfs的实际文件大小 download_bytes rfs_size = simple_strtoul(argv[4], NULL, 16); //获取rootfs 区域 image[5] for (i=0, image = raw_area_control.image; i<15; i++) { if (image[i].attribute == attribute) break; } start_blk = image[i].start_blk; //一个块512的大小对齐 blkcnt = rfs_size/MOVI_BLKSIZE + ((rfs_size&(MOVI_BLKSIZE-1)) ? 1 : 0); image[i].used_blk = blkcnt; printf("%s RFS.. %ld, %ld ", rw ? "writing":"reading", start_blk, blkcnt); //写rootfs 16M + 25K +512K + 4MB - 16M + 25K +512K + 4MB +26MB sprintf(run_cmd,"mmc %s 0 0x%lx 0x%lx 0x%lx", rw ? "write":"read", addr, start_blk, blkcnt); run_command(run_cmd, 0); printf("completed\n"); return 1; } return 1; usage: printf("Usage:\n%s\n", cmdtp->usage); return -1; }
#########################################################
分析:cmd_movi.c
#ifdef CONFIG_CMD_MOVINAND
init_raw_area_table(&host->block_dev);
#endif
#########################################################
int init_raw_area_table (block_dev_desc_t * dev_desc) { //找到设备 struct mmc *host = find_mmc_device(dev_desc->dev); //第一次确实不相等 if (raw_area_control.magic_number != MAGIC_NUMBER_MOVI) { int i = 0; member_t *image; u32 capacity; if (host->high_capacity) { capacity = host->capacity; #ifdef CONFIG_S3C6410 if(IS_SD(host)) capacity -= 1024; #endif } else { //注意此处,块大小 > 512时 capacity = host->capacity * (host->read_bl_len / MOVI_BLKSIZE); } //读取是否有raw分区表。 dev_desc->block_read(dev_desc->dev, capacity - (eFUSE_SIZE/MOVI_BLKSIZE) - 1, 1, &raw_area_control); if (raw_area_control.magic_number == MAGIC_NUMBER_MOVI) { return 0; } //没有raw分区表就增加一个 /* add magic number */ raw_area_control.magic_number = MAGIC_NUMBER_MOVI; //从bl1 开始放 /* init raw_area will be 16MB */ //一个块大小512,的倍数表示起始的块地址,也就是偏移16M? raw_area_control.start_blk = 16*1024*1024/MOVI_BLKSIZE; //0.5k 的efuse 和 0.5k的recvers 总大小块 raw_area_control.total_blk = capacity; raw_area_control.next_raw_area = 0; strcpy(raw_area_control.description, "initial raw table"); //指向image image = raw_area_control.image; /* image 0 should be fwbl1 */ //image【0】 我们没必要有。 ####################################### /* image 1 should be bl2 */ //第一次写完了efuse后,在它后面写bl2.所以使用efuse作为起始块地址。 image[1].start_blk = (eFUSE_SIZE/MOVI_BLKSIZE); //8K 的块大小个数 image[1].used_blk = MOVI_BL1_BLKCNT; //大小8K image[1].size = SS_SIZE; image[1].attribute = 0x1; //标注此区为u-boot parted strcpy(image[1].description, "u-boot parted"); ####################################################### //接下来保存环境参数 /* image 2 should be environment */ //上一个的结束块地址 image[2].start_blk = image[1].start_blk + MOVI_BL1_BLKCNT; //使用了16k的块大小个数 image[2].used_blk = MOVI_ENV_BLKCNT; //大小16K image[2].size = CFG_ENV_SIZE; image[2].attribute = 0x10; //标注此区为 environment strcpy(image[2].description, "environment"); dbg("env: %d\n", image[2].start_blk); ########################################################### /* image 3 should be bl2 */ //开始放BL2 image[3].start_blk = image[2].start_blk + MOVI_ENV_BLKCNT; //512KB的块大小个数 image[3].used_blk = MOVI_BL2_BLKCNT; //512KB image[3].size = PART_SIZE_BL; image[3].attribute = 0x2; //标注此区为u-boot strcpy(image[3].description, "u-boot"); dbg("bl2: %d\n", image[3].start_blk); #################################################### /* image 4 should be kernel */ //这里接下来存放内核信息 image[4].start_blk = image[3].start_blk + MOVI_BL2_BLKCNT; //4M的块大小个数 image[4].used_blk = MOVI_ZIMAGE_BLKCNT; //大小4M image[4].size = PART_SIZE_KERNEL; image[4].attribute = 0x4; //标注此区为kernel strcpy(image[4].description, "kernel"); dbg("knl: %d\n", image[4].start_blk); ###################################################### /* image 5 should be RFS */ //接下来放rootfs image[5].start_blk = image[4].start_blk + MOVI_ZIMAGE_BLKCNT; //26M的块大小 image[5].used_blk = MOVI_ROOTFS_BLKCNT; //26M大小 image[5].size = PART_SIZE_ROOTFS; image[5].attribute = 0x8; strcpy(image[5].description, "rfs"); dbg("rfs: %d\n", image[5].start_blk); for (i=6; i<15; i++) { raw_area_control.image[i].start_blk = 0; raw_area_control.image[i].used_blk = 0; } ------------------------------总结一下:
raw 分区:
16M -- 16M + 1K : efuse区域 标示:initial raw table
image[1] , 0x1
16M + 1K -- 16M + 1K + 8K :bl2前半部分区域标示: u-boot parted
image[2] , 0x10
16M + 9K -- 16M + 9K +16K : 环境参数保存区域:environment
image[3], 0x2
16M + 9K +16K -- 16M + 25K +512K :bl2 后半部分区域: u-boot
image[4[, 0x4
16M + 25K +512K -- 16M + 25K +512K + 4MB : kernel 区域: kernel
image[5],0x8
16M + 25K +512K + 4MB - 16M + 25K +512K + 4MB +26MB
rootfs区域,表示: rfs
image[5].attribute = 0x8;
方便烧写对应:
case 'r':
if (argc != 5)
goto usage;
attribute = 0x8;
###############################################################