从开机加电到执行 main 函数之前的过程, 实际上是分三步完成,目的是实现从启动盘加载操作系统程序,完成执行 mian 函数所需要的准备工作。第一步,启动 BIOS,准备实模式下的中断向量表和中断 服务程序;第二步,从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第一步中准备的中断服务程序实现的;第三步,为执行 32 位的 main 函数做过渡工作。下面,我们详细分析这三步 在计算机中是如何完成的:
我们先从硬件角度看,Intel 80x86 系列的 CPU 分别在实模工和32位保护模式下运行。为了兼容,也为了解决最开始的启动问题,Intel 将所有 80x86 系列的 CPU ,包括最新型号的 CPU 硬件都一股 脑的设计为加电即进入 16 位实模式状态运行。同时,将 CPU 硬件逻辑设计成在加电瞬间,强行将 CS 的值置为 0xF000, IP 的值置为 0xFFF0, 这时 CS:IP 就指向 0xFFFF0 这个地址位置上,而它 正好指向了 BIOS 的地址范围。
BIOS 程序的代码量并不大,但非常精深,需要对整个计算机硬件体系结构非常熟悉才能看得懂。要想讲清楚它,可能需要另外出一本书,介于篇幅所限,这里就不讲了。BIOS 程序被固化在主板上的 ROM 芯片 里。BIOS 程序在内存最开始的位置(0x00000)用1KB的内存空间(0-1023,即0x00000-0x003FF)构建中断向量表,紧接着的是 256 字节的 BIOS 数据区,并在约 57KB以后的位置加载与中断向量表相应 的中断服务(约占8K)。共有256个中断向量,每个占4字节(2字节是CS,2字节是IP),所以中断向量表大小是1K,即 256*4=1KB 。
执行完 BIOS 代码后,CPU 会接收到一个 int 0x19 中断,CPU 找到这个中断向量后,指向 0x0E6F2, 这个就是 int 0x19 对应的中断服务程序的入口地址,它的作用是把扇区中的程序(512B)加载到内 存中指定的位置。这个程序的功能是 BIOS 事先设计好,并固定的,与操作系统无关。这个扇区就称为启动扇区(bootsect),里面的程序是由汇编程序汇编而成。
BIOS 把 bootsect 引导程序载入内存后,然后由 bootsect 把第二批,第三批等程序都加载到内存中,但目前更重要的工作是要规划内存,包括将要加载的 setup 程序的扇区数(SETUPLEN),以及加载到 的位置(SETUPSEG),以及移动 (BOOTSECT) 到新的位置(INITSEG),内核(kernel)加载位置(SYSSEG),内核末尾位置(ENDSEG)和根文件系统设备号(ROOT_DEV)。
完成上面的工作后,借助 BIOS 提供的 int 0x13 中断向量所指向的中断服务程序(磁盘服务程序),将 SETUP 程序加载到内存中,最终实现整个操作系统的代码全部加载至内存。(期间省略若干详细描述)
接下来,操作系统要使计算机在保护模式下工作,这期间要做大量的重建工作,并且持续工作到操作系统的 main 函数的执行过程中。包括打开寻址空间,打开保护模式,建立保护模式下的中断响应机制与保护 模式配套的相关工作,建立内存的分页机制,最后做好调用 main 函数的准备。这里只是做了一些简单描述,要真正了解 Linux 的核心,需要具备方方面面的知识和积累。但我相信大多数人并不需要真正去掌握它,只要有所了解,就可以开始继续我们后面的工作了,如果您想对Linux有更 深的认识,建议购买相关书籍以及到网上查阅更多的内容介绍!
# 0 停机 # 1 单用户模式 # 2 多用户模式,没有NFS # 3 完全多用户模式(标准运行级) # 4 系统保留 # 5 x windows # 6 重启
goapp@ubuntu:/etc/init.d$ ls acpid dbus mdadm php7.0-fpm single script-name grub-common mdadm-waitidle plymouth skeleton ...2, update-rc.d命令
update-rc.d A defaults 80 20 update-rc.d B defaults 90 10上面两行,A 启动序号为80 ,而 B 为90 ,那么启动时,A 先于 B 启动;关闭时,A 为20,B为10,则先关 B ,再关 A 。
update-rc.d httpd start 20 2 3 4 5 . stop 20 0 1 6 .上面表示在2、3、4、5这五个运行级别中,由小到大,第20个开始运行ushare;在 0 1 6这3个运行级别中,第20个关闭apachectl。 这是合并起来的写法,注意它有2个点号
1, umount /dev/sdc1 2, fdisk /dev/sdc (d 删除分区,n 新建分区, p 打印分区。删除原分区,新建分区大小,起始位置不变,数据内容不会删除) 3, e2fsck -f /dev/sdc1 (检查) 4, resize2fs -p /dev/sdc1 5, mount /dev/sdc1