From da443eab0d293e9cc569147d40e666193f532687 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sat, 27 Mar 2010 20:16:51 +0200 Subject: [PATCH] kvm: Fix kernel boot IP Booting to a Linux kernel is no longer supported. Therefore, start executing at offset 0x200 of bzImage which has a jump to real-mode setup code. See Documentation/x86/boot.txt for more details. Signed-off-by: Pekka Enberg --- tools/kvm/include/kvm/kvm.h | 3 +++ tools/kvm/kvm.c | 26 ++++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index d3f6ac86f801..edec88b8bee5 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -15,6 +15,9 @@ struct kvm { uint64_t ram_size; void *ram_start; + uint16_t boot_cs; + uint16_t boot_ip; + struct kvm_regs regs; struct kvm_sregs sregs; }; diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index 421467510791..d52a0aab6ee9 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -156,7 +156,7 @@ static inline uint32_t segment_to_flat(uint16_t selector, uint16_t offset) #define BOOT_LOADER_CS 0x0000 #define BOOT_LOADER_IP 0x7c00 -static int load_flat_binary(struct kvm *kvm, int fd) +static int load_flat_binary(struct kvm *self, int fd) { void *p; int nr; @@ -164,11 +164,14 @@ static int load_flat_binary(struct kvm *kvm, int fd) if (lseek(fd, 0, SEEK_SET) < 0) die_perror("lseek"); - p = guest_addr_to_host(kvm, segment_to_flat(BOOT_LOADER_CS, BOOT_LOADER_IP)); + p = guest_addr_to_host(self, segment_to_flat(BOOT_LOADER_CS, BOOT_LOADER_IP)); while ((nr = read(fd, p, 65536)) > 0) p += nr; + self->boot_cs = BOOT_LOADER_CS; + self->boot_ip = BOOT_LOADER_IP; + return true; } @@ -182,7 +185,7 @@ static const char *BZIMAGE_MAGIC = "HdrS"; #define BZ_DEFAULT_SETUP_SECTS 4 -static bool load_bzimage(struct kvm *kvm, int fd) +static bool load_bzimage(struct kvm *self, int fd) { unsigned long setup_sects; struct boot_params boot; @@ -211,16 +214,23 @@ static bool load_bzimage(struct kvm *kvm, int fd) setup_sects = BZ_DEFAULT_SETUP_SECTS; setup_size = setup_sects << 9; - p = guest_addr_to_host(kvm, segment_to_flat(BOOT_LOADER_CS, BOOT_LOADER_IP)); + p = guest_addr_to_host(self, segment_to_flat(BOOT_LOADER_CS, BOOT_LOADER_IP)); if (read(fd, p, setup_size) != setup_size) die_perror("read"); - p = guest_addr_to_host(kvm, BZ_KERNEL_START); + p = guest_addr_to_host(self, BZ_KERNEL_START); while ((nr = read(fd, p, 65536)) > 0) p += nr; + self->boot_cs = BOOT_LOADER_CS; + /* + * The real-mode setup code starts at offset 0x200 of a bzImage. See + * Documentation/x86/boot.txt for details. + */ + self->boot_ip = BOOT_LOADER_IP + 0x200; + return true; } @@ -270,8 +280,8 @@ void kvm__reset_vcpu(struct kvm *self) * KVM on Intel requires 'base' to be 'selector * 16' in * real mode. */ - .selector = BOOT_LOADER_CS, - .base = BOOT_LOADER_CS * 16, + .selector = self->boot_cs, + .base = self->boot_cs * 16, .limit = 0xffffU, .type = 0x0bU, .present = 1, @@ -335,7 +345,7 @@ void kvm__reset_vcpu(struct kvm *self) die_perror("KVM_SET_SREGS failed"); self->regs = (struct kvm_regs) { - .rip = BOOT_LOADER_IP, + .rip = self->boot_ip, /* We start the guest in 16-bit real mode */ .rflags = 0x0000000000000002ULL, }; -- 2.39.5