现在把esp、GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编。

下面看切换堆栈和GDT的关键代码:

; 导入函数
extern cstart ; 导入全局变量
extern gdt_ptr [SECTION .bss]
StackSpace resb 2 * 1024
StackTop: ; 栈顶 ; 把 esp 从 LOADER 挪到 KERNEL
mov esp, StackTop ; 堆栈在 bss 段中 sgdt [gdt_ptr] ; cstart() 中将会用到 gdt_ptr
call cstart ; 在此函数中改变了gdt_ptr,让它指向新的GDT
lgdt [gdt_ptr] ; 使用新的GDT

最后这4个语句完成了切换堆栈和更换GDT的任务。StackTop定义在.bss段中,堆栈大小为2KB。

PUBLIC	void*	memcpy(void* pDst, void* pSrc, int iSize);

PUBLIC	void	disp_str(char * pszInfo);

PUBLIC	u8		gdt_ptr[6];	/* 0~15:Limit  16~47:Base */
PUBLIC DESCRIPTOR gdt[GDT_SIZE]; PUBLIC void cstart()
{ disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
"-----\"cstart\" begins-----\n"); /* 将 LOADER 中的 GDT 复制到新的 GDT 中 */
memcpy(&gdt, /* New GDT */
(void*)(*((u32*)(&gdt_ptr[2]))), /* Base of Old GDT */
*((u16*)(&gdt_ptr[0])) + 1 /* Limit of Old GDT */
);
/* gdt_ptr[6] 共 6 个字节:0~15:Limit 16~47:Base。用作 sgdt/lgdt 的参数。*/
u16* p_gdt_limit = (u16*)(&gdt_ptr[0]);
u32* p_gdt_base = (u32*)(&gdt_ptr[2]);
*p_gdt_limit = GDT_SIZE * sizeof(DESCRIPTOR) - 1;
*p_gdt_base = (u32)&gdt;
}

函数首先把位于Loader中的原GDT全部复制给新的GDT,然后把gdt_ptr中的内容换成新的GDT的基地址和界限。SGDT——保存全局描述符,gdt_ptr[2]的值本身就是个地址,所以前面带上(void*)表示是个指针。memcpy之所以用void*,是因为需要一个字节一个字节复制。

编译:

nasm boot.asm -o boot.bin

nasm loader.asm -o loader.bin

nasm -f elf -o kernel.o kernel.asm

nasm -f elf -o string.o string.asm

nasm -f elf -o kliba.o kliba.asm

gcc -m32 -c -fno-builtin -o start.o start.c

----

dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc

sudo mount -o loop a.img /mnt/hgfs/

sudo cp loader.bin /mnt/hgfs/ -v

sudo umount /mnt/hgfs/

----

ld -m elf_i386 -s -Ttext 0x30400 -o kernel.bin kernel.o string.o start.o kliba.o

sudo mount -o loop a.img /mnt/hgfs/

sudo cp kernel.bin /mnt/hgfs/ -v

sudo umount /mnt/hgfs/

运行结果如下:

源码

操作系统开发系列—12.d.扩充内核 ●的更多相关文章

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

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

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

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

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

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

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

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

  5. 操作系统开发系列—12.b.从Loader跳入保护模式

    现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ...

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

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

  7. 操作系统开发系列—10.内核HelloWorld ●

    a.我们先来体验一下在Linux下用汇编编程的感觉,见代码 [section .data] ; 数据在此 strHello db "Hello, world!", 0Ah STRL ...

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

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

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

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

随机推荐

  1. .net后台模拟浏览器get/post请求

    #region 后台模拟浏览器get/post请求 /// <summary> /// 发送请求方式 /// </summary> /// <param name=&qu ...

  2. .net using使用小结

    在.net中using使用方法有3种,分别是using指令.using定义使用范围.using别名. using指令,即引用命名空间. using System; using System.Colle ...

  3. 总结消息队列RabbitMQ的基本用法

    一.RabbitMQ是什么? AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组 ...

  4. ios基础之 view的frame 与 bounds 的区别 (转)

    前言: 学习ios开发有一段时间了,项目也做了两个了,今天看视频,突然发现view的frame和bound两个属性,发现bound怎么也想不明白,好像饶你了死胡同里,经过一番尝试和思考,终于弄明白bo ...

  5. 一个有意思的js小问题

    问题:如何实现以下函数? add(2, 5); // 7 add(2)(5); // 7 第一个就不用说了,很简单,关键是看第二个,add(2)(5),可见add(2)应该返回的是一个函数,这个函数再 ...

  6. how-to-redirect-cin-and-cout-to-files

    #include <iostream> #include <fstream> #include <string> void f() { std::string li ...

  7. objective-c NSMutableAttributedString

    NSMutableAttributedString 是一个很强悍的富文本处理字符串,可以方便的实现一个字符串中某个字符的样式处理.我把我下面代码实现的功能步骤说一下:首先拼接两个字符串,然后给前前半部 ...

  8. 使用maven profile实现多环境可移植构建(转自CSDN)

    使用maven profile实现多环境可移植构建 标签: maven profilemaven自动构建maven自动部署maven可移植构建持续集成 2014-04-25 23:37 26905人阅 ...

  9. Linux CentOS 6.6安装JDK1.7

    Linux CentOS 6.6安装JDK1.7 目录 1.下载JDK 2.卸载JDK 3.安装JDK 3.1..rpm后缀格式JDK安装方式 3.2..tar.gz后缀格式JDK安装方式 4.验证安 ...

  10. # 关于Apache的25个初中级面试题

    注:本文从自己的Markdown博客复制出,除标题字体加粗.代码风格改变.图片重新上传外其余均为markdown语法. 标签(空格分隔): LAMP --- 原文:[关于Apache的25个初中级面试 ...