Chinaunix首页 | 论坛 | 博客
  • 博客访问: 586510
  • 博文数量: 197
  • 博客积分: 7001
  • 博客等级: 大校
  • 技术积分: 2155
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-24 00:29
文章分类

全部博文(197)

文章存档

2022年(1)

2019年(2)

2015年(1)

2012年(100)

2011年(69)

2010年(14)

2007年(3)

2005年(7)

分类: LINUX

2012-03-18 22:51:56

参考资料

xen Interface manual Xen v3.0 for x86

非常有用的材料

In vanilla Linux the IDT is initialized in trap_init() using set__gate() functions. Because Xen handles the IDT, it requires all calls to these function to be replaced with a single call to the HYPERVISOR_set_trap_table() hypercall.

HYPERVISOR_set_trap_table() accepts as a parameter the virtual IDT of the guest, represented by the trap_table structure (of type struct trap_info) in traps-xen.c.

struct trap_info resembles a trap or interrupt gate, having fields for vector, handler segment selector and offset.

Xen maintains two IDT's, one global IDT (its own) and other per domain IDT. Xen uses global IDT to register the entire trap handler except for system call handler (int 0x80).

 

  A virtual IDT is provided by guest OS for setting up interrupt vector table.

  The exception stack frame presented to a virtual trap handler is identical to its native equivalent.

 

Xen guest 中的trap table linux-2.6-xen-sparse /arch/i386/kernel/traps-xen.c

static trap_info_t trap_table[] = {

       {  0, 0, __KERNEL_CS, (unsigned long)divide_error        },

       {  1, 0|4, __KERNEL_CS, (unsigned long)debug                     },

       {  3, 3|4, __KERNEL_CS, (unsigned long)int3                 },

       {  4, 3, __KERNEL_CS, (unsigned long)overflow                   },

       {  5, 0, __KERNEL_CS, (unsigned long)bounds               },

       {  6, 0, __KERNEL_CS, (unsigned long)invalid_op                  },

       {  7, 0|4, __KERNEL_CS, (unsigned long)device_not_available },

       {  9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },

       { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS         },

       { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present   },

       { 12, 0, __KERNEL_CS, (unsigned long)stack_segment            },

       { 13, 0, __KERNEL_CS, (unsigned long)general_protection              },

       { 14, 0|4, __KERNEL_CS, (unsigned long)page_fault         },

       { 15, 0, __KERNEL_CS, (unsigned long)fixup_4gb_segment            },

       { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error             },

       { 17, 0, __KERNEL_CS, (unsigned long)alignment_check         },

#ifdef CONFIG_X86_MCE

       { 18, 0, __KERNEL_CS, (unsigned long)machine_check           },

#endif

       { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error     },

       { SYSCALL_VECTOR,  3, __KERNEL_CS, (unsigned long)system_call },

       {  0, 0,     0, 0                                      }

};

 

void trap_init() {

HYPERVISOR_set_trap_table(trap_table);

}

为什么要使用中断门

hypercall 使用中断门见hypercall篇“Xen中的实现”小节。

a curious question about IDT descriptor type for hypercall. What's the reason to use interrupt-gate type (14) for hypercall (0x82) on 32bit Xen?

 

回答:

Everything's an interrupt gate on 32-bit Xen, so that we can safely (atomically) save away guest segment register state. NMI is the only real pain, and I suppose MCE too.

Interrupt handlers save and restore segment registers. We could fault on a reload of a segment register and lose the original segment register value.

 

的流处理程

入口和出口见xen/arch/x86/x86-32/entry.Shandle_exception

 

可分为以下几种情况

1 guest application的系统调用,直接切换到ring 1 guest kernel执行,见后面的小节。

2 其余情况由xen的异常处理程序处理,发生异常 ==> 陷入VMM. When an exception occurs the processor transfers control to the Xen hypervisor, using the Xen exception handlers in entry.S.

2.1 如下面的异常 in xen/arch/x86/traps.c,都将调用do_trap

DO_ERROR_NOCODE(TRAP_divide_error,    divide_error)

DO_ERROR_NOCODE(TRAP_overflow,        overflow)

DO_ERROR_NOCODE(TRAP_bounds,          bounds)

DO_ERROR_NOCODE(TRAP_copro_seg,       coprocessor_segment_overrun)

DO_ERROR(       TRAP_invalid_tss,     invalid_TSS)

DO_ERROR(       TRAP_no_segment,      segment_not_present)

DO_ERROR(       TRAP_stack_error,     stack_segment)

DO_ERROR_NOCODE(TRAP_copro_error,     coprocessor_error)

DO_ERROR(       TRAP_alignment_check, alignment_check)

DO_ERROR_NOCODE(TRAP_simd_error,      simd_coprocessor_error)

do_trap()==> 判断trap是否来自Guest OS ==> 如果是,调用()。否则xen panic
              Guest OS App --> VMM --> Guest OS Kernel

2.2  GPEInvalid op有自己的处理函数do_general_protection do_invalid_op。特别值得一提的是do_general_protection,有时候guest kernel执行sensitive instruction会导致GPE,所以调用emulate_privileged_op模拟执行,其他的处理类似do_trap

 

一个示例见

的处理

1 Gets from the guest context the gate for the exception

2 Creates the exception frame required by the guest OS to process the exception

Then iret is executed to return control to the guest OS exception handler

 

另外提一下 The Definitive Guide to the Xen Hypervisor 7.2 p120的说法不确切。

The code path for delivering a trap is significantly simpler than that for events.When the guest is run on a particular (physical) CPU, the hypervisor installs an Interrupt Descriptor Table (IDT) on behalf of the guest domain. This means that the interrupt handling path does not involve the hypervisor at all, for all interrupts are handled by the guest.”

System Call

trap table有如下项:

{ SYSCALL_VECTOR,  3, __KERNEL_CS, (unsigned long)system_call },

前面已经提到int 80h被特殊对待,If everything is 32-bit, "int 80" will be used, but it'll be directed directly to the guest kernel in ring 1 (i.e. the hypervisor isn't involved).

具体的实现见:

in xen/arch/x86/traps.c:do_set_trap_table():

 if ( cur.vector == 0x80 )

     init_int80_direct_trap(curr);

init_int80_direct_trap 将设置int80_desc,然后进程切换时paravirt_ctxt_switch_to =>set_int80_direct_trap

 

When a VM gets scheduled, its system call handler (from per domain IDT table) is registered with the processorVCPU内). Hence when a domain/VM executes a system call, its own handler is executed.

==》这样X86_32就可以不陷入VMM了。而且可以做到每个Guest OSsystem call不同。

 

Implementation differs for x86_64: Xen registers its own system call handler with the processor and from that handler routes the request to VM/Domain specific handler.

==》因为x86_64Kernel也是在Ring-3(和以前的Ring-0不同),以前的system call不能用了,只能改写。

 


阅读(1678) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~