9 int ctlfd, regsfd, mapfd, waitfd;
10 Channel *waitch, *sleepch, *notifch;
11 enum { MSEC = 1000*1000, MinSleep = MSEC, SleeperPoll = 2000*MSEC } ;
13 typedef struct VmxNotif VmxNotif;
19 int mainstacksize = 65536;
28 sysfatal("malloc: %r");
30 setmalloctag(v, getcallerpc(&sz));
35 vmerror(char *fmt, ...)
41 fmtfdinit(&f, 2, buf, sizeof buf);
43 fmtvprint(&f, fmt, arg);
56 rc = vfprint(ctlfd, fmt, va);
64 if(r->segname == nil){
65 if(fprint(mapfd, "--- wb %#ullx %#ullx\n", (uvlong)r->start, (uvlong)r->end) < 0)
66 vmerror("updating memory map: %r");
68 if(fprint(mapfd, "%c%c%c wb %#ullx %#ullx %s %#ullx\n",
69 (r->type & REGR) != 0 ? 'r' : '-',
70 (r->type & REGW) != 0 ? 'w' : '-',
71 (r->type & REGX) != 0 ? 'x' : '-',
72 (uvlong)r->start, (uvlong)r->end, r->segname, (uvlong)r->segoff) < 0)
73 vmerror("updating memory map: %r");
84 fd = open("#X/status", OREAD);
85 if(fd < 0) sysfatal("open: %r");
86 rc = read(fd, buf, sizeof(buf)-1);
87 if(rc < 0) sysfatal("read: %r");
91 ctlfd = open("#X/ctl", ORDWR);
92 if(ctlfd < 0) sysfatal("open: %r");
93 if(strcmp(buf, "inactive\n") != 0)
98 regsfd = open("#X/regs", ORDWR);
99 if(regsfd < 0) sysfatal("open: %r");
101 mapfd = open("#X/map", OWRITE|OTRUNC);
102 if(mapfd < 0) sysfatal("open: %r");
103 for(r = mmap; r != nil; r = r->next)
106 waitfd = open("#X/wait", OREAD);
107 if(waitfd < 0) sysfatal("open: %r");
110 enum { RCENT = 256 };
113 uvlong rcvalid[(RCENT+63)/64], rcdirty[(RCENT+63)/64];
120 for(i = 0; i < RCENT; i++)
121 if(rcname[i] != nil && strcmp(n, rcname[i]) == 0)
130 static char buf[4096];
135 e = buf + sizeof(buf);
137 for(i = 0; i < (RCENT+63)/64; i++){
138 if(v = rcdirty[i], v != 0){
139 for(j = 0; j < 64; j++)
141 p = seprint(p, e, "%s%c%#ullx%c", rcname[i*64+j], togo?'=':' ', rcval[i*64+j], togo?';':'\n');
146 if(!togo && p != buf && write(regsfd, buf, p - buf) < p - buf)
147 sysfatal("rcflush: write: %r");
148 return p != buf ? buf : nil;
160 rc = pread(regsfd, buf, sizeof(buf) - 1, 0);
161 if(rc < 0) sysfatal("rcload: pread: %r");
164 for(i = 0; i < nelem(rcname); i++){
168 nf = tokenize(p, f, nelem(f));
172 rcname[i] = strdup(f[0]);
173 rcval[i] = strtoull(f[1], nil, 0);
174 rcvalid[i>>6] |= 1ULL<<(i&63);
176 for(; i < nelem(rcname); i++){
179 rcvalid[i>>6] &= ~(1ULL<<(i&63));
189 if(i < 0 || (rcvalid[i>>6]>>i&1) == 0){
192 if(i < 0) sysfatal("unknown register %s", reg);
198 rpoke(char *reg, uvlong val, int clean)
204 if((rcvalid[i>>6]>>(i&63)&1) != 0 && rcval[i] == val) return;
207 for(i = 0; i < nelem(rcname); i++)
208 if(rcname[i] == nil){
209 rcname[i] = strdup(reg);
212 assert(i < nelem(rcname));
215 rcvalid[i>>6] |= 1ULL<<(i&63);
217 rcdirty[i>>6] |= 1ULL<<(i&63);
221 rgetsz(char *reg, int sz)
224 case 1: return (u8int)rget(reg);
225 case 2: return (u16int)rget(reg);
226 case 4: return (u32int)rget(reg);
227 case 8: return rget(reg);
229 vmerror("invalid size operand for rgetsz");
236 rsetsz(char *reg, uvlong val, int sz)
239 case 1: rset(reg, (u8int)val | rget(reg) & ~0xffULL); break;
240 case 2: rset(reg, (u16int)val | rget(reg) & ~0xffffULL); break;
241 case 4: rset(reg, (u32int)val); break;
242 case 8: rset(reg, val); break;
244 vmerror("invalid size operand for rsetsz");
250 mkregion(u64int pa, u64int end, int type)
254 r = emalloc(sizeof(Region));
255 if(end < pa) sysfatal("end of region %p before start of region %#p", (void*)end, (void*)pa);
256 if((pa & BY2PG-1) != 0 || (end & BY2PG-1) != 0) sysfatal("address %#p not page aligned", (void*)pa);
260 for(s = mmap; s != nil; s = s->next)
261 if(!(pa < s->start && end < s->end || pa >= s->start && pa >= s->end))
262 sysfatal("region %#p-%#p overlaps region %#p-%#p", (void*)pa, (void*)end, (void*)s->start, (void*)s->end);
263 for(rp = &mmap; (*rp) != nil && (*rp)->start < end; rp = &(*rp)->next)
275 for(r = mmap; r != nil; r = r->next)
276 if(addr >= r->start && addr < r->end)
282 gptr(u64int addr, u64int len)
286 if(addr + len < addr)
288 for(r = mmap; r != nil; r = r->next)
289 if(addr >= r->start && addr < r->end){
290 if(addr + len > r->end)
292 return (uchar *) r->v + (addr - r->start);
302 for(r = mmap; r != nil; r = r->next)
303 if(v >= r->v && v < r->ve)
304 return (uchar *) v - (uchar *) r->v + r->start;
313 for(r = mmap; r != nil; r = r->next)
314 if(v >= r->v && v < r->ve)
315 return (uchar *) r->ve - (uchar *) v;
322 return (u8int *) v + gavail(v);
326 uvlong tmpoff, vgamemoff;
337 sz = BY2PG; /* temporary page */
338 sz += 256*1024; /* vga */
339 for(r = mmap; r != nil; r = r->next){
340 if((r->type & REGALLOC) == 0)
343 if(sz + (r->end - r->start) < sz)
344 sysfatal("out of address space");
345 sz += r->end - r->start;
347 gmem = segattach(0, sn, nil, sz);
348 if(gmem == (void*)-1){
349 snprint(buf, sizeof(buf), "#g/%s", sn);
350 fd = create(buf, OREAD, DMDIR | 0777);
351 if(fd < 0) sysfatal("create: %r");
353 snprint(buf, sizeof(buf), "#g/%s/ctl", sn);
354 fd = open(buf, OWRITE|OTRUNC);
355 if(fd < 0) sysfatal("open: %r");
356 snprint(buf, sizeof(buf), "va %#ullx %#ullx sticky", 0x10000000ULL, (uvlong)sz);
357 if(write(fd, buf, strlen(buf)) < 0) sysfatal("write: %r");
359 gmem = segattach(0, sn, nil, sz);
360 if(gmem == (void*)-1) sysfatal("segattach: %r");
362 memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
364 for(r = mmap; r != nil; r = r->next){
365 if(r->segname == nil) continue;
366 r->segoff = p - gmem;
368 p += r->end - r->start;
372 vgamemoff = p - gmem;
373 regptr(0xa0000)->segoff = vgamemoff;
374 regptr(0xa0000)->v = vgamem;
376 regptr(0xa0000)->ve = p;
382 postexc(char *name, vlong code)
385 if(ctl("exc %s,%#ux", name, (u32int)code) < 0)
386 sysfatal("ctl(postexc): %r");
388 if(ctl("exc %s", name) < 0)
389 sysfatal("ctl(postexc): %r");
398 if(ctl("go %s", s == nil ? "" : s) < 0)
399 sysfatal("go %s: %r", s == nil ? "" : s);
406 static char buf[512];
410 threadsetname("waitexit");
412 rc = read(waitfd, buf, sizeof(buf) - 1);
414 sysfatal("read: %r");
416 p = strchr(buf, '\n');
418 sendp(waitch, strdup(buf));
422 vlong timerevent = -1;
431 timerid = threadid();
432 timerevent = nsec() + SleeperPoll;
434 threadsetname("sleeper");
439 if(then <= now) timerevent = now + SleeperPoll;
441 if(then - now >= MinSleep){
442 sleep((then - now) / MSEC);
459 proccreate(waitproc, nil, 4096);
460 proccreate(sleeperproc, nil, 4096);
469 [WAIT] {waitch, &waitmsg, CHANRCV},
470 [SLEEP] {sleepch, &ul, CHANRCV},
471 [NOTIF] {notifch, ¬if, CHANRCV},
477 processexit(waitmsg);
488 if(getexit == 0 && state == VMRUNNING)
496 sendnotif(void (*f)(void *), void *arg)
498 VmxNotif notif = {f, arg};
500 if(threadid() == mainid)
503 send(notifch, ¬if);
506 extern void vgainit(void);
507 extern void pciinit(void);
508 extern void pcibusmap(void);
509 extern void cpuidinit(void);
510 extern void vgafbparse(char *);
511 extern void init9p(char *);
524 l = strtoull(s, &p, 0);
526 case 'k': case 'K': p++; l *= 1<<10; break;
527 case 'm': case 'M': p++; l *= 1<<20; break;
528 case 'g': case 'G': p++; l *= 1<<30; break;
530 if(*p != 0) sysfatal("invalid argument: %s", s);
539 extern u32int iodebug[32];
544 n = strtoul(s, &p, 0);
546 no: sysfatal("invalid iodebug argument (error at %#q)", s);
547 if(n >= sizeof(iodebug)*8)
548 range: sysfatal("out of iodebug range (0-%#ux)", sizeof(iodebug)*8-1);
551 m = strtoul(s, &p, 0);
552 if(m >= sizeof(iodebug)*8)
554 if(s == p || m < n) goto no;
560 iodebug[n>>5] &= ~(1<<(n&31));
562 iodebug[n>>5] |= 1<<(n&31);
572 blanks = strdup(argv0);
573 for(p = blanks; *p != 0; p++)
575 fprint(2, "usage: %s [ -M mem ] [ -c com1rd[,com1wr] ] [ -C com2rd[,com2r] ] [ -n nic ]\n", argv0);
576 fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v vga ] [ -9 srv ] kernel [ args ... ]\n", blanks);
577 threadexitsall("usage");
580 void (*kconfig)(void);
583 threadmain(int argc, char **argv)
585 static int (*edev[16])(char *);
586 static char *edevt[nelem(edev)];
587 static char *edevaux[nelem(edev)];
589 static uvlong gmemsz = 64*1024*1024;
590 static char *srvname;
591 extern uintptr fbsz, fbaddr;
597 waitch = chancreate(sizeof(char *), 32);
598 sleepch = chancreate(sizeof(ulong), 32);
599 notifch = chancreate(sizeof(VmxNotif), 16);
603 bootmod = realloc(bootmod, (bootmodn + 1) * sizeof(char *));
604 bootmod[bootmodn++] = strdup(EARGF(usage()));
607 uartinit(0, EARGF(usage()));
610 uartinit(1, EARGF(usage()));
613 assert(edevn < nelem(edev));
614 edev[edevn] = mkvionet;
615 edevt[edevn] = "virtio network";
616 edevaux[edevn++] = strdup(EARGF(usage()));
619 assert(edevn < nelem(edev));
620 edevaux[edevn] = strdup(EARGF(usage()));
621 if(strncmp(edevaux[edevn], "ide:", 4) == 0){
623 edev[edevn] = mkideblk;
624 edevt[edevn] = "ide block";
626 edev[edevn] = mkvioblk;
627 edevt[edevn] = "virtio block";
632 gmemsz = siparse(EARGF(usage()));
633 if(gmemsz != (uintptr) gmemsz) sysfatal("too much memory for address space");
636 vgafbparse(EARGF(usage()));
639 if(srvname != nil) usage();
640 srvname = EARGF(usage());
643 setiodebug(EARGF(usage()));
648 if(argc < 1) usage();
652 if(gmemsz < 1<<20) sysfatal("640 KB of RAM is not enough for everyone");
653 mkregion(0, 0xa0000, REGALLOC|REGFREE|REGRWX);
654 mkregion(0xa0000, 0xc0000, REGALLOC);
655 mkregion(0xc0000, 0x100000, REGALLOC|REGRES|REGRWX);
656 if(fbsz != 0 && fbaddr < gmemsz){
657 mkregion(0x100000, fbaddr, REGALLOC|REGFREE|REGRWX);
658 mkregion(fbaddr + fbsz, gmemsz, REGALLOC|REGFREE|REGRWX);
660 mkregion(0x100000, gmemsz, REGALLOC|REGFREE|REGRWX);
662 if(fbaddr < 1<<20) sysfatal("framebuffer must not be within first 1 MB");
663 if(fbaddr != (u32int) fbaddr || (u32int)(fbaddr+fbsz) < fbaddr) sysfatal("framebuffer must be within first 4 GB");
664 mkregion(fbaddr, fbaddr+fbsz, REGALLOC|REGRWX);
672 for(i = 0; i < edevn; i++)
673 if(edev[i](edevaux[i]) < 0)
674 sysfatal("%s: %r", edevt[i]);
678 if(srvname != nil) init9p(srvname);
679 if(kconfig != nil) kconfig();