编写一个可以自行启动的计算机,不需要在现有操作系统环境中运行的程序

一、相关资料

     系统启动初始化完成后最终调用19h,该中断读取软盘的第一扇区或硬盘的第一扇区到0:7c00开始的512个字节的内存空间中,并将cs:ip指向0:7c00执行。

更详细参考王爽汇编语言第二版,课程设计2,p.312

 

二、设计思路

    将安装程序分为三个段,

1、第一个段为安装程序,负责将第二个段写入第一扇区,第三个段写入2-17扇区;



2、第二个段是主引导程序,存在于软盘第一扇区,由BIOS的19h中断读取到0:7c00开始的内存单元中,并执行0:7c00的第一行代码。这一段的任务是将软盘2-17扇区的数据读入内存,并执行。(这里读入到了2000:0开始的内存中)



3、第三个段是系统程序,存放所有引导所需的程序和子程序

 

三、详细设计

assume cs:setupsg



;安装程序

;将引导所需的程序写入到软盘

setupsg segment

assume cs:setupsg

setup:

 ;主引导程序安装到第一扇区

 mov ax,initsg

 mov es,ax

 mov bx,0

 

 mov al,1

 mov ch,0

 mov cl,1

 mov dl,0

 mov dh,0

 

 mov ah,3

 int 13h

 

 ;子程序安装到从第2扇区开始的扇区

 mov ax,syssg

 mov es,ax

 mov al,15

 mov cl,2

 

 mov ah,3

 int 13h

 

 ;安装结束,返回

 mov ax,4c00h

 int 21h

 

setupsg ends





;主引导程序

;包含所有子程序的直接定址表,扇区加载程序,菜单

initsg segment

assume cs:initsg

init:

 call loadsys

 

 mov ax,2000h

 push ax

 mov ax,0

 push ax

 retf

 



loadsys:

 mov ax,2000h  ;软盘数据读取到2000:0

 mov es,ax

 mov bx,0

 

 mov al,15  ;读取的扇区数

 mov ch,0  ;0磁道

 mov cl,2  ;2扇区

 mov dl,0  ;0号驱动器

 mov dh,0  ;0面

 

 mov ah,2

 int 13h

 

 ret





initsg ends



 



;子程序

;包含所有菜单需要调用的子过程

syssg segment

assume cs:syssg



;菜单显示功能

menu:

 jmp near ptr menushow

 menudata dw offset md0,offset md1,offset md2,offset md3,offset md4,offset md5

 md0 db "------ welcome ------",0

 md1 db "1) reset pc",0

 md2 db "2) start system",0

 md3 db "3) clock",0

 md4 db "4) set clock",0

 md5 db "copyright @ 2010 Shiying,Inc.All rights reserved.",0

 systable dw sys_restart,sys_disksys,sys_showclock,sys_setclock

menushow:

 mov dh,5

 mov dl,30

 mov bp,0

 mov ax,cs

 mov ds,ax

 mov cx,5

menushow_s:

 push cx

 mov si,menudata[bp]

 mov cl,02h

 call sys_showstr

 add bp,2

 add dh,2

 pop cx

 loop menushow_s

 mov si,offset md5

 mov dh,23

 mov dl,28

 mov cl,02h

 call sys_showstr

 

 

;处理用户输入

sys_input:

 mov ah,0

 int 16h

 mov bx,0

 mov bl,al

 mov al,30h

 sub bl,al ;ascii转换为序列号

 sub bl,1 ;1-4转换为0-3

 

 cmp bx,0

 jb cycle

 cmp bx,3

 ja cycle

 add bx,bx

 call word ptr systable[bx]  ;调用菜单功能

 

cycle:

 jmp short sys_input

 

 

;重启计算机

sys_restart:

 mov ax,0ffffh

 push ax

 mov ax,0h

 push ax

 retf

 



;从硬盘引导

sys_disksys:

 call cls

 

 mov ax,0h  ;硬盘数据读取到0:7c00

 mov es,ax

 mov bx,7c00h

 

 mov al,1  ;读取的扇区数

 mov ch,0  ;0磁道

 mov cl,1  ;1扇区

 mov dl,80h  ;c盘

 mov dh,0  ;0面

 

 mov ah,2

 int 13h

 

 mov ax,0h

 push ax

 mov ax,7c00h

 push ax

 retf





;显示时钟

sys_showclock:

 call cls

 jmp short clockread

clockdata:

 clockstr dw offset cl1,offset cl2,offset cl3

 clockcolor db 02h

 cl1 db '00/00/00 00:00:00',0

 cl2 db 'press ESC return menu!',0

 cl3 db 'press F1 change color!',0

 cltable db 9,8,7,4,2,0

clockread:

 mov si,0        ;si指向'yy/mm/dd hh:mm:ss'的首地址

 mov di,0        ;di指向9,8,7,4,2,0的首地址

 mov cx,6        ;循环次数

clockread_s:

 push cx

 mov al,cltable[di]    ;从CMOS中读出年份的BCD码

 out 70h,al        

 in al,71h

 mov ah,al        ;al中位读出的数据

 mov cl,4        

 shr ah,cl        ;ah中为年份的十位数

 and al,00001111b    ;al中为年份的个位数

 add ah,30h        ;把数值转换为对应的ASCII码

 add al,30h        ;同上

 mov byte ptr cl1[si],ah    ;把读出的时间写入

 mov byte ptr cl1[si+1],al

 add si,3

 inc di

 pop cx

 loop clockread_s

clockprint:

 mov dh,6

 mov dl,30

 mov bp,0

 mov ax,cs

 mov ds,ax

 mov cx,3

clockprint_s:

 push cx

 mov si,clockstr[bp]

 mov cl,clockcolor[0]  ;将颜色值赋值给cl

 call sys_showstr

 add bp,2

 add dh,2

 pop cx

 loop clockprint_s

 mov ah,1 ;调用16h中断的1号功能(非阻塞)

 int 16h

 cmp al,1bh ;判断是否为ESC

 je clockreturn ;若是ESC,回到菜单

 cmp ah,3bh ;判断是否为F1

 je changecolor

 jmp short clockread

clockreturn:

 call cls

 mov ah,0    ;16h中断的1号功能不会清除键盘缓冲区,下次读取还会读出

 int 16h     ;调用0号功能清除一次

 jmp near ptr menu

changecolor:

 inc clockcolor

 mov ah,0    ;16h中断的1号功能不会清除键盘缓冲区,下次读取还会读出

 int 16h     ;调用0号功能清除一次

 jmp near ptr clockread

 



;设置时钟

sys_setclock:

 jmp short setclock

 setclockdata db 'Please input time like "yy/mm/dd hh:mm:ss"',0

 setsuccess   db  'Set clock successful! Press any key return...',0

setclock:

 call cls

 mov dh,6

 mov dl,20

 mov cl,02h

 mov ax,cs

 mov ds,ax

 mov si,offset setclockdata

 call sys_showstr

 call getstr 

 call settime

 mov dh,10

 mov dl,20

 mov cl,02h

 mov ax,cs

 mov ds,ax

 mov si,offset setsuccess

 call sys_showstr

 mov ah,0

 int 16h

 call cls

 jmp near ptr menu





;ds:si指向时间字符串

settime:

 jmp short seting

 settable db 9,8,7,4,2,0

seting:

 mov bx,0

 mov cx,6

settime_s:

 mov dh,ds:[si]

 inc si

 mov dl,ds:[si]

 add si,2

 mov al,30h

 sub dl,al

 sub dh,al

 shl dh,1

 shl dh,1

 shl dh,1

 shl dh,1

 or dl,dh

 mov al,settable[bx]

 out 70h,al

 mov al,dl

 out 71h,al

 inc bx

 loop settime_s

 ret

 

;子程序:接收字符串

getstr:

 push ax

getstrs:

 mov ah,0

 int 16h

 cmp al,20h

 jb nochar

 mov ah,0

 call charstack

 mov ah,2

 mov dh,8

 mov dl,25

 call charstack

 jmp getstrs

nochar:

 cmp ah,0eh

 je backspace

 cmp ah,1ch

 je enter

 jmp getstrs

backspace:

 mov ah,1

 call charstack

 mov ah,2

 call charstack

 jmp getstrs

enter:

 mov al,0

 mov ah,0

 call charstack

 mov ah,2

 call charstack

 pop ax

 ret

 

 

;子程序:字符串入栈,出栈和显示

;参数:(ah)=功能号,0入栈,1出栈,2显示

;  ds:si指向字符栈空间,对于0号功能,(al)表示入栈字符

;  1号功能,(al)返回的字符,对于2号功能,(dh)(dl)字符串在屏幕显示的行列位置

charstack:

 jmp short charstart

 table dw charpush,charpop,charshow

 top  dw 0

charstart:

 push bx

 push dx

 push di

 push es

 cmp ah,2

 ja sret

 mov bl,ah

 mov bh,0

 add bx,bx

 jmp word ptr table[bx]

charpush:

 mov bx,top

 mov [si][bx],al

 inc top

 jmp sret

charpop:

 cmp top,0

 je sret

 dec top

 mov bx,top

 mov al,[si][bx]

 jmp sret

charshow:

 mov bx,0b800h

 mov es,bx

 mov al,160

 mov ah,0

 mul dh

 mov di,ax

 add dl,dl

 mov dh,0

 add di,dx

 mov bx,0

charshows:

 cmp bx,top

 jne noempty

 mov byte ptr es:[di],' '

 mov byte ptr es:[di+1],02h

 jmp sret

noempty:

 mov al,[si][bx]

 mov es:[di],al

 mov byte ptr es:[di+2],' '

 mov byte ptr es:[di+1],02h

 inc bx

 add di,2

 jmp charshows

sret:

 pop es

 pop di

 pop dx

 pop bx

 ret

 



;显示0结尾的字符串

;参数:dh=行号,dl=列号,cl=颜色,ds:si指向字符串首地址

sys_showstr:

 push ax

 push cx

 push dx

 push si

 push bp

 push es

 mov ax,0b800h

 mov es,ax

 mov al,80*2 ;80*2*行号

 mul dh

 mov dh,0

 add dx,dx ;列号*2

 add ax,dx

 mov bp,ax

showstr_s:

 mov ch,ds:[si]

 cmp ch,0

 je showstr_return

 mov es:[bp],ch

 inc bp

 mov es:[bp],cl

 inc bp

 inc si

 jmp short showstr_s

showstr_return:

 pop es

 pop bp

 pop si

 pop dx

 pop cx

 pop ax

 ret

 



;清屏

cls:

 mov ax,0b800h

 mov ds,ax

 mov bx,0

 mov cx,24*80*2

cls_s:

 mov byte ptr ds:[bx],0

 add bx,2

 loop cls_s

 mov bx,1

resetcol:

 mov byte ptr ds:[bx],07h

 add bx,2

 loop resetcol

 ret

 

 

syssg ends





;安装过程的第一行指令

end setup

 

 

 

 

四、测试过程

1、测试工具

     测试使用Sun VirtualBox虚拟机和仿真虚拟软驱(http://download.csdn.net/source/2209509

a)安装仿真虚拟软驱以后,我的电脑中会模拟出一个本地磁盘A,可以像真的软盘一样对其进行读写等
b)在windows命令行下对程序进行编译连接,执行后引导代码写入到软盘中

c)新建一个虚拟机,使用软盘A引导,启动虚拟机

你可能感兴趣的:(操作系统)