1. 程式人生 > >Cubietruck---8. u-boot及boot.img簡略分析

Cubietruck---8. u-boot及boot.img簡略分析

一. u-boot的編譯與連結
1. lichee下編譯命令
[email protected]:/work/ct/lichee$  ./build.sh -p sun7i_android -m uboot
u-boot的編譯是用指令碼lichee/u-boot/build.sh
  1. function build_uboot()
  2. {
  3.      make distclean CROSS_COMPILE=arm-linux-gnueabi-
  4.      make -j8 ${LICHEE_CHIP} CROSS_COMPILE=arm-linux-gnueabi-
  5.      [ $? -ne 0 ] &&
     exit 1
  6.      cp -f u-boot.bin ../out/${LICHEE_PLATFORM}/common/      
  7. }
2. 連結
  1. cd /work/ct/lichee/u-boot && arm-linux-gnueabi-ld -pie -T u-boot.lds -Bstatic -Ttext 0x4A000000 *.-o u-boot
說明u-boot的text段是從 0x4A000000開始的,連結指令碼是u-boot.lds
  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
  2. OUTPUT_ARCH(
    arm)
  3. ENTRY(_start)
  4. SECTIONS
  5. {
  6.  . = 0x00000000;      //在連結時通過-Ttext改為0x4A000000
  7.  . = ALIGN(4);
  8.  .text :
  9.  {
  10.   arch/arm/cpu/armv7/start.(.text)    //u-boot的開始
  11.   *(.text)
  12.  }
  13. }
因為boot.axf把u-boot.bin讀到了0x4A000000,所以執行地址與載入地址相同.
二. u-boot分析
1. stars.S
在arch/arm/cpu/armv7/start.S中,這兒的start.S就非常簡單了,因為執行地址與載入地址相同,所以程式碼不需要再拷貝到另外的地方去,
並且在此之前ram與cpu的頻率都配好了,所以這兒在中斷向量之後,稍做配置就進入了c程式碼的board_init_f

2. 啟動linux
在arch/arm/lib/board.c中
  好像這兒挺複雜的先進入board_init_f --> relocate_code --> start.S--> board_init_r
board_init_r中有main_loop--> run_command
啟動核心的命令是:
bootcmd=run setargs_nand boot_normal
展開後就是:
run setenv bootargs console=ttyS0,115200 root=/dev/nandd 
run sunxi_flash read 40007800 boot;boota 40007800
為什麼這兒是40007800呢, 因為核心要執行在0x40008000處,而boot.img中前0x800(2048)位元組是header(大小為0x800),
header之後是核心,所以將boot.img讀到0x40007800,前0x800是header,那麼核心就正好放在了0x40008000處.
boota 40007800
  1. int do_boota (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  2. {
  3.     addr = simple_strtoul(argv[1], NULL, 16);    //將字串0x40007800存在addr中
  4.     //這個fastboot_boot_img_hdr結構體與 pc上的mkbootimg的結構體是一個,只不過名字變了
  5.     struct fastboot_boot_img_hdr *fb_hdr = (struct fastboot_boot_img_hdr *)addr; 
  6.     //hdr指向核心在記憶體的起始地址   
  7.     image_header_t *hdr =(image_header_t *)(addr + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE);
  8.     //將boot.img的header備份一下
  9.     memcpy(boot_hdr, (void*) addr, sizeof(*hdr));
  10.     if (memcmp(fb_hdr->magic, FASTBOOT_BOOT_MAGIC, 8)) {   //檢驗
  11.         puts("boota: bad boot image magic, maybe not a boot.img?\n");
  12.         return 1;
  13.     }
  14.     kaddr = addr + fb_hdr->page_size;
  15.     raddr = kaddr + ALIGN(fb_hdr->kernel_size, fb_hdr->page_size);
  16.     if((fb_hdr->unused[0] == 0x55) &&(fb_hdr->unused[1] == 0xaa))
  17.     {
  18.         dbmsg("bootimg load in boot1!\n");
  19.         do_boota_linux(fb_hdr);                 //1.1核心的啟動
  20.         tick_printf(__FILE__, __LINE__);
  21.     }
  22.     puts("Boot linux failed, control return to monitor\n");
  23.     return 0;
  24. }

在arch/arm/lib/bootm.c中,傳遞initram的起始地址
  1. int do_boota_linux (struct fastboot_boot_img_hdr *hdr)
  2. {
  3.     ulong initrd_start, initrd_end;
  4.     void (*kernel_entry)(int zero, int arch, uint params);
  5.     bd_t *bd = gd->bd;
  6.     kernel_entry = (void (*)(int, int, uint))(hdr->kernel_addr);   //將地址0x40008000轉為函式
  7.     initrd_start = hdr->ramdisk_addr;
  8.     initrd_end = initrd_start + hdr->ramdisk_size;
  9.     setup_start_tag (bd);                            //配置tag結構體開始
  10.     //設定tag
  11.     ....
  12.     setup_initrd_tag (bd, initrd_start, initrd_end);  //配置initram,將起始地址與大小傳給tag
  13.     setup_end_tag (bd);                              //配置tag結構體結束
  14.     sunxi_flash_exit();
  15.     announce_and_cleanup();    //引導核心前的初始,清tlb類似
  16.    *(volatile unsigned int *)(0x01c20C00 + 0x84 ) = 0;
  17.    *(volatile unsigned int *)(0x01c20C00 + 0x8C ) = 0x05DB05DB;
  18.    *(volatile unsigned int *)(0x01c20C00 + 0x80 ) = 0;
  19.    *(volatile unsigned int *)(0x01c20000 + 0x144) &= ~(1U << 31);
  20.     kernel_entry(0, bd->bi_arch_number, bd->bi_boot_params);    //跳到0x40008000處執行
  21.     return 1;
  22. }
上述啟動linux過程,實際上是對boot.img的解析過程,下面就來看一下boot.img有什麼. 三.boot.img分析
3.1 boot.im生成過程
./android42/out/host/linux-x86/bin/mkbootimg --kernel ./linux-3.3/bImage --ramdisk ./android42/out/target/product/sugar-cubietruck/ramdisk.img --base 0x40000000 --output./android42/out/target/product/sugar-cubietruck/boot.img 
mkbootimg有四個引數:
    kernel        指定bImage的路徑
    ramdisk      指定ramdisk的路徑
    base          指定kerenel與ramdisk的基地址,為0x40000000
    output       指定輸出檔案的路徑
在android42/system/core/mkbootimg/mkbootimag.c中
  1. int main(int argc, char **argv)
  2. {
  3.     boot_img_hdr hdr;
  4.     unsigned base = 0x10000000; //由引數base確定0x40000000
  5.     unsigned kernel_offset = 0x00008000;
  6.     unsigned ramdisk_offset = 0x01000000;
  7.     unsigned second_offset = 0x00f00000;
  8.     unsigned tags_offset = 0x00000100;
  9.     hdr.page_size = pagesize;
  10.     hdr.kernel_addr = base + kernel_offset;     //0x40008000
  11.     hdr.ramdisk_addr = base + ramdisk_offset;   //0x41000000
  12.     hdr.second_addr = base + second_offset;     //0x40f00000
  13.     hdr.tags_addr = base + tags_offset;         //0x40000100
  14.     kernel_data = load_file(kernel_fn, &hdr.kernel_size);        //將核心讀取到buffer中(函式中有malloc)
  15.     ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);     //將ramdisk讀取到buffer中(函式中有malloc)   
  16.     memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
  17.     fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);      //開啟輸出檔案boot.img
  18.     write(fd, &hdr, sizeof(hdr));                                //將head寫入到boot.img中  
  19.     write_padding(fd, pagesize, sizeof(hdr));                    //2048(0x800)位元組對齊
  20.     write(fd, kernel_data, hdr.kernel_size);                     //將kernel寫入到boot.img中
  21.     write_padding(fd, pagesize, hdr.kernel_size);                //2048(0x800)位元組對齊
  22.     write(fd, ramdisk_data, hdr.ramdisk_size);                   //將ramdisk寫入到boot.img中
  23.     write_padding(fd, pagesize, hdr.ramdisk_size);                //2048(0x800)位元組對齊
  24.     return 0; 
  25. }
3.2 boot.img的組成
所以這個boot.img是由3部分組成
  header  (kernel_size代表了核心的大小,kernel_addr)  
  kernel
  ramdisk

  1. struct fastboot_boot_img_hdr {
  2.     unsigned char magic[FASTBOOT_BOOT_MAGIC_SIZE];
  3.     unsigned kernel_size;    //核心的大小
  4.     unsigned kernel_addr;    //核心的載入地址      
  5.     unsigned ramdisk_size;   //ramdisk的大小
  6.     unsigned ramdisk_addr;   //ramdisk的起始地址
  7.     unsigned second_size;    //其它
  8.     unsigned second_addr;    //其它
  9.     unsigned tags_addr;      //其它
  10.     unsigned page_size;      //對齊到多少位元組
  11.     unsigned unused[2];      //
  12.     unsigned char name[FASTBOOT_BOOT_NAME_SIZE]; /* asciiz product name */
  13.     unsigned char cmdline[FASTBOOT_BOOT_ARGS_SIZE];
  14.     unsigned id[8]; /* timestamp / checksum / sha1 / etc */
  15. };



相關推薦

Cubietruck---8. u-bootboot.img簡略分析

一. u-boot的編譯與連結1. lichee下編譯命令[email protected]:/work/ct/lichee$  ./build.sh -p sun7i_android -m ubootu-boot的編譯是用指令碼lichee/u-boot/bui

移植u-boot-2011.03到S3C2440(utu2440)的方法與步驟###8. u-boot引導啟動nand flash中核心和根檔案系統cramfs和使用者檔案系統yaffs2支援

rivers/rtc/hctosys.c: unable to open rtc device (rtc0)uncorrectable error : <3>uncorrectable error : <3>end_request: I/O error, dev mtdblock2, 

修復/boot/etc/fstab、自制linux、編譯安裝內核

修復/boot、/etc/fstab、自制linux、編譯內核 修復/boot及/etc/fstab、自制linux、編譯安裝內核實驗一、破壞dev/sda 的MBR的446字節:破壞:dd if=/dev/zero of=/dev/sda bs=1 count=446 查看:hexdump -C -n

u-boot sdfuse命令燒錄分析----從SD卡載入核心

在u-boot移植過程中,由於u-boot燒錄在SD卡中,因此老是載入核心失敗,是什麼原因呢?在載入核心的列印資訊中有這樣類似的資訊: reading kernel.. 1120, 10240 MMC read: dev # 1, block # 112

u-boot啟動之Makefile結構分析

先進行配置命令: make smdk2410_config 在Makefile檔案中: smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24

U-boot根目錄下的mkconfig分析

原文地址:http://blog.csdn.net/qq_28992301/article/details/51812103 U-boot根目錄下的mkconfig分析 此檔案位於uboot原始碼的根目錄下,是原始碼自帶的shell指令碼檔案,主要功能是建立符號連結以及一些標

boot.img分析

3 boot.img的載入  在lk 中, smem_ptable_init 函式中會初始化 smem_apps_flash_start ,它通過讀share memory ,也就是ARM9端傳入的0:APPS   這樣在targe_init函式中,會將offset = smem_apps_flash_st

【imx6ul】U-Boot 2016.03執行過程分析-ARM Cortex-A7

uboot組織架構正在朝著linux架構方向發展,不同版本稍有不同,一下以U-Boot 2016.03為例。分析入口:以u-boot.lds(其決定了各個段的排布方式)開始:1、u-boot.lds://設定輸出檔案大小端格式 OUTPUT_FORMAT("elf32-lit

U-boot初始化階段流程分析

U-boot的初始化主要分為兩個階段 第一階段:主要是SOC內部的初始化,板級的初始化比較少,所以移植的修改量比較小。此階段由組合語言編寫,程式碼主體分佈在start.S和lowlevel_init.S中。 其中start.S作為主幹,其主要流程為: 注:

DAY-8 Linux基礎常用命令(4)

打開 ip地址 grep 軟件包 linux基礎 tro mks 官網 vim 一、制作swap分區(命令) swapon –s 查看當前激活狀態的swap分區 free –m 以m為單位查看分區 swapoff關閉分區 swapon打開分區 添加swap分區——mks

Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.5.6.RELEASE:repackage failed: Unable to find main class

spl final package exce main project clas ini exit 異常 [INFO] --- spring-boot-maven-plugin:1.5.6.RELEASE:repackage (default) @ spring-boot

12.8 Linux發展VMware創建CentOS虛擬機

菜鳥驛站12.8Linux發展及VMware創建CentOS虛擬機內容:1. Linux發展 人物和事件2. Linux發行版本3. 通過VMware 搭建CentOs 系統4. 通過xshell連接5. 無法連接服務器排錯6. 雲服務器的簡單原理l Centos下載地址http://mirrors.aliy

Failure to transfer org.springframework.boot:spring-boot-maven-plugin

com info framework failure image 技術 找不到 update pen springboot 錯誤 Failure to transfer org.springframework.boot:spring-boot-maven-plugin

spring boot 2.0 源碼分析(五)

pen div shutdown down etc messages servle started fec 在上一篇文章中我們詳細分析了spring boot是如何準備上下文環境的,今天我們來看一下run函數剩余的內容。還是先把run函數貼出來: /**

CentOS6.8 安裝FTP添加用戶

bool list 速度 from img 分享圖片 down log_file tp服務器 一 安裝FTP 1 檢測是否已經安裝FTP rpm -qa | grep vsftpd 2 若沒有,則進行安裝 yum install vsftpd 二 設置vsftpd開

java 7/ 8 中 HashMap concurrentHashMap

前言:      HashMap 不支援併發操作,而concurrentHashMap 支援併發操作,本文簡單介紹Java 7 、Java8 中HashMap 及 concurrentHashMap 底層實現。 1、Java 7 中  HashMap

c# UTF-8解碼編碼陣列與List<string>之間轉換等基本知識點總結

Encoding utf8 = Encoding.UTF8; //首先用utf-8進行解碼                 &

logstash 資料採集時間差8小時問題解決

最近採用logstash採集日誌按天產生檔案 使用過程中發現logstash timestamp記錄的時間戳為UTC時間。 比我們的時區早8個小時。 不能確保每天的資料在同一檔案。 造成傳送到es裡的資料每天早上8點才建立索引,傳送的file的資料每天早上8點自動切割。 不符合我

Java 8 Stream介紹使用

fin integer locate linked 包含 println swa character edi (原) stream的內容比較多,先簡單看一下它的說明: A sequence of elements supporting sequential and

centos下Jdk1.8的安裝配置

安裝之前,首先要確定centos是否集成了自帶的openjdk,如果有,我們先要刪除自帶的openjdk,具體步驟如下: 1)在系統終端輸入:rpm -qa|grep java,如果有openjdk的話,會出現類似於XXXX_openjdk_XXX的資訊; 2)