U-boot给kernel传参数和kernel读取参数—struct tag
生活随笔
收集整理的這篇文章主要介紹了
U-boot给kernel传参数和kernel读取参数—struct tag
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
U-boot 會給 Linux Kernel 傳遞很多參數(shù),如:串口, RAM , videofb 等。
而 Linux kernel 也會讀取和處理這些參數(shù)。兩者之間
通過 struct tag 來傳遞參數(shù)。
U-boot 把要傳遞給 kernel 的東西保存在 struct tag 數(shù)據(jù)結(jié)構(gòu)中,啟動 kernel 時,把這個結(jié)構(gòu)體的物理地址傳給 kernel ; Linux kernel 通過這個地址,用 parse_tags 分析出傳遞過來的參數(shù)。
本文主要以 U-boot 傳遞 RAM 和 Linux kernel 讀取 RAM 參數(shù)為例進(jìn)行說明。
1 、u-boot 給kernel 傳RAM 參數(shù)
? ?? ? ./common/cmd_bootm.c 文件中, bootm 命令對應(yīng)的 do_bootm 函數(shù),當(dāng)分析 uImage 中信息發(fā)現(xiàn) OS 是 Linux 時 , 調(diào)用 ./lib_arm/bootm.c 文件中的 do_bootm_linux 函數(shù)來啟動 Linux kernel 。
? ?? ? 在 do_bootm_linux 函數(shù)中:
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
? ?? ?? ?? ?? ?? ? ulong addr, ulong *len_ptr, int verify)
{
......
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
? ? defined (CONFIG_CMDLINE_TAG) || \
? ? defined (CONFIG_INITRD_TAG) || \
? ? defined (CONFIG_SERIAL_TAG) || \
? ? defined (CONFIG_REVISION_TAG) || \
? ? defined (CONFIG_LCD) || \
? ? defined (CONFIG_VFD)
? ?? ? setup_start_tag (bd);? ?? ?// 初始化 tag 結(jié)構(gòu)體開始
#ifdef CONFIG_SERIAL_TAG
? ?? ? setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
? ?? ? setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
? ?? ? setup_memory_tags (bd);? ?? ?// 設(shè)置 RAM 參數(shù)
#endif
#ifdef CONFIG_CMDLINE_TAG
? ?? ? setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
? ?? ? if (initrd_start && initrd_end)
? ?? ?? ?? ???setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
? ?? ? setup_videolfb_tag ((gd_t *) gd);
#endif
? ?? ? setup_end_tag (bd);? ?? ?? ?? ???// 初始化 tag 結(jié)構(gòu)體結(jié)束
#endif
......
......
? ?? ? theKernel (0, machid, bd->bi_boot_params);
// 傳給 Kernel 的參數(shù)= (struct tag *) 型的 bd->bi_boot_params
//bd->bi_boot_params 在 board_init 函數(shù)中初始化如對于 at91rm9200 ,初始化在 at91rm9200dk.c 的 board_init 中進(jìn)行: bd->bi_boot_params =PHYS_SDRAM + 0x100;
// 這個地址也是所有 taglist 的首地址,見下面的 setup_start_tag 函數(shù)
}
??
? ?? ? 對于 setup_start_tag 和 setup_memory_tags 函數(shù)說明如下。
? ?? ? 函數(shù) setup_start_tag 也在此文件中定義,如下:
static void setup_start_tag (bd_t *bd)
{
? ?? ? params = (struct tag *) bd->bi_boot_params;
// 初始化 (struct tag *) 型的全局變量 params 為bd->bi_boot_params 的地址,之后的setup tags 相關(guān)函數(shù)如下面的 setup_memory_tags 就把其它 tag 的數(shù)據(jù)放在此地址的偏移地址上。
??
? ?? ? params->hdr.tag = ATAG_CORE;
? ?? ? params->hdr.size = tag_size (tag_core);
? ?? ? params->u.core.flags = 0;
? ?? ? params->u.core.pagesize = 0;
? ?? ? params->u.core.rootdev = 0;
? ?? ? params = tag_next (params);
}
? ?? ?
RAM 相關(guān)參數(shù)在 bootm.c 中的函數(shù) setup_memory_tags 中初始化:
static void setup_memory_tags (bd_t *bd)
{
? ?? ? int i;
? ?? ? for (i = 0; i
? ?? ?? ?? ???params->hdr.tag = ATAG_MEM;
? ?? ?? ?? ???params->hdr.size = tag_size (tag_mem32);
? ?? ?? ?? ???params->u.mem.start = bd->bi_dram .start;
? ?? ?? ?? ???params->u.mem.size = bd->bi_dram.size;
? ?? ?? ?? ???params = tag_next (params);
? ?? ? }? ?? ?? ?? ?? ?? ? // 初始化內(nèi)存相關(guān) tag
}
??
2 、Kernel 讀取U-boot 傳遞的相關(guān)參數(shù)
對于 Linux Kernel , ARM 平臺啟動時,先執(zhí)行 arch/arm/kernel/head.S ,此文件會調(diào)用 arch/arm/kernel/head-common.S 中的函數(shù),并最后調(diào)用 start_kernel :
......
b? ???start_kernel
......
??
init/main.c 中的 start_kernel 函數(shù)中會調(diào)用 setup_arch 函數(shù)來處理各種平臺相關(guān)的動作,包括了 u-boot 傳遞過來參數(shù)的分析和保存:
start_kernel()
{
......
? ?? ? setup_arch(&command_line);
......
}
? ?? ?
? ?? ? 其中, setup_arch 函數(shù)在 arch/arm/kernel/setup.c 文件中實(shí)現(xiàn),如下:
void __init setup_arch(char **cmdline_p)
{
? ?? ? struct tag *tags = (struct tag *)&init_tags;
? ?? ? struct machine_desc *mdesc;
? ?? ? char *from = default_command_line;
? ?? ? setup_processor();
? ?? ? mdesc = setup_machine(machine_arch_type);
? ?? ? machine_name = mdesc->name;
? ?? ? if (mdesc->soft_reboot)
? ?? ?? ?? ???reboot_setup("s");
? ?? ? if (__atags_pointer)? ?? ?? ?? ???
// 指向各種 tag 起始位置的指針,定義如下:
//unsigned int __atags_pointer??__initdata;
// 此指針指向 __initdata 段,各種 tag 的信息保存在這個段中。
? ?? ?? ?? ???tags = phys_to_virt(__atags_pointer);
? ?? ? else if (mdesc->boot_params)
? ?? ?? ?? ???tags = phys_to_virt(mdesc->boot_params);
? ?? ? if (tags->hdr.tag != ATAG_CORE)
? ?? ?? ?? ???convert_to_tag_list(tags);
? ?? ? if (tags->hdr.tag != ATAG_CORE)
? ?? ?? ?? ???tags = (struct tag *)&init_tags;
? ?? ? if (mdesc->fixup)
? ?? ?? ?? ???mdesc->fixup(mdesc, tags, &from, &meminfo);
? ?? ? if (tags->hdr.tag == ATAG_CORE) {
? ?? ?? ?? ???if (meminfo.nr_banks != 0)
? ?? ?? ?? ?? ?? ?? ?squash_mem_tags(tags);
? ?? ?? ?? ???save_atags(tags);
? ?? ?? ?? ???parse_tags(tags);??
// 處理各種 tags ,其中包括了 RAM 參數(shù)的處理。
// 這個函數(shù)處理如下 tags :
__tagtable(ATAG_MEM, parse_tag_mem32);
__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
__tagtable(ATAG_SERIAL, parse_tag_serialnr);
__tagtable(ATAG_REVISION, parse_tag_revision);
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
? ?? ? }
? ?? ? init_mm.start_code = (unsigned long) &_text;
? ?? ? init_mm.end_code? ?= (unsigned long) &_etext;
? ?? ? init_mm.end_data? ?= (unsigned long) &_edata;
? ?? ? init_mm.brk? ?? ? = (unsigned long) &_end;
? ?? ? memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
? ?? ? boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
? ?? ? parse_cmdline(cmdline_p, from);??// 處理編譯內(nèi)核時指定的 cmdline 或 u-boot 傳遞的 cmdline
? ?? ? paging_init(&meminfo, mdesc);
? ?? ? request_standard_resources(&meminfo, mdesc);
#ifdef CONFIG_SMP
? ?? ? smp_init_cpus();
#endif
? ?? ? cpu_init();
? ?? ? init_arch_irq = mdesc->init_irq;
? ?? ? system_timer = mdesc->timer;
? ?? ? init_machine = mdesc->init_machine;
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
? ?? ? conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
? ?? ? conswitchp = &dummy_con;
#endif
#endif
? ?? ? early_trap_init();
}
??
對于處理 RAM 的 tag ,調(diào)用了 parse_tag_mem32 函數(shù):
static int __init parse_tag_mem32(const struct tag *tag)
{
......
? ?? ? arm_add_memory(tag->u.mem.start, tag->u.mem.size);
......
}
__tagtable(ATAG_MEM, parse_tag_mem32);
? ?? ? 上述的 arm_add_memory 函數(shù)定義如下:
static void __init arm_add_memory(unsigned long start, unsigned long size)
{
? ?? ? struct membank *bank;
? ?? ? size -= start & ~PAGE_MASK;
??
? ?? ? bank = &meminfo.bank[meminfo.nr_banks++];
? ?? ? bank->start = PAGE_ALIGN(start);
? ?? ? bank->size??= size & PAGE_MASK;
? ?? ? bank->node??= PHYS_TO_NID(start);
}
? ?? ? 如上可見, parse_tag_mem32 函數(shù)調(diào)用 arm_add_memory 函數(shù)把 RAM 的 start 和 size 等參數(shù)保存到了 meminfo 結(jié)構(gòu)的 meminfo 結(jié)構(gòu)體中。最后,在 setup_arch 中執(zhí)行下面語句:
? ?? ? paging_init(&meminfo, mdesc);
? ?? ? 對有 MMU 的平臺上調(diào)用 arch/arm/mm/nommu.c 中的 paging_init ,否則調(diào)用 arch/arm/mm/mmu.c 中的 paging_init 函數(shù)。這里暫不分析 mmu.c 中的 paging_init 函數(shù)。
??
??
3 、關(guān)于U-boot 中的bd 和gd
U-boot 中有一個用來保存很多有用信息的全局結(jié)構(gòu)體-- gd_t ( global data 縮寫),其中包括了 bd 變量,可以說 gd_t 結(jié)構(gòu)體包括了 u-boot 中所有重要全局變量。最后傳遞給內(nèi)核的參數(shù),都是從 gd 和 bd 中來的,如上述的 setup_memory_tags 函數(shù)作用就是用 bd 中的值來初始化 RAM 相應(yīng)的 tag 。
對于 ARM 平臺這個結(jié)構(gòu)體的定義大致如下:
include/asm-arm/global_data.h
typedef? ? struct? ?? ?global_data {
? ?? ? bd_t? ?? ???*bd;
? ?? ? unsigned long??flags;
? ?? ? unsigned long??baudrate;
? ?? ? unsigned long??have_console; /* serial_init() was called */
? ?? ? unsigned long??reloc_off;? ?? ? /* Relocation Offset */
? ?? ? unsigned long??env_addr;? ?? ? /* Address??of Environment struct */
? ?? ? unsigned long??env_valid;? ?? ? /* Checksum of Environment valid? */
? ?? ? unsigned long??fb_base;??/* base address of frame buffer */
? ?? ? void? ?? ???**jt;? ?? ???/* jump table */
} gd_t;
??
在 U-boot 中使用 gd 結(jié)構(gòu)之前要用先用宏 DECLARE_GLOBAL_DATA_PTR 來聲明。這個宏的定義如下:
include/asm-arm/global_data.h
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
從這個宏的定義可以看出, gd 是一個保存在 ARM 的 r8 寄存器中的 gd_t 結(jié)構(gòu)體的指針。
??
說明:本文的版本為U-boot-1.3.4 、Linux-2.6.28 ,平臺是ARM 。
//補(bǔ)充一下:
來自:http://hi.baidu.com/armfans/blog/item/306cd5035f24ff084afb514b.html
bootloader巧妙地利用函數(shù)指針及傳參規(guī)范將R0:0x0,R1:機(jī)器號,R2:參數(shù)地址傳遞給內(nèi)核.由于R0,R1比較簡單,不需要再作說明.需要花點(diǎn)時間了解的是R2寄存器.
R2寄存器傳遞的是一個指針,這個指針指向一個TAG區(qū)域.UBOOT和Linux內(nèi)核之間正是通過這個擴(kuò)展了的TAG區(qū)域來進(jìn)行復(fù)雜參數(shù)的傳遞,如 command line,文件系統(tǒng)信息等等,用戶也可以擴(kuò)展這個TAG來進(jìn)行更多參數(shù)的傳遞.TAG區(qū)域存放的地址,也就是R2的值,是在/board /yourboard/youboard.c里的board_init函數(shù)中初始化的,如在UB4020中初始化為:gd->bd->bi_boot_params = 0x30000100;,這是一個絕對地址.
TAG區(qū)的結(jié)構(gòu)比較簡單,可以視為一個一個TAG的排列(數(shù)組?),每一個TAG傳遞一種特定類型的參數(shù).各種系統(tǒng)TAG的定義可以參考./include/asm-arm/setup.h.
下面是一個TAG區(qū)的例子:
0x30000100 00000005 54410001 00000000 00000000
0x30000110 00000000 0000000F 54410009 746F6F72
0x30000120 65642F3D 61722F76 7220306D 6F632077
0x30000130 6C6F736E 74743D65 2C305379 30303639
0x30000140 696E6920 6C2F3D74 78756E69 EA006372
0x30000150 00000004 54420005 30300040 00200000
0x30000160 00000000 00000000
我們可以看到一共有三個TAG:
第一個TAG的長度是5個字,類型是ATAG_CORE(54410001),有三個元素,均為全零.TAG區(qū)必須以這個TAG開頭.
第二個TAG的長度是F個字,類型是ATAG_CMDLINE(54410009),這是一個字符串,是向內(nèi)核傳遞的kernel command line
第三個TAG的長度是4個字,類型是ATAG_INITRD2(54410005),有兩個元素,第一個是start:30300040(30300000+40),第二個是size:200000(2M)
如果說還有第四個TAG,那就是末尾的兩個全零,這是TAG結(jié)束的標(biāo)志.
這些TAG是在./lib_arm/arm_linux.c中的do_bootm_linux函數(shù)中建立起來的.具體建立哪些TAG,由相應(yīng)的控制宏決定.具體可以參考相應(yīng)代碼.例子中第一個TAG是起始TAG,如果環(huán)境變量中有bootargs,則建立第二個TAG,如果bootm有兩個參數(shù)(引導(dǎo)文件系統(tǒng)),則會讀取文件系統(tǒng)頭部的必要信息,建立第三個TAG.
內(nèi)核啟動后,將根據(jù)R2寄存器的值找到這些TAG,并根據(jù)TAG類型,調(diào)用相應(yīng)的處理函數(shù)進(jìn)行處理,從而獲取內(nèi)核運(yùn)行的必要信息.
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:
http://blog.csdn.net/lanmanck/archive/2009/06/24/4294685.aspx
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎
本文主要以 U-boot 傳遞 RAM 和 Linux kernel 讀取 RAM 參數(shù)為例進(jìn)行說明。
1 、u-boot 給kernel 傳RAM 參數(shù)
? ?? ? ./common/cmd_bootm.c 文件中, bootm 命令對應(yīng)的 do_bootm 函數(shù),當(dāng)分析 uImage 中信息發(fā)現(xiàn) OS 是 Linux 時 , 調(diào)用 ./lib_arm/bootm.c 文件中的 do_bootm_linux 函數(shù)來啟動 Linux kernel 。
? ?? ? 在 do_bootm_linux 函數(shù)中:
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
? ?? ?? ?? ?? ?? ? ulong addr, ulong *len_ptr, int verify)
{
......
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
? ? defined (CONFIG_CMDLINE_TAG) || \
? ? defined (CONFIG_INITRD_TAG) || \
? ? defined (CONFIG_SERIAL_TAG) || \
? ? defined (CONFIG_REVISION_TAG) || \
? ? defined (CONFIG_LCD) || \
? ? defined (CONFIG_VFD)
? ?? ? setup_start_tag (bd);? ?? ?// 初始化 tag 結(jié)構(gòu)體開始
#ifdef CONFIG_SERIAL_TAG
? ?? ? setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
? ?? ? setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
? ?? ? setup_memory_tags (bd);? ?? ?// 設(shè)置 RAM 參數(shù)
#endif
#ifdef CONFIG_CMDLINE_TAG
? ?? ? setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
? ?? ? if (initrd_start && initrd_end)
? ?? ?? ?? ???setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
? ?? ? setup_videolfb_tag ((gd_t *) gd);
#endif
? ?? ? setup_end_tag (bd);? ?? ?? ?? ???// 初始化 tag 結(jié)構(gòu)體結(jié)束
#endif
......
......
? ?? ? theKernel (0, machid, bd->bi_boot_params);
// 傳給 Kernel 的參數(shù)= (struct tag *) 型的 bd->bi_boot_params
//bd->bi_boot_params 在 board_init 函數(shù)中初始化如對于 at91rm9200 ,初始化在 at91rm9200dk.c 的 board_init 中進(jìn)行: bd->bi_boot_params =PHYS_SDRAM + 0x100;
// 這個地址也是所有 taglist 的首地址,見下面的 setup_start_tag 函數(shù)
}
??
? ?? ? 對于 setup_start_tag 和 setup_memory_tags 函數(shù)說明如下。
? ?? ? 函數(shù) setup_start_tag 也在此文件中定義,如下:
static void setup_start_tag (bd_t *bd)
{
? ?? ? params = (struct tag *) bd->bi_boot_params;
// 初始化 (struct tag *) 型的全局變量 params 為bd->bi_boot_params 的地址,之后的setup tags 相關(guān)函數(shù)如下面的 setup_memory_tags 就把其它 tag 的數(shù)據(jù)放在此地址的偏移地址上。
??
? ?? ? params->hdr.tag = ATAG_CORE;
? ?? ? params->hdr.size = tag_size (tag_core);
? ?? ? params->u.core.flags = 0;
? ?? ? params->u.core.pagesize = 0;
? ?? ? params->u.core.rootdev = 0;
? ?? ? params = tag_next (params);
}
? ?? ?
RAM 相關(guān)參數(shù)在 bootm.c 中的函數(shù) setup_memory_tags 中初始化:
static void setup_memory_tags (bd_t *bd)
{
? ?? ? int i;
? ?? ? for (i = 0; i
? ?? ?? ?? ???params->hdr.tag = ATAG_MEM;
? ?? ?? ?? ???params->hdr.size = tag_size (tag_mem32);
? ?? ?? ?? ???params->u.mem.start = bd->bi_dram .start;
? ?? ?? ?? ???params->u.mem.size = bd->bi_dram.size;
? ?? ?? ?? ???params = tag_next (params);
? ?? ? }? ?? ?? ?? ?? ?? ? // 初始化內(nèi)存相關(guān) tag
}
??
2 、Kernel 讀取U-boot 傳遞的相關(guān)參數(shù)
對于 Linux Kernel , ARM 平臺啟動時,先執(zhí)行 arch/arm/kernel/head.S ,此文件會調(diào)用 arch/arm/kernel/head-common.S 中的函數(shù),并最后調(diào)用 start_kernel :
......
b? ???start_kernel
......
??
init/main.c 中的 start_kernel 函數(shù)中會調(diào)用 setup_arch 函數(shù)來處理各種平臺相關(guān)的動作,包括了 u-boot 傳遞過來參數(shù)的分析和保存:
start_kernel()
{
......
? ?? ? setup_arch(&command_line);
......
}
? ?? ?
? ?? ? 其中, setup_arch 函數(shù)在 arch/arm/kernel/setup.c 文件中實(shí)現(xiàn),如下:
void __init setup_arch(char **cmdline_p)
{
? ?? ? struct tag *tags = (struct tag *)&init_tags;
? ?? ? struct machine_desc *mdesc;
? ?? ? char *from = default_command_line;
? ?? ? setup_processor();
? ?? ? mdesc = setup_machine(machine_arch_type);
? ?? ? machine_name = mdesc->name;
? ?? ? if (mdesc->soft_reboot)
? ?? ?? ?? ???reboot_setup("s");
? ?? ? if (__atags_pointer)? ?? ?? ?? ???
// 指向各種 tag 起始位置的指針,定義如下:
//unsigned int __atags_pointer??__initdata;
// 此指針指向 __initdata 段,各種 tag 的信息保存在這個段中。
? ?? ?? ?? ???tags = phys_to_virt(__atags_pointer);
? ?? ? else if (mdesc->boot_params)
? ?? ?? ?? ???tags = phys_to_virt(mdesc->boot_params);
? ?? ? if (tags->hdr.tag != ATAG_CORE)
? ?? ?? ?? ???convert_to_tag_list(tags);
? ?? ? if (tags->hdr.tag != ATAG_CORE)
? ?? ?? ?? ???tags = (struct tag *)&init_tags;
? ?? ? if (mdesc->fixup)
? ?? ?? ?? ???mdesc->fixup(mdesc, tags, &from, &meminfo);
? ?? ? if (tags->hdr.tag == ATAG_CORE) {
? ?? ?? ?? ???if (meminfo.nr_banks != 0)
? ?? ?? ?? ?? ?? ?? ?squash_mem_tags(tags);
? ?? ?? ?? ???save_atags(tags);
? ?? ?? ?? ???parse_tags(tags);??
// 處理各種 tags ,其中包括了 RAM 參數(shù)的處理。
// 這個函數(shù)處理如下 tags :
__tagtable(ATAG_MEM, parse_tag_mem32);
__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
__tagtable(ATAG_SERIAL, parse_tag_serialnr);
__tagtable(ATAG_REVISION, parse_tag_revision);
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
? ?? ? }
? ?? ? init_mm.start_code = (unsigned long) &_text;
? ?? ? init_mm.end_code? ?= (unsigned long) &_etext;
? ?? ? init_mm.end_data? ?= (unsigned long) &_edata;
? ?? ? init_mm.brk? ?? ? = (unsigned long) &_end;
? ?? ? memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
? ?? ? boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
? ?? ? parse_cmdline(cmdline_p, from);??// 處理編譯內(nèi)核時指定的 cmdline 或 u-boot 傳遞的 cmdline
? ?? ? paging_init(&meminfo, mdesc);
? ?? ? request_standard_resources(&meminfo, mdesc);
#ifdef CONFIG_SMP
? ?? ? smp_init_cpus();
#endif
? ?? ? cpu_init();
? ?? ? init_arch_irq = mdesc->init_irq;
? ?? ? system_timer = mdesc->timer;
? ?? ? init_machine = mdesc->init_machine;
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
? ?? ? conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
? ?? ? conswitchp = &dummy_con;
#endif
#endif
? ?? ? early_trap_init();
}
??
對于處理 RAM 的 tag ,調(diào)用了 parse_tag_mem32 函數(shù):
static int __init parse_tag_mem32(const struct tag *tag)
{
......
? ?? ? arm_add_memory(tag->u.mem.start, tag->u.mem.size);
......
}
__tagtable(ATAG_MEM, parse_tag_mem32);
? ?? ? 上述的 arm_add_memory 函數(shù)定義如下:
static void __init arm_add_memory(unsigned long start, unsigned long size)
{
? ?? ? struct membank *bank;
? ?? ? size -= start & ~PAGE_MASK;
??
? ?? ? bank = &meminfo.bank[meminfo.nr_banks++];
? ?? ? bank->start = PAGE_ALIGN(start);
? ?? ? bank->size??= size & PAGE_MASK;
? ?? ? bank->node??= PHYS_TO_NID(start);
}
? ?? ? 如上可見, parse_tag_mem32 函數(shù)調(diào)用 arm_add_memory 函數(shù)把 RAM 的 start 和 size 等參數(shù)保存到了 meminfo 結(jié)構(gòu)的 meminfo 結(jié)構(gòu)體中。最后,在 setup_arch 中執(zhí)行下面語句:
? ?? ? paging_init(&meminfo, mdesc);
? ?? ? 對有 MMU 的平臺上調(diào)用 arch/arm/mm/nommu.c 中的 paging_init ,否則調(diào)用 arch/arm/mm/mmu.c 中的 paging_init 函數(shù)。這里暫不分析 mmu.c 中的 paging_init 函數(shù)。
??
??
3 、關(guān)于U-boot 中的bd 和gd
U-boot 中有一個用來保存很多有用信息的全局結(jié)構(gòu)體-- gd_t ( global data 縮寫),其中包括了 bd 變量,可以說 gd_t 結(jié)構(gòu)體包括了 u-boot 中所有重要全局變量。最后傳遞給內(nèi)核的參數(shù),都是從 gd 和 bd 中來的,如上述的 setup_memory_tags 函數(shù)作用就是用 bd 中的值來初始化 RAM 相應(yīng)的 tag 。
對于 ARM 平臺這個結(jié)構(gòu)體的定義大致如下:
include/asm-arm/global_data.h
typedef? ? struct? ?? ?global_data {
? ?? ? bd_t? ?? ???*bd;
? ?? ? unsigned long??flags;
? ?? ? unsigned long??baudrate;
? ?? ? unsigned long??have_console; /* serial_init() was called */
? ?? ? unsigned long??reloc_off;? ?? ? /* Relocation Offset */
? ?? ? unsigned long??env_addr;? ?? ? /* Address??of Environment struct */
? ?? ? unsigned long??env_valid;? ?? ? /* Checksum of Environment valid? */
? ?? ? unsigned long??fb_base;??/* base address of frame buffer */
? ?? ? void? ?? ???**jt;? ?? ???/* jump table */
} gd_t;
??
在 U-boot 中使用 gd 結(jié)構(gòu)之前要用先用宏 DECLARE_GLOBAL_DATA_PTR 來聲明。這個宏的定義如下:
include/asm-arm/global_data.h
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
從這個宏的定義可以看出, gd 是一個保存在 ARM 的 r8 寄存器中的 gd_t 結(jié)構(gòu)體的指針。
??
說明:本文的版本為U-boot-1.3.4 、Linux-2.6.28 ,平臺是ARM 。
//補(bǔ)充一下:
來自:http://hi.baidu.com/armfans/blog/item/306cd5035f24ff084afb514b.html
bootloader巧妙地利用函數(shù)指針及傳參規(guī)范將R0:0x0,R1:機(jī)器號,R2:參數(shù)地址傳遞給內(nèi)核.由于R0,R1比較簡單,不需要再作說明.需要花點(diǎn)時間了解的是R2寄存器.
R2寄存器傳遞的是一個指針,這個指針指向一個TAG區(qū)域.UBOOT和Linux內(nèi)核之間正是通過這個擴(kuò)展了的TAG區(qū)域來進(jìn)行復(fù)雜參數(shù)的傳遞,如 command line,文件系統(tǒng)信息等等,用戶也可以擴(kuò)展這個TAG來進(jìn)行更多參數(shù)的傳遞.TAG區(qū)域存放的地址,也就是R2的值,是在/board /yourboard/youboard.c里的board_init函數(shù)中初始化的,如在UB4020中初始化為:gd->bd->bi_boot_params = 0x30000100;,這是一個絕對地址.
TAG區(qū)的結(jié)構(gòu)比較簡單,可以視為一個一個TAG的排列(數(shù)組?),每一個TAG傳遞一種特定類型的參數(shù).各種系統(tǒng)TAG的定義可以參考./include/asm-arm/setup.h.
下面是一個TAG區(qū)的例子:
0x30000100 00000005 54410001 00000000 00000000
0x30000110 00000000 0000000F 54410009 746F6F72
0x30000120 65642F3D 61722F76 7220306D 6F632077
0x30000130 6C6F736E 74743D65 2C305379 30303639
0x30000140 696E6920 6C2F3D74 78756E69 EA006372
0x30000150 00000004 54420005 30300040 00200000
0x30000160 00000000 00000000
我們可以看到一共有三個TAG:
第一個TAG的長度是5個字,類型是ATAG_CORE(54410001),有三個元素,均為全零.TAG區(qū)必須以這個TAG開頭.
第二個TAG的長度是F個字,類型是ATAG_CMDLINE(54410009),這是一個字符串,是向內(nèi)核傳遞的kernel command line
第三個TAG的長度是4個字,類型是ATAG_INITRD2(54410005),有兩個元素,第一個是start:30300040(30300000+40),第二個是size:200000(2M)
如果說還有第四個TAG,那就是末尾的兩個全零,這是TAG結(jié)束的標(biāo)志.
這些TAG是在./lib_arm/arm_linux.c中的do_bootm_linux函數(shù)中建立起來的.具體建立哪些TAG,由相應(yīng)的控制宏決定.具體可以參考相應(yīng)代碼.例子中第一個TAG是起始TAG,如果環(huán)境變量中有bootargs,則建立第二個TAG,如果bootm有兩個參數(shù)(引導(dǎo)文件系統(tǒng)),則會讀取文件系統(tǒng)頭部的必要信息,建立第三個TAG.
內(nèi)核啟動后,將根據(jù)R2寄存器的值找到這些TAG,并根據(jù)TAG類型,調(diào)用相應(yīng)的處理函數(shù)進(jìn)行處理,從而獲取內(nèi)核運(yùn)行的必要信息.
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:
http://blog.csdn.net/lanmanck/archive/2009/06/24/4294685.aspx
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎
總結(jié)
以上是生活随笔為你收集整理的U-boot给kernel传参数和kernel读取参数—struct tag的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 锤子那点事儿
- 下一篇: 3d照片环效果(修改版--添加了x轴y轴