pmon中x86emu对vga初始化浅析

    xiaoxiao2024-11-15  61

     

    本文主要简要描述下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的初始化。

    最新回复(0)