mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-30 07:37:49 +00:00
lguest: per-vcpu interrupt processing.
This patch adapts interrupt processing for using the vcpu struct. Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
ad8d8f3bc6
commit
177e449dc5
@ -203,7 +203,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
|
|||||||
/* Check if there are any interrupts which can be delivered
|
/* Check if there are any interrupts which can be delivered
|
||||||
* now: if so, this sets up the hander to be executed when we
|
* now: if so, this sets up the hander to be executed when we
|
||||||
* next run the Guest. */
|
* next run the Guest. */
|
||||||
maybe_do_interrupt(lg);
|
maybe_do_interrupt(cpu);
|
||||||
|
|
||||||
/* All long-lived kernel loops need to check with this horrible
|
/* All long-lived kernel loops need to check with this horrible
|
||||||
* thing called the freezer. If the Host is trying to suspend,
|
* thing called the freezer. If the Host is trying to suspend,
|
||||||
|
@ -60,11 +60,12 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
|
|||||||
* We set up the stack just like the CPU does for a real interrupt, so it's
|
* 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
|
* identical for the Guest (and the standard "iret" instruction will undo
|
||||||
* it). */
|
* it). */
|
||||||
static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
|
static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err)
|
||||||
{
|
{
|
||||||
unsigned long gstack, origstack;
|
unsigned long gstack, origstack;
|
||||||
u32 eflags, ss, irq_enable;
|
u32 eflags, ss, irq_enable;
|
||||||
unsigned long virtstack;
|
unsigned long virtstack;
|
||||||
|
struct lguest *lg = cpu->lg;
|
||||||
|
|
||||||
/* There are two cases for interrupts: one where the Guest is already
|
/* There are two cases for interrupts: one where the Guest is already
|
||||||
* in the kernel, and a more complex one where the Guest is in
|
* in the kernel, and a more complex one where the Guest is in
|
||||||
@ -129,9 +130,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
|
|||||||
*
|
*
|
||||||
* maybe_do_interrupt() gets called before every entry to the Guest, to see if
|
* maybe_do_interrupt() gets called before every entry to the Guest, to see if
|
||||||
* we should divert the Guest to running an interrupt handler. */
|
* we should divert the Guest to running an interrupt handler. */
|
||||||
void maybe_do_interrupt(struct lguest *lg)
|
void maybe_do_interrupt(struct lg_cpu *cpu)
|
||||||
{
|
{
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
|
struct lguest *lg = cpu->lg;
|
||||||
DECLARE_BITMAP(blk, LGUEST_IRQS);
|
DECLARE_BITMAP(blk, LGUEST_IRQS);
|
||||||
struct desc_struct *idt;
|
struct desc_struct *idt;
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ void maybe_do_interrupt(struct lguest *lg)
|
|||||||
sizeof(blk)))
|
sizeof(blk)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
|
bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
|
||||||
|
|
||||||
/* Find the first interrupt. */
|
/* Find the first interrupt. */
|
||||||
irq = find_first_bit(blk, LGUEST_IRQS);
|
irq = find_first_bit(blk, LGUEST_IRQS);
|
||||||
@ -180,11 +182,11 @@ void maybe_do_interrupt(struct lguest *lg)
|
|||||||
/* If they don't have a handler (yet?), we just ignore it */
|
/* If they don't have a handler (yet?), we just ignore it */
|
||||||
if (idt_present(idt->a, idt->b)) {
|
if (idt_present(idt->a, idt->b)) {
|
||||||
/* OK, mark it no longer pending and deliver it. */
|
/* OK, mark it no longer pending and deliver it. */
|
||||||
clear_bit(irq, lg->irqs_pending);
|
clear_bit(irq, cpu->irqs_pending);
|
||||||
/* set_guest_interrupt() takes the interrupt descriptor and a
|
/* set_guest_interrupt() takes the interrupt descriptor and a
|
||||||
* flag to say whether this interrupt pushes an error code onto
|
* flag to say whether this interrupt pushes an error code onto
|
||||||
* the stack as well: virtual interrupts never do. */
|
* the stack as well: virtual interrupts never do. */
|
||||||
set_guest_interrupt(lg, idt->a, idt->b, 0);
|
set_guest_interrupt(cpu, idt->a, idt->b, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Every time we deliver an interrupt, we update the timestamp in the
|
/* Every time we deliver an interrupt, we update the timestamp in the
|
||||||
@ -245,19 +247,19 @@ static int has_err(unsigned int trap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* deliver_trap() returns true if it could deliver the trap. */
|
/* deliver_trap() returns true if it could deliver the trap. */
|
||||||
int deliver_trap(struct lguest *lg, unsigned int num)
|
int deliver_trap(struct lg_cpu *cpu, unsigned int num)
|
||||||
{
|
{
|
||||||
/* Trap numbers are always 8 bit, but we set an impossible trap number
|
/* Trap numbers are always 8 bit, but we set an impossible trap number
|
||||||
* for traps inside the Switcher, so check that here. */
|
* for traps inside the Switcher, so check that here. */
|
||||||
if (num >= ARRAY_SIZE(lg->arch.idt))
|
if (num >= ARRAY_SIZE(cpu->lg->arch.idt))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Early on the Guest hasn't set the IDT entries (or maybe it put a
|
/* 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. */
|
* bogus one in): if we fail here, the Guest will be killed. */
|
||||||
if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b))
|
if (!idt_present(cpu->lg->arch.idt[num].a, cpu->lg->arch.idt[num].b))
|
||||||
return 0;
|
return 0;
|
||||||
set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b,
|
set_guest_interrupt(cpu, cpu->lg->arch.idt[num].a,
|
||||||
has_err(num));
|
cpu->lg->arch.idt[num].b, has_err(num));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +495,7 @@ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
|
|||||||
struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
|
struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
|
||||||
|
|
||||||
/* Remember the first interrupt is the timer interrupt. */
|
/* Remember the first interrupt is the timer interrupt. */
|
||||||
set_bit(0, cpu->lg->irqs_pending);
|
set_bit(0, cpu->irqs_pending);
|
||||||
/* If the Guest is actually stopped, we need to wake it up. */
|
/* If the Guest is actually stopped, we need to wake it up. */
|
||||||
if (cpu->lg->halted)
|
if (cpu->lg->halted)
|
||||||
wake_up_process(cpu->lg->tsk);
|
wake_up_process(cpu->lg->tsk);
|
||||||
|
@ -50,6 +50,9 @@ struct lg_cpu {
|
|||||||
|
|
||||||
/* Virtual clock device */
|
/* Virtual clock device */
|
||||||
struct hrtimer hrt;
|
struct hrtimer hrt;
|
||||||
|
|
||||||
|
/* Pending virtual interrupts */
|
||||||
|
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The private info the thread maintains about the guest. */
|
/* The private info the thread maintains about the guest. */
|
||||||
@ -97,9 +100,6 @@ struct lguest
|
|||||||
const char *dead;
|
const char *dead;
|
||||||
|
|
||||||
struct lguest_arch arch;
|
struct lguest_arch arch;
|
||||||
|
|
||||||
/* Pending virtual interrupts */
|
|
||||||
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct mutex lguest_lock;
|
extern struct mutex lguest_lock;
|
||||||
@ -136,8 +136,8 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
|
|||||||
#define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT)
|
#define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT)
|
||||||
|
|
||||||
/* interrupts_and_traps.c: */
|
/* interrupts_and_traps.c: */
|
||||||
void maybe_do_interrupt(struct lguest *lg);
|
void maybe_do_interrupt(struct lg_cpu *cpu);
|
||||||
int deliver_trap(struct lguest *lg, unsigned int num);
|
int deliver_trap(struct lg_cpu *cpu, unsigned int num);
|
||||||
void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
|
void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
|
||||||
void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
|
void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
|
||||||
void pin_stack_pages(struct lguest *lg);
|
void pin_stack_pages(struct lguest *lg);
|
||||||
|
@ -36,7 +36,7 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
|
|||||||
|
|
||||||
/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
|
/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
|
||||||
* number to /dev/lguest. */
|
* number to /dev/lguest. */
|
||||||
static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
|
static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
|
||||||
{
|
{
|
||||||
unsigned long irq;
|
unsigned long irq;
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
/* Next time the Guest runs, the core code will see if it can deliver
|
/* Next time the Guest runs, the core code will see if it can deliver
|
||||||
* this interrupt. */
|
* this interrupt. */
|
||||||
set_bit(irq, lg->irqs_pending);
|
set_bit(irq, cpu->irqs_pending);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ static ssize_t write(struct file *file, const char __user *in,
|
|||||||
struct lguest *lg = file->private_data;
|
struct lguest *lg = file->private_data;
|
||||||
const unsigned long __user *input = (const unsigned long __user *)in;
|
const unsigned long __user *input = (const unsigned long __user *)in;
|
||||||
unsigned long req;
|
unsigned long req;
|
||||||
struct lg_cpu *cpu;
|
struct lg_cpu *uninitialized_var(cpu);
|
||||||
unsigned int cpu_id = *off;
|
unsigned int cpu_id = *off;
|
||||||
|
|
||||||
if (get_user(req, input) != 0)
|
if (get_user(req, input) != 0)
|
||||||
@ -253,7 +253,7 @@ static ssize_t write(struct file *file, const char __user *in,
|
|||||||
case LHREQ_INITIALIZE:
|
case LHREQ_INITIALIZE:
|
||||||
return initialize(file, input);
|
return initialize(file, input);
|
||||||
case LHREQ_IRQ:
|
case LHREQ_IRQ:
|
||||||
return user_send_irq(lg, input);
|
return user_send_irq(cpu, input);
|
||||||
case LHREQ_BREAK:
|
case LHREQ_BREAK:
|
||||||
return break_guest_out(lg, input);
|
return break_guest_out(lg, input);
|
||||||
default:
|
default:
|
||||||
|
@ -342,7 +342,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We didn't handle the trap, so it needs to go to the Guest. */
|
/* We didn't handle the trap, so it needs to go to the Guest. */
|
||||||
if (!deliver_trap(lg, lg->regs->trapnum))
|
if (!deliver_trap(cpu, lg->regs->trapnum))
|
||||||
/* If the Guest doesn't have a handler (either it hasn't
|
/* If the Guest doesn't have a handler (either it hasn't
|
||||||
* registered any yet, or it's one of the faults we don't let
|
* registered any yet, or it's one of the faults we don't let
|
||||||
* it handle), it dies with a cryptic error message. */
|
* it handle), it dies with a cryptic error message. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user