- 论坛徽章:
- 0
|
第三站 跟着流程走(一):
far jmp后发生什么?
接下来用IDA pro打开ex38dq6.BIN观察,这个是BIOS的主体文件,跟着流程走,看看far jmp后BIOS做什么工作。
一、下面是第一张流程图:
![]()
1、第一条指令 jmp far ptr F000:E05B 经过几个跳转,跳到F000:F46C处
2、以下是F000:F46C的代码:
seg000:FF46C cli
seg000:FF46D cld
seg000:FF46E xchg bx, bx
seg000:FF470 smsw ax
seg000:FF473 test al, 1
seg000:FF475 jz short near ptr 0F480h
seg000:FF477 cli
seg000:FF478 mov al, 0FEh ; '?
seg000:FF47A out 64h, al ; AT Keyboard controller 8042.
seg000:FF47A ; Resend the last transmission
seg000:FF47C cli
seg000:FF47D hlt
--------------------------------------------------------------
取机器状态字,也就是CR0寄存器,测试CR0.PE是否为1,判断CPU是否处于实模式状态,若不是则停机。
若处于实模式转到F000:F480继续处理。
3、转到F000:F480又经过一道跳转,来到F000:E043进行处理
4、下面是F000:E043的代码:
seg000:FE043 mov al, 8Fh ; '? ; disable NMI# and get 0Fh offset register
seg000:FE045 out 70h, al ; CMOS Memory:
seg000:FE045 ;
seg000:FE047 out 0EBh, al
seg000:FE049 in al, 71h ; get OFh offset register data
seg000:FE04B out 0EBh, al
seg000:FE04D or al, al ; is RESET ?
seg000:FE04F jmp near ptr 0F483h
在这里,取 CMOS RAM 中位于0F处1个字节的数据,通过测试这个字节是否为0,判断是否属正常启动。
5、正常启动的话,调用F000:54DE这个子过程进行处理,否则跳到F000:3468。
二、下面看看F000:54DE的处理,以下是第二张流程图:
![]()
下面proc_F54DE的代码:
seg000:F54DE mov ax, 0
seg000:F54E1 mov es, ax
seg000:F54E3 cmp word ptr es:472h, 1234h
seg000:F54EA jnz short near ptr 54F8h
seg000:F54EC mov al, 8Fh ; '?
seg000:F54EE out 70h, al ; CMOS Memory:
seg000:F54EE ;
seg000:F54F0 out 0EBh, al
seg000:F54F2 mov al, 0AAh ; '?
seg000:F54F4 out 71h, al ; CMOS Memory:
seg000:F54F4 ;
seg000:F54F6 out 0EBh, al
seg000:F54F8 mov dx, 3C4h
seg000:F54FB mov al, 1
seg000:F54FD out dx, al ; EGA: sequencer address reg
seg000:F54FD ; clocking mode. Data bits:
seg000:F54FD ; 0: 1=8 dots/char; 0=9 dots/char
seg000:F54FD ; 1: CRT bandwidth: 1=low; 0=high
seg000:F54FD ; 2: 1=shift every char; 0=every 2nd char
seg000:F54FD ; 3: dot clock: 1=halved
seg000:F54FE inc dl
seg000:F5500 in al, dx ; EGA port: sequencer data register
seg000:F5501 or al, 20h
seg000:F5503 out dx, al ; EGA port: sequencer data register
seg000:F5504 call near ptr 76FBh
seg000:F5507 retn
1、在BIOS数据区的0472处存放着一个复位标志:
seg000:F54E3 cmp word ptr es:472h, 1234h
通过比较 [0472] 是否1234h,标志1234h是一个热启动标志位,机器热启动时,例如:按下CTRL+ALT+DEL 三个键时,由键盘中断处理程序在[0472]处写标志1234h。
2、是热启动的话,将写入AA标志到CMOS RAM 的0F处。
3、接着设置EGA相应的工作状态。
4、在proc_F76FB过程里置定时器1的状态。
5、最后调用过程proc_F2941进行芯片组的初始化。
三、下面是本站节的重点,初始化某部分芯片组,下面是流程图:
![]()
1、下面重点理解 write_pci_byte这个BIOS提供的rontine,代码如下:
seg000:FF798 xchg ax, cx ; write_byte routine
seg000:FF799 shl ecx, 10h
seg000:FF79D xchg ax, cx
seg000:FF79E mov ax, 8000h ; Bus 0
seg000:FF7A1 shl eax, 10h
seg000:FF7A5 mov ax, cx
seg000:FF7A7 and al, 0FCh
seg000:FF7A9 mov dx, 0CF8h ; config_address register
seg000:FF7AC out dx, eax
seg000:FF7AE add dl, 4 ; config_data register
seg000:FF7B1 mov al, cl
seg000:FF7B3 and al, 3
seg000:FF7B5 add dl, al
seg000:FF7B7 mov eax, ecx
seg000:FF7BA shr eax, 10h
seg000:FF7BE out dx, al
seg000:FF7BF retn
将这个routine功能简化为C代码形式来看比较直观:
void wirte_pci_byte(int offset_number, int mask)
{
if (number == -1)
jmp_7666();
do_wirte_pci_byte(offset_number, mask);
}
这段routine固定写PCI的Bus0,Device0,Function0,offset 值放在cx中,由调用者传来,置什么值放在al寄存器,这是1个字节的值。
Bus0,Dev0,Fun0是hostbrige控制器(NorthBridge),也即是DRAM控制器的地址所在。这段代码是典型的写PCI设置的手法。PCI设置地址送入config_address_register中,然后往config_data_register里写数据,这个PCI设备地址将映射到PCI设备的寄存器,如前面介绍的地址空间图所示,PCI设备地址范围是E000_0000 ~ EFFF_FFFF,这段空间提交到相应的PCI设备。
2、现在回过头来看调用者,cx=95,al=33 这个参数传给 write_pci_byte。Offset是95,mask码是33。Offset 95在write_pci_byte将被置为94,这将是DRAM控制器的PAM4寄存器,PAM4寄存器控制D_8000 ~ D_FFFF内存空间的属性。写入33,结果是:将这段空间置为read/write属性,这将是所有访问这段空间的操作会提交到DRAM。而不再是ROM。
3、Offset 96的结果和offset 95一样,在write_pci_byte的掩码中被置为offset 94。
|
|