操作系统基础

209 阅读7分钟

1.1 什么是操作系统

​ 首先我们来看计算机硬件设备的分布 image-20210619004641611

那么有了这些硬件设备,计算机可以干什么呢,计算机可以帮助我们解决很多实际的问题,比如当我们在键盘上输入“hello world”,计算机会帮我们将其展示在显示器上,这里我们给出实现的机制:

image-20210619004659758

但在实际实现的时候,我们只需键入即可,而底层复杂的操作对于用户来说就像一个黑盒子,是不可见的。那这个封装起来的黑盒子是由什么实现的呢,

这里我们先给出结论——操作系统

什么是操作系统

操作系统(Operating System,简称OS)是管理计算机硬件与软件资源的计算机程序。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入设备与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。

下面我们来对定义进行剖析

操作系统管理的计算机硬件都有什么?

  • cpu管理
  • 内存管理
  • 终端管理
  • 磁盘管理
  • 文件管理
  • 网络管理
  • 电源管理
  • 多核管理

而对于操作系统,我们应该做到能改操作系统

1.2 揭开钢琴的盖子

我们不妨把操作系统比作一个钢琴,要弹出美妙的乐曲,我们不仅要了解每个琴键的作用,也要可以打开盖子,通过调整琴弦的粗细长短改变音调。

我们不妨试着打开计算机的盖子,从打开电源的那一刻开始,操作系统的故事就已然开始了——

首先,我们先根据认知猜测一下,打开电源后显示"loading ...",那这些数据是通过怎样的曲折最终发送到显存的呢?开机后,整个IO设备和文件系统都可以用了,是不是在开机时完成的初始化呢,如果是,又做了怎样的初始化呢?

这一切,都要从最核心的思想——冯诺依曼结构谈起。

艺术来源于生活,技术也不例外,计算机说到底就是一个计算模型,当人要计算1+1=2的时候,我们会先将1+1写在纸上,然后大脑运算出结果2,再将其写到纸上。这里,纸就如同一个存储器,而大脑就是运算器,控制器,笔是输入输出设备。很酷对吧,但是1*1=?怎么搞呢?2/2呢,看来这个计算模型还需要存储多种模式,而运算器能识别不同的模式。至此,无龙珠集齐,我们可以召唤神龙——冯诺依曼结构

image-20210619004719586

所谓大道至简,不过如是


2.2操纵系统启动

小小的分割一手,因为以上知识帮助我们在脑海中形成了一个操作系统的最小单元,接下来就要一探究竟了。

计算机对应用程序的处理,也就是取指执行的过程,那么它指向内存何处呢?

  1. X86 PC刚开机时CPU处于实模式,此时CS=0XFFFF,IP=0X0000,寻址到0XFFFFO,也就是ROM BIOS映射区,接着检查RAM,键盘,显示器,软硬磁盘,将磁盘的0磁道0扇区读入0X7C00处,设置cs=0x7c0,ip=0x0000

  2. 为什么要跳转到0X7C00处呢?这块内存区域存储的是什么呢?

    这里存放的是磁盘引导扇区读入的512个字节,也是开机后执行的第一段我们可以控制的程序,操作系统的故事从这里开始........

    image-20210619004735500

    代码很多,我们不追求每句都能看懂,而要抓住核心点——

    这段代码将引导扇区的代码以字节为单位循环加载到CS=INITSEG,ip= GO处,或称段间跳转

    image-20210619004753041

    在bootsect.s中加载load_setup模块,该模块通过中断信号0X13读取到扇区数量,并跳转ok_load_setup模块,

    image-20210619004806578

    在该模块中获取磁盘参数,读取光标位置,循环写入24个字符,并在最后跳转read_it标号,而该标号属于System模块

    image-20210619004820607

    在System模块中,读取磁道,重新回到setup模块执行,CPU进入保护模式,并初始化中断控制,那CPU是如何进入保护模式的呢?自然需要标志寄存器cr0.当PE=1时启动保护模式,PG=1时自动分页,CPU在进入保护模式后,有一个关键跳转,即jmpi 0, 8,这里设置cs=8是用来查询GDT表,即中断向量表。这里我们简单那描述一下GDT表的表项——

    image-20210619004835241

    那么程序计数器PC跳转到了哪呢?那就是关键的System模块,

    image-20210619004851277

    image-20210619004906587

    image-20210619005014321

    开局几张图,剩下全靠编,假装有"字"

    才疏学浅,这几张图以我的水准实在无法给出一个容易理解的答案,等什么时候经过时间沉淀突然悟了,再回来讲述这些汇编背后的故事.........

3.1操作系统的接口

要学习操作系统的接口,我们必须先了解接口是什么,在日常生活中,我们使用插座,油门这种类型的物件,其实就是在使用接口。牛津词典是这样定义接口的:

接口是连接两个东西,屏蔽细节,用于信号转换的

那么什么是操作系统的接口呢?

image-20210619005049553

可见,操作系统接口将上层软件和操作系统连接起来。表面上看用户可以直接与操作系统交互,然而操作系统接口是面对用户的吗?

显然不是,我们通常使用计算机的方式有三种,分别是

  • 命令行

  • 图形化界面

  • 应用程序

    image-20210619005102257

由此可以看出操作系统接口不是面向用户的,这三种方式都归于调用系统常用的C语言函数及普通函数(应用程序接口)来实现。

到这里,我们可以给出操作系统接口一个相对贴近的定义了——

操作系统接口:接口表现为调用,又由系统提供,因而称操作系统接口为系统调用

既然交互的过程是通过函数来实现的,那通常会调用那些函数呢,IEEE组织针对系统调用制定了一个标准族,即POSIX

可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX),是IEEE为要在各种UNIX操作系统上运行的软件,而定义API的一系列互相关联的标准的总称


这里我抛转引玉。简要介绍操作系统实现系统调用的方式。

假设我们在linux0.11中添加一个名称为hello的系统调用,它实现的功能是打印hello,xaiolin。操作系统实现系统调用的基本过程是:

  1. 应用程序调用库函数API
  2. API将系统调用号存入EAX寄存器,然后通过中断调用使系统进入内核态
  3. 内核中的中断处理函数根据系统调用号调用对应的内核函数
  4. 系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数
  5. 中断处理函数返回到API
  6. API将EAX返回给应用程序。

对应的,我们操作的过程是这样的——

  1. 首先参照其他API编写用户接口_syscall1(int,hello)
  2. 接着找到linux0.11目录下的/include/unistd.h文件,在其中添加系统调用号和用户接口声明_syscall1(int,hello),这一步主要是为了补全宏展开以后需要的参数。
  3. 然后就要在kernel/x.c文件中写真正的系统调用函数了,这里调用put_fs_byte循环打印输出,再加入简单的参数判断即可。
  4. 那系统怎么知道系统调用的存在呢?所以还要在include/linux/sys.h文件中加入系统调用声明,即sys_hello(),下一步很自然应该是修改系统调用的总数,使其总数加1。
  5. 到这里,外围的工作就ok了,但要展示效果,还需要编译内核,所以还需要修改MakeFile文件,具体操作是在依赖中添加对应项,最终make file就ok了

好了,回归正题,如何扩展系统调用的参数数量呢?有看到几种方法,但回答的都很简略,想知道具体的实施方法。


日拱一卒,功不唐捐