Operating Systems Three Easy Pieces(OSTEP) - Memory Virtualization

Chapter14 Memory API 14.2 The malloc() call 分配字符串长度的时候要注意:malloc(strlen(s) + 1),多分配一个byte给\0。strlen函数计算长度不会统计\0。 14.4 Common Errors Not Allocating Enough Memory char *src = "hello"; char *dst = (char *) malloc(strlen(src)); // wrong!!! char *dst = (char *) malloc(strlen(src) + 1); strcpy(dst, src); // work properly strcpy拷贝的时候会把\0也拷贝过去,所以分配长度的时候要strlen()+1。 否则多拷贝的一个byte,会写到heap的其他变量所属的地址,可能会导致fault。 Forgetting to Initialize Allocated Memory malloc分配出来的内存,需要初始化,否则可能是随机内存值。 Forgetting To Free Memory malloc分配出来的内存需要free掉。不然长时间运行的进程会导致内存泄漏。 短时间运行就结束的进程可能不会有这个问题,在进程结束后系统会自动回收内存,但free掉不使用的内存仍然是一个好习惯。 Freeing Memory Before You Are Done With It Freeing Memory Repeatedly Chapter15 Address Translation 地址转换 Chapter16 Segmentation 分段 16....

2024-03-27 · 1 min

Operating Systems Three Easy Pieces(OSTEP) - CPU Virtualization

这篇文章是阅读 OSTEP 3~11 的笔记,主要讲的是 Virtualization 中 Virtualize CPU 的部分。 Chapter4 Process 4.2 Process API 一般 OS 会提供以下的进程 API 来操作进程: Create: 创建进程。 Destroy: 结束进程。 Wait: Wait a process to stop running. 等待进程结束。 Miscellaneous Control: Suspend/Resume… 休眠,唤醒等等。 Status: 查看进程状态。 4.3 Process Creation 首先 OS 将存储在 disk or SSD 的 program 程序加载进 memory 内存。 这边有两种方式,一种是在运行前把 code 和 static data 全部加载进内存。现代操作系统一般会使用第二种方式,懒加载,只加载即将使用的 code 和 data。 分配栈。 分配堆。 分配三个文件描述符,标准输入 0,标准输出 1,错误 2。 4.4 Process Status 进程的状态有:...

2024-03-21 · 5 min

I2C spec

Reference I2C 为什么要用开漏输出,而不能用推挽输出。 防止短路。两个 push pull 输出相连,如果一个输出高,一个输出低,会短路。 线与。开漏输出有一个输出端输出低,则整条线都为低,所有输出高才为高。 https://www.zhihu.com/question/534999506 https://www.eet-china.com/mp/a87499.html 以上都是针对 multiple masters 多个输出端的,如果是 single master config 的话,推挽输出是否可以? 2 I2C-bus features Only two bus lines are required; a serial data line (SDA) and a serial clock line (SCL). It is a true multi-controller bus including collision detection and arbitration to prevent data corruption if two or more controllers simultaneously initiate data transfer. Serial, 8-bit oriented, bidirectional data transfers can be made at up to 100 kbit/s in the Standard-mode, up to 400 kbit/s in the Fast-mode, up to 1 Mbit/s in Fast-mode Plus, or up to 3....

2023-09-12 · 2 min

Cortex-M3权威指南

Reference 《Cortex-M3权威指南》 《ARMv7-M Architecture Reference Manual》 《Cortex-M3 Technical Reference Manual》 Chapter1 介绍 Cortex-M3处理器(CM3)采用ARMv7-M架构,它包括所有的16位Thumb指令集和基本的32位Thumb-2指令集架构,Cortex-M3处理器不能执行ARM指令集。 CM3的出现,还在ARM处理器中破天荒地支持了“非对齐数据访问支持”。 Chapter2 CM3概览 2.2 Registers CM3有R0-R15,16个registers。R13作为堆栈指针SP。SP有两个,但在同一时刻只能有一个可以看到,这也就是所谓的“banked”寄存器。 绝大多数16位Thumb指令只能访问R0-R7,而32位Thumb-2指令可以访问所有寄存器。 Cortex-M3拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个。 主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程) 进程堆栈指针(PSP):由用户的应用程序代码使用。 R14 LR:当调用一个子程序时,由R14存储返回地址。 R15 PC: 指向当前的程序地址。如果修改它的值,就能改变程序的执行流。 2.3 操作模式和特权级别 两种操作模式:handler mode(异常服务程序代码),thread mode(应用程序代码)。 两种特权级别:特权级,用户级。 在CM3运行主应用程序时(线程模式),既可以使用特权级,也可以使用用户级;但是异常服务例程必须在特权级下执行。复位后,处理器默认进入线程模式,特权极访问。 用户级的程序不能简简单单地试图改写CONTROL寄存器就回到特权级,它必须先“申诉”:执行一条系统调用指令(SVC)。这会触发SVC异常,然后由异常服务例程(通常是操作系统的一部分)接管,如果批准了进入,则异常服务例程修改CONTROL寄存器,才能在用户级的线程模式下重新进入特权级。 2.5 存储器映射 总体来说,Cortex-M3支持4GB存储空间,如图2.6所示地被划分成若干区域。 从图中可见,不像其它的ARM架构,它们的存储器映射由半导体厂家说了算,Cortex-M3预先定义好了“粗线条的”存储器映射。 2.6 总线接口 2.9 中断和异常 11种系统异常+5个保留档位+240个外部中断。 编号 类型 优先级 简介 0 N/A N/A 没有异常在运行 1 复位 -3(最高) 复位 2 NMI -2 不可屏蔽中断(来自外部NMI输入脚) 3 硬(hard) fault -1 所有被disable的fault,都将“上访”成硬fault 4 MemManage fault 可编程 存储器管理fault,MPU访问犯规以及访问非法位置 5 总线fault 可编程 总线错误(预取流产(Abort)或数据流产) 6 用法(usage)Fault 可编程 由于程序错误导致的异常 7-10 保留 N/A N/A 11 SVCall 可编程 系统服务调用 12 调试监视器 可编程 调试监视器(断点,数据观察点,或者是外部调试请求 13 保留 N/A N/A 14 PendSV 可编程 为系统设备而设的“可悬挂请求”(pendable request) 15 SysTick 可编程 系统滴答定时器 16-255 IRQ #0~239 可编程 外中断#0~#239 2....

2023-09-06 · 2 min

Rust

1.2 Even Better TOML,支持 .toml 文件完整特性 Error Lens, 更好的获得错误展示 One Dark Pro, 非常好看的 VSCode 主题 CodeLLDB, Debugger 程序 1.3 Cargo cargo new hello_world tree cargo run is equal to cargo build + ./target/debug/world_hello 默认的是debug模式,编译器不会做任何的优化,编译速度快,运行慢。 高性能模式,生产发布模式: cargo run --release cargo build --release cargo check 检查编译能否通过 cargo.toml 项目数据描述文件 cargo.lock 项目依赖详细清单 在cargo.toml中定义依赖的三种方式: [dependencies] rand = "0.3" hammer = { version = "0.5.0"} color = { git = "https://github.com/bjz/color-rs" } geometry = { path = "crates/geometry" } 2....

2023-05-20 · 3 min

RISC-V手册 第十章 RISC-V特权架构

10.1 导言 到目前为止,本书主要关注RISC-V 对通用计算的支持:我们引入的所有指令都在用户模式(User mode 应用程序的代码在此模式下运行)下可用。本章介绍两种新的权限模式:运行最可信的代码的机器模式(machine mode),以及为Linux,FreeBSD 和Windows 等操作系统提供支持的监管者模式(supervisor mode)。 图10.1是RISC-V 特权指令的图形表示,图10.2列出了这些指令的操作码。显然,特权架构添加的指令非常少。作为替代,几个新的控制状态寄存器(CSR)显示了附加的功能。 10.2 简单嵌入式系统的机器模式 机器模式(缩写为M模式, M-mode)是 RISC-V中(hart hardware thread,硬件线程)可以执行的最高权限模式。程)可以执行的最高权限模式。在M模式下运行的hart对内存,I/O和一些对于启动和配置系统来说必要的底层功能有着完全的使用权。因此它是唯一所有标准RISC-V处理器都必须实现的权限模式。实际上简单的 RISC-V微控制器仅支持 M模式。 机器模式最重要的特性是拦截和处理异常的能力。RISC-V将异常分为两类。一类是同步异常。另一类是中断,它是与指令流异步的外部事件,比如鼠标的单击。 在 M模式运行期间可能发生的同步异常有五种: 访问错误异常:当物理内存的地址不支持访问类型时发生(例如尝试写入 ROM)。 断点异常:在执行 ebreak指令,或者地址或数据与调试触发器匹配时发生。 环境调用异常:在执行 ecall指令时发生。 非法指令异常:在译码阶段发现无效操作码时发生。 非对齐地址异常:在有效地址不能被访问大小整除时发生,例如地址为0x12的amoadd.w。 有三种标准的中断源:软件、时钟和外部来源。软件中断通过向内存映射寄存器中存数来触发。 10.3 机器模式下的异常处理 八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分: mtvec (Machine Trap Vector) 它保存发生异常时处理器需要跳转到的地址。 mepc (Machine Exception PC) 它指向发生异常的指令。 mcause (Machine Exception Cause) 它指示发生异常的种类。 mie (Machine Interrupt Enable) 它指出处理器目前能处理和必须忽略的中断。 mip (Machine Interrupt Pending) 它列出目前正准备处理的中断。 mtval (Machine Trap Value) 它保存了陷入 trap 的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。 mscratch (Machine Scratch) 它暂时存放一个字大小的数据。 mstatus (Machine Status) 它保存全局中断使能,以及许多其他的状态,如图10....

2023-01-09 · 2 min

RISC-V手册 第三、四章 RISC-V汇编语言,乘法和除法指令

第三章 RISC-V汇编语言 3.2 函数调用规范 3.3 汇编器 这类指令在巧妙配置常规指令的基础上实现,称为伪指令。图 3.3和 3.4列出了 RISC-V伪指令。 汇编程序的开头是一些汇编指示符,它们是汇编器的命令。图 3.9是RISC-V的汇编指示符。其中图 3.6中用到的指示符有: .text:进入代码段。 .align 2:后续代码按2^2字节对齐。 .globl main:声明全局符号 “main” .section .rodata:进入只读数据段 .balign 4:数据段按4字节对齐 .string “Hello, %s!\n": 创建空字符结尾的字符串 .string “world": 创建空字符结尾的字符串 3.4 链接器 3.5 静态链接和动态链接 上一节对 静态链接进行了说明,在程序运行前所有的库都进行了链接和加载。如果这样的库很大,链接一个库到多个程序中会十分占用内存。另外,链接时库是绑定的,即使它们后来的更新修复了 bug,强制的静态链接的代码仍然会使用旧的、有bug的版本。 为了解决这两个问题,现在的许多系统使用动态链接,外部的函数在第一次被调用时才会加载和链接。后续所有调用都使用快速链接,因此只会产生一次动态开销。每次程序开始运行,它都会按照需要链接最新版本的库函数。另外,如果多个程序使用了同一个动态链接库,库代码在内存中只会加载一次。 编译器产生的代码和静态链接的代码很相似。其不同之处在于,跳转的目标不是实际的函数,而是一个只有三条指令的存根函数( stub function)。存根函数会从内存中的一个表中加载实际的函数的地址并跳转。不过,在第一次调用时,表中还没有实际的函数的地址,只有一个动态链接的过程的地址。当这个动态链接过程被调用时,动态链接器通过符号表找到实际要调用的函数,复制到内存中,更新记录实际的函数地址的表。后续的每次调用的开销就是存根函数的三条指令的开销。 第四章 乘法和除法指令 RV32M向RV32I中添加了整数乘法和除法指令。图4.1是RV32M扩展指令集的图形表示,图4.2列出了它们的操作码。 RV32M具有有符号和无符号整数的除法指令:divide(div)和divide unsigned(divu),它们将商放入目标寄存器。在少数情况下,程序员需要余数而不是商,因此RV32M提供remainder(rem)和remainder unsigned(remu),它们在目标寄存器写入余数,而不是商。 将两个32位数相乘得到的是64位的乘积。为了正确地得到一个有符号或无符号的64位积,RISC-V中带有四个乘 法指令。要得到整数要得到整数32位乘积( 64位中的低 32位)就用 mul指令。要得到高32位,如果操作数都是有符号数,就用mulh指令;如果操作数都是无符号数,就用mulhu指令。指令;如果一个有符号一个无符号,可以用mulhsu指令。在一条指令中完成把64位积写入两个 32位寄存器的操作会使硬件设计变得复杂,所以RV32M需要两条乘法指令才能得到一个完整的64位积。 对许多微处理器来说,整数除法是相对较慢的操作。如前述,除数为2的幂次的无符号除法可以用右移来代替。事实证明,通过乘以近似倒数再修正积的高32位的方法,可以优化除数为其它数的除法。例如,图 4.3显示了 3为除数的无符号除法的代码。 {% note danger %} lui t0, 0xaaaab 为什么t0=0xaaaaaaab而不是0xaaaab000 {% endnote %}

2023-01-06 · 1 min

RISC-V手册 第二章 RV32I基础整数指令集

1.2 模块化与增量型 ISA ​和几乎所有以往的 ISA不同,RISC-V是模块化的。它的核心是一个名为RV32I的基础 ISA,运行一个完整的软件栈。RV32I是固定的,永远不会改变。模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。可以生成当前硬件条件下的最佳代码。惯例是把代表扩展的字母附加到指令集名称之后作为指示。例如,RV32IMFD将乘法( RV32M),单精度浮点(RV32F)和双精度浮点(RV32D)的扩展添加到了基础指令集 RV32I)中。 2.2 RV32I 指令格式 ​用于寄存器-寄存器操作的R类型指令,用于短立即数和访存load操作的I型指令,用于访存store操作的S型指令,用于条件跳转操作的B类型指令,用于长立即数的U型指令和用于无条件跳转的J型指令。 2.3 RV32I 寄存器 ​RV32I有31寄存器加上一个值恒为0的x0寄存器。 2.4 RV32I 整数计算 ​简单的算术指令(add, sub)、逻辑指令(and, or, xor),以及图2.1中的移位指令(sll, srl, sra)和其他ISA差不多。他们从寄存器读取两个32位的值,并将32位结果写入目标寄存器。 ​程序可以根据比较结果生成布尔值。为应对这种使用场景下,RV32I提供一个当小于时置位的指令(slt)。 ​图2.1剩下的两条整数计算指令主要用于构造大的常量数值和链接。加载立即数到高位(lui)将20位常量加载到寄存器的高20位。接着便可以使用标准的立即指令来创建32位常量。 有什么不同之处? RISC-V中没有字节或半字宽度的整数计算操作。操作始终是以完整的寄存器宽度。 RV32I也不包含乘法和除法,它们包含在可选的RV32M扩展中。 2.5 RV32I 的Load 和 Store ​除了提供32位字(lw,sw)的加载和存储外,图2.1中说明,RV32I 支持加载有符号和无符号字节和半字(lb,lbu,lh,lhu)和存储字节和半字(sb,sh)。有符号字节和半字符号扩展为32位再写入目的寄存器。即使是自然数据类型更窄,低位宽数据也是被扩展后再处理,这使得后续的整数计算指令能正确处理所有的32位。在文本和无符号整数中常用的无符号字节和半字,在写入目标寄存器之前都被无符号扩展到32位。 RV32I 条件分支 ​相等(beq),不相等 (bne),大于等于(bge),或小于(blt)。最后两种比较有符号比较,RV32I也提供相应的无符号版本比较的:bgeu和bltu。分支指令的寻址方式是12位的立即数乘以2,符号扩展它,然后将得到值加到PC上作为分支的跳转地址。{% label danger @这句话没理解 %} {% note info %} 补充说明:获取PC 当前的PC可以通过将auipc的U立即数字段设置为0来获得。 {% endnote %} 2.7 RV32I无条件跳转 ​图2.1中的跳转并链接指令(jal)具有双重功能。若将下一条指令PC + 4的地址保存到目标寄存器中,通常是返回地址寄存器ra(见图2.4),便可以用它来实现过程调用。如果使用零寄存器(x0)替换ra作为目标寄存器,则可以实现无条件跳转,因为x0不能更改。像分支一样,jal将其20位分支地址乘以2,进行符号扩展后再添加到PC上,便得到了跳转地址。 {% note info %} jal x1, X means jump to X, and save the return address which is normally PC+4 to the x1....

2023-01-06 · 1 min

程序员的自我修养学习笔记

objdump -h # 显示段结构 objdump -s # 将所有段以16进制打印出来 objdump -d # 反汇编 objdump -D # 反汇编更多信息 objdump -t # 查看符号 objdump -R # 查看目标文件重定位表 readelf -S # 显示段结构 readelf -h # 查看文件头 readelf -s # 查看符号表 readelf -l # 查看ELF加载时的Segment readelf -d 第二章 编译和链接 2.1.1 预处理 gcc –E hello.c –o hello.i 展开宏定义 处理预编译指令 “#if”、“#ifdef”等等 处理 “#include ”预编译指令 删除注释 添加行号和文件名标识 保留所有的 #pragma 编译器指令 2.1.2 编译 编译:gcc –S hello.i –o hello.s 预编译+编译:gcc –S hello....

2022-01-27 · 2 min · YC-Xiang