linux驱动17---arm获取内存的大小

3800阅读 0评论2017-01-12 wangcong02345
分类:LINUX

一.总体说明     
arm中内存的大小及地址是uboot通过参数传给kernel的

二.uboot中内存大小的确
2.1 参数的位置
在board/sunxi/sun8iw7/sun8iw7.c中
  1. int board_init(void)
  2. {
  3.     gd->bd->bi_arch_number = LINUX_MACHINE_ID;
  4.     gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100);     //这儿确定了参数的位置
  5.     return 0;
  6. }
  7. include/configs/sun8iw7p1.h
        #define CONFIG_SYS_SDRAM_BASE    (0x40000000)
        #define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE    -->所以这个位置是0x40000100
2.2 参数中数据的填充
2.2.1 初始化参数
在arch/arm/lib/bootm.c中L213:do_boota_linux-->setup_start_tag
  1. 先定义了一个全局变量 --> static struct tag *params;
  2. static void setup_start_tag (bd_t *bd)
  3. {
  4.     params = (struct tag *) bd->bi_boot_params;   //全局变量params指向参数的内存

  5.     params->hdr.tag = ATAG_CORE;
  6.     params->hdr.size = tag_size (tag_core);

  7.     params->u.core.flags = 0;
  8.     params->u.core.pagesize = 0;
  9.     params->u.core.rootdev = 0;

  10.     params = tag_next (params);
  11. }
2.2.2 填充args的参数,以内存为例 
arch/arm/lib/bootm.c中L213:do_boota_linux-->setup_memory_tags
  1. static void setup_memory_tags (bd_t *bd)
  2. {
  3.     int i;

  4.     for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
  5.         params->hdr.tag = ATAG_MEM;                     //类型为ATA_MEM
  6.         params->hdr.size = tag_size (tag_mem32);

  7.         params->u.mem.start = bd->bi_dram[i].start;     //物理内存的起始地址
  8.         params->u.mem.size = bd->bi_dram[i].size;       //物理内存的大小
  9.         if(gd->ram_size_mb && (!bd->bi_dram[i].size))
  10.             params->u.mem.size = gd->ram_size_mb;
  11.         params = tag_next (params);
  12.     }
  13. }
2.2.3 完整流程
arch/arm/lib/bootm.c中L213:do_boota_linux-->setup_memory_tags
  1. int do_boota_linux (struct fastboot_boot_img_hdr *hdr)
  2. {
  3.     ulong initrd_start, initrd_end;
  4.     void (*kernel_entry)(int zero, int arch, uint params);
  5.     bd_t *bd = gd->bd;

  6.     kernel_entry = (void (*)(int, int, uint))(hdr->kernel_addr);

  7. #ifdef CONFIG_CMDLINE_TAG
  8.     char *commandline = getenv ("bootargs");
  9. #endif

  10.     initrd_start = hdr->ramdisk_addr;
  11.     initrd_end = initrd_start + hdr->ramdisk_size;
  12. #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
  13.     defined (CONFIG_CMDLINE_TAG) || \
  14.     defined (CONFIG_INITRD_TAG) || \
  15.     defined (CONFIG_SERIAL_TAG) || \
  16.     defined (CONFIG_REVISION_TAG)
  17.     setup_start_tag (bd);                  //初始化参
  18. #ifdef CONFIG_SERIAL_TAG
  19.     setup_serial_tag (&params);
  20. #endif
  21. #ifdef CONFIG_REVISION_TAG
  22.     setup_revision_tag (&params);         //填充参数-->vision
  23. #endif
  24. #ifdef CONFIG_SETUP_MEMORY_TAGS
  25.     setup_memory_tags (bd);               //填充参数-->内存
  26. #endif
  27. #ifdef CONFIG_CMDLINE_TAG    
  28.     setup_commandline_tag (bd, (char *)hdr->cmdline);   //填充参数-->cmdline,这个在内核启动时会打印出来
  29. #endif    
  30. #ifdef CONFIG_INITRD_TAG
  31.     if (hdr->ramdisk_size)
  32.         setup_initrd_tag (bd, initrd_start, initrd_end);
  33. #endif
  34. #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
  35.     setup_videolfb_tag ((gd_t *) gd);
  36. #endif
  37.     setup_end_tag (bd);
  38. #endif

  39.     announce_and_cleanup();

  40.     kernel_entry(0, bd->bi_arch_number, bd->bi_boot_params);   //最后启动内核

  41.     return 1;
  42. }
注意:原来内核中打印的cmdline并不是全部uboot的参数

三.uboot与kernel的参数传递
3.1 在arch/arm/kernel/setup.c中L1060-->start_kernel-->setup_arch
重点关注meminfo这个结构体
  1. void __init setup_arch(char **cmdline_p)
  2. {
  3.     struct machine_desc *mdesc;
  4.     int i; //add by cong
  5.     setup_processor();

  6.     mdesc = setup_machine_fdt(__atags_pointer);
  7.     for(i=0; i<NR_BANKS; i++//add by cong   -->此处打印发现meminfo结构体为空
  8.         dbmsg("bank[%d]-->[0x%x--0x%x],h=%x", i, meminfo.bank[i].start, meminfo.bank[i].size, meminfo.bank[i].highmem);
  9.     
  10.     if (!mdesc)
  11.         mdesc = setup_machine_tags(machine_arch_type);    -->所以重点在setup_machine_tags中,这个函数会解析uboot中的参数包括meminfo
  12.     for(i=0; i<NR_BANKS; i++//add by cong -->此处打印发现meminfo结构体不为空
  13.        dbmsg("bank[%d]-->[0x%x--0x%x],h=%x", i, meminfo.bank[i].start, meminfo.bank[i].size, meminfo.bank[i].highmem);
  14.     
  15.     machine_desc = mdesc;
  16.     machine_name = mdesc->name;

  17.     setup_dma_zone(mdesc);
  18.  
  19.     if (mdesc->restart_mode)
  20.         reboot_setup(&mdesc->restart_mode);
  21.     
  22.     init_mm.start_code = (unsigned long) _text;
  23.     init_mm.end_code = (unsigned long) _etext;
  24.     init_mm.end_data = (unsigned long) _edata;
  25.     init_mm.brk     = (unsigned long) _end;

  26.     /* populate cmd_line too for later use, preserving boot_command_line */
  27.     strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
  28.     *cmdline_p = cmd_line;

  29.     parse_early_param();
  30.     
  31.     sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
  32.     sanity_check_meminfo();
  33.     arm_memblock_init(&meminfo, mdesc);                  //将meminfo中的数据放到memblock

  34.     paging_init(mdesc);
  35.     request_standard_resources(mdesc);

  36.     if (mdesc->restart)
  37.         arm_pm_restart = mdesc->restart;

  38.     unflatten_device_tree();

  39. #ifdef CONFIG_ARCH_SUNXI
  40.     /* init sys_config script parse */
  41.     script_init();
  42. #endif

  43. #ifdef CONFIG_SMP
  44.     if (is_smp()) {
  45.         if (!mdesc->smp_init || !mdesc->smp_init())
  46.             smp_set_ops(mdesc->smp);
  47.         smp_init_cpus();
  48.         smp_build_mpidr_hash();
  49.     }
  50. #endif
  51.     reserve_crashkernel();

  52.     tcm_init();

  53. #ifdef CONFIG_MULTI_IRQ_HANDLER
  54.     handle_arch_irq = mdesc->handle_irq;
  55. #endif

  56. #ifdef CONFIG_VT
  57. #if defined(CONFIG_VGA_CONSOLE)
  58.     conswitchp = &vga_con;
  59. #elif defined(CONFIG_DUMMY_CONSOLE)
  60.     conswitchp = &dummy_con;
  61. #endif
  62. #endif

  63.     if (mdesc->init_early)
  64.         mdesc->init_early();
  65. }
3.2 解析参数的过程 在arch/arm/kernel/setup.c中L979
  1. static struct machine_desc * __init setup_machine_tags(unsigned int nr)
  2. {
  3.     struct tag *tags = (struct tag *)&init_tags;
  4.     struct machine_desc *mdesc = NULL, *p;
  5.     char *from = default_command_line;
  6.     int i; //cong
  7.     init_tags.mem.start = PHYS_OFFSET;

  8.     /*
  9.      * locate machine in the list of supported machines.
  10.      */
  11.     for_each_machine_desc(p)
  12.         if (nr == p->nr) {
  13.             printk("Machine: %s\n", p->name);
  14.             mdesc = p;
  15.             break;
  16.         }

  17.     if (!mdesc) {
  18.         early_print("\nError: unrecognized/unsupported machine ID"
  19.             " (r1 = 0x%08x).\n\n", nr);
  20.         dump_machine_table(); /* does not return */
  21.     }

  22.     if (__atags_pointer)
  23.         tags = phys_to_virt(__atags_pointer);
  24.     else if (mdesc->atag_offset)
  25.         tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);

  26. #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
  27.     /*
  28.      * If we have the old style parameters, convert them to
  29.      * a tag list.
  30.      */
  31.     if (tags->hdr.tag != ATAG_CORE)
  32.         convert_to_tag_list(tags);
  33. #endif

  34.     if (tags->hdr.tag != ATAG_CORE) {
  35. #if defined(CONFIG_OF)
  36.         /*
  37.          * If CONFIG_OF is set, then assume this is a reasonably
  38.          * modern system that should pass boot parameters
  39.          */
  40.         early_print("Warning: Neither atags nor dtb found\n");
  41. #endif
  42.         tags = (struct tag *)&init_tags;
  43.     }
  44.     for(i=0; i<NR_BANKS; i++)
  45.         dbmsg("bank[%d]-->[0x%x--0x%x],h=%x", i, meminfo.bank[i].start, meminfo.bank[i].size, meminfo.bank[i].highmem);

  46.     if (mdesc->fixup)
  47.     {
  48.      dbmsg("fixup=0x%x", mdesc->fixup);
  49.      mdesc->fixup(tags, &from, &meminfo);
  50.     }
  51.     for(i=0; i<NR_BANKS; i++)    -->此处打印发现meminfo结构体为空
  52.         dbmsg("bank[%d]-->[0x%x--0x%x],h=%x", i, meminfo.bank[i].start, meminfo.bank[i].size, meminfo.bank[i].highmem);
  53.     
  54.     if (tags->hdr.tag == ATAG_CORE) {
  55.         if (meminfo.nr_banks != 0)
  56.             squash_mem_tags(tags);
  57.         save_atags(tags);
  58.         parse_tags(tags);          -->所以重点在parse_tags中
  59.     }
  60.     for(i=0; i<NR_BANKS; i++)    -->此处打印发现meminfo结构体不为空
  61.     dbmsg("bank[%d]-->[0x%x--0x%x],h=%x", i, meminfo.bank[i].start, meminfo.bank[i].size, meminfo.bank[i].highmem);
  62.     
  63.     /* parse_early_param needs a boot_command_line */
  64.     strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

  65.     return mdesc;
  66. }
在arch/arm/kernel/setup.c中L859:setup_machine_tags-->parse_tags
  1. static void __init parse_tags(const struct tag *t)
  2. {
  3.     for (; t->hdr.size; t = tag_next(t))
  4.         if (!parse_tag(t))
  5.             printk(KERN_WARNING  "Ignoring unrecognised tag 0x%08x\n", t->hdr.tag);
  6. }
在arch/arm/kernel/setup.c中L866:setup_machine_tags-->parse_tags-->parse_tag
  1. static int __init parse_tag(const struct tag *tag)
  2. {
  3.     extern struct tagtable __tagtable_begin, __tagtable_end;
  4.     struct tagtable *t;

  5.     for (t = &__tagtable_begin; t < &__tagtable_end; t++)
  6.         if (tag->hdr.tag == t->tag) {
  7.             t->parse(tag);    //对每个参数都调用一次t->parse:例如mem类型会调用parse_tag_mem32
  8.             break;
  9.         }

  10.     return t < &__tagtable_end;
  11. }
在arch/arm/kernel/setup.c中L776:setup_machine_tags-->parse_tags-->parse_tag-->parse_tag_mem32
  1. static int __init parse_tag_mem32(const struct tag *tag)
  2. {
  3.     dbmsg("tag->start=0x%x, tag->mem.size=0x%x", tag->u.mem.start, tag->u.mem.size);   
  4.     //打印结果tag->u.mem.start=0x40000000, tag->u.mem.size=0x40000000 
  5.     //正好是内存的起始与大小
  6.     return arm_add_memory(tag->u.mem.start, tag->u.mem.size);    //这会将start与size保存在meminfo中
  7. }
3.3  从memblock中获取内存大小
在arch/arm/mm/init.c中start_kernel-->mm_init-->mem_init
  1. void __init mem_init(void)
  2. {
  3.     ....

  4.     /*
  5.      * Since our memory may not be contiguous, calculate the
  6.      * real number of pages we have in this system
  7.      */
  8.     printk(KERN_INFO "Memory:");
  9.     num_physpages = 0;
  10.     for_each_memblock(memory, reg) {   
  11.         unsigned long pages = memblock_region_memory_end_pfn(reg) -  memblock_region_memory_base_pfn(reg);
  12.         num_physpages += pages;
  13.         printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
  14.     }
  15.     printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));

  16.     printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
  17.         nr_free_pages() << (PAGE_SHIFT-10),
  18.         free_pages << (PAGE_SHIFT-10),
  19.         reserved_pages << (PAGE_SHIFT-10),
  20.         totalhigh_pages << (PAGE_SHIFT-10));
  21.     ....
  22. }
注意这个宏:
  1. #define for_each_memblock(memblock_type, region)                    \
  2.   for (region = memblock.memblock_type.regions;                \ 这儿的memblock不是结构体
  3.      region < (memblock.memblock_type.regions + memblock.memblock_type.cnt);    \
  4.      region++)  
  5. //注意:这儿的memblock不是结构体,而是变量名 
  6. struct memblock memblock __initdata_memblock -->在mm/memblock.c中定义的




上一篇:linux2.4.18----26.由内核态切换到用户态
下一篇:android开发----1.init进程分析