您的位置 首页 开关

Linux内核高-低端内存设置代码盯梢(ARM构架)

对于ARM中内核如何在启动的时候设置高低端内存的分界线(也是逻辑地址与虚拟地址分界线(虚拟地址)减去那个固定的偏移),这里我稍微引导…

关于ARM中内核如安在发动的时分设置高低端内存的分界线(也是逻辑地址与虚拟地址分界线(虚拟地址)减去那个固定的偏移),这儿我略微引导下(内核剖析运用Linux-3.0):

首要定位设置内核虚拟地址开始方位(也便是内核逻辑地址结尾+1的地址)的文件:init.c (arch\arm\mm),在这个文件中的void __init bootmem_init(void)函数如下
  1. void __init bootmem_init(void)
  2. {
  3. unsigned long min,max_low,max_high;
  4. max_low=max_high=0;
  5. find_limits(&min,&max_low,&max_high);
  6. arm_bootmem_init(min,max_low);
  7. /*
  8. *Sparsemem triestoallocate bootmeminmemory_present(),
  9. *so must be done after the fixed reservations
  10. */
  11. arm_memory_present();
  12. /*
  13. *sparse_init()needs the bootmem allocator upandrunning.
  14. */
  15. sparse_init();
  16. /*
  17. *Nowfree the memoryfree_area_init_node needs
  18. *the sparse mem_map arrays initialized by sparse_init()
  19. *formemmap_init_zone(),otherwise all PFNs are invalid.
  20. */
  21. arm_bootmem_free(min,max_low,max_high);
  22. high_memory = __va(((phys_addr_t)max_low << PAGE_SHIFT) - 1) + 1;
  23. /*
  24. *This doesnt seemtobe used by the Linux memory manager any
  25. *more,butisused by ll_rw_block.Ifwe cangetrid of it,we
  26. *alsogetrid of some of the stuff above as well.
  27. *
  28. *Note:max_low_pfnandmax_pfn reflect the number of _pages_in
  29. *the system,notthe maximum PFN.
  30. */
  31. max_low_pfn=max_lowPHYS_PFN_OFFSET;
  32. max_pfn=max_highPHYS_PFN_OFFSET;
  33. }
这个high_memory=__va(((phys_addr_t)max_low<<PAGE_SHIFT)1)+1;句子便是要害。从这儿能够知道max_low便是高端内存的开始地址(物理地址)。那么这个max_low是怎么得到的?其实看上面的代码能够推测出,他其实是在find_limits(&min,&max_low,&max_high);中(在同一个文件中)被设置的:
  1. static void __init find_limits(unsigned long*min,unsigned long*max_low,
  2. unsigned long*max_high)
  3. {
  4. struct meminfo*mi=&meminfo;
  5. inti;
  6. *min=-1UL;
  7. *max_low=*max_high=0;
  8. for_each_bank(i,mi){
  9. struct membank*bank=&mi->bank[i];
  10. unsigned long start,end;
  11. start=bank_pfn_start(bank);
  12. end=bank_pfn_end(bank);
  13. if(*min>start)
  14. *min=start;
  15. if(*max_high<end)
  16. *max_high=end;
  17. if (bank->highmem)
  18. continue;
  19. if (*max_low < end)
  20. *max_low = end;
  21. }
  22. }
这个函数的意思很明显:经过扫描struct meminfo*mi=&meminfo;(结构体meminfo的数组)中的一切信息,设置三个指针所指的变量:
  1. min :内存物理地址开始
  2. max_low :低端内存区物理地址结尾
  3. max_high :高端内存区物理地址结尾
从上面能够看出,max_low和max_high所保存的地址不同便是因为bank->highmem形成的,它是内存bank被设为高端内存的根据:
  1. “假如这个内存bank是高端内存(bank->highmem != 0),越过max_low = end;句子,max_low和max_high将不同(成果实际上是max_high >max_low);
  2. 不然假定没有一个内存bank是高端内存(一切bank->highmem == 0)max_low和max_high必定共同(高端内存巨细为0)”
当然要完结这个函数的功用,有必要确保meminfo所指数组中的一切bank是依照地址数据从小到大排序好的哦~~。可是这个咱们不必忧虑,后边会看到的:)
经过上面的盯梢,焦点会集到了全局变量(同一个文件中):
  1. struct meminfo meminfo;
这个结构体的界说(setup.h (arch\arm\include\asm)):
  1. /*
  2. * Memory map description
  3. */
  4. #define NR_BANKS 8
  5. struct membank {
  6. phys_addr_t start;
  7. unsigned long size;
  8. unsigned int highmem;
  9. };
  10. struct meminfo {
  11. int nr_banks;
  12. struct membank bank[NR_BANKS];
  13. };
  14. extern struct meminfo meminfo;
  15. #define for_each_bank(iter,mi)\
  16. for (iter = 0; iter < (mi)->nr_banks; iter++)
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT)
#define bank_phys_start(bank) (bank)->start
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
#define bank_phys_size(bank) (bank)->size
只需找到初始化这个全局变量并完结排序的当地,就能够知道高端内存是怎么装备的了!!OK,明晰方针,go on~~~
经过查找代码,咱们能够在setup.c (arch\arm\kernel)这个文件中找到相关的代码。在体系发动早期会运转的函数(详细的次序你能够自行剖析下ARM内核的发动流程,今后我也会写下)中有这样一个函数:
  1. void __init setup_arch(char **cmdline_p)
  2. {
  3. struct machine_desc *mdesc;
  4. unwind_init();
  5. setup_processor();
  6. mdesc = setup_machine_fdt(__atags_pointer);
  7. if (!mdesc)
  8. mdesc = setup_machine_tags(machine_arch_type);
  9. machine_desc = mdesc;
  10. machine_name = mdesc->name;
  11. if (mdesc->soft_reboot)
  12. reboot_setup(“s”);
  13. init_mm.start_code = (unsigned long) _text;
  14. init_mm.end_code = (unsigned long) _etext;
  15. init_mm.end_data = (unsigned long) _edata;
  16. init_mm.brk = (unsigned long) _end;
  17. strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
  18. *cmdline_p = cmd_line;
  19. parse_early_param();
  20. sanity_check_meminfo();
  21. arm_memblock_init(&meminfo, mdesc);
  22. paging_init(mdesc);
  23. request_standard_resources(mdesc);
  24. unflatten_device_tree();
  25. #ifdef CONFIG_SMP
  26. if (is_smp())
  27. smp_init_cpus();
  28. #endif
  29. reserve_crashkernel();
  30. cpu_init();
  31. tcm_init();
  32. #ifdef CONFIG_MULTI_IRQ_HANDLER
  33. handle_arch_irq = mdesc->handle_irq;
  34. #endif
  35. #ifdef CONFIG_VT
  36. #if defined(CONFIG_VGA_CONSOLE)
  37. conswitchp = &vga_con;
  38. #elif defined(CONFIG_DUMMY_CONSOLE)
  39. conswitchp = &dummy_con;
  40. #endif
  41. #endif
  42. early_trap_init();
  43. if (mdesc->init_early)
  44. mdesc->init_early();
  45. }
在上面的注释中,我现已表明晰要点和解析,下面我细化下:
(1)获取参数部分
经过parse_early_param();函数能够解析内核发动参数中的许多字符串,可是关于咱们这次剖析内存的话主要是剖析以下两个参数:
mem=size@start参数,她为初始化struct meminfo meminfo;(咱们一向重视的内存信息哦~)供给信息。详细的获取信息的函数(相同坐落setup.c (arch\arm\kernel)):
  1. int __init arm_add_memory(phys_addr_t start, unsigned long size)
  2. {
  3. struct membank *bank = &meminfo.bank[meminfo.nr_banks];
  4. if (meminfo.nr_banks >= NR_BANKS) {
  5. printk(KERN_CRIT “NR_BANKS too low, “
  6. “ignoring memory at 0xllx\n”, (long long)start);
  7. return -EINVAL;
  8. }
  9. /*
  10. * Ensure that start/size are aligned to a page boundary.
  11. * Size is appropriately rounded down, start is rounded up.
  12. */
  13. size -= start & ~PAGE_MASK;
  14. bank->start = PAGE_ALIGN(start);
  15. bank->size = size & PAGE_MASK;
  16. /*
  17. * Check whether this memory region has non-zero size or
  18. * invalid node number.
  19. */
  20. if (bank->size == 0)
  21. return -EINVAL;
  22. meminfo.nr_banks++;
  23. return 0;
  24. }
  25. /*
  26. * Pick out the memory size. We look for mem=size@start,
  27. * where start and size are “size[KkMm]”
  28. */
  29. static int __init early_mem(char *p)
  30. {
  31. static int usermem __initdata = 0;
  32. unsigned long size;
  33. phys_addr_t start;
  34. char *endp;
  35. /*
  36. * If the user specifies memory size, we
  37. * blow away any automatically generated
  38. * size.
  39. */
  40. if (usermem == 0) {
  41. usermem = 1;
  42. meminfo.nr_banks = 0;
  43. }
  44. start = PHYS_OFFSET;
  45. size = memparse(p, &endp);
  46. if (*endp == @)
  47. start = memparse(endp + 1, NULL);
  48. arm_add_memory(start, size);
  49. return 0;
  50. }
  51. early_param(“mem”, early_mem);
vmalloc=size参数,她为初始化vmalloc_min(需求保存的内核虚拟地址空间巨细,也便是这个内核虚拟地址空间中除掉逻辑地址空间和必要的避免越界的维护空泛后最少要预留的地址空间)供给信息。详细的完结函数(坐落mmu.c (arch\arm\mm)):
  1. static void * __initdata vmalloc_min = (void *)(VMALLOC_END – SZ_128M);
  1. /*
  2. * vmalloc=size forces the vmalloc area to be exactly size
  3. * bytes. This can be used to increase (or decrease) the vmalloc
  4. * area – the default is 128m.
  5. */
  6. static int __init early_vmalloc(char *arg)
  7. {
  8. unsigned long vmalloc_reserve = memparse(arg, NULL);
  9. if (vmalloc_reserve < SZ_16M) {
  10. vmalloc_reserve = SZ_16M;
  11. printk(KERN_WARNING
  12. “vmalloc area too small, limiting to %luMB\n”,
  13. vmalloc_reserve >> 20);
  14. }
  15. if (vmalloc_reserve > VMALLOC_END – (PAGE_OFFSET + SZ_32M)) {
  16. vmalloc_reserve = VMALLOC_END – (PAGE_OFFSET + SZ_32M);
  17. printk(KERN_WARNING
  18. “vmalloc area is too big, limiting to %luMB\n”,
  19. vmalloc_reserve >> 20);
  20. }
  21. vmalloc_min = (void *)(VMALLOC_END – vmalloc_reserve);
  22. return 0;
  23. }
  24. early_param(“vmalloc”, early_vmalloc);
(2)在获得了必要的信息(初始化好struct meminfo meminfo和vmalloc_min)后,内核经过sanity_check_meminfo函数主动去经过vmalloc_min信息来初始化每个meminfo.bank[?]中的highmem成员。此过程中假如有必要,将或许会改动meminfo中的bank数组。处理函数坐落mmu.c (arch\arm\mm):
  1. static phys_addr_t lowmem_limit __initdata = 0;
  2. void __init sanity_check_meminfo(void)
  3. {
  4. int i, j, highmem = 0;
  5. for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
  6. struct membank *bank = &meminfo.bank[j];
  7. *bank = meminfo.bank[i];
  8. #ifdef CONFIG_HIGHMEM
  9. if (__va(bank->start) >= vmalloc_min ||
  10. __va(bank->start) < (void *)PAGE_OFFSET)
  11. highmem = 1;
  12. bank->highmem = highmem;
  13. /*
  14. * Split those memory banks which are partially overlapping
  15. * the vmalloc area greatly simplifying things later.
  16. */
  17. if (__va(bank->start) < vmalloc_min &&
  18. bank->size > vmalloc_min – __va(bank->start)) {
  19. if (meminfo.nr_banks >= NR_BANKS) {
  20. printk(KERN_CRIT “NR_BANKS too low, “
  21. “ignoring high memory\n”);
  22. } else {
  23. memmove(bank + 1, bank,
  24. (meminfo.nr_banks – i) * sizeof(*bank));
  25. meminfo.nr_banks++;
  26. i++;
  27. bank[1].size -= vmalloc_min – __va(bank->start);
  28. bank[1].start = __pa(vmalloc_min – 1) + 1;
  29. bank[1].highmem = highmem = 1;
  30. j++;
  31. }
  32. bank->size = vmalloc_min – __va(bank->start);
  33. }
  34. #else
  35. bank->highmem = highmem;
  36. /*
  37. * Check whether this memory bank would entirely overlap
  38. * the vmalloc area.
  39. */
  40. if (__va(bank->start) >= vmalloc_min ||
  41. __va(bank->start) < (void *)PAGE_OFFSET) {
  42. printk(KERN_NOTICE “Ignoring RAM at %.8llx-%.8llx “
  43. “(vmalloc region overlap).\n”,
  44. (unsigned long long)bank->start,
  45. (unsigned long long)bank->start + bank->size – 1);
  46. continue;
  47. }
  48. /*
  49. * Check whether this memory bank would partially overlap
  50. * the vmalloc area.
  51. */
  52. if (__va(bank->start + bank->size) > vmalloc_min ||
  53. __va(bank->start + bank->size) < __va(bank->start)) {
  54. unsigned long newsize = vmalloc_min – __va(bank->start);
  55. printk(KERN_NOTICE “Truncating RAM at %.8llx-%.8llx “
  56. “to -%.8llx (vmalloc region overlap).\n”,
  57. (unsigned long long)bank->start,
  58. (unsigned long long)bank->start + bank->size – 1,
  59. (unsigned long long)bank->start + newsize – 1);
  60. bank->size = newsize;
  61. }
  62. #endif
  63. if (!bank->highmem && bank->start + bank->size > lowmem_limit)
  64. lowmem_limit = bank->start + bank->size;
  65. j++;
  66. }
  67. #ifdef CONFIG_HIGHMEM
  68. if (highmem) {
  69. const char *reason = NULL;
  70. if (cache_is_vipt_aliasing()) {
  71. /*
  72. * Interactions between kmap and other mappings
  73. * make highmem support with aliasing VIPT caches
  74. * rather difficult.
  75. */
  76. reason = “with VIPT aliasing cache”;
  77. }
  78. if (reason) {
  79. printk(KERN_CRIT “HIGHMEM is not supported %s, ignoring high memory\n”,
  80. reason);
  81. while (j > 0 && meminfo.bank[j – 1].highmem)
  82. j–;
  83. }
  84. }
  85. #endif
  86. meminfo.nr_banks = j;
  87. memblock_set_current_limit(lowmem_limit);
  88. }
(3)最终有必要做的便是排序了,完结了这个作业就能够彻底被咱们上面说到的find_limits函数运用了,而这个作业就放在了接下来的arm_memblock_init(&meminfo, mdesc);中的一最初:
  1. static int __init meminfo_cmp(const void *_a, const void *_b)
  2. {
  3. const struct membank *a = _a, *b = _b;
  4. long cmp = bank_pfn_start(a) – bank_pfn_start(b);
  5. return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
  6. }
  7. void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
  8. {
  9. int i;
  10. sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
  11. memblock_init();
  12. for (i = 0; i < mi->nr_banks; i++)
  13. memblock_add(mi->bank[i].start, mi->bank[i].size);
  14. /* Register the kernel text, kernel data and initrd with memblock. */
  15. #ifdef CONFIG_XIP_KERNEL
  16. memblock_reserve(__pa(_sdata), _end – _sdata);
  17. #else
  18. memblock_reserve(__pa(_stext), _end – _stext);
  19. #endif
  20. #ifdef CONFIG_BLK_DEV_INITRD
  21. if (phys_initrd_size &&
  22. !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
  23. pr_err(“INITRD: 0xlx+0xlx is not a memory region – disabling initrd\n”,
  24. phys_initrd_start, phys_initrd_size);
  25. phys_initrd_start = phys_initrd_size = 0;
  26. }
  27. if (phys_initrd_size &&
  28. memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
  29. pr_err(“INITRD: 0xlx+0xlx overlaps in-use memory region – disabling initrd\n”,
  30. phys_initrd_start, phys_initrd_size);
  31. phys_initrd_start = phys_initrd_size = 0;
  32. }
  33. if (phys_initrd_size) {
  34. memblock_reserve(phys_initrd_start, phys_initrd_size);
  35. /* Now convert initrd to virtual addresses */
  36. initrd_start = __phys_to_virt(phys_initrd_start);
  37. initrd_end = initrd_start + phys_initrd_size;
  38. }
  39. #endif
  40. arm_mm_memblock_reserve();
  41. arm_dt_memblock_reserve();
  42. /* reserve any platform specific memblock areas */
  43. if (mdesc->reserve)
  44. mdesc->reserve();
  45. memblock_analyze();
  46. memblock_dump_all();
  47. }
经过上面的剖析,整个高低端内存是怎么确认的基本就明晰了,这儿总结一下:
ARM构架中,高-低段内存是内核经过内核发动参数(mem=size@start和vmalloc=size)来主动装备的,假如没有特别去装备他,那么在一般的ARM体系中是不会有高端内存存在的。除非你体系的RAM很大或vmalloc装备得很大,就很或许呈现高端内存。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/kaiguan/262686.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部