]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/lguest/lguest_asm.S
lguest: documentation VI: Switcher
[mirror_ubuntu-bionic-kernel.git] / drivers / lguest / lguest_asm.S
CommitLineData
07ad157f
RR
1#include <linux/linkage.h>
2#include <linux/lguest.h>
3#include <asm/asm-offsets.h>
4#include <asm/thread_info.h>
876be9d8 5#include <asm/processor-flags.h>
07ad157f 6
b2b47c21
RR
7/*G:020 This is where we begin: we have a magic signature which the launcher
8 * looks for. The plan is that the Linux boot protocol will be extended with a
07ad157f 9 * "platform type" field which will guide us here from the normal entry point,
b2b47c21
RR
10 * but for the moment this suffices. The normal boot code uses %esi for the
11 * boot header, so we do too. We convert it to a virtual address by adding
12 * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
07ad157f 13 *
b2b47c21
RR
14 * The .section line puts this code in .init.text so it will be discarded after
15 * boot. */
07ad157f
RR
16.section .init.text, "ax", @progbits
17.ascii "GenuineLguest"
18 /* Set up initial stack. */
19 movl $(init_thread_union+THREAD_SIZE),%esp
d7e28ffe
RR
20 movl %esi, %eax
21 addl $__PAGE_OFFSET, %eax
07ad157f
RR
22 jmp lguest_init
23
b2b47c21
RR
24/*G:055 We create a macro which puts the assembler code between lgstart_ and
25 * lgend_ markers. These templates end up in the .init.text section, so they
26 * are discarded after boot. */
07ad157f
RR
27#define LGUEST_PATCH(name, insns...) \
28 lgstart_##name: insns; lgend_##name:; \
29 .globl lgstart_##name; .globl lgend_##name
30
31LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
32LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
33LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
34LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
b2b47c21 35/*:*/
07ad157f
RR
36
37.text
38/* These demark the EIP range where host should never deliver interrupts. */
39.global lguest_noirq_start
40.global lguest_noirq_end
41
b2b47c21
RR
42/*G:045 There is one final paravirt_op that the Guest implements, and glancing
43 * at it you can see why I left it to last. It's *cool*! It's in *assembler*!
44 *
45 * The "iret" instruction is used to return from an interrupt or trap. The
46 * stack looks like this:
47 * old address
48 * old code segment & privilege level
49 * old processor flags ("eflags")
50 *
51 * The "iret" instruction pops those values off the stack and restores them all
52 * at once. The only problem is that eflags includes the Interrupt Flag which
53 * the Guest can't change: the CPU will simply ignore it when we do an "iret".
54 * So we have to copy eflags from the stack to lguest_data.irq_enabled before
55 * we do the "iret".
56 *
57 * There are two problems with this: firstly, we need to use a register to do
58 * the copy and secondly, the whole thing needs to be atomic. The first
59 * problem is easy to solve: push %eax on the stack so we can use it, and then
60 * restore it at the end just before the real "iret".
61 *
62 * The second is harder: copying eflags to lguest_data.irq_enabled will turn
63 * interrupts on before we're finished, so we could be interrupted before we
64 * return to userspace or wherever. Our solution to this is to surround the
65 * code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the
66 * Host that it is *never* to interrupt us there, even if interrupts seem to be
67 * enabled. */
07ad157f
RR
68ENTRY(lguest_iret)
69 pushl %eax
70 movl 12(%esp), %eax
71lguest_noirq_start:
b2b47c21
RR
72 /* Note the %ss: segment prefix here. Normal data accesses use the
73 * "ds" segment, but that will have already been restored for whatever
74 * we're returning to (such as userspace): we can't trust it. The %ss:
75 * prefix makes sure we use the stack segment, which is still valid. */
07ad157f
RR
76 movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
77 popl %eax
78 iret
79lguest_noirq_end: