diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-07-26 10:41:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-26 11:35:17 -0700 |
commit | b2b47c214f4e85ce3968120d42e8b18eccb4f4e3 (patch) | |
tree | f77d6898a769b8e0fcb552207e87f273bdc19f09 /drivers/lguest/lguest_asm.S | |
parent | f938d2c892db0d80d144253d4a7b7083efdbedeb (diff) | |
download | kernel_samsung_aries-b2b47c214f4e85ce3968120d42e8b18eccb4f4e3.zip kernel_samsung_aries-b2b47c214f4e85ce3968120d42e8b18eccb4f4e3.tar.gz kernel_samsung_aries-b2b47c214f4e85ce3968120d42e8b18eccb4f4e3.tar.bz2 |
lguest: documentation II: Guest
Documentation: The Guest
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/lguest/lguest_asm.S')
-rw-r--r-- | drivers/lguest/lguest_asm.S | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S index a3dbf22..3126ae9 100644 --- a/drivers/lguest/lguest_asm.S +++ b/drivers/lguest/lguest_asm.S @@ -4,15 +4,15 @@ #include <asm/thread_info.h> #include <asm/processor-flags.h> -/* - * This is where we begin: we have a magic signature which the launcher looks - * for. The plan is that the Linux boot protocol will be extended with a +/*G:020 This is where we begin: we have a magic signature which the launcher + * looks for. The plan is that the Linux boot protocol will be extended with a * "platform type" field which will guide us here from the normal entry point, - * but for the moment this suffices. We pass the virtual address of the boot - * info to lguest_init(). + * but for the moment this suffices. The normal boot code uses %esi for the + * boot header, so we do too. We convert it to a virtual address by adding + * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax). * - * We put it in .init.text will be discarded after boot. - */ + * The .section line puts this code in .init.text so it will be discarded after + * boot. */ .section .init.text, "ax", @progbits .ascii "GenuineLguest" /* Set up initial stack. */ @@ -21,7 +21,9 @@ addl $__PAGE_OFFSET, %eax jmp lguest_init -/* The templates for inline patching. */ +/*G:055 We create a macro which puts the assembler code between lgstart_ and + * lgend_ markers. These templates end up in the .init.text section, so they + * are discarded after boot. */ #define LGUEST_PATCH(name, insns...) \ lgstart_##name: insns; lgend_##name:; \ .globl lgstart_##name; .globl lgend_##name @@ -30,24 +32,47 @@ LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled) LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled) LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled) LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax) +/*:*/ .text /* These demark the EIP range where host should never deliver interrupts. */ .global lguest_noirq_start .global lguest_noirq_end -/* - * We move eflags word to lguest_data.irq_enabled to restore interrupt state. - * For page faults, gpfs and virtual interrupts, the hypervisor has saved - * eflags manually, otherwise it was delivered directly and so eflags reflects - * the real machine IF state, ie. interrupts on. Since the kernel always dies - * if it takes such a trap with interrupts disabled anyway, turning interrupts - * back on unconditionally here is OK. - */ +/*G:045 There is one final paravirt_op that the Guest implements, and glancing + * at it you can see why I left it to last. It's *cool*! It's in *assembler*! + * + * The "iret" instruction is used to return from an interrupt or trap. The + * stack looks like this: + * old address + * old code segment & privilege level + * old processor flags ("eflags") + * + * The "iret" instruction pops those values off the stack and restores them all + * at once. The only problem is that eflags includes the Interrupt Flag which + * the Guest can't change: the CPU will simply ignore it when we do an "iret". + * So we have to copy eflags from the stack to lguest_data.irq_enabled before + * we do the "iret". + * + * There are two problems with this: firstly, we need to use a register to do + * the copy and secondly, the whole thing needs to be atomic. The first + * problem is easy to solve: push %eax on the stack so we can use it, and then + * restore it at the end just before the real "iret". + * + * The second is harder: copying eflags to lguest_data.irq_enabled will turn + * interrupts on before we're finished, so we could be interrupted before we + * return to userspace or wherever. Our solution to this is to surround the + * code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the + * Host that it is *never* to interrupt us there, even if interrupts seem to be + * enabled. */ ENTRY(lguest_iret) pushl %eax movl 12(%esp), %eax lguest_noirq_start: + /* Note the %ss: segment prefix here. Normal data accesses use the + * "ds" segment, but that will have already been restored for whatever + * we're returning to (such as userspace): we can't trust it. The %ss: + * prefix makes sure we use the stack segment, which is still valid. */ movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled popl %eax iret |