11 int ctlfd, regsfd, mapfd, waitfd;
12 Channel *waitch, *sleepch, *notifch;
13 enum { MSEC = 1000*1000, MinSleep = MSEC, SleeperPoll = 2000*MSEC } ;
15 typedef struct VmxNotif VmxNotif;
21 int mainstacksize = 65536;
30 sysfatal("malloc: %r");
32 setmalloctag(v, getcallerpc(&sz));
37 vmerror(char *fmt, ...)
43 fmtfdinit(&f, 2, buf, sizeof buf);
45 fmtvprint(&f, fmt, arg);
58 rc = vfprint(ctlfd, fmt, va);
66 if(r->segname == nil){
67 if(fprint(mapfd, "--- wb %#ullx %#ullx\n", (uvlong)r->start, (uvlong)r->end) < 0)
68 vmerror("updating memory map: %r");
70 if(fprint(mapfd, "%c%c%c wb %#ullx %#ullx %s %#ullx\n",
71 (r->type & REGR) != 0 ? 'r' : '-',
72 (r->type & REGW) != 0 ? 'w' : '-',
73 (r->type & REGX) != 0 ? 'x' : '-',
74 (uvlong)r->start, (uvlong)r->end, r->segname, (uvlong)r->segoff) < 0)
75 vmerror("updating memory map: %r");
82 static char name[128];
85 ctlfd = open("#X/clone", ORDWR|ORCLOSE);
86 if(ctlfd < 0) sysfatal("open: %r");
87 rc = read(ctlfd, name, sizeof(name) - 1);
88 if(rc < 0) sysfatal("read: %r");
92 segname = smprint("vm.%s", name);
96 snprint(buf, sizeof(buf), "#X/%s/regs", name);
97 regsfd = open(buf, ORDWR);
98 if(regsfd < 0) sysfatal("open: %r");
100 snprint(buf, sizeof(buf), "#X/%s/map", name);
101 mapfd = open(buf, OWRITE|OTRUNC);
102 if(mapfd < 0) sysfatal("open: %r");
104 snprint(buf, sizeof(buf), "#X/%s/wait", name);
105 waitfd = open(buf, OREAD);
106 if(waitfd < 0) sysfatal("open: %r");
109 enum { RCENT = 256 };
112 uvlong rcvalid[(RCENT+63)/64], rcdirty[(RCENT+63)/64];
119 for(i = 0; i < RCENT; i++)
120 if(rcname[i] != nil && strcmp(n, rcname[i]) == 0)
129 static char buf[4096];
134 e = buf + sizeof(buf);
136 for(i = 0; i < (RCENT+63)/64; i++){
137 if(v = rcdirty[i], v != 0){
138 for(j = 0; j < 64; j++)
140 p = seprint(p, e, "%s%c%#ullx%c", rcname[i*64+j], togo?'=':' ', rcval[i*64+j], togo?';':'\n');
145 if(!togo && p != buf && write(regsfd, buf, p - buf) < p - buf)
146 sysfatal("rcflush: write: %r");
147 return p != buf ? buf : nil;
159 rc = pread(regsfd, buf, sizeof(buf) - 1, 0);
160 if(rc < 0) sysfatal("rcload: pread: %r");
163 for(i = 0; i < nelem(rcname); i++){
167 nf = tokenize(p, f, nelem(f));
171 rcname[i] = strdup(f[0]);
172 rcval[i] = strtoull(f[1], nil, 0);
173 rcvalid[i>>6] |= 1ULL<<(i&63);
175 for(; i < nelem(rcname); i++){
178 rcvalid[i>>6] &= ~(1ULL<<(i&63));
188 if(i < 0 || (rcvalid[i>>6]>>i&1) == 0){
191 if(i < 0) sysfatal("unknown register %s", reg);
197 rpoke(char *reg, uvlong val, int clean)
203 if((rcvalid[i>>6]>>(i&63)&1) != 0 && rcval[i] == val) return;
206 for(i = 0; i < nelem(rcname); i++)
207 if(rcname[i] == nil){
208 rcname[i] = strdup(reg);
211 assert(i < nelem(rcname));
214 rcvalid[i>>6] |= 1ULL<<(i&63);
216 rcdirty[i>>6] |= 1ULL<<(i&63);
220 rgetsz(char *reg, int sz)
223 case 1: return (u8int)rget(reg);
224 case 2: return (u16int)rget(reg);
225 case 4: return (u32int)rget(reg);
226 case 8: return rget(reg);
228 vmerror("invalid size operand for rgetsz");
235 rsetsz(char *reg, uvlong val, int sz)
238 case 1: rset(reg, (u8int)val | rget(reg) & ~0xffULL); break;
239 case 2: rset(reg, (u16int)val | rget(reg) & ~0xffffULL); break;
240 case 4: rset(reg, (u32int)val); break;
241 case 8: rset(reg, val); break;
243 vmerror("invalid size operand for rsetsz");
249 mkregion(u64int pa, u64int end, int type)
253 r = emalloc(sizeof(Region));
254 if(end < pa) sysfatal("end of region %p before start of region %#p", (void*)end, (void*)pa);
255 if((pa & BY2PG-1) != 0 || (end & BY2PG-1) != 0) sysfatal("address %#p not page aligned", (void*)pa);
259 for(s = mmap; s != nil; s = s->next)
260 if(!(pa < s->start && end < s->end || pa >= s->start && pa >= s->end))
261 sysfatal("region %#p-%#p overlaps region %#p-%#p", (void*)pa, (void*)end, (void*)s->start, (void*)s->end);
262 for(rp = &mmap; (*rp) != nil && (*rp)->start < end; rp = &(*rp)->next)
274 for(r = mmap; r != nil; r = r->next)
275 if(addr >= r->start && addr < r->end)
281 gptr(u64int addr, u64int len)
285 if(addr + len < addr)
287 for(r = mmap; r != nil; r = r->next)
288 if(addr >= r->start && addr < r->end){
289 if(addr + len > r->end)
291 return (uchar *) r->v + (addr - r->start);
301 for(r = mmap; r != nil; r = r->next)
302 if(v >= r->v && v < r->ve)
303 return (uchar *) v - (uchar *) r->v + r->start;
312 for(r = mmap; r != nil; r = r->next)
313 if(v >= r->v && v < r->ve)
314 return (uchar *) r->ve - (uchar *) v;
321 return (u8int *) v + gavail(v);
325 uvlong tmpoff, vgamemoff;
336 sz = BY2PG; /* temporary page */
337 sz += 256*1024; /* vga */
338 for(r = mmap; r != nil; r = r->next){
339 if((r->type & REGALLOC) == 0)
342 if(sz + (r->end - r->start) < sz)
343 sysfatal("out of address space");
344 sz += r->end - r->start;
346 gmem = segattach(0, sn, nil, sz);
347 if(gmem == (void*)-1){
348 snprint(buf, sizeof(buf), "#g/%s", sn);
349 fd = create(buf, OREAD|segrclose, DMDIR | 0777);
350 if(fd < 0) sysfatal("create: %r");
351 snprint(buf, sizeof(buf), "#g/%s/ctl", sn);
352 fd = open(buf, OWRITE|OTRUNC);
353 if(fd < 0) sysfatal("open: %r");
354 snprint(buf, sizeof(buf), "va %#ullx %#ullx sticky", 0x10000000ULL, (uvlong)sz);
355 if(write(fd, buf, strlen(buf)) < 0) sysfatal("write: %r");
357 gmem = segattach(0, sn, nil, sz);
358 if(gmem == (void*)-1) sysfatal("segattach: %r");
360 memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
362 for(r = mmap; r != nil; r = r->next){
363 if(r->segname == nil) continue;
364 r->segoff = p - gmem;
366 p += r->end - r->start;
370 vgamemoff = p - gmem;
371 regptr(0xa0000)->segoff = vgamemoff;
372 regptr(0xa0000)->v = vgamem;
374 regptr(0xa0000)->ve = p;
378 for(r = mmap; r != nil; r = r->next)
384 postexc(char *name, vlong code)
387 if(ctl("exc %s,%#ux", name, (u32int)code) < 0)
388 sysfatal("ctl(postexc): %r");
390 if(ctl("exc %s", name) < 0)
391 sysfatal("ctl(postexc): %r");
400 if(ctl("go %s", s == nil ? "" : s) < 0)
401 sysfatal("go %s: %r", s == nil ? "" : s);
408 static char buf[512];
412 threadsetname("waitexit");
414 rc = read(waitfd, buf, sizeof(buf) - 1);
416 sysfatal("read: %r");
418 p = strchr(buf, '\n');
420 sendp(waitch, strdup(buf));
424 vlong timerevent = -1;
433 timerid = threadid();
434 timerevent = nsec() + SleeperPoll;
436 threadsetname("sleeper");
441 if(then <= now) timerevent = now + SleeperPoll;
443 if(then - now >= MinSleep){
444 sleep((then - now) / MSEC);
461 proccreate(waitproc, nil, 4096);
462 proccreate(sleeperproc, nil, 4096);
471 [WAIT] {waitch, &waitmsg, CHANRCV},
472 [SLEEP] {sleepch, &ul, CHANRCV},
473 [NOTIF] {notifch, ¬if, CHANRCV},
479 processexit(waitmsg);
490 if(getexit == 0 && state == VMRUNNING)
498 sendnotif(void (*f)(void *), void *arg)
500 VmxNotif notif = {f, arg};
502 if(threadid() == mainid)
505 send(notifch, ¬if);
508 extern void vgainit(void);
509 extern void pciinit(void);
510 extern void pcibusmap(void);
511 extern void cpuidinit(void);
512 extern void vgafbparse(char *);
513 extern void init9p(char *);
526 l = strtoull(s, &p, 0);
528 case 'k': case 'K': p++; l *= 1<<10; break;
529 case 'm': case 'M': p++; l *= 1<<20; break;
530 case 'g': case 'G': p++; l *= 1<<30; break;
532 if(*p != 0) sysfatal("invalid argument: %s", s);
541 extern u32int iodebug[32];
546 n = strtoul(s, &p, 0);
548 no: sysfatal("invalid iodebug argument (error at %#q)", s);
549 if(n >= sizeof(iodebug)*8)
550 range: sysfatal("out of iodebug range (0-%#ux)", sizeof(iodebug)*8-1);
553 m = strtoul(s, &p, 0);
554 if(m >= sizeof(iodebug)*8)
556 if(s == p || m < n) goto no;
562 iodebug[n>>5] &= ~(1<<(n&31));
564 iodebug[n>>5] |= 1<<(n&31);
574 blanks = strdup(argv0);
575 for(p = blanks; *p != 0; p++)
577 fprint(2, "usage: %s [ -M mem ] [ -c com1rd[,com1wr] ] [ -C com2rd[,com2r] ] [ -n nic ]\n", argv0);
578 fprint(2, " %s [ -d blockfile ] [ -m module ] [ -v vga ] [ -9 srv ] kernel [ args ... ]\n", blanks);
579 threadexitsall("usage");
582 void (*kconfig)(void);
585 threadmain(int argc, char **argv)
587 static int (*edev[16])(char *);
588 static char *edevt[nelem(edev)];
589 static char *edevaux[nelem(edev)];
591 static uvlong gmemsz = 64*1024*1024;
592 static char *srvname;
593 extern uintptr fbsz, fbaddr;
599 waitch = chancreate(sizeof(char *), 32);
600 sleepch = chancreate(sizeof(ulong), 32);
601 notifch = chancreate(sizeof(VmxNotif), 16);
605 bootmod = realloc(bootmod, (bootmodn + 1) * sizeof(char *));
606 bootmod[bootmodn++] = strdup(EARGF(usage()));
609 segname = strdup(EARGF(usage()));
613 uartinit(0, EARGF(usage()));
616 uartinit(1, EARGF(usage()));
619 assert(edevn < nelem(edev));
620 edev[edevn] = mkvionet;
621 edevt[edevn] = "virtio network";
622 edevaux[edevn++] = strdup(EARGF(usage()));
625 assert(edevn < nelem(edev));
626 edevaux[edevn] = strdup(EARGF(usage()));
627 if(strncmp(edevaux[edevn], "ide:", 4) == 0){
629 edev[edevn] = mkideblk;
630 edevt[edevn] = "ide block";
632 edev[edevn] = mkvioblk;
633 edevt[edevn] = "virtio block";
638 gmemsz = siparse(EARGF(usage()));
639 if(gmemsz != (uintptr) gmemsz) sysfatal("too much memory for address space");
642 vgafbparse(EARGF(usage()));
645 if(srvname != nil) usage();
646 srvname = EARGF(usage());
649 setiodebug(EARGF(usage()));
654 if(argc < 1) usage();
658 if(gmemsz < 1<<20) sysfatal("640 KB of RAM is not enough for everyone");
659 mkregion(0, 0xa0000, REGALLOC|REGFREE|REGRWX);
660 mkregion(0xa0000, 0xc0000, REGALLOC|REGRWX);
661 mkregion(0xc0000, 0x100000, REGALLOC|REGRES|REGRWX);
662 if(fbsz != 0 && fbaddr < gmemsz){
663 mkregion(0x100000, fbaddr, REGALLOC|REGFREE|REGRWX);
664 mkregion(fbaddr + fbsz, gmemsz, REGALLOC|REGFREE|REGRWX);
666 mkregion(0x100000, gmemsz, REGALLOC|REGFREE|REGRWX);
668 if(fbaddr < 1<<20) sysfatal("framebuffer must not be within first 1 MB");
669 if(fbaddr != (u32int) fbaddr || (u32int)(fbaddr+fbsz) < fbaddr) sysfatal("framebuffer must be within first 4 GB");
670 mkregion(fbaddr, fbaddr+fbsz, REGALLOC|REGRWX);
678 for(i = 0; i < edevn; i++)
679 if(edev[i](edevaux[i]) < 0)
680 sysfatal("%s: %r", edevt[i]);
684 if(srvname != nil) init9p(srvname);
685 if(kconfig != nil) kconfig();