微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux内核高-低端内存设置代码跟踪(ARM构架)

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

时间:11-21 来源:互联网 点击:
对于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 memory-free_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_low-PHYS_PFN_OFFSET;
  32. max_pfn=max_high-PHYS_PFN_OFFSET;
  33. }

这个high_memory=__va(((phys_addr_t)max_lowPAGE_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_highend)
  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内核的启动流程,以后我也会写下)中有这样一个函数:

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top