This commit is contained in:
'mr software' 2024-01-30 23:10:15 -08:00
parent ed75530a63
commit 7f63992386
6 changed files with 1358 additions and 1135 deletions

1
build Executable file
View File

@ -0,0 +1 @@
cc -Iinc src/*.c -o dpvm

36
inc/mz.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef MZ_H
#define MZ_H
#include <stdint.h>
#include <string.h>
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;
uint32_t loadmz(mz*, uint8_t*, uint32_t, uint32_t, mz_start*);
#endif

BIN
it/IT.EXE

Binary file not shown.

2216
it/IT.MAP

File diff suppressed because it is too large Load Diff

59
src/mz.c Normal file
View File

@ -0,0 +1,59 @@
#include <mz.h>
#include <stdio.h>
#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(
"mz\t%04X\n"
"bytes\t%u\n"
"pages\t%u\n"
"relsz\t%u\n"
"len\t%u\n"
"minall\t%u\n"
"maxall\t%u\n"
"ss\t%04X\n"
"sp\t%04X\n"
"sum\t%04X\n"
"ip\t%04X\n"
"cs\t%04X\n"
"rel*\t%04X\n"
"overlay\t%u\n"
,m->mz
,m->bytes
,m->pages
,m->relsz
,m->len
,m->minalloc
,m->maxalloc
,m->ss
,m->sp
,m->sum
,m->ip
,m->cs
,m->rel
,m->overlay
);*/
uint32_t sz = (((uint32_t)m->pages-1) << 9) + (m->bytes ? m->bytes : 512) - (m->len << 4);
memcpy( // copy mz to memory
mem + (seg << 4),
m8 + (m->len << 4),
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;
*z = (mz_start) {
m->ss+seg,
m->sp,
m->ip,
m->cs+seg
};
}

127
src/vm.c Normal file
View File

@ -0,0 +1,127 @@
#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 <errno.h>
#include <fcntl.h>
#include <mz.h>
#define MSIZE 0x100000 // size of conventional memory
/* 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
*/
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, s.st_size, 0x40, &ms);
free(mzbuf);
printf("done\n");
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.cr0 = 0;
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,
};
mem[((uint32_t)ms.cs << 4) + ms.ip] = 0xF4; // hlt
ioctl(vcpufd, KVM_SET_REGS, &regs);
printf("begin vm\n");
while(1) {
errno = 0;
ret = ioctl(vcpufd, KVM_RUN, NULL);
if(ret == -1) exit(!!printf("kvm error: %s\n", strerror(errno)));
switch (run->exit_reason) {
case KVM_EXIT_HLT:
exit(!printf("got instruction `hlt`, exiting\n"));
break;
case KVM_EXIT_IO:
break;
case KVM_EXIT_INTR:
break;
case KVM_EXIT_INTERNAL_ERROR:
exit(printf("internal error %u\n", run->internal.suberror));
break;
default:
exit(printf("vmexit %u\n", run->exit_reason));
break;
}
}
}