提交 73044f05 编写于 作者: G Glauber de Oliveira Costa 提交者: Rusty Russell

lguest: make hypercalls use the vcpu struct

this patch changes do_hcall() and do_async_hcall() interfaces (and obviously their
callers) to get a vcpu struct. Again, a vcpu services the hypercall, not the whole
guest
Signed-off-by: NGlauber de Oliveira Costa <gcosta@redhat.com>
Signed-off-by: NRusty Russell <rusty@rustcorp.com.au>
上级 7ea07a15
...@@ -181,8 +181,8 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) ...@@ -181,8 +181,8 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
/* We stop running once the Guest is dead. */ /* We stop running once the Guest is dead. */
while (!lg->dead) { while (!lg->dead) {
/* First we run any hypercalls the Guest wants done. */ /* First we run any hypercalls the Guest wants done. */
if (lg->hcall) if (cpu->hcall)
do_hypercalls(lg); do_hypercalls(cpu);
/* It's possible the Guest did a NOTIFY hypercall to the /* It's possible the Guest did a NOTIFY hypercall to the
* Launcher, in which case we return from the read() now. */ * Launcher, in which case we return from the read() now. */
...@@ -234,7 +234,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) ...@@ -234,7 +234,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
local_irq_enable(); local_irq_enable();
/* Now we deal with whatever happened to the Guest. */ /* Now we deal with whatever happened to the Guest. */
lguest_arch_handle_trap(lg); lguest_arch_handle_trap(cpu);
} }
if (lg->dead == ERR_PTR(-ERESTART)) if (lg->dead == ERR_PTR(-ERESTART))
......
...@@ -29,8 +29,10 @@ ...@@ -29,8 +29,10 @@
/*H:120 This is the core hypercall routine: where the Guest gets what it wants. /*H:120 This is the core hypercall routine: where the Guest gets what it wants.
* Or gets killed. Or, in the case of LHCALL_CRASH, both. */ * Or gets killed. Or, in the case of LHCALL_CRASH, both. */
static void do_hcall(struct lguest *lg, struct hcall_args *args) static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
{ {
struct lguest *lg = cpu->lg;
switch (args->arg0) { switch (args->arg0) {
case LHCALL_FLUSH_ASYNC: case LHCALL_FLUSH_ASYNC:
/* This call does nothing, except by breaking out of the Guest /* This call does nothing, except by breaking out of the Guest
...@@ -93,7 +95,7 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -93,7 +95,7 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
break; break;
default: default:
/* It should be an architecture-specific hypercall. */ /* It should be an architecture-specific hypercall. */
if (lguest_arch_do_hcall(lg, args)) if (lguest_arch_do_hcall(cpu, args))
kill_guest(lg, "Bad hypercall %li\n", args->arg0); kill_guest(lg, "Bad hypercall %li\n", args->arg0);
} }
} }
...@@ -106,10 +108,11 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -106,10 +108,11 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
* Guest put them in the ring, but we also promise the Guest that they will * Guest put them in the ring, but we also promise the Guest that they will
* happen before any normal hypercall (which is why we check this before * happen before any normal hypercall (which is why we check this before
* checking for a normal hcall). */ * checking for a normal hcall). */
static void do_async_hcalls(struct lguest *lg) static void do_async_hcalls(struct lg_cpu *cpu)
{ {
unsigned int i; unsigned int i;
u8 st[LHCALL_RING_SIZE]; u8 st[LHCALL_RING_SIZE];
struct lguest *lg = cpu->lg;
/* For simplicity, we copy the entire call status array in at once. */ /* For simplicity, we copy the entire call status array in at once. */
if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
...@@ -121,7 +124,7 @@ static void do_async_hcalls(struct lguest *lg) ...@@ -121,7 +124,7 @@ static void do_async_hcalls(struct lguest *lg)
/* We remember where we were up to from last time. This makes /* We remember where we were up to from last time. This makes
* sure that the hypercalls are done in the order the Guest * sure that the hypercalls are done in the order the Guest
* places them in the ring. */ * places them in the ring. */
unsigned int n = lg->next_hcall; unsigned int n = cpu->next_hcall;
/* 0xFF means there's no call here (yet). */ /* 0xFF means there's no call here (yet). */
if (st[n] == 0xFF) if (st[n] == 0xFF)
...@@ -129,8 +132,8 @@ static void do_async_hcalls(struct lguest *lg) ...@@ -129,8 +132,8 @@ static void do_async_hcalls(struct lguest *lg)
/* OK, we have hypercall. Increment the "next_hcall" cursor, /* OK, we have hypercall. Increment the "next_hcall" cursor,
* and wrap back to 0 if we reach the end. */ * and wrap back to 0 if we reach the end. */
if (++lg->next_hcall == LHCALL_RING_SIZE) if (++cpu->next_hcall == LHCALL_RING_SIZE)
lg->next_hcall = 0; cpu->next_hcall = 0;
/* Copy the hypercall arguments into a local copy of /* Copy the hypercall arguments into a local copy of
* the hcall_args struct. */ * the hcall_args struct. */
...@@ -141,7 +144,7 @@ static void do_async_hcalls(struct lguest *lg) ...@@ -141,7 +144,7 @@ static void do_async_hcalls(struct lguest *lg)
} }
/* Do the hypercall, same as a normal one. */ /* Do the hypercall, same as a normal one. */
do_hcall(lg, &args); do_hcall(cpu, &args);
/* Mark the hypercall done. */ /* Mark the hypercall done. */
if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
...@@ -158,16 +161,17 @@ static void do_async_hcalls(struct lguest *lg) ...@@ -158,16 +161,17 @@ static void do_async_hcalls(struct lguest *lg)
/* Last of all, we look at what happens first of all. The very first time the /* Last of all, we look at what happens first of all. The very first time the
* Guest makes a hypercall, we end up here to set things up: */ * Guest makes a hypercall, we end up here to set things up: */
static void initialize(struct lguest *lg) static void initialize(struct lg_cpu *cpu)
{ {
struct lguest *lg = cpu->lg;
/* You can't do anything until you're initialized. The Guest knows the /* You can't do anything until you're initialized. The Guest knows the
* rules, so we're unforgiving here. */ * rules, so we're unforgiving here. */
if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) { if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) {
kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0); kill_guest(lg, "hypercall %li before INIT", cpu->hcall->arg0);
return; return;
} }
if (lguest_arch_init_hypercalls(lg)) if (lguest_arch_init_hypercalls(cpu))
kill_guest(lg, "bad guest page %p", lg->lguest_data); kill_guest(lg, "bad guest page %p", lg->lguest_data);
/* The Guest tells us where we're not to deliver interrupts by putting /* The Guest tells us where we're not to deliver interrupts by putting
...@@ -196,27 +200,27 @@ static void initialize(struct lguest *lg) ...@@ -196,27 +200,27 @@ static void initialize(struct lguest *lg)
* Remember from the Guest, hypercalls come in two flavors: normal and * Remember from the Guest, hypercalls come in two flavors: normal and
* asynchronous. This file handles both of types. * asynchronous. This file handles both of types.
*/ */
void do_hypercalls(struct lguest *lg) void do_hypercalls(struct lg_cpu *cpu)
{ {
/* Not initialized yet? This hypercall must do it. */ /* Not initialized yet? This hypercall must do it. */
if (unlikely(!lg->lguest_data)) { if (unlikely(!cpu->lg->lguest_data)) {
/* Set up the "struct lguest_data" */ /* Set up the "struct lguest_data" */
initialize(lg); initialize(cpu);
/* Hcall is done. */ /* Hcall is done. */
lg->hcall = NULL; cpu->hcall = NULL;
return; return;
} }
/* The Guest has initialized. /* The Guest has initialized.
* *
* Look in the hypercall ring for the async hypercalls: */ * Look in the hypercall ring for the async hypercalls: */
do_async_hcalls(lg); do_async_hcalls(cpu);
/* If we stopped reading the hypercall ring because the Guest did a /* If we stopped reading the hypercall ring because the Guest did a
* NOTIFY to the Launcher, we want to return now. Otherwise we do * NOTIFY to the Launcher, we want to return now. Otherwise we do
* the hypercall. */ * the hypercall. */
if (!lg->pending_notify) { if (!cpu->lg->pending_notify) {
do_hcall(lg, lg->hcall); do_hcall(cpu, cpu->hcall);
/* Tricky point: we reset the hcall pointer to mark the /* Tricky point: we reset the hcall pointer to mark the
* hypercall as "done". We use the hcall pointer rather than * hypercall as "done". We use the hcall pointer rather than
* the trap number to indicate a hypercall is pending. * the trap number to indicate a hypercall is pending.
...@@ -227,7 +231,7 @@ void do_hypercalls(struct lguest *lg) ...@@ -227,7 +231,7 @@ void do_hypercalls(struct lguest *lg)
* Launcher, the run_guest() loop will exit without running the * Launcher, the run_guest() loop will exit without running the
* Guest. When it comes back it would try to re-run the * Guest. When it comes back it would try to re-run the
* hypercall. */ * hypercall. */
lg->hcall = NULL; cpu->hcall = NULL;
} }
} }
......
...@@ -43,6 +43,10 @@ struct lguest; ...@@ -43,6 +43,10 @@ struct lguest;
struct lg_cpu { struct lg_cpu {
unsigned int id; unsigned int id;
struct lguest *lg; struct lguest *lg;
/* If a hypercall was asked for, this points to the arguments. */
struct hcall_args *hcall;
u32 next_hcall;
}; };
/* The private info the thread maintains about the guest. */ /* The private info the thread maintains about the guest. */
...@@ -65,13 +69,9 @@ struct lguest ...@@ -65,13 +69,9 @@ struct lguest
u32 cr2; u32 cr2;
int halted; int halted;
int ts; int ts;
u32 next_hcall;
u32 esp1; u32 esp1;
u8 ss1; u8 ss1;
/* If a hypercall was asked for, this points to the arguments. */
struct hcall_args *hcall;
/* Do we need to stop what we're doing and return to userspace? */ /* Do we need to stop what we're doing and return to userspace? */
int break_out; int break_out;
wait_queue_head_t break_wq; wait_queue_head_t break_wq;
...@@ -178,9 +178,9 @@ void page_table_guest_data_init(struct lguest *lg); ...@@ -178,9 +178,9 @@ void page_table_guest_data_init(struct lguest *lg);
void lguest_arch_host_init(void); void lguest_arch_host_init(void);
void lguest_arch_host_fini(void); void lguest_arch_host_fini(void);
void lguest_arch_run_guest(struct lg_cpu *cpu); void lguest_arch_run_guest(struct lg_cpu *cpu);
void lguest_arch_handle_trap(struct lguest *lg); void lguest_arch_handle_trap(struct lg_cpu *cpu);
int lguest_arch_init_hypercalls(struct lguest *lg); int lguest_arch_init_hypercalls(struct lg_cpu *cpu);
int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args); int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args);
void lguest_arch_setup_regs(struct lguest *lg, unsigned long start); void lguest_arch_setup_regs(struct lguest *lg, unsigned long start);
/* <arch>/switcher.S: */ /* <arch>/switcher.S: */
...@@ -191,7 +191,7 @@ int lguest_device_init(void); ...@@ -191,7 +191,7 @@ int lguest_device_init(void);
void lguest_device_remove(void); void lguest_device_remove(void);
/* hypercalls.c: */ /* hypercalls.c: */
void do_hypercalls(struct lguest *lg); void do_hypercalls(struct lg_cpu *cpu);
void write_timestamp(struct lguest *lg); void write_timestamp(struct lguest *lg);
/*L:035 /*L:035
......
...@@ -283,8 +283,9 @@ static int emulate_insn(struct lguest *lg) ...@@ -283,8 +283,9 @@ static int emulate_insn(struct lguest *lg)
} }
/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
void lguest_arch_handle_trap(struct lguest *lg) void lguest_arch_handle_trap(struct lg_cpu *cpu)
{ {
struct lguest *lg = cpu->lg;
switch (lg->regs->trapnum) { switch (lg->regs->trapnum) {
case 13: /* We've intercepted a General Protection Fault. */ case 13: /* We've intercepted a General Protection Fault. */
/* Check if this was one of those annoying IN or OUT /* Check if this was one of those annoying IN or OUT
...@@ -336,7 +337,7 @@ void lguest_arch_handle_trap(struct lguest *lg) ...@@ -336,7 +337,7 @@ void lguest_arch_handle_trap(struct lguest *lg)
case LGUEST_TRAP_ENTRY: case LGUEST_TRAP_ENTRY:
/* Our 'struct hcall_args' maps directly over our regs: we set /* Our 'struct hcall_args' maps directly over our regs: we set
* up the pointer now to indicate a hypercall is pending. */ * up the pointer now to indicate a hypercall is pending. */
lg->hcall = (struct hcall_args *)lg->regs; cpu->hcall = (struct hcall_args *)lg->regs;
return; return;
} }
...@@ -491,8 +492,10 @@ void __exit lguest_arch_host_fini(void) ...@@ -491,8 +492,10 @@ void __exit lguest_arch_host_fini(void)
/*H:122 The i386-specific hypercalls simply farm out to the right functions. */ /*H:122 The i386-specific hypercalls simply farm out to the right functions. */
int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args) int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
{ {
struct lguest *lg = cpu->lg;
switch (args->arg0) { switch (args->arg0) {
case LHCALL_LOAD_GDT: case LHCALL_LOAD_GDT:
load_guest_gdt(lg, args->arg1, args->arg2); load_guest_gdt(lg, args->arg1, args->arg2);
...@@ -511,13 +514,14 @@ int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -511,13 +514,14 @@ int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args)
} }
/*H:126 i386-specific hypercall initialization: */ /*H:126 i386-specific hypercall initialization: */
int lguest_arch_init_hypercalls(struct lguest *lg) int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
{ {
u32 tsc_speed; u32 tsc_speed;
struct lguest *lg = cpu->lg;
/* The pointer to the Guest's "struct lguest_data" is the only /* The pointer to the Guest's "struct lguest_data" is the only
* argument. We check that address now. */ * argument. We check that address now. */
if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data))) if (!lguest_address_ok(lg, cpu->hcall->arg1, sizeof(*lg->lguest_data)))
return -EFAULT; return -EFAULT;
/* Having checked it, we simply set lg->lguest_data to point straight /* Having checked it, we simply set lg->lguest_data to point straight
...@@ -525,7 +529,7 @@ int lguest_arch_init_hypercalls(struct lguest *lg) ...@@ -525,7 +529,7 @@ int lguest_arch_init_hypercalls(struct lguest *lg)
* copy_to_user/from_user from now on, instead of lgread/write. I put * copy_to_user/from_user from now on, instead of lgread/write. I put
* this in to show that I'm not immune to writing stupid * this in to show that I'm not immune to writing stupid
* optimizations. */ * optimizations. */
lg->lguest_data = lg->mem_base + lg->hcall->arg1; lg->lguest_data = lg->mem_base + cpu->hcall->arg1;
/* We insist that the Time Stamp Counter exist and doesn't change with /* We insist that the Time Stamp Counter exist and doesn't change with
* cpu frequency. Some devious chip manufacturers decided that TSC * cpu frequency. Some devious chip manufacturers decided that TSC
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册