| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> linux-4.19 内存 -> 正文阅读 |
|
[系统运维]linux-4.19 内存 |
目录 加载解析fdt 存储信息start_kernel()-》setup_arch()-》setup_machine_fdt()-》 early_init_dt_scan_memory() 通过fdt 获取存储信息,base_address和size,再通过early_init_dt_add_memory_arch(base, size);?加入memblock 子系统。 kaslr和页表映射kernel-4.19/arch/arm64/mm/init.c 659#define MLK(b, t) b, t, ((t) - (b)) >> 10 kernel-4.19/arch/arm64/include/asm/pgtable.h 这里VMALLOC_START 跟 KIMAGE_VADDR 一样 kernel-4.19/arch/arm64/kernel/head.S map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14 map_memory 是将虚拟地址x5 ,长度x6 映射到物理地址x3 开始的位置;其中x0 页表地址,x1 第一个页表项,通常x1=x0+PAGE_SIZE;x4 表示对应页表等级由多少项。这里是将内核代码段.text 从虚拟地址KIMAGE_VADDR + TEXT_OFFSET+KASLR 偏移? 对应虚拟地址映射到物理地址_text 对应连续物理地址。 vmlinux 对应的是编译链接地址;coredump 及内核堆栈对应的是运行时地址; 支持kaslr之前,kernel加载到system RAM的某个位置,它之前的内存kernel是无法管理的,所以一般将kernel加载到system RAM的 起始位置+TEXT_OFFSET(0x080000)处,因为kaslr修改成可以随意加载到system RAM的任何位置,只要满足对齐要求就可以; 这样.text? 其实位置跟 VMALLOC区其实地址有一个偏移 add_link?= addr_run - (VAMLLOC_START - .text_start) +?TEXT_OFFSET? ???? add_link? 是addr2line 使用,addr_run 是虚拟地址,运行时堆栈地址。 .text_start 是load物理地址??? MTK 平台: static inline void show_kaslr(void) 55{ 56 u64 const kaslr_offset = aee_get_kimage_vaddr() - KIMAGE_VADDR; 57 58 pr_notice("Kernel Offset: 0x%llx from 0x%lx\n", 59 kaslr_offset, KIMAGE_VADDR); 60 pr_notice("PHYS_OFFSET: 0x%llx\n", PHYS_OFFSET); 61 aee_rr_rec_kaslr_offset(kaslr_offset); 62} aee_get_kimage_vaddr? 从coredump 里面读取kimage_vaddr 对应地址 9#if defined(KIMAGE_VADDR)
35#define PCI_IO_SIZE?? ??? ?SZ_16M 内核虚拟地址起点:VA_START = 0xffff_0000_0000_0000 PAGE_OFFSET? =0xffff_1000_0000_0000 ?PAGE_OFFSET - the virtual address of the start of the linear map (top(VA_BITS - 1)) KIMAGE_VADDR - the virtual address of the start of the kernel image 这里MODULES_VSIZE = 128M = 0x8000000 ?kernel-4.19/arch/arm64/Makefile 这里CONFIG_ARM64_PAGE_SHIFT 页大小 12 位 User space 地址mmu转换示例: task_struct->mm 如果是内核线程,为空(内核线程没有进程地址空间)。 task_struct->active_mm 如果是内核线程,指向被借用的用户进程的地址空间(mm)。 user space各个process 保存自己独立的pgd,存放在task__struct->mm->pgd里面,每次做context ?switch时,会把next_task的pgd存放到TTBR0_EL0里面,从而实现不同process不同的地址空间。 TTBR0_EL1 对应内核pgd cr3寄存器的加载 cr3寄存器的加载是在进程调度的时候更新的,具体如下 schedule()->context_switch()->switch_mm()->load_cr3(next->pgd) load_cr3加载的是mm_struct->pgd,即线性地址,而实际上加裁到cr3寄存器的是实际的物理地址write_cr3(__pa(pgdir));在装载cr3寄存器时将线性地址通过__pa转换成了物理地址了,所以cr3寄存器是装的是实实在在的物理地址。正在使用的页目录的物理地址存在cr3控制寄存器中 假设页表映射层级是4,即配置CONFIG_ARM64_PGTABLE_LEVELS=4。地址宽度是48,即配置CONFIG_ARM64_VA_BITS=48,页大小4K,每个页表项占 8字节 PGD? [47,39]? ? ? ? ? 512*512G=256T PUD? [38,30]? ? ? ? ? 512G PMD [29,21]? ? ? ? ? 512*2M = 1G PTE? [20,12]? ? ? ? ? 4K/8=512 项,512*4K = 2M PAGE_SHIFT? ?[11~0] kernel-4.19/arch/arm64/include/asm/pgtable-hwdef.h */ 16#ifndef __ASM_PGTABLE_HWDEF_H 17#define __ASM_PGTABLE_HWDEF_H 18 19#include <asm/memory.h> 20 21/* 22 * Number of page-table levels required to address 'va_bits' wide 23 * address, without section mapping. We resolve the top (va_bits - PAGE_SHIFT) 24 * bits with (PAGE_SHIFT - 3) bits at each page table level. Hence: 25 * 26 * levels = DIV_ROUND_UP((va_bits - PAGE_SHIFT), (PAGE_SHIFT - 3)) 27 * 28 * where DIV_ROUND_UP(n, d) => (((n) + (d) - 1) / (d)) 29 * 30 * We cannot include linux/kernel.h which defines DIV_ROUND_UP here 31 * due to build issues. So we open code DIV_ROUND_UP here: 32 * 33 * ((((va_bits) - PAGE_SHIFT) + (PAGE_SHIFT - 3) - 1) / (PAGE_SHIFT - 3)) 34 * 35 * which gets simplified as : 36 */ 37#define ARM64_HW_PGTABLE_LEVELS(va_bits) (((va_bits) - 4) / (PAGE_SHIFT - 3)) 38 39/* 40 * Size mapped by an entry at level n ( 0 <= n <= 3) 41 * We map (PAGE_SHIFT - 3) at all translation levels and PAGE_SHIFT bits 42 * in the final page. The maximum number of translation levels supported by 43 * the architecture is 4. Hence, starting at at level n, we have further 44 * ((4 - n) - 1) levels of translation excluding the offset within the page. 45 * So, the total number of bits mapped by an entry at level n is : 46 * 47 * ((4 - n) - 1) * (PAGE_SHIFT - 3) + PAGE_SHIFT 48 * 49 * Rearranging it a bit we get : 50 * (4 - n) * (PAGE_SHIFT - 3) + 3 51 */ 52#define ARM64_HW_PGTABLE_LEVEL_SHIFT(n) ((PAGE_SHIFT - 3) * (4 - (n)) + 3) 53 54#define PTRS_PER_PTE (1 << (PAGE_SHIFT - 3)) 55 56/* 57 * PMD_SHIFT determines the size a level 2 page table entry can map. 58 */ 59#if CONFIG_PGTABLE_LEVELS > 2 60#define PMD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(2) 61#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT) 62#define PMD_MASK (~(PMD_SIZE-1)) 63#define PTRS_PER_PMD PTRS_PER_PTE 64#endif 65 66/* 67 * PUD_SHIFT determines the size a level 1 page table entry can map. 68 */ 69#if CONFIG_PGTABLE_LEVELS > 3 70#define PUD_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(1) 71#define PUD_SIZE (_AC(1, UL) << PUD_SHIFT) 72#define PUD_MASK (~(PUD_SIZE-1)) 73#define PTRS_PER_PUD PTRS_PER_PTE 74#endif 75 76/* 77 * PGDIR_SHIFT determines the size a top-level page table entry can map 78 * (depending on the configuration, this level can be 0, 1 or 2). 79 */ 80#define PGDIR_SHIFT ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - CONFIG_PGTABLE_LEVELS) 81#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) 82#define PGDIR_MASK (~(PGDIR_SIZE-1)) 83#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT)) 84 85/* 86 * Section address mask and size definitions. 87 */ 88#define SECTION_SHIFT PMD_SHIFT 89#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) 90#define SECTION_MASK (~(SECTION_SIZE-1)) ?当配置CONFIG_PGTABLE_LEVELS为4 ,则为4级页表 PGDIR_SHIFT = ARM64_HW_PGTABLE_LEVEL_SHIFT(0)? ?= 39 ,表示VA 中除了本级页表地址,还有39 位表示其它级地址 ?PTRS_PER_PGD? = (1 << (VA_BITS - PGDIR_SHIFT))? = 1<<9? 虚拟地址到物理地址转换virt_to_phys和phys_to_virt 内核虚拟地址起点:VA_START = 0xffff_0000_0000_0000 PAGE_OFFSET? =0xffff_1000_0000_0000 ?PAGE_OFFSET - the virtual address of the start of the linear map (top(VA_BITS - 1)) 对于48位虚拟地址,从PAGE_OFFSET 开始的往大地址的区域是线性区域,跟物理地址就是一个PHYS_OFFSET 偏差;如果不是线性区域,这个时候是?kimage_voffset? 偏移;
kimage_voffset 的获取:
__primary_switch 这里获取的是MMU 没有打开时的_text 链接的地址(相对VMALLOC有一个偏移),加载地址跟链接地址一样; __primary_switched? x4 获取是运行时_text 运行虚拟地址,这个时候运行地址跟加载地址不一样,从而x4-x0 就是运行虚拟地址跟加载地址的一个偏移存入kimage_voffset。 ?参考 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 11:59:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |