您的位置:首页 > 其它

开发操作系统实践(三)——LinDos引导扇区内容及运行环境搭建

2012-03-08 21:27 477 查看
几乎用了一周的时间才将引导扇区源代码编写、测试完成。期间不知道经历了多少痛苦和磨难。终究原因,是因为基础知识的不扎实。因为在编写过程中有很多转移指令,因为掌握的不够牢固,不能灵活运用,导致出错频繁,精神几乎崩溃

!还好,毕竟坚持了下来,基本测试通过了。

一、编译环境搭建

先说一下,我的开发环境。我用的是Windows7系统,用visual Studio2008编写源代码,因为它里面有个很不错的文本编辑器,如下图:



你可以在visual Studio2008中通过如下设置方式,使其看起来跟上面一样。打开文件菜单,新建——文件——文本文件,编写好后,将其保存为.asm文件。通过点击工具——选项——环境——字体和颜色,可以设置前景色和背景色,及字体大小。另外点击工具菜单——选项——文本编辑器——所有语言,可以显示行号。通过上面的调整,你可以发现,你的文本编辑器和上图看起来一样了。
二、在上一篇文章里,我已经说过,我的LinDos0.01要运行在软盘上。考虑到现在大多数计算机几乎不再配置软盘驱动器了,我搭建了一个虚拟计算机,来运行它。我用的是VMWare Workstation 8来搭建一个虚拟计算机。通过下面的步骤,来创建一个适合LinDos运行的虚拟硬件环境。打开VMware,点击文件菜单——新的虚拟机——自定义——WorkStation8.0——我以后再安装操作系统——选择一个客户机操作系统:其他,版本:其他——虚拟机名称:LinDos——处理器数量:1——内存:4M——不使用网络连接——BUslogic——创建一个新的逻辑磁盘——IDE——最大磁盘空间:1G,单个文件虚拟成磁盘——磁盘文件:你自己命名——完成
好了你已经搭建好我们的运行环境了。如下图:



三、创建软盘镜像文件
因为我们没有软盘驱动器,所以要在虚拟环境中运行软盘镜像文件。创建一个软盘镜像文件,很简单,用WinHex就可以办到。打开WinHex,点击文件菜单——新建——创建的文件大小:1440KB。将该文件保存为boot.img文件。好了,这就是一个软盘镜像文件了。
四、文件在磁盘上的存放
参见上篇文章:LinDos文件系统
五、引导扇区源代码
引导程序主要完成了下面的工作:
1、设置DS、SS与CS在一个代码段,设置堆栈指针到7C00H处
2、将引导程序前N个字节(里面包含有磁盘的信息,操作系统名称等)移入内存0050:0000处
3、根据根目录表所在的逻辑扇区号,计算它的物理磁头号、磁道号、逻辑扇区号
4、将根目录表所在的第一个扇区的内容读入内存0070:0000
5、要想引导系统,必须将引导文件放在根目录表的第一个目录项中。所以这一步分析根目录表的第一项文件名是否是系统引导文件“LDloader.sys”
6、计算系统引导文件LDloader.sys占用的扇区数,目录项偏移110B处是文件的大小
7、将LDloader.sys文件读入系统内存0070:0000。这里又有一个先决条件,即LDloader.sys文件放在用户数据区开头的连续扇区中。
8、JMP 0070:0000,完成系统引导,转去执行LDloader.sys。

;########################################

;# #

;# 软盘引导扇区源代码 #

;# #

;# 2012年3月05日 #

;########################################

org 7c00h

jmp start

;系统数据区

BootSecCount db 1 ;引导程序占用的扇区数

FATtype db 12 ;文件分配表FAT类型,这里是FAT12类型

FATcount db 2 ;FAT表个数

SecsOfCluster db 1 ;每簇扇区数

BytesOfSector dw 512 ;每扇区字节数

Heads db 2 ;磁头数

CylinderOfHead dw 80 ;每面磁道数

SecsOfCylinder dw 18 ;每磁道扇区数

DiskType db 0 ;磁盘类型,驱动器号(编号法则为:磁盘的第一个分区为0,第二个为1,依次类推。若为硬盘,则第7位置1

;也就是若是硬盘第一个分区则设成0x80,软盘则为0x00)

RDTcount dw 128 ;根目录表中的目录项数

BytesOfDT dw 128 ;每个目录项占用的字节数

RDTlogicSecLow dw 19 ;根目录表开始逻辑扇区号低地址值,(本来该值可以根据上面的参数计算出来,但会提高引导程序的复杂度,为了保证它的内容在

RDTlogicSecHigh dw 0 ;根目录表开始逻辑扇区号高地址值, 512字节内,我们用现成的值代替繁琐的计算过程)

UserDataLogicSecLow dw 51 ;用户数据区开始逻辑扇区号低16位

UserDataLogicSecHigh dw 0 ;用户数据区开始逻辑扇区号高16位

SystemVer db "LinDos 0.01" ;系统版本号,占用11字节

Volume db "System Disk" ;磁盘名称,最大11字节

;系统数据区结束

start:

mov ax,cs

mov ds,ax

mov ss,ax

mov sp,7c00h

;将系统数据区保存至内存0050:0000

mov si,BootSecCount

mov di,0

mov ax,50h

mov es,ax

mov cx,start-BootSecCount

cld

rep movsb

;调用SubDiskAddress子程序,计算根目录表所在的磁头号、磁道号、扇区号

ReadLBR:

mov dx,[RDTlogicSecHigh]

mov ax,[RDTlogicSecLow]

call SubDiskAddress

;将根目录表所在的第一个扇区的内容读入内存0070:0000

mov ax,70h

mov es,ax

mov bx,0

call ReadDisk

jnc next2 ;读磁盘成功跳转,否则显示错误信息

NonSysErr:

mov ax,cs

mov es,ax

mov ax,ErrorMSG

mov bp,ax

mov cx,SystemName-ErrorMSG

call TypeMSG

;获取键盘输入,按任意键重新读取磁盘

xor ax,ax

int 16h

jmp ReadLBR

next2:

;分析根目录表的第一项文件名是否是系统引导文件“LDloader.sys”

mov ax,70h

mov es,ax

mov di,0

mov si,SystemName

mov cx,11

CMPstr:

mov dl,[es:di]

mov dh,[ds:si]

cmp dl,dh

jne NonSysErr

inc di

inc si

loop CMPstr

mov dl,[es:di+1] ;检查该目录项最后一个字符是否是0

cmp dl,0

jne NonSysErr

;下面的程序,要将系统引导程序LDloader.sys从磁盘读入内存0070:0000

;1、计算LDloader.sys占用的扇区数,目录项偏移110B处是文件的大小

mov dx,[es:112]

mov ax,[es:110]

mov cx,512

call subn_32v16

cmp bx,0

je next3

inc ax ;这里我们假设LDloader.sys不会超过2^16个扇区

next3:

push ax

;显示载入系统文件提示信息

mov ax,cs

mov es,ax

mov ax,LoadMSG

mov bp,ax

mov cx,16

call TypeMSG

mov ax,70h

mov es,ax

;2、将用户数据区开始的N个扇区读入内存0070:0000

pop cx ;要读入的扇区数

mov ax,[UserDataLogicSecLow]

mov dx,[UserDataLogicSecHigh]

xor bx,bx

ReadLDlod:

push cx

push dx

push ax

push bx

call SubDiskAddress ;计算扇区物理地址

pop bx

push bx

call ReadDisk

jc NonSysErr

pop bx

add bx,512

pop ax

pop dx

inc ax

adc dx,0

pop cx

loop ReadLDlod

jmp 0070h:0000

;=============================================================================================

;根据逻辑扇区号计算对应磁盘的磁头号、磁道号、扇区号

;逻辑扇区号与物理扇区换算关系:逻辑扇区按照扇区号、磁头号、柱面号(或磁道号)增长的顺序连续分配

;假设:LH---LinDos逻辑扇区0的磁头号

; LC---LinDos逻辑扇区0的柱面号

; LS---LinDos逻辑扇区0的扇区号

; NS---每磁道扇区数

; NH---磁盘总的磁头数

;若已知某扇区柱面号C,磁头号H,扇区号S,则其对应的逻辑扇区号RS公式为:

; RS=NH*NS*(C-LC)+NS*(H-LH)+(S-DS)

;若已知某扇区的逻辑扇区号RS,则其对应的柱面号C,磁头号H,扇区号S公式为:

; S=(RS MOD NS)+LS

; H=((RS DIV NS) MOD NH)+LH

; C=((RS DIV NS)DIV NH)+LC

;入口参数:DX:逻辑扇区号高16位

; AX:逻辑扇区号低16位

;出口参数:CH—柱面,CL—扇区,DH—磁头

;=============================================================================================

SubDiskAddress:

;1、计算物理扇区号

push dx

push ax

mov cx,[SecsOfCylinder]

call subn_32v16

add bx,1

mov [Volume],bl ;保存物理扇区号

;2、计算磁头号

pop ax

pop dx

push dx

push ax

mov cx,[SecsOfCylinder]

call subn_32v16

xor cx,cx

mov cl,[Heads]

call subn_32v16

mov [Volume+1],bl ;保存物理磁头号

;3、计算物理磁道号

pop ax

pop dx

mov cx,[SecsOfCylinder]

call subn_32v16

xor cx,cx

mov cl,[Heads]

call subn_32v16

mov ch,al ;返回柱面号

mov dh,[Volume+1] ;返回磁头号

mov cl,[Volume] ;返回扇区号

ret

;===============================

;显示字符串函数

;入口参数:ES:BP,字符串地址

; CX,字符串长度

;

;

;===============================

TypeMSG:

push cx

mov ah,3 ;调用int 10H 03H功能,获得光标坐标

mov bh,0

int 10h

pop cx

mov ax,1301h ;调用int 10H 13H功能,显示字符串

mov bx,0fh

int 10h

ret

;===============================

;无符号数的32位值除以16位值

;入:DXAX=被除数

; CX=除数

;出:DXAX=商

; BX=余数

;===============================

subn_32v16:

push ax

mov ax,dx

mov dx,0

div cx

mov bx,ax

pop ax

div cx

xchg bx,dx

ret

;===============================

;读磁盘扇区功能,读入一个扇区

;入:

; CH—柱面,CL—扇区,DH—磁头

; ES:BX=缓冲区地址

;出:CF=0—操作成功,AH=00H,AL=传输的扇区数

; CF=1—操作失败,AH=状态码

;===============================

ReadDisk:

mov ax,0201h

mov dl,[DiskType]

int 13h

ret

ErrorMSG db "None system or disk error!",10,13,"Replace disk press anykey when ready.",10,13

SystemName db "LDloader.sys"

LoadMSG db "Loading... ...",10,13

times 510-($-$$) db 0

dw 0aa55h

将上面的程序保存为boot.asm。

六、编译程序
利用nasm for win32,在windows7环境中直接编译。执行如下的命令nasm boot.asm -o boot.bin
七、将引导程序写入磁盘镜像文件
打开WinHex,打开磁盘镜像文件,boot.bin,打开编译好的引导程序boot.bin。选择boot.bin的所有内容,将光标移动到boot.img文件0字节处,并选择该字节,点击鼠标右键——编辑——剪贴板数据——写入。好了,引导扇区的内容已经写入磁盘0面0道1扇区了。
八、系统引导程序
这里仅仅是个测试版本,用来检测能否引导系统,所以它的内容很简单。只是显示了一段欢迎信息。源代码如下:
org 0

jmp start

Message db "Welcome to our new operation system"

start:

mov ax,70h

mov es,ax

mov ax,Message

mov bp,ax

mov cx,start-Message

call TypeMSG

jmp $

;===============================

;显示字符串函数

;入口参数:ES:BP,字符串地址

; CX,字符串长度

;

;

;===============================

TypeMSG:

push cx

mov ah,3 ;调用int 10H 03H功能,获得光标坐标

mov bh,0

int 10h

pop cx

mov ax,1301h ;调用int 10H 13H功能,显示字符串

mov bx,0fh

int 10h

ret

将上面的程序,编译为LDloader.bin文件,并在winhex中打开,同时打开boot.bin文件。LDloader.sys文件应为于磁盘逻辑扇区51号(0面1道16扇区,至于如何计算,可参见上面的引导程序源代码)。所以我们在boot.bin文件中,打开位置菜单——转到偏移地址——26112处,将LDloader.sys文件的内容写入该处。
九、进一步完善boot.bin
因为引导程序还要检测根目录表的第一目录项的文件名是否是LDLoader.sys,并且要计算它的大小。所以我们要在根目录表的第一个目录项处填入字符串“LDloader.sys”。打开winhex,并打开文件boot.bin。将位置定位于偏移地址9728处(即逻辑19扇区,1面0道2扇区),从偏移9728开始,分别写入16进制:4C 44 6C 6F 61 64 65 72 2E 73 79
73 00。然后定位于9838处,写入00 02 00 00,这里是该文件的大小。
十、在虚拟系统中引导系统
打开vmware,选择我们刚才创建的虚拟计算机LinDos,点击右键——设置——软盘驱动器——使用软盘镜像文件:选择我们创建的boot.img文件。记住在设备状态中一定要选择“打开电源时连接”选项。好了打开电源,你就会看到下面的内容:



上面的源文件及软盘镜像文件您可以点击下面的连接下载。欢迎有软盘驱动器的留言测试情况。我只在我的虚拟系统中引导成功。

下载源文件及磁盘镜像文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: