⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux操作系统内核引导程序详细剖析.txt

📁 Linux操作系统内核引导程序详细剖析
💻 TXT
📖 第 1 页 / 共 2 页
字号:
int 0x10 

  

! ok, 我们已经显示出了信息,现在 

! 我们要加载系统了(到0x10000处)(64k处) 

  

mov ax,#SYSSEG 

mov es,ax ! es=0x01000的段; 

call read_it !! 读system,es为输入参数; 

call kill_motor !! 关闭驱动器马达; 

call print_nl !! 打印回车换行; 

  

! 这以后,我们来检查要使用哪个根设备(root-device)。如果已指定了设备(!=0) 

! 则不做任何事而使用给定的设备。否则的话,使用/dev/fd0H2880 (2,32)或/dev/PS0 

(2,28) 

! 或者是/dev/at0 (2,8)之一,这取决于我们假设我们知道的扇区数而定。 

!! |__ ps0?? (x,y)--表示主、次设备号? 

  

seg cs 

mov ax,root_dev 

or ax,ax 

jne root_defined 

seg cs 

mov bx,sectors !! sectors = 每磁道扇区数; 

mov ax,#0x0208 ! /dev/ps0 - 1.2Mb; 

cmp bx,#15 

je root_defined 

mov al,#0x1c ! /dev/PS0 - 1.44Mb !! 0x1C = 28; 

cmp bx,#18 

je root_defined 

mov al,0x20 ! /dev/fd0H2880 - 2.88Mb; 

cmp bx,#36 

je root_defined 

mov al,#0 ! /dev/fd0 - autodetect; 

root_defined: 

seg cs 

mov root_dev,ax !! 其中保存由设备的主、次设备号; 

  

! 这以后(所有程序都加载了),我们就跳转至 

! 被直接加载到boot块后面的setup程序去: 

  

jmpi 0,SETUPSEG !! 跳转到0x9020:0000(setup程序的开始位置); 

  

  

! 这段程序将系统(system)加载到0x10000(64k)处, 

! 注意不要跨越64kb边界。我们试图以最快的速度 

! 来加载,只要可能就整个磁道一起读入。 

! 

! 输入(in): es - 开始地址段(通常是0x1000) 

! 

sread: .word 0 ! 当前磁道已读的扇区数; 

head: .word 0 ! 当前磁头; 

track: .word 0 ! 当前磁道; 

  

read_it: 

mov al,setup_sects 

inc al 

mov sread,al !! 当前sread=5; 

mov ax,es !! es=0x1000; 

test ax,#0x0fff !! (ax AND 0x0fff, if ax=0x1000 then zero-flag=1 ); 

die: jne die ! es 必须在64kB的边界; 

xor bx,bx ! bx 是段内的开始地址; 

rp_read: 

#ifdef __BIG_KERNEL__ 

#define CALL_HIGHLOAD_KLUDGE .word 0x1eff, 0x220 ! 调用 far * bootsect_kludge 

! 注意: as86不能汇编这; 

CALL_HIGHLOAD_KLUDGE ! 这是在setup.S中的程序; 

#else 

mov ax,es 

sub ax,#SYSSEG ! 当前es段值减system加载时的启始段值(0x1000); 

#endif 

cmp ax,syssize ! 我们是否已经都加载了?(ax=0x7f00 ?); 

jbe ok1_read !! if ax <= syssize then 继续读; 

ret !! 全都加载完了,返回! 

ok1_read: 

mov ax,sectors !! sectors=每磁道扇区数; 

sub ax,sread !! 减去当前磁道已读扇区数,al=当前磁道未读的扇区数(ah=0); 

mov cx,ax 

shl cx,#9 !! 乘512,cx = 当前磁道未读的字节数; 

add cx,bx !! 加上段内偏移值,es:bx为当前读入的数据缓冲区地址; 

jnc ok2_read !! 如果没有超过64K则继续读; 

je ok2_read !! 如果正好64K也继续读; 

xor ax,ax 

sub ax,bx 

shr ax,#9 

ok2_read: 

call read_track !! es:bx ->缓冲区,al=要读的扇区数,也即当前磁道未读的扇区数; 

  

mov cx,ax !! ax仍为调用read_track之前的值,即为读入的扇区数; 

add ax,sread !! ax = 当前磁道已读的扇区数; 

cmp ax,sectors !! 已经读完当前磁道上的扇区了吗? 

jne ok3_read !! 没有,则跳转; 

mov ax,#1 

sub ax,head !! 当前是磁头1吗? 

jne ok4_read !! 不是(是磁头0)则跳转(此时ax=1); 

inc track !! 当前是磁头1,则读下一磁道(当前磁道加1); 

ok4_read: 

mov head,ax !! 保存当前磁头号; 

xor ax,ax !! 本磁道已读扇区数清零; 

ok3_read: 

mov sread,ax !! 存本磁道已读扇区数; 

shl cx,#9 !! 刚才一次读操作读入的扇区数 * 512; 

add bx,cx !! 调整数据缓冲区的起始指针; 

jnc rp_read !! 如果该指针没有超过64K的段内最大偏移量,则跳转继续读操作; 

mov ax,es !! 如果超过了,则将段地址加0x1000(下一个64K段); 

add ah,#0x10 

mov es,ax 

xor bx,bx !! 缓冲区地址段内偏移量置零; 

jmp rp_read !! 继续读操作; 

  

  

  

read_track: 

pusha !! 将寄存器ax,cx,dx,bx,sp,bp,si,di压入堆栈; 

pusha 

mov ax,#0xe2e ! loading... message 2e = . !! 显示一个. 

mov bx,#7 

int 0x10 

popa 

  

mov dx,track !! track = 当前磁道; 

mov cx,sread 

inc cx !! cl = 扇区号,要读的起始扇区; 

mov ch,dl !! ch = 磁道号的低8位; 

mov dx,head !! 

mov dh,dl !! dh = 当前磁头号; 

and dx,#0x0100 !! dl = 驱动器号(0); 

mov ah,#2 !! 功能2(读),es:bx指向读数据缓冲区; 

  

push dx ! 为出错转储保存寄存器的值到堆栈上; 

push cx 

push bx 

push ax 

  

int 0x13 

jc bad_rt !! 如果出错,则跳转; 

add sp, #8 !! 清(放弃)堆栈上刚推入的4个寄存器值; 

popa 

ret 

  

bad_rt: push ax ! 保存出错码; 

call print_all ! ah = error, al = read; 

  

  

xor ah,ah 

xor dl,dl 

int 0x13 

  

  

add sp,#10 

popa 

jmp read_track 

  

/* 

* print_all是用于调试的。 

* 它将打印出所有寄存器的值。所作的假设是 

* 从一个子程序中调用的,并有如下所示的堆栈帧结构 

* dx 

* cx 

* bx 

* ax 

* error 

* ret <- sp 

* 

*/ 

  

print_all: 

mov cx,#5 ! 出错码 + 4个寄存器 

mov bp,sp 

  

print_loop: 

push cx ! 保存剩余的计数值 

call print_nl ! 为了增强阅读性,打印换行 

  

cmp cl, #5 

jae no_reg ! 看看是否需要寄存器的名称 

  

mov ax,#0xe05 + A - l 

sub al,cl 

int 0x10 

  

mov al,#X 

int 0x10 

  

mov al,#: 

int 0x10 

  

no_reg: 

add bp,#2 ! 下一个寄存器 

call print_hex ! 打印值 

pop cx 

loop print_loop 

ret 

  

print_nl: !! 打印回车换行。 

mov ax,#0xe0d ! CR 

int 0x10 

mov al,#0xa ! LF 

int 0x10 

ret 

  

/* 

* print_hex是用于调试目的的,打印出 

* ss:bp所指向的十六进制数。 

* !! 例如,十六进制数是0x4321时,则al分别等于4,3,2,1调用中断打印出来 4321 

*/ 

  

print_hex: 

mov cx, #4 ! 4个十六进制数字 

mov dx, (bp) ! 将(bp)所指的值放入dx中 

print_digit: 

rol dx, #4 ! 循环以使低4比特用上 !! 取dx的高4比特移到低4比特处。 

mov ax, #0xe0f ! ah = 请求的功能值,al = 半字节(4个比特)掩码。 

and al, dl !! 取dl的低4比特值。 

add al, #0x90 ! 将al转换为ASCII十六进制码(4个指令) 

daa !! 十进制调整 

adc al, #0x40 !! (adc dest, src ==> dest := dest + src + c ) 

daa 

int 0x10 

loop print_digit 

ret 

  

  

/* 

* 这个过程(子程序)关闭软驱的马达,这样 

* 我们进入内核后它的状态就是已知的,以后也就 

* 不用担心它了。 

*/ 

kill_motor: 

push dx 

mov dx,#0x3f2 

xor al,al 

outb 

pop dx 

ret 

  

!! 数据区 

sectors: 

.word 0 !! 当前每磁道扇区数。(36||18||15||9) 

  

disksizes: !! 每磁道扇区数表 

.byte 36, 18, 15, 9 

  

msg1: 

.byte 13, 10 

.ascii "Loading" 

  

.org 497 !! 从boot程序的二进制文件的497字节开始 

setup_sects: 

.byte SETUPSECS 

root_flags: 

.word CONFIG_ROOT_RDONLY 

syssize: 

.word SYSSIZE 

swap_dev: 

.word SWAP_DEV 

ram_size: 

.word RAMDISK 

vid_mode: 

.word SVGA_MODE 

root_dev: 

.word ROOT_DEV 

 

boot_flag: !! 分区启动标志 

.word 0xAA55 

  

  

  

-- 

 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -