读完王爽汇编第三版的精简版的操作系统,对没有错,就是操作系统
需要注意的是:
0、多谢:http://www.cnblogs.com/S-E-P/archive/2010/04/06/2045067.html的代码。
1、将代码拷贝到软盘,然后再从软盘拷贝到内存的时候,程序中用到的字符串怎么寻址,因为按照目前书中的知识面,如果用标号访问字符串,则用的是偏移地址,而代码经过这样的2次拷贝后,地址早不知道偏移到哪去了(字符串地址=cs+偏移,如果要固定死cs,就限制太大了)。
解决方案:就是将各个功能分段,将每个功能放到独立的段里,此问题就大大简化了。
2、需要注意的是,功能函数的返回可以用retf简化程序的跳转,如下,跳转到2000:0
mov ax,2000h
push ax
mov ax,0
push ax
retf
当然也可以用call dword 2000:0。
测试环境:
1、我用的是vbox安装MS dos7.10。
2、用winImage制作共享软盘share.vfd和系统启动盘boot.vfd。注意,同时只能有一个程序访问vfd文件,因此winImage修改vfd时,要关闭dos,反之亦然。
2.1 share.vfd用于windows和vbox的dos系统共享软件用的,放在2号软驱(盘符B:)
2.2 boot.vfd是用于写入自制的操作系统的,放在1号软驱(盘符A:),这和bios的启动规则有关系,不赘述(见Page312)
测试过程:
直接在dos上编译代码的直接忽略这些步骤,我是在windows上的dosbox上测试并编辑代码,然后再virtual dos上测试。
1、将代码保存成kcsj2.asm,上位机编译成程序kcsj2.exe。
2、用winImage打开share.vfd,拖入kcsj.exe保存。
3、直接在v dos上将kcsj2.exe拷贝到c盘,执行kcsj2.exe制作系统盘,重启。
附录一,代码:
; 简化kcsj2的程序
; 任务菜单,只保留,restpc,startsystem,clock(只显示时间)
;注意有软盘模拟工具
;系统盘制作 段
assume cs:FloppyInstallCode
FloppyInstallCode segment
start:
;-------------------
;注意,此处没有考虑拷贝的长度,软盘上肯定有多余的字
;节,但是没有关系,因为指令会将那些字节跳过去
;-------------------
; 拷贝代码引导程序
mov ax, lodesysSeg
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
call showerror
; 拷贝任务程序
mov ax, taskCodeSeg
mov es, ax
mov bx, 0
mov al,15 ; 此处是为了保险,写的15
mov cl,2 ; 第二扇区
mov ah,3
int 13h
call showerror
;安装结束,返回
mov ax,4c00h
int 21h
showerror:
jmp short showerror_code
err db 'error: ', 0
ok db 'ok',0
buff db '0123456789abcdef'
showerror_code:
push ax
push bx
push ds
mov bx, 0b800h
mov ds, bx
cmp ah, 0
jne showerror_error
mov byte ptr ds:[18], 'o'
mov byte ptr ds:[20], 'k'
jmp short showerror_exit
showerror_error:
mov byte ptr ds:[0], 'e'
mov byte ptr ds:[2], 'r'
mov byte ptr ds:[4], 'r'
mov byte ptr ds:[6], 'o'
mov byte ptr ds:[8], 'r'
mov byte ptr ds:[10], ':'
mov al, ah
and al, 00001111b
shr ah, 1
shr ah, 1
shr ah, 1
shr ah, 1
sub bx, bx
mov bl, al
mov bl, buff[bx]
mov byte ptr ds:[12], bl
mov bl, ah
mov bl, buff[bx]
mov byte ptr ds:[14], bl
mov byte ptr ds:[16], '!'
jmp short showerror_exit
showerror_exit:
pop ds
pop bx
pop ax
ret
FloppyInstallCode ends
;--------------------------------
;引导扇区的程序
;主引导程序
;包含所有子程序的直接定址表,扇区加载程序,菜单
assume cs:lodesysSeg
lodesysSeg segment
init:
call loadsys
; 调到第二扇区执行,2000地址,自己任意设定,只要大于512字节跳过lodesysSeg就可以了
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
lodesysSegend:
nop
lodesysSeg ends
;------------------------------------------
; 任务代码, 第二扇区以后
assume cs:taskCodeSeg
taskCodeSeg segment
realcode:
jmp short run
tip1 db "1. rest pc",0
tip2 db "2. start system",0
tip3 db "3. clock",0
tipoff dw tip1, tip2, tip3
run:
; mov dh, 12
; mov dl, 34
; call showtime
call showtips
mov ah, 0
int 16h
; al
cmp al, '1'
je if_1
cmp al, '2'
je if_2
cmp al, '3'
je if_3
cmp al, 'q'
jmp exit
jmp run
if_1:
call reset_pc
jmp run
if_2:
call start_system
jmp run
if_3:
call clock
jmp run
mov ax, 4c00h
int 21h
showtips:
push ds
push es
push si
push di
push ax
push bx
push cx
push dx
mov ax, 0b800h
mov ds, ax
mov ax, 0
mov dx, 0 ; ?st tip
mov si, 0 ; screen pos
mov cx, 3 ; 3 tips
showtips_loop:
push si
mov bx, dx
mov bx, tipoff[bx]
showonetip:
mov al, byte ptr cs:[bx]
cmp al, 0
je showonetip_over
mov byte ptr ds:[si], al
mov byte ptr ds:[si+1], 00000100b
add si, 2
inc bx
jmp showonetip
showonetip_over:
pop si
add si, 160
add dx, 2
loop showtips_loop
pop dx
pop cx
pop bx
pop ax
pop di
pop si
pop es
pop ds
ret
;---------------
exit:
mov ax, 4c00h
int 21h
reset_pc:
;直接设置cs:ip,跳转到ffff:0
mov ax, 0
mov word ptr ds:[0], ax
mov ax, 0ffffh
mov ds:[2], ax
call dword ptr ds:[0]
ret
start_system:
;将C盘的第0道0面1扇区读入到0:7C00
mov ax, 0
mov es, ax
mov bx, 07c00h
mov al, 1
mov ch, 0
mov cl, 1
mov dl, 80h
mov dh, 0
mov ah, 2
int 13h
; 返回到0:7c00,注意retf的使用
mov ax, 0h
push ax
mov ax, 7c00h
push ax
retf
clock:
;显示时间
mov dh, 12
mov dl, 34
call showtime
ret
;--------------------------
; show cmos time
; 参数:dh:dl,位置中的行和列
showtime:
jmp short showtime_code
showtime_data:
db 9,8,7,4,2,0 ; 端口中时间的字节偏移
db '// :: ' ; 间隔符
showtime_code:
push es
push si
push ds
push di
push bx
push cx
push dx
call clearscreen
; 写入的位置
mov ax, 0b800h
mov es, ax
push dx
sub ax, ax
mov al, dh
mov bx, 160
mul bx
mov cx, ax
pop dx
sub ax, ax
mov al, dl
mov bx, 2
mul bx
add ax, cx
mov di, ax
; ds:si=cmos偏移字段缓存区的地址
mov ax, cs
mov ds, ax
mov ax, offset showtime_data
mov si, ax
mov cx, 6
showtime_looptime:
push cx
;偏移
mov al, byte ptr ds:[si]
out 70h, al
in al, 71h
;十位的计算
mov bh, al
and bh, 11110000b
mov cl, 4
shr bh, cl
add bh, 30h
mov byte ptr es:[di], bh
mov byte ptr es:[di+1], 00000010b
;个位的计算
mov bl, al
and bl, 00001111b
add bl, 30h
mov byte ptr es:[di+2], bl
mov byte ptr es:[di+3], 00000010b
;显示分隔符
mov al, byte ptr ds:[si+6]
mov byte ptr es:[di+4], al
mov byte ptr es:[di+5], 00000010b
add di, 6
inc si
pop cx
loop showtime_looptime
pop dx
pop cx
pop bx
pop di
pop ds
pop si
pop es
ret
;------------------------------------------
; 参数:无
; 清屏
clearscreen:
push ax
push bx
push cx
push es
mov ax, 0b800h
mov es, ax
mov bx, 0
mov ax, 0
mov cx, 160*25
clearscreen_loop:
mov byte ptr word ptr es:[bx], ' '
add bx,2
loop clearscreen_loop
pop es
pop cx
pop bx
pop ax
ret
taskCodeSeg ends
end start
附录二,vfd注意事项:
1、新建
2、不要直接保存,要使用save as:
3、剩下的dos和winImage不要同时使用就可以了