![](https://img-blog.csdnimg.cn/20201014180756930.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
项目
文章平均质量分 81
从0写Linux操作系统
小丑乐
这个作者很懒,什么都没留下…
展开
-
磁盘与Fat16系统
只使用LBA模式对磁盘进行读写,而不是难于理解地的CHS模式。在LBA操作模式下,磁盘就是一块块连续的、相同大小的扇区集合。FAT16文件系统的结构以及工作原理,同时还在整个文件系统中增加了该类型文件系统相关的接口支持。FAT16文件系统采用的是不连续的存储方式:将文件拆分成多个相同的数据块,然后在磁盘分区中找到空闲簇,写入簇。FAT16为了便于快速找到文件中簇链的链接关系,将这种关系单独放置到了FAT表中。每一个表项都对应于一个簇,表项的值代表了簇的下一簇是什么。原创 2024-09-02 14:51:08 · 498 阅读 · 0 评论 -
使用文件系统管理硬件设备
对sys_open代码进行了优化,使得其打开方式做到更加通用,不再直接使用devfs_open,而是根据路径找到对应的文件系统fs_t结构,再调用其中的open函数,进而使得其代码变得更加通用。对sys_read/sys_write等函数实现做了修改,使其全部采用调用文件系统fs_t中相应的回调函数来完成文件的特定操作,而无需再像以前那样调用设备管理层dev_xxx中的接口。我们设计了 fs_t结构用于描述某种特定的文件系统。注意的事项为:在打开设备文件系统中的文件时,默认文件名最后的几位为次设备号。原创 2024-09-01 16:50:30 · 900 阅读 · 0 评论 -
实现一个命令行解释器
由于getopt将会在其它命令的执行时重复使用,因此需要在退出echo命令的执行时,将optind重置。在应用程序的执行过程中,程序可能会主动结束执行,或者从main返回,因此需要给进程一个主动退出执行的接口。使用echo命令时,使用的形式为echo -n 重复数量 -h 待重复的字符串,其中有-n和-h为选项,且-n的后边必须加上一个数量值。当返回时-1时,表示已经没有参数,即对于echo -n 重复数量 -h 字符串,表示已经扫描完所有以-开头的选项,后续已经没有其它选项。,包含可以被执行的若干指令。原创 2024-09-01 15:39:46 · 487 阅读 · 0 评论 -
设备管理与文件系统
文件系统的常见功能是将磁盘上的数据抽像成文件和目录,并将其组织成目录树的形式,一切皆文件(设备,外设接口)6、为进程添加文件打开表每个应用程序在运行过程中,都有可能打开文件并进行读写,且各个应用程序之间操作文件行为应当相互不干扰,以及多个进程同时打开同一文件中要处理冲突的问题解决办法:定义一个全局的file_t文件表,其中包含所有打开的文件表。每个进程只维护一个指针,指向表中的某个文件。每个进程既有自己的打开文件表,同时也能够方便实现文件地共享、处理打开同一文件的冲突问题。原创 2024-08-31 17:27:59 · 801 阅读 · 0 评论 -
使用控制台与键盘进行输入输出
计算机在上电启动后,显示器被默认配置成80x25列的文本显示模式。其使用从0xb8000开始,一共32KB的显存用于显示。如要在屏幕上指定位置显示特定的字符,则只需找到该位置对应的显存地址,写入2字节的数据:ascii码和颜色属性字节。由于一屏共8025个字符,每个字符占用2个字节,所以一屏字符显示需要约4000字节数据。而显存一共32KB,因此这些存储区域可以存储8块屏幕的显示数据。后续可以通过切换对应的显存屏幕数据。原创 2024-08-31 16:27:47 · 660 阅读 · 0 评论 -
使用C标准库中的printf输出
在newlib库中,当我们使用malloc进行内存分配时,就会从堆中分配一大块内存,然后再自行对这块内存进行管理,从中分配要求的大小的内容。printf中的参数会被格式化成最终的字符串,该字符串会被传入系统调用write作为参数,而现在我们只能将字符串打印到串口,暂时还没有写到屏幕上的方法,因此在实现中,直接使用了log_printf打印。级I/O和文件系统访问(open、close、read、write、lseek、stat、fstat、fcntl、link、unlink、rename);原创 2024-08-31 15:25:14 · 394 阅读 · 0 评论 -
新进程的加载与创建
首先,需要为系统调用预留接口并添加相应的ID,然后在库函数中实现该系统调用的接口。接着,需要处理系统调用的映射表,调用task.c中的函数实现进程主动放弃CPU的功能。当fork()返回值会返回进程的id,当进程发现pid==0,就知道了自己是fork出来的子进程;创建完成就是增加exec()系统调用,与实现fork()系统调用过程一样,其功能就是使用sys_exec加载应用程序。1)建立独立的 不和操作系统代码文件一起编译的文件,比如建立main.c文件,添加main函数。fork创建子进程。原创 2024-08-31 15:03:20 · 434 阅读 · 0 评论 -
建立系统调用
然后在执行系统调用时,从传入的参数中获得需要调用的函数对应的id。为了取得系统调用传入的函数,课程定义了syscall_frame_t结构来解析栈中的寄存器和参数值,通过该结构体,即可获得系统调用传入的参数,以及当前执行系统调用时的状态。根据GCC对函数返回值的处理规则:函数调用的返回值保存在eax寄存器中,在系统调用之后,执行frame->eax=ret,用于将执行结果返回给应用程序。使用向量号为0x80的中断门,当需要执行系统调用时,执行int 0x80指令,参数也是通过寄存器传递。原创 2024-08-30 15:20:14 · 234 阅读 · 0 评论 -
隔离操作系统与进程
这些区域的分布,可以通过链接脚本来配置,通过kernel.lds中的配置,可以控制这些代码和数据在内存中应该存在的位置。在kernel.elf被加载到内存中后,first_task中的所有的代码和数据还只存在于1MB以下的内存中。init_main运行在权限级0的模式下,而first_task需要运行在特权级3,因此这里涉及到从高特权级切换到低特权级的情况。,但是由于没有文件系统,二者仍然是一同编译的,所以最终汇编出来的文件中,first_task和内核的代码是混在一起的。:1位,控制页面的可写权限。原创 2024-08-29 15:41:15 · 697 阅读 · 0 评论 -
虚拟内存管理和保护模式
启动分页机制后,应用程序就看不到机器的物理内存了,看到的就是虚拟的,不存在的内存空间。这块虚拟内存也是划分成了一个个4KB的内存页。操作系统会通过·页表将这些虚拟内存空间中连续的内存页,从物理内存空间中找空闲的物理页,简历一个映射关系。就可以将多个不连续的物理页,变成了进程使用的连续内存页。这样进程就感觉自己在使用连续的内存页,而实际最终在物理内存的表现上却是实现不连续的内存页。页表由CR3来管理。原创 2024-08-29 14:16:00 · 610 阅读 · 0 评论 -
进程间的同步与互斥
1)等待信号:对于等信号量而言,如果事件或资源的计数不为0,则说明事件已经发生或者资源是可用的,所以不需要等,而如果为0,则需要等待,进程不能继续往下运行。2)发送信号:当事件发生或者资源可用时,如果有进程在队列中等,则唤醒一个进程让其可以继续往下运行。由于事件发生的次数可能不止一次,或者资源可用的数量可能不止一个,因此,信号量内部会维护一个计数器,用于表示某种事件发生的次数或者某种资源可用的数量。等待队列的排序顺序设置比较简单,当事件发生或资源可用时,最先等待的进程最先获得事件的处理权。原创 2024-08-29 10:15:51 · 275 阅读 · 0 评论 -
任务管理与延时
由于系统中可能会有多个进程同时延时,为了将这些进程有效的管理,额外做了一个延时队列,将需要延时的进程暂时插入到就绪队列中。目前的系统中,CPU总是被用于安排运行处于就绪队列头部的进程的代码,所以导致了如果该进程总是处于头部,那么其后的任务将迟迟得不到运行的机会,会被活活“饿死”当系统中所有任务都尝试延时时,系统将崩溃,操作系统不知道做什么,因此考虑增加空闲进程,这个进程就是在其他进程都不需要运行的时候才运行。使用sys_sleep进行延时,实际的延时是有误差的,不会准确的延时指定的时间。原创 2024-08-29 09:54:49 · 239 阅读 · 0 评论 -
实现链表数据结构
既要将结点的前后结点中相应的指针重新进行设置,将前一结点的next指向后面的结点,将后一结点的pre指向前面的结点。此外,如果结点位于链表的头部或者尾部,还需要更新first或last指针。所实现的链表为双向链表,既每个结点中包含两个指针: next指向后继结构,pre指向前驱结点。1)删除头部要考虑到队列只有一个结点的情况,因为这意味着在修改first指针时还要同时更新last指针,将last设置为空。插入尾部也要特别考虑队列为空的情况,因为如果为空,则还需要更新first指针。原创 2024-08-28 11:10:04 · 111 阅读 · 0 评论 -
实现简单的进程切换
在执行该指令时,CPU会自动将保存当前任务的状态到TSS,然后从另一任务的TSS中取出状态进行恢复。进行不同程序运行的切换时,需要将前一个程序完整的运行状态全部保存到TSS,这样当后续该程序需要再次运行时,再将该状态进行从TSS中恢复,从而就像能完整地继续从上次切换的位置继续往下运行,好像什么都没发生一样。目前只需要在切换时,保存号当前的段寄存器、通用寄存器、EIP、EFLAGS中的内容到当前程序的TSS中,然后再加载下一个将要运行程序的TSS中段寄存器、通用寄存器、EIP、EFLAGS值进行恢复。原创 2024-08-28 10:42:25 · 387 阅读 · 0 评论 -
日志与printf格式化输出
当有更多参数时,如func_arg(a, b, c, d, e),则栈中压入的参数从上(高地址)到下(低地址)依次为e, d, c, b , a。在函数内部,只有func_arg(int a, ....)中的a参数有名字可以引用,而要获取其它参数,则需要借助a找到对应的栈位置,然后再在栈中依次往上(高地址)逐个去取出相应的参数。课程使用RS232接口进行输出,其通过两根信号线:发送信号、接收信号,便能实现与外部的数据输入输出通信,qemu有实现对这种接口的模拟。不过,不同的显示终端对于\n的解释不同。原创 2024-08-28 10:03:02 · 359 阅读 · 0 评论 -
加载:loader实现
内联汇编显示字符串:利用显示单个字符的原理检测内容容量:利用BIOS的软中断服务切换到保护模式:A20地址线的开启,使得可用内存不局限于1MB,采用GDT表管理内存,使用LGDT寄存器指明GDT表的基这地址和大小进入保护模式,不方便用BIOS的软中断,因此引入LBA进行磁盘读取,在加载内核文件时,需要对ELF文件解析,将内核相关数据、代码保存到内存的指定位置,然后跳到指定地址去执行内核代码。原创 2024-08-27 14:54:55 · 602 阅读 · 0 评论 -
引导:boot实现
boot和loader下都有对应的汇编文件。了解计算机启动流程?启动—跳转到BIOS—自检—加载引导代码—引导代码加载操作系统到内核—跳转到操作系统执行BIOS自检完成会检查第0扇区最后两个字节是够是x55, 0xaa,来确认是否包含有效的引导代码。原创 2024-08-27 11:00:58 · 874 阅读 · 0 评论 -
开发环境准备
如前面所述,不要在Ubuntu中的snap工具中安装VSCode,请从微软官网下载安装VSCode。主要原因是snap封装了一个环境。缺省情况下,GCC工具链可通过如下位置点击后选择,但随着VSCode版本升级,其界面也有所变化,所以下面的工具条不一定可见。,点击下载deb包。下载完成后,使用如下命令安装或者双击安装。vscode默认不允许在汇编中设置断点,所以我们需要修改其缺省配置。原创 2024-08-27 09:44:20 · 185 阅读 · 0 评论