现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了。

首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段、一个0~4GB的可读写段和一个指向显存开始地址的段:

; GDT
; 段基址 段界限, 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR|DA_32|DA_LIMIT_4K ;0-4G
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW|DA_32|DA_LIMIT_4K;0-4G
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW|DA_DPL3 ; 显存首地址 GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1 ; 段界限
dd BaseOfLoaderPhyAddr + LABEL_GDT ; 基地址 ; GDT 选择子
SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3

在之前学习保护模式时,大部分描述符的段基址都是运行时计算后填入相应位置的,因为那时我们的程序是由BIOS或者DOS加载的,我们不知道段地址,于是也就不知道程序运行时在内存中的位置。

如今,Loader是由我们自己加载的,段地址已经被确定为BaseOfLoader,所以在Loader中出现的标号(变量)的物理地址可以用下面的公式来表示:

标号(变量)的物理地址=BaseOfLoader*10h+标号(变量)的偏移

我们把它以及相应的声明放在load.inc中。

BaseOfLoader	    equ	 09000h	; LOADER.BIN 被加载到的位置 ----  段地址
OffsetOfLoader equ 0100h ; LOADER.BIN 被加载到的位置 ---- 偏移地址 BaseOfLoaderPhyAddr equ BaseOfLoader*10h ; LOADER.BIN 被加载到的位置 ---- 物理地址 BaseOfKernelFile equ 08000h ; KERNEL.BIN 被加载到的位置 ---- 段地址
OffsetOfKernelFile equ 0h ; KERNEL.BIN 被加载到的位置 ---- 偏移地址

我们定义了一个宏BaseOfLoaderPhyAddr用以代替BaseOfLoader*10h,它在loader.asm中被用到一次,用来计算GDT的基址。

运行结果如下:

源码

操作系统开发系列—12.b.从Loader跳入保护模式的更多相关文章

  1. 操作系统开发系列—12.a.从Loader到内核 ●

    Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader ...

  2. 操作系统开发系列—12.c.从Loader加载ELF内核,顺便解释下函数调用过程 ●

    实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_of ...

  3. 操作系统开发系列—12.f.在内核中添加中断处理 ●

    因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*========= ...

  4. 操作系统开发系列—12.e.Makefile

    先来看一个简单的Makefile,我们把它放在目录/boot下,可以用来编译boot.bin和loader.bin. # Makefile for boot # Programs, flags, et ...

  5. 操作系统开发系列—12.d.扩充内核 ●

    现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 exter ...

  6. 操作系统开发系列—12.g.在内核中设置键盘中断

    8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int i ...

  7. 操作系统开发系列—9.Loader

    一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列 ...

  8. 操作系统开发系列—13.a.进程 ●

    进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启 ...

  9. 操作系统开发系列—4.LDT

    一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放 ...

随机推荐

  1. 文本框只读属性,disabled不能提交

    设置文本框和文本域只读的时候用到disabled="disabled",结果后台获取不到,后来想起这个不会提交,应该用readonly

  2. C#--析构函数

  3. C语言学习009:管道连接输入输出

    现在我们需要对gpsdata.csv文件中的数据进行筛选,然后将符合条件的数据输出到output.json文件中,第一种方式当然是在之前的代码中进行修改,但是如果我们不想修改原来的代码就能得到我们期望 ...

  4. 基于MVC4+EasyUI的Web开发框架经验总结(6)--在页面中应用下拉列表的处理

    在很多Web界面中,我们都可以看到很多下拉列表的元素,有些是固定的,有些是动态的:有些是字典内容,有些是其他表里面的名称字段:有时候引用的是外键ID,有时候引用的是名称文本内容:正确快速使用下拉列表的 ...

  5. C# 在异步中使用HttpWebRequest出现的“正在终止线程”错误的解决方案

    最近做接口对接,因需求变化需要用到异步推送信息,就利用委托做了异步. 程序运行过程中时不时出现“正在终止线程”的错误信息,导致两边订单信息不一致,代码如下: byte[] byteData = Enc ...

  6. 【工具】清理Windows Installer冗余文件(支持64位NT6.x系统)

    样子: 支持系统: Windows NT 5.x/6.x 32及64位所有系统.需.net framework 2.0运行环境 功能: 清理上述系统中冗余的Windows Installer补丁文件. ...

  7. Lua使用心得(2)

    在lua脚本调用中,如果我们碰到一种不好的脚本,例如: while 1 do do end 那我们的程序主线程也会被阻塞住.那我们如何防止这种问题呢?下面就给出一个解决的办法. 首先为了不阻塞主线程, ...

  8. ajaxfileupload asp.net 的简单使用

    本人菜鸟,第一次写博客,不会排版,只是记录工作中常用的东西 ajaxfileupload.js源码: http://www.rczjp.cn/HTML/110420/20113620053635.ht ...

  9. Asp.net中使用Server.HtmlDecode(string str)的使用

    前言: 在使用Visual Studio开发web页面时,需要在GridView中绑定Table数据,并加入了CommandField, 试图,点击详情按钮是,获取GridView中Rows中Cell ...

  10. cookies

    Cookie[] cookies=request.getCookies(); for(Cookie c:cookies) out.println(c.getValue()+" ") ...