u-boot向kernel传递设备树、环境变量解析
【
do_bootm_states---wzf test
states:0x1
continue ......
need_boot_fn:0x0
states:0x1
## Flattened Device Tree blob at 88000000
Booting using the fdt blob at 0x88000000
do_bootm_states---wzf test
states:0x700
continue ......
need_boot_fn:0x700
states:0x700
using: FDT
IMAGE_ENABLE_OF_LIBFDT
IMAGE_ENABLE_RAMDISK_HIGH
IMAGE_ENABLE_OF_LIBFDT
Loading Device Tree to 8ffe3000, end 8ffff907 ... OK
IMAGE_ENABLE_OF_LIBFDT
BOOTM_STATE_OS_GO---wzf test
】
二、Cmd/bootm.c中
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
……
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
BOOTM_STATE_OS_CMDLINE |
#endif
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO, &images, 1);
}
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
(函数中只会执行下述显示内容)
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
……
#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
if (!ret && (states & BOOTM_STATE_FDT)) {//将设备树读取到内存中
boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
&images->ft_len);
}
……
boot_fn = bootm_os_get_boot_func(images->os.os);[get到do_bootm_linux]
if (!ret && (states & BOOTM_STATE_OS_PREP)) {
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
if (images->os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif
【相当于do_bootm_linux(BOOTM_STATE_OS_PREP, argc, argv, images)】
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
}
……
/* Now run the OS! We hope this doesn't return */
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,images, boot_fn);
……
}
三、Arch/arm/lib/bootm.c中
int do_bootm_linux(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
……
boot_prep_linux(images);
boot_jump_linux(images, flag);
……
}
注:
【
arch/arm/include/asm/setup.h中
#define __tag __attribute__((unused, __section__(".taglist")))
#define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn }
同时定义了struct tag、tag_cmdline、tag_revision、tag_core等
】
Arch/arm/lib/bootm.c中
static void boot_prep_linux(bootm_headers_t *images)
{
char *commandline = getenv("bootargs");
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
#ifdef CONFIG_OF_LIBFDT
debug("using: FDT\n");
if (image_setup_linux(images)) {//在设备树末尾添加一些参数
printf("FDT creation failed! hanging...");
hang();
}
#endif
} else if (BOOTM_ENABLE_TAGS) {//构造填充要传递的tags
debug("using: ATAGS\n");
setup_start_tag(gd->bd);
if (BOOTM_ENABLE_SERIAL_TAG)
setup_serial_tag(¶ms);
if (BOOTM_ENABLE_CMDLINE_TAG)
setup_commandline_tag(gd->bd, commandline);
if (BOOTM_ENABLE_REVISION_TAG)
setup_revision_tag(¶ms);
if (BOOTM_ENABLE_MEMORY_TAGS)
setup_memory_tags(gd->bd);
if (BOOTM_ENABLE_INITRD_TAG) {
/*
* In boot_ramdisk_high(), it may relocate ramdisk to
* a specified location. And set images->initrd_start &
* images->initrd_end to relocated ramdisk's start/end
* addresses. So use them instead of images->rd_start &
* images->rd_end when possible.
*/
if (images->initrd_start && images->initrd_end) {
setup_initrd_tag(gd->bd, images->initrd_start,
images->initrd_end);
} else if (images->rd_start && images->rd_end) {
setup_initrd_tag(gd->bd, images->rd_start,
images->rd_end);
}
}
setup_board_tags(¶ms);
setup_end_tag(gd->bd);
} else {
printf("FDT and ATAGS support not compiled in - hanging\n");
hang();
}
}
Common/image.c中:
int image_setup_linux(bootm_headers_t *images)//通过此函数在设备树末尾添加一些参数
{
ulong of_size = images->ft_len;
char **of_flat_tree = &images->ft_addr;
ulong *initrd_start = &images->initrd_start;
ulong *initrd_end = &images->initrd_end;
struct lmb *lmb = &images->lmb;
ulong rd_len;
int ret;
if (IMAGE_ENABLE_OF_LIBFDT)
boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);
if (IMAGE_BOOT_GET_CMDLINE) {
ret = boot_get_cmdline(lmb, &images->cmdline_start,
&images->cmdline_end);
if (ret) {
puts("ERROR with allocation of cmdline\n");
return ret;
}
}
if (IMAGE_ENABLE_RAMDISK_HIGH) {
rd_len = images->rd_end - images->rd_start;
ret = boot_ramdisk_high(lmb, images->rd_start, rd_len,
initrd_start, initrd_end);
if (ret)
return ret;
}
if (IMAGE_ENABLE_OF_LIBFDT) {
ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
if (ret)
return ret;
}
if (IMAGE_ENABLE_OF_LIBFDT && of_size) {
ret = image_setup_libfdt(images, *of_flat_tree, of_size, lmb);
if (ret)
return ret;
}
return 0;
}
四、Arch/arm/lib/bootm.c中
static void boot_jump_linux(bootm_headers_t *images, int flag)//跳到内核
{
#ifdef CONFIG_ARM64
void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
void *res2);
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
void *res2))images->ep;
debug("## Transferring control to Linux (at address %lx)...\n",
(ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
announce_and_cleanup(fake);
if (!fake) {
#ifdef CONFIG_ARMV8_PSCI
armv8_setup_psci();
#endif
do_nonsec_virt_switch();
update_os_arch_secondary_cores(images->os.arch);
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
armv8_switch_to_el2((u64)images->ft_addr, 0, 0,
(u64)switch_to_el1, ES_TO_AARCH64);
#else
if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
(images->os.arch == IH_ARCH_ARM))
armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
(u64)images->ft_addr,
(u64)images->ep,
ES_TO_AARCH32);
else
armv8_switch_to_el2((u64)images->ft_addr, 0, 0,
images->ep,
ES_TO_AARCH64);
#endif
}
#else
unsigned long machid = gd->bd->bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(int, int, uint))images->ep;
s = getenv("machid");
if (s) {
if (strict_strtoul(s, 16, &machid) < 0) {
debug("strict_strtoul failed!\n");
return;
}
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(fake);
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
r2 = (unsigned long)images->ft_addr;
else
r2 = gd->bd->bi_boot_params;
if (!fake) {
#ifdef CONFIG_ARMV7_NONSEC
if (armv7_boot_nonsec()) {
armv7_init_nonsec();
secure_ram_addr(_do_nonsec_entry)(kernel_entry,
0, machid, r2);
} else
#endif
kernel_entry(0, machid, r2);
}
#endif
}
第二部分:Kernel中
一、内核C入口函数
Init/main.c中start_kernel()
{
char *command_line;
…
setup_arch(&command_line);
…
}
到arch/arm/kernel/setup.c中
注:
{
Arch/arm/mm/mmu.c中:
extern unsigned long __atags_pointer;
arch/arm/kernel/head-common.S中
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
赋值__atags_pointer
}
unsigned int __atags_pointer __initdata;
void __init setup arch(char **cmdline_p)
{
const struct machine_desc *mdesc;
…
mdesc = setup_machine_fdt(__atags_pointer);//解析设备树
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);//解析tags
…
}
二、设备树接收及分析
arch/arm/kernel/devtree.c中:
const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{
const struct machine_desc *mdesc, *mdesc_best = NULL;
…
mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
...
}
主要的解析在drivers/of/fdt.c中
const void * __init of_flat_dt_match_machine(const void *default_match,
const void * (*get_next_compat)(const char * const**));
三、TAGS接收及分析
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
到arch/arm/kernel/atags_parse.c中
const struct machine_desc * __init
setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
{
…
if (tags->hdr.tag == ATAG_CORE) {
if (memblock_phys_mem_size())
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
}
…
}
解析主要在arch/arm/kernel/atags_parse.c中
static void __init parse_tags(const struct tag *t)
{
for (; t->hdr.size; t = tag_next(t))
if (!parse_tag(t))
pr_warn("Ignoring unrecognised tag 0x%08x\n",
t->hdr.tag);
}
static int __init parse_tag(const struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
arch/arm/kernel/vmlinux.lds中
.init.tagtable : {
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;
}
Arch/arm/include/uapi/asm/setup.h中
struct tagtable {
__u32 tag;
int (*parse)(const struct tag *);
};
同时也定义了struct tag、tag_core、tag_mem32、tag_revision、tag_cmdline等
Arch/arm/include/asm/setup.h中
#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \
static const struct tagtable __tagtable_##fn __tag = { tag, fn }
如下定义各种__tagtable,解析tags(ATAG_*、结构体的定义与UBOOT中一致)
The tag table is built by the linker from all the __tagtable
atags_parse.c (arch\arm\kernel) line 64 : __tagtable(ATAG_CORE, parse_tag_core);
atags_parse.c (arch\arm\kernel) line 71 : __tagtable(ATAG_MEM, parse_tag_mem32);
atags_parse.c (arch\arm\kernel) line 88 : __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
atags_parse.c (arch\arm\kernel) line 106 : __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
atags_parse.c (arch\arm\kernel) line 116 : __tagtable(ATAG_SERIAL, parse_tag_serialnr);
atags_parse.c (arch\arm\kernel) line 124 : __tagtable(ATAG_REVISION, parse_tag_revision);
atags_parse.c (arch\arm\kernel) line 141 : __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
common.c (arch\arm\mach-footbridge) line 52 : __tagtable(ATAG_MEMCLK, parse_tag_memclk);
init.c (arch\arm\mm) line 79 : __tagtable(ATAG_INITRD, parse_tag_initrd);
init.c (arch\arm\mm) line 88 : __tagtable(ATAG_INITRD2, parse_tag_initrd2);
riscpc.c (arch\arm\mach-rpc) line 66 : __tagtable(ATAG_ACORN, parse_tag_acorn);
第三部分:最终处理
一、uboot中修改
在include/configs/am57xx_evm.h中添加#define UBOOTVERSION “01”
在common/image.c中修改
//mod by wzf for version management 2018.08.04
//#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
int boot_get_cmdline(struct lmb *lmb, ulong *cmd_start, ulong *cmd_end)
{
char *cmdline;
//char *s;
cmdline = (char *)(ulong)lmb_alloc_base(lmb, CONFIG_SYS_BARGSIZE, 0xf,
getenv_bootm_mapsize() + getenv_bootm_low());
if (cmdline == NULL)
return -1;
//if ((s = getenv("bootargs")) == NULL)
// s = "";
strcpy(cmdline, UBOOTVERSION);
*cmd_start = (ulong) & cmdline[0];
*cmd_end = *cmd_start + strlen(cmdline);
debug("## cmdline at 0x%08lx ... 0x%08lx\n", *cmd_start, *cmd_end);
printf("###UBOOTVERSION:%s\n",cmdline);
return 0;
}
//#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
int image_setup_linux(bootm_headers_t *images)
{
……
//mod by wzf for version management 2018.08.04
//if (IMAGE_BOOT_GET_CMDLINE) {
if(1) {
ret = boot_get_cmdline(lmb, &images->cmdline_start,
&images->cmdline_end);
if (ret) {
puts("ERROR with allocation of cmdline\n");
return ret;
}
}
……
}
二、kernel中修改
修改arch/arm/kernel/setup.c
/* mod by wzf for version management 2018.08.04 */
char ubootversion[2];
void __init setup_arch(char **cmdline_p)
{
const struct machine_desc *mdesc;
unsigned int ubootversion_addr = __atags_pointer + 0x1cc00;
setup_processor();
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
strncpy(ubootversion, (char *)phys_to_virt(ubootversion_addr), 2);
machine_desc = mdesc;
……
}
修改fs/proc/Makefile
proc-y += version.o
# add by wzf for version management 2018.08.04
proc-y += kernelversion.o
proc-y += ubootversion.o
proc-y += softirqs.o
添加fs/proc/kernelversion.c
/* add by wzf for version management 2018.08.04 */
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/utsname.h>
const char hepu_kernelversion[] = "01";
static int kernelversion_proc_show(struct seq_file *m, void *v)
{
seq_printf(m,hepu_kernelversion);
return 0;
}
static int kernelversion_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, kernelversion_proc_show, NULL);
}
static const struct file_operations kernelversion_proc_fops = {
.open = kernelversion_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init proc_kernelversion_init(void)
{
proc_create("kernelversion", 0, NULL, &kernelversion_proc_fops);
return 0;
}
fs_initcall(proc_kernelversion_init);
添加fs/proc/ubootversion.c
/* add by wzf for version management 2018.08.04 */
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/utsname.h>
extern char ubootversion[];
static int ubootversion_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, (const char *)ubootversion);
return 0;
}
static int ubootversion_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, ubootversion_proc_show, NULL);
}
static const struct file_operations ubootversion_proc_fops = {
.open = ubootversion_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init proc_ubootversion_init(void)
{
proc_create("ubootversion", 0, NULL, &ubootversion_proc_fops);
return 0;
}
fs_initcall(proc_ubootversion_init);