shithub: riscv

Download patch

ref: 164588e3e2aca1f6deac1dd4bcf962a0867a26fc
parent: becb89bae53e01785bfd843478737eeb77a9419f
author: aiju <devnull@localhost>
date: Tue Jun 20 11:15:53 EDT 2017

vmx(1): clean up region handling code; changes to support amd64

--- a/sys/src/cmd/vmx/dat.h
+++ b/sys/src/cmd/vmx/dat.h
@@ -35,7 +35,14 @@
 
 struct Region {
 	uintptr start, end;
-	enum { REGNO, REGMEM, REGFB } type;
+	enum {
+		REGALLOC = 1, /* allocate memory for region */
+		REGRO = 2, /* read-only */
+		
+		/* E820 types, 0 == omitted from memory map */
+		REGFREE = 1<<8, /* report to OS as free */
+		REGRES = 2<<8, /* report to OS as reserved */
+	} type;
 	char *segname;
 	uvlong segoff;
 	void *v, *ve;
--- a/sys/src/cmd/vmx/exith.c
+++ b/sys/src/cmd/vmx/exith.c
@@ -33,7 +33,7 @@
 	extern uchar *tmp;
 	extern uvlong tmpoff;
 	void *targ;
-	uvlong pc, si;
+	uvlong pc;
 	char buf[ERRMAX];
 	extern int getexit;
 	
@@ -46,7 +46,6 @@
 	case 8: *(u64int*)targ = *val; break;
 	}
 	pc = rget(RPC);
-	si = rget("si");
 	rcflush(0);
 	if(ctl("step -map %#ullx vm %#ullx", pa & ~0xfff, tmpoff) < 0){
 		rerrstr(buf, sizeof(buf));
@@ -262,7 +261,10 @@
 		ax = cp->ax;
 		bx = 0;
 		cx = cp->cx & 0x121;
-		dx = cp->dx & 0x04100000;
+		if(sizeof(uintptr) == 8)
+			dx = cp->dx & 0x24100800;
+		else
+			dx = cp->dx & 0x04100000;
 		break;
 	case 0x80000002: goto literal; /* brand string */
 	case 0x80000003: goto literal; /* brand string */
@@ -308,10 +310,6 @@
 		if(rd) val = rget("pat");
 		else rset("pat", val);
 		break;
-	case 0xC0000080:
-		if(rd) val = rget("efer");
-		else rset("efer", val);
-		break;
 	case 0x8B: val = 0; break; /* microcode update */
 	default:
 		if(rd){
@@ -376,7 +374,7 @@
 		}
 		break;
 	case 4:
-		switch(ei->qual >> 4 & 3){
+		switch(q >> 4 & 3){
 		case 0:
 			vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
 			rset("cr4real", rget(x86reg[q >> 8 & 15]));
--- a/sys/src/cmd/vmx/ksetup.c
+++ b/sys/src/cmd/vmx/ksetup.c
@@ -14,27 +14,48 @@
 extern int cmdlinen;
 extern char **cmdlinev;
 
+static int elf64;
 
 static int
-isusermem(Region *r)
+biostype(Region *r)
 {
-	return r->type == REGMEM;
+	return r->type >> 8 & 0xff;
 }
 
+static void *
+pack(void *v, char *fmt, ...)
+{
+	uchar *p;
+	va_list va;
+	
+	p = v;
+	va_start(va, fmt);
+	for(; *fmt != 0; fmt++)
+		switch(*fmt){
+		case '.': p++; break;
+		case 's': PUT16(p, 0, va_arg(va, int)); p += 2; break;
+		case 'i': PUT32(p, 0, va_arg(va, u32int)); p += 4; break;
+		case 'v': PUT64(p, 0, va_arg(va, u64int)); p += 8; break;
+		case 'z': if(elf64) {PUT64(p, 0, va_arg(va, uintptr)); p += 8;} else {PUT32(p, 0, va_arg(va, uintptr)); p += 4;} break;
+		default: sysfatal("pack: unknown fmt character %c", *fmt);
+		}
+	va_end(va);
+	return p;
+}
+
 static int
 putmmap(uchar *p0)
 {
-	u32int *p;
+	uchar *p;
 	Region *r;
+	int t;
 	
-	p = (u32int *) p0;
+	p = p0;
 	for(r = mmap; r != nil; r = r->next){
-		if(!isusermem(r)) continue;
-		if(gavail(p) < 20) sysfatal("out of guest memory");
-		p[0] = 20;
-		p[1] = r->start;
-		p[2] = r->end - r->start;
-		p[3] = 1;
+		t = biostype(r);
+		if(t == 0) continue;
+		if(gavail(p) < 24) sysfatal("out of guest memory");
+		p = pack(p, "ivvi", 20, (uvlong) r->start, (uvlong)(r->end - r->start), t);
 	}
 	return (uchar *) p - p0;
 }
@@ -131,6 +152,7 @@
 	bssend = -(-bssend & -BY2PG);
 	p = gptr(bssend, 128);
 	if(p == nil) sysfatal("no space for multiboot structure");
+	memset(p, 0, 128);
 	p[0] = 1<<0;
 	p[1] = gavail(gptr(0, 0)) >> 10;
 	if(p[1] > 640) p[1] = 640;
@@ -165,7 +187,6 @@
 	return 1;
 }
 
-static int elf64;
 typedef struct ELFHeader ELFHeader;
 struct ELFHeader {
 	uintptr entry, phoff, shoff;
@@ -283,11 +304,19 @@
 elfsymbol(ELFSymbol *s, uchar *p, uchar *e)
 {
 	s->iname = elff(&p, e, 4);
-	s->addr = elff(&p, e, -1);
-	s->size = elff(&p, e, -1);
-	s->info = elff(&p, e, 1);
-	s->other = elff(&p, e, 1);
-	s->shndx = elff(&p, e, 2);
+	if(elf64){
+		s->info = elff(&p, e, 1);
+		s->other = elff(&p, e, 1);
+		s->shndx = elff(&p, e, 2);
+		s->addr = elff(&p, e, -1);
+		s->size = elff(&p, e, -1);
+	}else{
+		s->addr = elff(&p, e, -1);
+		s->size = elff(&p, e, -1);
+		s->info = elff(&p, e, 1);
+		s->other = elff(&p, e, 1);
+		s->shndx = elff(&p, e, 2);
+	}
 }
 
 static void
@@ -442,7 +471,7 @@
 }
 
 static uchar *obsdarg, *obsdarg0, *obsdargnext;
-static int obsdargc;
+static int obsdarglen;
 static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev;
 
 enum {
@@ -459,35 +488,8 @@
 	BOOTARG_BOOTSR,
 	BOOTARG_EFIINFO,
 	BOOTARG_END = -1,
-	
-	BIOS_MAP_END = 0,
-	BIOS_MAP_FREE,
-	BIOS_MAP_RES,
-	BIOS_MAP_ACPI,
-	BIOS_MAP_NVS,
 };
 
-static void *
-pack(void *v, char *fmt, ...)
-{
-	uchar *p;
-	va_list va;
-	
-	p = v;
-	va_start(va, fmt);
-	for(; *fmt != 0; fmt++)
-		switch(*fmt){
-		case '.': p++; break;
-		case 's': PUT16(p, 0, va_arg(va, int)); p += 2; break;
-		case 'i': PUT32(p, 0, va_arg(va, u32int)); p += 4; break;
-		case 'v': PUT64(p, 0, va_arg(va, u64int)); p += 8; break;
-		case 'z': if(elf64) {PUT64(p, 0, va_arg(va, uintptr)); p += 8;} else {PUT32(p, 0, va_arg(va, uintptr)); p += 4;} break;
-		default: sysfatal("pack: unknown fmt character %c", *fmt);
-		}
-	va_end(va);
-	return p;
-}
-
 static void
 obsdelfload(void)
 {
@@ -546,10 +548,10 @@
 {
 	if(obsdarg == obsdarg0 + 12) obsdarg += 4;
 	PUT32(obsdarg0, 4, obsdarg - obsdarg0); /* size */
+	obsdarglen += obsdarg - obsdarg0;
 	PUT32(obsdargnext, 0, gpa(obsdarg0));
 	obsdargnext = obsdarg0 + 8;
 	obsdarg0 = nil;	
-	obsdargc++;
 }
 
 static void
@@ -556,18 +558,15 @@
 obsdargs(void)
 {
 	Region *r;
-	uvlong s, e;
+	int t;
 
 	obsdstart(BOOTARG_MEMMAP);
-	obsdpack("vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
 	for(r = mmap; r != nil; r = r->next){
-		s = r->start;
-		e = r->end;
-		if(s < (1<<20)) s = 1<<20;
-		if(e <= s || r->type == REGFB) continue;
-		obsdpack("vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
+		t = biostype(r);
+		if(t == 0) continue;
+		obsdpack("vvi", (uvlong)r->start, (uvlong)(r->end - r->start), t);
 	}
-	obsdpack("vvi", 0ULL, 0ULL, BIOS_MAP_END);
+	obsdpack("vvi", 0ULL, 0ULL, 0);
 	obsdend();
 	obsdstart(BOOTARG_CONSDEV); obsdpack("iiii", obsdconsdev, -1, -1, 0); obsdend();
 	if(obsddbcons != -1){
@@ -668,7 +667,7 @@
 	obsdargnext = &v[32]; /* bootargv */
 	obsdargs();
 	assert(obsdarg0 == nil);
-	PUT32(v, 28, obsdargc); /* bootargc */
+	PUT32(v, 28, obsdarglen); /* bootargc */
 	rset(RSP, sp);
 	rset(RPC, eh.entry);
 	return 1;
@@ -708,7 +707,6 @@
 	if(addr >= memend) addr = memend - 1;
 	if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd");
 	addr = addr - (sz - 1) & -4;
-	print("%#ux %#ux\n", addr, (u32int)sz);
 	v = gptr(addr, sz);
 	if(v == nil) sysfatal("linux: initrd: gptr failed");
 	seek(fd, 0, 0);
@@ -799,18 +797,15 @@
 {
 	Region *r;
 	uchar *v;
-	uvlong s, e;
+	int t;
 	int n;
 	
 	v = zp + 0x2d0;
-	v = pack(v, "vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
 	n = 1;
 	for(r = mmap; r != nil; r = r->next){
-		s = r->start;
-		e = r->end;
-		if(s < (1<<20)) s = 1<<20;
-		if(e <= s || r->type == REGFB) continue;
-		v = pack(v, "vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
+		t = biostype(r);
+		if(t == 0) continue;
+		v = pack(v, "vvi", r->start, r->end - r->start, t);
 		n++;
 	}
 	PUT8(zp, 0x1e8, n);
--- a/sys/src/cmd/vmx/virtio.c
+++ b/sys/src/cmd/vmx/virtio.c
@@ -86,7 +86,7 @@
 	int val;
 	
 	d = ((void**)arg)[0];
-	val = (int) ((void**)arg)[1];
+	val = (uintptr)((void**)arg)[1];
 	if(val != 0)
 		d->isrstat |= val;
 	else
--- a/sys/src/cmd/vmx/vmx.c
+++ b/sys/src/cmd/vmx/vmx.c
@@ -64,7 +64,9 @@
 	static int fd;
 	static char buf[128];
 	Region *r;
-	int rc;
+	uvlong start, end, off;
+	char *name;
+	int rc, type;
 	
 	fd = open("#X/status", OREAD);
 	if(fd < 0) sysfatal("open: %r");
@@ -85,9 +87,26 @@
 	
 	fd = open("#X/map", OWRITE|OTRUNC);
 	if(fd < 0) sysfatal("open: %r");
-	for(r = mmap; r != nil; r = r->next)
-		if(r->segname != nil && fprint(fd, "rwx wb %#ullx %#ullx %s %#ullx\n", (uvlong)r->start, (uvlong)r->end, r->segname, r->segoff) < 0)
+	for(r = mmap; r != nil; ){
+		if(r->segname == nil){
+			r = r->next;
+			continue;
+		}
+		start = r->start;
+		end = r->end;
+		name = r->segname;
+		off = r->segoff;
+		type = r->type;
+		while(r = r->next, r != nil){
+			if(r->segname == nil)
+				continue;
+			if(r->start != end || r->segoff != off + end - start || ((r->type ^ type) & REGRO) != 0)
+				break;
+			end = r->end;
+		}
+		if(fprint(fd, "r%cx wb %#ullx %#ullx %s %#ullx\n", (type & REGRO) != 0 ? '-' : 'w', start, end, name, off) < 0)
 			sysfatal("writing memory map: %r");
+	}
 	close(fd);
 	
 	waitfd = open("#X/wait", OREAD);
@@ -205,16 +224,15 @@
 }
 
 Region *
-mkregion(u64int pa, u64int len, int type)
+mkregion(u64int pa, u64int end, int type)
 {
 	Region *r, **rp;
-	
-	assert(pa + len >= pa);
+
 	r = emalloc(sizeof(Region));
-	if((pa & BY2PG-1) != 0) sysfatal("address %p not page aligned", (void*)pa);
+	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);
 	r->start = pa;
-	len = -(-len & -BY2PG);
-	r->end = pa + len;
+	r->end = end;
 	r->type = type;
 	for(rp = &mmap; *rp != nil; rp = &(*rp)->next)
 		;
@@ -245,7 +263,7 @@
 
 	for(r = mmap; r != nil; r = r->next)
 		if(v >= r->v && v < r->ve)
-			return (uchar *) v - (uchar *) r->v;
+			return (uchar *) v - (uchar *) r->v + r->start;
 	return -1;
 }
 
@@ -280,10 +298,8 @@
 
 	sz = BY2PG;
 	for(r = mmap; r != nil; r = r->next){
-		switch(r->type){
-		case REGMEM: case REGFB: break;
-		default: continue;
-		}
+		if((r->type & REGALLOC) == 0)
+			continue;
 		r->segname = sn;
 		if(sz + (r->end - r->start) < sz)
 			sysfatal("out of address space");
@@ -304,7 +320,7 @@
 		gmem = segattach(0, sn, nil, sz);
 		if(gmem == (void*)-1) sysfatal("segattach: %r");
 	}
-	memset(gmem, 0, sz > 1>>24 ? 1>>24 : sz);
+	memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
 	p = gmem;
 	for(r = mmap; r != nil; r = r->next){
 		if(r->segname == nil) continue;
@@ -537,11 +553,19 @@
 	cmdlinen = argc - 1;
 	cmdlinev = argv + 1;
 	
-	mkregion(0, gmemsz, REGMEM);
+	if(gmemsz < 1<<20) sysfatal("640 KB of RAM is not enough for everyone");
+	mkregion(0, 0xa0000, REGALLOC|REGFREE);
+	mkregion(0xa0000, 0xc0000, REGALLOC);
+	mkregion(0xc0000, 0x100000, REGALLOC|REGRES);
+	if(fbsz != 0 && fbaddr < gmemsz){
+		mkregion(0x100000, fbaddr, REGALLOC|REGFREE);
+		mkregion(fbaddr + fbsz, gmemsz, REGALLOC|REGFREE);
+	}else
+		mkregion(0x100000, gmemsz, REGALLOC|REGFREE);
 	if(fbsz != 0){
-		if(fbaddr + fbsz < fbaddr) sysfatal("invalid fb address");
-		if(fbaddr + fbsz < gmemsz) sysfatal("framebuffer overlaps with physical memory");
-		mkregion(fbaddr, fbsz, REGFB);
+		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");
+		mkregion(fbaddr, fbaddr+fbsz, REGALLOC);
 	}
 	mksegment("vm");
 	vmxsetup();