一个操作系统的实现(3)

文件系统

文件系统是建立在硬盘上的一个程序,所以由2部分组成:驱动和管理文件系统的进程FS。

首先看一下驱动是如何工作的:

通常,主板上面有2个IDE插槽,分别叫做IDE0/IDE1。每个IDE通道又可以接2个设备。驱动进程的目的就是要隐藏硬件细节,向FS进程提供统一的接口具体到这里,驱动为FS提供的接口就是打开,读取,写入,关闭等接口。下面是硬盘驱动程序:

Task_hd()

{

       Recv(any, msg) //接受任何进程传来的消息

       If(msg == DEV_OPEN)  //如果是打开设备消息,则对硬盘寄存器做一些操作,比如获取硬盘信息等。

       {

              Out_byte(***)   //向硬盘寄存器写入数据

              Recv(interrupt, msg) //阻塞等待硬盘中断发生(表示需要的数据已经得到)

       }

       Send(src, msg) //将获取的硬盘信息返回给发送者进程

}

上面的程序之添加了一个读取硬盘信息的消息,其他比如读取写入数据的消息和这个都是类似的。

有一点需要注意,驱动程序task_hd在读取硬盘信息或者写入数据到硬盘时候的操作其实比上面的情况略微复杂,下面来看一个完成的调用过程:

1 task_fs 文件系统进程 需要操作硬盘,给硬盘驱动进程task_hd() 发送一个msg。

2 假设这时,task_hd()处于空闲状态,即等待在recv(any,msg)处,则会接受这个消息,并向硬盘发送命令。

3 硬盘完成工作后,会触发中断, Recv(interrupt, msg)返回,并给task_fs 文件系统进程发送硬盘数据消息。

4 task_fs 文件系统进程 得到CPU时间时,会收到硬盘数据消息。

 

 

最简单的硬盘驱动看来是告一段落了。下面就可以在此基础上实现一个文件系统,首先需要明白一个文件系统的几个基本要素

1)  有地方存放metadata(一般为硬盘第二个扇区,因为第一个扇区为引导分区)

2)  有地方记录扇区使用情况(位图法)

3)  有地方记录任一文件信息,包括文件名,修改时间,占用哪些扇区等(一个i-node数组,每个元素包含了文件名,属性等信息。同时也需要一个位图来表示i-node数组的使用情况)

4)  文件索引

以后就按照这个方法来组织硬盘结构,创建/删除/写入/读取文件不过是按照这种格式来组织硬盘而已

 

为了实现多系统在硬盘上共存,必须将硬盘划分为多个分区。每个系统占用一个分区。通过一个硬盘的引导扇区可以设置硬盘分区,硬盘最多可以分为4个物理分区。其中每个分区还可以继续划分为多个逻辑分区。

一般Linux的设备分为主设备号和次设备号,主设备号表示不同的物理设备(硬盘,软盘);次设备号表示物理设备上的分区。归纳一下就是:主设备号告诉OS用哪个驱动程序来处理,次设备号告诉驱动程序这是哪个设备。

 

下面看一下硬盘驱动读取和写入数据的过程:

1 首先还是一样task_fs() 文件系统进程通过前面实现的IPC机制将读取(写入)硬盘数据消息发送(即复制)给task_hd()

2 task_hd()

{

       …

       Case:DEV_OPEN //如果某用户进程需要打开一个文件

              为文件内容分配扇区

              分配一个i-node

              分配inode-map

              分配sector-map

              创建文件索引

 

       Case: DEV_READ //读文件

              首先找到将要读取的文件的文件描述符和位置

              根据文件描述符通过驱动获取的该文件在硬盘的具体位置(即i-node)。

              将硬盘内容复制到缓存

}

这一部分写的不是很清楚,理一下思路,我的理解就是硬盘首先有一个文件系统结构(fat32,ntfs,ext2等等),相对于的就有一个硬盘驱动程序用来管理硬盘使用的文件系统并对上层提供文件操作的接口。上层用户需要读取硬盘数据的时候,首先将消息发送给FS,然后FS会将该消息发送给硬盘驱动程序,硬盘驱动程序根据硬盘所使用的文件格式来找到相应的数据并吧数据复制到OS提供的一个缓存中拱用户进程使用。

 

 

                                                        内存管理

到了现在,还没有完成了就是和内存相关的一些东西,首先看看如何创建一个进程(fork),每个shell就是一个子进程。

一个新的进程需要的条件有:

1 代码,数据,堆栈(从父进程复制过来)

2 在进程表中占据一个位置

3 在GDT中有一个位置,指向了该进程对应的LTD,也就是指向了进程的数据和堆栈等

 

看一下linux中fork用法:

First_proc()

{

       Int id = fork();

       If(pid != 0) //这是父进程

       Else 子进程运行

}

父子进程公用一个代码段

 

可以看到,内存管理主要需要在OS中增加2个进程,分别为所有用户的祖先进程(INIT0)和MM进程(memory Management process)。

Init0进程有些特殊,首先一般的进程的虚拟内存空间对用户来说是0-4GB,但是init0的内存在这里大致等于内核占用内存的大小。

Fork的大概步骤如下:

1 用户调用fork

2 通过消息机制发送FORK消息给MM

3 MM主循环完成创建进程的工作,主要流程为:找一个空闲的进程表项作为新进程的进程表项;读取父进程的表示内存占用的LDT,从中取出父进程的代码,数据和堆栈段内存首地址和范围。

3 根据父进程的内存占用情况,分配相同大小的内存给子进程。(分配内存需要注意的就是内存不要重复使用),然后将父进程的内存中的内容复制给子进程。

4 如果父进程有打开文件,要给FS进程发送一个消息来处理父子进程间的共享文件。(FS利用计数器实现)

 

销毁一个进程也差不多,唯一需要注意的就是MM在销毁一个进程的时候,需要首先销毁他的所有子进程。

 

 

 

接下来说明一下几个概念,大多是复制过来的:

CRT:一个应用程序只能调用2种东西:属于自己的函数,以及中断(系统调用就是软中断)。但是实际上,OS还为普通应用程序提供了一个CRT,这个库里面有已经编译好的库函数代码。用户应用程序可以很方便的使用CRT,而免去了很多中断调用。

 

       OS自带应用程序:每个OS都可以附带和安装很多应用程序,简单来说目的就是为了把应用程序从光盘中安装到OS认识的硬盘中并知道位置,这样在需要用时,OS可以自己找到该应用程序。例如,一个最简单的应用程序:

_start

Main(){printf(***);}

把他安装到OS中的步骤大致如下:

1 编译连接该应用程序并打包(设为inst.tar)

2 将打包的应用程序二进制文件写入OS安装盘的某扇区(设该扇区号为X)。

3 启动系统时,在mkfs()创建文件系统时建立一个新的文件cmd.tar,他对应的起始文件扇区号为X。

4 在init进程中,将cmd.tar解压,将其中包含的文件(即为inst.tar)存入文件系统。

 

 

Exec才等同于windows里面的CreartProcess.

First_proc()

{

       Int id = fork();

       If(pid != 0) //这是父进程

       Else 子进程运行

       {

              Exec()   //参数即为新的代码段

       }

}

 

Exec的执行流程:

检查参数个数并将它们依次存放到某连续内存处

向MM发送消息,消息体就是上面存放参数的连续内存。

3 MM消息接收到这个消息,将参数取出(由于exec所在进程和MM不是同一个进程,所有他们的虚拟地址不一样,MM需要通过物理地址复制的方式来获取消息)

根据exec传来的参数,MM将要执行文件复制到自己的缓冲区中

被执行文件是elf格式,MM根据格式将被执行文件的各个段放置到合适的空闲内存中。

建立栈

 

 

OK all done with simplest mode.. 

              2011.1.15 AM8:45  

        i love joliet - teddy_xiong  in ZNUFE

sylar MAIL: cug@live.cn

转载于:https://www.cnblogs.com/xumaojun/p/8544130.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/466465.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言,谁都能看得懂的归并排序

喜欢看排序算法动态效果的,可以看看这个网站https://visualgo.net/zh/sorting里面很多算法的动画解释,可以看到算法的排序效果,而且还附带了伪代码的实现过程。本来想录制几张动图放上来,但是因为图片较大,传不上来&am…

一份详细的服务器安全解决方案

一、操作系统配置 1.安装操作系统(NTFS分区)后,装杀毒软件,我选用的是卡巴。 2.安装系统补丁。扫描漏洞全面杀毒 3.删除Windows Server 2003默认共享 首先编写如下内容的批处理文件: echo off net share C$ /del net share D$ /del net …

GetModuleFileName

GetModuleFileName 获取当前进程已加载模块的文件的完整路径,该模块必须由当前进程加载。如果想要获取另一个已加载模块的文件路径,可以使用GetModuleFileNameEx函数。 声明GetModuleFileName(VB) Declare Function GetModuleFileName Lib “kernel32”…

jQuery load() 中文乱码

1、使用editplus创建了demo.txt (ANSI保存的)&#xff0c; $("#div1").load("demo.txt");//div显示中文乱码--->html5中定义<meta charset"utf-8"/>,编码解码不一致造成中文乱码&#xff0c;将文本文件demo.txt另存为utf-8格式&#xf…

内核链表list.h文件剖析

内核链表list.h文件剖析 一、内核链表的结构【双向循环链表】 内核链表的好主要体现为两点&#xff0c;1是可扩展性&#xff0c;2是封装。可以将内核链表复用到用户态编程中&#xff0c;以后在用户态下编程就不需要写一些关于链表的代码了&#xff0c;直接将内核中list.h中的代…

CAN总线很难吗?CAN总线看不懂是不可能的!

CAN&#xff08;Controller Area Network&#xff09;即控制器局域网&#xff0c;是一种能够实现分布式实时控制的串行通信网络。想到CAN就要想到德国的Bosch公司&#xff0c;因为CAN就是这个公司开发的&#xff08;和Intel&#xff09;CAN有很多优秀的特点&#xff0c;使得它能…

GetDlgItem

GetDlgItemText() GetDlgItemText是C中的函数&#xff0c;调用这个函数以获得与对话框中的控件相关的标题或文本。GetDlgItemText成员函数将文本拷贝到lpStr指向的位置并返回拷贝的字节的数目。 函数说明 CWnd类的成员函数。 函数原型 int GetDlgItemText( HWND hDlg , int n…

开放课程管理系统(Moodle)的介绍(转)

一、虚拟学习环境 关于虚拟学习环境&#xff0c;很难用一个简单的定义来描述。可以说是&#xff0c;支持和管理教与学的各项活动的基于网络的环境。也可以认为是学习管理系统的组成部分。当应用于远程教育时&#xff0c;通常认为它包括“任何用于创造一个统一的、类似于面对面的…

C语言必须写main函数?最简单的 Hello world 你其实一点都不懂!

我们在刚写程序的时候&#xff0c;第一个都是 hello world&#xff0c;而在这里&#xff0c;完整的代码就是&#xff1a;我们打眼一看&#xff0c;其实很简单&#xff0c;就是引入头文件&#xff0c;写一个主函数&#xff0c;然后输出一句话&#xff0c;但是当我们编译出来ELF的…

内核链表使用举例

内核链表使用举例#ifndef _EVENT_LIST_H_ #define _EVENT_LIST_H_#include "list.h" // 内核链表头文件typedef int (*event_cb)(void *data);typedef struct {void *params;event_cb handle;struct list_head list; } event_elem_t;int EventListAdd(event_elem_t *…

CObList

CObList CObList类支持非唯一的CObject指针&#xff0c;并可顺次访问或通过指针值访问有序列表。CObList列表的行为类似于双向链接列表。CObList是非常有用的集合类族的代表&#xff0c;具有诊断转储的特性并且能够包含混合的指针。 POSITION类型的变量为列表的键。使用POSITIO…

源码包安装

一、源码包和RPM包的区别 1、区别 安装之前的区别&#xff1a;概念上的区别 安装之后的区别&#xff1a;安装位置不同 2、RPM包安装位置 是安装在默认位置中 注&#xff1a;安装位置是写RPM包的作者决定的 注&#xff1a;RPM包支持指定安装位置&#xff0c;但是不建议指定位置安…

年轻10岁简单又易行的妙方

爱美的女性&#xff0c;谁不想使自己更年轻&#xff0c;并能留住一份健康的美?我们介绍的方法非常容易实现&#xff0c;只要你能够坚持。想要年轻10岁?没有想象中那么困难,但是也要持之以恒哦!这里推荐的都是价廉易置的)鉴借&#xff0c;愿能给大家有参考之用&#xff1a;1.一…

计算最后一个单词的字符串长度

题目 http://www.nowcoder.com/questionTerminal/8c949ea5f36f422594b306a2300315da 看了大家的答案&#xff0c;觉得还是稍微复杂。给一个比骄简单的解题思路。 只要是空格&#xff0c;就把计数置0&#xff0c;要不然就一直自增。 #include "stdio.h" #include …

strstrsubstr、AfxGetApp

1.strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是&#xff0c;则该函数返回str2在str1中首次出现的地址&#xff1b;否则&#xff0c;返回NULL。 2.substr是C语言函数&#xff0c;主要功能是复制子字符串&#xff0c;要求从指定位置开始&#xff0c;并具有…

Linux下修改SSH登录端口

Linux下修改SSH登录端口LINUX 的默认SSH 端口是 22。为了防止别人暴力破解&#xff0c;建议修改SSH 访问端口&#xff1a;vim /etc/ssh/sshd_config 找到Port 22 这一行&#xff0c;这是是默认端口22&#xff0c;现在改成Port 1234这个数字自己定&#xff0c;但是不要超过65536…

五岁的时候,你在干什么?

文章写在2021.2.7号——想不到啊想不到&#xff0c;这么快你就五岁了。今天是楠哥的生日&#xff0c;在五年前的今天&#xff0c;小伙子在深圳宝安妇幼出生&#xff0c;刚出生的时候&#xff0c;样子很丑&#xff0c;第一次见面&#xff0c;我心情很紧张&#xff0c;不怎么敢靠…

GetLocalTime

GetLocalTime是一个Windows API 函数&#xff0c;用来获取当地的当前系统日期和时间。 函数原型: VOID GetLocalTime( LPSYSTEMTIME lpSystemTime //address of system times structure ); 参数说明: lpSystemTime: 指向一个用户自定义包含日期和时间信息的类型为 SYSTEMTIME 的…

Java集合(7):散列与散列码

散列的价值在于速度。我们使用数组来保存键的信息&#xff0c;这个信息并不是键本身&#xff0c;而是通过键对象生成一个数字(散列码)&#xff0c;作为数组下标。由于数组的容量是固定的&#xff0c;而散列容器的大小是可变的&#xff0c;所以不同的键可以产生相同的数组下标(散…

301转向代码合集

教育资源网将SEO工作中所需要的301转向代码进行了整理&#xff0c;收藏并分享&#xff0c;以备查阅。 1、IIS下301设置 Internet信息服务管理器 -> 虚拟目录 -> 重定向到URL&#xff0c;输入需要转向的目标URL&#xff0c;并选择“资源的永久重定向”。 2、ASP下的301转向…