006-继续编写操作系统
2017-03-05 16:15
148 查看
上次我们完成了ipl的阶段性目标,现在主要开始着手写操作系统内核。由于在实模式下能够使用的内存实在太少,而且对硬件也而是一种浪费,因此,我们要写一个32位内核的操作系统,所以,就要先进入保护模式。但是,由于在保护模式下不能调用BIOS,因此,要在引入保护模式之前,把可能需要用到的信息保存在内存中。我们指定了一些位置来存放相对应的信息,主要是关于屏幕的信息以及键盘指示灯的信息,代码如下:
接下来就可以向保护模式努力了,不过在此之前,还要先明白很多原理才可以继续接下来的工作。
下面来介绍一下分段,在实模式下,段的设置其实应该是16字节为一段的,因为DS寄存器存储的数据表示段,DS:BX就会把DS的值乘上16再加上BX的值,所以DS的最小单位就是16字节,而在保护模式下,寻址空间为4GB,仅仅利用这样一个16位寄存器是无法表示出来的,所以,将内存划分为了8192个段(用到的是段寄存器的高13位,第14位为0时访问GDT,为1是访问LDT,后两位则是特权选择器),每个段有512个字节,而DS中表示的值,就对应每个段的段号,每一个段号对应一个32位的内存地址,并且还需要4字节来存储其他信息,那这样一个对应关系就需要一张表来储存,所以我们就需要8192×8B=64KB的内存空间来存储这张表,这部分数据就被称为GDT(global
descriptor table),而CPU中会有一个专门的寄存器来存放GDT的地址,这个寄存器就是GDTR,CPU通过GDTR找到GDT,就可以确认当前DS中所表示段号的具体地址,再与其他实际的偏移地址相加,便可以计算出物理地址。
下一个概念是IDT(interrupt descriptor table),和GDT类似,它是用来记录中断的,由于x86结构的CPU最多支持256种中断,因此,IDT的大小也应该是256×8B=2KB。当发生了中断时,CPU将根据IDTR的值找到IDT,然后再根据中断号找到对应的中断处理函数,执行对应的指令。
GDTR是一个48位寄存器,给它赋值时必须从一个内存地址开始的连续6个字节给其赋值,指令是LGDT,其低16位是段上限,高32位表示GDT开始地址。在GDT中,每一个单元需要32位地址、20位段上限、12位段属性。20位上限表示页,每页是4KB,所以一共可以表示4KB×1M=4GB。段属性高4位是拓展访问权,低8位是原始访问权(286就有的)。具体的排布如下图:
IDT与其类似,以下是排布图:
下一个概念是PIC(Programmable Interrupt Controller),即可编程中断控制器。这是用来处理中断的,CPU在高速运转中为了不使低速设备拖后腿,所以使用了中断机制,让它不用自己去持续监听,但总是需要一个设备来做这件事情,这就PIC,它原本是一个独立的芯片,后来被集成在CPU中,通常情况下CPU中会有2个PIC,每个PIC有8个控制端和一个输出端,一个PIC直接连接CPU,另外一个将输出端接入刚才PIC的2号输入口,这样CPU就可以接受15个中断消息了。IMR是中断屏蔽寄存器,这是一个8位寄存器,某位为1表示PIC对应引脚的中断被屏蔽。ICW是初始化控制数据,一共有4个,ICW1~ICW4,1和4是与主板的电器性质相关的(比如说保险丝之类的),所以一般是固定数据。ICW3与主从连接性质有关,而由于硬件线路固定,所以这里一般也是固定值。值得注意的就是ICW2,这个寄存器用来设置中断号,它会给CPU发送消息,而这部分消息会被CPU当做一个int指令来执行,所以也就间接出发了BIOS中断。0x00~0x1f这些中断被保留,作为CPU系统保护通知调用的中断,因此IRQ端口只能设置0x20~0x2f这16个中断。
下次将讲解如何进入保护模式。
CYLS EQU 0x0ff0 LEDS EQU 0x0ff1 VMODE EQU 0x0ff2 SCRNX EQU 0x0ff4 SCRNY EQU 0x0ff6 VRAM EQU 0x0ff8 org 0xc200 ; 这里的org并不是真的可以决定在内存中的加载位置(由ipl决定),而是为了让编译器可以算出正确的标签所代表的内存位置 mov al, 0x13 ; 320×200×8位色 mov ah, 0x00 int 0x10 ; 0x10号中断,ah=0时为VGA显卡图形模式 mov byte[VMODE], 8 mov word[SCRNX], 320 mov word[SCRNY], 200 mov dword[VRAM], 0x000a0000 mov ah, 0x02 int 0x16 ; ah=0x02时获取键盘led灯状态,保存在al中 mov [LEDS], al
接下来就可以向保护模式努力了,不过在此之前,还要先明白很多原理才可以继续接下来的工作。
下面来介绍一下分段,在实模式下,段的设置其实应该是16字节为一段的,因为DS寄存器存储的数据表示段,DS:BX就会把DS的值乘上16再加上BX的值,所以DS的最小单位就是16字节,而在保护模式下,寻址空间为4GB,仅仅利用这样一个16位寄存器是无法表示出来的,所以,将内存划分为了8192个段(用到的是段寄存器的高13位,第14位为0时访问GDT,为1是访问LDT,后两位则是特权选择器),每个段有512个字节,而DS中表示的值,就对应每个段的段号,每一个段号对应一个32位的内存地址,并且还需要4字节来存储其他信息,那这样一个对应关系就需要一张表来储存,所以我们就需要8192×8B=64KB的内存空间来存储这张表,这部分数据就被称为GDT(global
descriptor table),而CPU中会有一个专门的寄存器来存放GDT的地址,这个寄存器就是GDTR,CPU通过GDTR找到GDT,就可以确认当前DS中所表示段号的具体地址,再与其他实际的偏移地址相加,便可以计算出物理地址。
下一个概念是IDT(interrupt descriptor table),和GDT类似,它是用来记录中断的,由于x86结构的CPU最多支持256种中断,因此,IDT的大小也应该是256×8B=2KB。当发生了中断时,CPU将根据IDTR的值找到IDT,然后再根据中断号找到对应的中断处理函数,执行对应的指令。
GDTR是一个48位寄存器,给它赋值时必须从一个内存地址开始的连续6个字节给其赋值,指令是LGDT,其低16位是段上限,高32位表示GDT开始地址。在GDT中,每一个单元需要32位地址、20位段上限、12位段属性。20位上限表示页,每页是4KB,所以一共可以表示4KB×1M=4GB。段属性高4位是拓展访问权,低8位是原始访问权(286就有的)。具体的排布如下图:
IDT与其类似,以下是排布图:
下一个概念是PIC(Programmable Interrupt Controller),即可编程中断控制器。这是用来处理中断的,CPU在高速运转中为了不使低速设备拖后腿,所以使用了中断机制,让它不用自己去持续监听,但总是需要一个设备来做这件事情,这就PIC,它原本是一个独立的芯片,后来被集成在CPU中,通常情况下CPU中会有2个PIC,每个PIC有8个控制端和一个输出端,一个PIC直接连接CPU,另外一个将输出端接入刚才PIC的2号输入口,这样CPU就可以接受15个中断消息了。IMR是中断屏蔽寄存器,这是一个8位寄存器,某位为1表示PIC对应引脚的中断被屏蔽。ICW是初始化控制数据,一共有4个,ICW1~ICW4,1和4是与主板的电器性质相关的(比如说保险丝之类的),所以一般是固定数据。ICW3与主从连接性质有关,而由于硬件线路固定,所以这里一般也是固定值。值得注意的就是ICW2,这个寄存器用来设置中断号,它会给CPU发送消息,而这部分消息会被CPU当做一个int指令来执行,所以也就间接出发了BIOS中断。0x00~0x1f这些中断被保留,作为CPU系统保护通知调用的中断,因此IRQ端口只能设置0x20~0x2f这16个中断。
下次将讲解如何进入保护模式。
相关文章推荐
- FL2440无操作系统应用程序编写测试006——ADC
- 操作系统编写之引导扇区
- 编写我们自己的操作系统-用启动扇区启动我的电脑
- 如何编写一个最简单的嵌入式操作系统(1)简单任务调度
- 对于自己动手编写操作系统的困惑
- 自己编写操作系统的笔记2
- 自己编写操作系统的笔记7
- 编写操作系统的建议
- 编写一个操作系统内核
- 006-编写第一个应用【外部nodejs调用】
- 编写操作系统之键盘交互的实现
- c语言编写的操作系统不会用到类,因为当时c++还没出现
- Linux操作系统的简单指令及如何使用vim编写一个程序,然后使用gcc查看【预处理】、【编译】、【汇编】、【链接】各阶段文件的内容。
- 操作系统 实验一、命令解释程序的编写实验
- 如何编写自己的操作系统(3)
- 从头开始编写一个实时嵌入式操作系统的内核(一)
- 《30天编写自己的操作系统》 关于如何让虚拟机从U盘启动
- 操作系统编写之引导扇区
- 从零开始搭建环境编写操作系统 AT&T GCC (三)引入C语言
- 从零开始搭建环境编写操作系统 AT&T GCC (九)内存管理