从零自制操作系统
文章平均质量分 80
看星猩的柴狗
IT爱好者一枚,菜狗CTF-PWN手
一个操作系统内核
一个编译器
一个解释器
一个数据库
一个 Web 服务器
一个 Web 浏览器
一个编辑器
展开
-
制作一个RISC-V的操作系统十六-系统调用
当说“试图设置PMP的第一个条目覆盖整个地址空间的访问权限”时,这指的是通过编程PMP的地址和配置寄存器来创建一个PMP规则,这个规则旨在允许对整个物理地址空间执行读、写和执行操作,而不受任何访问限制。就是用户态使用的函数用到的头文件和内核态使用的函数用到的头文件建议分别封装到各个文件中,在用户态中的作为C库,内核态中的内核维护,如果头文件相关定义不一致可能会出现问题。寄存器存储的是第一个区间的上界物理地址的高32位,即使设置为全1,也无法完美覆盖到地址空间的最末尾。为0xf,二进制形式为1111。原创 2024-04-28 22:20:02 · 1313 阅读 · 0 评论 -
制作一个RISC-V的操作系统十五-软件定时器
如果中间有定时中断发送,那么定时器设置到一半,就会去处理中断,此时也会去检查软件定时器,假设此时软件定时器想的是当前时刻的一个时刻后,那么此时由于中断中会将该时刻加一个,但检查时候由于软件定时器没有设置完成,那么会导致错过这个时刻,要等到下次定时器中断才会检查软件定时器并成功调用其中处理函数。如果为20,首先到达11发现小于26,此时到下层,发现大于17,到达17,发现小于26,调到下一层,再次比对20,比对成功。单次:就是定时器设置一个时间,当到达该时间后就会退出,该定时器将被销毁,不再起作用。原创 2024-04-28 00:23:38 · 749 阅读 · 0 评论 -
制作一个RISC-V的操作系统十四-任务同步和锁
一个典型的使用场景是,当一个内核线程发起I/O操作后,可以挂起自己并在完成变量上等待,直到I/O完成,设备驱动或者其他相关部分会触发这个完成变量以唤醒等待的线程。在操作系统和多线程编程中,完成变量(Completion Variable)是一种同步原语,主要用于实现线程或进程间的同步,尤其是在一个任务完成特定工作后通知另一个任务的场景。并发执行中,当一个进程访问临界区时,除非访问结束,否则其他进程(即使切换到了该进程)不能进入临界区即阻塞。即再切换到A准备获取B锁,然后再切换到B获取A锁会阻塞。原创 2024-04-24 21:21:39 · 785 阅读 · 1 评论 -
制作一个RISC-V的操作系统十三-抢占式多任务和兼容协作式多任务
RISC-V 规范定义了多种处理器模式,其中之一是 Machine 模式,这是一种最高权限模式,用于实现操作系统内核或 hypervisor 等核心功能。在RISC-V体系结构中,当一个hart(硬件线程)需要向另一个hart发送软件中断时,可以通过向另一个hart的MSIP位写入1来发起中断请求。MSIP映射到寄存器MSIP上的一个位,这个寄存器映射到内存上,即MSIP是memory-mapped的,这意味着可以通过内存访问指令(如load/store指令)来读写这个位,进而触发或清除中断。原创 2024-04-21 15:54:02 · 788 阅读 · 1 评论 -
制作一个RISC-V的操作系统十二-定时器中断
我们实现的初始化就是根据hartid将对应的mtimecmp设置一个初始值,然后设置一些使能中断位。mtime按照一定频率递增,当大于等于mtimecmp时会产生一个timer中断。通过读取当前时间和此时的tick值来计算得到当前最新的时间。MTIP是mip上模式的代表当前是否发送计时器中断位。硬件定时器的周期:就是多久会触发一次计时器中断。MTIE是mie上m模式的使能计时器中断位。类似计数器,按照硬件对应的固定频率递增。上电后会自动复位为0,有硬件自动完成。产生软件中断和定时器中断。原创 2024-04-17 22:04:35 · 480 阅读 · 0 评论 -
制作一个RISC-V的操作系统十一-外部设备中断
这个链接错误提示说明项目中有两个对象文件(plic.o和Trap.o)都在尝试定义相同的函数read_mie和write_mie,并且这些函数定义位于头文件的第14行和第19行。在C/C++中,函数不应该在头文件中直接定义,而应该只声明函数原型。否则,当包含这个头文件的源文件被编译后,就会导致每个源文件都生成一次该函数的定义,进而引发链接阶段的重复定义错误。解决方法如下:将read_mie和write_mie函数的定义移到一个单独的源文件(如trap.c或trap.s。原创 2024-04-17 00:48:08 · 892 阅读 · 0 评论 -
制作一个RISC-V的操作系统十-Trap和Exception(流 mtvec mepc mcause mtval mstatus trap完整流程)
陷入到S之前的权限可以是 U S 所以用一个比特位表示,陷入到U只能是U,那没有必要保存,因为执行完trap后恢复到的和执行trap时一样。在RISC-V架构的特权模式下,不同的异常等级(如Machine、Supervisor、User等)会有对应的陷阱值寄存器,例如在Supervisor模式下,类似的寄存器可能是。WPRI:读这个寄存器的时候忽略该部分的值,写这个寄存器的时候要保留该部分原来的值(不要变)base:存储trap入口函数的基地址右移两位的即四字节对齐的地址。寄存器会被设置为相关的错误值。原创 2024-04-09 22:45:32 · 837 阅读 · 0 评论 -
制作一个RISC-V的操作系统九-上下文切换和协作式多任务(任务 任务上下文 多任务 多任务系统分类 协作式多任务 代码实现 )
SW 和 LW 指令是 RISC-V 指令集中最基本和最常用的两个指令,它们为 RISC-V 提供了在内存和寄存器之间高效传输数据的能力,是构建复杂计算系统的基础。这三个寄存器在 RISC-V 体系结构中扮演着重要的角色,为 RISC-V 系统提供了高效的全局数据访问、线程管理和基本操作支持。初始化就是设置各个任务的上下文(各个任务的上下文保存到内存中),如设置上下文的ra(返回地址)为任务的第一条指令。当执行的核数小于要执行的任务时,此时任务会轮流运转到CPU上,以保证各个任务在宏观上被执行着。原创 2024-04-04 16:20:19 · 840 阅读 · 0 评论 -
制作一个RISC-V的操作系统八-内存管理(内存管理分类 链接脚本 ld 脚本语法 从ld 脚本获取符号值 基于page级别实现动态分配 管理heap区域各个page的状态 动态分配(页级别) 代码)
汇编中可以使用链接脚本中的符号来赋值,只不过要当链接后才会生效,即生成目标文件时并不会赋值成功(该符号会被识别为未定义符号(Undefined symbol)表示该符号在当前目标文件中没有定义,在链接阶段会被解析为其他目标文件中定义的符号。data段里声明了一个变量, 这个变量的值会被包进ELF里,ELF文件里会包括这个变量的符号与值,但是如果比如编译器发现, 你有些变量一开始是0, 编译器就可以只存他们的符号, 不存值(反正都是0), 把他们都放到BSS段中(就是在heap中动态分配page级别的大小。原创 2024-03-31 22:07:27 · 908 阅读 · 0 评论 -
制作一个RISC-V的操作系统七-UART初始化(UART NS16550A 规定 目标 发送数据 代码 extern)
电脑使用qemu时可以理解为qemu模拟了那块板子,同时那块板子与已经与你的电脑相连接了(我们对应的指定的内核也在那块板子上运行,而连接传输数据遵循UART的形式,通过板子上的UART接口和电脑的UART接口相连从而把数据传输到电脑,再通过电脑进行显示)对DLL和DLM进行写入,写的是内存,在io设备中应该有另外的寄存器用于保存波特率,DLL和DLM中的波特率设置好后io设备会自动的保存好(群里某个大佬的回复)THR存放发送的数据,一个字符,LSR存放着THR内的数据是否发送出去的信号,在第五位。原创 2024-03-25 16:15:56 · 933 阅读 · 0 评论 -
制作一个RISC-V的操作系统六-bootstrap program(risv 引导程序)
qemu将platform的外设和内存都进行统一编址,将所有物理地址从零到最高地址都分配掉,下图显示的就是不同硬件对应的物理地址范围(qemu模拟出来物理地址)BIOS引导完成后,bootloader(引导程序)就接手初始化硬件设备、建立存储器空间的映射,以便为操作系统内核准备好正确的软硬件环境。rd是x0时,不会将csr中的数据写入x0,只会执行第二步的动作那就相当于向csr写一个寄存器了。引导程序初始化:引导程序初始化包括设置基本的硬件环境,如处理器模式,内存管理单元(MMU)等。原创 2024-03-21 23:34:28 · 727 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程七(栈 栈帧 为何要有 函数调用约定 寄存器约定 跳转和返回指令约定 被调用函数约定 练习 C与汇编混合编程 汇编中嵌入C c中嵌入汇编 )
在汇编代码中,使用mul指令将a的平方保存在result_a寄存器中,将b的平方保存在result_b寄存器中,然后使用add指令将result_a和result_b的值相加后保存到c寄存器中。最后,使用约束操作数([c] “=r” ©)将c寄存器的值存储到变量c中,并将变量a和b的值存储到对应的寄存器中。通过约定参数的传递方式,编译器和汇编器可以有效地处理函数参数的传递,并生成正确的汇编和机器代码。在内嵌汇编中,可以使用输出和输入操作数约束来指定C代码中的变量名作为汇编代码的输入和输出。原创 2024-03-14 17:15:34 · 919 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程六(条件分支指令 伪指令 无条件跳转指令 问题 指令寻址模式总结)
B-type:B指代branch6-11中:先是第11位然后才是1到4位24-31中:先是5到10位,然后才是第12位符号扩展,所以是-20482和20472标号:标签类似地址写loop不写地址值汇编结果无条件跳转指令以寄存器值为基址来偏移跳转AUPIC会构造一个32位的数,将IMM作为其高20位,并存放到X6中,然后JALR跳转到X6+IMM的低12位的值。所以整体来看就是跳转到X6+一个32位数值原创 2024-03-14 11:06:20 · 389 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程五(逻辑运算 逻辑移位 算数移位 练习 5-4 内存读写指令 读指令 写指令 练习5-6 register .macro macro_nam)
在C语言中,register关键字用于告诉编译器,变量a应尝试在CPU寄存器中存储,而不是RAM中。然而,此建议通常对现代优化编译器没有实际影响,因为编译器通常会自动选择将哪些变量存储在寄存器中。此外,register变量不能取地址,因为它们可能不存在内存中,从而没有内存地址可供引用。然而在现代编程中,使用register关键字现在已经很罕见,优化编译器已经足够聪明,可以自动决定哪些变量应存储在寄存器中,以获得最佳性能。就是单纯写一定的比特数,所以不存在要扩展的这个概念,那么也不存在如何扩展的概念了。原创 2024-03-03 10:37:44 · 695 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程四(伪指令和指令 addi 基于算数运算实现的相关伪指令 addi指令的局限性 LUI(构造高20位) 练习 lui和addi联合使用 li)
伪指令的例子可能包含类似于“li”(load immediate)这样的指令,它用于将一个立即数加载到寄存器中,实际上它可能会被扩展成一组“lui”(load upper immediate)和“addi”(add immediate)指令,来实现将32位或64位的常数加载到寄存器中。透明度:使用指令时,程序员需要明确知道和指定每一条指令的操作,伪指令允许程序员写出更符合直觉的代码,背后的具体指令细节由汇编器处理。在RISC-V架构中,指令遵循特定的二进制格式,每一条指令都对应着一组由硬件执行的操作。原创 2024-03-02 14:15:52 · 1015 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程三(分析makefile 指令分析 )
QEMU -s 自动在模拟器启动是启动gdbserver,gdbserver与gdb通过网络连接。gdb server默认端口1234,然后等待gdb与之连接 -S参数代表 gdbserver启动调试程序后停止然后等待用户输入.-kernel ./可执行文件 代表要加载的镜像。对于-4先求出对应4的二进制编码为0100,然后取反加1,为1100,然后符号位为1,左扩展1,为11111100。对于4直接求出对应4的二进制编码为0100,(留一个为符号位)然后扩展由于是整数,左扩展0,为00000100。原创 2023-12-06 18:12:47 · 1266 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程二
XLEN:变量代表当前机器的字长(32位 64位 128位)指令对齐:下图中是4个字节的倍数。错位可能会导致程序允许异常。RV32I:RISC-V32位机器整数指令集。Pseudoinstruction:伪指令。一个寄存器有5个比特对应32个通用寄存器。x0:不能写,只能读,读出来的是0。指令集分非特权指令集和特权指令集。ALU能直接交互的是寄存器。funct7:占7个比特。funct3:占3个比特。多字节才有字节序这种概念。opcode编码格式。被翻译为基本机器指令。原创 2023-12-06 12:54:21 · 539 阅读 · 0 评论 -
制作一个RISC-V的操作系统五-RISC-V汇编语言编程一
高级:可以理解就是更贴近人的理解低级:可以理解就是更贴近机器的难移植:汇编指令基本上和机器指令一一对应的,不同的指令集架构的机器语言不同。所以一个机器上的汇编可能不能运行到另一个机构不同的机器上。灵活:高级语言与底层的交互是编译器生成了机器指令再交互的,如果想对生成的机器指令进行优化,此时高级语言不能直接做到,所以不够灵活。反之汇编更底层,更能直接控制对应机器指令的生成,所以优化更方便。不同汇编器支持汇编语法不一样大写S 保护预处理语句小写s 纯粹汇编语句。原创 2023-12-05 22:51:31 · 898 阅读 · 0 评论 -
制作一个RISC-V的操作系统四-嵌入式开发介绍
程序跑到开发板上,或者说运行到硬件上。原创 2023-12-05 18:59:22 · 1488 阅读 · 0 评论 -
制作一个RISC-V的操作系统三-编译与链接
预处理: 把#define #include 这些#开头的宏语言转为标准的C语言编译:C语言变成机器指令链接:把编译后的指令文件与其他库链接到一块调试需要加入调试信息建议实战一下,观察区别如该程序可重定位文件:链接才能把位置定下来核心转储文件:程序崩溃时相关信息。原创 2023-12-04 13:29:53 · 1568 阅读 · 0 评论 -
制作一个RISC-V的操作系统二-RISC-V ISA介绍
接口规范:可理解为一种标准Microarchitecture:微架构(是对指令集架构的一种硬件上的实现,如两种硬件架构都可以实现x86,那么可称这两种硬件架构是微架构)CISC:X86RISC:图中剩下都是。原创 2023-12-02 21:58:22 · 582 阅读 · 0 评论 -
制作一个RISC-V的操作系统一-计算机系统漫游
把机器指令取到寄存器,然后翻译,再执行,然后再取指,如此循环。感觉就是个中间人防止应用程序直接访问硬件造成的一些不好的影响。此时指向第一个位置的内容,将该位置的内容放入指令寄存器。首先编译和链接某c文件,此时得到的可执行文件在磁盘中。第3个用的是第三种(此时最高两位无意义,因为用不到)指令集架构ISA又是操作系统到硬件的接口。PC指向要运行的指令的地址(将要运行)把用得多的放到离CPU近的地方。a+b的实现可分为图中的四步。将内存中的指令一条一条执行。第1,2,4个用的是第一种。翻译指令寄存器的内容。原创 2023-12-02 20:17:25 · 552 阅读 · 0 评论 -
制作一个RISC-V的操作系统-环境搭建
由于之前的操作系统反馈难度太大,所以准备从这个RISC-V操作系统出发,以后知识层面更加深入再去完善。原创 2023-12-02 19:11:24 · 602 阅读 · 0 评论 -
从零制作操作系统-第五部分(简单显示与连接器)
此外,注意if语句后的左中括号[前后都有有空格,双等号“==”表示相等符号,单等号“=”既可以表示相等也可表示赋值,其区别为:当比较时,比较符号左右都有空格;当一个变量使用 export 进行声明后,变量和它的值将被加入到当前工作的环境变量中,以后在 make 执行的所有规则的命令都可以使用这个变量。几乎所有的链接脚本都是在做这些事情。在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。原创 2023-11-15 23:37:41 · 44 阅读 · 0 评论 -
从零制作操作系统-第四部分(GRUB引导实践)
hlt指令:使程序停止运行,处理器进入暂停状态,不执行任何操作,不影响标志。当RESET线上有复位信号、CPU响应非屏蔽中断、CPU响应可屏蔽中断3种情况之一时,CPU脱离暂停状态,执行HLT的下一条指令。CLI汇编指令全称为Clear Interupt,该指令的作用是禁止中断发生,在CLI起效之后,所有外部中断都被屏蔽,这样可以保证当前运行的代码不被打断,起到保护代码运行的作用。汇编指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。.long:定义四个字节数据。原创 2023-11-12 20:28:53 · 40 阅读 · 0 评论 -
从零制作操作系统-第四部分(GRUB引导)
而CPU寻址时是按照段+偏移的方式来寻址的,也就意味着能寻址的最高地址为0xFFFF:0xFFFF,即0x10FFEF(0xFFFF0+0xFFFF)。当时有一些程序利用了这种地址环绕机制进行工作,可是不久以后IBM公司又引入了AT机,使用的是Intel 80286的CPU,具有24根地址线,最高可以寻址16MB,并且有和8088一样的实模式运行模式,因此无法在超出1MB的地方产生地址环绕。%CR0=(%CR0&0x7FFFFFFF)|0x1 :相当于最高位清0,最低位置1. PE=1 PG=0。原创 2023-11-12 14:55:55 · 33 阅读 · 0 评论 -
从零制作操作系统-第三部分(环境搭建)
构建GCC交叉编译套件 (简单来说就是在某个系统平台下可以产生另一个系统平台的可执行文件的编译器)Bochs (x86模拟器 推荐)QEMU (x86模拟器)原创 2023-11-12 11:53:18 · 19 阅读 · 0 评论 -
从零自制操作系统-第二部分(保护模式下的内存管理)
因为在8086CPU中,地址线是20位,但寄存器是16位的,最高寻址64KB,它无法寻址到1M内存。于是,Intel设计了这种寻 址方式,先缩小4位成16位放入到段寄存器,用到时候,再将其扩大到20位,这也造成了段的首地址必须是16的倍数的限制。全局描述符表是一块内存空间,最大为64KB(1KB=1024B)可以理解为是一个数组,里面每个元素是段描述符。段选择器:32位汇编中16位段寄存器(CS、DS、ES、SS、FS、GS)中不再存放段基址,而是存放段选择器。16位:段起始地址*16+所在段中的偏移。原创 2023-11-03 21:45:30 · 109 阅读 · 2 评论 -
从零自制操作系统-第一部分(保护模式)
x86是一个intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合,这个x与处理器没有任何关系,它是一个对所有某某86系统的简单的广泛的定义,例如:i386, 586,奔腾(pentium)。由于早期intel的CPU编号都是如8086,80286来编号(都有86),由于这整个系列的CPU都是指令兼容的,所以都用X86来标识所使用的指令集合.如今的奔腾,P2,P4,赛扬系列都是支持X86指令系统的,所以都属于X86家族。CPU安照内存地图的规则去控制内存的访问。实模式转换到保护模式。原创 2023-10-30 13:52:02 · 84 阅读 · 1 评论