Commit | Line | Data |
---|---|---|
d7e28ffe RR |
1 | #include <linux/uaccess.h> |
2 | #include "lg.h" | |
3 | ||
4 | static unsigned long idt_address(u32 lo, u32 hi) | |
5 | { | |
6 | return (lo & 0x0000FFFF) | (hi & 0xFFFF0000); | |
7 | } | |
8 | ||
9 | static int idt_type(u32 lo, u32 hi) | |
10 | { | |
11 | return (hi >> 8) & 0xF; | |
12 | } | |
13 | ||
14 | static int idt_present(u32 lo, u32 hi) | |
15 | { | |
16 | return (hi & 0x8000); | |
17 | } | |
18 | ||
19 | static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) | |
20 | { | |
21 | *gstack -= 4; | |
22 | lgwrite_u32(lg, *gstack, val); | |
23 | } | |
24 | ||
25 | static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |
26 | { | |
27 | unsigned long gstack; | |
28 | u32 eflags, ss, irq_enable; | |
29 | ||
30 | /* If they want a ring change, we use new stack and push old ss/esp */ | |
31 | if ((lg->regs->ss&0x3) != GUEST_PL) { | |
32 | gstack = guest_pa(lg, lg->esp1); | |
33 | ss = lg->ss1; | |
34 | push_guest_stack(lg, &gstack, lg->regs->ss); | |
35 | push_guest_stack(lg, &gstack, lg->regs->esp); | |
36 | } else { | |
37 | gstack = guest_pa(lg, lg->regs->esp); | |
38 | ss = lg->regs->ss; | |
39 | } | |
40 | ||
41 | /* We use IF bit in eflags to indicate whether irqs were disabled | |
42 | (it's always 0, since irqs are enabled when guest is running). */ | |
43 | eflags = lg->regs->eflags; | |
44 | if (get_user(irq_enable, &lg->lguest_data->irq_enabled)) | |
45 | irq_enable = 0; | |
46 | eflags |= (irq_enable & X86_EFLAGS_IF); | |
47 | ||
48 | push_guest_stack(lg, &gstack, eflags); | |
49 | push_guest_stack(lg, &gstack, lg->regs->cs); | |
50 | push_guest_stack(lg, &gstack, lg->regs->eip); | |
51 | ||
52 | if (has_err) | |
53 | push_guest_stack(lg, &gstack, lg->regs->errcode); | |
54 | ||
55 | /* Change the real stack so switcher returns to trap handler */ | |
56 | lg->regs->ss = ss; | |
57 | lg->regs->esp = gstack + lg->page_offset; | |
58 | lg->regs->cs = (__KERNEL_CS|GUEST_PL); | |
59 | lg->regs->eip = idt_address(lo, hi); | |
60 | ||
61 | /* Disable interrupts for an interrupt gate. */ | |
62 | if (idt_type(lo, hi) == 0xE) | |
63 | if (put_user(0, &lg->lguest_data->irq_enabled)) | |
64 | kill_guest(lg, "Disabling interrupts"); | |
65 | } | |
66 | ||
67 | void maybe_do_interrupt(struct lguest *lg) | |
68 | { | |
69 | unsigned int irq; | |
70 | DECLARE_BITMAP(blk, LGUEST_IRQS); | |
71 | struct desc_struct *idt; | |
72 | ||
73 | if (!lg->lguest_data) | |
74 | return; | |
75 | ||
76 | /* Mask out any interrupts they have blocked. */ | |
77 | if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts, | |
78 | sizeof(blk))) | |
79 | return; | |
80 | ||
81 | bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS); | |
82 | ||
83 | irq = find_first_bit(blk, LGUEST_IRQS); | |
84 | if (irq >= LGUEST_IRQS) | |
85 | return; | |
86 | ||
87 | if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end) | |
88 | return; | |
89 | ||
90 | /* If they're halted, we re-enable interrupts. */ | |
91 | if (lg->halted) { | |
92 | /* Re-enable interrupts. */ | |
93 | if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled)) | |
94 | kill_guest(lg, "Re-enabling interrupts"); | |
95 | lg->halted = 0; | |
96 | } else { | |
97 | /* Maybe they have interrupts disabled? */ | |
98 | u32 irq_enabled; | |
99 | if (get_user(irq_enabled, &lg->lguest_data->irq_enabled)) | |
100 | irq_enabled = 0; | |
101 | if (!irq_enabled) | |
102 | return; | |
103 | } | |
104 | ||
105 | idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq]; | |
106 | if (idt_present(idt->a, idt->b)) { | |
107 | clear_bit(irq, lg->irqs_pending); | |
108 | set_guest_interrupt(lg, idt->a, idt->b, 0); | |
109 | } | |
110 | } | |
111 | ||
112 | static int has_err(unsigned int trap) | |
113 | { | |
114 | return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17); | |
115 | } | |
116 | ||
117 | int deliver_trap(struct lguest *lg, unsigned int num) | |
118 | { | |
119 | u32 lo = lg->idt[num].a, hi = lg->idt[num].b; | |
120 | ||
121 | if (!idt_present(lo, hi)) | |
122 | return 0; | |
123 | set_guest_interrupt(lg, lo, hi, has_err(num)); | |
124 | return 1; | |
125 | } | |
126 | ||
127 | static int direct_trap(const struct lguest *lg, | |
128 | const struct desc_struct *trap, | |
129 | unsigned int num) | |
130 | { | |
131 | /* Hardware interrupts don't go to guest (except syscall). */ | |
132 | if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR) | |
133 | return 0; | |
134 | ||
135 | /* We intercept page fault (demand shadow paging & cr2 saving) | |
136 | protection fault (in/out emulation) and device not | |
137 | available (TS handling), and hypercall */ | |
138 | if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY) | |
139 | return 0; | |
140 | ||
141 | /* Interrupt gates (0xE) or not present (0x0) can't go direct. */ | |
142 | return idt_type(trap->a, trap->b) == 0xF; | |
143 | } | |
144 | ||
145 | void pin_stack_pages(struct lguest *lg) | |
146 | { | |
147 | unsigned int i; | |
148 | ||
149 | for (i = 0; i < lg->stack_pages; i++) | |
150 | pin_page(lg, lg->esp1 - i * PAGE_SIZE); | |
151 | } | |
152 | ||
153 | void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) | |
154 | { | |
155 | /* You cannot have a stack segment with priv level 0. */ | |
156 | if ((seg & 0x3) != GUEST_PL) | |
157 | kill_guest(lg, "bad stack segment %i", seg); | |
158 | if (pages > 2) | |
159 | kill_guest(lg, "bad stack pages %u", pages); | |
160 | lg->ss1 = seg; | |
161 | lg->esp1 = esp; | |
162 | lg->stack_pages = pages; | |
163 | pin_stack_pages(lg); | |
164 | } | |
165 | ||
166 | /* Set up trap in IDT. */ | |
167 | static void set_trap(struct lguest *lg, struct desc_struct *trap, | |
168 | unsigned int num, u32 lo, u32 hi) | |
169 | { | |
170 | u8 type = idt_type(lo, hi); | |
171 | ||
172 | if (!idt_present(lo, hi)) { | |
173 | trap->a = trap->b = 0; | |
174 | return; | |
175 | } | |
176 | ||
177 | if (type != 0xE && type != 0xF) | |
178 | kill_guest(lg, "bad IDT type %i", type); | |
179 | ||
180 | trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF); | |
181 | trap->b = (hi&0xFFFFEF00); | |
182 | } | |
183 | ||
184 | void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) | |
185 | { | |
186 | /* Guest never handles: NMI, doublefault, hypercall, spurious irq. */ | |
187 | if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY) | |
188 | return; | |
189 | ||
190 | lg->changed |= CHANGED_IDT; | |
191 | if (num < ARRAY_SIZE(lg->idt)) | |
192 | set_trap(lg, &lg->idt[num], num, lo, hi); | |
193 | else if (num == SYSCALL_VECTOR) | |
194 | set_trap(lg, &lg->syscall_idt, num, lo, hi); | |
195 | } | |
196 | ||
197 | static void default_idt_entry(struct desc_struct *idt, | |
198 | int trap, | |
199 | const unsigned long handler) | |
200 | { | |
201 | u32 flags = 0x8e00; | |
202 | ||
203 | /* They can't "int" into any of them except hypercall. */ | |
204 | if (trap == LGUEST_TRAP_ENTRY) | |
205 | flags |= (GUEST_PL << 13); | |
206 | ||
207 | idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF); | |
208 | idt->b = (handler&0xFFFF0000) | flags; | |
209 | } | |
210 | ||
211 | void setup_default_idt_entries(struct lguest_ro_state *state, | |
212 | const unsigned long *def) | |
213 | { | |
214 | unsigned int i; | |
215 | ||
216 | for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++) | |
217 | default_idt_entry(&state->guest_idt[i], i, def[i]); | |
218 | } | |
219 | ||
220 | void copy_traps(const struct lguest *lg, struct desc_struct *idt, | |
221 | const unsigned long *def) | |
222 | { | |
223 | unsigned int i; | |
224 | ||
225 | /* All hardware interrupts are same whatever the guest: only the | |
226 | * traps might be different. */ | |
227 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) { | |
228 | if (direct_trap(lg, &lg->idt[i], i)) | |
229 | idt[i] = lg->idt[i]; | |
230 | else | |
231 | default_idt_entry(&idt[i], i, def[i]); | |
232 | } | |
233 | i = SYSCALL_VECTOR; | |
234 | if (direct_trap(lg, &lg->syscall_idt, i)) | |
235 | idt[i] = lg->syscall_idt; | |
236 | else | |
237 | default_idt_entry(&idt[i], i, def[i]); | |
238 | } | |
239 | ||
240 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) | |
241 | { | |
242 | ktime_t expires; | |
243 | ||
244 | if (unlikely(delta == 0)) { | |
245 | /* Clock event device is shutting down. */ | |
246 | hrtimer_cancel(&lg->hrt); | |
247 | return; | |
248 | } | |
249 | ||
250 | expires = ktime_add_ns(ktime_get_real(), delta); | |
251 | hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); | |
252 | } | |
253 | ||
254 | static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) | |
255 | { | |
256 | struct lguest *lg = container_of(timer, struct lguest, hrt); | |
257 | ||
258 | set_bit(0, lg->irqs_pending); | |
259 | if (lg->halted) | |
260 | wake_up_process(lg->tsk); | |
261 | return HRTIMER_NORESTART; | |
262 | } | |
263 | ||
264 | void init_clockdev(struct lguest *lg) | |
265 | { | |
266 | hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); | |
267 | lg->hrt.function = clockdev_fn; | |
268 | } |