《LINUX内核设计的艺术》第一章从开机家电到执行main函数之前的过程 学习笔记之一

从开机加电到实行main函数之前的过程

分为三步,目的是实现从启动盘加载操作系统程序,完成实现main函数的准备工作

  1. 启动BLOS,准备是模式下的中断向量表和中断服务程序

  2. 从启动盘加载操作系统程序到内存。加载操作系统程序就是靠第一步实现的

  3. 为实现32位的main函数做过度工作

1.1启动blos,准备实模式下的中断向量表和中断服务程序

由blos来加载软件操作系统的任务

1.1.1         BLOS的启动原理

0XFFFF0

由硬件来启动,CPU硬件设计逻辑设计为加电瞬间就强行将CS的值置于0xFFFF,IP的值置于0x0000,这样CS:IP就指向0xFFFF0这个地址位置。

IP:指令指针寄存器。记录将要实行的指令在代码段内的偏移地址,和CS组合就是将要实行的指令的内存地址。(实模式是绝对地址,指令指针是16位,IP)(保护模式下为线性地址,指令指针为32位,EIP)

CS:代码段寄存器密祉乡CPU当前实行代码段在内存中所在的局域

1.1.2        
BLOS在内存中加载中断向量表和中断服务程序

这里选用BLOS有8KB,所占的地址段有0xFE000~0xFFFFF

BLOS在内存中开始加载中断向量表和中断服务程序就是启动(boot)操作系统至关重要的工作

0x00000~0x003FF 1KB中断向量表

0x00400~0x004FF BLOS数据数据表

0x0E2CE~0x0FFFF 中断服务程序

中断向量表一共有256个中断向量,每个中断向量占4个字节,其中两个CS还有两个是IP,每个向量都是指向各自的中断服务程序

1.2 加载操作系统内核程序并为保护模式做准备

分三批加载操作系统的内核代码

第一批由int 0x19h 把第一扇区bootsect的内容加载到内存中

第二三批在bootsect的指挥下,分别把其后的四个扇区和随后的240个扇区内容加载至内核

1.2.1加载第一部分代码,引导程序(bootsect)

计算机硬件体系结构的设计与BLOS联手操作,会让CPU接受int 19h中断,CPU接收到这个中断后,立即就在中断向量表中找到这个向量。然后int
19h把CPU指向0x0E6F2(就是服务程序的入口)。这个程序就是吧软盘的第一个扇区中的程序(512B)加载到内存中指定的任何一个位置。

差不多就是将软驱0号磁头对应盘面的0磁道1扇区的内容拷贝到内存0x07C00处。

这个扇区的内容就是LINUX0.11操作系统的引导程序。

第一扇区的载入标识表示操作系统的代码终于要发挥作用了

1.2.2加载第二部分代码-setup

1.Bootsect对于内存的规划

在实模式下,寻址的最大范围是1MB,为了规划内存,bootsect首先设计了如下代码来对后续操作所涉及的内存位置进行设置。

SETUPLE           
将要加载的setup程序的扇区数

SETUPSEG         被加载到的位置

BOOTSEG                  
启动扇区被BLOS加载的位置

INITSEG            
将要移动到的新位置

SYSSEG             
Kernel内核将被加载的位置

SYSEND            
内核的末尾位置

ROOT_DEV       根文件系统设备号

设置这些位置就是为了保证将载入内存的代码和意见载入内存的代码数据各在其位,互不覆盖

2.复制bootset

接下来,bootset启动程序将它自身(全部512B内容)从内存0xc7c00(BOOTSEG)复制到0x90000(INITSEG)处,注意此时,CPU的段寄存器(CS)指向BOOTSEG

start:

mov ax,#BOOTSEG

mov ds,ax

mov ax,#INITSEG

mov es,ax

mov
cx,#256                               
//控制循环控制量

sub   si,si

sub   di,di

rep

movw

//bootseg复制到新位置,后实行以下这行粗代码

jmpi
go,INITSEG

go:   mov ax,cs

//实行完这个跳跃,CS就变为INITSEG,IP也从INITSEG到了go:mov
ax
,cs对应的指令偏移,换句话来说就是CS:IP到了这一行开始往下实行。

由于bootset复制到了新地方,要在新的地方实行。所以要对DS,ES,SS,SP进行调整。

mov ds,ax

mov es,ax

! put stack at 0x9ff00.

mov ss,ax

mov
sp,#0xFF00               
! arbitrary value >>512

! load the setup-sectors directly after the bootblock.

! Note that ‘es‘ is already set up.

上述代码的作用就是通过ax,用CS的值0x9000来把

数据寄存器(DS)

附加段寄存器(ES)

栈基址寄存器(SS)

设置成与代码段寄存器CS相同的位置。,并将栈顶指针sp指向偏移地址0xFF00处

压栈的方向就是高地址到低地址方向

Bootsect的第一步操作:规划内存并把自身从0x07C00的位置复制到0x90000的位置的动作已经完成了。

3.将Setup程序加载到内存中

要借助int 0x 13h中断向量,也是就是指向“磁盘服务程序”

和int 0x 19h的区别在于,前者是自身启动代码bootsect执行的。后者是BIOS实行的

后者的中断服务程序只负责把软盘的第一扇区的代码就加载到0x07c00位置。前者是将指定扇区的代码加载到内存的指定位置。

load_setup:

mov
dx,#0x0000               
! drive 0, head 0

mov
cx,#0x0002               
! sector 2, track 0

mov
bx,#0x0200               
! address = 512, in INITSEG

mov
ax,#0x0200+SETUPLEN   ! service 2, nr of sectors

int   
0x13                           
! read it

jnc   
ok_load_setup                  
! ok - continue

mov dx,#0x0000

mov
ax,#0x0000               
! reset the diskette

int   
0x13

j        load_setup

ok_load_setup:

从代码开始处的4个mov指令可以看得出系统给BIOS中断程序传参数是靠几个通用寄存器实现的。

参数传递完毕后,实行int
0x13h这个指令,产生0x13中断,通过中断向量表找到这个中断向量程序,将软盘的第二扇区开始的4个扇区,就是说setup.S对应的程序加载至内存的setup(0x90200)处。

可以看得出,bootsect和setup是连在一起的。

读扇区:

ah=0x02 - 读磁盘扇区到内存;a1=需要读出的扇区数量

ch=磁道(柱面)号的低8位; c1=开始扇区(位0-5),磁道号高2 位(位6-7);

dh=磁头号; d1=驱动器号(如果是硬盘则位7要 置位),0为当前A驱动器

es:bx->指向数据缓冲区;如果出错则CF标志置位。

1.2.3加载第三部分代码-system模块

下面就是system代码,仍然是bootsect用BIOS提供的int 0x
13h中断将240个扇区的system模块加载进内存。加载工作主要是由bootsect来调用read
it来完成。这个子程序将软盘地6扇区开始的月240个扇区的system模块加载至内存的SYSSEG(0x10000)出往后的120KB空间中。

整个操作系统都载入了内存,bootsect的主体都完成了,还有一点小事,就是要再次确认一下根设备号。在书里例子就是得知软盘就是跟设备,所以就把跟设备号保存在root——dev中,这个根设备号作为机器系统数据之一。

所以要检查要使用哪个根文件系统设备(简称根设备)。如果已经指定了设备(!=0)就直接使用给定的设备。否则就需要根据BIOS
报告的每磁道扇区数来确定到底使用/dev/PS0 (2,28) 还是 /dev/at0 (2,8)。

故在此bootsect的工作完毕。

下面就是执行

jmpi 0,SETUPSEG ! 跳转到0x9020:0000(setup.s 程序的开始处)。

Setup程序开始,他做的第一件事情就是利用BIOS来提供的中断服务程序从设备上提取出内核运行所需的技巧系统数据,其中包括,光标位置和现实页面等数据,并分别从中断向量,0x41,o46向量值所指的内存弟子出获取硬盘参数表1,和硬盘参数表2,把他们存放在0x9000:0x0080,0x9000:0x0090处。这些数据将被加载到内存的0x90000~0x901FC位置。标出了其内容及准确的位置,这些数据将在以后main函数执行是发挥重要作用。

这段代码提取出的机器系统数据将覆盖bootsect程序所在的部分区域。

下面就是有重要意义上的从实模式到保护模式的转变,使得LINUX0.11变为现代操作系统

《LINUX内核设计的艺术》第一章从开机家电到执行main函数之前的过程 学习笔记之一,布布扣,bubuko.com

时间: 2024-10-08 19:35:15

《LINUX内核设计的艺术》第一章从开机家电到执行main函数之前的过程 学习笔记之一的相关文章

linux内核设计与实现第一章

1.1 unix的历史 Thompson实现unix 伯克利大学对其进一步开发推出了著名的BSD 其他各大厂商相继推出自己的unix 1.1.2 unix的特性 unix系统是一个强大,健壮,稳定的操作系统 unix中,一切东西都是文件 unix由c编写,移植性非常好 1.1.3unix的总结 Unix现在已经发胀成为一个支持抢占式多任务,多线程,TCP/IP网络的现代化操作系统 1.2linux简介 来自为知笔记(Wiz)

linux内核设计的艺术--系统启动第一步

计算机究竟是如何执行起来的呢,在我学习计算机的时候一直不是非常明确,可是近期借了本<linux内核设计的艺术>算是知道了计算机从按开机到启动操作系统之间究竟做了些什么. 这本书刚開始介绍的并非linux的启动,而是linux启动之前的一步,也就是在你按下了开机button之后进入系统引导之前计算机做的事情,这个时候做的事情是每台执行操作系统的计算机都须要做的.大致的步骤也差点儿相同,OK,进入正题. 事实上在当我们按了开机键的时候,硬件电路将CPU的CS设置成0XF000,IP设置成0XFFF

linux内核设计的艺术--加载内核代码

在BIOS触发0x19中断将磁盘的第一个扇区(512B)加载到内存中后,计算机才真正开始执行磁盘上的程序.而这512B的程序bootsect.s中的第一批代码,此时处理器还处于实模式内存寻址的最大范围是1M(0x0000-0xFFFF),接下来我们看看在bootsect.s的第一批代码中做了些什么? SYSSIZE = 0x3000 //内核程序的大小 SETUPLEN = 4 //要加载的setup程序长度单位为扇区数 BOOTSEG = 0x07c0 //启动扇区被BIOS加载的位置,也就是

《Linux内核设计的艺术》学习笔记(一)从开机加电到执行main函数之前的过程

分享一个最近丢了手机心塞到爆炸的我,现在穷的只剩下满脑子的智慧了,好了,我要开始学习了. 首先,搭建一个linux0.11的系统环境,贴出结果图. 从开机加电到执行main函数之前的过程. 1. 启动BIOS,准备实模式下的中断向量表和中断服务程序; 2. 从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第一步中断服务程序实现的; 3. 为执行32位的main函数做过渡工作. 启动BIOS,准备实模式下的中断向量表和中断服务程序 cpu的硬件设计为加电即进入16位实模式下状态运行,

《Linux内核设计的艺术》学习笔记(一)从开机加电到执行main函数

  实验内核版本:0.11 ◆ 从开机到main函数的三步: ① 启动BIOS,准备实模式下的中断向量表和中断服务程序: ② 从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务程序实现的: ③ 为执行保护模式下32位的main函数做过渡工作. ? Intel将所有80x86系列的CPU硬件都设计为加电即进入16位实模式状态运行: ? 将CPU硬件逻辑设计为在加电瞬间强行将CS置为0xFFFF,IP置为0x0000,即是CS:IP指向了0xFFFF0这个地址: 整个过程是一

linux内核设计的艺术-开始执行main函数

为了执行linux内的C语言main函数,上一篇讲到了,为了从汇编语言环境跳转到C语言环境下执行,将CPU工作模式从16位转变到32位模式(C语言是32位的),并且重新建立了GDT与IDT,但是此时GDT和IDT中并没有内容,所以不能进行内存寻址与中断,接下来就是初始化GDT和IDT了. 进入32位模式后,寄存器也将变为32位寄存器,下面的汇编语法和之前的intel汇编有些不同,为AT&T汇编,至于差别不在赘述. Head.S startup_32: //重设段寄存器内容 movl $0x10,

linux内核设计的艺术--载入内核代码

在BIOS触发0x19中断将磁盘的第一个扇区(512B)载入到内存中后.计算机才真正開始运行磁盘上的程序.而这512B的程序就是bootsect.s,此时处理器还处于实模式内存寻址的最大范围是1M(0x0000-0xFFFF),接下来我们看看在bootsect.s的第一批代码中做了些什么? </pre><pre name="code" class="cpp">SYSSIZE = 0x3000 //内核程序的大小 SETUPLEN = 4 //

linux内核设计的艺术--从16位转向32位

上一篇讲到了将kernel模块加载到了内存的0x10000-0x10000+120KB处,接下来,将会执行setup.s中的代码了. 首先,setup要获取一系列系统硬件信息 mov ax,#INITSEG mov ds,ax //设置段地址 mov ah,#0x03 xor bh,bh int 0x10 //调用0x10中断获取屏幕光标位置 mov [0],dx //将屏幕光标保存至0x90000处 //调用0x15中断,获取内存信息保存至0x90002 mov ah,#0x88 int 0x

《Linux内核设计的艺术》学习笔记(五)INT 0x10中断

参考书籍:<IBM-PC汇编语言程序设计>   ◆ 设置显示方式: AH = 0 AL = 00 40 × 25 黑白文本,16级灰度 AL = 01 40 × 25 16色文本 AL = 02 80 × 25 黑白文本,16级灰度 AL = 03 80 × 25 16色文本 AL = 04 320 × 200 4色图形 AL = 05 320 × 200 黑白图形,4色灰度 AL = 06 640 × 200 黑白图形 AL = 07 80 × 25 黑白文本 AL = 08 160 × 2