仿FDISK及PQMAGIC列出分区逻辑盘符的prw.asm实现
   作者:马文晓 于2003-12-2上传 

  仿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


欢迎访问AoGo汇编小站:http://www.aogosoft.com