王爽.彙編.第三版.課程設計2
讀完王爽彙編第三版的精簡版的作業系統,對沒有錯,就是作業系統
需要注意的是:
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不要同時使用就可以了