From 5c0bff4ba204cfad7aedb8c1c20f1c29265dcb01 Mon Sep 17 00:00:00 2001 From: aiju Date: Wed, 21 Jun 2017 22:18:26 +0000 Subject: vmx(1): add support for (so far) crude 9p debugging fs; add gdb stub; clean up linux gdt code --- sys/src/cmd/vmx/9p.c | 65 ++++++++++++ sys/src/cmd/vmx/dat.h | 9 +- sys/src/cmd/vmx/exith.c | 10 +- sys/src/cmd/vmx/fns.h | 1 + sys/src/cmd/vmx/io.c | 3 +- sys/src/cmd/vmx/ksetup.c | 34 +++---- sys/src/cmd/vmx/mkfile | 10 ++ sys/src/cmd/vmx/vmx.c | 14 ++- sys/src/cmd/vmx/vmxgdb.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++ sys/src/cmd/vmx/x86.c | 124 +++++++++++++++++++++++ sys/src/cmd/vmx/x86.h | 29 ++++++ 11 files changed, 531 insertions(+), 27 deletions(-) create mode 100644 sys/src/cmd/vmx/9p.c create mode 100644 sys/src/cmd/vmx/vmxgdb.c create mode 100644 sys/src/cmd/vmx/x86.c create mode 100644 sys/src/cmd/vmx/x86.h diff --git a/sys/src/cmd/vmx/9p.c b/sys/src/cmd/vmx/9p.c new file mode 100644 index 000000000..69cc744f2 --- /dev/null +++ b/sys/src/cmd/vmx/9p.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include <9p.h> +#include "dat.h" +#include "fns.h" + +extern int regsfd; +char Egreg[] = "the front fell off"; + +enum { + Qregs, + Qmem, + Qmax +}; + +static Dir files[] = { + [Qregs] {.name "regs", .mode 0440}, + [Qmem] {.name "mem", .mode 0440}, +}; + +void +srvread(Req *r) +{ + int rc; + + switch(r->fid->qid.path){ + case Qregs: + rc = pread(regsfd, r->ofcall.data, r->ifcall.count, r->ifcall.offset); + if(rc < 0) + responderror(r); + else{ + r->ofcall.count = rc; + respond(r, nil); + } + break; + case Qmem: + r->ofcall.count = vmemread(r->ofcall.data, r->ifcall.count, r->ifcall.offset); + if(r->ofcall.count == 0) + respond(r, "fault"); + else + respond(r, nil); + break; + default: + respond(r, Egreg); + } +} + +Srv vmxsrv = { + .read srvread, +}; + +void +init9p(char *srvname) +{ + char *uid; + int i; + + uid = getuser(); + vmxsrv.tree = alloctree(uid, uid, 0770, nil); + for(i = 0; i < Qmax; i++) + createfile(vmxsrv.tree->root, files[i].name, uid, files[i].mode, nil); + threadpostmountsrv(&vmxsrv, srvname, nil, 0); +} diff --git a/sys/src/cmd/vmx/dat.h b/sys/src/cmd/vmx/dat.h index 156fdaa58..f34fd3164 100644 --- a/sys/src/cmd/vmx/dat.h +++ b/sys/src/cmd/vmx/dat.h @@ -3,7 +3,14 @@ typedef struct PCICap PCICap; typedef struct PCIBar PCIBar; typedef struct Region Region; -extern int halt, irqactive; +extern int irqactive; + +enum { + VMRUNNING, + VMHALT, + VMDEAD, +}; +extern int state; enum { BY2PG = 4096 diff --git a/sys/src/cmd/vmx/exith.c b/sys/src/cmd/vmx/exith.c index 939763dcd..69aba6bac 100644 --- a/sys/src/cmd/vmx/exith.c +++ b/sys/src/cmd/vmx/exith.c @@ -5,6 +5,8 @@ #include "dat.h" #include "fns.h" +int persist = 0; + typedef struct ExitInfo ExitInfo; struct ExitInfo { char *raw; @@ -407,7 +409,7 @@ static void hlt(ExitInfo *ei) { if(irqactive == 0) - halt = 1; + state = VMHALT; skipinstr(ei); } @@ -484,5 +486,9 @@ processexit(char *msg) vmerror("vmx: unknown notification %s", f[0]+1); return; } - sysfatal("unknown exit: %s", msg); + if(persist){ + vmerror("unknown exit: %s", msg); + state = VMDEAD; + }else + sysfatal("unknown exit: %s", msg); } diff --git a/sys/src/cmd/vmx/fns.h b/sys/src/cmd/vmx/fns.h index cff97b0af..f37a6512d 100644 --- a/sys/src/cmd/vmx/fns.h +++ b/sys/src/cmd/vmx/fns.h @@ -43,3 +43,4 @@ void i8042kick(void *); u32int roundpow2(u32int); u32int vgagetpal(u8int); void vgasetpal(u8int, u32int); +uintptr vmemread(void *, uintptr, uintptr); diff --git a/sys/src/cmd/vmx/io.c b/sys/src/cmd/vmx/io.c index 6579a1e93..a61347248 100644 --- a/sys/src/cmd/vmx/io.c +++ b/sys/src/cmd/vmx/io.c @@ -202,7 +202,8 @@ picupdate(Pic *p) if(m != 0 && irqactive != n){ if(ctl("irq %d", n) < 0) sysfatal("ctl: %r"); - halt = 0; + if(state == VMHALT) + state = VMRUNNING; irqactive = n; }else if(m == 0 && irqactive >= 0){ if(ctl("irq") < 0) diff --git a/sys/src/cmd/vmx/ksetup.c b/sys/src/cmd/vmx/ksetup.c index 3e2ee742f..d3a17e1bc 100644 --- a/sys/src/cmd/vmx/ksetup.c +++ b/sys/src/cmd/vmx/ksetup.c @@ -5,6 +5,7 @@ #include #include "dat.h" #include "fns.h" +#include "x86.h" static uchar hdr[8192]; static int fd; @@ -789,20 +790,6 @@ linuxscreeninfo(void *zp) } } -enum { - GDTRW = 2<<8, - GDTRX = 10<<8, - GDTS = 1<<12, - GDTP = 1<<15, - GDT64 = 1<<21, - GDT32 = 1<<22, - GDTG = 1<<23, -}; -#define GDTLIM0(l) ((l) & 0x0ffff) -#define GDTLIM1(l) ((l) & 0xf0000) -#define GDTBASE0(b) ((b) << 16) -#define GDTBASE1(b) ((b) >> 16 & 0xff | (b) & 0xff000000) - static void linuxgdt(void *v) { @@ -810,10 +797,10 @@ linuxgdt(void *v) base = gpa(v); rset("gdtrbase", base); - v = pack(v, "ii", 0, 0); - v = pack(v, "ii", 0, 0); - v = pack(v, "ii", GDTLIM0(-1) | GDTBASE0(0), GDTLIM1(-1) | GDTBASE1(0) | GDTRX | GDTG | GDTS | GDTP | GDT32); - v = pack(v, "ii", GDTLIM0(-1) | GDTBASE0(0), GDTLIM1(-1) | GDTBASE1(0) | GDTRW | GDTG | GDTS | GDTP | GDT32); + v = pack(v, "vvvv", 0, 0, + GDTBASE(0) | GDTLIM(-1) | GDTRX | GDTG | GDTP | GDT32, + GDTBASE(0) | GDTLIM(-1) | GDTRW | GDTG | GDTP | GDT32 + ); rset("gdtrlimit", gpa(v) - base - 1); rset("cs", 0x10); rset("ds", 0x18); @@ -914,6 +901,7 @@ trylinux(void) return 1; } + void loadkernel(char *fn) { @@ -921,7 +909,13 @@ loadkernel(char *fn) if(fd < 0) sysfatal("open: %r"); if(readn(fd, hdr, sizeof(hdr)) <= 0) sysfatal("readn: %r"); - if(!trymultiboot() && !tryelf() && !trylinux()) - sysfatal("%s: unknown format", fn); + if(trymultiboot()) + goto done; + if(tryelf()) + goto done; + if(trylinux()) + goto done; + sysfatal("%s: unknown format", fn); +done: close(fd); } diff --git a/sys/src/cmd/vmx/mkfile b/sys/src/cmd/vmx/mkfile index be1860dc2..bc2478a85 100644 --- a/sys/src/cmd/vmx/mkfile +++ b/sys/src/cmd/vmx/mkfile @@ -12,5 +12,15 @@ OFILES=\ pci.$O \ virtio.$O \ vesa.$O \ + 9p.$O \ + x86.$O \ +#include +#include + +char *vmxroot = "/n/vmx"; + +Biobuf *bin, *bout; +int regsfd, memfd; +int noack; + +void * +emalloc(ulong sz) +{ + void *v; + + v = malloc(sz); + if(v == nil) + sysfatal("malloc: %r"); + memset(v, 0, sz); + setmalloctag(v, getcallerpc(&sz)); + return v; +} + +int +eBgetc(Biobuf *bp) +{ + int c; + + c = Bgetc(bp); + if(c < 0) sysfatal("Bgetc: %r"); + return c; +} + +char * +rpack(void) +{ + int c; + char *pkt; + ulong npkt; + u8int csum, csum2; + char buf[3], *p; + + while(eBgetc(bin) != '$') + ; + if(0){ +repeat: + free(pkt); + } + pkt = nil; + npkt = 0; + csum = 0; + while(c = eBgetc(bin)){ + if(c == '#') break; + if(c == '$') goto repeat; + csum += c; + if(c == '}'){ + c = eBgetc(bin); + if(c == '#') break; + if(c == '$') goto repeat; + csum += c; + c ^= 0x20; + } + if(npkt % 64 == 0) + pkt = realloc(pkt, npkt + 64); + pkt[npkt++] = c; + } + if(npkt % 64 == 0) + pkt = realloc(pkt, npkt + 1); + pkt[npkt] = 0; + buf[0] = eBgetc(bin); + if(buf[0] == '$') goto repeat; + buf[1] = eBgetc(bin); + if(buf[1] == '$') goto repeat; + if(noack) return pkt; + buf[2] = 0; + csum2 = strtol(buf, &p, 16); + if(p != &buf[2] || csum != csum2){ + Bputc(bout, '-'); + goto repeat; + } + Bputc(bout, '+'); + return pkt; +} + +int +bflush(Biobufhdr *, void *v, long n) +{ + Bflush(bout); + return read(bin->fid, v, n); +} + +void +wpack(char *p0) +{ + u8int csum; + char *p; + + fprint(2, "-> %s\n", p0); +again: + p = p0; + csum = 0; + Bputc(bout, '$'); + for(; *p != 0; p++) + switch(*p){ + case '$': case '#': case '{': case '*': + Bputc(bout, '{'); + Bputc(bout, *p ^ 0x20); + csum += '{' + (*p ^ 0x20); + break; + default: + Bputc(bout, *p); + csum += *p; + } + Bprint(bout, "#%.2uX", csum); + if(noack) return; + for(;;) + switch(eBgetc(bin)){ + case '+': return; + case '-': goto again; + case '$': Bungetc(bin); return; + } +} + +static char *regname[] = { + "ax", "cx", "dx", "bx", + "sp", "bp", "si", "di", + "pc", "flags", "cs", "ss", + "ds", "es", "fs", "gs", +}; + +char * +regpacket(void) +{ + char *buf; + char rbuf[8192]; + int rc; + char *p, *q, *f[2]; + int pos, i, l; + uvlong v; + char tbuf[3]; + + l = 4 * nelem(regname); + buf = emalloc(2 * l + 1); + memset(buf, 'x', 2 * l); + rc = pread(regsfd, rbuf, sizeof(rbuf)-1, 0); + if(rc < 0){ + free(buf); + return strdup(""); + } + rbuf[rc] = 0; + p = rbuf; + for(;; p = q + 1){ + q = strchr(p, '\n'); + if(q == nil) break; + *q = 0; + if(tokenize(p, f, nelem(f)) < 2) continue; + v = strtoull(f[1], nil, 0); + pos = 0; + for(i = 0; i < nelem(regname); i++){ + if(strcmp(f[0], regname[i]) == 0) + break; + pos += 4; + } + if(i == nelem(regname)) continue; + l = 4; + while(l--){ + sprint(tbuf, "%.2ux", (u8int)v); + ((u16int*)buf)[pos++] = *(u16int*)tbuf; + v >>= 8; + } + } + return buf; +} + +char * +memread(char *p) +{ + char *q; + uvlong addr, count; + char *buf; + int rc, i; + char tbuf[3]; + + addr = strtoull(p, &q, 16); + if(p == q || *q != ',') return strdup("E99"); + count = strtoull(q + 1, &p, 16); + if(q+1 == p || *p != 0) return strdup("E99"); + if(count > 65536) count = 65536; + buf = emalloc(2*count+4); + rc = pread(memfd, buf, count, addr); + if(rc <= 0) return strcpy(buf, "E01"); + for(i = rc; --i >= 0; ){ + sprint(tbuf, "%.2ux", (uchar)buf[i]); + ((u16int*)buf)[i] = *(u16int*)tbuf; + } + return buf; +} + +void +main(int, char **) +{ + char *p, *msg; + + bin = Bfdopen(0, OREAD); + if(bin == nil) sysfatal("Bfdopen: %r"); + bout = Bfdopen(1, OWRITE); + if(bout == nil) sysfatal("Bfdpen: %r"); + Biofn(bin, bflush); + + p = smprint("%s/mem", vmxroot); + memfd = open(p, OREAD); + free(p); + if(memfd < 0) sysfatal("open: %r"); + + p = smprint("%s/regs", vmxroot); + regsfd = open(p, OREAD); + free(p); + if(regsfd < 0) sysfatal("open: %r"); + + for(;;){ + msg = rpack(); + fprint(2, "<- %s\n", msg); + reinterpret: + switch(*msg){ + case 'g': + p = regpacket(); + wpack(p); + free(p); + break; + case '?': + wpack("S00"); + break; + case 'm': + p = memread(msg+1); + wpack(p); + free(p); + break; + case 'q': + if(strncmp(msg, "qSupported", 10) == 0 && (msg[10] == ':' || msg[10] == 0)){ + wpack("PacketSize=4096;QStartNoAckMode+"); + }else + goto no; + break; + case 'Q': + if(strcmp(msg, "QStartNoAckMode") == 0){ + wpack("OK"); + noack = 1; + } + break; + case 'H': + msg[0] = msg[1]; + msg[1] = 0; + goto reinterpret; + default: no: wpack(""); break; + } + free(msg); + } + +} diff --git a/sys/src/cmd/vmx/x86.c b/sys/src/cmd/vmx/x86.c new file mode 100644 index 000000000..f7d60617b --- /dev/null +++ b/sys/src/cmd/vmx/x86.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" +#include "x86.h" + +typedef struct VMemReq VMemReq; +struct VMemReq { + QLock; + uintptr va, len; + void *buf; + uintptr rc; +}; + +static uintptr +translateflat(uintptr va, uintptr *pa, uintptr) +{ + *pa = va; + if(va == 0) + return -1; + return 0; +} + +static uintptr +translate32(uintptr va, uintptr *pa, uintptr cr4) +{ + void *pd, *pt; + u32int pde, pte; + + if(sizeof(uintptr) != 4 && va >> 32 != 0) return -1; + pd = gptr(rget("cr3") & ~0xfff, 4096); + if(pd == nil) return 0; + pde = GET32(pd, (va >> 22) * 4); + if((pde & 1) == 0) return 0; + if((pde & 0x80) != 0 && (cr4 & Cr4Pse) != 0){ + *pa = pde & (1<<22) - 1 | (uintptr)(pde & 0xfe000) << 19; + return (1<<22) - (va & (1<<22)-1); + } + pt = gptr(pde & ~0xfff, 4096); + if(pt == nil) return 0; + pte = GET32(pt, va >> 10 & 0xffc); + if((pte & 1) == 0) return 0; + *pa = pte & ~0xfff | va & 0xfff; + return 0x1000 - (va & 0xfff); +} + +static uintptr +translatepae(uintptr, uintptr *, uintptr) +{ + vmerror("PAE translation not implemented"); + return 0; +} + +static uintptr +translate64(uintptr, uintptr *, uintptr) +{ + vmerror("long mode translation not implemented"); + return 0; +} + +static uintptr (* +translator(uintptr *cr4p))(uintptr, uintptr *, uintptr) +{ + uintptr cr0, cr4, efer; + + cr0 = rget("cr0real"); + if((cr0 & Cr0Pg) == 0) + return translateflat; + efer = rget("efer"); + if((efer & EferLme) != 0) + return translate64; + cr4 = rget("cr4real"); + *cr4p = cr4; + if((cr4 & Cr4Pae) != 0) + return translatepae; + return translate32; +} + +static void +vmemread0(void *aux) +{ + VMemReq *req; + uintptr va, pa, n, ok, pok, cr4; + void *v; + uintptr (*trans)(uintptr, uintptr *, uintptr); + uchar *p; + + req = aux; + va = req->va; + n = req->len; + p = req->buf; + trans = translator(&cr4); + while(n > 0){ + ok = trans(va, &pa, cr4); + if(ok == 0) break; + if(ok > n) ok = n; + v = gptr(pa, 1); + if(v == nil) break; + pok = gavail(v); + if(ok > pok) ok = pok; + memmove(p, v, ok); + n -= ok; + p += ok; + va += ok; + } + req->rc = req->len - n; + qunlock(req); +} + +uintptr +vmemread(void *buf, uintptr len, uintptr va) +{ + VMemReq req; + + memset(&req, 0, sizeof(VMemReq)); + req.buf = buf; + req.len = len; + req.va = va; + qlock(&req); + sendnotif(vmemread0, &req); + qlock(&req); + return req.rc; +} diff --git a/sys/src/cmd/vmx/x86.h b/sys/src/cmd/vmx/x86.h new file mode 100644 index 000000000..df19a35b4 --- /dev/null +++ b/sys/src/cmd/vmx/x86.h @@ -0,0 +1,29 @@ +#define GDTTYPE(x) ((uvlong)(x)<<40) +enum { + GDTR = GDTTYPE(0x10), /* read-only */ + GDTRW = GDTTYPE(0x12), /* read-write * + GDTX = GDTTYPE(0x18), /* execute-only */ + GDTRX = GDTTYPE(0x1A), /* read-execute */ + + GDTTSS = GDTTYPE(0x09), + + GDTA = 1ULL<<40, /* accessed */ + GDTE = 1ULL<<42, /* expand down (data only) */ + GDTC = GDTE, /* conforming (code only) */ + GDTP = 1ULL<<47, /* present */ + GDT64 = 1ULL<<53, /* 64-bit code segment */ + GDT32 = 1ULL<<54, /* 32-bit segment */ + GDTG = 1ULL<<55, /* granularity */ +}; +#define GDTLIM(l) ((l) & 0xffff | (uvlong)((l) & 0xf0000)<<32) +#define GDTBASE(l) (((uvlong)(l) & 0xffffff)<<16 | (uvlong)((l) & 0xff000000)<<32) +#define GDTDPL(l) ((uvlong)(l)<<45) + +enum { + Cr0Pg = 1<<31, + + Cr4Pse = 1<<4, + Cr4Pae = 1<<5, + + EferLme = 1<<8, +}; -- cgit v1.2.3