日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

u-boot分析之内核启动(五)

發(fā)布時(shí)間:2025/4/5 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 u-boot分析之内核启动(五) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

u-boot(五)內(nèi)核啟動(dòng)

  • 概述
  • 分區(qū)空間
  • 內(nèi)核文件格式
  • 內(nèi)核復(fù)制跳轉(zhuǎn)
  • 內(nèi)核啟動(dòng)
  • 機(jī)器ID
  • 啟動(dòng)參數(shù)
  • (起始tag)setup_start_tag
  • 內(nèi)存設(shè)置
  • 根文件系統(tǒng),啟動(dòng)程序,串口設(shè)備
  • (結(jié)束)setup_end_tag

u-boot(五)內(nèi)核啟動(dòng)

概述

啟動(dòng)命令:bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,具體代碼實(shí)現(xiàn)的重點(diǎn)是以下:

  • s=getenv ("bootcmd")?獲取環(huán)境變量
  • run_command (s, 0);?啟動(dòng)內(nèi)核,這個(gè)s=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
  • s就是先讀出內(nèi)核,再啟動(dòng)內(nèi)核了
  • 備注?jffs2是一種文件格式,在這里并不需要文件格式,但是使用這個(gè)jffs2 可以不使用頁(yè)對(duì)齊,如果使用nand read,需要考慮頁(yè)對(duì)齊或者塊對(duì)齊,最終會(huì)使用nand_read_opts

    • 我們也可以在u-boot 命令行直接輸入boot來(lái)啟動(dòng)內(nèi)核,但是實(shí)際的命令是一樣的,是在cmd_bootm.c中調(diào)用do_bootd>run_command (getenv ("bootcmd"), flag)

    分區(qū)空間

    常見(jiàn)的內(nèi)部空間布局如下:

    BootloaderBoot parametersKernelRoot filesystem
    u-boot,它會(huì)在內(nèi)存的某個(gè)地方存放著內(nèi)核啟動(dòng)的一些參數(shù),也稱為tagu-boot 參數(shù),包含傳遞給內(nèi)核的一些東西內(nèi)核根文件系統(tǒng)

    嵌入式的FLASH沒(méi)有實(shí)際的分區(qū),所謂分區(qū)只是一個(gè)名稱,具體的地址是寫死的. 在include/configs/100ask24x0.h

    #define MTDIDS_DEFAULT "nand0=nandflash0" #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \"128k(params)," \"2m(kernel)," \"-(root)"

    這里定義了mtdparts分區(qū),位于nandflash0,bootloader大小是256k,從0開(kāi)始,然后是128k大小的params,接下去是2M的kernel內(nèi)核,剩余的都是root文件系統(tǒng).

    內(nèi)核文件格式

    Flash上存儲(chǔ)的內(nèi)核格式為uImage,包含了一個(gè)64字節(jié)頭部加真正的內(nèi)核Image.

    /** all data in network byte order (aka natural aka bigendian)*/ #define IH_NMLEN 32 /* Image Name Length */typedef struct image_header {uint32_t ih_magic; /* Image Header Magic Number */uint32_t ih_hcrc; /* Image Header CRC Checksum */uint32_t ih_time; /* Image Creation Timestamp */uint32_t ih_size; /* Image Data Size */uint32_t ih_load; /* Data Load Address */uint32_t ih_ep; /* Entry Point Address */uint32_t ih_dcrc; /* Image Data CRC Checksum */uint8_t ih_os; /* Operating System */uint8_t ih_arch; /* CPU architecture */uint8_t ih_type; /* Image Type */uint8_t ih_comp; /* Compression Type */uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t;
    • ih_load表示加載地址,表示內(nèi)核應(yīng)該放在哪里,加載地址為0x30008000
    • ih_ep表示入口地址,表示跳轉(zhuǎn)的地址,也就是內(nèi)核代碼段的入口,廣義上的main入口

    內(nèi)核復(fù)制跳轉(zhuǎn)

    bootm會(huì)先判斷內(nèi)核是否在加載地址,否則先移動(dòng)內(nèi)核到指定的加載地址,然后跳轉(zhuǎn)。

    命令中0x30007FC0 地址可以隨便放,只要不破壞已經(jīng)用到的信息就好,?bootm命令如果發(fā)現(xiàn)當(dāng)前內(nèi)核并不在加載地址,需要移動(dòng)內(nèi)核到加載地址。do_bootm函數(shù)中memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);?移動(dòng)內(nèi)核。

    所以如果ih_load=我們內(nèi)核的地址的時(shí)候,就不需要move,節(jié)省時(shí)間.jz2440 的加載地址是0x30008000,頭部是64字節(jié),所以,0x30008000-64=0x30007FC0,所以我們copy內(nèi)核到0x30007FC0 .

    內(nèi)核啟動(dòng)

    //在 bootm命令中有l(wèi)inux內(nèi)核跳轉(zhuǎn),//lib_arm/armlinux.c-->do_bootm_linux do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);//theKernel 就是uimage的頭部中的入口地址-theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);// 設(shè)置一些參數(shù)setup_start_tag (bd);setup_memory_tags (bd);setup_commandline_tag (bd, commandline);setup_end_tag (bd);// 所以內(nèi)核的入口參數(shù)-theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

    機(jī)器ID

    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);中的第二個(gè)參數(shù)是機(jī)器ID,內(nèi)核通過(guò)比對(duì)機(jī)器ID判斷是否支持啟動(dòng).gd->bd->bi_arch_number = MACH_TYPE_S3C2440;

    啟動(dòng)參數(shù)

    內(nèi)核跳轉(zhuǎn)之前,同樣需要設(shè)置內(nèi)核的啟動(dòng)參數(shù).內(nèi)核的參數(shù)是按照tag組織的.也就是在某個(gè)地址(0x30000100,在100ask24x0.c中定義),按照某種格式存儲(chǔ),這種格式具體為【size....tagid....tag值】

    在do_bootm_linux中有設(shè)置內(nèi)存,命令行參數(shù)等,代碼片段如下

    bd_t *bd = gd->bd; //設(shè)置起始的頭 setup_start_tag (bd); //設(shè)置內(nèi)存 setup_memory_tags (bd); setup_commandline_tag (bd, commandline); //.... // 設(shè)置結(jié)束的id setup_end_tag (bd);

    具體有以下幾種tag,代碼中以聯(lián)合體定義,這樣方便使用同一個(gè)指針指向它,方便之處見(jiàn)setup_start_tag分析.

    //這個(gè)tag 就是一個(gè)包含了所有類型tag的一個(gè)聯(lián)合體,是實(shí)際tag的內(nèi)容值 struct tag {struct tag_header hdr;union {struct tag_core core;struct tag_mem32 mem;struct tag_videotext videotext;struct tag_ramdisk ramdisk;struct tag_initrd initrd;struct tag_serialnr serialnr;struct tag_revision revision;struct tag_videolfb videolfb;struct tag_cmdline cmdline;/** Acorn specific*/struct tag_acorn acorn;/** DC21285 specific*/struct tag_memclk memclk;} u; };

    (起始tag)setup_start_tag

    static void setup_start_tag (bd_t *bd) {// 這個(gè)tag 就是一個(gè)包含了所有類型tag的一個(gè)聯(lián)合體// 使用聯(lián)合體之后,下面就可以使用 params->具體的tag類型params = (struct tag *) bd->bi_boot_params;params->hdr.tag = ATAG_CORE;params->hdr.size = tag_size (tag_core);//tag_core 也就是接下去這三個(gè)參數(shù)了//tag_size =zise + tag + 實(shí)際的值params->u.core.flags = 0;params->u.core.pagesize = 0;params->u.core.rootdev = 0;//指向下一個(gè)參數(shù)params = tag_next (params); }#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) // 這里 tag_header就是 size+tag , type 就是實(shí)際的tag的內(nèi)容 // tag_size就是包含 id 和 size 和 內(nèi)容的大小了

    因?yàn)閎d_t *bd = gd->bd;,所以搜索下gd->bd->bi_boot_params,也就是在board/100ask24x0/100ask24x0.c中定義,也就是說(shuō)參數(shù)是放在0x30000100.

    gd->bd->bi_boot_params = 0x30000100;

    內(nèi)存設(shè)置

    static void setup_memory_tags (bd_t *bd) {int i;for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {params->hdr.tag = ATAG_MEM;params->hdr.size = tag_size (tag_mem32);params->u.mem.start = bd->bi_dram[i].start;params->u.mem.size = bd->bi_dram[i].size;params = tag_next (params);} }

    搜索下gd->bd->bi_dram[0],同樣在board/100ask24x0/100ask24x0.c定義

    int dram_init (void) {gd->bd->bi_dram[0].start = PHYS_SDRAM_1;gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;return 0; } #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */

    這個(gè)函數(shù)是在lib_arm/board.c中的init_sequence調(diào)用,也就是start_armboot中調(diào)用,也就是在u-boot(三)第一階段的C中使用的

    根文件系統(tǒng),啟動(dòng)程序,串口設(shè)備

    char *commandline = getenv ("bootargs"); setup_commandline_tag (bd, commandline);static void setup_commandline_tag (bd_t *bd, char *commandline) {char *p;if (!commandline)return;/* eat leading white space */for (p = commandline; *p == ' '; p++);/* skip non-existent command lines so the kernel will still* use its default command line.*/if (*p == '\0')return;params->hdr.tag = ATAG_CMDLINE;params->hdr.size =(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;strcpy (params->u.cmdline.cmdline, p);params = tag_next (params); }

    設(shè)置命令tag,多了參數(shù)commandline,源自環(huán)境變量bootargs查看下環(huán)境變量bootargs,使用print查看,也可搜索下代碼

    "bootargs=" CONFIG_BOOTARGS "\0" //include/configs/100ask24x0.h #define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"
    • root=/dev/mtdblock3表示根文件系統(tǒng)從第四個(gè)FLASH分區(qū)開(kāi)始(從0開(kāi)始計(jì)數(shù))可以往上看分區(qū)空間
    • init=/linuxrc指示第一個(gè)應(yīng)用程序
    • console=ttySAC0,內(nèi)核打印信息從串口0 打印

    (結(jié)束)setup_end_tag

    設(shè)置結(jié)束標(biāo)志

    轉(zhuǎn)載:https://www.cnblogs.com/zongzi10010/p/10023681.html

    總結(jié)

    以上是生活随笔為你收集整理的u-boot分析之内核启动(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。