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

首先是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. Elasticsearch增删改查 之 —— mget多文档查询

    之前说过了针对单一文档的增删改查,基本也算是达到了一个基本数据库的功能.本篇主要描述的是多文档的查询,通过这个查询语法,可以根据多个文档的查询条件,返回多个文档集合. 更多内容可以参考我整理的ELK文 ...

  2. Ajax.ActionLink打开页面之后,表单验证失效

    这两天遇到这个问题搞了很久,原因是验证插件默认是在页面初始化时初始化,ajax调用导致页面不会初始化,所以验证插件也没有初始化.解决方案如下 @Ajax.ActionLink("Edit&q ...

  3. SignalR入门之多平台SignalR服务端

    之前创建SignalR服务端是基于Web应用程序而言的.那么能不能把SignalR服务端做成控制台应用程序.Winform或windows服务呢? 答案是肯定的. 之前尽管看起来好像是IIS和ASP. ...

  4. Exception raised during rendering: java.lang.System.arraycopy([CI[CII)V

    最近下载一个新版本的adt-bundle,Android API是20. 把Plain Text控件往布局上面拖时,发现拖不上去,出现了下面的错误: Exception raised during r ...

  5. line-height 属性

    p.small {line-height:90%} p.big {line-height:200%}     该属性会影响行框的布局.在应用到一个块级元素时,它定义了该元素中基线之间的最小距离而不是最 ...

  6. java servlet上传centos服务器

    前面一篇随笔说了Centos上架设javaWeb运行环境的方法,这篇主要讲打包上传服务器. 一.数据库连接文件.propeties 为了数据库安全,mysql3306端口访问我做了ip访问限制,由于m ...

  7. 基础-WeakReference

    一.概述 为了更好的理解WeakHashMap的原理,我们有必要先来了解一下WeakReference的作用及实现原理.Java中有一个专门的包java.lang.ref,里面定义了我们通常所说的几种 ...

  8. PHP storm快捷键

    左边文件路径看不到了,按alt+1就出来了 ctrl+j 插入活动代码提示 ctrl+alt+t 当前位置插入环绕代码 alt+insert 生成代码菜单 ctrl+q 查看代码注释 ctrl+d 复 ...

  9. 【转】nginx优化 突破十万并发

    一.一般来说nginx 配置文件中对优化比较有作用的为以下几项: 1. worker_processes 8; nginx 进程数,建议按照cpu 数目来指定,一般为它的倍数 (如,2个四核的cpu计 ...

  10. cnodejs社区论坛1--登陆