diff options
author | aiju <devnull@localhost> | 2017-06-21 22:18:26 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2017-06-21 22:18:26 +0000 |
commit | 5c0bff4ba204cfad7aedb8c1c20f1c29265dcb01 (patch) | |
tree | 055fa5e6319b94d0f2992480a0e6ed0271179fb6 /sys/src/cmd/vmx | |
parent | 37b9ab5a043e45a68979632c177e11af7a439027 (diff) |
vmx(1): add support for (so far) crude 9p debugging fs; add gdb stub; clean up linux gdt code
Diffstat (limited to 'sys/src/cmd/vmx')
-rw-r--r-- | sys/src/cmd/vmx/9p.c | 65 | ||||
-rw-r--r-- | sys/src/cmd/vmx/dat.h | 9 | ||||
-rw-r--r-- | sys/src/cmd/vmx/exith.c | 10 | ||||
-rw-r--r-- | sys/src/cmd/vmx/fns.h | 1 | ||||
-rw-r--r-- | sys/src/cmd/vmx/io.c | 3 | ||||
-rw-r--r-- | sys/src/cmd/vmx/ksetup.c | 34 | ||||
-rw-r--r-- | sys/src/cmd/vmx/mkfile | 10 | ||||
-rw-r--r-- | sys/src/cmd/vmx/vmx.c | 14 | ||||
-rw-r--r-- | sys/src/cmd/vmx/vmxgdb.c | 259 | ||||
-rw-r--r-- | sys/src/cmd/vmx/x86.c | 124 | ||||
-rw-r--r-- | sys/src/cmd/vmx/x86.h | 29 |
11 files changed, 531 insertions, 27 deletions
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 <u.h> +#include <libc.h> +#include <thread.h> +#include <fcall.h> +#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 <libsec.h> #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 \ </sys/src/cmd/mkone + +install:V: $BIN/vmxgdb + +$BIN/vmxgdb: $O.vmxgdb + cp $prereq $BIN/vmxgdb + +$O.vmxgdb: vmxgdb.$O + $LD $LDFLAGS -o $target $prereq diff --git a/sys/src/cmd/vmx/vmx.c b/sys/src/cmd/vmx/vmx.c index 902405c8a..481424935 100644 --- a/sys/src/cmd/vmx/vmx.c +++ b/sys/src/cmd/vmx/vmx.c @@ -9,7 +9,7 @@ Region *mmap; int ctlfd, regsfd, waitfd; Channel *waitch, *sleepch, *notifch; enum { MSEC = 1000*1000, MinSleep = MSEC, SleeperPoll = 2000*MSEC } ; -int getexit, halt; +int getexit, state; typedef struct VmxNotif VmxNotif; struct VmxNotif { void (*f)(void *); @@ -440,7 +440,7 @@ runloop(void) notif.f(notif.arg); break; } - if(getexit == 0 && halt == 0) + if(getexit == 0 && state == VMRUNNING) launch(); } } @@ -463,6 +463,7 @@ extern void pciinit(void); extern void pcibusmap(void); extern void cpuidinit(void); extern void vgafbparse(char *); +extern void init9p(char *); int cmdlinen; char **cmdlinev; @@ -494,7 +495,7 @@ usage(void) for(p = blanks; *p != 0; p++) *p = ' '; fprint(2, "usage: %s [ -M mem ] [ -c com1rd[,com1wr] ] [ -C com2rd[,com2r] ] [ -n nic ]\n", argv0); - fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v vga ] kernel [ args ... ]\n", blanks); + fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v vga ] [ -9 srv ] kernel [ args ... ]\n", blanks); threadexitsall("usage"); } @@ -506,6 +507,7 @@ threadmain(int argc, char **argv) static char *edevaux[nelem(edev)]; static int edevn; static uvlong gmemsz = 64*1024*1024; + static char *srvname; extern uintptr fbsz, fbaddr; int i; @@ -546,6 +548,10 @@ threadmain(int argc, char **argv) case 'v': vgafbparse(EARGF(usage())); break; + case '9': + if(srvname != nil) usage(); + srvname = EARGF(usage()); + break; default: usage(); } ARGEND; @@ -578,6 +584,8 @@ threadmain(int argc, char **argv) sysfatal("%s: %r", edevt[i]); pcibusmap(); + + if(srvname != nil) init9p(srvname); runloop(); exits(nil); } diff --git a/sys/src/cmd/vmx/vmxgdb.c b/sys/src/cmd/vmx/vmxgdb.c new file mode 100644 index 000000000..827b7f508 --- /dev/null +++ b/sys/src/cmd/vmx/vmxgdb.c @@ -0,0 +1,259 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +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 <u.h> +#include <libc.h> +#include <thread.h> +#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, +}; |