BitVisor中外部中断的处理流程浅析
2012-07-24 15:15
381 查看
这里分析一下关于BitVisor中关于外部中断(0x00000001)的处理流程,开始的创建虚拟话环境,初始化数据结构就不介绍了。首先从vt_mainloop()(.\core\vt_main.c)开始说起。相关函数值介绍与中断处理有关部分。
在vt_mainloop()主要在函数末尾通过一个判断是否单步执行的if语句,将流程分为两种情况。但是其实所要操作是一样的只有一个函数(vt__vm_run_with_tf ()和vt__vm_run ())调用不同。
下边是一个比较重要的数据结构。该数据结构中使用一个union,使用这个就够方便了存储VM_EXIT_INTR_INFO中的数据。
该数据可以直接调用U32 v写入到VM_ENTRY_INTR_INFO_FIELD中。也可以调用struct intr_info s来按项存储中断信息。
该函数检验了中断信息的合法性。和其他几种运行模式的情况。与主题关系不大,就不做解释了。
该函数将已有的数据填充到VMCS_VMENTRY_INTR_INFO_FIELD中,该数据可能为本次中断陷入VMM后从VM_EXIT_INTR_INFO中读取的也可能使上次运行之后人为填充的内容。等待后续检测。
该函数主要是检验IDT的问题与简单的中断处理无关。不做介绍了。
关键性操作在vt__exit_reason ()中。函数vt__exit_reason ()就是一个事件分发函数,我们主要关心的是两个部分
前者为外部中断事件,后者为中断窗事件。两者共同完成VMM对外部中断的处理。
前者处理中STATUS_UPDATE (asm_lock_incl (&stat_intcnt));获得中断后的异常(待验证)。
其后连个分发函数的处理方法完全相同。我们EXIT_REASON_EXTERNAL_INT的处理比较直观,EXIT_REASON_INTERRUPT_WINDOW的处理则稍微费些波折,所以我们先研究一下后者。
后者的处理函数是current->exint.hlt ();通过查找其声明及定义:
可知在后者调用exint.hlt ()函数时,实际是调用了exint_pass_hlt()(.\core\exint_pass.c)函数,其函数体为:
可见最终EXIT_REASON_EXTERNAL_INT和EXIT_REASON_INTERRUPT_WINDOW事件的处理方式是一致的。下边主要介绍一下处理过程。
再讲处理过程之前,首先说一下其中会用到的一个数据结构struct vmctl_func(.\core\vmctl.h)由于声明太长只列举其中有得到的参数:
下边主要说一下处理函数do_exint_pass (),其函数体为:
主要实现功能为首先获取系统进入VMM前的EFLAGS值,用来判断是否可中断(IF位)。
如果IF=1,那么首先利用do_externalint_enable ()(.\core\int.c)函数获取中断号,该函数辗转调用了int_callfunc (arg, func)(.\core\int_handler.h)函数,该函数应该是实现获取中断号(根据后续操作人为,待确定),大家可自行查看该函数。
如果返回值大于0,执行一系列函数
接下来将要用到两个函数
我看可以看到这两个函数分别设置中断位和中断窗位的有效与否。为后续VMM陷入做准备。
到此vt__exit_reason ()工作完成接下来执行vt__event_delivery_update ()函数。
该函数就主要是判断一下中断的合法性,也就是判断本次陷入VMM后,是否需要注入事件,如果必须则保持原有效位,否则清除有效位。
void do_exint_pass (void)是一个核心函数,它的大概处理思路是:
---------------------------------------------------------------------------------
- - IF==1 - 直接注入事件,开启外部中断,关闭中断窗口 -
-外部中断 - - -
- - IF==0 - 关闭外部中断,开启中断窗口 -
---------------------------------------------------------------------------------
- - IF==1 - 注入上次外部中断信息,开启外部中断,关闭中断窗口 -
-中断窗口 - - -
- - IF==0 - 关闭外部中断,开启中断窗口 -
---------------------------------------------------------------------------------
大概的流程就是这样,为了不误导大家,有一些细节我没有描述特别清楚。以后深入研究后在回来修改。
在vt_mainloop()主要在函数末尾通过一个判断是否单步执行的if语句,将流程分为两种情况。但是其实所要操作是一样的只有一个函数(vt__vm_run_with_tf ()和vt__vm_run ())调用不同。
vt__nmi (); vt__event_delivery_setup (); vt__vm_run (); cpu_mmu_spt_tlbflush (); vt__event_delivery_check (); vt__exit_reason (); //(.\core\vt_main.c) vt__event_delivery_update ();
下边是一个比较重要的数据结构。该数据结构中使用一个union,使用这个就够方便了存储VM_EXIT_INTR_INFO中的数据。
该数据可以直接调用U32 v写入到VM_ENTRY_INTR_INFO_FIELD中。也可以调用struct intr_info s来按项存储中断信息。
struct vt_intr_data { (.\core\vt.h) union { struct intr_info s; u32 v; } vmcs_intr_info; u32 vmcs_exception_errcode; u32 vmcs_instruction_len; };
static void vt__nmi (void) ( .\core\vt_main.c) { struct vt_intr_data *vid = ¤t->u.vt.intr; if (vid->vmcs_intr_info.s.valid == INTR_INFO_VALID_VALID) return; if (!current->nmi.get_nmi_count ()) return; if (!current->u.vt.vr.pe) panic ("NMI in real mode"); printf ("VT NMI!\n"); /* DEBUG */ vid->vmcs_intr_info.v = 0; vid->vmcs_intr_info.s.vector = EXCEPTION_NMI; vid->vmcs_intr_info.s.type = INTR_INFO_TYPE_NMI; vid->vmcs_intr_info.s.err = INTR_INFO_ERR_INVALID; vid->vmcs_intr_info.s.valid = INTR_INFO_VALID_VALID }
该函数检验了中断信息的合法性。和其他几种运行模式的情况。与主题关系不大,就不做解释了。
static void vt__event_delivery_setup (void) (.\core\vt_main.c) { struct vt_intr_data *vid = ¤t->u.vt.intr; if (vid->vmcs_intr_info.s.valid == INTR_INFO_VALID_VALID) { asm_vmwrite (VMCS_VMENTRY_INTR_INFO_FIELD, vid->vmcs_intr_info.v); if (vid->vmcs_intr_info.s.err == INTR_INFO_ERR_VALID) asm_vmwrite (VMCS_VMENTRY_EXCEPTION_ERRCODE, vid->vmcs_exception_errcode); asm_vmwrite (VMCS_VMENTRY_INSTRUCTION_LEN, vid->vmcs_instruction_len); } }
该函数将已有的数据填充到VMCS_VMENTRY_INTR_INFO_FIELD中,该数据可能为本次中断陷入VMM后从VM_EXIT_INTR_INFO中读取的也可能使上次运行之后人为填充的内容。等待后续检测。
static void vt__event_delivery_check (void)
该函数主要是检验IDT的问题与简单的中断处理无关。不做介绍了。
关键性操作在vt__exit_reason ()中。函数vt__exit_reason ()就是一个事件分发函数,我们主要关心的是两个部分
case EXIT_REASON_EXTERNAL_INT: STATUS_UPDATE (asm_lock_incl (&stat_intcnt)); do_exint_pass (); break; case EXIT_REASON_INTERRUPT_WINDOW: current->exint.hlt (); break;
前者为外部中断事件,后者为中断窗事件。两者共同完成VMM对外部中断的处理。
前者处理中STATUS_UPDATE (asm_lock_incl (&stat_intcnt));获得中断后的异常(待验证)。
其后连个分发函数的处理方法完全相同。我们EXIT_REASON_EXTERNAL_INT的处理比较直观,EXIT_REASON_INTERRUPT_WINDOW的处理则稍微费些波折,所以我们先研究一下后者。
后者的处理函数是current->exint.hlt ();通过查找其声明及定义:
struct exint_func { //(声明于.\core\cpu.h) void (*int_enabled) (void); void (*exintfunc_default) (int num); void (*hlt) (void); }; static struct exint_func func = { //(定义于.\core\exint_pass.c) exint_pass_int_enabled, exint_pass_default, exint_pass_hlt, };
可知在后者调用exint.hlt ()函数时,实际是调用了exint_pass_hlt()(.\core\exint_pass.c)函数,其函数体为:
static void exint_pass_hlt (void) { do_exint_pass (); }
可见最终EXIT_REASON_EXTERNAL_INT和EXIT_REASON_INTERRUPT_WINDOW事件的处理方式是一致的。下边主要介绍一下处理过程。
再讲处理过程之前,首先说一下其中会用到的一个数据结构struct vmctl_func(.\core\vmctl.h)由于声明太长只列举其中有得到的参数:
struct vmctl_func { …… void (*generate_external_int) (uint num); …… void (*exint_pass) (bool enable); void (*exint_pending) (bool pending); …… }; static struct vmctl_func func = { (定义于.\core\vt.c) …… vt_generate_external_int, …… vt_exint_pass, vt_exint_pending, …… };
下边主要说一下处理函数do_exint_pass (),其函数体为:
void do_exint_pass (void) { ulong rflags; int num; current->vmctl.read_flags (&rflags); if (rflags & RFLAGS_IF_BIT) { /* if interrupts are enabled */ num = do_externalint_enable (); if (num >= 0) current->exint.exintfunc_default (num); current->vmctl.exint_pending (false); current->vmctl.exint_pass (false); } else { current->vmctl.exint_pending (true); current->vmctl.exint_pass (true); } }
主要实现功能为首先获取系统进入VMM前的EFLAGS值,用来判断是否可中断(IF位)。
如果IF=1,那么首先利用do_externalint_enable ()(.\core\int.c)函数获取中断号,该函数辗转调用了int_callfunc (arg, func)(.\core\int_handler.h)函数,该函数应该是实现获取中断号(根据后续操作人为,待确定),大家可自行查看该函数。
如果返回值大于0,执行一系列函数
static void exint_pass_default (int num) //(.\core\exint_pass.c) { current->vmctl.generate_external_int (num); }由上知需要调用vt_generate_external_int (u32 num),通过观察函数发现该函数是将外部中断信息存放到了全局变量current中了。
void vt_generate_external_int (u32 num) //(.\core\vt.c) { struct vt_intr_data *vid = ¤t->u.vt.intr; if (current->u.vt.vr.pe) { vid->vmcs_intr_info.s.vector = num; vid->vmcs_intr_info.s.type = INTR_INFO_TYPE_EXTERNAL; vid->vmcs_intr_info.s.err = INTR_INFO_ERR_INVALID; vid->vmcs_intr_info.s.nmi = 0; vid->vmcs_intr_info.s.reserved = 0; vid->vmcs_intr_info.s.valid = INTR_INFO_VALID_VALID; vid->vmcs_instruction_len = 0; current->u.vt.event = VT_EVENT_TYPE_DELIVERY; } else { cpu_emul_realmode_int (num); } }
接下来将要用到两个函数
static void vt_exint_pass (bool enable) { ulong pin; asm_vmread (VMCS_PIN_BASED_VMEXEC_CTL, &pin); if (enable) pin &= ~VMCS_PIN_BASED_VMEXEC_CTL_EXINTEXIT_BIT; else pin |= VMCS_PIN_BASED_VMEXEC_CTL_EXINTEXIT_BIT; asm_vmwrite (VMCS_PIN_BASED_VMEXEC_CTL, pin); } static void vt_exint_pending (bool pending) { ulong proc; asm_vmread (VMCS_PROC_BASED_VMEXEC_CTL, &proc); if (pending) proc |= VMCS_PROC_BASED_VMEXEC_CTL_INTRWINEXIT_BIT; else proc &= ~VMCS_PROC_BASED_VMEXEC_CTL_INTRWINEXIT_BIT; asm_vmwrite (VMCS_PROC_BASED_VMEXEC_CTL, proc); }
我看可以看到这两个函数分别设置中断位和中断窗位的有效与否。为后续VMM陷入做准备。
到此vt__exit_reason ()工作完成接下来执行vt__event_delivery_update ()函数。
static void vt__event_delivery_update (void) ( .\core\vt_main.c) { struct vt_intr_data *vid = ¤t->u.vt.intr; if (vid->vmcs_intr_info.s.valid == INTR_INFO_VALID_VALID &¤t->u.vt.event == VT_EVENT_TYPE_PHYSICAL) vid->vmcs_intr_info.s.valid = INTR_INFO_VALID_INVALID; }
该函数就主要是判断一下中断的合法性,也就是判断本次陷入VMM后,是否需要注入事件,如果必须则保持原有效位,否则清除有效位。
void do_exint_pass (void)是一个核心函数,它的大概处理思路是:
---------------------------------------------------------------------------------
- - IF==1 - 直接注入事件,开启外部中断,关闭中断窗口 -
-外部中断 - - -
- - IF==0 - 关闭外部中断,开启中断窗口 -
---------------------------------------------------------------------------------
- - IF==1 - 注入上次外部中断信息,开启外部中断,关闭中断窗口 -
-中断窗口 - - -
- - IF==0 - 关闭外部中断,开启中断窗口 -
---------------------------------------------------------------------------------
大概的流程就是这样,为了不误导大家,有一些细节我没有描述特别清楚。以后深入研究后在回来修改。
相关文章推荐
- STM32外部中断处理流程及注意事项
- 浅析达芬奇DM644x平台ARM中断处理流程
- 中断处理流程,ok6410
- 浅析高光谱遥感图像处理流程
- Linux中断处理流程
- Linux中断处理流程 - 中断向量表跳来跳去跳到C
- 浅析frmware的加载和init通过netlink处理uevent事件的一般流程
- linux中断处理浅析
- 中断处理流程
- arm linux 下中断流程简要分析--中断处理流程
- Exynos4412 中断驱动开发(二)—— 中断处理流程分析
- 浅析frmware的加载和init通过netlink处理uevent事件的一般流程(转)
- 析达芬奇DM644x平台ARM中断处理流程
- 设备直通下,中断处理流程
- MFC浅析(3) 文档视图结构中命令的处理流程
- Linux中断处理流程
- 按键处理及外部中断
- (C#)中断程序流程,处理事件(委托,事件,Lambda表达式)-3/3
- Keil MDK下的TQ2440外部中断处理程序
- ARM:ARM中断异常的处理流程