aboutsummaryrefslogtreecommitdiffstats
path: root/xen/include/asm-x86/x86_32/asm_defns.h
blob: a9f65f22dae9cafa5b58f08c7aa7f6dce0ffbe8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#ifndef __X86_32_ASM_DEFNS_H__
#define __X86_32_ASM_DEFNS_H__

#include <asm/percpu.h>

#ifdef CONFIG_FRAME_POINTER
/* Indicate special exception stack frame by inverting the frame pointer. */
#define SETUP_EXCEPTION_FRAME_POINTER           \
        movl  %esp,%ebp;                        \
        notl  %ebp
#else
#define SETUP_EXCEPTION_FRAME_POINTER
#endif

#ifndef NDEBUG
#define ASSERT_INTERRUPT_STATUS(x)              \
        pushf;                                  \
        testb $X86_EFLAGS_IF>>8,1(%esp);        \
        j##x  1f;                               \
        ud2a;                                   \
1:      addl  $4,%esp;
#else
#define ASSERT_INTERRUPT_STATUS(x)
#endif

#define ASSERT_INTERRUPTS_ENABLED  ASSERT_INTERRUPT_STATUS(nz)
#define ASSERT_INTERRUPTS_DISABLED ASSERT_INTERRUPT_STATUS(z)

#define SAVE_ALL_GPRS                                   \
        cld;                                            \
        pushl %eax;                                     \
        pushl %ebp;                                     \
        SETUP_EXCEPTION_FRAME_POINTER;                  \
        pushl %edi;                                     \
        pushl %esi;                                     \
        pushl %edx;                                     \
        pushl %ecx;                                     \
        pushl %ebx

/*
 * Saves all register state into an exception/interrupt stack frame.
 * Returns to the caller at <xen_lbl> if the interrupted context is within
 * Xen; at <vm86_lbl> if the interrupted context is vm86; or falls through
 * if the interrupted context is an ordinary guest protected-mode context.
 * In all cases %ecx contains __HYPERVISOR_DS. %ds/%es are guaranteed to
 * contain __HYPERVISOR_DS unless control passes to <xen_lbl>, in which case
 * the caller is reponsible for validity of %ds/%es.
 */
#define SAVE_ALL(xen_lbl, vm86_lbl)                     \
        SAVE_ALL_GPRS;                                  \
        testl $(X86_EFLAGS_VM),UREGS_eflags(%esp);      \
        mov   %ds,%edi;                                 \
        mov   %es,%esi;                                 \
        mov   $(__HYPERVISOR_DS),%ecx;                  \
        jnz   86f;                                      \
        .text 1;                                        \
        86:   call setup_vm86_frame;                    \
        jmp   vm86_lbl;                                 \
        .previous;                                      \
        testb $3,UREGS_cs(%esp);                        \
        jz    xen_lbl;                                  \
        /*                                              \
         * We are the outermost Xen context, but our    \
         * life is complicated by NMIs and MCEs. These  \
         * could occur in our critical section and      \
         * pollute %ds and %es. We have to detect that  \
         * this has occurred and avoid saving Xen DS/ES \
         * values to the guest stack frame.             \
         */                                             \
        cmpw  %cx,%di;                                  \
        mov   %ecx,%ds;                                 \
        mov   %fs,UREGS_fs(%esp);                       \
        cmove UREGS_ds(%esp),%edi;                      \
        cmpw  %cx,%si;                                  \
        mov   %edi,UREGS_ds(%esp);                      \
        cmove UREGS_es(%esp),%esi;                      \
        mov   %ecx,%es;                                 \
        mov   %gs,UREGS_gs(%esp);                       \
        mov   %esi,UREGS_es(%esp)

#ifdef PERF_COUNTERS
#define PERFC_INCR(_name,_idx,_cur)                     \
        pushl _cur;                                     \
        movl VCPU_processor(_cur),_cur;                 \
        shll $PERCPU_SHIFT,_cur;                        \
        incl per_cpu__perfcounters+ASM_PERFC_##_name*4(_cur,_idx,4);\
        popl _cur
#else
#define PERFC_INCR(_name,_idx,_cur)
#endif

#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL
#define FIXUP_RING0_GUEST_STACK                         \
        testl $2,8(%esp);                               \
        jnz 1f; /* rings 2 & 3 permitted */             \
        testl $1,8(%esp);                               \
        jz 2f;                                          \
        ud2; /* ring 1 should not be used */            \
        2:cmpl $(__HYPERVISOR_VIRT_START),%esp;         \
        jge 1f;                                         \
        call fixup_ring0_guest_stack;                   \
        1:
#else
#define FIXUP_RING0_GUEST_STACK
#endif

#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
#define XBUILD_SMP_INTERRUPT(x,v)               \
__asm__(                                        \
    "\n"__ALIGN_STR"\n"                         \
    ".globl " STR(x) "\n\t"                     \
    STR(x) ":\n\t"                              \
    "pushl $"#v"<<16\n\t"                       \
    STR(FIXUP_RING0_GUEST_STACK)                \
    STR(SAVE_ALL(1f,1f)) "\n\t"                 \
    "1:movl %esp,%eax\n\t"                      \
    "pushl %eax\n\t"                            \
    "call "STR(smp_##x)"\n\t"                   \
    "addl $4,%esp\n\t"                          \
    "jmp ret_from_intr\n");

#define BUILD_COMMON_IRQ()                      \
__asm__(                                        \
    "\n" __ALIGN_STR"\n"                        \
    "common_interrupt:\n\t"                     \
    STR(FIXUP_RING0_GUEST_STACK)                \
    STR(SAVE_ALL(1f,1f)) "\n\t"                 \
    "1:movl %esp,%eax\n\t"                      \
    "pushl %eax\n\t"                            \
    "call " STR(do_IRQ) "\n\t"                  \
    "addl $4,%esp\n\t"                          \
    "jmp ret_from_intr\n");

#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

#define BUILD_IRQ(nr)                           \
void IRQ_NAME(nr);                   \
__asm__(                                        \
"\n"__ALIGN_STR"\n"                             \
STR(IRQ) #nr "_interrupt:\n\t"                  \
    "pushl $"#nr"<<16\n\t"                      \
    "jmp common_interrupt");

#endif /* __X86_32_ASM_DEFNS_H__ */