ref: 5c0bff4ba204cfad7aedb8c1c20f1c29265dcb01
parent: 37b9ab5a043e45a68979632c177e11af7a439027
author: aiju <devnull@localhost>
date: Wed Jun 21 18:18:26 EDT 2017
vmx(1): add support for (so far) crude 9p debugging fs; add gdb stub; clean up linux gdt code
--- /dev/null
+++ b/sys/src/cmd/vmx/9p.c
@@ -1,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);
+}
--- a/sys/src/cmd/vmx/dat.h
+++ b/sys/src/cmd/vmx/dat.h
@@ -3,7 +3,14 @@
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
--- 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 @@
hlt(ExitInfo *ei)
{
if(irqactive == 0)
- halt = 1;
+ state = VMHALT;
skipinstr(ei);
}
@@ -484,5 +486,9 @@
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);
}
--- a/sys/src/cmd/vmx/fns.h
+++ b/sys/src/cmd/vmx/fns.h
@@ -43,3 +43,4 @@
u32int roundpow2(u32int);
u32int vgagetpal(u8int);
void vgasetpal(u8int, u32int);
+uintptr vmemread(void *, uintptr, uintptr);
--- a/sys/src/cmd/vmx/io.c
+++ b/sys/src/cmd/vmx/io.c
@@ -202,7 +202,8 @@
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)
--- 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 @@
}
}
-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 @@
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 @@
return 1;
}
+
void
loadkernel(char *fn)
{
@@ -921,7 +909,13 @@
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);
}
--- a/sys/src/cmd/vmx/mkfile
+++ b/sys/src/cmd/vmx/mkfile
@@ -12,5 +12,15 @@
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
--- a/sys/src/cmd/vmx/vmx.c
+++ b/sys/src/cmd/vmx/vmx.c
@@ -9,7 +9,7 @@
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 @@
notif.f(notif.arg);
break;
}
- if(getexit == 0 && halt == 0)
+ if(getexit == 0 && state == VMRUNNING)
launch();
}
}
@@ -463,6 +463,7 @@
extern void pcibusmap(void);
extern void cpuidinit(void);
extern void vgafbparse(char *);
+extern void init9p(char *);
int cmdlinen;
char **cmdlinev;
@@ -494,7 +495,7 @@
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 @@
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 @@
case 'v':
vgafbparse(EARGF(usage()));
break;
+ case '9':
+ if(srvname != nil) usage();
+ srvname = EARGF(usage());
+ break;
default:
usage();
} ARGEND;
@@ -578,6 +584,8 @@
sysfatal("%s: %r", edevt[i]);
pcibusmap();
+
+ if(srvname != nil) init9p(srvname);
runloop();
exits(nil);
}
--- /dev/null
+++ b/sys/src/cmd/vmx/vmxgdb.c
@@ -1,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);
+ }
+
+}
--- /dev/null
+++ b/sys/src/cmd/vmx/x86.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/cmd/vmx/x86.h
@@ -1,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,
+};