📄 1.html
字号:
#include<p>
.text<p>
SETUPSECS = 4 ! 默认的setup程序扇区数(setup-sectors)的默认值;<p>
BOOTSEG = 0x7C0 ! bootsect的原始地址;<p>
INITSEG = DEF_INITSEG ! 将bootsect程序移到这个段处(0x9000) - 避开;<br>
SETUPSEG = DEF_SETUPSEG ! 设置程序(setup)从这里开始(0x9020);<br>
SYSSEG = DEF_SYSSEG ! 系统加载至0x1000(65536)(64k)段处;<br>
SYSSIZE = DEF_SYSSIZE ! 系统的大小(0x7F00): 要加载的16字节为一节的数;<br>
!! 以上4个DEF_参数定义在boot.h中:<br>
!! DEF_INITSEG 0x9000<br>
!! DEF_SYSSEG 0x1000<br>
!! DEF_SETUPSEG 0x9020<br>
!! DEF_SYSSIZE 0x7F00 (=32512=31.75k)*16=508k<p>
! ROOT_DEV & SWAP_DEV 现在是由"build"中编制的;<br>
ROOT_DEV = 0<br>
SWAP_DEV = 0<br>
#ifndef SVGA_MODE<br>
#define SVGA_MODE ASK_VGA<br>
#endif<br>
#ifndef RAMDISK<br>
#define RAMDISK 0<br>
#endif<br>
#ifndef CONFIG_ROOT_RDONLY<br>
#define CONFIG_ROOT_RDONLY 1<br>
#endif<p>
! ld86 需要一个入口标识符,这和通常的一样;<br>
.globl _main<br>
_main:<br>
#if 0 /* 调试程序的异常分支,除非BIOS古怪(比如老的HP机)否则是无害的 */<br>
int 3<br>
#endif<br>
mov ax,#BOOTSEG !! 将ds段寄存器置为0x7C0;<br>
mov ds,ax<br>
mov ax,#INITSEG !! 将es段寄存器置为0x9000;<br>
mov es,ax<br>
mov cx,#256 !! 将cx计数器置为256(要移动256个字, 512字节);<br>
sub si,si !! 源地址 ds:si=0x07C0:0x0000;<br>
sub di,di !! 目的地址es:di=0x9000:0x0000;<br>
cld !! 清方向标志;<br>
rep !! 将这段程序从0x7C0:0(31k)移至0x9000:0(576k)处;<br>
movsw !! 共256个字(512字节)(0x200长);<br>
jmpi go,INITSEG !! 间接跳转至移动后的本程序go处;<p>
! ax和es现在已经含有INITSEG的值(0x9000);<p>
go: mov di,#0x4000-12 ! 0x4000(16k)是>=bootsect + setup 的长度 +<br>
! + 堆栈的长度 的任意的值;<br>
! 12 是磁盘参数块的大小 es:di=0x94000-12=592k-12;<p>
! bde - 将0xff00改成了0x4000以从0x6400处使用调试程序(bde)。如果<br>
! 我们检测过最高内存的话就不用担心这事了,还有,我的BIOS可以被配置为将wini驱动<br>
表<br>
! 放在内存高端而不是放在向量表中。老式的堆栈区可能会搞乱驱动表;<p>
mov ds,ax ! 置ds数据段为0x9000;<br>
mov ss,ax ! 置堆栈段为0x9000;<br>
mov sp,di ! 置堆栈指针INITSEG:0x4000-12处;<br>
/*<br>
* 许多BIOS的默认磁盘参数表将不能<br>
* 进行扇区数大于在表中指定<br>
* 的最大扇区数( - 在某些情况下<br>
* 这意味着是7个扇区)后面的多扇区的读操作。<br>
*<br>
* 由于单个扇区的读操作是很慢的而且当然是没问题的,<br>
* 我们必须在RAM中(为第一个磁盘)创建新的参数表。<br>
* 我们将把最大扇区数设置为36 - 我们在一个ED 2.88驱动器上所能<br>
* 遇到的最大值。<br>
*<br>
* 此值太高是没有任何害处的,但是低的话就会有问题了。<br>
*<br>
* 段寄存器是这样的: ds=es=ss=cs - INITSEG,(=0X9000)<br>
* fs = 0, gs没有用到。<br>
*/<p>
! 上面执行重复操作(rep)以后,cx为0;<p>
mov fs,cx !! 置fs段寄存器=0;<br>
mov bx,#0x78 ! fs:bx是磁盘参数表的地址;<br>
push ds<br>
seg fs<br>
lds si,(bx) ! ds:si是源地址;<br>
!! 将fs:bx地址所指的指针值放入ds:si中;<br>
mov cl,#6 ! 拷贝12个字节到0x9000:0x4000-12开始处;<br>
cld<br>
push di !! 指针0x9000:0x4000-12处;<p>
rep<br>
movsw<p>
pop di !! di仍指向0x9000:0x4000-12处(参数表开始处);<br>
pop si !! ds => si=INITSEG(=0X9000);<p>
movb 4(di),*36 ! 修正扇区计数值;<p>
seg fs<br>
mov (bx),di !! 修改fs:bx(0000:0x0078)处磁盘参数表的地址为0x9000:0x4000-12;<br>
seg fs<br>
mov 2(bx),es<p>
! 将setup程序所在的扇区(setup-sectors)直接加载到boot块的后面。!! 0x90200开始处<br>
;<br>
! 注意,es已经设置好了。<br>
! 同样经过rep循环后cx为0<p>
load_setup:<br>
xor ah,ah ! 复位软驱(FDC);<br>
xor dl,dl<br>
int 0x13<p>
xor dx,dx ! 驱动器0, 磁头0;<br>
mov cl,#0x02 ! 从扇区2开始,磁道0;<br>
mov bx,#0x0200 ! 置数据缓冲区地址=es:bx=0x9000:0x200;<br>
! 在INITSEG段中,即0x90200处;<br>
mov ah,#0x02 ! 要调用功能号2(读操作);<br>
mov al,setup_sects ! 要读入的扇区数SETUPSECS=4;<br>
! (假释所有数据都在磁头0、磁道0);<br>
int 0x13 ! 读操作;<br>
jnc ok_load_setup ! ok则继续;<p>
push ax ! 否则显示出错信息。保存ah的值(功能号2);<br>
call print_nl !! 打印换行;<br>
mov bp,sp !! bp将作为调用print_hex的参数;<br>
call print_hex !! 打印bp所指的数据;<br>
pop ax<p>
jmp load_setup !! 重试!<p>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<br>
!!INT 13 - DISK - READ SECTOR(S) INTO MEMORY<br>
!! AH = 02h<br>
!! AL = number of sectors to read (must be nonzero)<br>
!! CH = low eight bits of cylinder number<br>
!! CL = sector number 1-63 (bits 0-5)<br>
!! high two bits of cylinder (bits 6-7, hard disk only)<br>
!! DH = head number<br>
!! DL = drive number (bit 7 set for hard disk)<br>
!! ES:BX -> data buffer<br>
!! Return: CF set on error<br>
!! if AH = 11h (corrected ECC error), AL = burst length<br>
!! CF clear if successful<br>
!! AH = status (see #00234)<br>
!! AL = number of sectors transferred (only valid if CF set for some<br>
!! BIOSes)<br>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<p>
<br>
ok_load_setup:<p>
! 取得磁盘驱动器参数,特别是每磁道扇区数(nr of sectors/track);<p>
#if 0<p>
! bde - Phoenix BIOS手册中提到功能0x08只对硬盘起作用。<br>
! 但它对于我的一个BIOS(1987 Award)不起作用。<br>
! 不检查错误码是致命的错误。<p>
xor dl,dl<br>
mov ah,#0x08 ! AH=8用于取得驱动器参数;<br>
int 0x13<br>
xor ch,ch<p>
!!!!!!!!!!!!!!!!!!!!!!!!!!!<br>
!! INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)<br>
!! AH = 08h<br>
!! DL = drive (bit 7 set for hard disk)<br>
!!Return: CF set on error<br>
!! AH = status (07h) (see #00234)<br>
!! CF clear if successful<br>
!! AH = 00h<br>
!! AL = 00h on at least some BIOSes<br>
!! BL = drive type (AT/PS2 floppies only) (see #00242)<br>
!! CH = low eight bits of maximum cylinder number<br>
!! CL = maximum sector number (bits 5-0)<br>
!! high two bits of maximum cylinder number (bits 7-6)<br>
!! DH = maximum head number<br>
!! DL = number of drives<br>
!! ES:DI -> drive parameter table (floppies only)<br>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!<p>
#else<p>
! 好象没有BIOS调用可取得扇区数。如果扇区36可以读就推测是36个扇区,<br>
! 如果扇区18可读就推测是18个扇区,如果扇区15可读就推测是15个扇区,<br>
! 否则推测是9. [36, 18, 15, 9]<p>
mov si,#disksizes ! ds:si->要测试扇区数大小的表;<p>
probe_loop:<br>
lodsb !! ds:si所指的字节 =>al, si=si+1;<br>
cbw ! 扩展为字(word);<br>
mov sectors, ax ! 第一个值是36,最后一个是9;<br>
cmp si,#disksizes+4<br>
jae got_sectors ! 如果所有测试都失败了,就试9;<br>
xchg ax,cx ! cx = 磁道和扇区(第一次是36=0x0024);<br>
xor dx,dx ! 驱动器0,磁头0;<br>
xor bl,bl !! 设置缓冲区es:bx = 0x9000:0x0a00(578.5k);<br>
mov bh,setup_sects !! setup_sects = 4 (共2k);<br>
inc bh<br>
shl bh,#1 ! setup后面的地址(es=cs);<br>
mov ax,#0x0201 ! 功能2(读),1个扇区;<br>
int 0x13<br>
jc probe_loop ! 如果不对,就试用下一个值;<p>
#endif<p>
got_sectors:<p>
! 恢复es<p>
mov ax,#INITSEG<br>
mov es,ax ! es = 0x9000;<p>
! 打印一些无用的信息(换行后,显示Loading)<p>
mov ah,#0x03 ! 读光标位置;<br>
xor bh,bh<br>
int 0x10<p>
mov cx,#9<br>
mov bx,#0x0007 ! 页0,属性7 (normal);<br>
mov bp,#msg1<br>
mov ax,#0x1301 ! 写字符串,移动光标;<br>
int 0x10<p>
! ok, 我们已经显示出了信息,现在<br>
! 我们要加载系统了(到0x10000处)(64k处)<p>
mov ax,#SYSSEG<br>
mov es,ax ! es=0x01000的段;<br>
call read_it !! 读system,es为输入参数;<br>
call kill_motor !! 关闭驱动器马达;<br>
call print_nl !! 打印回车换行;<p>
! 这以后,我们来检查要使用哪个根设备(root-device)。如果已指定了设备(!=0)<br>
! 则不做任何事而使用给定的设备。否则的话,使用/dev/fd0H2880 (2,32)或/dev/PS0<br>
(2,28)<br>
! 或者是/dev/at0 (2,8)之一,这取决于我们假设我们知道的扇区数而定。<br>
!! |__ ps0?? (x,y)--表示主、次设备号?<p>
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 !! 其中保存由设备的主、次设备号;<p>
! 这以后(所有程序都加载了),我们就跳转至<br>
! 被直接加载到boot块后面的setup程序去:<p>
jmpi 0,SETUPSEG !! 跳转到0x9020:0000(setup程序的开始位置);<p>
<br>
! 这段程序将系统(system)加载到0x10000(64k)处,<br>
! 注意不要跨越64kb边界。我们试图以最快的速度<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -