1. #define VA_BITS (CONFIG_ARM64_VA_BITS)
虚拟地址宽度,最大值为48,比如配置为39,用户地址0- 0x0000007f_ffffffffff
内核空间地址为0xffffff80_00000000-0xfffffffff_fffffffff,分别为256G
#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
内核虚拟地址起始地址:0xffffff80_00000000
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
PHYS_OFFSET Physical start address of the first bank of RAM. PAGE_OFFSET Virtual start address of the first bank of RAM. During the kernel boot phase, virtual address PAGE_OFFSET will be mapped to physical address PHYS_OFFSET, along with any other mappings you supply. This should be the same value as TASK_SIZE.
2.
#define MODULES_END (PAGE_OFFSET)
#define MODULES_VADDR (MODULES_END - SZ_64M)
模块虚拟地址
//struct page 数组的大小
#define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
vmalloc 分配的起始地址
#define VMALLOC_START (KASAN_SHADOW_END + SZ_64K)
vmalloc分配结束地址
#define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
struct page数起始地址
#define VMEMMAP_START (VMALLOC_END + SZ_64K)
3.
memstart_addr为DDR的起始物理地址(base),vmemmap为什么减去起始ddr的物理地址 ?
在计算一个page的pfn时,都是基于系统的物理0地址,所以预先减去base,在进行page和pfn转换时,就可以直接相加/相减
pfn_to_page(pfn) vmemmap + pfn ;如果不预先减去base,那么应该是vmemmap +(pfn- pfn_base)
#define vmemmap ((struct page *)VMEMMAP_START - \
SECTION_ALIGN_DOWN(memstart_addr >> PAGE_SHIFT))//__va
ARM64_HW_PGTABLE_LEVELS(va_bits):根据内核支持最大虚拟地址来确定页表级数
由于每级页表占用9bit,所以 (va_bits-PAGE_SHIFT)/(PAGE_SHIFT-3)
向上取整:((((va_bits) - PAGE_SHIFT) + (PAGE_SHIFT - 3) - 1) / (PAGE_SHIFT - 3))
最后简化:(((va_bits) - 4) / (PAGE_SHIFT - 3))
所以就有 #define ARM64_HW_PGTABLE_LEVELS(va_bits) (((va_bits) - 4) / (PAGE_SHIFT - 3))
ARM64_HW_PGTABLE_LEVEL_SHIFT(n) : 根据页表级n,计算出第n级页表bit偏移
#define PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) : PMD页表的偏移bit =21
#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT):一个PMD表项能标识的内存size = 2M
PGDIR_SIZE //一个PGD能表示的内存大小
PUD_SHIFT/PGDIR_SHIFT 类似PMD的理解.
pgd_offset_k(addr):根据虚拟地址addr获取对应的pgd项.
pmd_offset(addr): 根据虚拟地址addr,从pud中获取对应的pmd项
pmd_index(addr):根据虚拟地址addr,计算pmd的index
//把pud的物理地址设置到pgd项中.
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE));
}
//把pte的物理地址设置到pmd项中.
pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
从上面可以看出pgd,pmd,pte中保存的内容都是物理地址
PTRS_PER_PGD: PGD项个数
PTRS_PER_PTE: PTE项个数
PTRS_PER_PMD:PMD项个数,这是三个一般都是相等且为(1<<9)
如果level为3,则PUD=1
4.内存相关的debug目录
/proc/meminfo
/proc/pagetypeinfo
/proc/buddyinfo
/proc/slabinfo
/proc/vmstat
/proc/zoneinfo
/proc/vmallocinfo
/sys/kernel/slab
/sys/kernel/debug/extfrag
/sys/kernel/debug/memblock
/proc/sys/vm
5.早期分配内存接口
early_alloc
6.sparse 内存模型
#define SECTION_SIZE_BITS 30 //一个section的大小2的30次方=1G
#define PAGES_PER_SECTION (1UL << PFN_SECTION_SHIFT)//一个secion中的page数量
#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)//把pfn转换成section号
#define NR_MEM_SECTIONS (1UL << SECTIONS_SHIFT)//计算系统中section数量
7.分配内存的flags
/*
* Watermark modifiers -- controls access to emergency reserves
*
* __GFP_HIGH indicates that the caller is high-priority and that granting
* the request is necessary before the system can make forward progress.
* For example, creating an IO context to clean pages.
*
* __GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is
* high priority. Users are typically interrupt handlers. This may be
* used in conjunction with __GFP_HIGH
*
* __GFP_MEMALLOC allows access to all memory. This should only be used when
* the caller guarantees the allocation will allow more memory to be freed
* very shortly e.g. process exiting or swapping. Users either should
* be the MM or co-ordinating closely with the VM (e.g. swap over NFS).
*
* __GFP_NOMEMALLOC is used to explicitly forbid access to emergency reserves.
* This takes precedence over the __GFP_MEMALLOC flag if both are set.