MBR笔记

原创
2015/04/14 22:19
阅读数 195

<bochs:1> 00000000000e[WGUI ] Sim client size(0, 0) != stretched size(640, 480)!

<bochs:2> b 0x7c00
<bochs:3> c
00000003740i[BIOS ] $Revision: 1.166 $ $Date: 2006/08/11 17:34:12 $
00000319045i[KBD  ] reset-disable command received
00000321693i[PIDE ] new BM-DMA address: 0xc000
00000327577i[P2I  ] PCI IRQ routing: PIRQA# set to 0x0b
00000327593i[P2I  ] write: ELCR2 = 0x08
00000327613i[ACPI ] new irq line = 11
00000446187i[VBIOS] VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $
00000446258i[BXVGA] VBE known Display Interface b0c0
00000446290i[BXVGA] VBE known Display Interface b0c4
00000449215i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000759983i[BIOS ] ata0-0: PCHS=512/4/16 translation=none LCHS=512/4/16
00000800002i[WGUI ] dimension update x=720 y=400 fontheight=16 fontwidth=9 bpp=8
(0) Breakpoint 1, 0x0000000000007c00 in ?? ()
Next at t=957062

;中断与0x7c00   开始MBR程序
;关中断
(0) [0x0000000000007c00] 0000:7c00 (unk. ctxt): cli                       ; fa
<bochs:4> n
Next at t=957063
(0) [0x0000000000007c01] 0000:7c01 (unk. ctxt): xor ax, ax                ; 31c0
<bochs:5> n
Next at t=957064
;设置段寄存器
(0) [0x0000000000007c03] 0000:7c03 (unk. ctxt): mov ss, ax                ; 8ed0
<bochs:6> n
Next at t=957065
;设置栈顶
(0) [0x0000000000007c05] 0000:7c05 (unk. ctxt): mov sp, 0x7c00            ; bc007c
<bochs:7> n
Next at t=957066
;开中断
(0) [0x0000000000007c08] 0000:7c08 (unk. ctxt): sti                       ; fb
<bochs:8> n
Next at t=957067
;设置数据段寄存器   就是把0x7c0 赋值给数据段寄存器  这里估计是源代码写重复了已经赋值了结果下面还用ax赋值给ds
;源代码中作者果然写重复了
;这里写重复了push和pop以及下面的都是已经把07c0h赋值给ds数据段寄存器了
 push 07c0h
 pop ds
 mov  ax, 07c0h       
 mov  ds, ax
;//////////////////////////////////////////////////分割线////////////////////////////////////

(0) [0x0000000000007c09] 0000:7c09 (unk. ctxt): push 0x07c0               ; 68c007
<bochs:9> n
Next at t=957068
(0) [0x0000000000007c0c] 0000:7c0c (unk. ctxt): pop ds                    ; 1f
<bochs:10>
Next at t=957069
(0) [0x0000000000007c0d] 0000:7c0d (unk. ctxt): mov ax, 0x07c0            ; b8c007
<bochs:11> n
Next at t=957070
(0) [0x0000000000007c10] 0000:7c10 (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:12> n
Next at t=957071
;加载ntldr 
;count - ntldr扇区总数   80000h/512-8=0x3f8
(0) [0x0000000000007c12] 0000:7c12 (unk. ctxt): push 0x000003f8           ; 6668f8030000
<bochs:13> n
Next at t=957072
;src开始读取的扇区号
(0) [0x0000000000007c18] 0000:7c18 (unk. ctxt): push 0x00000008           ; 666808000000
<bochs:14> n
Next at t=957073
;des - 存放数据的目的地址(物理内存地址)
(0) [0x0000000000007c1e] 0000:7c1e (unk. ctxt): push 0x00020000           ; 666800000200
<bochs:15> n
Next at t=957074
;这里是call  LoadSector(int des,int src,int count);
;用c语言描述:

 void LoadSector(int des,int src,int count)
{
     int run = count / 64; //计算扇区的循环次数 为了提高效率不安扇区127的倍数取,取2的6次方64
     int mod = count % 64; //计算剩余扇区
     for(int i=0,i<run,i++)
     {
          ReadWriteSector(0x80,src,0,64,des,0x42); //每次读取64扇区
          src = src +64; //重写计算扇区
          des = des + 64*512; //重新计算目的地址
     }
     if(mod) //如果纯在剩余扇区,读取一次就ok了
     {
      ReadWriteSector(0x80,src,0,64,des,0x42);
     }
}


(0) [0x0000000000007c24] 0000:7c24 (unk. ctxt): call .+7 (0x00007c2e)     ; e80700
<bochs:16> n
Next at t=1171020
;采用fastboot跳转至  0x2000:0003 如果是NTFS boot则跳转至0x2000:0000刚好执行 jmp RealStart 而fatboot则会忽略3B这条指令
(0) [0x0000000000007c27] 0000:7c27 (unk. ctxt): push 0x2000               ; 680020
<bochs:17> n
Next at t=1171021
(0) [0x0000000000007c2a] 0000:7c2a (unk. ctxt): push 0x0000               ; 680000
<bochs:18> n
Next at t=1171022
(0) [0x0000000000007c2d] 0000:7c2d (unk. ctxt): retf                      ; cb
<bochs:19> n
Next at t=1171023
(0) [0x0000000000020000] 2000:0000 (unk. ctxt): jmp .+509 (0x00020200)    ; e9fd01
<bochs:20>

LoadSector实现:

 void LoadSector(int des,int src,int count)
{
     int run = count / 64; //计算扇区的循环次数 为了提高效率不安扇区127的倍数取,取2的6次方64
     int mod = count % 64; //计算剩余扇区
     for(int i=0,i<run,i++)
     {
          ReadWriteSector(0x80,src,0,64,des,0x42); //每次读取64扇区
          src = src +64; //重写计算扇区
          des = des + 64*512; //重新计算目的地址
     }
     if(mod) //如果纯在剩余扇区,读取一次就ok了
     {
          ReadWriteSector(0x80,src,0,64,des,0x42);
     }
}

LoadSector的nasm源代码:

 void LoadSector(
; int des, 
; int src, 
; int count);
LoadSector:
;{
 push  ebp  
 mov  ebp, esp  ;保存栈框架  这里是0x7c00-4-4-4-2=0x7bf2  进入LoadSector的三次push call LoadSector占2B
 
 sub  esp, 0E4h  ;开辟栈空间0e4h=228
 push  ebx  
 push  esi  
 push  edi  
 
 ;int run = count / 64;
 mov  eax,dword [ebp+0Eh]  ;ebp+0eh为进入函数后的esp+14及最开始的push count
 cdq                 ;扩展edx为eax的高位
 and  edx, 3Fh 
 add  eax, edx 
 sar  eax, 6     ;右移6位及除以64
 mov  dword [ebp-8], eax  ;保存循环次数ebp-8
 
 ;int mod = count % 64;
 mov  eax, dword [ebp+0Eh]  ;读取扇区数 这里就是将参数count的值传入给eax  就是最开始的ebp+14
 and  eax, 8000003Fh   ;实现摸64操作
 jns  .set_mod
 dec  eax  
 or  eax,0FFFFFFC0h 
 inc  eax  
 
.set_mod: 
 mov  dword [ebp-14h], eax  ;将64的余数放到ebp -  14h中  最开始开辟了228B的空间
 ;for(int i=0; i<run; i++)
 mov  dword [ebp-20h], 0  ;i的空间地址设置成为0
 jmp  _read
 
_loop:
 mov  eax,dword [ebp-20h] 
 add  eax,1 
 mov  dword [ebp-20h],eax 
_read:   
    mov  eax,dword [ebp-20h]  ;将i的值给eax和次数比较
 cmp  eax,dword [ebp-8]   ;eax和ebp-8及最开始的count比较
 jge  _left     ;大于等于则跳转 退出循环
 ;{
 ;ReadWriteSector(0x80, src, 0, 64, des, 0x42);
 push  dword 42h
 mov  eax, dword [ebp+6] 
 push  eax  
 push  dword 40h  
 push  dword 0    
 mov  ecx, dword [ebp+0Ah] 
 push  ecx  
 push  dword 80h  
 call  ReadWriteSector
 add  esp, 24
 ;src = src + 64;
 mov  eax, dword [ebp+0Ah] 
 add  eax, 40h 
 mov  dword [ebp+0Ah], eax 
 ;des = des + 64*512;
 mov  eax, dword [ebp+6] 
 add  eax, 8000h 
 mov  dword [ebp+6], eax 
 ;}
 jmp  _loop
 ;if(mod)
_left:
 cmp  dword [ebp-14h],0           
    je  .return
 ;{
  ;ReadWriteSector(0x80, src, 0, mod, des, 0x42);
 push  dword 42h 
 mov  eax, dword [ebp+6] 
 push  eax  
 mov  ecx, dword [ebp-14h] 
 push  ecx  
 push  dword 0    
 mov  edx, dword [ebp+0Ah] 
 push  edx  
 push  dword 80h  
 call  ReadWriteSector
 add  esp, 24
 ;}
;}
.return:   
    pop  edi  
 pop  esi  
 pop  ebx  
 add  esp, 0E4h 
 mov  esp, ebp 
 pop  ebp  
 ret 12
 ReadWriteSector汇编代码
相关的数据结构
;Disk Address Packet
struc DAP                        
 .PacketSize     resb  1     ;数据包的大小,固定为10h
 .Reserved       resb  1     ;预留空间固定为1字节
 .BlockCount     resw  1   ;0~127 要传输的扇区数目
 .BufferOffset   resw  1     ;传输缓冲的偏移地址
 .BufferSegment  resw  1    ;传输缓冲的地址段
 .LBNLow         resd  1   ;0
 .LBNHigh        resd  1  ;
endstruc  
 
struc SectorFrame      
 .DriveNum        resd  1 ;表示读取数据所在的磁盘
 .LBNLow          resd  1 ;要读取数据所在的骑士扇区号
 .LBNHigh         resd  1 ;
 .BlockCount      resd  1 ;一次读取的扇区数
 .Buffer          resd  1    ;所读取数据存放的物理地址
 .ReadWrite       resd  1 ;表示进行什么操作  读还是写
endstruc

 
;NTSTATUS 
;(_cdecl* ReadWriteSector)(
; ULONG DriveNum, 
; ULONG LBNLow, 
; ULONG LBNHigh, 
; ULONG BlockCount, 
; PVOID Buffer, 
; ULONG ReadWrite); // Read=0x42,Write=0x43
 
ReadWriteSector:
    push  bp
    mov  bp, sp
    add  bp, 4
    push  ds
    push  si
    push  bx
 
    push  0
    pop  ds
     
 sub  sp, 16
 mov  si, sp
 mov  byte [si+DAP.PacketSize], 10h        
 mov  byte [si+DAP.Reserved], 0          
 mov  al,byte [bp+SectorFrame.BlockCount]
 mov  byte[si+DAP.BlockCount], al           
 mov  byte[si+DAP.BlockCount+1], 0         
 mov  eax, dword[bp+SectorFrame.Buffer]
    mov  bx, ax
    and  bx, 0fh     
    mov  word[si+DAP.BufferOffset], bx        
    shr  eax, 4
    mov  word[si+DAP.BufferSegment], ax        
    mov  eax, dword[bp+SectorFrame.LBNLow]
    mov  dword[si+DAP.LBNLow], eax            
    mov  eax, dword[bp+SectorFrame.LBNHigh]
    mov  dword[si+DAP.LBNHigh], eax           
    mov  ah, byte [bp+SectorFrame.ReadWrite]                                          
    mov  dl, byte [bp+SectorFrame.DriveNum]          
    int  13h
    jc   .error
    xor  eax, eax
.error:
    and  eax, 0000ffffh
            
 add  sp, 16
 pop  bx
 pop  si
 pop  ds
 
 pop  bp
 retn

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部