diff options
| -rw-r--r-- | arch/x86/lguest/boot.c | 1 | ||||
| -rw-r--r-- | drivers/lguest/core.c | 30 | ||||
| -rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 49 | ||||
| -rw-r--r-- | drivers/lguest/lg.h | 3 | ||||
| -rw-r--r-- | drivers/lguest/x86/core.c | 4 | ||||
| -rw-r--r-- | include/linux/lguest.h | 3 |
6 files changed, 79 insertions, 11 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 1040f9b2f997..3a06b51c98ad 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
| @@ -87,6 +87,7 @@ struct lguest_data lguest_data = { | |||
| 87 | .noirq_start = (u32)lguest_noirq_start, | 87 | .noirq_start = (u32)lguest_noirq_start, |
| 88 | .noirq_end = (u32)lguest_noirq_end, | 88 | .noirq_end = (u32)lguest_noirq_end, |
| 89 | .blocked_interrupts = { 1 }, /* Block timer interrupts */ | 89 | .blocked_interrupts = { 1 }, /* Block timer interrupts */ |
| 90 | .syscall_vec = SYSCALL_VECTOR, | ||
| 90 | }; | 91 | }; |
| 91 | static cycle_t clock_base; | 92 | static cycle_t clock_base; |
| 92 | 93 | ||
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 02556bae9e9f..41b26e592d38 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
| @@ -281,37 +281,47 @@ static int __init init(void) | |||
| 281 | /* First we put the Switcher up in very high virtual memory. */ | 281 | /* First we put the Switcher up in very high virtual memory. */ |
| 282 | err = map_switcher(); | 282 | err = map_switcher(); |
| 283 | if (err) | 283 | if (err) |
| 284 | return err; | 284 | goto out; |
| 285 | 285 | ||
| 286 | /* Now we set up the pagetable implementation for the Guests. */ | 286 | /* Now we set up the pagetable implementation for the Guests. */ |
| 287 | err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES); | 287 | err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES); |
| 288 | if (err) { | 288 | if (err) |
| 289 | unmap_switcher(); | 289 | goto unmap; |
| 290 | return err; | ||
| 291 | } | ||
| 292 | 290 | ||
| 293 | /* The I/O subsystem needs some things initialized. */ | 291 | /* The I/O subsystem needs some things initialized. */ |
| 294 | lguest_io_init(); | 292 | lguest_io_init(); |
| 295 | 293 | ||
| 294 | /* We might need to reserve an interrupt vector. */ | ||
| 295 | err = init_interrupts(); | ||
| 296 | if (err) | ||
| 297 | goto free_pgtables; | ||
| 298 | |||
| 296 | /* /dev/lguest needs to be registered. */ | 299 | /* /dev/lguest needs to be registered. */ |
| 297 | err = lguest_device_init(); | 300 | err = lguest_device_init(); |
| 298 | if (err) { | 301 | if (err) |
| 299 | free_pagetables(); | 302 | goto free_interrupts; |
| 300 | unmap_switcher(); | ||
| 301 | return err; | ||
| 302 | } | ||
| 303 | 303 | ||
| 304 | /* Finally we do some architecture-specific setup. */ | 304 | /* Finally we do some architecture-specific setup. */ |
| 305 | lguest_arch_host_init(); | 305 | lguest_arch_host_init(); |
| 306 | 306 | ||
| 307 | /* All good! */ | 307 | /* All good! */ |
| 308 | return 0; | 308 | return 0; |
| 309 | |||
| 310 | free_interrupts: | ||
| 311 | free_interrupts(); | ||
| 312 | free_pgtables: | ||
| 313 | free_pagetables(); | ||
| 314 | unmap: | ||
| 315 | unmap_switcher(); | ||
| 316 | out: | ||
| 317 | return err; | ||
| 309 | } | 318 | } |
| 310 | 319 | ||
| 311 | /* Cleaning up is just the same code, backwards. With a little French. */ | 320 | /* Cleaning up is just the same code, backwards. With a little French. */ |
| 312 | static void __exit fini(void) | 321 | static void __exit fini(void) |
| 313 | { | 322 | { |
| 314 | lguest_device_remove(); | 323 | lguest_device_remove(); |
| 324 | free_interrupts(); | ||
| 315 | free_pagetables(); | 325 | free_pagetables(); |
| 316 | unmap_switcher(); | 326 | unmap_switcher(); |
| 317 | 327 | ||
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index fdefc0afc38c..a57d757eab6e 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
| @@ -12,8 +12,14 @@ | |||
| 12 | * them first, so we also have a way of "reflecting" them into the Guest as if | 12 | * them first, so we also have a way of "reflecting" them into the Guest as if |
| 13 | * they had been delivered to it directly. :*/ | 13 | * they had been delivered to it directly. :*/ |
| 14 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/module.h> | ||
| 15 | #include "lg.h" | 17 | #include "lg.h" |
| 16 | 18 | ||
| 19 | /* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */ | ||
| 20 | static unsigned int syscall_vector = SYSCALL_VECTOR; | ||
| 21 | module_param(syscall_vector, uint, 0444); | ||
| 22 | |||
| 17 | /* The address of the interrupt handler is split into two bits: */ | 23 | /* The address of the interrupt handler is split into two bits: */ |
| 18 | static unsigned long idt_address(u32 lo, u32 hi) | 24 | static unsigned long idt_address(u32 lo, u32 hi) |
| 19 | { | 25 | { |
| @@ -183,6 +189,47 @@ void maybe_do_interrupt(struct lguest *lg) | |||
| 183 | * timer interrupt. */ | 189 | * timer interrupt. */ |
| 184 | write_timestamp(lg); | 190 | write_timestamp(lg); |
| 185 | } | 191 | } |
| 192 | /*:*/ | ||
| 193 | |||
| 194 | /* Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent | ||
| 195 | * me a patch, so we support that too. It'd be a big step for lguest if half | ||
| 196 | * the Plan 9 user base were to start using it. | ||
| 197 | * | ||
| 198 | * Actually now I think of it, it's possible that Ron *is* half the Plan 9 | ||
| 199 | * userbase. Oh well. */ | ||
| 200 | static bool could_be_syscall(unsigned int num) | ||
| 201 | { | ||
| 202 | /* Normal Linux SYSCALL_VECTOR or reserved vector? */ | ||
| 203 | return num == SYSCALL_VECTOR || num == syscall_vector; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* The syscall vector it wants must be unused by Host. */ | ||
| 207 | bool check_syscall_vector(struct lguest *lg) | ||
| 208 | { | ||
| 209 | u32 vector; | ||
| 210 | |||
| 211 | if (get_user(vector, &lg->lguest_data->syscall_vec)) | ||
| 212 | return false; | ||
| 213 | |||
| 214 | return could_be_syscall(vector); | ||
| 215 | } | ||
| 216 | |||
| 217 | int init_interrupts(void) | ||
| 218 | { | ||
| 219 | /* If they want some strange system call vector, reserve it now */ | ||
| 220 | if (syscall_vector != SYSCALL_VECTOR | ||
| 221 | && test_and_set_bit(syscall_vector, used_vectors)) { | ||
| 222 | printk("lg: couldn't reserve syscall %u\n", syscall_vector); | ||
| 223 | return -EBUSY; | ||
| 224 | } | ||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | void free_interrupts(void) | ||
| 229 | { | ||
| 230 | if (syscall_vector != SYSCALL_VECTOR) | ||
| 231 | clear_bit(syscall_vector, used_vectors); | ||
| 232 | } | ||
| 186 | 233 | ||
| 187 | /*H:220 Now we've got the routines to deliver interrupts, delivering traps | 234 | /*H:220 Now we've got the routines to deliver interrupts, delivering traps |
| 188 | * like page fault is easy. The only trick is that Intel decided that some | 235 | * like page fault is easy. The only trick is that Intel decided that some |
| @@ -224,7 +271,7 @@ static int direct_trap(unsigned int num) | |||
| 224 | { | 271 | { |
| 225 | /* Hardware interrupts don't go to the Guest at all (except system | 272 | /* Hardware interrupts don't go to the Guest at all (except system |
| 226 | * call). */ | 273 | * call). */ |
| 227 | if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR) | 274 | if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num)) |
| 228 | return 0; | 275 | return 0; |
| 229 | 276 | ||
| 230 | /* The Host needs to see page faults (for shadow paging and to save the | 277 | /* The Host needs to see page faults (for shadow paging and to save the |
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index f921684dbe5c..7408cebe995e 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
| @@ -141,6 +141,9 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, | |||
| 141 | const unsigned long *def); | 141 | const unsigned long *def); |
| 142 | void guest_set_clockevent(struct lguest *lg, unsigned long delta); | 142 | void guest_set_clockevent(struct lguest *lg, unsigned long delta); |
| 143 | void init_clockdev(struct lguest *lg); | 143 | void init_clockdev(struct lguest *lg); |
| 144 | bool check_syscall_vector(struct lguest *lg); | ||
| 145 | int init_interrupts(void); | ||
| 146 | void free_interrupts(void); | ||
| 144 | 147 | ||
| 145 | /* segments.c: */ | 148 | /* segments.c: */ |
| 146 | void setup_default_gdt_entries(struct lguest_ro_state *state); | 149 | void setup_default_gdt_entries(struct lguest_ro_state *state); |
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 84c09082f27f..a125109446dc 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
| @@ -530,6 +530,10 @@ int lguest_arch_init_hypercalls(struct lguest *lg) | |||
| 530 | if (put_user(tsc_speed, &lg->lguest_data->tsc_khz)) | 530 | if (put_user(tsc_speed, &lg->lguest_data->tsc_khz)) |
| 531 | return -EFAULT; | 531 | return -EFAULT; |
| 532 | 532 | ||
| 533 | /* The interrupt code might not like the system call vector. */ | ||
| 534 | if (!check_syscall_vector(lg)) | ||
| 535 | kill_guest(lg, "bad syscall vector"); | ||
| 536 | |||
| 533 | return 0; | 537 | return 0; |
| 534 | } | 538 | } |
| 535 | /* Now we've examined the hypercall code; our Guest can make requests. There | 539 | /* Now we've examined the hypercall code; our Guest can make requests. There |
diff --git a/include/linux/lguest.h b/include/linux/lguest.h index 9ddac2f0a97c..083052236db9 100644 --- a/include/linux/lguest.h +++ b/include/linux/lguest.h | |||
| @@ -48,6 +48,9 @@ struct lguest_data | |||
| 48 | /* Fields initialized by the Guest at boot: */ | 48 | /* Fields initialized by the Guest at boot: */ |
| 49 | /* Instruction range to suppress interrupts even if enabled */ | 49 | /* Instruction range to suppress interrupts even if enabled */ |
| 50 | unsigned long noirq_start, noirq_end; | 50 | unsigned long noirq_start, noirq_end; |
| 51 | |||
| 52 | /* The vector to try to use for system calls (0x40 or 0x80). */ | ||
| 53 | unsigned int syscall_vec; | ||
| 51 | }; | 54 | }; |
| 52 | extern struct lguest_data lguest_data; | 55 | extern struct lguest_data lguest_data; |
| 53 | #endif /* __ASSEMBLY__ */ | 56 | #endif /* __ASSEMBLY__ */ |
