Blame view
drivers/lguest/interrupts_and_traps.c
20.2 KB
2e04ef769 lguest: fix comme... |
1 2 |
/*P:800 * Interrupts (traps) are complicated enough to earn their own file. |
f938d2c89 lguest: documenta... |
3 4 5 6 7 8 9 10 11 12 13 |
* There are three classes of interrupts: * * 1) Real hardware interrupts which occur while we're running the Guest, * 2) Interrupts for virtual devices attached to the Guest, and * 3) Traps and faults from the Guest. * * Real hardware interrupts must be delivered to the Host, not the Guest. * Virtual interrupts must be delivered to the Guest, but we make them look * just like real hardware would deliver them. Traps from the Guest can be set * up to go directly back into the Guest, but sometimes the Host wants to see * them first, so we also have a way of "reflecting" them into the Guest as if |
2e04ef769 lguest: fix comme... |
14 15 |
* they had been delivered to it directly. :*/ |
d7e28ffe6 lguest: the host ... |
16 |
#include <linux/uaccess.h> |
c18acd73f Allow guest to sp... |
17 18 |
#include <linux/interrupt.h> #include <linux/module.h> |
d43c36dc6 headers: remove s... |
19 |
#include <linux/sched.h> |
d7e28ffe6 lguest: the host ... |
20 |
#include "lg.h" |
c18acd73f Allow guest to sp... |
21 22 23 |
/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */ static unsigned int syscall_vector = SYSCALL_VECTOR; module_param(syscall_vector, uint, 0444); |
bff672e63 lguest: documenta... |
24 |
/* The address of the interrupt handler is split into two bits: */ |
d7e28ffe6 lguest: the host ... |
25 26 27 28 |
static unsigned long idt_address(u32 lo, u32 hi) { return (lo & 0x0000FFFF) | (hi & 0xFFFF0000); } |
2e04ef769 lguest: fix comme... |
29 30 31 32 |
/* * The "type" of the interrupt handler is a 4 bit field: we only support a * couple of types. */ |
d7e28ffe6 lguest: the host ... |
33 34 35 36 |
static int idt_type(u32 lo, u32 hi) { return (hi >> 8) & 0xF; } |
bff672e63 lguest: documenta... |
37 |
/* An IDT entry can't be used unless the "present" bit is set. */ |
df1693abc lguest: use bool ... |
38 |
static bool idt_present(u32 lo, u32 hi) |
d7e28ffe6 lguest: the host ... |
39 40 41 |
{ return (hi & 0x8000); } |
2e04ef769 lguest: fix comme... |
42 43 44 45 |
/* * We need a helper to "push" a value onto the Guest's stack, since that's a * big part of what delivering an interrupt does. */ |
382ac6b3f lguest: get rid o... |
46 |
static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val) |
d7e28ffe6 lguest: the host ... |
47 |
{ |
bff672e63 lguest: documenta... |
48 |
/* Stack grows upwards: move stack then write value. */ |
d7e28ffe6 lguest: the host ... |
49 |
*gstack -= 4; |
382ac6b3f lguest: get rid o... |
50 |
lgwrite(cpu, *gstack, u32, val); |
d7e28ffe6 lguest: the host ... |
51 |
} |
2e04ef769 lguest: fix comme... |
52 53 |
/*H:210 * The set_guest_interrupt() routine actually delivers the interrupt or |
bff672e63 lguest: documenta... |
54 55 56 57 58 59 60 61 62 63 |
* trap. The mechanics of delivering traps and interrupts to the Guest are the * same, except some traps have an "error code" which gets pushed onto the * stack as well: the caller tells us if this is one. * * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this * interrupt or trap. It's split into two parts for traditional reasons: gcc * on i386 used to be frightened by 64 bit numbers. * * We set up the stack just like the CPU does for a real interrupt, so it's * identical for the Guest (and the standard "iret" instruction will undo |
2e04ef769 lguest: fix comme... |
64 65 |
* it). */ |
df1693abc lguest: use bool ... |
66 67 |
static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, bool has_err) |
d7e28ffe6 lguest: the host ... |
68 |
{ |
47436aa4a Boot with virtual... |
69 |
unsigned long gstack, origstack; |
d7e28ffe6 lguest: the host ... |
70 |
u32 eflags, ss, irq_enable; |
47436aa4a Boot with virtual... |
71 |
unsigned long virtstack; |
d7e28ffe6 lguest: the host ... |
72 |
|
2e04ef769 lguest: fix comme... |
73 74 |
/* * There are two cases for interrupts: one where the Guest is already |
bff672e63 lguest: documenta... |
75 |
* in the kernel, and a more complex one where the Guest is in |
2e04ef769 lguest: fix comme... |
76 77 |
* userspace. We check the privilege level to find out. */ |
a53a35a8b lguest: make regi... |
78 |
if ((cpu->regs->ss&0x3) != GUEST_PL) { |
2e04ef769 lguest: fix comme... |
79 80 81 82 |
/* * The Guest told us their kernel stack with the SET_STACK * hypercall: both the virtual address and the segment. */ |
4665ac8e2 lguest: makes spe... |
83 84 |
virtstack = cpu->esp1; ss = cpu->ss1; |
47436aa4a Boot with virtual... |
85 |
|
1713608f2 lguest: per-vcpu ... |
86 |
origstack = gstack = guest_pa(cpu, virtstack); |
2e04ef769 lguest: fix comme... |
87 88 |
/* * We push the old stack segment and pointer onto the new |
bff672e63 lguest: documenta... |
89 90 |
* stack: when the Guest does an "iret" back from the interrupt * handler the CPU will notice they're dropping privilege |
2e04ef769 lguest: fix comme... |
91 92 |
* levels and expect these here. */ |
382ac6b3f lguest: get rid o... |
93 94 |
push_guest_stack(cpu, &gstack, cpu->regs->ss); push_guest_stack(cpu, &gstack, cpu->regs->esp); |
d7e28ffe6 lguest: the host ... |
95 |
} else { |
bff672e63 lguest: documenta... |
96 |
/* We're staying on the same Guest (kernel) stack. */ |
a53a35a8b lguest: make regi... |
97 98 |
virtstack = cpu->regs->esp; ss = cpu->regs->ss; |
47436aa4a Boot with virtual... |
99 |
|
1713608f2 lguest: per-vcpu ... |
100 |
origstack = gstack = guest_pa(cpu, virtstack); |
d7e28ffe6 lguest: the host ... |
101 |
} |
2e04ef769 lguest: fix comme... |
102 103 |
/* * Remember that we never let the Guest actually disable interrupts, so |
bff672e63 lguest: documenta... |
104 |
* the "Interrupt Flag" bit is always set. We copy that bit from the |
e1e72965e lguest: documenta... |
105 |
* Guest's "irq_enabled" field into the eflags word: we saw the Guest |
2e04ef769 lguest: fix comme... |
106 107 |
* copy it back in "lguest_iret". */ |
a53a35a8b lguest: make regi... |
108 |
eflags = cpu->regs->eflags; |
382ac6b3f lguest: get rid o... |
109 |
if (get_user(irq_enable, &cpu->lg->lguest_data->irq_enabled) == 0 |
e5faff45b lguest: fix sense... |
110 111 |
&& !(irq_enable & X86_EFLAGS_IF)) eflags &= ~X86_EFLAGS_IF; |
d7e28ffe6 lguest: the host ... |
112 |
|
2e04ef769 lguest: fix comme... |
113 114 |
/* * An interrupt is expected to push three things on the stack: the old |
bff672e63 lguest: documenta... |
115 |
* "eflags" word, the old code segment, and the old instruction |
2e04ef769 lguest: fix comme... |
116 117 |
* pointer. */ |
382ac6b3f lguest: get rid o... |
118 119 120 |
push_guest_stack(cpu, &gstack, eflags); push_guest_stack(cpu, &gstack, cpu->regs->cs); push_guest_stack(cpu, &gstack, cpu->regs->eip); |
d7e28ffe6 lguest: the host ... |
121 |
|
bff672e63 lguest: documenta... |
122 |
/* For the six traps which supply an error code, we push that, too. */ |
d7e28ffe6 lguest: the host ... |
123 |
if (has_err) |
382ac6b3f lguest: get rid o... |
124 |
push_guest_stack(cpu, &gstack, cpu->regs->errcode); |
d7e28ffe6 lguest: the host ... |
125 |
|
2e04ef769 lguest: fix comme... |
126 127 128 129 |
/* * Now we've pushed all the old state, we change the stack, the code * segment and the address to execute. */ |
a53a35a8b lguest: make regi... |
130 131 132 133 |
cpu->regs->ss = ss; cpu->regs->esp = virtstack + (gstack - origstack); cpu->regs->cs = (__KERNEL_CS|GUEST_PL); cpu->regs->eip = idt_address(lo, hi); |
d7e28ffe6 lguest: the host ... |
134 |
|
2e04ef769 lguest: fix comme... |
135 136 137 138 |
/* * There are two kinds of interrupt handlers: 0xE is an "interrupt * gate" which expects interrupts to be disabled on entry. */ |
d7e28ffe6 lguest: the host ... |
139 |
if (idt_type(lo, hi) == 0xE) |
382ac6b3f lguest: get rid o... |
140 141 |
if (put_user(0, &cpu->lg->lguest_data->irq_enabled)) kill_guest(cpu, "Disabling interrupts"); |
d7e28ffe6 lguest: the host ... |
142 |
} |
e1e72965e lguest: documenta... |
143 |
/*H:205 |
bff672e63 lguest: documenta... |
144 145 |
* Virtual Interrupts. * |
abd41f037 lguest: fix race ... |
146 147 |
* interrupt_pending() returns the first pending interrupt which isn't blocked * by the Guest. It is called before every entry to the Guest, and just before |
2e04ef769 lguest: fix comme... |
148 149 |
* we go to sleep when the Guest has halted itself. */ |
a32a8813d lguest: improve i... |
150 |
unsigned int interrupt_pending(struct lg_cpu *cpu, bool *more) |
d7e28ffe6 lguest: the host ... |
151 152 153 |
{ unsigned int irq; DECLARE_BITMAP(blk, LGUEST_IRQS); |
d7e28ffe6 lguest: the host ... |
154 |
|
bff672e63 lguest: documenta... |
155 |
/* If the Guest hasn't even initialized yet, we can do nothing. */ |
382ac6b3f lguest: get rid o... |
156 |
if (!cpu->lg->lguest_data) |
abd41f037 lguest: fix race ... |
157 |
return LGUEST_IRQS; |
d7e28ffe6 lguest: the host ... |
158 |
|
2e04ef769 lguest: fix comme... |
159 160 161 162 |
/* * Take our "irqs_pending" array and remove any interrupts the Guest * wants blocked: the result ends up in "blk". */ |
382ac6b3f lguest: get rid o... |
163 |
if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts, |
d7e28ffe6 lguest: the host ... |
164 |
sizeof(blk))) |
abd41f037 lguest: fix race ... |
165 |
return LGUEST_IRQS; |
177e449dc lguest: per-vcpu ... |
166 |
bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS); |
d7e28ffe6 lguest: the host ... |
167 |
|
bff672e63 lguest: documenta... |
168 |
/* Find the first interrupt. */ |
d7e28ffe6 lguest: the host ... |
169 |
irq = find_first_bit(blk, LGUEST_IRQS); |
a32a8813d lguest: improve i... |
170 |
*more = find_next_bit(blk, LGUEST_IRQS, irq+1); |
abd41f037 lguest: fix race ... |
171 172 173 |
return irq; } |
2e04ef769 lguest: fix comme... |
174 175 176 177 |
/* * This actually diverts the Guest to running an interrupt handler, once an * interrupt has been identified by interrupt_pending(). */ |
a32a8813d lguest: improve i... |
178 |
void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more) |
abd41f037 lguest: fix race ... |
179 180 181 182 |
{ struct desc_struct *idt; BUG_ON(irq >= LGUEST_IRQS); |
d7e28ffe6 lguest: the host ... |
183 |
|
2e04ef769 lguest: fix comme... |
184 185 186 187 |
/* * They may be in the middle of an iret, where they asked us never to * deliver interrupts. */ |
382ac6b3f lguest: get rid o... |
188 189 |
if (cpu->regs->eip >= cpu->lg->noirq_start && (cpu->regs->eip < cpu->lg->noirq_end)) |
d7e28ffe6 lguest: the host ... |
190 |
return; |
bff672e63 lguest: documenta... |
191 |
/* If they're halted, interrupts restart them. */ |
66686c2ab lguest: per-vcpu ... |
192 |
if (cpu->halted) { |
d7e28ffe6 lguest: the host ... |
193 |
/* Re-enable interrupts. */ |
382ac6b3f lguest: get rid o... |
194 195 |
if (put_user(X86_EFLAGS_IF, &cpu->lg->lguest_data->irq_enabled)) kill_guest(cpu, "Re-enabling interrupts"); |
66686c2ab lguest: per-vcpu ... |
196 |
cpu->halted = 0; |
d7e28ffe6 lguest: the host ... |
197 |
} else { |
bff672e63 lguest: documenta... |
198 |
/* Otherwise we check if they have interrupts disabled. */ |
d7e28ffe6 lguest: the host ... |
199 |
u32 irq_enabled; |
382ac6b3f lguest: get rid o... |
200 |
if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled)) |
d7e28ffe6 lguest: the host ... |
201 |
irq_enabled = 0; |
a32a8813d lguest: improve i... |
202 203 204 205 |
if (!irq_enabled) { /* Make sure they know an IRQ is pending. */ put_user(X86_EFLAGS_IF, &cpu->lg->lguest_data->irq_pending); |
d7e28ffe6 lguest: the host ... |
206 |
return; |
a32a8813d lguest: improve i... |
207 |
} |
d7e28ffe6 lguest: the host ... |
208 |
} |
2e04ef769 lguest: fix comme... |
209 210 |
/* * Look at the IDT entry the Guest gave us for this interrupt. The |
bff672e63 lguest: documenta... |
211 |
* first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip |
2e04ef769 lguest: fix comme... |
212 213 |
* over them. */ |
fc708b3e4 lguest: replace l... |
214 |
idt = &cpu->arch.idt[FIRST_EXTERNAL_VECTOR+irq]; |
bff672e63 lguest: documenta... |
215 |
/* If they don't have a handler (yet?), we just ignore it */ |
d7e28ffe6 lguest: the host ... |
216 |
if (idt_present(idt->a, idt->b)) { |
bff672e63 lguest: documenta... |
217 |
/* OK, mark it no longer pending and deliver it. */ |
177e449dc lguest: per-vcpu ... |
218 |
clear_bit(irq, cpu->irqs_pending); |
2e04ef769 lguest: fix comme... |
219 220 |
/* * set_guest_interrupt() takes the interrupt descriptor and a |
bff672e63 lguest: documenta... |
221 |
* flag to say whether this interrupt pushes an error code onto |
2e04ef769 lguest: fix comme... |
222 223 |
* the stack as well: virtual interrupts never do. */ |
df1693abc lguest: use bool ... |
224 |
set_guest_interrupt(cpu, idt->a, idt->b, false); |
d7e28ffe6 lguest: the host ... |
225 |
} |
6c8dca5d5 Provide timespec ... |
226 |
|
2e04ef769 lguest: fix comme... |
227 228 |
/* * Every time we deliver an interrupt, we update the timestamp in the |
6c8dca5d5 Provide timespec ... |
229 230 231 |
* Guest's lguest_data struct. It would be better for the Guest if we * did this more often, but it can actually be quite slow: doing it * here is a compromise which means at least it gets updated every |
2e04ef769 lguest: fix comme... |
232 233 |
* timer interrupt. */ |
382ac6b3f lguest: get rid o... |
234 |
write_timestamp(cpu); |
a32a8813d lguest: improve i... |
235 |
|
2e04ef769 lguest: fix comme... |
236 237 238 239 |
/* * If there are no other interrupts we want to deliver, clear * the pending flag. */ |
a32a8813d lguest: improve i... |
240 241 |
if (!more) put_user(0, &cpu->lg->lguest_data->irq_pending); |
d7e28ffe6 lguest: the host ... |
242 |
} |
9f155a9b3 lguest: allow any... |
243 244 245 246 |
/* And this is the routine when we want to set an interrupt for the Guest. */ void set_interrupt(struct lg_cpu *cpu, unsigned int irq) { |
2e04ef769 lguest: fix comme... |
247 248 249 250 |
/* * Next time the Guest runs, the core code will see if it can deliver * this interrupt. */ |
9f155a9b3 lguest: allow any... |
251 |
set_bit(irq, cpu->irqs_pending); |
2e04ef769 lguest: fix comme... |
252 253 254 255 |
/* * Make sure it sees it; it might be asleep (eg. halted), or running * the Guest right now, in which case kick_process() will knock it out. */ |
9f155a9b3 lguest: allow any... |
256 257 258 |
if (!wake_up_process(cpu->tsk)) kick_process(cpu->tsk); } |
c18acd73f Allow guest to sp... |
259 |
/*:*/ |
2e04ef769 lguest: fix comme... |
260 261 |
/* * Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent |
c18acd73f Allow guest to sp... |
262 263 264 265 |
* me a patch, so we support that too. It'd be a big step for lguest if half * the Plan 9 user base were to start using it. * * Actually now I think of it, it's possible that Ron *is* half the Plan 9 |
2e04ef769 lguest: fix comme... |
266 267 |
* userbase. Oh well. */ |
c18acd73f Allow guest to sp... |
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
static bool could_be_syscall(unsigned int num) { /* Normal Linux SYSCALL_VECTOR or reserved vector? */ return num == SYSCALL_VECTOR || num == syscall_vector; } /* The syscall vector it wants must be unused by Host. */ bool check_syscall_vector(struct lguest *lg) { u32 vector; if (get_user(vector, &lg->lguest_data->syscall_vec)) return false; return could_be_syscall(vector); } int init_interrupts(void) { /* If they want some strange system call vector, reserve it now */ |
b77b881f2 x86: fix lguest u... |
288 289 290 291 292 293 294 295 296 |
if (syscall_vector != SYSCALL_VECTOR) { if (test_bit(syscall_vector, used_vectors) || vector_used_by_percpu_irq(syscall_vector)) { printk(KERN_ERR "lg: couldn't reserve syscall %u ", syscall_vector); return -EBUSY; } set_bit(syscall_vector, used_vectors); |
c18acd73f Allow guest to sp... |
297 |
} |
b77b881f2 x86: fix lguest u... |
298 |
|
c18acd73f Allow guest to sp... |
299 300 301 302 303 304 305 306 |
return 0; } void free_interrupts(void) { if (syscall_vector != SYSCALL_VECTOR) clear_bit(syscall_vector, used_vectors); } |
d7e28ffe6 lguest: the host ... |
307 |
|
2e04ef769 lguest: fix comme... |
308 309 |
/*H:220 * Now we've got the routines to deliver interrupts, delivering traps like |
a6bd8e130 lguest: comment d... |
310 |
* page fault is easy. The only trick is that Intel decided that some traps |
2e04ef769 lguest: fix comme... |
311 312 |
* should have error codes: */ |
df1693abc lguest: use bool ... |
313 |
static bool has_err(unsigned int trap) |
d7e28ffe6 lguest: the host ... |
314 315 316 |
{ return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17); } |
bff672e63 lguest: documenta... |
317 |
/* deliver_trap() returns true if it could deliver the trap. */ |
df1693abc lguest: use bool ... |
318 |
bool deliver_trap(struct lg_cpu *cpu, unsigned int num) |
d7e28ffe6 lguest: the host ... |
319 |
{ |
2e04ef769 lguest: fix comme... |
320 321 322 323 |
/* * Trap numbers are always 8 bit, but we set an impossible trap number * for traps inside the Switcher, so check that here. */ |
fc708b3e4 lguest: replace l... |
324 |
if (num >= ARRAY_SIZE(cpu->arch.idt)) |
df1693abc lguest: use bool ... |
325 |
return false; |
d7e28ffe6 lguest: the host ... |
326 |
|
2e04ef769 lguest: fix comme... |
327 328 329 330 |
/* * Early on the Guest hasn't set the IDT entries (or maybe it put a * bogus one in): if we fail here, the Guest will be killed. */ |
fc708b3e4 lguest: replace l... |
331 |
if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b)) |
df1693abc lguest: use bool ... |
332 |
return false; |
fc708b3e4 lguest: replace l... |
333 334 |
set_guest_interrupt(cpu, cpu->arch.idt[num].a, cpu->arch.idt[num].b, has_err(num)); |
df1693abc lguest: use bool ... |
335 |
return true; |
d7e28ffe6 lguest: the host ... |
336 |
} |
2e04ef769 lguest: fix comme... |
337 338 |
/*H:250 * Here's the hard part: returning to the Host every time a trap happens |
bff672e63 lguest: documenta... |
339 |
* and then calling deliver_trap() and re-entering the Guest is slow. |
e1e72965e lguest: documenta... |
340 341 |
* Particularly because Guest userspace system calls are traps (usually trap * 128). |
bff672e63 lguest: documenta... |
342 343 344 345 346 |
* * So we'd like to set up the IDT to tell the CPU to deliver traps directly * into the Guest. This is possible, but the complexities cause the size of * this file to double! However, 150 lines of code is worth writing for taking * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all |
e1e72965e lguest: documenta... |
347 |
* the other hypervisors would beat it up at lunchtime. |
bff672e63 lguest: documenta... |
348 |
* |
56adbe9dd Make shadow IDT a... |
349 |
* This routine indicates if a particular trap number could be delivered |
2e04ef769 lguest: fix comme... |
350 351 |
* directly. */ |
df1693abc lguest: use bool ... |
352 |
static bool direct_trap(unsigned int num) |
d7e28ffe6 lguest: the host ... |
353 |
{ |
2e04ef769 lguest: fix comme... |
354 355 356 357 |
/* * Hardware interrupts don't go to the Guest at all (except system * call). */ |
c18acd73f Allow guest to sp... |
358 |
if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num)) |
df1693abc lguest: use bool ... |
359 |
return false; |
d7e28ffe6 lguest: the host ... |
360 |
|
2e04ef769 lguest: fix comme... |
361 362 |
/* * The Host needs to see page faults (for shadow paging and to save the |
bff672e63 lguest: documenta... |
363 |
* fault address), general protection faults (in/out emulation) and |
6d7a5d1ea lguest: don't rew... |
364 |
* device not available (TS handling) and of course, the hypercall trap. |
2e04ef769 lguest: fix comme... |
365 |
*/ |
6d7a5d1ea lguest: don't rew... |
366 |
return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY; |
d7e28ffe6 lguest: the host ... |
367 |
} |
f56a384e9 lguest: documenta... |
368 |
/*:*/ |
2e04ef769 lguest: fix comme... |
369 370 |
/*M:005 * The Guest has the ability to turn its interrupt gates into trap gates, |
f56a384e9 lguest: documenta... |
371 372 373 |
* if it is careful. The Host will let trap gates can go directly to the * Guest, but the Guest needs the interrupts atomically disabled for an * interrupt gate. It can do this by pointing the trap gate at instructions |
2e04ef769 lguest: fix comme... |
374 375 |
* within noirq_start and noirq_end, where it can safely disable interrupts. */ |
f56a384e9 lguest: documenta... |
376 |
|
2e04ef769 lguest: fix comme... |
377 378 |
/*M:006 * The Guests do not use the sysenter (fast system call) instruction, |
f56a384e9 lguest: documenta... |
379 380 381 382 |
* because it's hardcoded to enter privilege level 0 and so can't go direct. * It's about twice as fast as the older "int 0x80" system call, so it might * still be worthwhile to handle it in the Switcher and lcall down to the * Guest. The sysenter semantics are hairy tho: search for that keyword in |
2e04ef769 lguest: fix comme... |
383 384 |
* entry.S :*/ |
d7e28ffe6 lguest: the host ... |
385 |
|
2e04ef769 lguest: fix comme... |
386 387 |
/*H:260 * When we make traps go directly into the Guest, we need to make sure |
bff672e63 lguest: documenta... |
388 389 390 391 392 |
* the kernel stack is valid (ie. mapped in the page tables). Otherwise, the * CPU trying to deliver the trap will fault while trying to push the interrupt * words on the stack: this is called a double fault, and it forces us to kill * the Guest. * |
2e04ef769 lguest: fix comme... |
393 394 |
* Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */ |
4665ac8e2 lguest: makes spe... |
395 |
void pin_stack_pages(struct lg_cpu *cpu) |
d7e28ffe6 lguest: the host ... |
396 397 |
{ unsigned int i; |
2e04ef769 lguest: fix comme... |
398 399 400 401 |
/* * Depending on the CONFIG_4KSTACKS option, the Guest can have one or * two pages of stack space. */ |
382ac6b3f lguest: get rid o... |
402 |
for (i = 0; i < cpu->lg->stack_pages; i++) |
2e04ef769 lguest: fix comme... |
403 404 |
/* * The stack grows *upwards*, so the address we're given is the |
8057d763e Fix lguest page-p... |
405 406 |
* start of the page after the kernel stack. Subtract one to * get back onto the first stack page, and keep subtracting to |
2e04ef769 lguest: fix comme... |
407 408 |
* get to the rest of the stack pages. */ |
1713608f2 lguest: per-vcpu ... |
409 |
pin_page(cpu, cpu->esp1 - 1 - i * PAGE_SIZE); |
d7e28ffe6 lguest: the host ... |
410 |
} |
2e04ef769 lguest: fix comme... |
411 412 |
/* * Direct traps also mean that we need to know whenever the Guest wants to use |
9f54288de lguest: update co... |
413 414 |
* a different kernel stack, so we can change the guest TSS to use that * stack. The TSS entries expect a virtual address, so unlike most addresses |
bff672e63 lguest: documenta... |
415 416 417 418 |
* the Guest gives us, the "esp" (stack pointer) value here is virtual, not * physical. * * In Linux each process has its own kernel stack, so this happens a lot: we |
2e04ef769 lguest: fix comme... |
419 420 |
* change stacks on each context switch. */ |
4665ac8e2 lguest: makes spe... |
421 |
void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages) |
d7e28ffe6 lguest: the host ... |
422 |
{ |
2e04ef769 lguest: fix comme... |
423 424 425 |
/* * You're not allowed a stack segment with privilege level 0: bad Guest! */ |
d7e28ffe6 lguest: the host ... |
426 |
if ((seg & 0x3) != GUEST_PL) |
382ac6b3f lguest: get rid o... |
427 |
kill_guest(cpu, "bad stack segment %i", seg); |
bff672e63 lguest: documenta... |
428 |
/* We only expect one or two stack pages. */ |
d7e28ffe6 lguest: the host ... |
429 |
if (pages > 2) |
382ac6b3f lguest: get rid o... |
430 |
kill_guest(cpu, "bad stack pages %u", pages); |
bff672e63 lguest: documenta... |
431 |
/* Save where the stack is, and how many pages */ |
4665ac8e2 lguest: makes spe... |
432 433 434 |
cpu->ss1 = seg; cpu->esp1 = esp; cpu->lg->stack_pages = pages; |
bff672e63 lguest: documenta... |
435 |
/* Make sure the new stack pages are mapped */ |
4665ac8e2 lguest: makes spe... |
436 |
pin_stack_pages(cpu); |
d7e28ffe6 lguest: the host ... |
437 |
} |
2e04ef769 lguest: fix comme... |
438 439 440 441 |
/* * All this reference to mapping stacks leads us neatly into the other complex * part of the Host: page table handling. */ |
bff672e63 lguest: documenta... |
442 |
|
2e04ef769 lguest: fix comme... |
443 444 445 446 |
/*H:235 * This is the routine which actually checks the Guest's IDT entry and * transfers it into the entry in "struct lguest": */ |
382ac6b3f lguest: get rid o... |
447 |
static void set_trap(struct lg_cpu *cpu, struct desc_struct *trap, |
d7e28ffe6 lguest: the host ... |
448 449 450 |
unsigned int num, u32 lo, u32 hi) { u8 type = idt_type(lo, hi); |
bff672e63 lguest: documenta... |
451 |
/* We zero-out a not-present entry */ |
d7e28ffe6 lguest: the host ... |
452 453 454 455 |
if (!idt_present(lo, hi)) { trap->a = trap->b = 0; return; } |
bff672e63 lguest: documenta... |
456 |
/* We only support interrupt and trap gates. */ |
d7e28ffe6 lguest: the host ... |
457 |
if (type != 0xE && type != 0xF) |
382ac6b3f lguest: get rid o... |
458 |
kill_guest(cpu, "bad IDT type %i", type); |
d7e28ffe6 lguest: the host ... |
459 |
|
2e04ef769 lguest: fix comme... |
460 461 |
/* * We only copy the handler address, present bit, privilege level and |
bff672e63 lguest: documenta... |
462 463 |
* type. The privilege level controls where the trap can be triggered * manually with an "int" instruction. This is usually GUEST_PL, |
2e04ef769 lguest: fix comme... |
464 465 |
* except for system calls which userspace can use. */ |
d7e28ffe6 lguest: the host ... |
466 467 468 |
trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF); trap->b = (hi&0xFFFFEF00); } |
2e04ef769 lguest: fix comme... |
469 470 |
/*H:230 * While we're here, dealing with delivering traps and interrupts to the |
bff672e63 lguest: documenta... |
471 472 473 474 475 |
* Guest, we might as well complete the picture: how the Guest tells us where * it wants them to go. This would be simple, except making traps fast * requires some tricks. * * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the |
2e04ef769 lguest: fix comme... |
476 477 |
* LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */ |
fc708b3e4 lguest: replace l... |
478 |
void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi) |
d7e28ffe6 lguest: the host ... |
479 |
{ |
2e04ef769 lguest: fix comme... |
480 481 482 483 |
/* * Guest never handles: NMI, doublefault, spurious interrupt or * hypercall. We ignore when it tries to set them. */ |
d7e28ffe6 lguest: the host ... |
484 485 |
if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY) return; |
2e04ef769 lguest: fix comme... |
486 487 488 489 |
/* * Mark the IDT as changed: next time the Guest runs we'll know we have * to copy this again. */ |
ae3749dcd lguest: move chan... |
490 |
cpu->changed |= CHANGED_IDT; |
bff672e63 lguest: documenta... |
491 |
|
56adbe9dd Make shadow IDT a... |
492 |
/* Check that the Guest doesn't try to step outside the bounds. */ |
fc708b3e4 lguest: replace l... |
493 |
if (num >= ARRAY_SIZE(cpu->arch.idt)) |
382ac6b3f lguest: get rid o... |
494 |
kill_guest(cpu, "Setting idt entry %u", num); |
56adbe9dd Make shadow IDT a... |
495 |
else |
382ac6b3f lguest: get rid o... |
496 |
set_trap(cpu, &cpu->arch.idt[num], num, lo, hi); |
d7e28ffe6 lguest: the host ... |
497 |
} |
2e04ef769 lguest: fix comme... |
498 499 |
/* * The default entry for each interrupt points into the Switcher routines which |
bff672e63 lguest: documenta... |
500 |
* simply return to the Host. The run_guest() loop will then call |
2e04ef769 lguest: fix comme... |
501 502 |
* deliver_trap() to bounce it back into the Guest. */ |
d7e28ffe6 lguest: the host ... |
503 504 |
static void default_idt_entry(struct desc_struct *idt, int trap, |
0c12091d8 lguest: Guest int... |
505 506 |
const unsigned long handler, const struct desc_struct *base) |
d7e28ffe6 lguest: the host ... |
507 |
{ |
bff672e63 lguest: documenta... |
508 |
/* A present interrupt gate. */ |
d7e28ffe6 lguest: the host ... |
509 |
u32 flags = 0x8e00; |
2e04ef769 lguest: fix comme... |
510 511 512 513 |
/* * Set the privilege level on the entry for the hypercall: this allows * the Guest to use the "int" instruction to trigger it. */ |
d7e28ffe6 lguest: the host ... |
514 515 |
if (trap == LGUEST_TRAP_ENTRY) flags |= (GUEST_PL << 13); |
0c12091d8 lguest: Guest int... |
516 |
else if (base) |
2e04ef769 lguest: fix comme... |
517 518 519 520 |
/* * Copy privilege level from what Guest asked for. This allows * debug (int 3) traps from Guest userspace, for example. */ |
0c12091d8 lguest: Guest int... |
521 |
flags |= (base->b & 0x6000); |
d7e28ffe6 lguest: the host ... |
522 |
|
bff672e63 lguest: documenta... |
523 |
/* Now pack it into the IDT entry in its weird format. */ |
d7e28ffe6 lguest: the host ... |
524 525 526 |
idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); idt->b = (handler&0xFFFF0000) | flags; } |
bff672e63 lguest: documenta... |
527 |
/* When the Guest first starts, we put default entries into the IDT. */ |
d7e28ffe6 lguest: the host ... |
528 529 530 531 532 533 |
void setup_default_idt_entries(struct lguest_ro_state *state, const unsigned long *def) { unsigned int i; for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) |
0c12091d8 lguest: Guest int... |
534 |
default_idt_entry(&state->guest_idt[i], i, def[i], NULL); |
d7e28ffe6 lguest: the host ... |
535 |
} |
2e04ef769 lguest: fix comme... |
536 537 |
/*H:240 * We don't use the IDT entries in the "struct lguest" directly, instead |
bff672e63 lguest: documenta... |
538 |
* we copy them into the IDT which we've set up for Guests on this CPU, just |
2e04ef769 lguest: fix comme... |
539 540 |
* before we run the Guest. This routine does that copy. */ |
fc708b3e4 lguest: replace l... |
541 |
void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, |
d7e28ffe6 lguest: the host ... |
542 543 544 |
const unsigned long *def) { unsigned int i; |
2e04ef769 lguest: fix comme... |
545 546 547 548 |
/* * We can simply copy the direct traps, otherwise we use the default * ones in the Switcher: they will return to the Host. */ |
fc708b3e4 lguest: replace l... |
549 |
for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { |
0c12091d8 lguest: Guest int... |
550 |
const struct desc_struct *gidt = &cpu->arch.idt[i]; |
56adbe9dd Make shadow IDT a... |
551 552 553 |
/* If no Guest can ever override this trap, leave it alone. */ if (!direct_trap(i)) continue; |
2e04ef769 lguest: fix comme... |
554 555 |
/* * Only trap gates (type 15) can go direct to the Guest. |
56adbe9dd Make shadow IDT a... |
556 557 |
* Interrupt gates (type 14) disable interrupts as they are * entered, which we never let the Guest do. Not present |
0c12091d8 lguest: Guest int... |
558 559 560 561 |
* entries (type 0x0) also can't go direct, of course. * * If it can't go direct, we still need to copy the priv. level: * they might want to give userspace access to a software |
2e04ef769 lguest: fix comme... |
562 563 |
* interrupt. */ |
0c12091d8 lguest: Guest int... |
564 565 |
if (idt_type(gidt->a, gidt->b) == 0xF) idt[i] = *gidt; |
d7e28ffe6 lguest: the host ... |
566 |
else |
0c12091d8 lguest: Guest int... |
567 |
default_idt_entry(&idt[i], i, def[i], gidt); |
d7e28ffe6 lguest: the host ... |
568 |
} |
d7e28ffe6 lguest: the host ... |
569 |
} |
e1e72965e lguest: documenta... |
570 571 572 573 574 575 576 577 578 579 580 |
/*H:200 * The Guest Clock. * * There are two sources of virtual interrupts. We saw one in lguest_user.c: * the Launcher sending interrupts for virtual devices. The other is the Guest * timer interrupt. * * The Guest uses the LHCALL_SET_CLOCKEVENT hypercall to tell us how long to * the next timer interrupt (in nanoseconds). We use the high-resolution timer * infrastructure to set a callback at that time. * |
2e04ef769 lguest: fix comme... |
581 582 |
* 0 means "turn off the clock". */ |
ad8d8f3bc lguest: per-vcpu ... |
583 |
void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta) |
d7e28ffe6 lguest: the host ... |
584 585 586 587 588 |
{ ktime_t expires; if (unlikely(delta == 0)) { /* Clock event device is shutting down. */ |
ad8d8f3bc lguest: per-vcpu ... |
589 |
hrtimer_cancel(&cpu->hrt); |
d7e28ffe6 lguest: the host ... |
590 591 |
return; } |
2e04ef769 lguest: fix comme... |
592 593 |
/* * We use wallclock time here, so the Guest might not be running for |
e1e72965e lguest: documenta... |
594 |
* all the time between now and the timer interrupt it asked for. This |
2e04ef769 lguest: fix comme... |
595 596 |
* is almost always the right thing to do. */ |
d7e28ffe6 lguest: the host ... |
597 |
expires = ktime_add_ns(ktime_get_real(), delta); |
ad8d8f3bc lguest: per-vcpu ... |
598 |
hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS); |
d7e28ffe6 lguest: the host ... |
599 |
} |
e1e72965e lguest: documenta... |
600 |
/* This is the function called when the Guest's timer expires. */ |
d7e28ffe6 lguest: the host ... |
601 602 |
static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) { |
ad8d8f3bc lguest: per-vcpu ... |
603 |
struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt); |
d7e28ffe6 lguest: the host ... |
604 |
|
e1e72965e lguest: documenta... |
605 |
/* Remember the first interrupt is the timer interrupt. */ |
9f155a9b3 lguest: allow any... |
606 |
set_interrupt(cpu, 0); |
d7e28ffe6 lguest: the host ... |
607 608 |
return HRTIMER_NORESTART; } |
e1e72965e lguest: documenta... |
609 |
/* This sets up the timer for this Guest. */ |
ad8d8f3bc lguest: per-vcpu ... |
610 |
void init_clockdev(struct lg_cpu *cpu) |
d7e28ffe6 lguest: the host ... |
611 |
{ |
ad8d8f3bc lguest: per-vcpu ... |
612 613 |
hrtimer_init(&cpu->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); cpu->hrt.function = clockdev_fn; |
d7e28ffe6 lguest: the host ... |
614 |
} |