AArch64执行状态提供了32个在任何时间任何特权级下都可访问的64位的通用寄存器。
每个寄存器都有64位宽,它们通常被称为寄存器X0-X30。
每个AArch64 64位通用寄存器(X0-X30)也具有32位(W0-W30)形式。
32位W寄存器取自相应的64位X寄存器的低32位。也就是说,W0映射到X0的低32位,W1映射到X1的低32位。
从W寄存器读取时,忽略相应X寄存器高32位,并保持其它不变。写入W寄存器时,将X寄存器的高32位设置为零。也就是说,将0xFFFFFFFF写入W0会将X0设置为0x00000000FFFFFFFF。
一、AArch64 特殊寄存器除了31个核心寄存器外,还有几个特殊的寄存器。
注意:没有被称为X31或W31的寄存器。许多指令被编码,例如:31代表零寄存器,ZR(WZR/XZR)。还有一组受限制的指令,其中对一个或多个参数进行编码,使数字31表示堆栈指针(SP)。
当访问零寄存器时,所有写操作都被忽略,所有读操作返回0。请注意,64位形式的SP寄存器不使用X前缀。
在ARMv8体系结构中,当CPU运行在AArch64状态时, ...
参考文档:Armv8-A Instruction Set Architecture.pdf
一、前言Armv8-A 中的指令集 Armv8-A 支持三种指令集:A32、T32 和 A64。
在AArch64执行状态下执行时使用A64指令集。它是一个固定长度的32位指令集。名称中的 “64”指的是 AArch64 执行状态对该指令的使用。它不是指内存中指令的大小。
A32 和 T32 指令集也分别称为“ARM”和“Thumb”。这些指令集在 AArch32 执行状态下执行时使用。在本指南中,我们不介绍 A32 和 T32 指令集。
每个版本的 Arm 架构都有自己的 Arm 架构参考手册(Arm ARM),可以在 Arm 开发者网站上找到。每个Arm ARM都提供了每条指令的详细说明,包括:
编码——指令在内存中的表示。
参数 - 指令的输入。
伪代码 - 指令的作用,以 Arm 伪代码语言表示。
限制 - 当指令不能使用时,或者它可以触发的异常。
A64 的指令描述也以 XML 和 HTML 形式提供。如果您需要经常参考说明,则 XML 和 HTML 格式
非常有用。 XM ...
01、认识一下Git!—简介Git是当前最先进、最主流的 分布式版本控制系统,免费、开源!核心能力就是版本控制。再具体一点,就是面向代码文件的版本控制,代码的任何修改历史都会被记录管理起来,意味着可以恢复到到以前的任意时刻状态。支持跨区域多人协作编辑,是团队项目开发的必备基础,所以Git也就成了程序员的必备技能。
🟢主要特点:
开源免费,使用广泛。
强大的文档(代码)的历史版本管理,直接记录完整快照(完整内容,而非差异),支持回滚、对比。
分布式多人协作的的代码协同开发,几乎所有操作都是本地执行的,支持代码合并、代码同步。
简单易用的分支管理,支持高效的创建分支、合并分支。
Git是Linux之父被迫开发的,为了解决Linux混乱的代码管理而开发的。Linux和Git之父 李纳斯·托沃兹(Linus Benedic Torvalds),来自1969年的芬兰。
02、Git是干什么的?—基础概念先了解下Git的基本概念,及基本框架、工作流程。
2.1、Git概念汇总
概念名称
描述
工作区(Workspace)
就是在电脑里能看到的代码库目录,是我们搬砖的地方,新 ...
缺页异常也叫缺页中断,页错误,是操作系统虚拟内存管理重要的一种机制,属于处理器的同步异常;
访问虚拟内存的时候,虚拟地址和物理地址没有建立映射关系,或者有访问权限错误发生时,会触发缺页异常;
内核必须处理此异常,而且对于进程来说时透明的。
一、缺页异常实现过程缺页异常,属于同步异常,触发时,CPU 会自动跳转到异常向量表;异常向量表入口地址在 arch/arm64/kernel/entry.S
1.1 相关源码文件异常入口:arch/arm64/kernel/entry.Sarm64 架构处理:arch/arm64/mm/fault.c通用代码:mm/memory.c
总体调用过程:
123456789101112131415vectors ///arch/arm64/kernel/entry.S 架构相关->el1_sync->el1_sync_handler->el1_abort->do_mem_abort ///arch/arm64/mm/f ...
一、kmalloc 函数1234567891011121314151617181920static __always_inline void *kmalloc(size_t size, gfp_t flags){if (__builtin_constant_p(size)) {#ifndef CONFIG_SLOB unsigned int index;#endif if (size > KMALLOC_MAX_CACHE_SIZE) return kmalloc_large(size, flags);#ifndef CONFIG_SLOB index = kmalloc_index(size); /// 查找使用的哪个 slab 缓冲区 if (!index) return ZERO_SIZE_PTR; return kmem_cache_alloc_trace( /// 从 slab 分配内存 kmall ...
一、补充点背景知识:
根据不同架构处理器,对内存的访问分为两种方式;a.x86 架构,将外设和普通内存分开,通过专门的 I / O 指令 (IN/OUT) 来访问外设的寄存器,称为“I/ O 地址空间”或“I/ O 端口空间”;
RISC 的 CPU,比如 ARM/PowerPC 等,采用统一编制,即将所有 I / O 外设的内存空间看作普通内存的一部分;
一般外设 I / O 的物理地址是已知的,但是开启 MMU 后,只能通过虚拟地址访问,因此需要将外设地址映射到虚拟地址;
二、ioremap 映射函数常用映射函数有
123#define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))#define ioremap_np(add ...
进程是独立的资源空间,每个进程都有自己独立的页表;
用户进程创建页表发生在三个时刻:
创建进程 fork 时;
缺页异常时;
进程切换时;
一、创建进程 fork核心函数
123__do_fork() -->copy_process -->dup_mm()
1.1 dum_mm 函数123456789101112131415161718static struct mm_struct *dup_mm(struct task_struct *tsk, struct mm_struct *oldmm){ struct mm_struct *mm; int err; mm = allocate_mm(); if (!mm) goto fail_nomem; memcpy(mm, oldmm, sizeof(*mm)); if (!mm_init(mm, tsk, mm->user_ns)) /// 分配私有的 pgd 页面 goto fail_nomem; ...
Linux 初始化过程,会依次建立如下页表映射:
恒等映射:页表基地址 idmap_pg_dir;
粗粒度内核镜像映射:页表基地址 init_pg_dir;
fixmap 映射:页表基地址为 init_pg_dir, 待 paging_init 之后为 swapper_pg_end;
细粒度内核镜像映射:页表基地址为 swapper_pg_dir;
线性映射:页表基地址为 swapper_pg_dir;
用户空间页表映射:页表基地址 task->mm->pgd;
上篇解析 “fixmap 映射” , 这里来解析主内核页表的创建, 包括 “细粒度内核镜像映射“ 和 “线性映射“;
创建完固定映射后,会初始化物理页面分配器, 即初始化伙伴系统;有了物理页面分配器,内核主页表就可以建立动态映射页表:
1234567/// 整理 memblock 的内存区域arm64_memblock_init();/// 至此,物理内存通过 memblock 模块添加入了系统,但此时只有 dtb,Image 所在的两端物理内存可以访问;// 其他区域的物理内存,还没建立映射,可以通过 me ...
Linux 初始化过程,会依次建立如下页表映射:
1. 恒等映射:页表基地址 idmap_pg_dir;
2. 粗粒度内核镜像映射:即上篇博文里的“第二次建立页表映射”,页表基地址 init_pg_dir;
3.fixmap 映射:页表基地址为 init_pg_dir, 待 paging_init 之后为 swapper_pg_end;
4. 细粒度内核镜像映射:页表基地址为 swapper_pg_dir;
5. 线性映射:页表基地址为 swapper_pg_dir;
6. 用户空间页表映射:页表基地址 task->mm->pgd;
上篇已经解析了 1 和 2 映射,这篇解析fixmap 映射。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910 ...
一、虚拟内存如果你是电子相关专业的,肯定在大学里捣鼓过单片机。单片机是没有操作系统的,所以每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。另外,单片机的 CPU 是直接操作内存的「物理地址」
在这种情况下,要想在内存中同时运行两个程序是不可能的。如果第一个程序在 2000 的位置写入一个新的值,将会擦掉第二个程序存放在相同位置上的所有内容,所以同时运行两个程序是根本行不通的,这两个程序会立刻崩溃。
操作系统是如何解决这个问题呢?
这里关键的问题是这两个程序都引用了绝对物理地址,而这正是我们最需要避免的。
我们可以把进程所使用的地址「隔离」开来,即让操作系统为每个进程分配独立的一套「虚拟地址」,人人都有,大家自己玩自己的地址就行,互不干涉。但是有个前提每个进程都不能访问物理地址,至于虚拟地址最终怎么落到物理内存里,对进程来说是透明的,操作系统已经把这些都安排的明明白白了。
操作系统会提供一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起来。
如果程序要访问虚拟地址的时候,由操作系统转换成不同的物理地址,这样不同的进程运行的时候,写入的是不同的物理地址,这样就不 ...