From d620d35017dcb4d1ce84b1b7fa2f575669568c03 Mon Sep 17 00:00:00 2001 From: mothcompute Date: Wed, 31 Jan 2024 19:25:53 -0800 Subject: [PATCH] final kvm version --- inc/mz.h | 1 - mzload.c | 63 ----------------------------------- src/mz.c | 16 ++++----- src/vm.c | 29 +++++++++++----- vm.c | 100 ------------------------------------------------------- 5 files changed, 29 insertions(+), 180 deletions(-) delete mode 100644 mzload.c delete mode 100644 vm.c diff --git a/inc/mz.h b/inc/mz.h index 1e05b0b..814ff07 100644 --- a/inc/mz.h +++ b/inc/mz.h @@ -24,7 +24,6 @@ typedef struct { // no endian checks - this will only work on x86+vm anyway cs, rel, // pointer to overlay; // zero if main binary - reloc r[]; } __attribute__((packed)) mz; typedef struct { diff --git a/mzload.c b/mzload.c deleted file mode 100644 index d913033..0000000 --- a/mzload.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -/* 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 - }; -} diff --git a/src/mz.c b/src/mz.c index c500f83..a0ddf68 100644 --- a/src/mz.c +++ b/src/mz.c @@ -4,7 +4,7 @@ #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) { - /*printf( + printf( "mz\t%04X\n" "bytes\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->rel ,m->overlay - );*/ + ); 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 ); - for(int i = 0; i < m->relsz; i++) *(uint16_t*)( - mem + - (seg << 4) + - ((uint32_t)m->r[i].segment << 4) + - (uint32_t)m->r[i].offset - ) += seg; + reloc* r = (reloc*)(m8 + m->rel); + for(int i = 0; i < m->relsz; i++) { + uint32_t off = (seg << 4) + ((uint32_t)r[i].segment << 4) + (uint32_t)r[i].offset; + printf("relocate %04X:%04X (%04X -> %04X)\n", r[i].segment, r[i].offset, *(uint16_t*)(mem + off), *(uint16_t*)(mem + off) + seg); + *(uint16_t*)(mem + off) += seg; + } *z = (mz_start) { m->ss+seg, diff --git a/src/vm.c b/src/vm.c index 97ba3f2..aae5266 100644 --- a/src/vm.c +++ b/src/vm.c @@ -34,6 +34,7 @@ int main(int argc, char** argv) { 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_EXIT_ON_EMULATION_FAILURE)); int vmfd = ioctl(kvm, KVM_CREATE_VM, (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 + for(int i = 0; i < 256; i++) ((reloc*)mem)[i] = (reloc){0xFF00 | i, 0xF000}; + mz* mzbuf = malloc(s.st_size); read(codefd, mzbuf, s.st_size); close(codefd); mz_start 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); printf("done\n"); @@ -64,7 +68,7 @@ int main(int argc, char** argv) { },*/ { .guest_phys_addr = 0xC0000, - .memory_size = 0x40000, + .memory_size = 0x40000 - 256, // leave 256b unmapped for interrupt trap .userspace_addr = (uint64_t)mem + 0xC0000, }, }; @@ -81,14 +85,14 @@ int main(int argc, char** argv) { ioctl(vcpufd, KVM_GET_SREGS, &sregs); + sregs.cs.selector = 0; // probably protected mode related? + sregs.ss.selector = 0; + sregs.cs.base = ms.cs; sregs.ss.base = ms.ss; sregs.cr0 = 0; - sregs.cs.selector = 0; // probably protected mode related? - sregs.ss.selector = 0; - ioctl(vcpufd, KVM_SET_SREGS, &sregs); struct kvm_regs regs = { @@ -97,7 +101,9 @@ int main(int argc, char** argv) { .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); @@ -107,20 +113,27 @@ int main(int argc, char** argv) { errno = 0; ret = ioctl(vcpufd, KVM_RUN, NULL); 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) { case KVM_EXIT_HLT: exit(!printf("got instruction `hlt`, exiting\n")); break; case KVM_EXIT_IO: - + exit(!printf("try io 0x%03X\n", run->io.port)); break; case KVM_EXIT_INTR: + exit(!printf("try execute interrupt %02X\n", mem[((uint32_t)ms.cs << 4) + ms.ip + 1])); break; 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; default: - exit(printf("vmexit %u\n", run->exit_reason)); + exit(!printf("vmexit %u\n", run->exit_reason)); break; } } diff --git a/vm.c b/vm.c deleted file mode 100644 index f96c921..0000000 --- a/vm.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; - } - } -}