pmon中x86emu对vga初始化浅析

 

本文主要简要描述下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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值