AArch64 启动流程总结
AArch64 启动流程总结引导装载程序硬件状态要求一、前置要求引导装载程序需完成以下关键操作,以确保 Linux 内核在 AArch64 架构下正确启动: 设置和初始化 RAM 设置设备树数据 解压内核映像 调用内核映像 (一)RAM 初始化(强制) 目标:定位并初始化系统中所有供内核使用的 RAM,确保内核能够存储系统变量和数据。 实现方式:依赖设备特性,可通过自动算法检测 RAM、使用设备已知的 RAM 信息或其他定制方法。 (二)设备树数据准备(强制) 格式要求:设备树数据块(dtb)需满足以下条件: 8 字节对齐,大小不超过 2MB。 避免放置在需特定属性映射的 2MB 区域内(因内核以 2MB 粒度映射 dtb)。 历史版本差异:v4.2 之前的内核要求 dtb 位于内核映像下方 text_offset 字节处开始的首个 512MB 内存区域内。 (三)内核映像解压(可选) 依赖条件:AArch64 内核无自解压代码,若使用压缩内核(如 Image.gz),需由引导装载程序通过 gzip...
arm64 linux内核虚拟内存布局
arm64 linux内核虚拟内存布局linux在arm64中的内存布局在AArch64架构的Linux内核中,内存管理的核心机制之一是虚拟地址空间的划分与页表转换。本文将基于内核文档Documentation/arch/arm64/memory.rst,深入解析4KB页和64KB页两种模式下的内存布局差异,以及它们在ELF启动场景中的实际应用。 一、内存布局的核心设计原则AArch64架构通过页大小和转换表级别的组合,实现灵活的虚拟地址空间配置。核心设计目标包括: 用户空间与内核空间隔离:通过虚拟地址最高位TTBR0/1(63位)区分,用户空间最高位为0,内核空间为1。 转换效率与地址空间平衡:小页(4KB)提供更细粒度的内存管理,大页(64KB)减少页表层级以提升转换效率。 兼容性与扩展性:支持3级/4级转换表(4KB页)和2级/3级转换表(64KB页),适配不同硬件平台。 二、4KB页模式:细腻控制与超大地址空间1. 地址空间划分(1)3级转换表(39位虚拟地址,512GB) 用户空间:0x0000000000000000 ~...
Linux网络源代码学习——整体介绍
Linux网络源代码学习——整体介绍 简介 源码目录 网络分层 网络与文件操作 数据结构 sk_buff结构 网络协议栈实现——数据struct 和 协议struct 面向过程/对象/ioc 其它 以下来自linux1.2.13源码。linux的网络部分由网卡的驱动程序和kernel的网络协议栈部分组成,它们相互交互,完成数据的接收和发送。 源码目录1234567891011121314151617linux-1.2.13||---net | |---protocols.c |---socket.c |---unix | | | |---proc.c | |---sock.c | |---unix.h |---inet | |---af_inet.c |---arp.h,arp.c ...
armv8虚拟化扫盲
armv8虚拟化扫盲虚拟化概述根据虚拟化实现方式不同,分为软件虚拟化和硬件虚拟化 软件虚拟化 qemu 硬件虚拟化 type1虚拟化:xen+ type2虚拟化:kvm 半虚拟化 virtio+ 软件虚拟化之qemu qemu也可以使用type2级别的硬件虚拟化配合,如果没有kvm硬件加速支持,qemu可以纯粹的软件虚拟化 qemu采用TCG中间指令格式,将guest os的指令翻译成TCG指令,然后再将TGC指令翻译成host os的指令 硬件虚拟化type1虚拟化type1虚拟化是hypervisor直接运行到硬件上,管理所有的硬件资源和虚拟机, 框图如下: 这种方式存在一个问题,就是hypervisor需要实现所有设备驱动,开发工作大 type2虚拟化type2虚拟化中的hypervisor运行在host os上,host os负责管理硬件资源,而hypervisor作为host os的组件 这种方式的问题是: 由于host os EL1和hypervisor...
rCore chapter3 多道程序分时系统任务
rCore chapter3 多道程序分时系统任务这一章在之前的章节中更进一步, 实现了任务调度的功能, 也就是任务不再是之前的批处理系统那样一个接一个地运行, 而是受到 OS 的调度。为了实现这一目标, 本章实现了下面的功能或机制: 将应用程序加载到不同的内存位置, 并且同时存在于内存中 内核添加上下文相关的数据结构,存储应用调度时的上下文信息,基于这些数据结构实现上下文切换函数 通过时钟中断实现抢占式调度 官方文档:https://learningos.cn/rCore-Camp-Guide-2025S/chapter3/index.html 1 应用程序数据结构1.1 应用程序加载位置这一过程相比之前的章节变化很小,就是将不同的应用程序链接到了操作系统的不同的位置,应用程序加载的位置是一个基址加上指定的偏移量。 1.2 应用程序的栈这一由于我们需要实现任务的切换,应用程序运行的 **上下文 **包括了各种寄存器、函数调用栈等,...
rCore chapter2 批处理系统
rCore chapter2 批处理系统参考文档:第二章:批处理系统 - rCore-Tutorial-Guide-2025S 文档 1 整体流程本章的目的是实现批处理系统,文档中称为 邓氏鱼OS , 其内容包括: 编写 Rust应用程序 , 并使用链接脚本调整内存布局 为 OS 实现系统调用 将应用程序从 efl 转化为 binary , 和 OS 的代码链接到一起 实现批处理的任务调度 引入 用户栈 和 内核栈 2 特权级2.1 特权级的概念下面这摘自官方文档张图展示了 riscv 中不同的特权级: PrivilegeStack RISC-V 定义了以下四个特权级别: **用户级别(User-Level or U-Mode) **:就是图中的 App 所在的级别, 用户级别是最低的特权级别,普通的应用程序在这个级别上运行。在这个级别上,程序不能直接访问硬件资源,如控制 I/O 和管理内存等。用户级别的代码需要通过 **系统调用 **( syscalls )与更高特权级别的软件交互来请求服务。而 syscalls 就是应用程序二进制接口, 图中的 ABI...
rCore chapter1 应用程序与基本环境
rCore chapter1 应用程序与基本环境参考文档: 第一章:应用程序与基本执行环境 - rCore-Tutorial-Guide-2025S 文档 1 理论知识梳理1.1 应用程序执行环境 应用程序执行环境栈 上图是从官方文档中摘取的, 操作系统 承接了 硬件平台 和各种编程语言标准库中的 系统调用 , 裸机程序就是没有操作系统的程序, 因此我们实现的程序需要绕过标准库直接和硬件打交道, 一句话就是, 不能调包了, 得手写 1.2 平台与目标三元组目标三元组 (Target Triplet): CPU 指令集、操作系统类型和标准运行时库。 Rust 工具链中的 rustc 可以获取以上信息: 12345678$ rustc --version --verboserustc 1.75.0-nightly (aa1a71e9e 2023-10-26)binary: rustccommit-hash: aa1a71e9e90f6eb3aed8cf79fc80bea304c17ecbcommit-date: 2023-10-26host:...
cell基本特性
cell基本特性 内部可变性:通过编译时保证安全,而非运行时锁 零成本抽象:无锁设计,性能接近直接操作原生数据 单线程限制:仅适用于单线程环境,跨线程需要使用 Mutex 或者 RwLock 等同步机制 基本用法1、创建 Cell: 12use std::cell::Cell;let shared_state = Cell::new(100); // 初始值为 100 的 Cell 2、常用方法: 方法 作用 示例 get() 获取不可变引用 let value = shared_state.get(); set(value) 替换整个值 shared_state.set(100); replace(value) 替换值并返回旧值 let old = shared_state.replace(200); take() 移除并返回值,原位置留空(None) let val = shared_state.take(); swap(value) 用新值替换旧值并返回旧值 let old =...
闭包
Rust中的闭包(Closure),也叫lambda表达式,是一个可以捕获环境变量的匿名函数。闭包特点如下: 声明时候使用||代替()将输入参数括起来 函数体定界符({})对于单个表达式闭包可以省略,对于多行表达式闭包必须有 闭包可以捕获环境变量,即外部作用域的变量 一个例子,下面示例输出3: 1234fn main() { let i = |i: u32| -> u32 { i + 1 }; println!("{}", i(2));} 捕获闭包可以捕获外部作用域的变量,即使这些变量被移动到了闭包内部。同时捕获也可以灵活的消耗生命周期比如可以move和borrow,move会将变量的所有权转移到闭包内部,borrow则不会。当然,你可以强制使用move把所有权移动到闭包内,这样外部函数就不能再使用这个变量了 1234567891011121314151617181920212223fn main() { use std::mem; let mut...
类型转换
rust跟其他C C++不同的是,不提供原生类型之间的隐式转换,需要通过强制类型转换来实现。类型转换可以分为以下几种: as转换 From和Into Traits TryFrom和TryInto 转换 ToString 和 FromStr 总结 常见问题参考 as转换 as 转换适用于简单的场景,依赖内置显示类型转换,且无法处理转换过程出现的错误 123456789101112131415fn main() { let a = 3.1 as i8; let b = 100_i8 as i32; let c = 'a' as u8; // 将字符'a'转换为整数,97 println!("{},{},{}",a,b,c) let mut values: [i32; 2] = [1, 2]; let p1: *mut i32 = values.as_mut_ptr(); let first_address = p1 as usize;...