Xen Test Framework
main.c
Go to the documentation of this file.
1 
32 #include <xtf.h>
33 
34 const char test_title[] = "Test nmi-taskswitch-priv";
35 
37 
38 void entry_NMI_task(void);
39 asm("exit_NMI_task:"
40  "iretl;"
41  "entry_NMI_task:;"
42 
43  "push $0;"
44  "push $" STR(X86_EXC_NMI) ";"
45 
46  "push %es;"
47  "push %ds;"
48 
49  "push %edi;"
50  "push %esi;"
51  "push %edx;"
52  "push %ecx;"
53  "push %eax;"
54  "push %ebx;"
55  "push %ebp;"
56 
57  "mov %esp, %eax;"
58  "call do_exception;"
59 
60  "pop %ebp;"
61  "pop %ebx;"
62  "pop %eax;"
63  "pop %ecx;"
64  "pop %edx;"
65  "pop %esi;"
66  "pop %edi;"
67 
68  "pop %ds;"
69  "pop %es;"
70 
71  "add $2*4, %esp;" /* entry_vector/error_code. */
72 
73  "jmp exit_NMI_task;");
74 
75 
76 static env_tss nmi_tss __aligned(16) =
77 {
78  .eip = _u(entry_NMI_task),
79  .cs = __KERN_CS,
80  .eflags = X86_EFLAGS_MBS,
81  .esp = _u(nmi_stack + PAGE_SIZE),
82  .ss = __KERN_DS,
83 
84  .ds = __USER_DS,
85  .es = __USER_DS,
86  .fs = __USER_DS,
87  .gs = __USER_DS,
88 
89  .cr3 = _u(cr3_target),
91 };
92 
93 bool do_unhandled_exception(struct cpu_regs *regs)
94 {
95  if ( regs->entry_vector != X86_EXC_NMI )
96  return false;
97 
98  unsigned int curr_ts = str();
99  if ( curr_ts != GDTE_AVAIL0 * 8 )
100  xtf_failure("Fail: Running NMI handler with unexpected %%tr\n"
101  " Expected %04x, got %04x\n", GDTE_AVAIL0 * 8, curr_ts);
102 
103  /* Follow the TSS link pointer to get the interrupted state. */
104  env_tss *t = _p(user_desc_base(&gdt[nmi_tss.link >> 3]));
105 
106  printk(" NMI at %04x:%p, stack %04x:%p\n",
107  t->cs, _p(t->eip), t->ss, _p(t->esp));
108 
109  return true;
110 }
111 
112 static void __user_text user_inject_nmi(void)
113 {
115 }
116 
117 void test_main(void)
118 {
119  unsigned int curr_ts;
120  int rc = apic_init(APIC_MODE_XAPIC);
121 
122  if ( rc )
123  return xtf_error("Error: Unable to set up xapic mode: %d\n", rc);
124 
125  /*
126  * Remap the Local APIC MMIO window as USER, so user_inject_nmi() can send
127  * a self-NMI. No INVLPG, as this is a strict relaxing of permissions.
128  */
129  pae_l2_identmap[APIC_DEFAULT_BASE >> PAE_L2_PT_SHIFT] |= _PAGE_USER;
130 
131  /*
132  * Set up NMI handling to be a task gate.
133  */
135  pack_task_gate(&idt[X86_EXC_NMI], GDTE_AVAIL0 * 8);
136 
137  /*
138  * Send an NMI from supervisor mode, checking that we task switch back to
139  * the expected TSS.
140  */
141  printk("First self-nmi, from supervisor mode\n");
143 
144  if ( (curr_ts = str()) != TSS_SEL )
145  xtf_failure("Fail: Running main task with unexpected %%tr\n"
146  " Expected %04x, got %04x\n", TSS_SEL, curr_ts);
147 
148  /*
149  * Send an NMI from user mode, and again check that we are in the expected
150  * task.
151  */
152  printk("Second self-nmi, from user mode\n");
154 
155  if ( (curr_ts = str()) != TSS_SEL )
156  xtf_failure("Fail: Running main task with unexpected %%tr\n"
157  " Expected %04x, got %04x\n", TSS_SEL, curr_ts);
158 
159  /*
160  * If Xen is still alive, it handled the user=>supervisor task switch
161  * properly.
162  */
163  xtf_success(NULL);
164 }
165 
166 /*
167  * Local variables:
168  * mode: C
169  * c-file-style: "BSD"
170  * c-basic-offset: 4
171  * tab-width: 4
172  * indent-tabs-mode: nil
173  * End:
174  */
#define X86_EFLAGS_MBS
Definition: processor.h:8
#define __page_aligned_bss
Definition: compiler.h:37
#define APIC_DEST_SELF
Definition: apic.h:27
static env_tss nmi_tss
Definition: main.c:76
#define APIC_DM_NMI
Definition: apic.h:25
#define _u(v)
Express an arbitrary value v as unsigned long.
Definition: numbers.h:53
int apic_init(enum apic_mode mode)
Discover and initialise the local APIC to the requested mode.
Definition: apic.c:33
void printk(const char *fmt,...)
Definition: console.c:134
#define STR(x)
Stringise an expression, expanding preprocessor tokens.
Definition: macro_magic.h:17
#define __user_text
Definition: compiler.h:33
static unsigned long user_desc_base(const user_desc *d)
Definition: desc.h:179
static void apic_mmio_icr_write(uint64_t val)
Definition: apic.h:59
static uint8_t nmi_stack[PAGE_SIZE]
Definition: main.c:36
static void user_inject_nmi(void)
Definition: main.c:112
#define NULL
Definition: stddef.h:12
void xtf_success(const char *fmt,...)
Report test success.
Definition: report.c:38
#define X86_TSS_INVALID_IO_BITMAP
Definition: x86-tss.h:66
static void exec_user_void(void(*fn)(void))
Definition: lib.h:70
user_desc gdt[NR_GDT_ENTRIES]
void test_main(void)
To be implemented by each test, as its entry point.
Definition: main.c:137
void xtf_failure(const char *fmt,...)
Report a test failure.
Definition: report.c:94
static unsigned int str(void)
Definition: lib.h:366
void entry_NMI_task(void)
const char test_title[]
The title of the test.
Definition: main.c:14
#define GDTE_AVAIL0
Definition: segment.h:37
#define _p(v)
Express an abitrary integer v as void *.
Definition: numbers.h:48
#define PAGE_SIZE
Definition: page.h:11
#define _PAGE_USER
Definition: page.h:27
void xtf_error(const char *fmt,...)
Report a test error.
Definition: report.c:80
#define APIC_DEFAULT_BASE
Definition: apic.h:31
#define X86_EXC_NMI
Definition: processor.h:104
static void pack_tss_desc(user_desc *d, const env_tss *t)
Definition: desc.h:203
#define PAE_L2_PT_SHIFT
Definition: page-pae.h:33
static void pack_task_gate(env_gate *g, unsigned int selector)
Definition: x86-gate.h:105
bool do_unhandled_exception(struct cpu_regs *regs)
May be implemented by a guest to provide custom exception handling.
Definition: main.c:93
__UINT8_TYPE__ uint8_t
Definition: stdint.h:14
#define __aligned(x)
Definition: compiler.h:9