rev 0.1
快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
ADI bf561 DSP
uclinux-2008r1.5-rc3(smp patch)
Visual DSP++ 5.0(update 5)
欢迎转载,但请保留作者信息
出现一个问题,在运行到memmap_init_zone函数时,内核跑飞了。跟踪下代码:
/*
* Initially all pages are reserved - free ones are freed
* up by free_all_bootmem() once the early boot process is
* done. Non-atomic initialization, single-pass.
*/
void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
unsigned long start_pfn, enum memmap_context context)
{
struct page *page;
unsigned long end_pfn = start_pfn + size;
unsigned long pfn;
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
/*
* There can be holes in boot-time mem_map[]s
* handed to this function. They do not
* exist on hotplugged memory.
*/
if (context == MEMMAP_EARLY) {
if (!early_pfn_valid(pfn))
continue;
if (!early_pfn_in_nid(pfn, nid))
continue;
}
page = pfn_to_page(pfn);
set_page_links(page, zone, nid, pfn);
init_page_count(page);
reset_page_mapcount(page);
SetPageReserved(page);
INIT_LIST_HEAD(&page->lru);
#ifdef WANT_PAGE_VIRTUAL
/* The shift won't overflow because ZONE_NORMAL is below 4G. */
if (!is_highmem_idx(zone))
set_page_address(page, __va(pfn << PAGE_SHIFT));
#endif
}
}
发现下面这几行代码没有生成相应的汇编代码:
if (context == MEMMAP_EARLY) {
if (!early_pfn_valid(pfn))
continue;
if (!early_pfn_in_nid(pfn, nid))
continue;
}
于是想是不是编译器出毛病了。但仔细查了下,发现两个定义:
#ifndef early_pfn_valid
#define early_pfn_valid(pfn) (1)
#endif
#ifdef CONFIG_NODES_SPAN_OTHER_NODES
#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid))
#else
#define early_pfn_in_nid(pfn, nid) (1)
#endif
原来这两个宏都返回常量1,编译器直接把这几行代码给优化掉了。
再设条件断点,发现这个循环在执行2378之后就挂了。因为这一段代码修改的变量只有page结构体,开始怀疑是page指针的问题,看一下page指针的值:0x00012940,落在.text这个段内,相当于改变了程序代码,想不出错都不行!
page指针来源于这一行:
page = pfn_to_page(pfn);
pfn_to_page这个宏接受一个page序号做为参数,并取得这个序号所代表的page结构体指针。这个转换需要用到一个叫mem_map的全局变量。
在内核中每个4K的页都有一个struct page与之相对应,而mem_map就是指向这个page数组的头指针。
查一下mem_map的值,为0!也就是说,mem_map没有初始化!难怪出错!
mem_map初始化的地方在这里:
static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
{
/* Skip empty nodes */
if (!pgdat->node_spanned_pages)
return;
#ifdef CONFIG_FLAT_NODE_MEM_MAP
/* ia64 gets its own node_mem_map, before this, without bootmem */
if (!pgdat->node_mem_map) {
unsigned long size, start, end;
struct page *map;
/*
* The zone's endpoints aren't required to be MAX_ORDER
* aligned but the node_mem_map endpoints must be in order
* for the buddy allocator to function correctly.
*/
start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
end = pgdat->node_start_pfn + pgdat->node_spanned_pages;
end = ALIGN(end, MAX_ORDER_NR_PAGES);
size = (end - start) * sizeof(struct page);
map = alloc_remap(pgdat->node_id, size);
if (!map)
map = alloc_bootmem_node(pgdat, size);
pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
/*
* With no DISCONTIG, the global mem_map is just set as node 0's
*/
if (pgdat == NODE_DATA(0)) {
mem_map = NODE_DATA(0)->node_mem_map;
#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
mem_map -= pgdat->node_start_pfn;
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
}
#endif
#endif /* CONFIG_FLAT_NODE_MEM_MAP */
}
当没有定义CONFIG_FLAT_NODE_MEM_MAP的时候,mem_map的确是不会初始化的!
知道问题的所在,解决就很简单了,直接在config.h加上这个宏定义即可。
uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(50):.spinlock.text(2009-1-24)
uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(51):CONFIG_LOG_BUF_SHIFT(2009-1-24)
uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(52):__ebss_l1(2009-1-28)
uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(53):ARRAY_SIZE(2009-1-30)
uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(54):MEM_SDRAM_BANKx(2009-2-1)