final kvm version
This commit is contained in:
parent
7f63992386
commit
d620d35017
1
inc/mz.h
1
inc/mz.h
|
@ -24,7 +24,6 @@ typedef struct { // no endian checks - this will only work on x86+vm anyway
|
||||||
cs,
|
cs,
|
||||||
rel, // pointer to
|
rel, // pointer to
|
||||||
overlay; // zero if main binary
|
overlay; // zero if main binary
|
||||||
reloc r[];
|
|
||||||
} __attribute__((packed)) mz;
|
} __attribute__((packed)) mz;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
63
mzload.c
63
mzload.c
|
@ -1,63 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* x86 memory map
|
|
||||||
0x00000 - 0x003FF IVT 0x400
|
|
||||||
0x00400 - 0x9FFFF FREE 0x9FC00
|
|
||||||
0xA0000 - 0xBFFFF VGA 0x20000
|
|
||||||
0xC0000 - 0xFFFFF FREE 0x40000
|
|
||||||
|
|
||||||
total freemem - 0xDFC00 - 916480 bytes/895.0K
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct { // pointer into program data into which load segment is added
|
|
||||||
uint16_t offset,
|
|
||||||
segment;
|
|
||||||
} __attribute__((packed)) reloc;
|
|
||||||
|
|
||||||
typedef struct { // no endian checks - this will only work on x86+vm anyway
|
|
||||||
uint16_t mz,
|
|
||||||
bytes,
|
|
||||||
pages,
|
|
||||||
relsz,
|
|
||||||
len,
|
|
||||||
minalloc, // can easily ignore - we have 895k free
|
|
||||||
maxalloc,
|
|
||||||
ss,
|
|
||||||
sp,
|
|
||||||
sum,
|
|
||||||
ip,
|
|
||||||
cs,
|
|
||||||
rel, // pointer to
|
|
||||||
overlay; // zero if main binary
|
|
||||||
reloc r[];
|
|
||||||
} __attribute__((packed)) mz;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t ss, sp, ip, cs;
|
|
||||||
} mz_start;
|
|
||||||
|
|
||||||
#define m8 ((uint8_t*)m) // access mz by byte
|
|
||||||
uint32_t loadmz(mz* m, uint8_t* mem, uint32_t seg, mz_start* m) {
|
|
||||||
|
|
||||||
uint32_t sz = (((uint32_t)m->pages) << 9) + m->bytes;
|
|
||||||
memcpy( // copy mz to memory
|
|
||||||
mem + (seg << 4),
|
|
||||||
m8 + (m->len << 4),
|
|
||||||
sz
|
|
||||||
);
|
|
||||||
|
|
||||||
for(int i = 0; i < m->relsz; i++) *(uint16_t*)(
|
|
||||||
m8 +
|
|
||||||
(seg << 4) +
|
|
||||||
((uint32_t)m->r[i].segment << 4) +
|
|
||||||
(uint32_t)m->r[i].offset
|
|
||||||
) += seg;
|
|
||||||
|
|
||||||
*m = (mz_start) {
|
|
||||||
m->ss+seg,
|
|
||||||
m->sp,
|
|
||||||
m->ip,
|
|
||||||
m->cs+seg
|
|
||||||
};
|
|
||||||
}
|
|
16
src/mz.c
16
src/mz.c
|
@ -4,7 +4,7 @@
|
||||||
#define m8 ((uint8_t*)m) // access mz by byte
|
#define m8 ((uint8_t*)m) // access mz by byte
|
||||||
uint32_t loadmz(mz* m, uint8_t* mem, uint32_t xsz, uint32_t seg, mz_start* z) {
|
uint32_t loadmz(mz* m, uint8_t* mem, uint32_t xsz, uint32_t seg, mz_start* z) {
|
||||||
|
|
||||||
/*printf(
|
printf(
|
||||||
"mz\t%04X\n"
|
"mz\t%04X\n"
|
||||||
"bytes\t%u\n"
|
"bytes\t%u\n"
|
||||||
"pages\t%u\n"
|
"pages\t%u\n"
|
||||||
|
@ -33,7 +33,7 @@ uint32_t loadmz(mz* m, uint8_t* mem, uint32_t xsz, uint32_t seg, mz_start* z) {
|
||||||
,m->cs
|
,m->cs
|
||||||
,m->rel
|
,m->rel
|
||||||
,m->overlay
|
,m->overlay
|
||||||
);*/
|
);
|
||||||
|
|
||||||
uint32_t sz = (((uint32_t)m->pages-1) << 9) + (m->bytes ? m->bytes : 512) - (m->len << 4);
|
uint32_t sz = (((uint32_t)m->pages-1) << 9) + (m->bytes ? m->bytes : 512) - (m->len << 4);
|
||||||
|
|
||||||
|
@ -43,12 +43,12 @@ uint32_t loadmz(mz* m, uint8_t* mem, uint32_t xsz, uint32_t seg, mz_start* z) {
|
||||||
sz
|
sz
|
||||||
);
|
);
|
||||||
|
|
||||||
for(int i = 0; i < m->relsz; i++) *(uint16_t*)(
|
reloc* r = (reloc*)(m8 + m->rel);
|
||||||
mem +
|
for(int i = 0; i < m->relsz; i++) {
|
||||||
(seg << 4) +
|
uint32_t off = (seg << 4) + ((uint32_t)r[i].segment << 4) + (uint32_t)r[i].offset;
|
||||||
((uint32_t)m->r[i].segment << 4) +
|
printf("relocate %04X:%04X (%04X -> %04X)\n", r[i].segment, r[i].offset, *(uint16_t*)(mem + off), *(uint16_t*)(mem + off) + seg);
|
||||||
(uint32_t)m->r[i].offset
|
*(uint16_t*)(mem + off) += seg;
|
||||||
) += seg;
|
}
|
||||||
|
|
||||||
*z = (mz_start) {
|
*z = (mz_start) {
|
||||||
m->ss+seg,
|
m->ss+seg,
|
||||||
|
|
29
src/vm.c
29
src/vm.c
|
@ -34,6 +34,7 @@ int main(int argc, char** argv) {
|
||||||
int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
|
int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
|
||||||
|
|
||||||
assert((ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) ^ ioctl(kvm, KVM_GET_API_VERSION, NULL)) == 13);
|
assert((ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) ^ ioctl(kvm, KVM_GET_API_VERSION, NULL)) == 13);
|
||||||
|
assert(ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_EXIT_ON_EMULATION_FAILURE));
|
||||||
|
|
||||||
int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0),
|
int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0),
|
||||||
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0),
|
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0),
|
||||||
|
@ -41,12 +42,15 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
uint8_t* mem = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // allocate conventional memory for vm
|
uint8_t* mem = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // allocate conventional memory for vm
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; i++) ((reloc*)mem)[i] = (reloc){0xFF00 | i, 0xF000};
|
||||||
|
|
||||||
mz* mzbuf = malloc(s.st_size);
|
mz* mzbuf = malloc(s.st_size);
|
||||||
read(codefd, mzbuf, s.st_size);
|
read(codefd, mzbuf, s.st_size);
|
||||||
close(codefd);
|
close(codefd);
|
||||||
|
|
||||||
mz_start ms;
|
mz_start ms;
|
||||||
uint32_t mzsz = loadmz(mzbuf, mem, s.st_size, 0x40, &ms);
|
uint32_t mzsz = loadmz(mzbuf, mem, s.st_size, 0x40, &ms);
|
||||||
|
//for(int i = 0; i < MSIZE; i++) mem[i] = 0xCC; // hlt cookie
|
||||||
free(mzbuf);
|
free(mzbuf);
|
||||||
|
|
||||||
printf("done\n");
|
printf("done\n");
|
||||||
|
@ -64,7 +68,7 @@ int main(int argc, char** argv) {
|
||||||
},*/
|
},*/
|
||||||
{
|
{
|
||||||
.guest_phys_addr = 0xC0000,
|
.guest_phys_addr = 0xC0000,
|
||||||
.memory_size = 0x40000,
|
.memory_size = 0x40000 - 256, // leave 256b unmapped for interrupt trap
|
||||||
.userspace_addr = (uint64_t)mem + 0xC0000,
|
.userspace_addr = (uint64_t)mem + 0xC0000,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -81,14 +85,14 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_GET_SREGS, &sregs);
|
ioctl(vcpufd, KVM_GET_SREGS, &sregs);
|
||||||
|
|
||||||
|
sregs.cs.selector = 0; // probably protected mode related?
|
||||||
|
sregs.ss.selector = 0;
|
||||||
|
|
||||||
sregs.cs.base = ms.cs;
|
sregs.cs.base = ms.cs;
|
||||||
sregs.ss.base = ms.ss;
|
sregs.ss.base = ms.ss;
|
||||||
|
|
||||||
sregs.cr0 = 0;
|
sregs.cr0 = 0;
|
||||||
|
|
||||||
sregs.cs.selector = 0; // probably protected mode related?
|
|
||||||
sregs.ss.selector = 0;
|
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_SET_SREGS, &sregs);
|
ioctl(vcpufd, KVM_SET_SREGS, &sregs);
|
||||||
|
|
||||||
struct kvm_regs regs = {
|
struct kvm_regs regs = {
|
||||||
|
@ -97,7 +101,9 @@ int main(int argc, char** argv) {
|
||||||
.rflags = 0x2,
|
.rflags = 0x2,
|
||||||
};
|
};
|
||||||
|
|
||||||
mem[((uint32_t)ms.cs << 4) + ms.ip] = 0xF4; // hlt
|
printf("try start ex at %07X (%04X:%04X)\n", ((uint32_t)ms.cs << 4) + ms.ip, ms.cs, ms.ip);
|
||||||
|
|
||||||
|
//mem[((uint32_t)ms.cs << 4) + ms.ip] = 0xF4; // hlt
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_SET_REGS, ®s);
|
ioctl(vcpufd, KVM_SET_REGS, ®s);
|
||||||
|
|
||||||
|
@ -107,20 +113,27 @@ int main(int argc, char** argv) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ret = ioctl(vcpufd, KVM_RUN, NULL);
|
ret = ioctl(vcpufd, KVM_RUN, NULL);
|
||||||
if(ret == -1) exit(!!printf("kvm error: %s\n", strerror(errno)));
|
if(ret == -1) exit(!!printf("kvm error: %s\n", strerror(errno)));
|
||||||
|
|
||||||
|
ioctl(vcpufd, KVM_GET_SREGS, &sregs);
|
||||||
|
ioctl(vcpufd, KVM_GET_REGS, ®s);
|
||||||
|
|
||||||
|
printf("vm exit at (%04X:%04X)\n", sregs.cs.base, regs.rip);
|
||||||
|
|
||||||
switch (run->exit_reason) {
|
switch (run->exit_reason) {
|
||||||
case KVM_EXIT_HLT:
|
case KVM_EXIT_HLT:
|
||||||
exit(!printf("got instruction `hlt`, exiting\n"));
|
exit(!printf("got instruction `hlt`, exiting\n"));
|
||||||
break;
|
break;
|
||||||
case KVM_EXIT_IO:
|
case KVM_EXIT_IO:
|
||||||
|
exit(!printf("try io 0x%03X\n", run->io.port));
|
||||||
break;
|
break;
|
||||||
case KVM_EXIT_INTR:
|
case KVM_EXIT_INTR:
|
||||||
|
exit(!printf("try execute interrupt %02X\n", mem[((uint32_t)ms.cs << 4) + ms.ip + 1]));
|
||||||
break;
|
break;
|
||||||
case KVM_EXIT_INTERNAL_ERROR:
|
case KVM_EXIT_INTERNAL_ERROR:
|
||||||
exit(printf("internal error %u\n", run->internal.suberror));
|
exit(!printf("internal error %u with isn size %u\n", run->emulation_failure.suberror, run->emulation_failure.insn_size));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
exit(printf("vmexit %u\n", run->exit_reason));
|
exit(!printf("vmexit %u\n", run->exit_reason));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
100
vm.c
100
vm.c
|
@ -1,100 +0,0 @@
|
||||||
#include <linux/kvm.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#define MSIZE 0x10000 // size of conventional memory
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
|
|
||||||
struct stat s;
|
|
||||||
int ret = stat(argv[1], &s);
|
|
||||||
if(ret) exit(!!printf("invalid file!\n"));
|
|
||||||
|
|
||||||
int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
|
|
||||||
|
|
||||||
assert((ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) ^ ioctl(kvm, KVM_GET_API_VERSION, NULL)) == 13);
|
|
||||||
|
|
||||||
int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0),
|
|
||||||
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0),
|
|
||||||
codefd = open(argv[1], O_RDONLY); // load boot sector from file
|
|
||||||
|
|
||||||
uint8_t* mem = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // allocate conventional memory for vm
|
|
||||||
|
|
||||||
mz* mzbuf = malloc(s.st_size);
|
|
||||||
read(codefd, mzbuf, s.st_size);
|
|
||||||
close(codefd);
|
|
||||||
|
|
||||||
mz_start ms;
|
|
||||||
uint32_t mzsz = loadmz(mzbuf, mem, 0x40, &ms);
|
|
||||||
|
|
||||||
struct kvm_userspace_memory_region memmap[2] = {
|
|
||||||
{
|
|
||||||
.guest_phys_addr = 0,
|
|
||||||
.memory_size = 0xA0000,
|
|
||||||
.userspace_addr = (uint64_t)mem,
|
|
||||||
},
|
|
||||||
/*{ // implied map
|
|
||||||
.guest_phys_addr = 0xA0000,
|
|
||||||
.memory_size = 0x20000,
|
|
||||||
.userspace_addr = (uint64_t)mem,
|
|
||||||
},*/
|
|
||||||
{
|
|
||||||
.guest_phys_addr = 0xC0000,
|
|
||||||
.memory_size = 0x40000,
|
|
||||||
.userspace_addr = (uint64_t)mem + 0xC0000,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
memmap[i].slot = i; // id of memory mapping
|
|
||||||
ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, memmap[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct kvm_sregs sregs;
|
|
||||||
struct kvm_run* run;
|
|
||||||
size_t run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL); // size of struct is. determined at runtime for some reason?
|
|
||||||
run = mmap(NULL, run_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
|
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_GET_SREGS, &sregs);
|
|
||||||
|
|
||||||
sregs.cs.base = ms.cs;
|
|
||||||
sregs.ss.base = ms.ss;
|
|
||||||
|
|
||||||
sregs.cs.selector = 0; // probably protected mode related?
|
|
||||||
sregs.ss.selector = 0;
|
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_SET_SREGS, &sregs);
|
|
||||||
|
|
||||||
struct kvm_regs regs = {
|
|
||||||
.rip = ms.ip,
|
|
||||||
.rsp = ms.sp,
|
|
||||||
.rflags = 0x2,
|
|
||||||
};
|
|
||||||
|
|
||||||
ioctl(vcpufd, KVM_SET_REGS, ®s);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
ret = ioctl(vcpufd, KVM_RUN, NULL);
|
|
||||||
if(ret == -1) exit(!!printf("kvm error\n"));
|
|
||||||
switch (run->exit_reason) {
|
|
||||||
case KVM_EXIT_HLT:
|
|
||||||
exit(!printf("got instruction `hlt`, exiting\n"));
|
|
||||||
break;
|
|
||||||
case KVM_EXIT_IO:
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
exit(printf("vmexit\n"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue