/**********************************************************************
* mkbootimg hacking
* 声明:
* 1. 本文源代码来自myzr_android4_2_2_1_1_0.tar.bz2中的mkbootimg.c;
* 2. 通过阅读该源码,可知Android的boot.img合成原理;
*
* 深圳 南山平山村 曾剑鋒 Mon May 4 13:09:49 CST 2015
**********************************************************************/ /* tools/mkbootimg/mkbootimg.c
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/ typedef struct boot_img_hdr boot_img_hdr; #define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512 /**
* 用于暂存需要的数据的结构体
*/
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE]; //文件类型标识 unsigned kernel_size; /* size in bytes 内核文件大小 */
unsigned kernel_addr; /* physical load addr 内核文件的起始地址 */ unsigned ramdisk_size; /* size in bytes randisk文件的大小*/
unsigned ramdisk_addr; /* physical load addr randisk文件的起始地址 */ unsigned second_size; /* size in bytes */
unsigned second_addr; /* physical load addr */ unsigned tags_addr; /* physical addr for kernel tags */
unsigned page_size; /* flash page size we assume */
unsigned unused[]; /* future expansion: should be 0 */ unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ unsigned char cmdline[BOOT_ARGS_SIZE]; /* 如果U-Boot没有指定bootargs,就会使用这里的参数 */ unsigned id[]; /* timestamp / checksum / sha1 / etc 个人感觉主要用于保存校验数据 */
}; #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> #include "mincrypt/sha.h"
#include "bootimg.h" /**
* 主要用于加载各种需要的文件的函数
*/
static void *load_file(const char *fn, unsigned *_sz)
{
char *data;
int sz;
int fd; data = ;
fd = open(fn, O_RDONLY); //带开文件
if(fd < ) return ; sz = lseek(fd, , SEEK_END); //跳到文件末尾,这样就知道文件的大小了
if(sz < ) goto oops; if(lseek(fd, , SEEK_SET) != ) goto oops; //返回到文件头 data = (char*) malloc(sz); //分配和文件一样大小的内存空间
if(data == ) goto oops; if(read(fd, data, sz) != sz) goto oops; //将文件内容读取到内存中
close(fd); if(_sz) *_sz = sz; //相当于返回文件的大小
return data; //返回文件数据的首地址 oops:
close(fd);
if(data != ) free(data);
return ;
} /**
* mkbootimg使用说明
*/
int usage(void)
{
fprintf(stderr,"usage: mkbootimg\n"
" --kernel <filename>\n"
" --ramdisk <filename>\n"
" [ --second <2ndbootloader-filename> ]\n"
" [ --cmdline <kernel-commandline> ]\n"
" [ --board <boardname> ]\n"
" [ --base <address> ]\n"
" [ --pagesize <pagesize> ]\n"
" -o|--output <filename>\n"
);
return ;
} /**
* boot.img中每部分数据都是以页为单位存储的,如果数据不足一页的倍数,
* 那么就将该页剩下的空间以0填充
*/
static unsigned char padding[] = { , }; int write_padding(int fd, unsigned pagesize, unsigned itemsize)
{
/**
* pagesize一般都是比较大的整数,例如:1k,2k,4k等等,那么
* pagesize-1,就变成了由0开始,后面跟了一堆1,例如:
* 1k = 10000000000(二进制);
* 1k-1 = 01111111111(二进制);
*/
unsigned pagemask = pagesize - ;
unsigned count; /**
* 由上面的解析可知,这里是确保itemsize需要填充的0的个数
* 小于pagesize并且大于0
* itemsize&pagemask相当于itemsize对pagemask取余
*/
if((itemsize & pagemask) == ) {
return ;
} /**
* 计算出需要填充多少个0, itemsize&pagemask相当于itemsize对pagemask取余
*/
count = pagesize - (itemsize & pagemask); if(write(fd, padding, count) != count) {
return -;
} else {
return ;
}
} int main(int argc, char **argv)
{
boot_img_hdr hdr; char *kernel_fn = ;
void *kernel_data = ;
char *ramdisk_fn = ;
void *ramdisk_data = ;
char *second_fn = ;
void *second_data = ;
char *cmdline = "";
char *bootimg = ;
char *board = "";
unsigned pagesize = ; //默认一页占用2K
int fd;
SHA_CTX ctx;
uint8_t* sha;
unsigned base = 0x10000000; //基址
unsigned kernel_offset = 0x00008000;
unsigned ramdisk_offset = 0x01000000;
unsigned second_offset = 0x00f00000;
unsigned tags_offset = 0x00000100; //可执行文件必须有参数,需知道内核文件在那里,ramdisk在那里等等信息
argc--;
argv++; memset(&hdr, , sizeof(hdr)); //清空结构体数据 /**
* 获取命令行参数
*/
while(argc > ){
char *arg = argv[];
char *val = argv[];
if(argc < ) {
return usage();
}
argc -= ;
argv += ;
if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
bootimg = val;
} else if(!strcmp(arg, "--kernel")) {
kernel_fn = val;
} else if(!strcmp(arg, "--ramdisk")) {
ramdisk_fn = val;
} else if(!strcmp(arg, "--second")) {
second_fn = val;
} else if(!strcmp(arg, "--cmdline")) {
cmdline = val;
} else if(!strcmp(arg, "--base")) {
base = strtoul(val, , );
} else if(!strcmp(arg, "--kernel_offset")) {
kernel_offset = strtoul(val, , );
} else if(!strcmp(arg, "--ramdisk_offset")) {
ramdisk_offset = strtoul(val, , );
} else if(!strcmp(arg, "--second_offset")) {
second_offset = strtoul(val, , );
} else if(!strcmp(arg, "--tags_offset")) {
tags_offset = strtoul(val, , );
} else if(!strcmp(arg, "--board")) {
board = val;
} else if(!strcmp(arg,"--pagesize")) {
pagesize = strtoul(val, , );
if ((pagesize != ) && (pagesize != )) { //页大小只能是两种情况,2k或者4k
fprintf(stderr,"error: unsupported page size %d\n", pagesize);
return -;
}
} else {
return usage();
}
}
hdr.page_size = pagesize; //设置页大小 /**
* 计算各种偏移地址
*/
hdr.kernel_addr = base + kernel_offset;
hdr.ramdisk_addr = base + ramdisk_offset;
hdr.second_addr = base + second_offset;
hdr.tags_addr = base + tags_offset; if(bootimg == ) {
fprintf(stderr,"error: no output filename specified\n");
return usage();
} if(kernel_fn == ) {
fprintf(stderr,"error: no kernel image specified\n");
return usage();
} if(ramdisk_fn == ) {
fprintf(stderr,"error: no ramdisk image specified\n");
return usage();
} if(strlen(board) >= BOOT_NAME_SIZE) {
fprintf(stderr,"error: board name too large\n");
return usage();
} strcpy(hdr.name, board); //板子类型 memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); //文件类型 //kernel命令行参数,如果U-Boot没有给出,将是用这里的参数
if(strlen(cmdline) > (BOOT_ARGS_SIZE - )) {
fprintf(stderr,"error: kernel commandline too large\n");
return ;
}
strcpy((char*)hdr.cmdline, cmdline); //加载内核文件,同时获取内核文件的大小
kernel_data = load_file(kernel_fn, &hdr.kernel_size);
if(kernel_data == ) {
fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
return ;
} if(!strcmp(ramdisk_fn,"NONE")) {
ramdisk_data = ;
hdr.ramdisk_size = ;
} else {
ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
if(ramdisk_data == ) {
fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
return ;
}
} if(second_fn) {
second_data = load_file(second_fn, &hdr.second_size);
if(second_data == ) {
fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
return ;
}
} /* put a hash of the contents in the header so boot images can be
* differentiated based on their first 2k.
*/
/**
* 个人理解这里是产生一些校验数据,可以不用关心,不影响阅读
*/
SHA_init(&ctx);
SHA_update(&ctx, kernel_data, hdr.kernel_size);
SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
SHA_update(&ctx, second_data, hdr.second_size);
SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
sha = SHA_final(&ctx);
memcpy(hdr.id, sha,
SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); /**
* 打开输出目标文件,如果文件不存在,那么就创建该文件,如果存在,那么就清空
*/
fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, );
if(fd < ) {
fprintf(stderr,"error: could not create '%s'\n", bootimg);
return ;
} /**
* 这里相当于写入文件头,和写bmp文件差不多的意思
*/
if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; /**
* 接下来按一定顺序写内容
*/
if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; if(second_data) {
if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
} return ; fail:
unlink(bootimg);
close(fd);
fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
strerror(errno));
return ;
}

最新文章

  1. URL Quoting
  2. tableviewcell边距和设置值不符
  3. activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
  4. 安装 centos7 注意事项
  5. sql server2012 动态端口
  6. 将小度WiFi改造为无线网卡(小度WiFi能够接收WiFi信号)
  7. JAVA 环境变量
  8. 第一篇:K-近邻分类算法原理分析与代码实现
  9. 如何在TableView上添加悬浮按钮
  10. Linux入门之常用命令(10)软连接 硬链接
  11. Python进阶---面向对象第三弹(进阶篇)
  12. myeclipse 的Customize Perspective 没有反应
  13. mybatis 调用 oracle 存储过程 select into 无记录时NO_DATA_FOUND异常处理分析
  14. redux学习与使用
  15. Android ListView几个重要属性
  16. CEIL与FLOOR
  17. 安全测试之bWAPP环境搭建
  18. SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化
  19. unity 归纳
  20. 3dsmax2014的下载、安装与注册激活教程详解

热门文章

  1. shell 注释
  2. 磁条卡,IC卡,ID卡,信用卡芯片卡,信用卡磁条卡 等等的区别
  3. STL_算法_01_查找算法
  4. windows 启用ipv6(for XX-net)补充“Ping请求找不到主机”问题
  5. C#中正确使用enum做Key的姿势
  6. Android scrollview和GridView混合使用
  7. SSH Secure Shell Client--- the host may be dow
  8. nyoj-833-博弈
  9. Nodejs AES加密
  10. spring boot 学习(七)小工具篇:表单重复提交