现在把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. Android学习笔记之Fast Json的使用

    PS:最近这两天发现了Fast Json 感觉实在是强大.. 学习内容: 1.什么是Fast Json 2.如何使用Fast Json 3.Fast Json的相关原理 4.Fast Json的优势, ...

  2. JS魔法堂:从void 0 === undefined说起

    一.前言 当使用coffeescript书写如下代码时 name = person?.name 会被预编译为 ; ,那么void 0到底是什么意思呢?运行得知void 0===undefined为tr ...

  3. python数据库(mysql)操作

    一.软件环境 python环境默认安装了sqlite3,如果需要使用sqlite3我们直接可以在python代码模块的顶部使用import sqlite3来导入该模块.本篇文章我是记录了python操 ...

  4. 头文件里面的ifndef /define/endif的作用

    c,c++里面,头文件里面的ifndef /define/endif的作用 今天和宿舍同学讨论一个小程序,发现有点地方不大懂······ 是关于头文件里面的一些地方: 例如:要编写头文件test.h ...

  5. C#-INotifyPropertyChanged(解决数据绑定的界面刷新问题)

    最近做项目用到DataGridView,用它绑定数据源后,如果数据源中的数据修改无法及时刷新到控件上,必须切换单元格的焦点才能导致刷新显示新数值,通过查官方文档,用INotifyPropertyCha ...

  6. html5学习笔记4--API Range对象(一)

    Range对象基本用法 效果图如下(在谷歌浏览器下的展示)

  7. Eclipse导入Java项目时“No projects are found to import”错误的处理

    用Eclipse导入Java项目时,经常会出现“No projects are found to import”错误(尤其是导入网上下载的项目时),这是因为文件夹里面没有.project和.class ...

  8. GJM : Taurus.MVC 2.0 开源发布:WebAPI开发教程 [转载]

    Taurus.MVC 2.0 开源发布:WebAPI开发教程 转载自http://www.cnblogs.com/cyq1162/p/6069020.html 因是新手  粘贴时有一个版权问题 本文原 ...

  9. nginx性能优化之线程池

    默认情况下,nginx的work process按照顺序一个个处理http请求,因此如果后台处理时间较长,则work process会长时间等待IO状态,因此限制并发性.如下所示: 所以,对于可能存在 ...

  10. 今天做项目用到框架,关于angual,然后自己整理了一番,自己上网也看了看。

    1. Angular 1.1. 库与框架的区别 jQuery:库 库一般都是封装了一些常用的方法 自己手动去调用这些方法,来完成我们的功能 $('#txt').val('我是小明'): $('div' ...