uclinux-2008r1(bf561)内核中与存储管理相关的几个全局变量

本文详细介绍了在BF561 DSP上uCLinux内核的内存管理机制,包括关键内存区域变量的定义和初始化过程,以及这些变量如何帮助内核理解并管理系统的物理内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
快乐虾
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)) {
….
从而将这个值更改。
这两个全局变量几乎都是同时使用的,它们的定义在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。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值