目录
物理内存数据结构
设备数物理内存描述
物理内存映射
map_kernel
map_mem
zone数据结构
zone类型
物理内存数据结构
- 站在处理器角度,管理物理内存的最小单位是页面。使用page数据结构描述,通常默认大小4kB,采用mem_map[]数组来存放这些page数据结构,数组与物理内存由一一对应关系。
设备数物理内存描述
- 在设备树dts中,定义内存的起始地址,大小 如VExpress平台 ;qemu虚拟机内存的描述在 hw/arm/virt.c文件中
memory@60000000{ device_type = "memory"; reg = <0x60000000 0x40000000>; }
dts文件的解析 start_kernel->setup_arch->setup_machine_fdt->early_init_dt_scan_nodes->early_init_dt_scan_memory
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
int in_use = 0;
low_mem_sz = size;
in_use = 1;
memblock_add_node(base, size, 0, MEMBLOCK_NONE);
}
memblock_add_node添加到memblock子系统中
物理内存映射
在内核使用之前,需要初始化内核页表,paging_init 函数完成,主要做两次映射,map_kernel与map_mem
void __init paging_init(void)
{
pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
map_kernel(pgdp);
map_mem(pgdp);
}
都是建立物理地址到内核虚拟地址的线性映射,但映射的地址不一样
map_kernel
- map_kernel映射内核镜像到内核空间的虚拟地址 该函数对内核映像的各个段分别进行映射,映射的内核空间虚拟地址为vmalloc区域; vmalloc区域的范围从0xFFFF 0000 1000 0000 到 0xFFFF 7DFF BFFF 0000
- 代码段:从_text到_etext
- 只读数据段:从__start_rodata到__inittext_begin;
- 初始化代码段:
- 初始化数据段:
- 数据段:从_data到_end
map_mem
- map_mem做物理内存的线性映射。 映射三段物理内存到线性映射区。线性映射区的范围从0xFFFF 8000 0000 0000 到0xFFFF FFFF FFFF FFFF,大小为128TB 为什么把第三段物理内存单独拿出来映射? 这三段物理内存都会被映射到 不可执行 的属性,但是后续代码里把第三段映射的属性设置成 只读 ,防止后续的其他内核模块不经意地修改了代码,如CPU休眠机制。另外,第一段和第二段映射启用了连续页表属性(PTE_CONT),单独把第三段映射拎出来可以避免连续页表特性映像第三段的映射。
对页表的初始化完成后,内核可以对内存进行管理,内核采样zone管理区来管理。
zone数据结构
struct zone {
/* Read-mostly fields */
/* zone watermarks, access with *_wmark_pages(zone) macros */
unsigned long _watermark[NR_WMARK];//每个zone在系统启动时会计算出3个水位,最低警戒水位,低水位和高水位,在页面分配器和kswapd页面回收中用到
unsigned long watermark_boost;
unsigned long nr_reserved_highatomic;
long lowmem_reserve[MAX_NR_ZONES];//防止页面分配器过度使用低端zone的内存
#ifdef CONFIG_NUMA
int node;
#endif
struct pglist_data *zone_pgdat;//指向内存节点
struct per_cpu_pages __percpu *per_cpu_pageset;
struct per_cpu_zonestat __percpu *per_cpu_zonestats;
int pageset_high_min;
int pageset_high_max;
int pageset_batch;
#ifndef CONFIG_SPARSEMEM
/*
* Flags for a pageblock_nr_pages block. See pageblock-flags.h.
* In SPARSEMEM, this map is stored in struct mem_section
*/
unsigned long *pageblock_flags;
#endif /* CONFIG_SPARSEMEM */
/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT*/
unsigned long zone_start_pfn;//起始页帧号
atomic_long_t managed_pages;//被伙伴系统管理的页面数量
unsigned long spanned_pages;//zone包含的页面数量
unsigned long present_pages;//实际管理的页面数量
#if defined(CONFIG_MEMORY_HOTPLUG)
unsigned long present_early_pages;
#endif
#ifdef CONFIG_CMA
unsigned long cma_pages;
#endif
const char *name;
...
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
atomic_long_t vm_numa_event[NR_VM_NUMA_EVENT_ITEMS];
} ____cacheline_internodealigned_in_smp;
- zone经常被访问到,因此数据结构使用L1高速缓存对齐;CACHELINE_PADDING 为了性能,填充对齐空间
zone类型
内核的zone分为ZONEDMA、ZONEDMA32、ZONENORMAL和 ZONEHIGHMEM