如何从uboot读取mac,然户传递到内核中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从uboot读取mac,然户传递到内核中相关的知识,希望对你有一定的参考价值。

参考技术A   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文件中(指Uboot的根目录),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 (?ms);
  #endif
  #ifdef CONFIG_REVISION_TAG
  setup_revision_tag (?ms);
  #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 < CONFIG_NR_DRAM_BANKS; i++)
  params->hdr.tag = ATAG_MEM;
  params->hdr.size = tag_size (tag_mem32);
  params->u.mem.start = bd->bi_dram[i].start;
  params->u.mem.size = bd->bi_dram[i].size;
  params = tag_next (params);
   //初始化内存相关tag
  
  2、Kernel读取U-boot传递的相关参数
  对于Linux Kernel,ARM平台启动时,先执行arch/arm/kernel/head.S,此文件会调用arch/arm/kernel/head- common.S和arch/arm/mm/proc-arm920.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函数。

以上是关于如何从uboot读取mac,然户传递到内核中的主要内容,如果未能解决你的问题,请参考以下文章

uboot环境变量(设置bootargs向linux内核传递正确的参数)

内核中对uboot传参tags的校验

内核中对uboot传参tags的校验

S5P210-uboot源码分析-uboot如何启动内核

uboot传递设备树

Linux学习 :Uboot 移植