mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-08-27 00:35:59 +00:00
Fix up 'ip' in kvm__reset_vcpu() to take real mode into account
We can't just set 'rip' to 1 MB mark because in real mode, 'ip' is just 16 bits wide. Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
This commit is contained in:
committed by
Will Deacon
parent
ce5e0ecbbf
commit
06e41eeadc
@@ -8,6 +8,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -189,20 +190,31 @@ uint32_t kvm__load_kernel(struct kvm *kvm, const char *kernel_filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t ip_flat_to_real(struct kvm *self, uint64_t ip)
|
||||
{
|
||||
uint64_t cs = self->sregs.cs.selector;
|
||||
|
||||
return ip - (cs << 4);
|
||||
}
|
||||
|
||||
static inline uint64_t ip_real_to_flat(struct kvm *self, uint64_t ip)
|
||||
{
|
||||
uint64_t cs = self->sregs.cs.selector;
|
||||
|
||||
return ip + (cs << 4);
|
||||
}
|
||||
|
||||
void kvm__reset_vcpu(struct kvm *self, uint64_t rip)
|
||||
{
|
||||
self->regs = (struct kvm_regs) {
|
||||
.rip = rip,
|
||||
.rflags = 0x0000000000000002ULL,
|
||||
};
|
||||
|
||||
if (ioctl(self->vcpu_fd, KVM_SET_REGS, &self->regs) < 0)
|
||||
die_perror("KVM_SET_REGS failed");
|
||||
/*
|
||||
* First set up segmentation because we need to translate the flat
|
||||
* 'rip' to segmented 16-bit cs:ip address.
|
||||
*/
|
||||
|
||||
self->sregs = (struct kvm_sregs) {
|
||||
.cr0 = 0x60000010ULL,
|
||||
.cs = (struct kvm_segment) {
|
||||
.selector = 0xf000UL,
|
||||
.selector = 0xfff0UL,
|
||||
.base = 0xffff0000UL,
|
||||
.limit = 0xffffU,
|
||||
.type = 0x0bU,
|
||||
@@ -265,6 +277,19 @@ void kvm__reset_vcpu(struct kvm *self, uint64_t rip)
|
||||
|
||||
if (ioctl(self->vcpu_fd, KVM_SET_SREGS, &self->sregs) < 0)
|
||||
die_perror("KVM_SET_SREGS failed");
|
||||
|
||||
self->regs = (struct kvm_regs) {
|
||||
/* We start the guest in 16-bit real mode */
|
||||
.rip = ip_flat_to_real(self, rip),
|
||||
.rflags = 0x0000000000000002ULL,
|
||||
};
|
||||
|
||||
if (self->regs.rip > USHRT_MAX)
|
||||
die("ip 0x%" PRIx64 " is too high for real mode", (uint64_t) self->regs.rip);
|
||||
|
||||
if (ioctl(self->vcpu_fd, KVM_SET_REGS, &self->regs) < 0)
|
||||
die_perror("KVM_SET_REGS failed");
|
||||
|
||||
}
|
||||
|
||||
void kvm__run(struct kvm *self)
|
||||
@@ -368,14 +393,14 @@ void kvm__show_code(struct kvm *self)
|
||||
unsigned int i;
|
||||
uint8_t *ip;
|
||||
|
||||
ip = guest_addr_to_host(self, self->regs.rip - code_prologue);
|
||||
ip = guest_addr_to_host(self, ip_real_to_flat(self, self->regs.rip) - code_prologue);
|
||||
|
||||
printf("Code: ");
|
||||
|
||||
for (i = 0; i < code_len; i++, ip++) {
|
||||
c = *ip;
|
||||
|
||||
if (ip == guest_addr_to_host(self, self->regs.rip))
|
||||
if (ip == guest_addr_to_host(self, ip_real_to_flat(self, self->regs.rip)))
|
||||
printf("<%02x> ", c);
|
||||
else
|
||||
printf("%02x ", c);
|
||||
|
||||
Reference in New Issue
Block a user