Chinaunix首页 | 论坛 | 博客
  • 博客访问: 266552
  • 博文数量: 53
  • 博客积分: 1910
  • 博客等级: 中尉
  • 技术积分: 1130
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-10 14:56
文章分类

全部博文(53)

文章存档

2013年(1)

2012年(17)

2011年(33)

2010年(2)

分类: 嵌入式

2012-08-12 16:46:46

  找framebuffer 物理内存的位置,把1G physical memory layout 整理了下,顺便复习下bootmem.
 
1. In u-boot:

点击(此处)折叠或打开

  1. #define CSD0_BASE_ADDR 0x70000000
  2. #define CSD1_BASE_ADDR 0xB0000000

  3. #define CONFIG_NR_DRAM_BANKS 2
  4. #define PHYS_SDRAM_1 CSD0_BASE_ADDR
  5. #define PHYS_SDRAM_1_SIZE (512 * 1024 * 1024)
  6. #define PHYS_SDRAM_2 CSD1_BASE_ADDR
  7. #define PHYS_SDRAM_2_SIZE (512 * 1024 * 1024)

  8. int dram_init(void)
  9. {
  10.  gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
  11.  gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
  12.  gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
  13.  gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
  14.  return 0;
  15. }

  16. static void setup_memory_tags (bd_t *bd)
  17. {
  18.  int i;

  19.  for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
  20.   params->hdr.tag = ATAG_MEM;
  21.   params->hdr.size = tag_size (tag_mem32);

  22.   params->u.mem.start = bd->bi_dram[i].start;
  23.   params->u.mem.size = bd->bi_dram[i].size;

  24.   params = tag_next (params);
  25.  }
  26. }

2个 bank ,物理内存不连续,0x70000000 512M, 0xB0000000 512M

(early_param("mem", early_mem);)
如果想保留u-boot所占内存,可使用如下boot parameter,
mem=size@start,
注意这会覆盖uboot ATAG_MEM flag ,和 kernel fixup 对内存的改动
所以可在fixup 中修改保留u-boot 所占内存


2.  In kernel:

boot parameters:

video=mxcdi1fb:RGB666,XGA ldb=di1 di1_primary pmem=32M,64M fbmem=5M gpu_memory=64
   
  fixup 在 parse_tags 前执行,修改ATAG_MEM tags 来保留物理内存:
 
  start_kernel()

    ->setup_arch()

        ->mdesc->fixup()

        ->parse_tags()

        ->parse_early_param()

        ->paging_init(mdesc);
  
           ->bootmem_init();

           ->devicemaps_init(mdesc);

经过fixup (fixup_android_board),实际可用物理内存如下:

bank0                          bank1
start address:
|0x70000000                    0xB0000000   
------------------------       ---------------------------------------------
|       512M           |  hole |    321M     | *1 | *2 | *3 | *4 | *5 | *6 |
------------------------       ---------------------------------------------
|pfn 物理页帧号:                            |
|start:                                      | end:
|0x70000                                     | 0xC4100  (0x54100 pages ,include hole)
| bank0 ,128K page(4K)

 /* 0x70000000, 0xC4100000 (0x70000, 0xC4100)*/

*1 gpu_device (reserve memory for gpu)
    start 321M , size 64M

*2 android_pmem_gpu_data
    start 321M+ 64M ,size 32M

*3 android_pmem_data
     start 321+64+32M =417M ,size 64M

*4 fb_mem
     start 417+64M ,size 13M

*5 fb_mem => reserve_2ndisp 因为di1_primary
     start 481+13M  ,size 13M

*6 fb0_mem
     start 507M ,size =5M

(上图未验证,看代码计算的)

 

paging_init ->bootmem_init
->
bootmem_init_node :
    -> #define NODE_DATA(nid)  (&contig_node_data)
 包含下面2个结构:
   1.  struct bootmem_data *bdata;
             bdata 结构的 成员 void *node_bootmem_map; 就是bootmem_map
      是1个bitmap ,每bit 表示物理内存使用的情况

          2. struct page *node_mem_map; 着个就是包含page entry(32bytes) 的结构pointer

    -> init_bootmem_node 找到kernel image _end 后的first page 做 bootmem_map 的起始页
    -> free_bootmem_node  对每个bank执行1次,现在为2次 mark_bootmem_node
       bootmem_map 的size 包含hole 部分, init_bootmem_node 中将no hole ,hole 都设置成reserve
       现在根据实际bank,将非hole 部分mark为free
    -> reserve_bootmem_node 将bootmem_node 所占page 设置为reserve

->reserve_node_zero 在bitmap中将kernel与主内核页表所占用的页框标识为已分配


   这时在第1个bank上物理内存分布大致如下,


   parameter list已不再占用内存,因为此前对它的引用已经完成。
   主内核页表的一级页表占用0x70004000~0x70008000。
   kernel占用_stext ~_end,这两个符号定义在vmlinux.lds.S中。
   initrd占用phys_initrd_start~phys_initrd_size,这两个变量的值由parameter list得到。
   bitmap占用紧随在符号_end之后的若干页框。 


->bootmem_free_node (for each node)  初始化页框分配器
  zhole_size 的计算方法考虑2个以上bank情况, 用包括hole的size 去掉两个bank的size,单位为page
  这里0xC4100-0x70000-0x20000(512M)-0x14100(321M) = 0xb0000 -0x90000
  512M hole,

  ->free_area_init_node(node, zone_size, start_pfn, zhole_size);
      free_area => buddy system的核心数据结构
     ->calculate_node_totalpages(struct pglist_data *pgdat,
  unsigned long *zones_size, unsigned long *zholes_size)
        这个函数可以计算出pglist_data的
      node_spanned_pages 包含hole pages
      node_present_pages 不包含hole pages
     ->alloc_node_mem_map(pgdat);     分配mem_map addr
       0x54100 pages,大概10M 空间

     ->free_area_init_core
        ->
          注意hole 部分的处理
          zone->spanned_pages = size;       /* total size, including holes */
          zone->present_pages = realsize;  /* amount of memory (excluding holes and mem_map use pages and dma pages ) */
        -> memmap_init =>
      void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
  unsigned long start_pfn, enum memmap_context context)
  SetPageReserved
      包括hole 部分,全部设置为reserve flag to struct page.

      后续到mm_init 继续,
      static void __init mm_init(void) {
      /*
       * page_cgroup requires countinous pages as memmap
       * and it's bigger than MAX_ORDER unless SPARSEMEM.
       */
          page_cgroup_init_flatmem();
          mem_init();
          kmem_cache_init();
          pgtable_cache_init();
          vmalloc_init();
      }
  


paging_init ->devicemaps_init(mdesc);
   -> Allocate the vector page early. 分配向量内存,并map到vaddr 0xffff0000
   -> mdesc->map_io => mx5_map_io
                    map mx5_io_desc!!!

arch\arm\mach-mx5\mm.c: (可以添加其他io map)
static struct map_desc mx5_io_desc[] __initdata = {
 {
  .virtual = AIPS1_BASE_ADDR_VIRT,
  .pfn = __phys_to_pfn(AIPS1_BASE_ADDR),
  .length = AIPS1_SIZE,
  .type = MT_DEVICE},
 {
  .virtual = SPBA0_BASE_ADDR_VIRT,
  .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
  .length = SPBA0_SIZE,
  .type = MT_DEVICE},
 {
  .virtual = AIPS2_BASE_ADDR_VIRT,
  .pfn = __phys_to_pfn(AIPS2_BASE_ADDR),
  .length = AIPS2_SIZE,
  .type = MT_DEVICE},
};

除了boot paramater, fixup,保留物理内存的办法还可以使用bootmem 的函数

分配位置可以放到.mapio 函数中在map io 前使用bootmem  的函数,进行physical mem的保留

主要函数如下:

1.
/**
 * reserve_bootmem - mark a page range as usable
 * @addr: starting address of the range
 * @size: size of the range in bytes
 * @flags: reservation flags (see linux/bootmem.h)
 *
 * Partial pages will be reserved.
 *
 * The range must be contiguous but may span node boundaries.
 */
int __init reserve_bootmem(unsigned long addr, unsigned long size,
       int flags)

2.

或者 page aligned 使用宏:
alloc_bootmem_pages(x)

3.

不需要对齐,使用:
alloc_bootmem(x)

x表示size

 
阅读(2042) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册