kvm: Implement support interrupt injection

This patch implement support for injecting interrupts from the userspace
hypervisor to the guest.

Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Pekka Enberg
2015-06-01 16:39:41 +01:00
committed by Will Deacon
parent ceba1fad4c
commit 8bb34e0dfa
5 changed files with 63 additions and 3 deletions
+3 -1
View File
@@ -27,6 +27,8 @@ DEPS := $(patsubst %.o,%.d,$(OBJS))
OBJS += bios.o
OBJS += bios/bios.o
LIBS += -lrt
uname_M := $(shell uname -m | sed -e s/i.86/i386/)
ifeq ($(uname_M),i386)
DEFINES += -DCONFIG_X86_32
@@ -60,7 +62,7 @@ all: $(PROGRAM)
$(PROGRAM): $(DEPS) $(OBJS)
$(E) " LINK " $@
$(Q) $(CC) $(OBJS) -o $@
$(Q) $(CC) $(OBJS) $(LIBS) -o $@
$(DEPS):
+5
View File
@@ -65,6 +65,11 @@ static struct serial8250_device device = {
.iobase = 0x3f8, /* ttyS0 */
};
void serial8250__interrupt(struct kvm *self)
{
/* TODO: inject 8250 interrupt for the guest */
}
static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
{
uint16_t offset = port - device.iobase;
+3
View File
@@ -1,6 +1,9 @@
#ifndef KVM__EARLY_PRINTK_H
#define KVM__EARLY_PRINTK_H
struct kvm;
void early_printk__init(void);
void serial8250__interrupt(struct kvm *self);
#endif /* KVM__EARLY_PRINTK_H */
+4 -1
View File
@@ -608,7 +608,10 @@ void kvm__setup_mem(struct kvm *self)
void kvm__run(struct kvm *self)
{
if (ioctl(self->vcpu_fd, KVM_RUN, 0) < 0)
int err;
err = ioctl(self->vcpu_fd, KVM_RUN, 0);
if (err && (errno != EINTR && errno != EAGAIN))
die_perror("KVM_RUN failed");
}
+48 -1
View File
@@ -12,6 +12,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
extern bool ioport_debug;
@@ -45,6 +46,47 @@ static bool option_matches(char *arg, const char *option)
return !strncmp(arg, option, strlen(option));
}
#define TIMER_INTERVAL_NS 1000000000
static void alarm_handler(int sig)
{
}
/*
* This function sets up a timer that's used to inject interrupts from the
* userspace hypervisor into the guest at periodical intervals. Please note
* that clock interrupt, for example, is not handled here.
*/
static void setup_timer(void)
{
struct itimerspec its;
struct sigaction sa;
struct sigevent sev;
timer_t timerid;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = alarm_handler;
sigaction(SIGALRM, &sa, NULL);
memset(&sev, 0, sizeof(struct sigevent));
sev.sigev_value.sival_int = 0;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
its.it_value.tv_sec = TIMER_INTERVAL_NS / 1000000000;
its.it_value.tv_nsec = TIMER_INTERVAL_NS % 1000000000;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) < 0)
die("timer_create()");
if (timer_settime(timerid, 0, &its, NULL) < 0)
die("timer_settime()");
}
int main(int argc, char *argv[])
{
const char *kernel_filename = NULL;
@@ -131,6 +173,8 @@ int main(int argc, char *argv[])
blk_virtio__init(kvm);
setup_timer();
for (;;) {
kvm__run(kvm);
@@ -165,7 +209,10 @@ int main(int argc, char *argv[])
if (!ret)
goto exit_kvm;
break;
}
case KVM_EXIT_INTR: {
serial8250__interrupt(kvm);
break;
}
default:
goto exit_kvm;