diff options
Diffstat (limited to 'drivers/lguest/hypercalls.c')
-rw-r--r-- | drivers/lguest/hypercalls.c | 177 |
1 files changed, 58 insertions, 119 deletions
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index db6caace3b9c..9d5184c7c14a 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c | |||
@@ -25,17 +25,13 @@ | |||
25 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
26 | #include <asm/page.h> | 26 | #include <asm/page.h> |
27 | #include <asm/pgtable.h> | 27 | #include <asm/pgtable.h> |
28 | #include <irq_vectors.h> | ||
29 | #include "lg.h" | 28 | #include "lg.h" |
30 | 29 | ||
31 | /*H:120 This is the core hypercall routine: where the Guest gets what it | 30 | /*H:120 This is the core hypercall routine: where the Guest gets what it wants. |
32 | * wants. Or gets killed. Or, in the case of LHCALL_CRASH, both. | 31 | * Or gets killed. Or, in the case of LHCALL_CRASH, both. */ |
33 | * | 32 | static void do_hcall(struct lguest *lg, struct hcall_args *args) |
34 | * Remember from the Guest: %eax == which call to make, and the arguments are | ||
35 | * packed into %edx, %ebx and %ecx if needed. */ | ||
36 | static void do_hcall(struct lguest *lg, struct lguest_regs *regs) | ||
37 | { | 33 | { |
38 | switch (regs->eax) { | 34 | switch (args->arg0) { |
39 | case LHCALL_FLUSH_ASYNC: | 35 | case LHCALL_FLUSH_ASYNC: |
40 | /* This call does nothing, except by breaking out of the Guest | 36 | /* This call does nothing, except by breaking out of the Guest |
41 | * it makes us process all the asynchronous hypercalls. */ | 37 | * it makes us process all the asynchronous hypercalls. */ |
@@ -51,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs) | |||
51 | char msg[128]; | 47 | char msg[128]; |
52 | /* If the lgread fails, it will call kill_guest() itself; the | 48 | /* If the lgread fails, it will call kill_guest() itself; the |
53 | * kill_guest() with the message will be ignored. */ | 49 | * kill_guest() with the message will be ignored. */ |
54 | lgread(lg, msg, regs->edx, sizeof(msg)); | 50 | __lgread(lg, msg, args->arg1, sizeof(msg)); |
55 | msg[sizeof(msg)-1] = '\0'; | 51 | msg[sizeof(msg)-1] = '\0'; |
56 | kill_guest(lg, "CRASH: %s", msg); | 52 | kill_guest(lg, "CRASH: %s", msg); |
57 | break; | 53 | break; |
@@ -59,67 +55,49 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs) | |||
59 | case LHCALL_FLUSH_TLB: | 55 | case LHCALL_FLUSH_TLB: |
60 | /* FLUSH_TLB comes in two flavors, depending on the | 56 | /* FLUSH_TLB comes in two flavors, depending on the |
61 | * argument: */ | 57 | * argument: */ |
62 | if (regs->edx) | 58 | if (args->arg1) |
63 | guest_pagetable_clear_all(lg); | 59 | guest_pagetable_clear_all(lg); |
64 | else | 60 | else |
65 | guest_pagetable_flush_user(lg); | 61 | guest_pagetable_flush_user(lg); |
66 | break; | 62 | break; |
67 | case LHCALL_BIND_DMA: | ||
68 | /* BIND_DMA really wants four arguments, but it's the only call | ||
69 | * which does. So the Guest packs the number of buffers and | ||
70 | * the interrupt number into the final argument, and we decode | ||
71 | * it here. This can legitimately fail, since we currently | ||
72 | * place a limit on the number of DMA pools a Guest can have. | ||
73 | * So we return true or false from this call. */ | ||
74 | regs->eax = bind_dma(lg, regs->edx, regs->ebx, | ||
75 | regs->ecx >> 8, regs->ecx & 0xFF); | ||
76 | break; | ||
77 | 63 | ||
78 | /* All these calls simply pass the arguments through to the right | 64 | /* All these calls simply pass the arguments through to the right |
79 | * routines. */ | 65 | * routines. */ |
80 | case LHCALL_SEND_DMA: | ||
81 | send_dma(lg, regs->edx, regs->ebx); | ||
82 | break; | ||
83 | case LHCALL_LOAD_GDT: | ||
84 | load_guest_gdt(lg, regs->edx, regs->ebx); | ||
85 | break; | ||
86 | case LHCALL_LOAD_IDT_ENTRY: | ||
87 | load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx); | ||
88 | break; | ||
89 | case LHCALL_NEW_PGTABLE: | 66 | case LHCALL_NEW_PGTABLE: |
90 | guest_new_pagetable(lg, regs->edx); | 67 | guest_new_pagetable(lg, args->arg1); |
91 | break; | 68 | break; |
92 | case LHCALL_SET_STACK: | 69 | case LHCALL_SET_STACK: |
93 | guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx); | 70 | guest_set_stack(lg, args->arg1, args->arg2, args->arg3); |
94 | break; | 71 | break; |
95 | case LHCALL_SET_PTE: | 72 | case LHCALL_SET_PTE: |
96 | guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx)); | 73 | guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3)); |
97 | break; | 74 | break; |
98 | case LHCALL_SET_PMD: | 75 | case LHCALL_SET_PMD: |
99 | guest_set_pmd(lg, regs->edx, regs->ebx); | 76 | guest_set_pmd(lg, args->arg1, args->arg2); |
100 | break; | ||
101 | case LHCALL_LOAD_TLS: | ||
102 | guest_load_tls(lg, regs->edx); | ||
103 | break; | 77 | break; |
104 | case LHCALL_SET_CLOCKEVENT: | 78 | case LHCALL_SET_CLOCKEVENT: |
105 | guest_set_clockevent(lg, regs->edx); | 79 | guest_set_clockevent(lg, args->arg1); |
106 | break; | 80 | break; |
107 | |||
108 | case LHCALL_TS: | 81 | case LHCALL_TS: |
109 | /* This sets the TS flag, as we saw used in run_guest(). */ | 82 | /* This sets the TS flag, as we saw used in run_guest(). */ |
110 | lg->ts = regs->edx; | 83 | lg->ts = args->arg1; |
111 | break; | 84 | break; |
112 | case LHCALL_HALT: | 85 | case LHCALL_HALT: |
113 | /* Similarly, this sets the halted flag for run_guest(). */ | 86 | /* Similarly, this sets the halted flag for run_guest(). */ |
114 | lg->halted = 1; | 87 | lg->halted = 1; |
115 | break; | 88 | break; |
89 | case LHCALL_NOTIFY: | ||
90 | lg->pending_notify = args->arg1; | ||
91 | break; | ||
116 | default: | 92 | default: |
117 | kill_guest(lg, "Bad hypercall %li\n", regs->eax); | 93 | if (lguest_arch_do_hcall(lg, args)) |
94 | kill_guest(lg, "Bad hypercall %li\n", args->arg0); | ||
118 | } | 95 | } |
119 | } | 96 | } |
97 | /*:*/ | ||
120 | 98 | ||
121 | /* Asynchronous hypercalls are easy: we just look in the array in the Guest's | 99 | /*H:124 Asynchronous hypercalls are easy: we just look in the array in the |
122 | * "struct lguest_data" and see if there are any new ones marked "ready". | 100 | * Guest's "struct lguest_data" to see if any new ones are marked "ready". |
123 | * | 101 | * |
124 | * We are careful to do these in order: obviously we respect the order the | 102 | * We are careful to do these in order: obviously we respect the order the |
125 | * Guest put them in the ring, but we also promise the Guest that they will | 103 | * Guest put them in the ring, but we also promise the Guest that they will |
@@ -134,10 +112,9 @@ static void do_async_hcalls(struct lguest *lg) | |||
134 | if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) | 112 | if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) |
135 | return; | 113 | return; |
136 | 114 | ||
137 | |||
138 | /* We process "struct lguest_data"s hcalls[] ring once. */ | 115 | /* We process "struct lguest_data"s hcalls[] ring once. */ |
139 | for (i = 0; i < ARRAY_SIZE(st); i++) { | 116 | for (i = 0; i < ARRAY_SIZE(st); i++) { |
140 | struct lguest_regs regs; | 117 | struct hcall_args args; |
141 | /* We remember where we were up to from last time. This makes | 118 | /* We remember where we were up to from last time. This makes |
142 | * sure that the hypercalls are done in the order the Guest | 119 | * sure that the hypercalls are done in the order the Guest |
143 | * places them in the ring. */ | 120 | * places them in the ring. */ |
@@ -152,18 +129,16 @@ static void do_async_hcalls(struct lguest *lg) | |||
152 | if (++lg->next_hcall == LHCALL_RING_SIZE) | 129 | if (++lg->next_hcall == LHCALL_RING_SIZE) |
153 | lg->next_hcall = 0; | 130 | lg->next_hcall = 0; |
154 | 131 | ||
155 | /* We copy the hypercall arguments into a fake register | 132 | /* Copy the hypercall arguments into a local copy of |
156 | * structure. This makes life simple for do_hcall(). */ | 133 | * the hcall_args struct. */ |
157 | if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax) | 134 | if (copy_from_user(&args, &lg->lguest_data->hcalls[n], |
158 | || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx) | 135 | sizeof(struct hcall_args))) { |
159 | || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx) | ||
160 | || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) { | ||
161 | kill_guest(lg, "Fetching async hypercalls"); | 136 | kill_guest(lg, "Fetching async hypercalls"); |
162 | break; | 137 | break; |
163 | } | 138 | } |
164 | 139 | ||
165 | /* Do the hypercall, same as a normal one. */ | 140 | /* Do the hypercall, same as a normal one. */ |
166 | do_hcall(lg, ®s); | 141 | do_hcall(lg, &args); |
167 | 142 | ||
168 | /* Mark the hypercall done. */ | 143 | /* Mark the hypercall done. */ |
169 | if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { | 144 | if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { |
@@ -171,9 +146,9 @@ static void do_async_hcalls(struct lguest *lg) | |||
171 | break; | 146 | break; |
172 | } | 147 | } |
173 | 148 | ||
174 | /* Stop doing hypercalls if we've just done a DMA to the | 149 | /* Stop doing hypercalls if they want to notify the Launcher: |
175 | * Launcher: it needs to service this first. */ | 150 | * it needs to service this first. */ |
176 | if (lg->dma_is_pending) | 151 | if (lg->pending_notify) |
177 | break; | 152 | break; |
178 | } | 153 | } |
179 | } | 154 | } |
@@ -182,76 +157,35 @@ static void do_async_hcalls(struct lguest *lg) | |||
182 | * Guest makes a hypercall, we end up here to set things up: */ | 157 | * Guest makes a hypercall, we end up here to set things up: */ |
183 | static void initialize(struct lguest *lg) | 158 | static void initialize(struct lguest *lg) |
184 | { | 159 | { |
185 | u32 tsc_speed; | ||
186 | 160 | ||
187 | /* You can't do anything until you're initialized. The Guest knows the | 161 | /* You can't do anything until you're initialized. The Guest knows the |
188 | * rules, so we're unforgiving here. */ | 162 | * rules, so we're unforgiving here. */ |
189 | if (lg->regs->eax != LHCALL_LGUEST_INIT) { | 163 | if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) { |
190 | kill_guest(lg, "hypercall %li before LGUEST_INIT", | 164 | kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0); |
191 | lg->regs->eax); | ||
192 | return; | 165 | return; |
193 | } | 166 | } |
194 | 167 | ||
195 | /* We insist that the Time Stamp Counter exist and doesn't change with | 168 | if (lguest_arch_init_hypercalls(lg)) |
196 | * cpu frequency. Some devious chip manufacturers decided that TSC | ||
197 | * changes could be handled in software. I decided that time going | ||
198 | * backwards might be good for benchmarks, but it's bad for users. | ||
199 | * | ||
200 | * We also insist that the TSC be stable: the kernel detects unreliable | ||
201 | * TSCs for its own purposes, and we use that here. */ | ||
202 | if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable()) | ||
203 | tsc_speed = tsc_khz; | ||
204 | else | ||
205 | tsc_speed = 0; | ||
206 | |||
207 | /* The pointer to the Guest's "struct lguest_data" is the only | ||
208 | * argument. */ | ||
209 | lg->lguest_data = (struct lguest_data __user *)lg->regs->edx; | ||
210 | /* If we check the address they gave is OK now, we can simply | ||
211 | * copy_to_user/from_user from now on rather than using lgread/lgwrite. | ||
212 | * I put this in to show that I'm not immune to writing stupid | ||
213 | * optimizations. */ | ||
214 | if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) { | ||
215 | kill_guest(lg, "bad guest page %p", lg->lguest_data); | 169 | kill_guest(lg, "bad guest page %p", lg->lguest_data); |
216 | return; | 170 | |
217 | } | ||
218 | /* The Guest tells us where we're not to deliver interrupts by putting | 171 | /* The Guest tells us where we're not to deliver interrupts by putting |
219 | * the range of addresses into "struct lguest_data". */ | 172 | * the range of addresses into "struct lguest_data". */ |
220 | if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) | 173 | if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) |
221 | || get_user(lg->noirq_end, &lg->lguest_data->noirq_end) | 174 | || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)) |
222 | /* We tell the Guest that it can't use the top 4MB of virtual | ||
223 | * addresses used by the Switcher. */ | ||
224 | || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem) | ||
225 | || put_user(tsc_speed, &lg->lguest_data->tsc_khz) | ||
226 | /* We also give the Guest a unique id, as used in lguest_net.c. */ | ||
227 | || put_user(lg->guestid, &lg->lguest_data->guestid)) | ||
228 | kill_guest(lg, "bad guest page %p", lg->lguest_data); | 175 | kill_guest(lg, "bad guest page %p", lg->lguest_data); |
229 | 176 | ||
230 | /* We write the current time into the Guest's data page once now. */ | 177 | /* We write the current time into the Guest's data page once now. */ |
231 | write_timestamp(lg); | 178 | write_timestamp(lg); |
232 | 179 | ||
180 | /* page_tables.c will also do some setup. */ | ||
181 | page_table_guest_data_init(lg); | ||
182 | |||
233 | /* This is the one case where the above accesses might have been the | 183 | /* This is the one case where the above accesses might have been the |
234 | * first write to a Guest page. This may have caused a copy-on-write | 184 | * first write to a Guest page. This may have caused a copy-on-write |
235 | * fault, but the Guest might be referring to the old (read-only) | 185 | * fault, but the Guest might be referring to the old (read-only) |
236 | * page. */ | 186 | * page. */ |
237 | guest_pagetable_clear_all(lg); | 187 | guest_pagetable_clear_all(lg); |
238 | } | 188 | } |
239 | /* Now we've examined the hypercall code; our Guest can make requests. There | ||
240 | * is one other way we can do things for the Guest, as we see in | ||
241 | * emulate_insn(). */ | ||
242 | |||
243 | /*H:110 Tricky point: we mark the hypercall as "done" once we've done it. | ||
244 | * Normally we don't need to do this: the Guest will run again and update the | ||
245 | * trap number before we come back around the run_guest() loop to | ||
246 | * do_hypercalls(). | ||
247 | * | ||
248 | * However, if we are signalled or the Guest sends DMA to the Launcher, that | ||
249 | * loop will exit without running the Guest. When it comes back it would try | ||
250 | * to re-run the hypercall. */ | ||
251 | static void clear_hcall(struct lguest *lg) | ||
252 | { | ||
253 | lg->regs->trapnum = 255; | ||
254 | } | ||
255 | 189 | ||
256 | /*H:100 | 190 | /*H:100 |
257 | * Hypercalls | 191 | * Hypercalls |
@@ -261,16 +195,12 @@ static void clear_hcall(struct lguest *lg) | |||
261 | */ | 195 | */ |
262 | void do_hypercalls(struct lguest *lg) | 196 | void do_hypercalls(struct lguest *lg) |
263 | { | 197 | { |
264 | /* Not initialized yet? */ | 198 | /* Not initialized yet? This hypercall must do it. */ |
265 | if (unlikely(!lg->lguest_data)) { | 199 | if (unlikely(!lg->lguest_data)) { |
266 | /* Did the Guest make a hypercall? We might have come back for | 200 | /* Set up the "struct lguest_data" */ |
267 | * some other reason (an interrupt, a different trap). */ | 201 | initialize(lg); |
268 | if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) { | 202 | /* Hcall is done. */ |
269 | /* Set up the "struct lguest_data" */ | 203 | lg->hcall = NULL; |
270 | initialize(lg); | ||
271 | /* The hypercall is done. */ | ||
272 | clear_hcall(lg); | ||
273 | } | ||
274 | return; | 204 | return; |
275 | } | 205 | } |
276 | 206 | ||
@@ -280,12 +210,21 @@ void do_hypercalls(struct lguest *lg) | |||
280 | do_async_hcalls(lg); | 210 | do_async_hcalls(lg); |
281 | 211 | ||
282 | /* If we stopped reading the hypercall ring because the Guest did a | 212 | /* If we stopped reading the hypercall ring because the Guest did a |
283 | * SEND_DMA to the Launcher, we want to return now. Otherwise if the | 213 | * NOTIFY to the Launcher, we want to return now. Otherwise we do |
284 | * Guest asked us to do a hypercall, we do it. */ | 214 | * the hypercall. */ |
285 | if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) { | 215 | if (!lg->pending_notify) { |
286 | do_hcall(lg, lg->regs); | 216 | do_hcall(lg, lg->hcall); |
287 | /* The hypercall is done. */ | 217 | /* Tricky point: we reset the hcall pointer to mark the |
288 | clear_hcall(lg); | 218 | * hypercall as "done". We use the hcall pointer rather than |
219 | * the trap number to indicate a hypercall is pending. | ||
220 | * Normally it doesn't matter: the Guest will run again and | ||
221 | * update the trap number before we come back here. | ||
222 | * | ||
223 | * However, if we are signalled or the Guest sends DMA to the | ||
224 | * Launcher, the run_guest() loop will exit without running the | ||
225 | * Guest. When it comes back it would try to re-run the | ||
226 | * hypercall. */ | ||
227 | lg->hcall = NULL; | ||
289 | } | 228 | } |
290 | } | 229 | } |
291 | 230 | ||
@@ -295,6 +234,6 @@ void write_timestamp(struct lguest *lg) | |||
295 | { | 234 | { |
296 | struct timespec now; | 235 | struct timespec now; |
297 | ktime_get_real_ts(&now); | 236 | ktime_get_real_ts(&now); |
298 | if (put_user(now, &lg->lguest_data->time)) | 237 | if (copy_to_user(&lg->lguest_data->time, &now, sizeof(struct timespec))) |
299 | kill_guest(lg, "Writing timestamp"); | 238 | kill_guest(lg, "Writing timestamp"); |
300 | } | 239 | } |