linux内核中为什么kzalloc申请3m的内存可以的

2025-04-25 23:24:17
推荐回答(1个)
回答1:

内核地址空间
Linux内核地址空间布局如下(arm):

用户空间和内核空间一般按3:1的比例划分,内核空间中物理内存都将被映射到0xc0000000到0xffffffff的地址空间中。在arm处理器上这种划分稍有不同,模块加载空间和持久映射区都在0xc0000000之下。下面对上图中宏做一说明:
模块加载区总共有14M,PAGE_OFFSET即为0xc0000000。
arch/arm/include/asm/memory.h
#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024)
#define MODULES_END (PAGE_OFFSET - PMD_SIZE)
如果页表分为两级,它的第一级一个地址条目表示2M空间,持久映射区就留取一个一级页表所表示的空间。
arch/arm/include/asm/pgtable-2level.h
#define PMD_SHIFT 21
#define PMD_SIZE (1UL << PMD_SHIFT)
arch/arm/include/asm/highmem.h
#define PKMAP_BASE (PAGE_OFFSET - PMD_SIZE)
VMALLOC区用于非一致内存分配,这个区域的起始地址由high_memory来决定,而high_memory是高端内存的起始地址,在运行中计算得到,但是这个区域肯定不小于240M,因为高端内存区域的起始地址小于vmalloc_min。
arch/arm/mm/mmu.c
static void * __initdata vmalloc_min =
(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
VMALLOC_OFFSET是一个安全区域,防止地址越界。
arch/arm/include/asm/pgtable.h
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_END 0xff000000UL
下面为临时映射区域
arch/arm/include/asm/fixmap.h
#define FIXADDR_START 0xfff00000UL
#define FIXADDR_TOP 0xfffe0000UL
从0xffff0000到4G空间用于异常向量表。
Linux所有内核线程的地址空间都是基于相同的映射,所以linux所有内核线程公用相同的地址空间。进程地址空间是用结构struct mm_struct来管理的。所有内核线程也公用一个struct mm_struct结构。
mm/init-mm.c
struct mm_struct init_mm = {
.mm_rb = RB_ROOT,
.pgd = swapper_pg_dir,
.mm_users = ATOMIC_INIT(2),
.mm_count = ATOMIC_INIT(1),
.mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem),
.page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
.mmlist = LIST_HEAD_INIT(init_mm.mmlist),
INIT_MM_CONTEXT(init_mm)
};
全局变量swapper_pg_dir指向内核页表的起始地址,在文件arch/arm/kernel/head.S中定义如下:
.globl swapper_pg_dir 定义全局变量
.equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE 为全局变量赋值
宏KERNEL_RAM_VADDR为0xc0000000+0x8000,PG_DIR_SIZE为0x4000,所以swapper_pg_dir指向地址0xc0004000。