自己动手操作系统一书的总结

news/2024/7/20 14:00:32 标签: 操作系统, 数据结构与算法, 内存管理

Orange 总结

Orange分为Boot部分,load部分和内核kernel部分:

具体内存分布如下图所示:

系统启动2011052216534887.png过程:bios加载boot部分(512byte)于内存7c00h处并跳转到7c00h处开始执行,boot部分代码负责将load部分加载于内存9000h处并跳转到那里。Load部分代码加载kernel然后控制权交给kernel。

每个部分的具体细节:

Boot部分:通过在软盘中找到load.bin所在位置,并且将其拷贝到9000h处,最后跳转到那里(具体技术包括对fat12文件系统结构的理解和对磁盘读写方法);

Load部分:

  1. 通过在软盘中找到kernel.bin所在位置并将其拷贝到80000h处;
  2. 然后开启保护模式和分页机制;
  3. 然后又将位于80000h处的kernel.bin拷贝到30000h处,并且设置kernel.bin

的入口为30400h(这里需要了解elf文件的结构);

Kernel 部分

1.由于以前的堆栈和gdt在load部分定义,故需要将其切换到内核中;(由cstart函数完成)

2.添加中断处理:(不可屏蔽中断和8259的几个外部中断),先初始化8259,比如设置8259主从片对应的中断号等等,建立idt,将中断处理程序与idt联系起来;(由cstart中的init_prot函数完成)

3.多进程处理(kernel_main函数):进程准备工作有:tss和gdt在gdt里面的初始化,加载tss,初始化进程结构体(包括进程的cs,ip,ss,sp等进程对应的ldt的内容及其属性的初始化,等等)进程开始运行时已经将进程结构体末端地址保存于tss中;

                               进程的运行和调度:初始化时钟中断,进程调度函数是时钟中断处理函数,进程切换函数是restart;从用户程序进入中断(也就是将要发生进程调度):先从tss中获取sp(为进程结构体的末端),然后将ss,sp,cs,eflags,ip等压栈(也就是压入进程结构体中),进入save函数保存进程上下文(保存在进程结构体中),然后切换堆栈到内核栈,进入时钟中断函数,从时钟中断函数返回后又进入进程切换函数restart,最后完成了进程的切换。

  1. 系统调用添加(类似于进程调度函数):将一个中断对应于系统调用,找到通用系统调用处理函数(进入中断),然后跟上面一样保存相应的进程上下文信息,根据系统调用号进入相应系统调用内核程序,最后返回到用户进程(返回值存放于eax中)。
  2. 输入输出系统:处理键盘中断(进扫描码存入缓冲区),从缓冲区读出键盘扫描码并解析,最后打印出来,对显示器
  3. 进程间通信(间接实现微内核模式),就是通过sendrec这个系统调用实现,然后通过msg_send和msg_receive这两个内核api完成了内核的通信,在进程表中有所有发送消息给此进程的链表队列,然后将一个任务进程(rpl=1)的处于无限循环中来接受用户进程的消息,然后作相应的处理后返回相应的信息(这就是系统调用的过程)。
  4. 文件系统:

磁盘驱动:发送命令(hd_cmd_out),然后等待磁盘准备好的中断interrupt_wait,然后在磁盘端口进行相应的读写操作

文件系统结构:

特征:仅有一个文件夹(‘/’),root区即该文件的内容,每个文件所占扇区大小确定,而且是连续扇区

boot sector:第0个扇区,引导扇区

superblock:超级快,第1个扇区,超级快记录了inode和sector(扇区)个数,

inode map区 :第2个扇区,记录inode个情况,第一位保留,可以记录的inode=512*8-1

sector map区:记录扇区的使用情况,第1为保留,所占的扇区数=总扇区数/(512*8)+1.(注意sector开始从root区记录扇区的使用情况,而且第一位保留)

inode区:记录文件大小,起始扇区,等等信息(本文件系统中每个文件最大大小确定,而且文件存储在连续的扇区中)inode所占的扇区大小=512*8*sizeof(inode)/512=8*sizeof(inode)

数据区:

root区:也就是文件夹’/’的内容,跟一个普通文件一样,占固定大小扇区,内容就是一个个文件的目录项(包括inode号和文件名)

其他文件存储区:其他普通文件存储区域

读取一个文件内容的过程:提取文件的文件名(没有前缀),从root区找到文件的inode号,从inode读取文件信息(起始扇区,文件大小等等),然后根据文件信息读取文件内容.

文件系统中几个全局变量:

struct file_desc

{

int              fd_mode; /**< R or W */

int              fd_pos;              /**< Current position for R/W. */

struct inode*   fd_inode; /**< Ptr to the i-node */

};

进程表中指向打开文件的指针数组struct  file_desc* flip[];全局变量struct  file_desc

f_desc_table[],每个数组成员代表一个打开文件,则其fd_inode不为空指针。而flip的每个数组成员正好指向f_desc_table的一个成员;还有个全局变量inode_table[],而f_desc_table中的fd_inode正好指向这个inode_table数组成员。

打开文件过程可以更具体描述为:根据文件名找到inode号,根据inode号从inode_table中查找,如果inode_table中有,则不需要从硬盘中读取,否则需要从硬盘中读取inode,

然后将上面几个数据结构建立关系,这样就一个文件打开了。

  1. 内存管理:(fork和exec两个系统调用的实现)

Fork:完全复制父进程的所有,具体过程如下:

进程表初始化的修改:修改init进程地址空间(以前是4g,现在修改成小于1mb的合适大小的),将所有的进程表元素(尽管有些进程表元素标记为未用)的全局描述符初始化(就是在全局描述符中填充相应进程的局部描述符的信息);

  1. 从进程表数组中找到一个空闲的元素,分配给子进程,对子进程表中的相关数据初始化(比如父进程id);
  2. 获取父进程的代码段和数据段的信息(包括段的开始地址,段界限,粒度)
  3. 将其完全进行拷贝(先在一个给定地址开始分配1mb内存给新进程),然后将其拷贝到新的大小为1mb地址处(仅需要拷贝1次,因为代码段和数据段占用相同的地址空间)
  4. 由于子进程的地址空间已经改变,故需要重新填写其相应局部选择子
  5. 具体怎么让程序分别跳到父进程和子进程运行,对于父进程,由于父进程先发

Send后发receive消息,而do_fork函数返回后像父进程发送了send消息,故父进程可以继续运行,但返回值是0,而对于子进程,由于完全复制父进程,所以其就是将执行receive消息(因为send时已经进入中断,父进程上下文被保护,然后do_fork函数被调用,然后就是子进程被创建进入就绪状态);最后do_fork函数最后向子进程发送消息(包含子进程的id).

进程地址空间切换要注意的问题:由于只有init以及其子进程所占用的进程地址空间大小为1mb,所以一段程序进入中断后,其进程地址空间就是原来内核的进程地址空间(也就是4gb大小的).

Exec系统调用实现:将文件(可执行文件,且有_start标识符开始,这样以便编译器识别)存取在硬盘指定扇区位置,然后操作系统启动时读取文件,然后以文件系统格式存放在硬盘中,然后根据文件名将文件内容读出来覆盖原有的进程地址空间,这样可执行文件就被拷贝到相应的进程地址空间中,然后设定相应的堆栈地址和入口地址(设置进程表的寄存器值),一旦进程被调度,则程序就可以运行起来.

转载于:https://www.cnblogs.com/zhouprogram/archive/2011/05/22/2053668.html


http://www.niftyadmin.cn/n/1850951.html

相关文章

电池容量足够低如何触发自动关机(Riogrande platformQualcom platform)

1. 进入手机/sys/devices/platform/nmk-i2c.2/i2c-2/2-0040/leds/ 或 sys/class/leds/目录list如下 pwr-red&#xff0c;pwr-green&#xff0c;pwr-blue //控制充电led l-key-red&#xff0c;l-key-green&#xff0c;l-key-blue //控制left button led m-key-…

asp.net关掉缓存

Response.Buffer true;Response.ExpiresAbsolute DateTime.Now.AddDays(-1);Response.Cache.SetExpires(DateTime.Now.AddDays(-1));Response.Expires 0;Response.CacheControl "no-cache";Response.Cache.SetNoStore()

[转]OOA/OOD/OOP区别

这是一个故事: "工程師修了一條隧道,隧道的一端就是美麗的風景,很多人會開車通過隧道.雖然隧道內已經有燈了,但是設計者擔心隧道可能會停電,所以在隧道的入口立了牌子,提醒駕駛員進入隧道前開燈.可是由此却使得駕駛員由於看到美麗的風景而忘記關燈的情況的發生." 引来…

vue图片压缩(不失真)

1.在index.html中引入mobileBUGFix.min.js // mobileBUGFix.min.js内容见最下面附件 2.在build/webpack.base.conf.js文件中增加&#xff1a; module.exports {externals: {MegaPixImage: MegaPixImage,JPEGEncoder: JPEGEncoder} } 3.新建compressImage.js&#xff0c;内容如…

Linux系统内核抢占补丁的原理(代码)

CPU在内核中运行时并不是处处不可抢占的&#xff0c;内核中存在一些空隙&#xff0c;在这时进行抢占是安全的&#xff0c;内核抢占补丁的基本原理就是将SMP可并行的代码段看成是可以进行内核抢占的区域。 Linux 2.4内核正好细化了多CPU下的内核线程同步机构&#xff0c;对不可…

Linux驱动修炼之道-INPUT子系统(上)

Linux驱动修炼之道-INPUT子系统(上) 努力成为linux kernel hacker的人李万鹏原创作品&#xff0c;为梦而战。出处 http://blog.csdn.net/woshixingaaa/archive/2011/05/19/6431094.aspx 内核的输入子系统是对分散的&#xff0c;多种不同类别的输入设备(如键盘&#xff0c;鼠标…

iphone知识汇总

//Label设置换行 label.lineBreakMode UILineBreakModeWordWrap; label.numberOfLines 0; 每日分享 &#xff0d; Locale Util 取得当前的国家和语言设定 复制代码 #import <Foundation/Foundation.h> interface LocaleUtils : NSObject { } (NSString *)getCoun…

selenium 代码常见报错

报错 selenium.common.exceptions.WebDriverException: Message: unknown error: call function result missing value 分析原因&#xff1a; 由于chromedriver.exe没有加入到环境变量&#xff0c;导致报错 解决方法&#xff1a; webdriver.Chrome(r位置chromedriver.exe)转载于…