快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
ADI bf561 DSP
uclinux-2008r1-rc8 (移植到vdsp5)
Visual DSP++ 5.0
欢迎转载,但请保留作者信息
这三个全局变量的定义在head.s文件中:
/*
* Set up the usable of RAM stuff. Size of RAM is determined then
* an initial stack set up at the end.
*/
.align 4
__rambase:
.long 0
__ramstart:
.long 0
__ramend:
.long 0
为了在C文件中使用它们,在include/asm/bfin-global.h中做了一个声明:
extern unsigned long _ramstart, _ramend, _rambase;
然后在setup_arch函数中对它们进行了初始化:
_ramend = CONFIG_MEM_SIZE * 1024 * 1024;
_ramstart = (unsigned long)__bss_stop;
_rambase = (unsigned long)_stext;
在这里__bss_stop是在ldf文件中定义:
bsz_sdram ZERO_INIT
{
…
INPUT_SECTION_ALIGN(4)
. = (. + 3) / 4 * 4;
___bss_stop = .;
__end = .;
} > MEM_SDRAM
而bsz_sdram是内核中的最后一个段,因此_ramstart将指向内核之后的第一个可用字节。
_stext也是在ldf文件中定义的一个变量:
.text
{
INPUT_SECTION_ALIGN(4)
. = (. + 3) / 4 * 4;
__text = .;
_text = .;
__stext = .;
…….
INPUT_SECTION_ALIGN(4)
. = (. + 3) / 4 * 4;
__etext = .;
} > MEM_SDRAM_TEXT
而.text是内核中排在最前面的一个段,因此_rambase将指向内核的起始位置。
在这里还需要注意_ramend的定义,虽然在这里给它赋了一个固定的值,但是通过引导程序设定启动参数可以进行更改,如引导程序使用
mem=32m
的时候,将会在parse_cmdline_early函数中触发下面的代码:
if (!memcmp(to, "mem=", 4)) {
to += 4;
memsize = memparse(to, &to);
if (memsize)
_ramend = memsize;
} else if (!memcmp(to, "max_mem=", 8)) {
….
从而将这个值更改。
1.1.2 memory_start和memory_end
这两个全局变量几乎都是同时使用的,它们的定义在arch/blackfin/kernel/setup.c中:
unsigned long memory_start, memory_end, physical_mem_end;
在setup_arch函数中对它们做了初始化工作:
memory_start = PAGE_ALIGN(_ramstart);
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
即memory_start指向内核结束的位置,但是向上做了页对齐(4K)。
/* by now the stack is part of the init task */
memory_end = _ramend - DMA_UNCACHED_REGION;
#if defined(CONFIG_DMA_UNCACHED_2M)
# define DMA_UNCACHED_REGION (2 * 1024 * 1024)
#elif defined(CONFIG_DMA_UNCACHED_1M)
# define DMA_UNCACHED_REGION (1024 * 1024)
#else
# define DMA_UNCACHED_REGION (0)
#endif
即memory_end指向可用物理内存的最高位置。
当没有启用MTD的时候,还有下面一段代码:
#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263)
/* Due to a Hardware Anomaly we need to limit the size of usable
* instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
* 05000263 - Hardware loop corrupted when taking an ICPLB exception
*/
#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
if (memory_end >= 56 * 1024 * 1024)
memory_end = 56 * 1024 * 1024;
#else
if (memory_end >= 60 * 1024 * 1024)
memory_end = 60 * 1024 * 1024;
#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263/n", memory_end >> 20);
#endif /* ANOMALY_05000263 */
此时,由于ANOMALY_05000263的缘故,memory_end将被限制为60M,即0x03c0 0000。
#if !defined(CONFIG_MTD_UCLINUX)
memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
#endif
由此,memory_end的值变为0x03bf f000。且不再改变。
当启用了MTD的时候,memory_end将指向物理内存减去RAMDISK大小的位置。
1.1.3 nr_kernel_pages与nr_all_pages
这两个值的定义都在mm/page_alloc.c中:
unsigned long __meminitdata nr_kernel_pages;
unsigned long __meminitdata nr_all_pages;
在free_area_init_core这个初始化函数中对它们赋初值:
static void __meminit free_area_init_core(struct pglist_data *pgdat,
unsigned long *zones_size, unsigned long *zholes_size)
{
…
for (j = 0; j < MAX_NR_ZONES; j++) {
struct zone *zone = pgdat->node_zones + j;
unsigned long size, realsize, memmap_pages;
// size = realsize = SDRAM的页表数量,对M SDRAM,其值为x3fff
size = zone_spanned_pages_in_node(nid, j, zones_size);
realsize = size - zone_absent_pages_in_node(nid, j,
zholes_size);
/*
* Adjust realsize so that it accounts for how much memory
* is used by this zone for memmap. This affects the watermark
* and per-cpu initialisations
*/
memmap_pages = (size * sizeof(struct page)) >> PAGE_SHIFT;
if (realsize >= memmap_pages) {
realsize -= memmap_pages;
printk(KERN_DEBUG
" %s zone: %lu pages used for memmap/n",
zone_names[j], memmap_pages);
} else
printk(KERN_WARNING
" %s zone: %lu pages exceeds realsize %lu/n",
zone_names[j], memmap_pages, realsize);
/* Account for reserved pages */
// dma_reserve的值可以从引导程序导入,在此为0
if (j == 0 && realsize > dma_reserve) {
realsize -= dma_reserve;
printk(KERN_DEBUG " %s zone: %lu pages reserved/n",
zone_names[0], dma_reserve);
}
// is_highmem_idx恒为
if (!is_highmem_idx(j))
nr_kernel_pages += realsize;
nr_all_pages += realsize;
….
}
}
从上述代码可以看出,这两个值都表示可用的页的数量,其表示的内存范围从0到60M,不包含page数组所占用的页。对于64MSDRAM(实际限制为60M),不启用MTD的情况,其值为0x3b6a。
1.1.4 mem_map
这个全局变量的定义在mm/nommu.c中:
struct page *mem_map;
在内核中每个4K的页都有一个struct page与之相对应,而mem_map就是指向这个page数组的头指针。
它的初始化由alloc_node_mem_map完成:
static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
{
…
/* 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);
}
/*
* 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;
}
}
从这个函数可以看出,它的值与pglist_data中的node_mem_map成员相同。
在这里pgdat指向全局唯一的pglist_data:
extern struct pglist_data contig_page_data;
pgdat->node_start_pfn的值为0。
pgdat->node_spanned_pages的值为整个SDRAM中的页(4K)数量。
1.1.5 contig_page_data
内核支持所谓的NUMA结构,它将整个系统的存储空间分成几个不连续的节点,每个节点用一个pglist_data进行描述,再将这些节点放在一个链表中,但在BF561系统内核中定义了一个叫NODE_DATA的宏,它的定义在include/linux/mmzone.h中
extern struct pglist_data contig_page_data;
#define NODE_DATA(nid) (&contig_page_data)
从这个定义可以看出,在内核中实际只有一个pglist_data。即contig_page_data。