pmon中x86emu对vga初始化浅析

来源:互联网 发布:微信一键拉人软件 编辑:程序博客网 时间:2024/05/29 15:58
本文主要简要描述下pmon中x86emu对vga初始化的步骤

1。主要思想:
x86emu 实际上可以看作是执行x86指令的一台虚拟机,对其介绍分为三个部分,内存空间
映射,模拟中断机制,和指令执行模拟三个方面。

2。内存空间映射
x86emu中寻址空间空间默认是0~100000大小,映射关系如下:
0~0xa0000 
                此空间访问  INTPriv(pInt)->base指针所指向的空间
0xa0000~0xc0000 
          此空间映射  INTPriv(pInt)->vRam指针指向的空间
0xc0000~0xf0000 
          此空间映射  INTPriv(pInt)->base+V_BIOS开始的空间
0xf0000~0x100000 
         此空间映射  INTPriv(pInt)->sysMem指针指向的空间

其中INTPriv(pInt)->vRam赋值是VGA_BASE + 0xa0000即vga分配的io空间
INTPriv(pInt)->base 和INTPriv(pInt)->sysMem 是在vga_bios_init函数中malloc的空间
INTPriv(pInt)->base+V_BIOS中开始的10000空间内拷贝了
Target/Bonitoxxxx/Bonito/vgarom.c中定义的vgarom数组内容。
而模拟执行的指令,也正是vgarom数组里面。

3。模拟中断机制
由于pmon中仅支持单线程操作,因此对于中断不可能异步执行。其中断处理函数如下:
 
28 void xf86ExecX86int10(xf86Int10InfoPtrpInt)
 
29 {
 
30    int sig = setup_int(pInt);
 
31
 
32    if (sig < 0)
33 
       return;
 
34
 
35    if (int_handler(pInt)) {
 
36        X86EMU_exec();
 
37    }
 
38
 
39    finish_int(pInt, sig);
 
40 }

其中setup_int 是保存现场, finish_int是恢复现场
int_handler(pInt)是为处理中断作准备。
 
X86EMU_exec()是执行中断处理程序。

int_handler函数内容如下:
 
33 int int_handler(xf86Int10InfoPtr pInt)
 
34 {
 
35    int num = pInt->num;
 
36    int ret = 0;
 
40    switch (num) {
 
41 #ifndef _PC
 
42    case 0x10:
 
43    case 0x42:
 
44    case 0x6D:
 
45        if (getIntVect(pInt, num) == I_S_DEFAULT_INT_VECT) {
 
46            printf("default int10 called,intno=%x\n", num);
 
47            ret = int42_handler(pInt);
 
48        }
 
49        break;
 
50    case 0x15:
 
51        ret = int15_handler(pInt);
 
52        break;
 
53 #endif
 
54    case 0x1A:
 
55        ret = int1A_handler(pInt);
 
56        break;
 
57    case 0xe6:
 
58        ret = intE6_handler(pInt);
 
59        break;
 
60    default:
 
61        break;
 
62    }
。。。。
可见起针对中断号pInt->num选择相应的处理函数,函数内容包括跳转虚拟的pc寄存器等等内容。


3.指令执行的模拟
x86emu将所有程序都看作是中断处理程序,因此其指令执行入口就是 X86EMU_exec()这个中断处理函数其内容如下:
 
92 void X86EMU_exec(void)
 
93 {
 
94    u8 op1;
 
95
 
96    M.x86.intr = 0;
 
97    DB(x86emu_end_instr();)
 
98
 
99    for (;;) {
 
100DB(    if (CHECK_IP_FETCH())
 
101          x86emu_check_ip_access();)
 
102        
 
103        SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
 
104        INC_DECODED_INST_LEN(1);
 
105        if (M.x86.intr) {
 
106            if (M.x86.intr & INTR_HALTED) {
 
107DB(            printf("halted\n");
 
108                X86EMU_trace_regs();)
 
109                return;
 
110            }
 
111            if (((M.x86.intr & INTR_SYNCH)&& (M.x86.intno == 0 || M.x86.intno== 2)) ||
 
112                !ACCESS_FLAG(F_IF)) {
 
113                x86emu_intr_handle();
 
114            }
 
115        }
 
117        //if(M.x86.debug==0x3){
 
118        printf("CS:%4X,IP:%4X,AX=%4X,BX=%4X,CX=%4X,DX=%4X,SP=%4X\n",M.x86.R_CS,M.x86.R_IP,
 
119            M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX,M.x86.R_SP);
 
120        printf("\tBP=%4X,SI=%4X,DI=%4X,DS=%4X,SS=%4X,ES=%4X\n",M.x86.R_BP,M.x86.R_SI,M.x86.R_DI,
 
121            M.x86.R_DS,M.x86.R_SS,M.x86.R_ES);
 
122       // }
 
123
 
123
 
124        op1 = (*sys_rdb)(((u32)M.x86.R_CS <<4) + (M.x86.R_IP++));
 
127        (*x86emu_optab[op1])(op1);
 
128    }
 
129 }
如上所示,M.x86是对x86处理器的寄存器的模拟,例如M.x86.R_AX模拟cpu的%ax寄存器,M.x86.intr模拟中断寄存器。

函数是一个死循环,出口当且仅当M.x86.intr & INTR_HALTED时,即中断处理完成时.

循环过程如下:
a)检测中断是否执行完,如果执行完了即:M.x86.intr & INTR_HALTED返回,否则继续
b)检测是否有中断:即((M.x86.intr & INTR_SYNCH)&& (M.x86.intno == 0 || M.x86.intno== 2)) || !ACCESS_FLAG(F_IF)
 
有则执行x86emu_intr_handle()函数,内容如下:
 
50 static void x86emu_intr_handle(void)
 
51 {
 
52    u8  intno;
 
53
 
54    if (M.x86.intr & INTR_SYNCH) {
 
55        intno = M.x86.intno;
 
56        if (_X86EMU_intrTab[intno]) {
 
57            (*_X86EMU_intrTab[intno])(intno);
 
58        } else {
 
59            push_word((u16)M.x86.R_FLG);
 
60            CLEAR_FLAG(F_IF);
 
61            CLEAR_FLAG(F_TF);
 
62            push_word(M.x86.R_CS);
 
63            M.x86.R_CS = mem_access_word(intno * 4 + 2);
 
64            push_word(M.x86.R_IP);
 
65            M.x86.R_IP = mem_access_word(intno * 4);
 
66            M.x86.intr = 0;
 
67        }
 
68    }
 
69 }
 
_X86EMU_intrTab[intno]中全部是static voidx86emu_do_int(int num)函数 内容如下:
 
18 static void x86emu_do_int(int num)
 
19 {
 
20    Int10Current->num = num;
 
21printf("int10current->num=0x%x\n",num);
 
22    if (!int_handler(Int10Current)) {
 
23    printf("int_handler_int10current is error,systemhalted...\n");
 
24            X86EMU_halt_sys();
 
25    }
 
26 }
即调用int_handler跳转地址等准备工作。否则继续执行

c) 取出指令,获得操作码
 
  即:op1 =(*sys_rdb)(((u32)M.x86.R_CS << 4) +(M.x86.R_IP++))
 
 sys_rdb是读地址操作,M.x86.R_CS通常是0xc000  M.x86.R_IP是模拟cpu的pc寄存器,因此起获得的是0xc0000 + ip
 
  的地址的代码即INTPriv(pInt)->base+V_BIOS开始的内容.

d) 执行操作码.
 
 即:(*x86emu_optab[op1])(op1)
 
 x86emu_optab是x86emu/int10/src/x86emu/op.c中实现的很多x86结构的指令。

如上循环不断执行直至中断处理完毕时方退出,此时便完成了对vga的初始化。

原创粉丝点击