仿98(DOS7.1)的F$.EXE(>512M模式運行),P_QUEST的P$.EXE
本文基於486DX2,主板,可帶primary(啟動)/secondary控制IDE器2,中斷14/15,每個IDE,可帶master(啟動,電纜中)/slave(纜端)(跳線ds插/空)2通道,每通道,可帶1台硬盤驅動器,每驅動器,可帶1塊NORMAL,LBA,LARGE模式的IDE硬盤.
DOS,98對硬盤,先按IDE,後按m/s,依次編號,不編閒置通道.例如,有3塊盤,塊1,2在pri_m/s上,塊3在sec_cs上,此3塊,編為80h~82h.
開機盤的IDE及通道,由BIOS的BOOT SEQ指定.
(1) DOS/98的讀寫F16/32格式的位置X的Y個連續扇區的BIOS中斷13h參數:
ah的2/3指明讀/寫,al的低6位指明Y,es:bx指向內存buf首,cl的低6位指明X的扇號sector,最小1,ch,左拼cl第6,7位,齊指X的柱面號cylinder,最小0,dh指明磁頭號head,最小0,dl指明軟硬盤編號.
IDE原有的NORMAL,BIOS限定柱面數1024,磁頭數16,扇區數63,每扇512字節,相乘=容量528MB.用作cmos_chs(cylinder:head:sector)立體尋扇.
LBA,僅磁頭數異達255,容量8.4GB
LARGE,柱面數>1024,磁頭數16,控制器做柱面數/2,磁頭數*2,以適13h.容量2048*16*63*512=1G
周邊設定:Block模式加速,PIO(並行I/O接口)模式,影響rate
(2) 針對LBA的擴展13h線性64位lba尋扇:
chs轉時,lba=c*sectors_per_cylinder+h*sectors_per_track+(s-1)
其中,sectors_per_cylinder為每柱面扇數,sectors_per_track為每磁道扇數,因s從1編號,要減1.
互轉,見"(7) 文"的chs2lba,lba2chs.
利用extblk塊:
extblk db 16 ;塊的字節數(含此字節)
db 0
sec_tot dw 1 指明Y個扇區
buf_off dw 0 ;內存buf偏移
buf_seg dw 0 ;buf段值
lbal dw 0 ;lba低雙字低字
lbah dw 0 ;lba低雙字高字
dd 0 ;lba高雙字
讀/寫時,ah=42h/43h,多ds:si指向extblk
擴展i13的BIOS支持性(柱數<1024,先用chs),及導出硬盤柱數,頭數,每道扇數,算法見"(7) 文"的h_geo
(3) 硬盤分區:
每硬盤,最多劃為DOS主分區,DOS擴展分區,非DOS分區之1的4區,述於16字節/區的64字節分區表(dpt):
bootON db 0 80H/0,是活躍/不活躍.
db ? 分區啟動chs的頭號
dw ? 低6位:扇區,低第6,7位與高字節,'齊指'柱面號
volume db 0 分區標識值
db ? 結束chs
dw ?
Front dd 0 此分區之前(稱隱藏)扇區數.INT_25H_dx=1,是在其後讀邏輯首扇
In dd 0 此分區所含扇區數
MBR(F$制的1扇盤主引導記錄,軟盤0:0:1,硬盤DOS分區的首扇,即INT_25H_扇號dx=1),轉cpu給Format.com制的駐有OS的活躍主分區引導記錄(OBR).
主分區的保留區(引導扇區PBS囿其內,軟盤僅藏1區)之後,常是2份FAT,再後,是根目錄.
PBS片斷:
0~2:JMP引導程序
3~0AH:廠,sys_ver
(BPB首)0BH~0CH:每扇bytes
0DH:每簇扇數
0EH~0FH:保留區扇數
10H:FAT份數
11H~12H:F16根目錄32字節項的數目,F32:0.
13H~14H:軟盤,32M內硬盤:分區總扇數
15H:介質,軟盤:F0H,硬盤:F8H
16H~17H:軟盤,32M內硬盤:每FAT占用扇
18H~19H:每道扇數
1AH~1BH:磁頭數
1CH~1FH:此分區之前隱藏扇數
20H~23H:32M外硬盤:分區總扇數
24H~27H:32M外硬盤:每FAT占用扇
40H:磁盤BIOS,1st硬盤:80H,軟盤:0
47H~51H:vol
52H~59H:file_sys
軟盤6.22的io.sys,最先分得簇,如目錄項0基第13字,指向1e,此12BIT的項值,是1f0002,指明01f->020->...->fff鏈.
分區標識值:
閒置:0
DOS主分區:1,4,6,0bh,0ch,0eh
DOS擴展分區:5,0fh
非DOS分區:其它
筆者用P,對硬盤劃分4個DOS主分區,再prw,讀此盤(0:0:0)到文件0,用debug,改分區vol值為2,用prw,回寫0到(0:0:0),P的分區info頁,顯vol對應XENIX.
釋意,見"(7) 文"的FAT
若vol<20H,則高4位,1/0表示隱藏/非隱藏,後綴X,用於擴展i13接口.
各硬盤,均含0:0:1(chs)的1扇MBR,其偏移1be字節,連續存4個分區表.
各硬盤,最多1個DOS擴展分區,其內,能劃分稱為邏輯分區的數個DOS主分區,非DOS分區.
邏輯分區串成鏈.例如,vol=5的擴展分區E,先含1個DOS主分區D,後含1個非DOS分區N,則E的Front域值F,是E內的各邏輯分區位置基址,F指明扇區S1,而S1的偏移1be字節,是D的分區表,偏移1ce字節,其vol=0fh,表示DOS擴展分區,其Front域值,加上基址F,指明扇區S2,而S2的偏移1be字節,是N的分區表,偏移1ce字節,其vol=鏈尾0.
(4) 仿F$及P$,列出分區邏輯盤符:
盤符,C:~Z:列出.用F$,P$,能建數個邏輯分區
分區超過Z:符時,F$照列,P$不賦盤符,prw賦^符
活躍分區數>1時,引導錯,但F$及prw照列,P$顯錯
F$,P$,依vol域,查以下3步,每步,查80h至83h:
(1) 查DOS主分區
若是,則查bootON是否80H,若是,此分區就占1個邏輯盤符,若無活躍主分區,表項在MBR首現的主分區,就占1個邏輯盤符.
例如,3硬盤,80h的第1,3分區是主分區,但第3分區活躍,則第3分區占盤符C:.而81h,只含DOS擴展分區,其上,含1個DOS主分區及1個非DOS分區;82h的第2,4分區是不活躍主分區,則最先在MBR中出現的第2分區,占盤符D:
(2) 查DOS擴展分區
按邏輯分區在鏈上次序,查它是否DOS主分區,若是,就占盤符,81h的DOS擴展分區上的DOS主分區,占盤符E:
(3) 查未占過盤符的DOS主分區及非DOS分區
按MBR中,分區表項出現的先後次序,查分區是否DOS主分區,若是,且它未占過盤符,就占盤符.80h的第1分區,占盤符F:,82h的第4分區,占盤符G:
F$,P$,prw,不給非DOS分區賦盤符,僅顯In值.
(5) 例:
筆者486,在pri_ds上,裝ST32140A驅動器(2012M),在sec_ds上,裝QUANTUM(514M).
(5.1) 80h上,現有vol=6的DOS活躍主分區(FAT16B,1299M),vol=6的主分區(F16B,39.4M),vol=17h的非DOS分區(HiddenNTFS,574.9M),vol=5的擴展分區,其托4個邏輯分區,按鏈上次序是:
vol=0bh的DOS主分區(F32,35.4M),vol=83h的非DOS分區(LINUX_Ext2,19.7M),vol=1的DOS主分區(Unfmt,3.9M),vol=6的主分區(41.3M)
(5.2) 81h上,現有vol=82h的非DOS分區(L_Swap,3M),vol=11h的非DOS分區(Unfmt,3M),vol=6的活躍主分區(472.5M),vol=0fh的擴展分區,其托4個邏輯分區,按鏈上次序:
vol=82h的非DOS分區(L_Swap,10.8M),vol=1的主分區(F12,8.8M),vol=7的非DOS分區(N,9,8M),vol=1的主分區(U,7.8M).
從98軟盤啟動,F$,P$,列出這些分區的盤符及容:
C:1299M
D;472.5M
E:35.4M
F:3.9M
G:41.3M
J:39.4M
H:8.8M
I:7.8M
(6) prw功能
命令行是prw.exe [foo1]
初見:
b(pb),p(arti),r(ead sec to foo/stdout),w(rite foo to sec),v(xd w)
命令鍵b,p,r,w,v:
(6.1) b,顯subBPB
(6.2) p,顯分區盤編號,邏輯盤符,BootON值,vol值,Front值,In值,例如
80,C:,Boot:80,FAT:06,Front:0000003f,In:00101661
(6.3) r,讀軟硬盤內容到新建foo,或stdout
(6.4) wv,寫已存foo到軟硬盤.v多依VxD,勝v86禁13h寫.算法,見"(8) 論V86下,直尋硬盤扇區,只能靠VxD"
rwv,用舊FCB式,讀源F16,F32,寫F16.逐扇有結果I/O,直至出錯或事成.
欲讀80h的MBR到文件b:d,先發:
prw b:d
再答r,界面:
drv(00~01,80~83)80
0~cyl(0029)
0~hd(1f)
1~sec(3f)
0~lba(00014abf)
c(hs),l(ba)l
0~lba(00014abf)00000000
0~cyl(0000)
0~hd(00)
1~sec(01)
0~lba(00000000)
1~total(ffff)0001
事成/中止,d長度512/0.
v86時,改向buf文符到F32的文件g,可發prw c:u>g
(7) 文
NIBSZ=8 ;8個hex數
nibasc macro
local nq
add al,48
cmp al,10+48
jb nq
add al,97-48-10
nq:
endm
alasc macro
mov ah,al
and al,15
nibasc
xchg ah,al
rept 4
shr al,1 高nibble
endm
nibasc
stosw
endm
axasc macro
push ax
mov al,ah 轉ah
alasc
pop ax 轉al
alasc
endm
d segment
buf db 511 dup(0) 放MRB.全囿V86頁(4k),buf長1023,囿DMA_64k
buf511 db 0 老buf尾
info_sz dw 26 ;min sz of info buf 新buf
flags dw 0 ;flags
cylinders0 dw 0 ;number of cylinders on disk
cylinders1 dw 0
heads00 db 0 ;number of heads on disk
heads01 db 0
heads1 dw 0
s1track00 db 0 ;number of sectors per track
s1track01 db 0
s1track1 dw 0
sectors dq 0 ;number of sectors on requested disk
sector_sz dw 0 ;number of bytes per sector
db 511-26 dup(0) ;新buf
FAT db 13,10,'0~0eh:'
db 13,10,'?OS,F12/Unfmt,,,F16/U_,EXtend,F16B,NTFS,,,,F32,F32_13X,,F16'
db 13,10,'11,14,16,17,1b:(Hidden)'
db 13,10,'F12/U_,F16,F16B,N,F32$'
.view db '0000,cx='
viewcx db '13EX,dx='
viewdx db 'tend'
CR db 13,10,36
extblk db 16,0 分區表16字節用
sec_tot dw 1
buf_off dw buf ;buf偏移
buf_seg dw SEG buf
lbal dw 0 ;lba低雙字低字
lbah dw 0 ;lba低雙字高字
dd 0 ;lba高雙字
cmd_p db 'b(pb),p(arti),r(ead sec to foo/stdout),w(rite foo to sec),v(xd w)$';rwv用
logi_p db 13,10,'logi_drv(A:=01)$'
subBPB db 13,10,'SV_sec:'
SV_sec db 0,'000,FATs:' 向foo讀
FATs db '00,sec_per_FAT:'
sec1FAT db '0000$'
drv_p db 13,10,'drv(00~01,80~83)$' ;擴展i13用
mod_p db 13,10,'c(hs),l(ba)$' ;dosext,nondos用
db 13,10
from80 db '8?,'
logidrv db 'C:,Boot:'
Boot db '?0,FAT:'
volume db '06,Front:'
Front_h dw ?,? 又做總扇數
Front_l db '0000,In:'
In_h dw 0,? 又做當前扇號
In_l db '0000$'
cyl_p db 13,10,'0~cyl('
cyl_p1 db '????)$'
hd_p db 13,10,'0~hd('
hd_p1 db '??)$'
sec_p db 13,10,'1~sec('
sec_p1 db '??)$'
lba_p db 13,10,'0~lba('
lbah_p1 db '????'
lbal_p1 db '????)$'
total_p db 13,10,'1~total(ffff)$'
scr_p db '^C,f(ast),n(ext)$'
primk db 1,4,6,11,12,14 主分區標識
primksz=$-primk
extmk db 5,15 擴展分區標識
extmksz=$-extmk
stk1 dw NIBSZ/4 dup(0) ;INnib棧
db 32
rowasc db (2+1)*16 dup(32),36
kbd db NIBSZ+1 ;鍵盤buf
kbd1 db 67 parti用
kbd2 db NIBSZ+1 dup(0)
fcbdrv db 0
fcbnam db 8 dup(32)
fcbext db 3 dup(32)
fcbblk dw 0
fcbrsz dw 512
fcbsz db 4 dup (4) 已占分區表號,4硬盤*1字節,parti用
fcbdat dw 0
fcbdos1 db 10 dup(0)
fcbrno db 0
entry label dword ;fcbrand
entrydi dw 0
entryes dw 0
media_h db 0 ;頭數
media_c dw 0 ;柱數
s1cyl dw 0 ;扇數/柱
s1track db 0 ;扇數/道
drv db 0 ;輸入
hd db 0
cyl dw 0
sec db 0
hextbl db '0123456789abcdef'
d ends
c segment
assume cs:c,ds:d,es:d
@ proc far
push ds ;為exe返回
xor ax,ax 壓cd20的psp:0
push ax
mov ax,d
mov es,ax
cmp byte ptr ds:[5dh],32 缺foo
je @0
inc es:SV_sec
mov cx,1+8+3
mov si,5ch sh復制盤符+大寫8.3名到5ch
lea di,fcbdrv
rep movsb es:di=ds:si的盤符+8.3
@0: mov ds,ax
mov ah,9
lea dx,cmd_p ;問命令
int 21h
mov ah,1
int 21h
cmp al,'b'
je b
jmp p
b: mov kbd,2 + 1
lea dx,logi_p 問邏輯盤
Call INnib
mov ax,440dh
mov cx,860h 傳統及擴展13,共享BPB前12字節
lea dx,buf
int 21h
mov ax,word ptr buf[7+3]
lea di,SV_sec
axasc
mov al,buf[7+5]
lea di,FATs
alasc
mov ax,word ptr buf[7+11]
or ax,ax
jnz bo
mov ax,word ptr buf[7+25]
bo: lea di,sec1FAT
axasc
mov ah,9
lea dx,subBPB
int 21h
ret
p: cmp al,'p'
jne r
mov ah,9
lea dx,FAT
int 21h
lea bx,buf
mov dx,80h 擴展i13,可兼容傳統
Call dospri
mov mod_p,dl
mov dl,80h
Call dosext
mov lbal,0
mov lbah,0
mov dl,80h
Call nondos
ret
r: mov cmd_p,al
cmp al,'r'
je rwv
cmp al,'w'
je rwv
cmp al,'v'
je v
ret
v: mov ax,1684h ;func
mov bx,3180h ;接口ID
int 2fh
mov ax,es ;es:di=V86口cs:ip
or ax,di
jnz v1
ret es,di全0,失敗
v1: mov entrydi,di
mov entryes,es
push ds
pop es
rwv: mov kbd,2 + 1
lea dx,drv_p 問磁盤
Call INnib
mov drv,bl
mov dl,bl 驅動器
test bl,80h
jne rwv1
xor dh,dh 頭
Call f_geo
jmp rwv2
rwv1: Call h_geo
rwv2: test media_h,255
jne rwv3
ret
rwv3: mul s1cyl
sub ax,1 ;lba始於0,可寫CF
sbb dx,0
mov lbal,ax
mov lbah,dx
Call lba2chs
Call rng
mov ah,9 ;問尋扇
lea dx,mod_p
int 21h
mov ah,1
int 21h
cmp al,'c'
je rwv4
mov kbd,8 + 1
lea dx,lba_p
call INnib ;問lbah,lbal
mov lbal,bx
mov ax,stk1
mov lbah,ax
Call lba2chs
jmp rwv5
rwv4:mov kbd,4 + 1
lea dx,cyl_p ;問柱面號
Call INnib
mov cyl,bx
mov kbd,2 + 1
lea dx,hd_p ;問頭號
Call INnib
mov hd,bl
mov kbd,2 + 1
lea dx,sec_p ;問扇號
Call INnib
mov sec,bl
Call chs2lba
rwv5:Call rng ;顯出立體,線性值
mov kbd,4 + 1
lea dx,total_p ;問總計
Call INnib
mov Front_h,bx
lea dx,fcbdrv ;指向fcb
mov ah,15 ;open for w,v
cmp cmd_p,'r'
jne rw1
test SV_sec,1 向foo讀
jz rw2
mov ah,16h ;create or trunc for r,軟盤啟動,拒存取F32盤
rw1: int 21h 改fcbdrv為3=C
or al,al al為0,成功
jnz rw7
mov fcbrsz,512 重置
rw2: mov ax,600h al=clr
mov bx,700h bl=page
xor cx,cx
mov dx,184fh 25*80
int 10h cursor grow 0,24
mov ah,1ah ;DTA
lea dx,buf
mov bx,dx ;I/O數據區
int 21h
rw3: test Front_h,65535
jz rw6
cmp cmd_p,'r'
jne rw4
mov ax,201h
mov dl,drv
Call rw1by1
je rw6
Call scr
test SV_sec,1 ;向foo讀
jz rw5
mov ah,15h ;強制write
lea dx,fcbdrv
int 21h
jmp rw5
rw4: mov ah,14h ;read
lea dx,fcbdrv
int 21h
Call scr
mov ax,301h
mov dl,drv
Call rw1by1
je rw8 ;出錯,關閉
rw5: add lbal,1
adc lbah,0
inc In_h
dec Front_h
jmp rw3
rw6: test SV_sec,1 向foo讀
jnz rw8
rw7: ret
rw8: mov ah,16 ;close
lea dx,fcbdrv
int 21h
ret
@ endp
dospri proc ;統計硬盤數,查DOS主分區
dospri0:cmp dl,80h+4
je dospri7
mov ax,201h ;測硬盤
mov cx,1
int 13h
jc dospri7
mov bp,4*16
xor si,si ;分區表,占4*16字節
dospri1:cmp si,4*16
je dospri4
mov al,buf[1beh+si+4] 取vol
mov cx,primksz 是主分區?
lea di,primk
repne scasb
jne dospri3
test byte ptr buf[1beh+si],80h ;取BootON
jnz dospri2
cmp bp,4*16
jnz dospri3
dospri2:mov bp,si ;暫選首現主分區
jnz dospri5
dospri3:Add si,16
jmp dospri1
dospri4:cmp bp,4*16
je dospri6
dospri5:mov si,dx
sub si,80h
mov ax,bp
div extblk
mov fcbsz[si],al 標占分區表項號
mov al,kbd1
mov logidrv,al
inc kbd1
Call Show
dospri6:inc dl ;讀下塊硬盤
jmp dospri0
dospri7:ret
dospri endp
pri_non proc
mov logidrv,32
mov cx,primksz
lea di,primk
repne scasb
jne non ;不賦非DOS分區盤符
mov logidrv,94 ^符
mov al,kbd1
cmp al,'Z'
ja non
mov logidrv,al
inc kbd1
non: Call Show
ret
pri_non endp
dosext proc 查DOS擴展分區
dosext0:cmp dl,mod_p
je dosext4
mov ax,201h
mov cx,1
int 13h
xor bp,bp
dosext1:cmp bp,4*16
je dosext3
mov al,buf[1beh+bp+4]
mov cx,extmksz 是擴展分區?
lea di,extmk
repne scasb
jne dosext2
push bx
push dx
Call h_geo
pop dx
pop bx
mov ax,word ptr buf[1beh+bp+8] ;Front low
mov entrydi,ax 基址
mov lbal,ax
mov ax,word ptr buf[1beh+bp+10] ;Front high
mov entryes,ax
mov lbah,ax
xor bp,bp ;為show
Call chain
jmp dosext3
dosext2:Add bp,16
jmp dosext1
dosext3:inc dl
jmp dosext0
dosext4:ret
dosext endp
h_geo proc
mov ah,41h
mov bx,55aah ;測BIOS支持i13_X
int 13h
jc h_geoo
cmp bx,0aa55h 再核
jne h_geoo
test cx,1 ;支持41~44,47~48第1子集?
jz h_geoo
mov ah,48h 取尺寸
lea si,info_sz
int 13h
mov al,heads00 ;頭數
or al,al
jz h_geoo 無效info包
mov media_h,al
inc drv_p 啟擴展
mov ah,s1track00 ;每道扇數
mov s1track,ah
mul ah
mov s1cyl,ax 每柱面扇數
mov ax,cylinders0 ;柱面數
mov media_c,ax
ret
h_geoo: mov ah,8 取尺寸
int 13h
jc h_geoq
inc dh
mov al,dh
mov media_h,al ;頭數
mov s1track,cl
and s1track,63 每道扇數
mul s1track
mov s1cyl,ax ;每柱面扇數
xchg ch,cl
rol ch,1
rol ch,1
and ch,3
mov ax,cx
inc ax
mov media_c,ax ;柱面數
h_geoq: ret
h_geo endp
chain proc ;處理鏈
chain0: mov ax,201h
Call rw1by1
mov al,buf[1beh+4]
call pri_non
test buf[1beh+16+4],255 ;0,5,15之1
je chain1
mov ax,word ptr buf[1beh+16+8]
add ax,entrydi ;加基址entrydi
mov lbal,ax
mov ax,word ptr buf[1beh+16+10]
adc ax,entryes ;加基址entryes
mov lbah,ax
jmp chain0
chain1: ret
chain endp
nondos proc 查未占過盤符的DOS主分區及非DOS分區
nondos0:cmp dl,mod_p
je nondos4
mov ax,201h
mov cx,1
int 13h
mov bp,dx
sub bp,80h
mov al,fcbsz[bp] 取已占分區表號
mul extblk
mov fcbdat,ax
xor bp,bp
nondos1:cmp bp,4*16
je nondos3
cmp bp,fcbdat
je nondos2 ;已占
mov al,buf[1beh+bp+4]
test al,255 不理閒置分區
jz nondos2
mov cx,extmksz ;略擴展分區
lea di,extmk
repne scasb
jz nondos2
call pri_non
nondos2:Add bp,16
jmp nondos1
nondos3:inc dl
jmp nondos0
nondos4:ret
nondos endp
show proc ;分區信息
push dx
and dl,3 盤號80~83
add dl,48
mov from80[1],dl
mov Boot,48 多數為0
test buf[1beh+bp],80h
jz show0
mov Boot,56
show0: mov al,buf[1beh+bp+4] ;顯vol
lea di,volume
alasc
mov ax,word ptr buf[1beh+bp+8] ;取Front low
add ax,lbal ;為chain而加
pushf
lea di,Front_l
axasc
mov ax,word ptr buf[1beh+bp+10] ;Front high
popf
adc ax,lbah ;為chain而加
lea di,Front_h
axasc
mov ax,word ptr buf[1beh+bp+12] ;取In low
lea di,In_l
axasc
mov ax,word ptr buf[1beh+bp+14] ;In high
lea di,In_h
axasc
mov ah,9
lea dx,from80
sub dx,2
int 21h
pop dx
ret
Show endp
rw1by1 proc 讀/寫1扇
test drv_p,1 13=傳統
jnz rw1by11
xor al,al 不校驗寫
or ah,40h
lea si,extblk ;擴展塊
jmp rw1by12
rw1by11:push ax
push dx
call lba2chs
pop dx
pop ax
call cxdh
mov word ptr viewcx,cx
mov word ptr viewdx,dx
rw1by12:cmp cmd_p,'v'
je rw1by13
int 13h
ret 遺c
rw1by13:Call [entry]
cmp bp,4096 VxD按(8.3)返bp值
jae rw1by14
push bx
add bx,bp ;使bx,bx+511在4k內
mov buf_off,bx 擴展i13
push cx
push si
lea si,buf511 ;原buf尾
mov di,si
add di,bp ;新buf尾
std ;從後向前移1扇
mov cx,256
rep movsw
cld
pop si
pop cx
Call [entry]
pop bx
mov buf_off,bx 擴展i13
cmp bp,4096
rw1by14:je rw1by15
cmp bp,1010h
jne rw1by16
xor ah,ah
Call [entry] 釋它頁
rw1by15:cmp al,al 置zr
rw1by16:ret
rw1by1 endp
f_geo proc
lea bx,buf ;緩區
mov cx,1 ;0:0:1(chs)引導扇
f_geo0: mov ax,201h ;讀1扇
int 13h ;讀11起的bios參數塊
jc f_geo0 ;換盤
mov al,[bx+26] ;偏移26:頭數
mov media_h,al
mov ah,[bx+24] ;偏移24:每道扇數
mov s1track,ah
mul ah
mov s1cyl,ax ;每柱面扇數
mov ax,[bx+19] ;偏移19:總扇數
xor dx,dx ;高字
div s1cyl
mov media_c,ax ;柱面數
ret
f_geo endp
rng proc
mov ax,cyl ;當前柱面
lea di,cyl_p1
axasc
mov al,hd ;當前頭
lea di,hd_p1
alasc
mov al,sec ;當前扇號
lea di,sec_p1
alasc
mov ax,lbah ;當前lba高字
lea di,lbah_p1
axasc
mov ax,lbal ;當前lba低字
lea di,lbal_p1
axasc
mov ah,9
lea dx,cyl_p
int 21h
lea dx,hd_p
int 21h
lea dx,sec_p
int 21h
lea dx,lba_p
int 21h
ret
rng endp
scr proc
mov cx,16 字符數/row
xor si,si
scr0: push bx
mov ah,2
xor bh,bh pg
xor dx,dx dh=row
int 10h
pop bx
lea dx,.view
test si,256
jz scr1
jmp scr3
scr1: mov di,dx
mov ax,In_h 現扇號
axasc
test drv_p,1
jnz scr2
jmp scr3
scr2: lea di,viewcx
mov ax,word ptr [di]
axasc
lea di,viewdx
mov ax,word ptr [di]
axasc
scr3: mov ah,9
int 21h
scr4: mov ax,si
lea di,stk1
axasc
lea bp,rowasc
scr5: mov al,[bx+si]
mov di,si
and di,15
mov FAT[di],46
cmp al,32
jb scr6
mov FAT[di],al
scr6: mov di,bp
alasc
Add bp,2+2-1
inc si
test si,15
jne scr5
mov ah,9 行的hex
lea dx,stk1
int 21h
push bx
mov ah,64 行的asc及漢字
mov bx,1
lea dx,FAT
int 21h
pop bx
mov ah,9
lea dx,CR
int 21h
test si,255
je scr7
jmp scr4
scr7: cmp scr_p,'f'
je scr8
mov ah,9
lea dx,scr_p
int 21h
mov ah,1 ;按1鍵
int 21h
cmp al,'f'
jne scr8
mov scr_p,al
scr8: test si,511
je scr9
jmp scr0
scr9: ret
scr endp
cxdh proc
mov dh,hd ;頭號
mov cx,cyl ;柱面號
xchg cl,ch
ror cl,1
ror cl,1
and cl,not 63
or cl,sec ;低6位扇號
ret
cxdh endp
lba2chs proc
mov ax,lbal
mov dx,lbah
div s1cyl ;柱面號
mov cyl,ax
mov ax,dx
div s1track
mov hd,al ;頭號
inc ah
mov sec,ah ;扇號
ret
lba2chs endp
chs2lba proc
mov ax,cyl ;柱面號
mul s1cyl
mov lbal,ax
mov lbah,dx
mov al,s1track ;每道扇數
mul hd
Add lbal,ax
adc lbah,0
mov al,sec ;此處,低6位扇號
dec al
cbw
Add lbal,ax
adc lbah,0
ret
chs2lba endp
INnib proc ;kbd限長nib入kbd2.轉後入stk1,低字還入bx
INnib0: mov ah,9
int 21h
push dx
inc ah ;回車才收
lea dx,kbd
int 21h
pop dx
mov al,kbd
dec al
cmp al,kbd1 ;實長
jnz INnib0
xor bp,bp
lea si,kbd2
INnib1: lodsb
mov cx,16
lea di,hextbl
repne scasb
jnz INnib0
dec kbd1
inc cx ;轉'[0-9a-f]'為0~15
sub cx,16
neg cx
rept 4
shl bx,1 ;bx接收nibble,左入0
endm
or bl,cl
test kbd1,3 ;已收4個nibble
jnz INnib1
mov stk1[bp],bx
add bp,TYPE stk1
test kbd1,NIBSZ*2-1
jnz INnib1
ret
INnib endp
c ends
end @
(8) 論V86下,直尋硬盤扇區,只能靠VxD
VToolsD建的C級VxD,有讀/寫DOS分區的R0_ReadAbsoluteDisk/R0_Write...函數.
例如,響應自32位C的W32_DEVICEIOCONTROL事件時,用格式R0_Read...(2,1,0,buf,&w),讀相對DOS分區的邏輯扇號是1的分區引導扇區PBS.這時,當前虛擬機hVM,是系統(證於Test_Sys_VM_Handle測事件實參IOCTLPARAMS.dioc_hvm).VxD不改hVM身份.
又如,響應自16位ASM程序的V86_API_Entry入口調用時,同上,讀PBS,這時,hVM是DOS(證於Test_...測入口實參VMHANDLE).
均讀PBS含"MSWIN4...".
但VxD,也能在V86下,用Exec_Int(0x13),法如13h,直尋硬盤,如PBS之前MBR.
筆者c.cpp+a.exe,直讀MBR連續5扇.需cfg.sys,隱dev=EMM386
(8.1) 用QuickVxD,建C++級VxD,設備名=C,設備ID=0x3180,選動態裝
選API頁Standard App Entry Points框Real/V86 Mode.體,見(8.3).
選OnSysDynamicDevice的Init及Exit.體中:
選發SHELL_SYSMODAL_Message(Get_Cur_VM_Handle(),MB_SYSTEMMODAL,"m","cap")
必發return(true)
(8.2) 寫a.asm,匯編時,/DNPAGE=5,指明5扇.讀變寫,需debug下,改r2w3處的2為3.
VxD查客戶這5扇緩區,囿V86空間1頁(4K字節)的整體性,未全囿,bp返回<4k的修正量.
IF2
IF NPAGE LT 1 or NPAGE GT 8
%OUT 0 .ERR
ENDIF
ENDIF
d segment
buf db NPAGE*512*2-1 dup(9);留足修區
entry dd 0
d ends
c segment
assume cs:c,ds:d
@: mov bp,d
mov ds,bp
mov ax,1684h 功能號
mov bx,3180h 接口ID
int 2fh
mov ax,es es/di=API_Entry入口段/偏移
or ax,di
jz @3 ;es及di全為零,失敗
mov word ptr [entry],di
mov word ptr [entry+2],es
mov ax,ds 設exec_int參數
mov es,ax
lea bx,buf es:bx,指向緩區首
r2w3: mov ah,2 讀80h硬盤MBR處NPAGE扇
mov al,NPAGE
mov cx,1 0:0:1(chs)
mov dx,128
std VxD出蘭屏,寫修
call [entry]
cmp bp,4096 VxD按(8.3)返bp值
jae @2
add bx,bp 修緩區首址
test ah,1 查讀/寫
jz @1 此例ah=2,讀盤
lea si,buf 寫入時,從後向前,移NPAGE*256字
add si,NPAGE*512-1 si指向原緩區尾
mov di, si
add di,bp di指向新緩區尾
mov cx, NPAGE*256
rep movsw ds:si所指cx字,移到es:di
mov cx,1
@1: call [entry]
cmp bp,4096
@2: je @3
cmp bp,1010h
jne @3
xor ah,ah ;釋它頁
call [entry]
@3: xor ax,ax
mov es,ax
mov ax,[bx+1beh] 成功/失敗,72h矢量=分區表首字/9
mov es:[1c8h],ax
mov ah,4ch
int 21h
c ends
end @
(8.3) ...V86_API_Entry(VMHANDLE hVM, CLIENT_STRUCT* pRegs)體
DWORD h,t;
CLIENT_STRUCT s;
if(pRegs->CBRS.Client_AH){//2讀3寫
h=(DWORD)Map_Flat(CLIENT_ES,CLIENT_BX);//h=客戶緩區首es:bx的32位線性址
t=h+pRegs->CBRS.Client_AL*512-1;//t=尾的線性址
if((h>>12)!=(t>>12)){
pRegs->CWRS.Client_BP=(4096-(h&4095));//首尾未囿同頁,bp返客戶增bx量
return;
}
if((h>>12)<0x110)//緩區能被V86尋,bp返4096
pRegs->CWRS.Client_BP=4096;
else
if(LinMapIntoV86(h>>12,hVM,0x10,1,0,&t)){
//緩區所在頁,成功映入V86第0x10頁,bp返0x1010
pRegs->CWRS.Client_BP=0x1010;
h=(16<<12)+(h&4095);//由t及偏移,得緩區V86址h
}else{//無頁等,bp返0x1110
pRegs->CWRS.Client_BP=0x1110;
return;
}
Save_Client_State(&s);//存reg
Begin_Nest_V86_Exec();//當前虛擬機,能尋V86
pRegs->CRS.Client_ES=(h>>4);//es=址h的段值
pRegs->CRS.Client_EBX=(h&15);//bx=址h的偏移
Exec_Int(0x13);
End_Nest_Exec();//復原
Restore_Client_State(&s);
if(pRegs->CWRS.Client_Flags&1024){//方向,控蘭屏
sprintf((char*)s.CBRS.Client_res30,"%x",pRegs->CWRS.Client_BP);
SHELL_SYSMODAL_Message(hVM,MB_SYSTEMMODAL,(char*)s.CBRS.Client_res30,"bp");
}
}else//知bp返0x1010時,客戶釋它頁
MapIntoV86(GetNulPageHandle(),hVM,16,1,0,0);
(8.4) 裝VxD法
靜態:
放C.VXD於c:\windows\system,在c:\windows\system.ini的386Enh,寫device=C.VxD,再reboot
動態4法:
用VxD_Loader,選C.VXD
用DriverMonitor,先打開C.VXD,再Start
放C.VXD於c:\windows\system\iosubsys,再reboot
用筆者DOS窗口a的exe
#include
#define pre "\\\\.\\"
main(int ac,char *av[]){
char *vxd;
HANDLE h;
if (ac==1) printf("vxd_load ?.vxd\n");
else{
vxd=malloc(strlen(pre)+strlen(av[1]));
sprintf(vxd,"%s%s",pre,av[1]);
h=CreateFile(vxd,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0);
if(h!=INVALID_HANDLE_VALUE){
printf("To unload,hit Enter");
getch();
CloseHandle(h);
}
}
}
裝C.VXD,事畢,敲回車到窗a,卸此VXD