购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.1.2 设置栈指针

栈是程序正常执行的必备条件,调用函数和返回,创建局部变量等都需要依赖栈,所以在进入内核的时候,必须保证栈已经被正确设置过了。而如果使用C语言做这些工作是比较简单的,所以这里就使用C语言来为内核准备程序栈。

在kernel目录下新建sched.c文件。这个文件的作用是进行进程调度,和进程相关的数据结构和算法都在这个文件中。毫无疑问,栈与进程之间的关系是极其密切的,所以内核程序栈的定义就被放到了这个文件。添加新的文件时,不要忘记修改makefile文件,这里的修改比较简单,就不再单独列出了。

虽然进程到现在为止还没有真正地被引入,但是它的栈、时钟中断等相关的数据结构必须先准备好。栈定义的代码如下所示:

1 #define PAGE_SIZE 4096

2

3 long user_stack[PAGE_SIZE>>2];

4

5 struct

6 {

7   long *a;

8   short b;

9 }stack_start={ & user_stack[PAGE_SIZE>>2],0x10};

在32位编译器上,long类型的长度是4B,所以user_stack的大小是4KB,是一个物理页的大小。stack_start这个结构体是供lss指令使用的,lss会把b的值送入ss寄存器,把a的值送入esp寄存器。这里要注意,初始化a的时候,用的不是user_stack的起始地址,而是它的结束位置。(最后一行,a的值是通过数组的最后一个元素地址初始化的。)这是因为x86的栈是向下增长的,即push指令会使得esp的值减小,所以esp的初始值就应该被设成高地址,而不是低地址。准备好stack_start结构以后,esp的初始化就可以在head.S中完成了:

1   ...

2   lssstack_start,%esp

3   call setup_idt

4   call setup_gdt

5   ...

再次编译执行,虽然看上去操作系统执行的效果没有发生什么变化,但实际上从lss指令开始,它后面的push指令和pop指令操作的都是新的栈了,所以main函数也在新的栈上运行。从现在开始,我们才真正地可以在main函数里实现更多的功能,这才是真正“天高任鸟飞”。

因为sched.c文件是新增的,所以在makefile文件中也必须新增相应的构建命令。这一步的代码比较简单,与main.c文件的做法基本一致,所以这里就不再列出了。接下来,我们还要为正式进入内核开发做更多的准备。 IiB3+PwpLTLKaXHjgENWI3kIiXmW8fylwY6q1nOpJs47Hncc4mj88yoYn5Ghmw2z

点击中间区域
呼出菜单
上一章
目录
下一章
×