分类: 嵌入式
2012-08-12 16:46:46
点击(此处)折叠或打开
2个 bank ,物理内存不连续,0x70000000 512M, 0xB0000000 512M
(early_param("mem", early_mem);)
如果想保留u-boot所占内存,可使用如下boot parameter,
,
注意这会覆盖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