vmx(1): add support for (so far) crude 9p debugging fs; add gdb stub; clean up linux gdt code

This commit is contained in:
aiju 2017-06-21 22:18:26 +00:00
parent 37b9ab5a04
commit 5c0bff4ba2
11 changed files with 531 additions and 27 deletions

65
sys/src/cmd/vmx/9p.c Normal file
View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -43,3 +43,4 @@ void i8042kick(void *);
u32int roundpow2(u32int);
u32int vgagetpal(u8int);
void vgasetpal(u8int, u32int);
uintptr vmemread(void *, uintptr, uintptr);

View file

@ -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)

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

259
sys/src/cmd/vmx/vmxgdb.c Normal file
View file

@ -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);
}
}

124
sys/src/cmd/vmx/x86.c Normal file
View file

@ -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;
}

29
sys/src/cmd/vmx/x86.h Normal file
View file

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