2017-06-13 14:18:14 +00:00
|
|
|
|
#include <u.h>
|
|
|
|
|
#include <libc.h>
|
|
|
|
|
#include <thread.h>
|
|
|
|
|
#include <draw.h>
|
|
|
|
|
#include "dat.h"
|
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
2017-08-28 17:27:41 +00:00
|
|
|
|
char *segname;
|
|
|
|
|
int segrclose;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
Region *mmap;
|
2017-08-24 08:06:41 +00:00
|
|
|
|
int ctlfd, regsfd, mapfd, waitfd;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
Channel *waitch, *sleepch, *notifch;
|
|
|
|
|
enum { MSEC = 1000*1000, MinSleep = MSEC, SleeperPoll = 2000*MSEC } ;
|
2017-06-21 22:18:26 +00:00
|
|
|
|
int getexit, state;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
typedef struct VmxNotif VmxNotif;
|
|
|
|
|
struct VmxNotif {
|
|
|
|
|
void (*f)(void *);
|
|
|
|
|
void *arg;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int mainstacksize = 65536;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
vmerror(char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
Fmt f;
|
|
|
|
|
char buf[256];
|
|
|
|
|
va_list arg;
|
|
|
|
|
|
|
|
|
|
fmtfdinit(&f, 2, buf, sizeof buf);
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
|
fmtvprint(&f, fmt, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
fmtprint(&f, "\n");
|
|
|
|
|
fmtfdflush(&f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ctl(char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list va;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
va_start(va, fmt);
|
|
|
|
|
rc = vfprint(ctlfd, fmt, va);
|
|
|
|
|
va_end(va);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 08:06:41 +00:00
|
|
|
|
void
|
|
|
|
|
modregion(Region *r)
|
|
|
|
|
{
|
|
|
|
|
if(r->segname == nil){
|
2017-08-24 09:01:30 +00:00
|
|
|
|
if(fprint(mapfd, "--- wb %#ullx %#ullx\n", (uvlong)r->start, (uvlong)r->end) < 0)
|
2017-08-24 08:06:41 +00:00
|
|
|
|
vmerror("updating memory map: %r");
|
|
|
|
|
}else
|
|
|
|
|
if(fprint(mapfd, "%c%c%c wb %#ullx %#ullx %s %#ullx\n",
|
|
|
|
|
(r->type & REGR) != 0 ? 'r' : '-',
|
|
|
|
|
(r->type & REGW) != 0 ? 'w' : '-',
|
|
|
|
|
(r->type & REGX) != 0 ? 'x' : '-',
|
2017-08-24 09:01:30 +00:00
|
|
|
|
(uvlong)r->start, (uvlong)r->end, r->segname, (uvlong)r->segoff) < 0)
|
2017-08-24 08:06:41 +00:00
|
|
|
|
vmerror("updating memory map: %r");
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
static void
|
|
|
|
|
vmxsetup(void)
|
|
|
|
|
{
|
|
|
|
|
static char buf[128];
|
2017-08-28 17:27:41 +00:00
|
|
|
|
static char name[128];
|
2017-08-24 08:06:41 +00:00
|
|
|
|
int rc;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
|
2017-08-28 17:27:41 +00:00
|
|
|
|
ctlfd = open("#X/clone", ORDWR|ORCLOSE);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(ctlfd < 0) sysfatal("open: %r");
|
2017-08-28 17:27:41 +00:00
|
|
|
|
rc = read(ctlfd, name, sizeof(name) - 1);
|
|
|
|
|
if(rc < 0) sysfatal("read: %r");
|
|
|
|
|
name[rc] = 0;
|
|
|
|
|
if(segname == nil){
|
|
|
|
|
segname = smprint("vm.%s", name);
|
|
|
|
|
segrclose = ORCLOSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprint(buf, sizeof(buf), "#X/%s/regs", name);
|
|
|
|
|
regsfd = open(buf, ORDWR);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(regsfd < 0) sysfatal("open: %r");
|
|
|
|
|
|
2017-08-28 17:27:41 +00:00
|
|
|
|
snprint(buf, sizeof(buf), "#X/%s/map", name);
|
|
|
|
|
mapfd = open(buf, OWRITE|OTRUNC);
|
2017-08-24 08:06:41 +00:00
|
|
|
|
if(mapfd < 0) sysfatal("open: %r");
|
2017-06-13 14:18:14 +00:00
|
|
|
|
|
2017-08-28 17:27:41 +00:00
|
|
|
|
snprint(buf, sizeof(buf), "#X/%s/wait", name);
|
|
|
|
|
waitfd = open(buf, OREAD);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(waitfd < 0) sysfatal("open: %r");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum { RCENT = 256 };
|
|
|
|
|
char *rcname[RCENT];
|
|
|
|
|
uvlong rcval[RCENT];
|
|
|
|
|
uvlong rcvalid[(RCENT+63)/64], rcdirty[(RCENT+63)/64];
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
rclookup(char *n)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < RCENT; i++)
|
|
|
|
|
if(rcname[i] != nil && strcmp(n, rcname[i]) == 0)
|
|
|
|
|
return i;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
rcflush(int togo)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
static char buf[4096];
|
|
|
|
|
char *p, *e;
|
|
|
|
|
uvlong v;
|
|
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
|
e = buf + sizeof(buf);
|
|
|
|
|
*p = 0;
|
|
|
|
|
for(i = 0; i < (RCENT+63)/64; i++){
|
|
|
|
|
if(v = rcdirty[i], v != 0){
|
|
|
|
|
for(j = 0; j < 64; j++)
|
|
|
|
|
if((v>>j & 1) != 0)
|
|
|
|
|
p = seprint(p, e, "%s%c%#ullx%c", rcname[i*64+j], togo?'=':' ', rcval[i*64+j], togo?';':'\n');
|
|
|
|
|
rcdirty[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
rcvalid[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
if(!togo && p != buf && write(regsfd, buf, p - buf) < p - buf)
|
|
|
|
|
sysfatal("rcflush: write: %r");
|
|
|
|
|
return p != buf ? buf : nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rcload(void)
|
|
|
|
|
{
|
|
|
|
|
char buf[4096];
|
|
|
|
|
char *p, *q, *f[2];
|
|
|
|
|
int nf;
|
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
|
|
rcflush(0);
|
|
|
|
|
rc = pread(regsfd, buf, sizeof(buf) - 1, 0);
|
|
|
|
|
if(rc < 0) sysfatal("rcload: pread: %r");
|
|
|
|
|
buf[rc] = 0;
|
|
|
|
|
p = buf;
|
|
|
|
|
for(i = 0; i < nelem(rcname); i++){
|
|
|
|
|
q = strchr(p, '\n');
|
|
|
|
|
if(q == nil) break;
|
|
|
|
|
*q = 0;
|
|
|
|
|
nf = tokenize(p, f, nelem(f));
|
|
|
|
|
p = q + 1;
|
|
|
|
|
if(nf < 2) break;
|
|
|
|
|
free(rcname[i]);
|
|
|
|
|
rcname[i] = strdup(f[0]);
|
|
|
|
|
rcval[i] = strtoull(f[1], nil, 0);
|
|
|
|
|
rcvalid[i>>6] |= 1ULL<<(i&63);
|
|
|
|
|
}
|
|
|
|
|
for(; i < nelem(rcname); i++){
|
|
|
|
|
free(rcname[i]);
|
|
|
|
|
rcname[i] = 0;
|
|
|
|
|
rcvalid[i>>6] &= ~(1ULL<<(i&63));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uvlong
|
|
|
|
|
rget(char *reg)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = rclookup(reg);
|
|
|
|
|
if(i < 0 || (rcvalid[i>>6]>>i&1) == 0){
|
|
|
|
|
rcload();
|
|
|
|
|
i = rclookup(reg);
|
|
|
|
|
if(i < 0) sysfatal("unknown register %s", reg);
|
|
|
|
|
}
|
|
|
|
|
return rcval[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rpoke(char *reg, uvlong val, int clean)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = rclookup(reg);
|
|
|
|
|
if(i >= 0){
|
|
|
|
|
if((rcvalid[i>>6]>>(i&63)&1) != 0 && rcval[i] == val) return;
|
|
|
|
|
goto goti;
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < nelem(rcname); i++)
|
|
|
|
|
if(rcname[i] == nil){
|
|
|
|
|
rcname[i] = strdup(reg);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
assert(i < nelem(rcname));
|
|
|
|
|
goti:
|
|
|
|
|
rcval[i] = val;
|
|
|
|
|
rcvalid[i>>6] |= 1ULL<<(i&63);
|
|
|
|
|
if(!clean)
|
|
|
|
|
rcdirty[i>>6] |= 1ULL<<(i&63);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 09:21:30 +00:00
|
|
|
|
uvlong
|
|
|
|
|
rgetsz(char *reg, int sz)
|
|
|
|
|
{
|
|
|
|
|
switch(sz){
|
|
|
|
|
case 1: return (u8int)rget(reg);
|
|
|
|
|
case 2: return (u16int)rget(reg);
|
|
|
|
|
case 4: return (u32int)rget(reg);
|
|
|
|
|
case 8: return rget(reg);
|
|
|
|
|
default:
|
|
|
|
|
vmerror("invalid size operand for rgetsz");
|
|
|
|
|
assert(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rsetsz(char *reg, uvlong val, int sz)
|
|
|
|
|
{
|
|
|
|
|
switch(sz){
|
|
|
|
|
case 1: rset(reg, (u8int)val | rget(reg) & ~0xffULL); break;
|
|
|
|
|
case 2: rset(reg, (u16int)val | rget(reg) & ~0xffffULL); break;
|
|
|
|
|
case 4: rset(reg, (u32int)val); break;
|
|
|
|
|
case 8: rset(reg, val); break;
|
|
|
|
|
default:
|
|
|
|
|
vmerror("invalid size operand for rsetsz");
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
Region *
|
2017-06-20 15:15:53 +00:00
|
|
|
|
mkregion(u64int pa, u64int end, int type)
|
2017-06-13 14:18:14 +00:00
|
|
|
|
{
|
2017-06-27 09:21:30 +00:00
|
|
|
|
Region *r, *s, **rp;
|
2017-06-20 15:15:53 +00:00
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
r = emalloc(sizeof(Region));
|
2017-06-27 09:21:30 +00:00
|
|
|
|
if(end < pa) sysfatal("end of region %p before start of region %#p", (void*)end, (void*)pa);
|
|
|
|
|
if((pa & BY2PG-1) != 0 || (end & BY2PG-1) != 0) sysfatal("address %#p not page aligned", (void*)pa);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
r->start = pa;
|
2017-06-20 15:15:53 +00:00
|
|
|
|
r->end = end;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
r->type = type;
|
2017-06-27 09:21:30 +00:00
|
|
|
|
for(s = mmap; s != nil; s = s->next)
|
|
|
|
|
if(!(pa < s->start && end < s->end || pa >= s->start && pa >= s->end))
|
2017-08-24 09:01:30 +00:00
|
|
|
|
sysfatal("region %#p-%#p overlaps region %#p-%#p", (void*)pa, (void*)end, (void*)s->start, (void*)s->end);
|
2017-06-27 09:21:30 +00:00
|
|
|
|
for(rp = &mmap; (*rp) != nil && (*rp)->start < end; rp = &(*rp)->next)
|
2017-06-13 14:18:14 +00:00
|
|
|
|
;
|
2017-06-27 09:21:30 +00:00
|
|
|
|
r->next = *rp;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
*rp = r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 08:06:41 +00:00
|
|
|
|
Region *
|
|
|
|
|
regptr(u64int addr)
|
|
|
|
|
{
|
|
|
|
|
Region *r;
|
|
|
|
|
|
|
|
|
|
for(r = mmap; r != nil; r = r->next)
|
|
|
|
|
if(addr >= r->start && addr < r->end)
|
|
|
|
|
return r;
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
void *
|
|
|
|
|
gptr(u64int addr, u64int len)
|
|
|
|
|
{
|
|
|
|
|
Region *r;
|
|
|
|
|
|
|
|
|
|
if(addr + len < addr)
|
|
|
|
|
return nil;
|
|
|
|
|
for(r = mmap; r != nil; r = r->next)
|
|
|
|
|
if(addr >= r->start && addr < r->end){
|
|
|
|
|
if(addr + len > r->end)
|
|
|
|
|
return nil;
|
|
|
|
|
return (uchar *) r->v + (addr - r->start);
|
|
|
|
|
}
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uintptr
|
|
|
|
|
gpa(void *v)
|
|
|
|
|
{
|
|
|
|
|
Region *r;
|
|
|
|
|
|
|
|
|
|
for(r = mmap; r != nil; r = r->next)
|
|
|
|
|
if(v >= r->v && v < r->ve)
|
2017-06-20 15:15:53 +00:00
|
|
|
|
return (uchar *) v - (uchar *) r->v + r->start;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uintptr
|
|
|
|
|
gavail(void *v)
|
|
|
|
|
{
|
|
|
|
|
Region *r;
|
|
|
|
|
|
|
|
|
|
for(r = mmap; r != nil; r = r->next)
|
|
|
|
|
if(v >= r->v && v < r->ve)
|
|
|
|
|
return (uchar *) r->ve - (uchar *) v;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
gend(void *v)
|
|
|
|
|
{
|
|
|
|
|
return (u8int *) v + gavail(v);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 08:06:41 +00:00
|
|
|
|
void *tmp, *vgamem;
|
|
|
|
|
uvlong tmpoff, vgamemoff;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mksegment(char *sn)
|
|
|
|
|
{
|
|
|
|
|
uintptr sz;
|
|
|
|
|
int fd;
|
|
|
|
|
Region *r;
|
|
|
|
|
char buf[256];
|
|
|
|
|
u8int *gmem, *p;
|
|
|
|
|
|
2017-08-24 08:06:41 +00:00
|
|
|
|
sz = BY2PG; /* temporary page */
|
|
|
|
|
sz += 256*1024; /* vga */
|
2017-06-13 14:18:14 +00:00
|
|
|
|
for(r = mmap; r != nil; r = r->next){
|
2017-06-20 15:15:53 +00:00
|
|
|
|
if((r->type & REGALLOC) == 0)
|
|
|
|
|
continue;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
r->segname = sn;
|
|
|
|
|
if(sz + (r->end - r->start) < sz)
|
|
|
|
|
sysfatal("out of address space");
|
|
|
|
|
sz += r->end - r->start;
|
|
|
|
|
}
|
|
|
|
|
gmem = segattach(0, sn, nil, sz);
|
|
|
|
|
if(gmem == (void*)-1){
|
|
|
|
|
snprint(buf, sizeof(buf), "#g/%s", sn);
|
2017-08-28 17:27:41 +00:00
|
|
|
|
fd = create(buf, OREAD|segrclose, DMDIR | 0777);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(fd < 0) sysfatal("create: %r");
|
|
|
|
|
snprint(buf, sizeof(buf), "#g/%s/ctl", sn);
|
|
|
|
|
fd = open(buf, OWRITE|OTRUNC);
|
|
|
|
|
if(fd < 0) sysfatal("open: %r");
|
2017-08-14 04:18:13 +02:00
|
|
|
|
snprint(buf, sizeof(buf), "va %#ullx %#ullx sticky", 0x10000000ULL, (uvlong)sz);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(write(fd, buf, strlen(buf)) < 0) sysfatal("write: %r");
|
|
|
|
|
close(fd);
|
|
|
|
|
gmem = segattach(0, sn, nil, sz);
|
|
|
|
|
if(gmem == (void*)-1) sysfatal("segattach: %r");
|
|
|
|
|
}
|
2017-06-20 15:15:53 +00:00
|
|
|
|
memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
p = gmem;
|
|
|
|
|
for(r = mmap; r != nil; r = r->next){
|
|
|
|
|
if(r->segname == nil) continue;
|
|
|
|
|
r->segoff = p - gmem;
|
|
|
|
|
r->v = p;
|
|
|
|
|
p += r->end - r->start;
|
|
|
|
|
r->ve = p;
|
|
|
|
|
}
|
2017-08-24 08:06:41 +00:00
|
|
|
|
vgamem = p;
|
|
|
|
|
vgamemoff = p - gmem;
|
|
|
|
|
regptr(0xa0000)->segoff = vgamemoff;
|
|
|
|
|
regptr(0xa0000)->v = vgamem;
|
|
|
|
|
p += 256*1024;
|
|
|
|
|
regptr(0xa0000)->ve = p;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
tmp = p;
|
|
|
|
|
tmpoff = p - gmem;
|
2017-08-28 17:27:41 +00:00
|
|
|
|
|
|
|
|
|
for(r = mmap; r != nil; r = r->next)
|
|
|
|
|
modregion(r);
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2017-06-17 22:50:03 +00:00
|
|
|
|
postexc(char *name, vlong code)
|
2017-06-13 14:18:14 +00:00
|
|
|
|
{
|
2017-06-17 22:50:03 +00:00
|
|
|
|
if(code >= 0){
|
|
|
|
|
if(ctl("exc %s,%#ux", name, (u32int)code) < 0)
|
|
|
|
|
sysfatal("ctl(postexc): %r");
|
|
|
|
|
}else
|
|
|
|
|
if(ctl("exc %s", name) < 0)
|
|
|
|
|
sysfatal("ctl(postexc): %r");
|
2017-06-13 14:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
launch(void)
|
|
|
|
|
{
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
s = rcflush(1);
|
|
|
|
|
if(ctl("go %s", s == nil ? "" : s) < 0)
|
2017-06-17 19:47:04 +00:00
|
|
|
|
sysfatal("go %s: %r", s == nil ? "" : s);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
getexit++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
waitproc(void *)
|
|
|
|
|
{
|
|
|
|
|
static char buf[512];
|
|
|
|
|
char *p;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
threadsetname("waitexit");
|
|
|
|
|
for(;;){
|
|
|
|
|
rc = read(waitfd, buf, sizeof(buf) - 1);
|
|
|
|
|
if(rc < 0)
|
|
|
|
|
sysfatal("read: %r");
|
|
|
|
|
buf[rc] = 0;
|
|
|
|
|
p = strchr(buf, '\n');
|
|
|
|
|
if(p != nil) *p = 0;
|
|
|
|
|
sendp(waitch, strdup(buf));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vlong timerevent = -1;
|
|
|
|
|
Lock timerlock;
|
|
|
|
|
int timerid;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sleeperproc(void *)
|
|
|
|
|
{
|
|
|
|
|
vlong then, now;
|
|
|
|
|
|
|
|
|
|
timerid = threadid();
|
2020-07-31 15:48:54 +02:00
|
|
|
|
timerevent = nanosec() + SleeperPoll;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
unlock(&timerlock);
|
|
|
|
|
threadsetname("sleeper");
|
|
|
|
|
for(;;){
|
|
|
|
|
lock(&timerlock);
|
|
|
|
|
then = timerevent;
|
2020-07-31 15:48:54 +02:00
|
|
|
|
now = nanosec();
|
2017-06-13 14:18:14 +00:00
|
|
|
|
if(then <= now) timerevent = now + SleeperPoll;
|
|
|
|
|
unlock(&timerlock);
|
|
|
|
|
if(then - now >= MinSleep){
|
|
|
|
|
sleep((then - now) / MSEC);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-07-31 15:48:54 +02:00
|
|
|
|
while(nanosec() < then)
|
2017-06-13 14:18:14 +00:00
|
|
|
|
;
|
|
|
|
|
sendul(sleepch, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
runloop(void)
|
|
|
|
|
{
|
|
|
|
|
char *waitmsg;
|
|
|
|
|
ulong ul;
|
|
|
|
|
VmxNotif notif;
|
|
|
|
|
|
|
|
|
|
lock(&timerlock);
|
|
|
|
|
proccreate(waitproc, nil, 4096);
|
|
|
|
|
proccreate(sleeperproc, nil, 4096);
|
|
|
|
|
launch();
|
|
|
|
|
for(;;){
|
|
|
|
|
enum {
|
|
|
|
|
WAIT,
|
|
|
|
|
SLEEP,
|
|
|
|
|
NOTIF,
|
|
|
|
|
};
|
|
|
|
|
Alt a[] = {
|
|
|
|
|
[WAIT] {waitch, &waitmsg, CHANRCV},
|
|
|
|
|
[SLEEP] {sleepch, &ul, CHANRCV},
|
|
|
|
|
[NOTIF] {notifch, ¬if, CHANRCV},
|
|
|
|
|
{nil, nil, CHANEND}
|
|
|
|
|
};
|
|
|
|
|
switch(alt(a)){
|
|
|
|
|
case WAIT:
|
|
|
|
|
getexit--;
|
|
|
|
|
processexit(waitmsg);
|
|
|
|
|
free(waitmsg);
|
|
|
|
|
break;
|
|
|
|
|
case SLEEP:
|
|
|
|
|
pitadvance();
|
2017-06-17 19:47:04 +00:00
|
|
|
|
rtcadvance();
|
2017-06-13 14:18:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case NOTIF:
|
|
|
|
|
notif.f(notif.arg);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-21 22:18:26 +00:00
|
|
|
|
if(getexit == 0 && state == VMRUNNING)
|
2017-06-13 14:18:14 +00:00
|
|
|
|
launch();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mainid;
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
sendnotif(void (*f)(void *), void *arg)
|
|
|
|
|
{
|
|
|
|
|
VmxNotif notif = {f, arg};
|
|
|
|
|
|
|
|
|
|
if(threadid() == mainid)
|
|
|
|
|
f(arg);
|
|
|
|
|
else
|
|
|
|
|
send(notifch, ¬if);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 18:59:54 +01:00
|
|
|
|
extern void vgainit(int);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
extern void pciinit(void);
|
|
|
|
|
extern void pcibusmap(void);
|
|
|
|
|
extern void cpuidinit(void);
|
|
|
|
|
extern void vgafbparse(char *);
|
2017-06-21 22:18:26 +00:00
|
|
|
|
extern void init9p(char *);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
|
|
|
|
|
int cmdlinen;
|
|
|
|
|
char **cmdlinev;
|
|
|
|
|
int bootmodn;
|
|
|
|
|
char **bootmod;
|
|
|
|
|
|
|
|
|
|
static uvlong
|
|
|
|
|
siparse(char *s)
|
|
|
|
|
{
|
|
|
|
|
uvlong l;
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
l = strtoull(s, &p, 0);
|
|
|
|
|
switch(*p){
|
|
|
|
|
case 'k': case 'K': p++; l *= 1<<10; break;
|
|
|
|
|
case 'm': case 'M': p++; l *= 1<<20; break;
|
|
|
|
|
case 'g': case 'G': p++; l *= 1<<30; break;
|
|
|
|
|
}
|
|
|
|
|
if(*p != 0) sysfatal("invalid argument: %s", s);
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 09:21:30 +00:00
|
|
|
|
static void
|
|
|
|
|
setiodebug(char *s)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
int n, m, neg;
|
|
|
|
|
extern u32int iodebug[32];
|
|
|
|
|
|
|
|
|
|
do{
|
|
|
|
|
if(neg = *s == '!')
|
|
|
|
|
s++;
|
|
|
|
|
n = strtoul(s, &p, 0);
|
|
|
|
|
if(s == p)
|
|
|
|
|
no: sysfatal("invalid iodebug argument (error at %#q)", s);
|
|
|
|
|
if(n >= sizeof(iodebug)*8)
|
|
|
|
|
range: sysfatal("out of iodebug range (0-%#ux)", sizeof(iodebug)*8-1);
|
|
|
|
|
s = p + 1;
|
|
|
|
|
if(*p == '-'){
|
|
|
|
|
m = strtoul(s, &p, 0);
|
|
|
|
|
if(m >= sizeof(iodebug)*8)
|
|
|
|
|
goto range;
|
|
|
|
|
if(s == p || m < n) goto no;
|
|
|
|
|
s = p + 1;
|
|
|
|
|
}else
|
|
|
|
|
m = n;
|
|
|
|
|
for(; n <= m; n++)
|
|
|
|
|
if(neg)
|
|
|
|
|
iodebug[n>>5] &= ~(1<<(n&31));
|
|
|
|
|
else
|
|
|
|
|
iodebug[n>>5] |= 1<<(n&31);
|
|
|
|
|
}while(*p == ',');
|
|
|
|
|
if(*p != 0) goto no;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
static void
|
|
|
|
|
usage(void)
|
|
|
|
|
{
|
|
|
|
|
char *blanks, *p;
|
|
|
|
|
|
|
|
|
|
blanks = strdup(argv0);
|
|
|
|
|
for(p = blanks; *p != 0; p++)
|
|
|
|
|
*p = ' ';
|
|
|
|
|
fprint(2, "usage: %s [ -M mem ] [ -c com1rd[,com1wr] ] [ -C com2rd[,com2r] ] [ -n nic ]\n", argv0);
|
2020-12-07 18:59:54 +01:00
|
|
|
|
fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v|-w vga ] [ -9 srv ] kernel [ args ... ]\n", blanks);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
threadexitsall("usage");
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 09:21:30 +00:00
|
|
|
|
void (*kconfig)(void);
|
|
|
|
|
|
2017-06-13 14:18:14 +00:00
|
|
|
|
void
|
|
|
|
|
threadmain(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
static int (*edev[16])(char *);
|
|
|
|
|
static char *edevt[nelem(edev)];
|
|
|
|
|
static char *edevaux[nelem(edev)];
|
|
|
|
|
static int edevn;
|
|
|
|
|
static uvlong gmemsz = 64*1024*1024;
|
2017-06-21 22:18:26 +00:00
|
|
|
|
static char *srvname;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
extern uintptr fbsz, fbaddr;
|
2020-12-07 18:59:54 +01:00
|
|
|
|
int newwin = 0;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
quotefmtinstall();
|
|
|
|
|
mainid = threadid();
|
|
|
|
|
cpuidinit();
|
|
|
|
|
waitch = chancreate(sizeof(char *), 32);
|
|
|
|
|
sleepch = chancreate(sizeof(ulong), 32);
|
|
|
|
|
notifch = chancreate(sizeof(VmxNotif), 16);
|
|
|
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
|
case 'm':
|
|
|
|
|
bootmod = realloc(bootmod, (bootmodn + 1) * sizeof(char *));
|
|
|
|
|
bootmod[bootmodn++] = strdup(EARGF(usage()));
|
|
|
|
|
break;
|
2017-08-28 17:27:41 +00:00
|
|
|
|
case 's':
|
|
|
|
|
segname = strdup(EARGF(usage()));
|
|
|
|
|
segrclose = 0;
|
|
|
|
|
break;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
case 'c':
|
|
|
|
|
uartinit(0, EARGF(usage()));
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
uartinit(1, EARGF(usage()));
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
assert(edevn < nelem(edev));
|
|
|
|
|
edev[edevn] = mkvionet;
|
|
|
|
|
edevt[edevn] = "virtio network";
|
|
|
|
|
edevaux[edevn++] = strdup(EARGF(usage()));
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
assert(edevn < nelem(edev));
|
2017-06-27 09:21:30 +00:00
|
|
|
|
edevaux[edevn] = strdup(EARGF(usage()));
|
|
|
|
|
if(strncmp(edevaux[edevn], "ide:", 4) == 0){
|
|
|
|
|
edevaux[edevn] += 4;
|
|
|
|
|
edev[edevn] = mkideblk;
|
|
|
|
|
edevt[edevn] = "ide block";
|
|
|
|
|
}else{
|
|
|
|
|
edev[edevn] = mkvioblk;
|
|
|
|
|
edevt[edevn] = "virtio block";
|
|
|
|
|
}
|
|
|
|
|
edevn++;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
break;
|
|
|
|
|
case 'M':
|
|
|
|
|
gmemsz = siparse(EARGF(usage()));
|
|
|
|
|
if(gmemsz != (uintptr) gmemsz) sysfatal("too much memory for address space");
|
|
|
|
|
break;
|
2020-12-07 18:59:54 +01:00
|
|
|
|
case 'w':
|
|
|
|
|
newwin = 1;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
case 'v':
|
|
|
|
|
vgafbparse(EARGF(usage()));
|
|
|
|
|
break;
|
2017-06-21 22:18:26 +00:00
|
|
|
|
case '9':
|
|
|
|
|
if(srvname != nil) usage();
|
|
|
|
|
srvname = EARGF(usage());
|
|
|
|
|
break;
|
2017-06-27 09:21:30 +00:00
|
|
|
|
case L'ι':
|
|
|
|
|
setiodebug(EARGF(usage()));
|
|
|
|
|
break;
|
2017-06-13 14:18:14 +00:00
|
|
|
|
default:
|
|
|
|
|
usage();
|
|
|
|
|
} ARGEND;
|
|
|
|
|
if(argc < 1) usage();
|
|
|
|
|
cmdlinen = argc - 1;
|
|
|
|
|
cmdlinev = argv + 1;
|
|
|
|
|
|
2017-06-20 15:15:53 +00:00
|
|
|
|
if(gmemsz < 1<<20) sysfatal("640 KB of RAM is not enough for everyone");
|
2017-08-24 08:06:41 +00:00
|
|
|
|
mkregion(0, 0xa0000, REGALLOC|REGFREE|REGRWX);
|
2017-08-24 09:25:23 +00:00
|
|
|
|
mkregion(0xa0000, 0xc0000, REGALLOC|REGRWX);
|
2017-08-24 08:06:41 +00:00
|
|
|
|
mkregion(0xc0000, 0x100000, REGALLOC|REGRES|REGRWX);
|
2017-06-20 15:15:53 +00:00
|
|
|
|
if(fbsz != 0 && fbaddr < gmemsz){
|
2017-08-24 08:06:41 +00:00
|
|
|
|
mkregion(0x100000, fbaddr, REGALLOC|REGFREE|REGRWX);
|
|
|
|
|
mkregion(fbaddr + fbsz, gmemsz, REGALLOC|REGFREE|REGRWX);
|
2017-06-20 15:15:53 +00:00
|
|
|
|
}else
|
2017-08-24 08:06:41 +00:00
|
|
|
|
mkregion(0x100000, gmemsz, REGALLOC|REGFREE|REGRWX);
|
2017-06-17 19:47:04 +00:00
|
|
|
|
if(fbsz != 0){
|
2017-06-20 15:15:53 +00:00
|
|
|
|
if(fbaddr < 1<<20) sysfatal("framebuffer must not be within first 1 MB");
|
|
|
|
|
if(fbaddr != (u32int) fbaddr || (u32int)(fbaddr+fbsz) < fbaddr) sysfatal("framebuffer must be within first 4 GB");
|
2017-08-24 08:06:41 +00:00
|
|
|
|
mkregion(fbaddr, fbaddr+fbsz, REGALLOC|REGRWX);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
vmxsetup();
|
2017-08-28 17:27:41 +00:00
|
|
|
|
mksegment(segname);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
loadkernel(argv[0]);
|
|
|
|
|
pciinit();
|
|
|
|
|
|
2020-12-07 18:59:54 +01:00
|
|
|
|
vgainit(newwin);
|
2017-06-13 14:18:14 +00:00
|
|
|
|
for(i = 0; i < edevn; i++)
|
|
|
|
|
if(edev[i](edevaux[i]) < 0)
|
|
|
|
|
sysfatal("%s: %r", edevt[i]);
|
|
|
|
|
|
|
|
|
|
pcibusmap();
|
2017-06-21 22:18:26 +00:00
|
|
|
|
|
|
|
|
|
if(srvname != nil) init9p(srvname);
|
2017-06-27 09:21:30 +00:00
|
|
|
|
if(kconfig != nil) kconfig();
|
2017-06-13 14:18:14 +00:00
|
|
|
|
runloop();
|
|
|
|
|
exits(nil);
|
|
|
|
|
}
|