提交 225bd41f 编写于 作者: Z Zihao Yu

x86: add kvm support

上级 2f1c8be6
......@@ -18,14 +18,14 @@ void add_pio_map(char *name, ioaddr_t addr, uint8_t *space, int len, io_callback
nr_map ++;
}
static inline uint32_t pio_read_common(ioaddr_t addr, int len) {
uint32_t pio_read_common(ioaddr_t addr, int len) {
assert(addr + len - 1 < PORT_IO_SPACE_MAX);
int mapid = find_mapid_by_addr(maps, nr_map, addr);
assert(mapid != -1);
return map_read(addr, len, &maps[mapid]);
}
static inline void pio_write_common(ioaddr_t addr, uint32_t data, int len) {
void pio_write_common(ioaddr_t addr, uint32_t data, int len) {
assert(addr + len - 1 < PORT_IO_SPACE_MAX);
int mapid = find_mapid_by_addr(maps, nr_map, addr);
assert(mapid != -1);
......
......@@ -193,8 +193,13 @@ static make_EHelper(2byte_esc) {
}
void isa_exec(vaddr_t *pc) {
#ifdef USE_KVM
extern void kvm_exec(void);
kvm_exec();
#else
uint32_t opcode = instr_fetch(pc, 1);
decinfo.opcode = opcode;
set_width(opcode_table[opcode].width);
idex(pc, &opcode_table[opcode]);
#endif
}
#include "nemu.h"
#include "cpu/exec.h"
#include "monitor/monitor.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/kvm.h>
extern uint32_t pio_read_common(ioaddr_t addr, int len);
extern void pio_write_common(ioaddr_t addr, uint32_t data, int len);
/* CR0 bits */
#define CR0_PE 1u
struct vm {
int sys_fd;
int fd;
char *mem;
};
void vm_init(struct vm *vm, size_t mem_size) {
int api_ver;
struct kvm_userspace_memory_region memreg;
vm->sys_fd = open("/dev/kvm", O_RDWR);
if (vm->sys_fd < 0) {
perror("open /dev/kvm");
assert(0);
}
api_ver = ioctl(vm->sys_fd, KVM_GET_API_VERSION, 0);
if (api_ver < 0) {
perror("KVM_GET_API_VERSION");
assert(0);
}
if (api_ver != KVM_API_VERSION) {
fprintf(stderr, "Got KVM api version %d, expected %d\n",
api_ver, KVM_API_VERSION);
assert(0);
}
vm->fd = ioctl(vm->sys_fd, KVM_CREATE_VM, 0);
if (vm->fd < 0) {
perror("KVM_CREATE_VM");
assert(0);
}
if (ioctl(vm->fd, KVM_SET_TSS_ADDR, 0xfffbd000) < 0) {
perror("KVM_SET_TSS_ADDR");
assert(0);
}
vm->mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
if (vm->mem == MAP_FAILED) {
perror("mmap mem");
assert(0);
}
madvise(vm->mem, mem_size, MADV_MERGEABLE);
memreg.slot = 0;
memreg.flags = 0;
memreg.guest_phys_addr = 0;
memreg.memory_size = mem_size;
memreg.userspace_addr = (unsigned long)vm->mem;
if (ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, &memreg) < 0) {
perror("KVM_SET_USER_MEMORY_REGION");
assert(0);
}
}
struct vcpu {
int fd;
struct kvm_run *kvm_run;
};
void vcpu_init(struct vm *vm, struct vcpu *vcpu) {
int vcpu_mmap_size;
vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, 0);
if (vcpu->fd < 0) {
perror("KVM_CREATE_VCPU");
assert(0);
}
vcpu_mmap_size = ioctl(vm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
if (vcpu_mmap_size <= 0) {
perror("KVM_GET_VCPU_MMAP_SIZE");
assert(0);
}
vcpu->kvm_run = mmap(NULL, vcpu_mmap_size, PROT_READ | PROT_WRITE,
MAP_SHARED, vcpu->fd, 0);
if (vcpu->kvm_run == MAP_FAILED) {
perror("mmap kvm_run");
assert(0);
}
}
int run_vm(struct vm *vm, struct vcpu *vcpu, size_t sz) {
struct kvm_regs regs;
for (;;) {
if (ioctl(vcpu->fd, KVM_RUN, 0) < 0) {
if (errno == EINTR) continue;
perror("KVM_RUN");
assert(0);
}
switch (vcpu->kvm_run->exit_reason) {
case KVM_EXIT_HLT:
if (ioctl(vcpu->fd, KVM_GET_REGS, &regs) < 0) {
perror("KVM_GET_REGS");
assert(0);
}
rtl_exit(NEMU_END, regs.rip, regs.rax);
return 0;
case KVM_EXIT_IO: {
struct kvm_run *p = vcpu->kvm_run;
uint8_t *p_data = (uint8_t *)p + p->io.data_offset;
if (p->io.direction == KVM_EXIT_IO_OUT) {
pio_write_common(p->io.port, *(uint32_t *)p_data, p->io.size);
}
else {
// FIXME
*(uint32_t *)p_data = pio_read_common(p->io.port, p->io.size);
}
continue;
}
/* fall through */
default:
fprintf(stderr, "Got exit_reason %d,"
" expected KVM_EXIT_HLT (%d)\n",
vcpu->kvm_run->exit_reason, KVM_EXIT_HLT);
assert(0);
}
}
}
static void setup_protected_mode(struct kvm_sregs *sregs) {
struct kvm_segment seg = {
.base = 0,
.limit = 0xffffffff,
.selector = 1 << 3,
.present = 1,
.type = 11, /* Code: execute, read, accessed */
.dpl = 0,
.db = 1,
.s = 1, /* Code/data */
.l = 0,
.g = 1, /* 4KB granularity */
};
sregs->cr0 |= CR0_PE; /* enter protected mode */
sregs->cs = seg;
seg.type = 3; /* Data: read/write, accessed */
seg.selector = 2 << 3;
sregs->ds = sregs->es = sregs->fs = sregs->gs = sregs->ss = seg;
}
int run_protected_mode(struct vm *vm, struct vcpu *vcpu) {
struct kvm_sregs sregs;
struct kvm_regs regs;
if (ioctl(vcpu->fd, KVM_GET_SREGS, &sregs) < 0) {
perror("KVM_GET_SREGS");
assert(0);
}
setup_protected_mode(&sregs);
if (ioctl(vcpu->fd, KVM_SET_SREGS, &sregs) < 0) {
perror("KVM_SET_SREGS");
assert(0);
}
memset(&regs, 0, sizeof(regs));
/* Clear all FLAGS bits, except bit 1 which is always set. */
regs.rflags = 2;
regs.rip = 0;
if (ioctl(vcpu->fd, KVM_SET_REGS, &regs) < 0) {
perror("KVM_SET_REGS");
assert(0);
}
memcpy(vm->mem, pmem, PMEM_SIZE);
return run_vm(vm, vcpu, 4);
}
void kvm_exec() {
struct vm vm;
struct vcpu vcpu;
vm_init(&vm, PMEM_SIZE);
vcpu_init(&vm, &vcpu);
run_protected_mode(&vm, &vcpu);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册