8)main
main
在完成了前面的所有准备后,进入了操作系统核心代码,继续跟随着《Linux源码趣读》,对main函数一天探究竟:
1 |
|
第一部分:参数取值与计算
1 |
|
包括根设备 ROOT_DEV,之前在汇编语言中获取的各个设备的参数信息 drive_info,以及通过计算得到的表示内存边界的值:
- main_memory_start、main_memory_end
- buffer_memory_start、buffer_memory_end
设备参数信息是 setup.s 这个汇编程序调用 BIOS 中断获取的各个设备的信息,并保存在约定好的内存地址 0x90000 处。
第二部分:初始化
1 |
|
这段代码非常规整,但需要逐个击破,因为每一个 init 都可能包含着操作系统某个模块的运作秘密:
mem_init(main_memory_start, memory_end);
- 初始化内存管理系统。这包括设置可用内存区域,初始化内存分配器等。
main_memory_start
和memory_end
定义了可用内存的范围。
- 初始化内存管理系统。这包括设置可用内存区域,初始化内存分配器等。
trap_init();
- 初始化中断和异常处理。设置中断向量表,初始化中断处理程序。这对于处理硬件中断和异常是必不可少的。
blk_dev_init();
- 初始化块设备。块设备是指以块为单位进行数据传输的设备,比如硬盘和软盘。这一步通常包括注册块设备驱动程序和初始化相关数据结构。
chr_dev_init();
- 初始化字符设备。字符设备是指以字符为单位进行数据传输的设备,比如键盘、鼠标和串口设备。这一步通常包括注册字符设备驱动程序和初始化相关数据结构。
tty_init();
- 初始化终端设备(TTY)。这是字符设备的一种,用于处理终端输入输出。TTY是Unix/Linux系统中重要的设备,负责与用户进行交互。
time_init();
- 初始化时间和定时器。这一步通常包括设置系统时钟,初始化定时器中断,以便操作系统能够进行时间管理。
sched_init();
- 初始化调度系统。调度系统负责管理进程的执行,分配CPU时间片。包括设置调度队列、初始化调度算法等。
buffer_init(buffer_memory_end);
- 初始化缓冲区管理系统。缓冲区管理用于暂存数据,提升I/O操作的效率。
buffer_memory_end
定义了缓冲区内存的结束地址。
- 初始化缓冲区管理系统。缓冲区管理用于暂存数据,提升I/O操作的效率。
hd_init();
- 初始化硬盘设备。这一步通常包括检测硬盘,设置硬盘控制器,准备硬盘驱动程序以便进行读写操作。
floppy_init();
- 初始化软盘设备。类似于硬盘初始化,这一步包括检测软盘驱动器,设置软盘控制器,准备软盘驱动程序以便进行读写操作。
第三部分:切换用户态
1 |
|
- 开启中断:通过
sti()
使能中断,系统可以响应硬件中断请求。 - 切换到用户模式:通过
move_to_user_mode()
将当前进程切换到受限的用户模式,保护内核空间的安全。 - 创建子进程:通过
fork()
创建一个新进程。在父进程中,fork()
返回子进程的PID;在子进程中,fork()
返回0。 - 初始化进程:在子进程中,执行
init()
函数,进一步完成系统的初始化工作,并启动用户态的各种服务和进程。
这个 init 函数是在一个新的进程里执行的,我们把这个进程叫做进程 1。
这个 init 函数会设置终端的标准 IO,并且又创建出一个执行 shell 程序的进程,用来接受用户的命令,这个新创建的进程叫做进程 2。
在这里我们就可以不断输入命令,交给操作系统去执行了,而操作系统最大的作用,就是如此
第四部分:死循环
1 |
|
如果没有任何任务可以运行,操作系统会一直陷入后面这个死循环。
8)main
https://carl-5535.github.io/2024/08/05/Linux0.11/8)main/