关于32位保护模式下的进程调度

前几篇学习笔记非常简短,因为想等现在手头工作差不多了来个总结性大招,但转眼一个月过去了,关于系统在保护模式下的操作实在是“仰之弥高,钻之弥坚”……心累,大招也放不出来了。

这一个月时间里,我主要是依靠这基本书在学保护模式和操作系统,有几本上一篇学习笔记中提到过了,再提一下表达我对作者大大们的谢意。

还有CSDN上的博客,尤其是《30天》的笔记,也给了我很大帮助:http://www.cnblogs.com/bitzhuwei/p/OS-in-30-days-10-programmable-interval-timer.html

*

32位的CPU有32根地址线,所以理论上的最大内存为2^32=4GB(实际上还要连外设所以达不到这么大),不像之前20位地址线的时候只有64MB。为了方便管理内存,避免内存中的程序相互影响而被破坏而设置了保护模式,使得程序只能访问程序事先预设访问的那部分内存。

内存管理的工具是GDT(Global Descriptor Table,全局描述符表),是内存中的一块区域,位置由操作系统开发者给定,GDT的首地址和长度存放在一个寄存器GDTR中。

GDT中的元素是描述符(Descriptor),一个描述符长度为8字节,存放了某一内存段的大小、起始地址和权限。不同描述符描述的内存段可以重合。

每一个段都必须有一个对应的描述符在GDT里,描述符是那个段的名片。

权限有0、1、2、3四个等级,boot和操作系统具有从BIOS哪里继承来的最高等级:0级。用户程序一般是3级(因此用户程序想要调用操作系统的API简直麻烦,需要通过调用门什么的,心累)。

从实模式(也就是8086的模式,BIOS加载完默认的模式)跳转到保护模式需要4步:

1.初始化GDT和GDTR。

2.打开A20地址线。A20地址线是一个历史遗留问题,因为16位的CPU只有A0~A19地址线,这一步的存在是为了兼容在16位CPU上跑的程序。

3.关闭中断。因为16位下的中断向量表和32位下的中断向量表有差别。

4.设置PE位。

OK,接下来所有的段跳转都要遵循32位模式了,不过我们先做一个far JMP,目的是清空流水线,尽管只是跳转到下一句指令。

BOOT的大致作用:

初始化GDT——>读内核——>根据内核头部修改GDT——>跳转到操作系统的入口。

操作系统内核一般分为5个区域,头部、公用例程段、内核数据段、内核代码段、尾部,如下所示:

(图摘自《从实模式到保护模式》)

其中,公用例程段给用户程序提供了系统调用的功能。Printf和中断处理程序都是在这块定义的。

当操作系统要读取并执行一个用户程序时,内代码的大致流程(参考资料为《从实模式到保护模式》):

切换到内核数据段,读取用户程序头部,了解用户程序尺寸和需要的内存数量——>

根据头部信息修改内核数据段的变量——>

调用动态分配内存的程序,动态分配内存——>

切换到0~4GB段,便于对所有内存区域进行操作——>

循环读用户程序到内存——>

分配堆栈地址——>

重写GDT和GDTR,在GDT中加入用户程序的段——>

重定位用户程序内的符号地址——>

出栈(??)——>

选择用户程序段(选择指向用户程序段的头部的选择子)——>

JMP [0X10](用户程序头部0x10处存放了用户程序的入口地址)——>

用户程序返回点——>恢复选择内核自己的核心数据段、堆栈段。

至于“重定位用户程序内的符号地址”这一步,也就是用户程序怎么把调用系统例程,当用户程序的优先级也是0的时候,大致是这么一个思路:

首先,在用户程序的头部做一个表格,就叫“U-SALT”表吧,表里面存放的是一个个系统函数名字符串,比如“@readdisk”、“@printf”……

首先的首先,内核的数据段也有一张对应的表格,就叫“C-SALT”表吧,里面每个元素是“函数名字符串+6个字节的地址表(2个字节的公用例程段的段选择子+4个字节的该程序在公用例程段的偏移地址)”。比如:“@readdisk”+地址。

然后,一一比对U-SALT和C-SALT中的字符串,如果对上了,就把C-SALT中的地址替换掉U-SALT中的字符串。

所以,U-SALT中的每个元素其实是一段特定的空间(比如256字节),那段空间的开头存放了函数名字符串。

以上是建立在用户程序可以访问公用例程段的基础上的,然而,很不幸,用户程序的优先级往往是3,访问不了,这时候,需要用到IDT(Interrupt Descriptor Table,中断描述符表),和一套复杂的升降优先级的过程,日后再说吧,如果我能搞懂的话。

以上主要参考了《实模式到保护模式》,以下将主要参考《30天》,作者把自制的那个操作系统叫做“纸娃娃系统”。《30天》的写作风格和另外两本还是很不一样的,总感觉什么事情到了《30天》这里就变得很容易。

《30天》使用的编译工具是作者自己根据NASM和gcc改的,所以一定程度上简化了编程。至于究竟是怎么改了,改了之后究竟哪里不同,我也不是很清楚。这本书总体上重实践而轻理论,专业名词很少,这是它的缺点和优点,另一个特点就是它很快就引入了图形界面(包括鼠标)和C语言(第3天就引入了)。

目前只不走心地看过前16天,用户进程和系统进程暂时还是放在一个文件里的,因此暂不涉及上文中SALT表的问题。

由于引入了多进程,必须涉及定时器中断,也就是分时系统的实现,需要用到定时器中断。用定时器实现分时系统的方法大概思路如下:

首先要设置定时器,定时器是CPU的外设,是个硬件,引脚地址和设置方法查资料就能得到。比如设定定时器中断时间为10ms中断一次。

然后要设定一些Timer,这些Timer只是软件上的概念,比如每0.1秒切换一次进程。

再然后把Timer按超时时间大小排列在一张链表里,越早到达超时时刻(超时时间越近)就排在前面,越晚到达超时时刻就排在后面。在Timer列表最后再坠上一个“哨兵”,只为了程序上实现的方便。

如此Timer链表设定好了。每次定时器中断到来的时候都先检查Timer链表的第一个Timer有没有超时,如果超时,就执行相应的动作。

15天、16天的“纸娃娃系统”里面跑着4个进程,分了好几个优先级,需要注意的是:这个优先级是纸娃娃系统自己定义的,和前文说到的0、1、2、3优先级没关系,GDT中默认优先级都是0。

此处“纸娃娃系统”定义的优先级又有两个等级,一个是lever,一个是priority,lever档次更高:高lever中的进程运行时,屏蔽所有低lever进程;而同一lever中有好几个priority,priority越高,分到的时间片长度越长。

主进程,也是优先级最高的进程,跑的是键盘鼠标的相应。采用一个FIFO的队列作为键盘和鼠标中断缓冲区,主进程的lever最高,所以当FIFO队列中有数据时,键鼠中断唤醒进程,进程可以得到立即执行,而FIFO中没有数据时,线程自动休眠,将CPU让给低lever的进程。

剩下3个进程跑的程序都是一样的,不同的只是priority,因此有的进程时间片更长,宏观上执行的更快。

由于需要使用多任务,用到了一种结构体TSS(Task State Segment,任务状态段),Intel公司建议,每个任务都有一个TSS,TSS是任务存在的标志,它存储任务的当前时刻几个寄存器的值,尤其是程序寄存器CS和SS的值。

TSS是内存中存在的一个段,所以在GDT中注册有它的位置。

当前正在运行的任务的TSS的地址存放在任务寄存器TR中。

进程切换时,段选择子指向TSS,偏移地址可以是任意值,一般写0000即可,CPU能判断段选择子究竟指向的是一段其他程序还是TSS。在任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到TR所指定的TSS中;然后,下一任务的TSS的选择子被装入TR;最后,从TR所指定的TSS中取出各寄存器的值送到处理器的各寄存器中(摘自紫陌的博客:https://www.cnblogs.com/guanlaiy/archive/2012/10/25/2738355.html)。

然而Linux的对TSS的用法略有不同,不是每个任务一个TSS,TR随着任务切换而改变,而是TR初始化之后就不变了,所有任务共享一个TSS,而任务的信息存放在另一个结构体thread_struct中(参考资料:http://blog.csdn.net/nodeathphoenix/article/details/39269997)

因为理解不深,这篇文章可能有诸多问题,回头再慢慢抿回来就是了。

顺便我越来越觉得写这本书的川合秀实大大是个日本萌妹,但是网上没有他的资料。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,774评论 0 27
  • 本文试图用有限的篇幅来阐述80386保护模式重要知识点。本文不是一个系统全面的知识介绍,您可能需要了解相关的803...
    JeffreyLi阅读 2,091评论 0 10
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,085评论 0 23
  • 嗨小姐每日复盘第八天By趙 每日目标: 1.每日坚持健身1小时以上 2.学习职业相关与心理学相关视频 完成情况: ...
    趙_ac3d阅读 133评论 0 0