u-boot向kernel传递设备树、环境变量解析

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(&params);

              if (BOOTM_ENABLE_CMDLINE_TAG)

                     setup_commandline_tag(gd->bd, commandline);

              if (BOOTM_ENABLE_REVISION_TAG)

                     setup_revision_tag(&params);

              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(&params);

              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);

 

猜你喜欢

转载自blog.csdn.net/u014626722/article/details/81502290