操作系统开发系列—4.LDT】的更多相关文章

一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放到LDT中. 和GDT一样,LDT也是用来存放描述符的.不同之处在于,LDT只属于某个任务.或者说,每个任务都有自己的LDT,每个任务私有的段,都应当在LDT中进行描述.另外,LDT的第1个描述符,也就是0号槽位,也是有效的.可以使用的. [SECTION .gdt] ; GDT ; 段基址, 段界…
上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A."); milli_delay(300); } } void TestB() { int i = 0x1000; while(1){ disp_str("B."); milli_delay(900); } } void TestC() { int i = 0x2000; while(1){…
在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是应用程序和操作系统之间的桥梁. 所以,一件事情就可能是应用程序做一部分,操作系统做一部分.这样,问题就又涉及特权级变换. 很明显,这已经难不倒我们了,因为进程的切换就是不停地在重复这么一个特权级变换的过程.在那里,触发变换的是外部中断,我们把这个诱因换一下就可以了,变成"int nnn",…
进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态就可以了. 在main.c中进程A的代码的下面添加进程B: void TestB() { int i = 0x1000; while(1){ disp_str("B"); disp_int(i++); disp_str("."); delay(1); } } 打印的字母…
进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启动的时候,这个信息重新被读出来. 在很多情况下,进程和进程调度是运行在不同的层级上的.这里本着简单的原则,我们让所有任务运行在ring1,而让进程切换运行在ring0. 诱发进程切换的原因不只一种,比较典型的情况是发生了时钟中断.但并非在每一次时钟中断时都一定会发生进程切换,不过这里为了容易理解和实…
因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*======================================================================* init_8259A *======================================================================*/ PU…
一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列工作,如果全都交给引导扇区来做,512字节很可能是不够用的,所以不妨把这个过程交给另外的模块来完成,我们把这个模块叫做Loader.引导扇区负责把Loader加载入内存并且把控制权交给它,其他工作放心地交给Loader来做,因为它没有512字节的限制,将会灵活得多. 为了操作方便,把软盘做成FAT12格式.这…
org 07c00h ;伪指令,告诉编译器程序会被加载到7c00处 mov ax, cs mov ds, ax mov es, ax call DispStr ;调用显示字符串例程 jmp $ ;无限循环 DispStr: mov ax, BootMessage mov bp, ax ;ES:BP=字符串地址 mov cx, 22 ;CX=字符串长度 mov ax, 01301h ;AH=13,AL=01h mov bx, 000ch ;页号为0(BH=0)黑底红字(BL=0Ch,高亮) mov…
计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是65535,因此,默认的时钟中断的发生频率就是1193180/65536约等于18.2HZ. 我们可以通过编程来控制8253.因为如果改变计数器的计数值,那么中断产生的时间间隔也就相应改变了. 比如,如果想让系统每10ms产生一次中断,也就是让输出频率为100HZ,那么需要为计数器赋值为1193180/1…
我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++); disp_str("."); delay(1); } } 然后在global.c: PUBLIC TASK task_table[NR_TASKS] = {{TestA, STACK_SIZE_TESTA, "TestA"}, {TestB, STACK_SIZE…