diff --git a/ivt.c b/ivt.c index e5e8503..36ffb01 100644 --- a/ivt.c +++ b/ivt.c @@ -36,3 +36,11 @@ void ivt_set_entry(struct ivt_entry e, unsigned int n) if (n < IVT_VECTORS) ivt_table[n] = e; } + +void ivt_set_all(struct ivt_entry e) +{ + unsigned int i; + + for (i = 0; i < IVT_VECTORS; i++) + ivt_table[i] = e; +} diff --git a/ivt.h b/ivt.h index 3b31cac..b895449 100644 --- a/ivt.h +++ b/ivt.h @@ -5,11 +5,12 @@ #define IVT_VECTORS 256 struct ivt_entry { - uint16_t segment; uint16_t offset; + uint16_t segment; } __attribute__((packed)); void ivt_reset(void); void ivt_copy_table(void *dst, unsigned int size); struct ivt_entry * const ivt_get_entry(unsigned int n); void ivt_set_entry(struct ivt_entry e, unsigned int n); +void ivt_set_all(struct ivt_entry e); diff --git a/kvm.c b/kvm.c index b3fe380..7d1f3f3 100644 --- a/kvm.c +++ b/kvm.c @@ -16,6 +16,7 @@ #include #include +#include "ivt.h" #include "util.h" /* @@ -198,6 +199,7 @@ static bool load_bzimage(struct kvm *self, int fd, const char *kernel_cmdline) { unsigned long setup_sects; struct boot_params boot; + struct ivt_entry real_mode_irq; ssize_t setup_size; void *p; int nr; @@ -241,6 +243,20 @@ static bool load_bzimage(struct kvm *self, int fd, const char *kernel_cmdline) self->boot_ip = BOOT_LOADER_IP + 0x200; self->boot_sp = BOOT_LOADER_SP; + /* + * Setup a *fake* real mode IVT, it has only one real + * hadler which does just iret + */ + real_mode_irq = (struct ivt_entry) { + .segment = 0, + .offset = 0x400 + 1, + }; + ivt_set_all(real_mode_irq); + p = guest_flat_to_host(self, 0); + ivt_copy_table(p, IVT_VECTORS * sizeof(real_mode_irq)); + p += IVT_VECTORS * sizeof(real_mode_irq) + 1; + *(char *)p = 0xcf; /* iret here */ + return true; }