boot 传递了什么内容到 kernel? 是怎样传递的?
/********************************************************************************/boot 传递了什么内容到 kernel? 是怎样传递的?
传递的内容是machid and tag address, 当然kernel entry 也是这里决定的
/********************************************************************************/
从最终的地方开始看:
arch/arm/lib/bootm.cint do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
/* No need for those on ARM */
if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
return -1;
if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}
if (flag & BOOTM_STATE_OS_GO) {
boot_jump_linux(images);
return 0;
}
boot_prep_linux(images);
boot_jump_linux(images);
return 0;
}
1] 首先看输入参数:
flag标识boot的方法,这里的flag为0,不关注flag的具体含义。另外argv没有使用,所以只需关注bootm_headers_t *images。/*
* Legacy and FIT format headers used by do_bootm() and do_bootm_<os>()
* routines.
*/
typedef struct bootm_headers {
/*
* Legacy os image header, if it is a multi component image
* then boot_get_ramdisk() and get_fdt() will attempt to get
* data from second and third component accordingly.
*/
image_header_t *legacy_hdr_os; /* image header pointer */
image_header_t legacy_hdr_os_copy; /* header copy */
ulong legacy_hdr_valid;
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
int verify; /* getenv("verify")[0] != 'n' */
int state;
struct lmb lmb; /* for memory mgmt */
} bootm_headers_t;
2] /* Subcommand: PREP */
static void boot_prep_linux(bootm_headers_t *images){
char *commandline = getenv("bootargs");
debug("using: ATAGS\n");
setup_start_tag(gd->bd);
setup_commandline_tag(gd->bd, commandline);
setup_memory_tags(gd->bd);
setup_end_tag(gd->bd);
}
/* gd 是个全局变量,boot_params的值是在 board_ini时赋值的,offset 为 0x100
* setup TAG, 就是把TAG写到地址固定的地方,kernel 从这个地方读取。
* 对应的kernel代码在哪里?
*/
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *)bd->bi_boot_params;
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);
}
borad/nufront/ns115xx/yy.c
board_init:
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x80000100;
3]/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images){
unsigned long machid = gd->bd->bi_arch_number;
char *s;
/* how to get a function point variable */
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
/* how to value a function point variable */
kernel_entry = (void (*)(int, int, uint))images->ep;
s = getenv("machid");
if (s) {
strict_strtoul(s, 16, &machid);
printf("Using machid 0x%lx from environment\n", machid);
}
debug("## Transferring control to Linux (at address %08lx)" \
"...\n", (ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
announce_and_cleanup();
s = getenv("dtbaddr");
if (s) {
strict_strtoul(s, 16, &r2);
printf("Using r2 0x%lx from environment\n", r2);
} else {
r2 = DTBADDR_DEFAULT;
printf("Using r2 0x%lx from default dtbaddr\n", r2);
}
/*r0:0, r1:machid, r2: tag address*/
kernel_entry(0, machid, r2);
}
TAG的内容来自哪里?怎样赋值的?怎样更改?
/********************************************************************************/TAG的内容来自哪里?怎样赋值的?怎样更改?
TAG的内容来自env,可以来自代码的设置,也可以从MMC等地方读出,setenv and saveenv
/********************************************************************************/
boot_prep_linux -> getenv("bootargs");
arch/arm/cpu/armxxx/start.s
bl board_init_f
board_init_f ->
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
-> env_init, /* initialize environment */
有多个 env_init的定义:从包含的头文件判断是: env_mmc.c
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
return 0;
}
board_init_r -> env_relocate();
void env_relocate(void)
{
if (gd->env_valid == 0) {
----
} else {
env_relocate_spec();
}
}
void env_relocate_spec(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
u32 offset;
if (init_mmc_for_env(mmc) || mmc_get_env_addr(mmc, &offset))
return set_default_env(NULL);
if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf))
return set_default_env(NULL);
env_import(buf, 1);
}
/*这里看上去只是建立了hash table,数据来自哪里?数据到底是存在hash table 里还是MMC中?*/
void set_default_env(const char *s)
{
if (himport_r(&env_htab, (char *)default_environment,
sizeof(default_environment), '\0', 0) == 0)
error("Environment import failed: errno = %d\n", errno);
gd->flags |= GD_FLG_ENV_READY;
}
U_BOOT_CMD_COMPLETE(
printenv, CONFIG_SYS_MAXARGS, 1, do_env_print,
"print environment variables",
"\n - print values of all environment variables\n"
"printenv name ...\n"
" - print value of environment variable 'name'",
var_complete
);
do_env_print -> env_print -> hexport_r(&env_htab,)[print whole list]
感到困惑的,为什么代码里没有决定bootargs, 是因为你写了set bootargs 'xxxx',
如果不写就是默认值,如果写入一次就保存啦?不是的必须使用saveenv才会保存到mmc,
setenv只是保存到ram中,也就是写道那个hash table 中。
该实例是使用保存在MMC中的数据:从MMC 中读出数据进行分析,代码中的 defaultsetting不起作用。
void env_relocate_spec(void)
{
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
env_import(buf, 1);
}