📄 00000050.htm
字号:
<BR>mov ax,#SYSSEG <BR>mov es,ax ! es=0x01000的段; <BR>call read_it !! 读system,es为输入参数; <BR>call kill_motor !! 关闭驱动器马达; <BR>call print_nl !! 打印回车换行; <BR> <BR>! 这以后,我们来检查要使用哪个根设备(root-device)。如果已指定了设备(!=0) <BR>! 则不做任何事而使用给定的设备。否则的话,使用/dev/fd0H2880 (2,32)或/dev/PS0 <BR>(2,28) <BR>! 或者是/dev/at0 (2,8)之一,这取决于我们假设我们知道的扇区数而定。 <BR>!! |__ ps0?? (x,y)--表示主、次设备号? <BR> <BR>seg cs <BR>mov ax,root_dev <BR>or ax,ax <BR>jne root_defined <BR>seg cs <BR>mov bx,sectors !! sectors = 每磁道扇区数; <BR>mov ax,#0x0208 ! /dev/ps0 - 1.2Mb; <BR>cmp bx,#15 <BR>je root_defined <BR>mov al,#0x1c ! /dev/PS0 - 1.44Mb !! 0x1C = 28; <BR>cmp bx,#18 <BR>je root_defined <BR>mov al,0x20 ! /dev/fd0H2880 - 2.88Mb; <BR>cmp bx,#36 <BR>je root_defined <BR>mov al,#0 ! /dev/fd0 - autodetect; <BR>root_defined: <BR>seg cs <BR>mov root_dev,ax !! 其中保存由设备的主、次设备号; <BR> <BR>! 这以后(所有程序都加载了),我们就跳转至 <BR>! 被直接加载到boot块后面的setup程序去: <BR> <BR>jmpi 0,SETUPSEG !! 跳转到0x9020:0000(setup程序的开始位置); <BR> <BR> <BR>! 这段程序将系统(system)加载到0x10000(64k)处, <BR>! 注意不要跨越64kb边界。我们试图以最快的速度 <BR>! 来加载,只要可能就整个磁道一起读入。 <BR>! <BR>! 输入(in): es - 开始地址段(通常是0x1000) <BR>! <BR>sread: .word 0 ! 当前磁道已读的扇区数; <BR>head: .word 0 ! 当前磁头; <BR>track: .word 0 ! 当前磁道; <BR> <BR>read_it: <BR>mov al,setup_sects <BR>inc al <BR>mov sread,al !! 当前sread=5; <BR>mov ax,es !! es=0x1000; <BR>test ax,#0x0fff !! (ax AND 0x0fff, if ax=0x1000 then zero-flag=1 ); <BR>die: jne die ! es 必须在64kB的边界; <BR>xor bx,bx ! bx 是段内的开始地址; <BR>rp_read: <BR>#ifdef __BIG_KERNEL__ <BR>#define CALL_HIGHLOAD_KLUDGE .word 0x1eff, 0x220 ! 调用 far * bootsect_kludge <BR>! 注意: as86不能汇编这; <BR>CALL_HIGHLOAD_KLUDGE ! 这是在setup.S中的程序; <BR>#else <BR>mov ax,es <BR>sub ax,#SYSSEG ! 当前es段值减system加载时的启始段值(0x1000); <BR>#endif <BR>cmp ax,syssize ! 我们是否已经都加载了?(ax=0x7f00 ?); <BR>jbe ok1_read !! if ax <= syssize then 继续读; <BR>ret !! 全都加载完了,返回! <BR>ok1_read: <BR>mov ax,sectors !! sectors=每磁道扇区数; <BR>sub ax,sread !! 减去当前磁道已读扇区数,al=当前磁道未读的扇区数(ah=0); <BR>mov cx,ax <BR>shl cx,#9 !! 乘512,cx = 当前磁道未读的字节数; <BR>add cx,bx !! 加上段内偏移值,es:bx为当前读入的数据缓冲区地址; <BR>jnc ok2_read !! 如果没有超过64K则继续读; <BR>je ok2_read !! 如果正好64K也继续读; <BR>xor ax,ax <BR>sub ax,bx <BR>shr ax,#9 <BR>ok2_read: <BR>call read_track !! es:bx ->缓冲区,al=要读的扇区数,也即当前磁道未读的扇区数; <BR> <BR>mov cx,ax !! ax仍为调用read_track之前的值,即为读入的扇区数; <BR>add ax,sread !! ax = 当前磁道已读的扇区数; <BR>cmp ax,sectors !! 已经读完当前磁道上的扇区了吗? <BR>jne ok3_read !! 没有,则跳转; <BR>mov ax,#1 <BR>sub ax,head !! 当前是磁头1吗? <BR>jne ok4_read !! 不是(是磁头0)则跳转(此时ax=1); <BR>inc track !! 当前是磁头1,则读下一磁道(当前磁道加1); <BR>ok4_read: <BR>mov head,ax !! 保存当前磁头号; <BR>xor ax,ax !! 本磁道已读扇区数清零; <BR>ok3_read: <BR>mov sread,ax !! 存本磁道已读扇区数; <BR>shl cx,#9 !! 刚才一次读操作读入的扇区数 * 512; <BR>add bx,cx !! 调整数据缓冲区的起始指针; <BR>jnc rp_read !! 如果该指针没有超过64K的段内最大偏移量,则跳转继续读操作; <BR>mov ax,es !! 如果超过了,则将段地址加0x1000(下一个64K段); <BR>add ah,#0x10 <BR>mov es,ax <BR>xor bx,bx !! 缓冲区地址段内偏移量置零; <BR>jmp rp_read !! 继续读操作; <BR> <BR> <BR> <BR>read_track: <BR>pusha !! 将寄存器ax,cx,dx,bx,sp,bp,si,di压入堆栈; <BR>pusha <BR>mov ax,#0xe2e ! loading... message 2e = . !! 显示一个. <BR>mov bx,#7 <BR>int 0x10 <BR>popa <BR> <BR>mov dx,track !! track = 当前磁道; <BR>mov cx,sread <BR>inc cx !! cl = 扇区号,要读的起始扇区; <BR>mov ch,dl !! ch = 磁道号的低8位; <BR>mov dx,head !! <BR>mov dh,dl !! dh = 当前磁头号; <BR>and dx,#0x0100 !! dl = 驱动器号(0); <BR>mov ah,#2 !! 功能2(读),es:bx指向读数据缓冲区; <BR> <BR>push dx ! 为出错转储保存寄存器的值到堆栈上; <BR>push cx <BR>push bx <BR>push ax <BR> <BR>int 0x13 <BR>jc bad_rt !! 如果出错,则跳转; <BR>add sp, #8 !! 清(放弃)堆栈上刚推入的4个寄存器值; <BR>popa <BR>ret <BR> <BR>bad_rt: push ax ! 保存出错码; <BR>call print_all ! ah = error, al = read; <BR> <BR> <BR>xor ah,ah <BR>xor dl,dl <BR>int 0x13 <BR> <BR> <BR>add sp,#10 <BR>popa <BR>jmp read_track <BR> <BR>/* <BR>* print_all是用于调试的。 <BR>* 它将打印出所有寄存器的值。所作的假设是 <BR>* 从一个子程序中调用的,并有如下所示的堆栈帧结构 <BR>* dx <BR>* cx <BR>* bx <BR>* ax <BR>* error <BR>* ret <- sp <BR>* <BR>*/ <BR> <BR>print_all: <BR>mov cx,#5 ! 出错码 + 4个寄存器 <BR>mov bp,sp <BR> <BR>print_loop: <BR>push cx ! 保存剩余的计数值 <BR>call print_nl ! 为了增强阅读性,打印换行 <BR> <BR>cmp cl, #5 <BR>jae no_reg ! 看看是否需要寄存器的名称 <BR> <BR>mov ax,#0xe05 + A - l <BR>sub al,cl <BR>int 0x10 <BR> <BR>mov al,#X <BR>int 0x10 <BR> <BR>mov al,#: <BR>int 0x10 <BR> <BR>no_reg: <BR>add bp,#2 ! 下一个寄存器 <BR>call print_hex ! 打印值 <BR>pop cx <BR>loop print_loop <BR>ret <BR> <BR>print_nl: !! 打印回车换行。 <BR>mov ax,#0xe0d ! CR <BR>int 0x10 <BR>mov al,#0xa ! LF <BR>int 0x10 <BR>ret <BR> <BR>/* <BR>* print_hex是用于调试目的的,打印出 <BR>* ss:bp所指向的十六进制数。 <BR>* !! 例如,十六进制数是0x4321时,则al分别等于4,3,2,1调用中断打印出来 4321 <BR>*/ <BR> <BR>print_hex: <BR>mov cx, #4 ! 4个十六进制数字 <BR>mov dx, (bp) ! 将(bp)所指的值放入dx中 <BR>print_digit: <BR>rol dx, #4 ! 循环以使低4比特用上 !! 取dx的高4比特移到低4比特处。 <BR>mov ax, #0xe0f ! ah = 请求的功能值,al = 半字节(4个比特)掩码。 <BR>and al, dl !! 取dl的低4比特值。 <BR>add al, #0x90 ! 将al转换为ASCII十六进制码(4个指令) <BR>daa !! 十进制调整 <BR>adc al, #0x40 !! (adc dest, src ==> dest := dest + src + c ) <BR>daa <BR>int 0x10 <BR>loop print_digit <BR>ret <BR> <BR> <BR>/* <BR>* 这个过程(子程序)关闭软驱的马达,这样 <BR>* 我们进入内核后它的状态就是已知的,以后也就 <BR>* 不用担心它了。 <BR>*/ <BR>kill_motor: <BR>push dx <BR>mov dx,#0x3f2 <BR>xor al,al <BR>outb <BR>pop dx <BR>ret <BR> <BR>!! 数据区 <BR>sectors: <BR>.word 0 !! 当前每磁道扇区数。(36||18||15||9) <BR> <BR>disksizes: !! 每磁道扇区数表 <BR>.byte 36, 18, 15, 9 <BR> <BR>msg1: <BR>.byte 13, 10 <BR>.ascii "Loading" <BR> <BR>.org 497 !! 从boot程序的二进制文件的497字节开始 <BR>setup_sects: <BR>.byte SETUPSECS <BR>root_flags: <BR>.word CONFIG_ROOT_RDONLY <BR>syssize: <BR>.word SYSSIZE <BR>swap_dev: <BR>.word SWAP_DEV <BR>ram_size: <BR>.word RAMDISK <BR>vid_mode: <BR>.word SVGA_MODE <BR>root_dev: <BR>.word ROOT_DEV <BR>boot_flag: !! 分区启动标志 <BR>.word 0xAA55 <BR> <BR> <BR> <BR> <BR>来源:Linux自由鸽 <BR> <BR>-- <BR> <BR>※ 来源:·BBS 水木清华站 smth.org·[FROM: 159.226.41.166] <BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -