- linux内核代码注释
第三章引导启动程序
boot目录中的三个汇编代码文件 bootsect.s和setup.s采用近似intel的汇编语法,需要8086汇编器连接器as86和ld86
head.s用GNU的汇编程序格式 并且运行在保护模式下,需要GNU的as进行编译。为AT&T语法的汇编语言程序。GNU只支持386后的cpu 不支持实模式下的程序
总体功能
pc加电-》cpu进入实模式-》从0xfff0开始执行程序代码(bios地址),进行系统检测,并在物理地址0处开始初始化中断向量--》启动设备的第一个扇区 引导扇区 512字节,读入到内存0x7c00处,并且跳转到此。
linux系统最前面的部分就是boot/bootsect.s 由bios读入到内存绝对地址0x7c00 (31k)--》当此程序执行时,会将自己移动到绝对地址0x90000 576k处--》将启动设备中后2k字节代码boot/setup.s读入到内存0x90200处,而内处的其他部分 system模块 则被读入到从地址0x10000开始处,,后面的setup程序会把system模块移动到内存起始处。 看上图
整个系统从地址0x10000移动到0x0000处,进入保护模式并跳转到系统的鱼虾部分 在0x0000处。此时所有的32位运行方式的设置启动完成,IDT GDT 以及LDT被加载,cpu和协处理器已经确认,分页机制也已经准备就绪
然后嗲用init/main.c程序
一bootsect.s 程序
(1)
磁盘引导块程序 驻留在磁盘的一个扇区中 引导扇区,0磁道 柱面,0磁头,第1个扇区。pc机加电rom-bios自检后,引导扇区由bios加载到内存0x7c00处,然后将自己移动到内存0x90000处。
作用:
1.将setup模块 (由setup.s编译而成)从磁盘加载到内存,紧接着bootsect的后面位置0x90200、
2.利用BIOS中断0x13取磁盘参数表中当前启动引导盘的参数
3.在屏幕上显示loading system... 字符串
4.将system模块从磁盘加载到内存0x10000开始处,
5.确定根文件系统的设备号 若未指定,则根据所保存的引导盘的每磁道扇区数判别处盘的类型和种类 并保存其设备号于root_dev 引导块0x508地址处,最后长跳转到setup程序的开始处 0x90200 执行setup程序。
(2)代码注释
- !
- ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
- ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
- ! versions of linux
- !
- SYSSIZE = 0x3000
- !
- ! bootsect.s (C) 1991 Linus Torvalds
- !
- ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
- ! iself out of the way to address 0x90000, and jumps there.
- !
- ! It then loads 'setup' directly after itself (0x90200), and the system
- ! at 0x10000, using BIOS interrupts.
- !
- ! NOTE! currently system is at most 8*65536 bytes long. This should be no
- ! problem, even in the future. I want to keep it simple. This 512 kB
- ! kernel size should be enough, especially as this doesn't contain the
- ! buffer cache as in minix
- !
- ! The loader has been made as simple as possible, and continuos
- ! read errors will result in a unbreakable loop. Reboot by hand. It
- ! loads pretty fast by getting whole sectors at a time whenever possible.
- .globl begtext, begdata, begbss, endtext, enddata, endbss //段定义
- .text
- begtext:
- .data
- begdata:
- .bss
- begbss:
- .text
- SETUPLEN = 4 ! nr of setup-sectors 扇区数量 定义
- BOOTSEG = 0x07c0 ! original address of boot-sector 开始段
- INITSEG = 0x9000 ! we move boot here - out of the way 初始段
- SETUPSEG = 0x9020 ! setup starts here setup程序所在段
- SYSSEG = 0x1000 ! system loaded at 0x10000 (65536). 系统模块段
- ENDSEG = SYSSEG + SYSSIZE ! where to stop loading 停止加载的位置
- ! ROOT_DEV: 0x000 - same type of floppy as boot. 软盘类型
- ! 0x301 - first partition on first drive etc 硬盘类型
- ROOT_DEV = 0x306 启动盘设备类型
- entry start 程序入口地址
- start:
- mov ax,#BOOTSEG
- mov ds,ax ds段基地址
- mov ax,#INITSEG
- mov es,ax es段基地址
- mov cx,#256
- sub si,si si和di均清0
- sub di,di
- rep 循环256次 共512个字节的内容
- movw 传送字 将bootseg段的代码移动到es指向的initseg段
- jmpi go,INITSEG 跳转到initseg段的go标号位置
- go: mov ax,cs cs ds es指向相同的位置
- mov ds,ax
- mov es,ax
- ! put stack at 0x9ff00.
- mov ss,ax ss堆栈段基址位0x9ff00
- mov sp,#0xFF00 ! arbitrary value >>512 sp指针的位置调整ss:sp=0x90000:ff00位置 此时位空栈 以上为初始化
- ! load the setup-sectors directly after the bootblock.
- ! Note that 'es' is already set up.
- load_setup: 加载setup程序
- mov dx,#0x0000 ! drive 0, head 0 驱动器0 磁头0 dh磁头 dl驱动器号
- mov cx,#0x0002 ! sector 2, track 0 扇区2 磁道0 ch磁道号 柱面号 cl开始扇区
- mov bx,#0x0200 ! address = 512, in INITSEG 512个字节
- mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors ah=2 功能号为2 al=4 扇区数量
- int 0x13 ! read it 中断13 读磁盘的功能 读如到es:bx 数据缓冲区
- jnc ok_load_setup ! ok - continue 判断cf标志位 cf=0正常 cf=1 出错
- mov dx,#0x0000
- mov ax,#0x0000 ! reset the diskette 重设寄存器
- int 0x13 调用中断13号 复位磁盘
- j load_setup 跳转load_setup
- ok_load_setup:
- ! Get disk drive parameters, specifically nr of sectors/track 以下为获取磁盘驱动器的参数
- mov dl,#0x00
- mov ax,#0x0800 ! AH=8 is get drive parameters
- int 0x13 中断13 ah为8调用获取磁盘参数
- mov ch,#0x00 ch清0
- seg cs 找cs段执行指令 下一条指令在cs段
- mov sectors,cx 保存每磁道扇区数
- mov ax,#INITSEG es指向0x9000的段处
- mov es,ax
- ! Print some inane message
- mov ah,#0x03 ! read cursor pos
- xor bh,bh
- int 0x10 中断 读取光标位置
- mov cx,#24 共24个字符
- mov bx,#0x0007 ! page 0, attribute 7 (normal) bh为页 bl为属性
- mov bp,#msg1 es:bp指向要显示的字符串
- mov ax,#0x1301 ! write string, move cursor ah为13 显示字符串功能, al为1表示写方式
- int 0x10 中断调用
- ! ok, we've written the message, now
- ! we want to load the system (at 0x10000)
- mov ax,#SYSSEG es指向0x1000处
- mov es,ax ! segment of 0x010000
- call read_it 调用子程序 134行
- call kill_motor 关闭马达 214行
- ! After that we check which root-device to use. If the device is
- ! defined (!= 0), nothing is done and the given device is used.
- ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
- ! on the number of sectors that the BIOS reports currently.
- seg cs
- mov ax,root_dev
- cmp ax,#0
- jne root_defined
- seg cs
- mov bx,sectors
- mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
- cmp bx,#15
- je root_defined
- mov ax,#0x021c ! /dev/PS0 - 1.44Mb
- cmp bx,#18
- je root_defined
- undef_root:
- jmp undef_root
- root_defined:
- seg cs
- mov root_dev,ax
- ! after that (everyting loaded), we jump to
- ! the setup-routine loaded directly after
- ! the bootblock:
- jmpi 0,SETUPSEG
- ! This routine loads the system at address 0x10000, making sure
- ! no 64kB boundaries are crossed. We try to load it as fast as
- ! possible, loading whole tracks whenever we can.
- !
- ! in: es - starting address segment (normally 0x1000)
- !
- sread: .word 1+SETUPLEN ! sectors read of current track 磁道中已经读取的扇区数 开始时已经读取1扇区 bootsect和setup程序所占的扇区数为setuplen
- head: .word 0 ! current head
- track: .word 0 ! current track
- read_it:
- mov ax,es
- test ax,#0x0fff es必须是64k边界 es实际指向的内存为0x10000共20位 相与的是高16位 数值结果不保存
- die: jne die ! es must be at 64kB boundary
- xor bx,bx ! bx is starting address within segment bx指向段基地址
- rp_read:
- mov ax,es
- cmp ax,#ENDSEG ! have we loaded all yet? 判断es是否等于停止加载的段地址
- jb ok1_read 小于时跳转到ok1_read标号处继续执行,否则返回
- ret
- ok1_read:
- seg cs cs段的指令执行
- mov ax,sectors 取每磁道扇区数
- sub ax,sread ax-sread 等于未读取的扇区数 结果送ax
- mov cx,ax
- shl cx,#9 左移9位 相当于乘以512 结果为未读扇区的字节数
- add cx,bx 加上bx(段内偏移值) 此次读操作后段内读入字节数
- jnc ok2_read cf标志位判断 是否有进位 如果不等于1 则跳转,即没有超过64k
- je ok2_read 等于64k则跳转 156行处
- xor ax,ax 超过64k 即加上此次将读磁道上所有未读扇区时会超过64k ,则ax清0
- sub ax,bx ax-bx 计算此次能读入的字节数 64k-bx(段内读偏移)
- shr ax,#9 再次将字节数转换成扇区数 右移9位 相当于除以512
- ok2_read:
- call read_track 调用read_track
- mov cx,ax
- add ax,sread
- seg cs
- cmp ax,sectors
- jne ok3_read
- mov ax,#1
- sub ax,head
- jne ok4_read
- inc track
- ok4_read:
- mov head,ax
- xor ax,ax
- ok3_read:
- mov sread,ax
- shl cx,#9
- add bx,cx
- jnc rp_read
- mov ax,es
- add ax,#0x1000
- mov es,ax
- xor bx,bx
- jmp rp_read
- read_track:
- push ax
- push bx
- push cx
- push dx
- mov dx,track
- mov cx,sread
- inc cx
- mov ch,dl
- mov dx,head
- mov dh,dl
- mov dl,#0
- and dx,#0x0100
- mov ah,#2
- int 0x13
- jc bad_rt
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- bad_rt: mov ax,#0
- mov dx,#0
- int 0x13
- pop dx
- pop cx
- pop bx
- pop ax
- jmp read_track
- /*
- * This procedure turns off the floppy drive motor, so
- * that we enter the kernel in a known state, and
- * don't have to worry about it later.
- */
- kill_motor:
- push dx
- mov dx,#0x3f2
- mov al,#0
- outb
- pop dx
- ret
- sectors:
- .word 0
- msg1:
- .byte 13,10
- .ascii "Loading system ..."
- .byte 13,10,13,10
- .org 508
- root_dev:
- .word ROOT_DEV
- boot_flag:
- .word 0xAA55
- .text
- endtext:
- .data
- enddata:
- .bss
- endbss: