Skip to content

GKLuestc/microKernel

Repository files navigation

于2024.7-2024.9完成6.828课程的学习与代码实现,对操作系统有了更深刻的认识和了解。极大的满足了对操作系统的好奇心,后续进行linux源码学习,也能打下基础。并且对后续的网络学习,数据库学习都有帮助。对实现原理感兴趣的,一定不能错过。😎

6.828课程链接:https://pdos.csail.mit.edu/6.828/2018/schedule.html 英文不好的同学也可以参考中文翻译:https://github.com/jacksonwuu/MIT-6.828-zh

介绍一下每章的大致内容:

lab1 BIOS、boot、kernel,操作系统的引导与启动

lab1的内容分为三个部分:

  • part1 简单介绍了汇编语言,物理内存地址空间,BIOS。
  • part2 介绍了BIOS从磁盘0号扇区读取 boot loader 到 0x7c00 处,并将 cs:ip 设置为 0x7c00。之后boot loader主要完成: a.创建两个全局描述符表项(代码段和数据段),然后设置CR0进入保护模式; b.从磁盘1号扇区读取4KB到0x10000处,并且识别kernel的ELF文件,加载内核各个段到指定位置。
  • part3主要介绍进入内核后的一些操作: a. 首先会统计可用内存,形成空闲内存链表,制作内核页目录,并且配置CR3开启分页模式。 b. 格式化输出字符串的原理。本质还是往物理内存0xB8000起始的显存写数据。 c. 函数调用过程,即栈区的压栈,弹栈,本质上是esp和ebp的跳转。

lab2 虚拟内存映射

lab2讲的是操作系统的内存管理,从内容上可用分为三个部分:

  • part1 物理内存管理,要进行内存管理首先需要知道哪些物理内存是空闲的,哪些是被使用的。还需要实现一些函数对物理内存进行管理。
  • part2 虚拟内存。一个虚拟地址(逻辑地址)如何被映射到物理地址,将实现一些函数来操作页目录和页表从而达到映射的目的。
  • part3 内核的地址空间。将结合 part1 和 part2 的成果,对内核地址空间进行映射。

lab3 用户环境(进程)管理

lab3主要介绍 JOS 操作系统中对进程,异常处理,系统调用。也是分为三个部分:

  • part1 用户环境建立,可用加载 ELF 文件并且执行。(目前还没有文件系统,只能在内核硬编码需要加载的用户程序,即用户程序必须和内核一起编译)
  • part2 建立异常处理机制,异常发生时能从用户态进入内核态进行处理,处理完成返回用户态。(其中涉及GDT权限管理,TSS栈区切换)。
  • part3 借助异常处理机制,提供系统调用的能力。

3.1 创建加载进程

在创建用户进程的时候,需要将用户进程的页目录继承内核页目录,从而实现用户空间对内核空间的隔离,并且为用户态到内核态的转换提供了基础。

3.2 处理中断和异常

异常和中断都是 “受保护的控制转移”,会使得处理器从用户态安全切换到内核态,并且不会给用户态代码提供干扰内核或其他环境的机会。

lab4 进程的创建、调度与通信

lab4 主要围绕进程相关概念进行介绍,主要有四个知识点:

  • part1 开启多处理器MP。这样每个CPU都能同时允许不同进程,实现真并行。并且需要用到锁来解决多CPU对内核临界区资源的访问。
  • part2 实现了简单的进程调度算法,原课程中实现了时间片轮转,本文修改添加了优先级的概念。
  • part3 允许用户注册缺页处理函数,通过系统调用实现,可以使用此能力实现写实拷贝技术COW。
  • part4 实现了一种简单的进程间通信(IPC),通过实现IPC_recv 和 IPC_send,最多交换的资源为一个页面大小,将页面起始地址放在eax寄存器中(事先规定)。后续的文件服务和网络服务,可以通过IPC实现一种简单的RPC调用。

lab5 文件系统

lab5 主要介绍了文件系统,由于 JOS 是一种微内核,有别于现代操作系统。JOS只负载内核最基本的功能,资源申请,进程创建于调度,中断与异常的处理等。所以文件系统和网络服务,都设计为一种服务进程,用户进程通过IPC与其通信,基于预设的指令(一种union联合体)来实现 RPC 调用。这种设计模型的缺点就是,效率异常低下,一次文件查询,需要经过多次用户态与内核态切换,优点是结构简洁方便初学者学习。 这一章内容,主要可以划分为4个部分:

  • part1 引入一个文件系统进程(FS进程)的特殊进程,该进程提供文件操作的接口。
  • part2 建立RPC机制,用户进程向 FS 进程发送请求,FS进程真正执行文件操作,并将结果返回给用户进程。
  • part3 引入了文件描述符(fd)这一更高级的抽象。fd 相当于是对IO文件的本体,操作接口的一种句柄,高度抽象化的体现(可以理解为从大量的看似不相关的机制中,提取出的公共特征,大道至简!)。通过 fd 可以将控制台,pipe,普通文件,外部设备统统按照文件来对待(因为他们都具有 IO 特性)。
  • part4 支持从磁盘加载程序运行,本质上是fork一个子进程,然后execv替换进程的各个段。

lab6 网络服务

lab6围绕网络展开。已经实现了一个具有基础功能的内核,来试试联网吧。但是网络驱动的编写非常复杂,从以太网,IP,到TCP/UDP通信的驱动。所以本章引入了一个在嵌入式中常用的网络驱动库,lwIP,实现轻量化网络服务。提到了3个比较重要的部分:

  • part1 内存映射IO。
  • part2 DMA技术(做过嵌入式的话应该不陌生)。
  • 用户级线程(协程)的实现,当一个用户服务请求发送到网络服务进程,网络服务进程会初步解析任务,之后创建一个协程去负责具体的任务处理,类似于实现了异步操作,防止主进程被请求任务阻塞,导致并发能力下降。

6.1 用户级线程

JOS 采用的线程,是为了实现网络服务的并发。无论是进程还是线程,对操作系统来说都是一个可以调度的单位,具有代码段,数据段,栈区,堆区等。线程本质上只拥有自己独立的栈区,其他部分都是共享的父进程。那么用户是不是也可以创建一块栈区,使其成为一种用户级线程。当然可以,但是这种创建的协程无法被调度,因为涉及到底层资源的控制,例如CPU寄存器,用户进程是没有这个权限的,所以需要内核来提供相应的系统调用,辅助用户进程实现协程的创建,切换等。 在现代操作系统中,实现协程,主要通过:

  • getcontext(ucontext_t *ucp)
    作用:获取当前线程的上下文,并将其存储在 ucp 指向的 ucontext_t 结构体中。
  • setcontext(const ucontext_t *ucp)
    作用:设置当前线程的上下文为 ucp 指向的上下文。这个调用会立即切换到指定的上下文。
  • makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
    作用:为 ucp 指向的上下文设置执行函数 func 和参数。
  • swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
    作用:保存当前线程的上下文到 oucp 指向的结构体中,并切换到 ucp 指向的上下文。

About

MIT6.828课程的学习代码

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •