阅读:1421回复:0
98启动软盘或关机到ms-dos,为何prw.asm的fcb_w命令失败?仿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 |
|
最新喜欢:mapofl |