shithub: riscv

Download patch

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,
+};