linux0.11源码分析第四弹——操作系统的框架代码
🚀 前言
本文只是介绍操作系统的框架代码,包括边界计算与设备信号获取,各种初始化,进入用户态,陷入死循环,整个操作系统核心的就是做了这四件事。希望各位给个三连,拜托啦,这对我真的很重要!!!
目录
- 🚀 前言
- 🏆 参数的取值和计算
- 🏆 初始化
- 🏆 切换用户态
- 🏆 死循环
- 🎯总结
- 📖参考资料
🏆 参数的取值和计算
首先是参数的取值与计算,下面代码展示了计算了那些东西
void main(void) /* This really IS void, no error here. */
{
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
if (memory_end > 12*1024*1024)
buffer_memory_end = 4*1024*1024;
else if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
main_memory_start = buffer_memory_end;
...
}
拆分来看,首先是前两行,是获取了根设备ROOT_DEV
以及之前汇编中获取的设备参数信息drive_info
,获取方式如下:
#define DRIVE_INFO (*(struct drive_info *)0x90080)
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
回顾一下内存的情况:
这里面在0x90000处有块地方存放的临时变量,具体可参考linux0.11源码分析第二弹——setup.s内容第一节,存放的顺序和地址如下:
依据这个图就可以看到代码中设置根设备号在0x901FC
以及设备参数信息从0x90080
开始的原因了。
之后就是划定边界,这部分在下一篇博客细说,这里看看就好。
🏆 初始化
在完成设备信息以及根设备号的获取后,需要进行一系列初始化,包括内存初始化,中断初始化,块设备请求项初始化,控制台初始化,时间初始化,进程调度初始化,缓冲区初始化,硬盘初始化等,代码如下所示:
void main(void)
{
...
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
...
}
🏆 切换用户态
在CPU指令中,有些指令很危险,如果错用将导致系统崩溃,所以CPU将指令分为特权级指令和非特权级指令。操作系统启动时对内存进行了划分,操作系统的数据都是存放于内核空间的,用户进程的数据是存放于用户空间的。处于用户态级别的程序只能访问用户空间,而处于内核态级别的程序可以访问用户空间和内核空间。说白了目的就是划分权限为了保护操作系统。
void main(void)
{
...
sti();
move_to_user_mode();
if (!fork()) { /* we count on this going ok */
init();
}
...
}
到此处会出现熟悉的终端界面(bochs进行模拟):
🏆 死循环
最后就是死循环,让操作系统一直执行。
void main(void)
{
...
for(;;) pause();
}
🎯总结
本节内容较少,主要就是梳理了一下操作系统的代码框架,整个操作系统都做了哪些事情,具体的东西会在后面博客有所讲解
📖参考资料
[1] linux源码趣读
[2] 一个64位操作系统的设计与实现