mawenxiao
驱动牛犊
驱动牛犊
  • 注册日期2002-04-18
  • 最后登录2004-04-10
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1421回复:0

98启动软盘或关机到ms-dos,为何prw.asm的fcb_w命令失败?

楼主#
更多 发布于:2003-11-06 11:52
 
仿FDISK及PQMAGIC,列出分区逻辑盘符的prw.asm实现

FDISK,系98的FDISK.EXE(>512M模式运行)
PQMAGIC,系POWER QUEST公司的PQMAGIC.EXE(DOS版,7)

本文基于486DX2,主板,可带primary/secondary两IDE控制器,中断14/15,每个IDE,可带master,slave两通道,每个通道,可带1台硬盘驱动器,每台驱动器,可带1块NORMAL,LBA,LARGE模式的IDE硬盘.

DOS,98对硬盘,先按IDE,后按master/slave,依次编号,不编闲置通道.例如,有3块盘,块1,2在primary的master/slave上,块3在secondary的slave上,此3块,编为80h~82h.

开机盘的IDE及通道,由BIOS的BOOT SEQUENCE指定.

(1) DOS/98的读写FAT 16/32格式的位置X的Y个连续扇区的BIOS中断13h参数:
ah的2/3指明读/写,al的低6位指明Y,es:bx指向内存buf首,cl的低6位指明X的扇号sector,最小值1,ch的8位,左拼cl第6,7位,齐指X的柱面号cylinder,最小值0,dh指明磁头号head,最小值0,dl指明软硬盘编号.

NORMAL,柱面数1024,磁头数16,扇区数63,每扇512字节,相乘=容量528MB.用作chs(cylinder,head,sector)立体寻扇及98挂大盘
LBA,磁头异数到255,容量8.4GB
LARGE,盘柱面数>1024,磁头数16时,控制器做柱面数/2,磁头数*2,以调13h.容量1G

(2) 针对LBA的扩展int 13h线性64位lba寻扇:

chs转成lba的公式:lba=c*sectors_per_cylinder+h*sectors_per_track+(s-1)
其中,sectors_per_cylinder为每柱面扇数,sectors_per_track为每磁道扇数,因s从1编号,要减1.

chs,lba的互转,见\"(7) prw文\"的chs2lba,lba2chs.

利用extblk块:

extblk  db  16  ;块的字节数(包括此字节)
rsv     db  0    ;需为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,dl意义不变

扩展i13接口的BIOS支持及导出硬盘的柱面数,磁头数,每磁道扇区数的算法,见\"(7) prw文\"的h_geo

(3) 硬盘分区:

每块硬盘,最多划为DOS主分区,DOS扩展分区,非DOS分区之1的4分区,述于16字节分区表:

bootON db 0 ;80h/00,指明活跃/不活跃.MBR交控制给驻有OS的活跃主分区引导记录
db ? ;指明启动头号
dw ? ;低6位指明启动扇区,高字节的8位,左拼低字节第6,7位,齐指启动柱面号
volume db 0 ;分区标识值
db ? ;指明结束头号
dw ? ;低6位指明结束扇区,高字节的8位,左拼低字节第6,7位,齐指结束柱面号
Front dd 0 ;此分区之前扇区数,低/高字在前/后,如10025009H,5009在前
In dd 0 ;此分区所含扇区数,低/高字在前/后

分区标识值:

闲置:0
DOS主分区:1,4,6,0bh,0ch,0eh
DOS扩展分区:5,0fh
非DOS分区:其它

笔者用P,对硬盘划分4个DOS主分区,再用prw,读此盘chs(0:0:0)到文件0,用debug,改分区volume值为2,用prw,回写0到chs(0:0:0),P的分区info页,显出volume对应FAT类型XENIX.再得

0~0fh,对应:
Unknown,FAT12/Unformatted,XENIX,XENIX2,FAT16/Unformatted,Extended,FAT16B,NTFS,AIX or Coherent,AIX SplitDrive,Boot Manager,FAT32,FAT32X,Type 0D,FAT16,ExtendedX

11h,14h,16,17h,1bh,对应:
HiddenFAT12/Unformatted,HiddenFAT16,HiddenFAT16B,HiddenNTFS,HiddenFAT32

65h,82h,83h,对应:
Netware,Linux_Swap,Linux_Ext2

若volume<20H,则高4位,1/0表示隐藏/非隐藏,后缀X,用于扩展i13接口.

各硬盘,均含称为主引导记录(MBR)的1个扇,位于chs第0头第0柱面第1扇,其偏移1be字节,连续存4个分区表.

各硬盘,最多1个DOS扩展分区,其内,能划分称为逻辑分区的数个DOS主分区,非DOS分区.

逻辑分区串成链.例如,volume为5的扩展分区E,先含1个DOS主分区D,后含1个非DOS分区N,则E的Front域值F,是E内的各逻辑分区位置基址,F指明扇区S1,而S1的偏移1be字节,是D的分区表,偏移1ce字节,其volume为0fh,表明是DOS扩展分区,其Front域值,加上基址F,指明扇区S2,而S2的偏移1be字节,是N的分区表,偏移1ce字节,其volume为链尾0.

(4) 仿F及P,列出分区逻辑盘符:

盘符,从C:列向Z:.用F及P,能建数个逻辑分区

分区超过Z:符时,F照列,P不赋盘符,prw赋^符

活跃区数>1时,F,prw照列,P显错,BIOS拒boot

F及P,依volume域,查以下3步,每步,查80h至83h:

(1) 查DOS主分区
分区若是DOS主分区,则查活跃值bootON是否80H,若是,此分区就占1个逻辑盘符,若无活跃主分区,表项在MBR首现的主分区,就占1个逻辑盘符.

例如,80h~82h硬盘,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) 例:

笔者机器,在primary master上,装ST32140A驱动器(2012M),在secondary master上,装QUANTUM MAVERICK 540A驱动器(514M).

(5.1) 80h上,现有volume为6的活跃主分区(FAT16B,1299M),volume为6的DOS主分区(FAT16B,39.4M),volume为17h的非DOS分区(HiddenNTFS,574.9M),volume为5的扩展分区,其上,有4个逻辑分区,按链上次序是:
volume为0bh的DOS主分区(FAT32,35.4M,簇xk),volume为83h的非DOS分区(Linux_Ext2,19.7M),volume为1的DOS主分区(Unformatted,3.9M),volume为6的DOS主分区(FAT16B,41.3M),

(5.2) 81h上,现有volume为82h的非DOS分区(Linux_Swap,3M),volume为11h的非DOS分区(Unformatted,3M),volume为6的活跃主分区(FAT16B,472.5M),volume为0fh的扩展分区,其上,有4个逻辑分区,按链上次序:

volume为82h的非DOS分区(Linux_Swap,10.8M),volume为1的DOS主分区(FAT12,8.8M),volume为7的非DOS分区(NTFS,9,8M),volume为1的DOS主分区(Unformatted,7.8M).

用98启动盘开机,F,P,prw,对这些分区,列出盘符及容量(MB:...是prw的16进制列出)

C:1299M(MB:00000513)
D;472.5M(MB:000001d9)
E:35.4M(MB:00000023)
F:3.9M(MB:00000004)
G:41.3M(MB:00000029)
J:39.4M(MB:00000027)
H:8.8M(MB:00000009)
I:7.8M(MB:00000008)

(6) FCB宿境v86的prw功能

命令行格式为prw.exe [foo],foo为当前目录下文件名.

初始界面:
p(artition),r(ead sec to cmdline_file/stdout),w(rite file to sec),v(xd write)

按p,r,w,v键,启动各命令:

(6.1) 命令p,显出如下值:分区硬盘编号(80),逻辑盘符(C:),BootON值(80),volume值(06),Front值(3f),In值(3ee041),从In得的容量(7dc):

80,C:,Boot(80),FAT(06),Front|In:0000003f|003ee041,MB:000007dc

p无限显示,则存失效F的扩展分区递归的硬盘锁.

(6.2) 命令r,读软硬盘内容到新建file,或stdout

(6.3) 命令w,写已存file内容到软硬盘.

(6.4) 命令v,用VxD写已存file内容到软硬盘,这克服9x的DOS窗口下(V86模式),硬盘被OS保护,不许int 13写的缺陷.算法见\"(8) 论9x的V86下,任意读写硬盘扇区,只能靠VxD\"

命令r/w/v,可用c(hs),l(ba)寻扇,最多受理ffff扇,出错时,部分扇区被写入文件.

对命令r,扇区从磁盘读到buf而写file/stdout前,对命令wv,扇区从file读到buf而写磁盘前,屏幕上方,显出正处理的扇区计数及buf十六进制值,下方,显出\"ctl_c,g(o),q(uiet),\",用户按ctl_c键,就异常结束,按\'q\'键,就不再显buf十六进制值.

例如,想读80h的MBR到文件0,可发:

prw 0

命令r界面及回答:

drv(00~01,80~83)80
0~cyl(03fd)
0~hd(3f)
1~sec(3f)
0~lba(003ee07f)
c(hs),l(ba)l
0~lba(003ee07f)00000000
0~cyl(0000)
0~hd(00)
1~sec(01)
0~lba(00000000)
1~total(ffff)0001

正常/异常结束,文件0长度=512/0.

(7) prw文

NIBSZ=8         ;8个hex数

nibasc          macro
                local   nibasc0

add al,48

                cmp             al,10+48
                jb              nibasc0

add al,97-48-10
nibasc0:
                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
        xchg ah,al ;转ah
        
push ax
                alasc
                pop ax

        xchg ah,al ;转al
        alasc
endm

d segment

buf     db      511 dup(0) ;放硬盘MRB.全囿V86页(4k),buf长1023
buf511 db 0 ;老buf尾
info_sz     dw 26  ;minimal size of information buffer ;新buf
flags         dw 0   ;information 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,13,10,\'0~0fh:\',13,10
db  \'Unknown,FAT12/Unformatted,XENIX,XENIX2,FAT16/Unformatted,Extended,FAT16B,NTF S,AIX or Coherent,AIX SplitDrive,Boot Manager,FAT32,FAT32X,Type  0D,FAT16,ExtendedX\',13,10

db 13,10,\'11,14,16,17,1b:\',13,10
db  \'HiddenFAT12/Unformatted,HiddenFAT16,HiddenFAT16B,HiddenNTFS,HiddenFAT32\',13, 10

db 13,10,\'65,82,83:\',13,10
db \'Netware,Linux_Swap,Linux_Ext2\',13,10,36

extblk  db  16 ;分区表16字节用
rsv     db  0
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 \'p(artition),r(ead sec to cmdline_file/stdout),w(rite file to sec),v(xd write)$\';rwv用
drv_p   db 13,10,\'drv(00~01,80~83)$\'       ;扩展i13用
mod_p   db 13,10,\'c(hs),l(ba)$\'            ;dosext,nondos用

.from80 dw  0d0ah
from80  db  \'80,\'     ;读扇到file
logidrv db  \'C:,Boot(\'
Boot    db  \'00),FAT(\'
volume  db  \'06),Front|In:\'
Front_h dw  ?,? ;又做总扇数
Front_l db  \'0000|\'
In_h    dw  ?,? ;又做当前扇号
In_l    db  \'0000,MB:\'
MB       db  \'00200000\',13,10,36

cyl_p   db  2 dup(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      \'ctl_c,g(o),q(uiet)$\'   ;显当前扇号

primk  db      1,4,6,0bh,0ch,0eh        ;主分区标识
primksz=$-primk
extmk  db      5,0fh            ;扩展分区标识
extmksz=$-extmk

stk1    dw NIBSZ/4 dup(0)  ;INnib栈
        db 32
rowasc  db (2+1)*15+2  dup(32),13,10,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 es:d,cs:c,ss:d,ds:d

@       proc    far

push    ds          ;exe返回方式

xor ax,ax
        push ax

        cld

        mov bx,d
        mov es,bx ;置es

        mov     si,5ch ;外壳,复制盘符,8.3名到5ch,而功能create/open,拒认.3名

        cmp     byte ptr [si+1],32
jne @1

        mov     es:from80,al ;未指明file
jmp @2

@1:     lea     di,fcbdrv
        mov cx,1 + 8 + 3       ;ds:si的盘符及8[3]大写名,送es:di
        rep movsb

@2:     mov ds,bx ;置ds

        mov ah,9
        lea dx,cmd_p   ;问命令
        int 21h

        mov     ah,1        
        int     21h

        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

        mov ax,ds              ;置es
        mov es,ax

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
        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 from80,255        ;读扇到file
        jz rw2

        mov     ah,16h      ;create or trunc for r
rw1:    int     21h ;改fcbdrv为3=C
        
or      al,al ;al为0,成功
        jnz rw6

        mov fcbrsz,512 ;重置

rw2:    mov     ah,1ah      ;DTA
        lea dx,buf
        mov bx,dx              ;内存数据区
        int     21h

rw3:   test    Front_h,65535
        jz rw6

cmp cmd_p,\'r\'
        jne rw4

        mov ax,201h
        mov dl,drv
        Call rw1sec
jc rw6

Call scr

        test from80,255        ;读扇到file
        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 rw1sec
        jc rw6             ;出错,关闭
 
rw5:    Add lbal,1
        adc lbah,0

        inc In_h
        dec Front_h
        jmp rw3

rw6:    test from80,255        ;读扇到file
jz rw7

mov     ah,16       ;close
        lea dx,fcbdrv
        int     21h

rw7: 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]   ;取volume
        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 drv_p,0 ;非扩展i13

        mov     ah,41h
        mov     bx,55aah    ;测BIOS支持扩展i13?
        int     13h
        jc      h_geo1

        cmp     bx,0aa55h ;再核
        jne     h_geo1

        test cx,1              ;支持41~44,47~48第1子集?
        je h_geo1

        inc drv_p ;支持

mov ah,48h ;取尺寸
        lea si,info_sz
        int 13h

        mov     al,heads00         ;头数
        mov     media_h,al

        mov     ah,s1track00 ;每道扇数
mov s1track,ah

        mul ah
        mov  s1cyl,ax     ;每柱面扇数

        mov     ax,cylinders0      ;柱面数
        mov     media_c,ax
ret

h_geo1:mov ah,8                       ;传统int 13取尺寸
        int 13h
        jc h_geo2

        inc dh

        mov al,dh
        mov     media_h,al  ;头数

        mov s1track,cl
        and s1track,63   ;每道扇数

        mul s1track
        mov     s1cyl,ax    ;每柱面扇数

        mov ax,cx
        mov cl,6
        shr al,cl
        xchg al,ah
        inc ax

        mov     media_c,ax  ;柱面数

h_geo2: ret
h_geo endp

chain     proc                ;处理链
chain0: mov ax,201h
        Call rw1sec

        mov al,buf[1beh+4]
        call pri_non

        test buf[1beh+16+4],255         ;0,5,0fh之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    ;分区信息

        mov al,dl ;取硬盘编号
        lea di,from80
        alasc

        mov al,buf[1beh+bp]    ;取BootON
        lea di,Boot
alasc

        mov al,buf[1beh+bp+4]  ;取volume
        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

        push dx

        mov     dx,word ptr buf[1beh+bp+14]  ;In high
mov ax,dx
        lea di,In_h
        axasc

        mov     ax,word ptr buf[1beh+bp+12]

rept 11 ;In扇转为M
shr dx,1
rcr ax,1
endm

        lea di,MB[4]
        axasc

        mov     ax,dx
        lea di,MB
        axasc

        mov ah,9
        lea dx,.from80
        int 21h

        pop dx
        ret
Show endp

rw1sec proc ;读/写1扇
        test dl,80h
        jz rw1sec1

        test    drv_p,1
        jz rw1sec1

xor al,al ;不校验写
        or     ah,40h
        lea     si,extblk   ;扩展块
        jmp rw1sec2

rw1sec1:push ax
        push dx
        call lba2chs
        pop dx
        pop ax

        call cxdh

rw1sec2:cmp cmd_p,\'v\'
        je rw1sec3

int 13h  
ret

rw1sec3:Call [entry] ;让VxD写

        test    bp,65535   ;被vxd返回值(0,好;1000h,坏;其他,为bx要增量)
        jz rw1sec4

        test    bp,1000h
        jnz rw1sec5

        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] ;再让VxD写

        pop bx
mov buf_off,bx ;扩展i13

rw1sec4:xor ah,ah
        Call [entry] ;释放v86页

clc
ret

rw1sec5:stc
ret

rw1sec endp

f_geo proc
        mov     ax,201h     ;读1扇
        lea     bx,buf      ;缓区
        mov     cx,1        ;引导扇,在0:0:1(chs)

        int     13h         ;读11起的bios参数块
        jc f_geo1

        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  ;柱面数
f_geo1: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
        xor     si,si

scr1:   mov     ax,2    ;清屏
int 10h

        mov     ax,In_h   ;当前扇号
        lea di,MB[4]
        mov dx,di
        axasc

        mov ah,9
        int 21h

        cmp     scr_p,\'q\'
        jne     scr2
        ret

scr2:   mov ax,si
        lea di,stk1
        axasc

        lea bp,rowasc

scr3:  mov al,[bx+si]
        mov di,bp
        alasc

        Add bp,2 + 2 - 1

        inc si
        test si,15
        jne scr3

        mov ah,9
        lea dx,stk1
        int     21h

        test si,255
        je scr4
        jmp scr2

scr4:   mov ah,9
        lea dx,scr_p
        int     21h

        mov     ah,1        ;按1键
        int     21h

        cmp al,\'q\'
        je scr6

        test si,511
        je scr5
        jmp scr1
scr5:   ret

scr6:   mov scr_p,al
        ret
scr     endp

cxdh proc
        mov     dh,hd       ;头号

        mov     cx,cyl      ;柱面号
        xchg ch,cl

rept 6
        shl cl,1
endm

        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
INnib1: 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 INnib1

        xor bp,bp

        lea si,kbd2
INnib2:lodsb

        mov cx,16
        lea di,hextbl
        repne scasb

        jnz INnib1

        dec kbd1

        inc cx          ;转\'[0-9a-f]\'为0~15
        sub cx,16
        neg cx

        rept 4
        shl bx,1        ;bx接收nibble
        endm

        and bl,240
        or bl,cl

        test kbd1,3     ;已收4个nibble
        jnz INnib2

        mov stk1[bp],bx
        add bp,TYPE stk1

        test kbd1,255
        jnz INnib2

        ret
INnib endp

c ends
        end     @

(8) 论9x的V86下,任意读写硬盘扇区,只能靠VxD

用VToolsD创建的C语言级VxD,有读/写DOS分区的R0_ReadAbsoluteDisk/R0WriteAbsoluteDisk函数.

例如,可在响应32位C对VxD的W32_DEVICEIOCONTROL事件的激发时,用格式R0_ReadAbsoluteDisk(2,1,0,buf,&w),读相对DOS分区的逻辑扇号是0的分区引导扇区PBS,对80H硬盘,PBS位于第0柱面第1头第1扇,记为0:1:1(chs).这时,激发W32_DEVICEIOCONTROL事件的虚拟机,是系统虚拟机(用Test_Sys_VM_Handle,测事件入口实参IOCTLPARAMS.dioc_hvm,得证).VxD不改变虚拟机身份.

又如,可在响应16位ASM程序对VxD的V86_API_Entry的入口调用时,用上述格式读PBS,这时,当前虚拟机是DOS虚拟机(用Test_Sys_VM_Handle,测入口实参VMHANDLE,得证).

均读得\"MSWIN4...\"等.

但VxD,也能在95的V86下,用Exec_Int(0x13),象int 13h那样,任意读写硬盘,如PBS之前的MBR(硬盘主引导记录,位于0:0:1(chs)).配套软件c.cpp及a.asm,实现这点,现讲读出MBR连续5扇例,config.sys,需rem dev=emm386.exe

(8.1) 用QuickVxD,建C++级VxD,设备名C,选动态安装
选API页Standard App Entry Points框Real/V86 Mode,体见(8.3)
选OnSysDynamicDeviceInit,OnSysDynamicDeviceExit,体返true
h中,写#define C_DeviceID 0x3180

(8.2) 编写调用上述入口的a.asm.不能让VxD服务更多扇区(>8),原因是VxD要把a.exe的这5扇内存,整体映进V86内存空间的1页(4096字节)v中(5扇跨越页界时,VxD让a.exe移5扇到合适处),然后对v,做exec_int(0x13).阅完映来(并未复制)的v内容后,a要让VxD释放共享资源v,这时,VxD把v映到系统空页.各系统空页有时不连续,这限制VxD每次最多服务1个空页所占的4096字节(8扇)

本例用/DNPAGE=5,让VxD服务5扇.读变写,需debug下,先填buf,再改r2w3处的2为3.

IF2
        IF NPAGE LT 1 or NPAGE GT 8
                 %OUT 0<NPAGE<9
                .ERR
        ENDIF
ENDIF

d    segment
buf     db      NPAGE*512*2-1 dup(0)
entry dd 0 ;放V86_API_Entry入口ip:cs
d    ends

c    segment
        assume cs:c,ds:d

@: mov     ax,d
        mov     ds,ax

        mov     ax,1684h ;功能号
        mov     bx,3180h ;接口ID
        int     2fh

        mov     ax,es ;取V86_API_Entry入口的段/偏移到es/di
        or      ax,di
        jz      @q          ;es及di全为零则失败

        mov     word ptr [entry],di
        mov     word ptr [entry+2],es

        mov     ax,ds ;同int 13h,设exec_int(0x13)参数
        mov     es,ax

        lea     bx,buf ;es:bx,指向缓区首

r2w3: mov     ah,2 ;读80h硬盘0:0:1(chs)开始的NPAGE扇
        mov     al,NPAGE
        mov     cx,1 ;0:0:1(chs)
        mov     dx,128

        call    [entry] ;让VxD服务

        test    bp,65535 ;从VxD返回的bp,有3类值:
;0 : 服务成功
;1000h : 服务失败
;[1~NPAGE*512-1] : bx要增量,即:
;原缓区首es:bx转为32位线性址a后,若与缓区尾,未囿同1页,a加bp后,是新缓区首,
;之后NPAGE*512字节,是新缓区尾,这时,首尾,囿同1页.

        jz      @r

        test    bp,4096
        jnz     @q

        add     bx,bp ;这使新缓区首尾,囿同1页

test ah,1 ;VxD不改ah.查读/写盘
jz @c ;此例ah=2,是读盘

       lea     si,buf ;写入时,要从后向前,移NPAGE*256字:
add si,NPAGE*512-1 ;si指向原缓区尾

        mov di, si
        add     di,bp ;di指向新缓区尾

        std                 ;ds:si指向的cx字,移到es:di
        mov cx, NPAGE*256
        rep movsw

        mov cx,1 ;0:0:1(chs)

@c: call    [entry] ;再次让VxD服务

@r: xor ah,ah ;释放V86页
call [entry]

@q:     mov     ah,4ch ;完
        int     21h

c    ends
        end     @

(8.3) 体

DWORD gb;

...V86_API_Entry(VMHANDLE hVM, CLIENT_STRUCT* pRegs){
DWORD a;
WORD o;
CLIENT_STRUCT s;

if(pRegs->CBRS.Client_AH){//AH=2/3,读/写
a=(DWORD)Map_Flat(CLIENT_ES,CLIENT_BX);//转客户的缓区首es:bx为32位线性地址a
gb=a+pRegs->CBRS.Client_AL*512-1;//存缓区尾的线性地址到gb
o=a&0xfff;//存a的页内偏移到o

a=a>>12;//页号
if(a!=(gb>>12)){
pRegs->CWRS.Client_BP=(0x1000-o);//若缓区首尾,未囿同1页,令bp返回客户对bx要增量
return;
}

;//若页a开始的1页,未成功映入V86空间第0x10页,令bp返回1000h.
if(!LinMapIntoV86(a,hVM,0x10,1,0,&gb)){
pRegs->CWRS.Client_BP=0x1000;
return;
}

//V86页号成功返到gb.若a已是有效V86页(<1M+HMA),gb是a,否则是0x10.
a=(gb<<12)+o;//由V86页gb及缓区在页内的偏移o,得到缓区首的20位V86地址a

Save_Client_State(&s);//保存reg
Begin_Nest_V86_Exec();//当前虚拟机,行于V86

pRegs->CRS.Client_ES=(a>>4);//地址a的段值存于ES,(若a=12345h,ES=1234h)
pRegs->CRS.Client_EBX=(a&15);//地址a的段内偏移存于EBX,(a=12345h,EBX=5)

Exec_Int(0x13);//调用V86模式13h

End_Nest_Exec();//恢复模式
Restore_Client_State(&s);//恢复reg

pRegs->CWRS.Client_BP=0;//成功,令BP返回0
}else//释放V86页
MapIntoV86(GetNulPageHandle(),hVM,gb,1,0,0);
}

运行时,用VxD Loader,或DriverMonitor的先Open再Start,动态装C.VxD,见C露VxD Viewer,再于DOS窗口,debug断a.exe于@q,见bx指向5扇首偏1be,含分区表.

或用笔者

#include <windows.h>

#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);
}
}
}

的exe,键入vxd_load C.VxD后,在另一DOS窗口,debug后,回车卸VxD

最新喜欢:

mapoflmapofl
游客

返回顶部