U-boot給kernel傳參數和kernel讀取參數—struct tag

U-boot 會給 Linux Kernel 傳遞很多參數,如:串口, RAM , videofb 等。 而 Linux kernel 也會讀取和處理這些參數。兩者之間 通過 struct tag 來傳遞參數U-boot 把要傳遞給 kernel 的東西保存在 struct tag 數據結構中,啟動 kernel 時,把這個結構體的物理地址傳給 kernel ; Linux kernel 通過這個地址,用 parse_tags 分析出傳遞過來的參數。
本文主要以 U-boot 傳遞 RAM 和 Linux kernel 讀取 RAM 參數為例進行說明。
1 、u-boot 給kernel 傳RAM 參數
? ?? ? ./common/cmd_bootm.c 文件中, bootm 命令對應的 do_bootm 函數,當分析 uImage 中信息發現 OS 是 Linux 時 , 調用 ./lib_arm/bootm.c 文件中的 do_bootm_linux 函數來啟動 Linux kernel 。
? ?? ? 在 do_bootm_linux 函數中:
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 結構體開始
#ifdef CONFIG_SERIAL_TAG
? ?? ? setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
? ?? ? setup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
? ?? ? setup_memory_tags (bd);? ?? ?// 設置 RAM 參數
#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 結構體結束
#endif
......
......
? ?? ? theKernel (0, machid, bd->bi_boot_params);
// 傳給 Kernel 的參數= (struct tag *) 型的 bd->bi_boot_params
//bd->bi_boot_params 在 board_init 函數中初始化如對于 at91rm9200 ,初始化在 at91rm9200dk.c 的 board_init 中進行: bd->bi_boot_params =PHYS_SDRAM + 0x100;
// 這個地址也是所有 taglist 的首地址,見下面的 setup_start_tag 函數
}
??
? ?? ? 對于 setup_start_tag 和 setup_memory_tags 函數說明如下。
? ?? ? 函數 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 相關函數如下面的 setup_memory_tags 就把其它 tag 的數據放在此地址的偏移地址上。
??
? ?? ? 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 相關參數在 bootm.c 中的函數 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);
? ?? ? }? ?? ?? ?? ?? ?? ? // 初始化內存相關 tag
}
??
2 、Kernel 讀取U-boot 傳遞的相關參數
對于 Linux Kernel , ARM 平臺啟動時,先執行 arch/arm/kernel/head.S ,此文件會調用 arch/arm/kernel/head-common.S 中的函數,并最后調用 start_kernel :
......
b? ???start_kernel
......
??
init/main.c 中的 start_kernel 函數中會調用 setup_arch 函數來處理各種平臺相關的動作,包括了 u-boot 傳遞過來參數的分析和保存:
start_kernel()
{
......
? ?? ? setup_arch(&command_line);
......
}
? ?? ?
? ?? ? 其中, setup_arch 函數在 arch/arm/kernel/setup.c 文件中實現,如下:
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 參數的處理。
// 這個函數處理如下 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);??// 處理編譯內核時指定的 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 ,調用了 parse_tag_mem32 函數:
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 函數定義如下:
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 函數調用 arm_add_memory 函數把 RAM 的 start 和 size 等參數保存到了 meminfo 結構的 meminfo 結構體中。最后,在 setup_arch 中執行下面語句:
? ?? ? paging_init(&meminfo, mdesc);
? ?? ? 對有 MMU 的平臺上調用 arch/arm/mm/nommu.c 中的 paging_init ,否則調用 arch/arm/mm/mmu.c 中的 paging_init 函數。這里暫不分析 mmu.c 中的 paging_init 函數。
??
??
3 、關于U-boot 中的bd 和gd
U-boot 中有一個用來保存很多有用信息的全局結構體-- gd_t ( global data 縮寫),其中包括了 bd 變量,可以說 gd_t 結構體包括了 u-boot 中所有重要全局變量。最后傳遞給內核的參數,都是從 gd 和 bd 中來的,如上述的 setup_memory_tags 函數作用就是用 bd 中的值來初始化 RAM 相應的 tag 。
對于 ARM 平臺這個結構體的定義大致如下:
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 結構之前要用先用宏 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 結構體的指針。
??
說明:本文的版本為U-boot-1.3.4 、Linux-2.6.28 ,平臺是ARM 。

//補充一下:
來自:http://hi.baidu.com/armfans/blog/item/306cd5035f24ff084afb514b.html
bootloader巧妙地利用函數指針及傳參規范將R0:0x0,R1:機器號,R2:參數地址傳遞給內核.由于R0,R1比較簡單,不需要再作說明.需要花點時間了解的是R2寄存器.
  R2寄存器傳遞的是一個指針,這個指針指向一個TAG區域.UBOOT和Linux內核之間正是通過這個擴展了的TAG區域來進行復雜參數的傳遞,如 command line,文件系統信息等等,用戶也可以擴展這個TAG來進行更多參數的傳遞.TAG區域存放的地址,也就是R2的值,是在/board /yourboard/youboard.c里的board_init函數中初始化的,如在UB4020中初始化為:gd->bd->bi_boot_params = 0x30000100;,這是一個絕對地址.
  TAG區的結構比較簡單,可以視為一個一個TAG的排列(數組?),每一個TAG傳遞一種特定類型的參數.各種系統TAG的定義可以參考./include/asm-arm/setup.h.
  下面是一個TAG區的例子:
  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區必須以這個TAG開頭.
  第二個TAG的長度是F個字,類型是ATAG_CMDLINE(54410009),這是一個字符串,是向內核傳遞的kernel command line
  第三個TAG的長度是4個字,類型是ATAG_INITRD2(54410005),有兩個元素,第一個是start:30300040(30300000+40),第二個是size:200000(2M)
  如果說還有第四個TAG,那就是末尾的兩個全零,這是TAG結束的標志.
  這些TAG是在./lib_arm/arm_linux.c中的do_bootm_linux函數中建立起來的.具體建立哪些TAG,由相應的控制宏決定.具體可以參考相應代碼.例子中第一個TAG是起始TAG,如果環境變量中有bootargs,則建立第二個TAG,如果bootm有兩個參數(引導文件系統),則會讀取文件系統頭部的必要信息,建立第三個TAG.
  內核啟動后,將根據R2寄存器的值找到這些TAG,并根據TAG類型,調用相應的處理函數進行處理,從而獲取內核運行的必要信息.
本文來自CSDN博客,轉載請標明出處:
http://blog.csdn.net/lanmanck/archive/2009/06/24/4294685.aspx


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253776.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

異步FIFO設計(Verilog)

FIFO(First In First Out)是異步數據傳輸時經常使用的存儲器。該存儲器的特點是數據先進先出(后進后出)。其實,多位寬數據的異步傳輸問題,無論是從快時鐘到慢時鐘域,還是從慢時鐘到快時鐘域&…

python中RabbitMQ的使用(路由鍵模糊匹配)

路由鍵模糊匹配 使用正則表達式進行匹配。其中“#”表示所有、全部的意思;“*”只匹配到一個詞。 匹配規則: 路由鍵:routings [ happy.work, happy.life , happy.work.teacher, sad.work, sad.life, sad.work.teacher ] "#"&am…

數據倉庫事實表分類[轉]

1)在數據倉庫領域有一個概念叫Transaction fact table,中文一般翻譯為“事務事實表”。 事務事實表是維度建模的數據倉庫中三種基本類型事實表中的一種,另外兩種分別是周期快照事實表和累積快照事實表。 事務事實表與周期快照事實表、累積快…

嵌入式系統文件系統比較 jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs

Linux支持多種文件系統,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,為了對各類文件系統 進行統一管理,Linux引入了虛擬文件系統VFS(Virtual File System),為各類文件系統提供一個統一的操作界面和應用編程接口。 …

Codeforces Beta Round #17 C. Balance DP

C. Balance題目鏈接 http://codeforces.com/contest/17/problem/C 題面 Nick likes strings very much, he likes to rotate them, sort them, rearrange characters within a string... Once he wrote a random string of characters a, b, c on a piece of paper and began t…

時鐘切換處理(Verilog)

隨著各種應用場景的限制,芯片在運行時往往需要在不同的應用下切換不同的時鐘源,例如低功耗和高性能模式就分別需要低頻率和高頻率的時鐘。兩個時鐘源有可能是同源且同步的,也有可能是不相關的。直接使用選擇邏輯進行時鐘切換大概率會導致分頻…

SSH整合中,使用父action重構子類action類.(在父類中獲取子類中的泛型對象)

import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type;import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven;/*** 文件名 : BaseAction.java* 提取SSH中的action類* 由于SSH的action中采用模型驅動的方法,使用泛…

用BusyBox制作Linux根文件系統

STEP 1:構建目錄結構 創建根文件系統目錄,主要包括以下目錄 /dev /etc /lib /usr /var /proc /tmp /home /root /mnt /bin /sbin /sys #mkdir /home/rootfs #cd /home/rootfs #mkdir dev etc lib usr var proc tmp home roo…

Angular Elements 組件在非angular 頁面中使用的DEMO

2019獨角獸企業重金招聘Python工程師標準>>> 一、Angular Elements 介紹 Angular Elements 是伴隨Angular6.0一起推出的新技術。它借助Chrome瀏覽器的ShadowDom API,實現一種自定義組件。 這種組件可以用Angular普通組件的開發技術進行編寫,…

(轉) android里,addContentView()動態增加view控件,并實現控件的頂部,中間,底部布局...

http://blog.csdn.net/bfboys/article/details/52563089轉載于:https://www.cnblogs.com/zhangminghan/p/6182909.html

verilog仿真——$test$plusargs 和 $value$plusargs

VERILOG的參數可以用define和parameter的方式定義,這種方法要求我們在編譯前將變量必須定義好,編譯完成之后再也不能修改; 然而,有時候我們在進行仿真時,需要從外部傳遞參數,這個要求怎么滿足呢&#xff1…

盧卡斯定理

盧卡斯定理:解決一類組合數取模問題 A、B是非負整數,p是質數。AB寫成p進制:Aa[n]a[n-1]...a[0],Bb[n]b[n-1]...b[0]。 則組合數C(A,B)與C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0]) modp同余 即:Lucas(n,m,p)c(n%p,m%p)*Luc…

內核理解

在純技術方面,內核是硬件與軟件之間的一個中間層。其作用是將應用程序的請求傳遞給硬件,并充當底層的驅動程序,對系統中的各種設備和組件。內核啟動init程序作為第一個進程,該進程負責進一步的系統初始化操作,并顯示登…

loadrunner中對https證書的配置

1、準備好網站的證書,一般證書是cer格式; 2、因為loadrunner只支持pem格式的證書,所以要將證書轉換格式,利用openssl工具;(或者直接讓開發提供pem格式的證書)3、得到pem格式的證書之后&#xff…

Android 9 Pie震撼來襲 同步登陸WeTest

作者:We Test小編商業轉載請聯系騰訊WeTest獲得授權,非商業轉載請注明出處。原文鏈接:wetest.qq.com/lab/view/40…WeTest 導讀2018年8月7日,Google對外發布最新 Android 9.0 正式版系統,并宣布系統版本Android P 被正…

Datapath綜合代碼規范(Verilog)

一、一般準則 1、有符號數運算 利用類型“signed”完成有符號數運算,而不是用無符號數模擬有符號數運算。這樣可以得到更好的QoR。在資源報告中檢查操作數的類型和大小。 2、符號/零擴展 盡量不要手動擴展。verilog利用signed/unsigned會自動完成擴展。這樣代碼可…

Linux下V4L2編程小結

http://www.360doc.com/content/12/0318/16/532901_195392228.shtml :davind dm365linux移植 http://www.embedhq.org/html/jsbw/2010/0425/390.html :Linux下V4L2編程小結

百(垃)度(圾)之星初賽B hdu6114

Chess 題意:中文題 思路:其實就是在n個格子上放m個棋子(n>m)(xjb套Lucas的板子... AC代碼: #include "iostream" #include "string.h" #include "stack" #include "…

variable 'xxx' unsafe in 'case'的處理

問題描述: case get(?Player_LoopTaskInfo) of{TargetCnt, TaskStar, TaskExp} ->ok;_ ->throw("not_found_loop_task_info") end 在case語句中,這樣寫,編譯時,會提示變量unsafe,解決編譯器報錯的…

SDUT 3347 數據結構實驗之數組三:快速轉置

數據結構實驗之數組三&#xff1a;快速轉置 Time Limit: 1000 ms Memory Limit: 65536 KiBProblem Description 轉置運算是一種最簡單的矩陣運算&#xff0c;對于一個m*n的矩陣M( 1 < m < 10000,1 < n < 10000 )&#xff0c;它的轉置矩陣T是一個n*m的矩陣&…