Browse Source

Plan 9 from Bell Labs 2011-07-23

David du Colombier 8 years ago
parent
commit
4868ac0147

+ 3 - 2
rc/bin/diskparts

@@ -3,6 +3,7 @@
 rfork e
 if (! test -e /dev/sdctl)
 	bind -b '#S' /dev
+bind -a /bin/disk /bin >[2]/dev/null		# work with /boot too
 
 # set up any /dev/sd partitions.
 # note that really big disks (e.g., aoe devices) may have no mbr
@@ -12,7 +13,7 @@ if (! test -e /dev/sdctl)
 # no plan 9 partition table will delete all extant partitions.
 for(disk in /dev/sd*) {
 	if(test -f $disk/data && test -f $disk/ctl)
-		{ disk/fdisk -p $disk/data |
+		{ fdisk -p $disk/data |
 			grep -v '^delpart ' >$disk/ctl } >[2]/dev/null
 	if(test -f $disk/plan9)
 		parts=($disk/plan9*)
@@ -20,7 +21,7 @@ for(disk in /dev/sd*) {
 		parts=($disk/data)
 	for(part in $parts)
 		if(test -f $part)
-			 { disk/prep -p $part |
+			 { prep -p $part |
 				grep -v '^delpart ' >$disk/ctl } >[2]/dev/null
 }
 

+ 190 - 0
sys/lib/acid/amd64

@@ -0,0 +1,190 @@
+// amd64
+
+defn acidinit()
+{
+	bplist = {};
+	bpfmt = 'b';
+
+	srcpath = {
+		"./",
+		"/sys/src/libc/port/",
+		"/sys/src/libc/9sys/",
+		"/sys/src/libc/amd64/"
+	};
+
+	srcfiles = {};		// list of loaded files
+	srctext = {};		// the text of the files
+}
+
+defn gpr()
+{
+	print("AX    ", *AX, "\n");
+	print("BX    ", *BX, "\n");
+	print("CX    ", *CX, "\n");
+	print("DX    ", *DX, "\n");
+	print("DI    ", *DI, "\n"); 
+	print("SI    ", *SI, "\n");
+	print("BP    ", *BP, "\n");
+	print("R8    ", *R8, "\n");
+	print("R9    ", *R9, "\n");
+	print("R10   ", *R10, "\n");
+	print("R11   ", *R11, "\n");
+	print("R12   ", *R12, "\n");
+	print("R13   ", *R13, "\n");
+	print("R14   ", *R14, "\n");
+	print("R15   ", *R15, "\n");
+}
+
+defn spr()
+{
+	print("DS  ", *DS, "  ES  ", *ES, "  FS  ", *FS, "  GS  ", *GS, "\n");
+	print("TYPE  ", *TYPE, "\n");
+	print("ERROR ", *ERROR, "\n");
+	print("PC    ", *PC, "\n");
+	print("CS    ", *CS, "\n");
+	print("FLAGS ", *FLAGS, "\n");
+	print("SP    ", *SP, "\n");
+	print("SS    ", *SS, "\n");
+}
+
+defn x87r()
+{
+	print("FCW  ", *FCW, "  FSW  ", *FSW, "  FTW  ", *FTW, "  FOP  ", *FOP, "\n");
+	print("RIP  ", *RIP, "   RDP  ", *RDP, "\n");
+	print("M0   ", *M0, "\n");
+	print("M1   ", *M1, "\n");
+	print("M2   ", *M2, "\n");
+	print("M3   ", *M3, "\n");
+	print("M4   ", *M4, "\n");
+	print("M5   ", *M5, "\n");
+	print("M6   ", *M6, "\n");
+	print("M7   ", *M7, "\n");
+}
+
+defn xmmr()
+{
+	print("MXCSR  ", *MXCSR, "   MXCSRMASK  ", *MXCSRMASK, "\n");
+	print("X0   ", *X0, "\n");
+	print("X1   ", *X1, "\n");
+	print("X2   ", *X2, "\n");
+	print("X3   ", *X3, "\n");
+	print("X4   ", *X4, "\n");
+	print("X5   ", *X5, "\n");
+	print("X6   ", *X6, "\n");
+	print("X7   ", *X7, "\n");
+	print("X8   ", *X8, "\n");
+	print("X9   ", *X9, "\n");
+	print("X10  ", *X10, "\n");
+	print("X11  ", *X11, "\n");
+	print("X12  ", *X12, "\n");
+	print("X13  ", *X13, "\n");
+	print("X14  ", *X14, "\n");
+	print("X15  ", *X15, "\n");
+}
+
+defn fpr()
+{
+	xmmr();
+}
+
+defn regs()
+{
+	gpr();
+	spr();
+}
+
+defn pstop(pid)
+{
+	local l;
+	local pc;
+
+	pc = *PC;
+
+	print(pid,": ", reason(*TRAP), "\t");
+	print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+	if notes then {
+		if notes[0] != "sys: breakpoint" then {
+			print("Notes pending:\n");
+			l = notes;
+			while l do {
+				print("\t", head l, "\n");
+				l = tail l;
+			}
+		}
+	}
+}
+
+defn lstk()				// trace with locals
+{
+	_stk(*PC, *SP, 0, 1);
+}
+
+defn stk()
+{
+	_stk(*PC, *SP, 0, 0);
+}
+
+aggr Ureg
+{
+	'W' 0 ax;
+	'W' 8 bx;
+	'W' 16 cx;
+	'W' 24 dx;
+	'W' 32 si;
+	'W' 40 di;
+	'W' 48 bp;
+	'W' 56 r8;
+	'W' 64 r9;
+	'W' 72 r10;
+	'W' 80 r11;
+	'W' 88 r12;
+	'W' 96 r13;
+	'W' 104 r14;
+	'W' 112 r15;
+	'u' 120 ds;
+	'u' 122 es;
+	'u' 124 fs;
+	'u' 126 gs;
+	'W' 128 type;
+	'W' 136 error;
+	'W' 144 ip;
+	'W' 152 cs;
+	'W' 160 flags;
+	'W' 168 sp;
+	'W' 176 ss;
+};
+
+defn
+Ureg(addr) {
+	complex Ureg addr;
+	print("	ax	", addr.ax, "\n");
+	print("	bx	", addr.bx, "\n");
+	print("	cx	", addr.cx, "\n");
+	print("	dx	", addr.dx, "\n");
+	print("	si	", addr.si, "\n");
+	print("	di	", addr.di, "\n");
+	print("	bp	", addr.bp, "\n");
+	print("	r8	", addr.r8, "\n");
+	print("	r9	", addr.r9, "\n");
+	print("	r10	", addr.r10, "\n");
+	print("	r11	", addr.r11, "\n");
+	print("	r12	", addr.r12, "\n");
+	print("	r13	", addr.r13, "\n");
+	print("	r14	", addr.r14, "\n");
+	print("	r15	", addr.r15, "\n");
+	print("	ds	", addr.ds, "\n");
+	print("	es	", addr.es, "\n");
+	print("	fs	", addr.fs, "\n");
+	print("	gs	", addr.gs, "\n");
+	print("	type	", addr.type, "\n");
+	print("	error	", addr.error, "\n");
+	print("	ip	", addr.ip, "\n");
+	print("	cs	", addr.cs, "\n");
+	print("	flags	", addr.flags, "\n");
+	print("	sp	", addr.sp, "\n");
+	print("	ss	", addr.ss, "\n");
+};
+sizeofUreg = 184;
+
+print("/sys/lib/acid/amd64");

+ 1 - 0
sys/lib/acid/arm

@@ -68,6 +68,7 @@ defn pstop(pid)
 	}
 }
 
+sizeofUreg=72;
 aggr Ureg
 {
 	'U' 0 r0;

+ 15 - 1
sys/man/8/plan9.ini

@@ -679,6 +679,18 @@ A value of
 consults only the first table,
 .B old
 only the second.
+.SS \fLreadparts=\fP
+Causes
+.I boot
+to look for MBR and Plan 9 partition tables on all
+.IR sd (3)
+disks, even before
+.I factotum
+is started, so NVRAM, for example, may be found.
+On PCs,
+.I 9load
+normally does this,
+so this variable is intended for other architectures.
 .SS \fLfs=a.b.c.d\fP
 .SS \fLauth=a.b.c.d\fP
 These specify the IP address of the file and authentication server
@@ -834,7 +846,7 @@ where
 .I unit
 is the numeric unit id.
 This variant syntax is a vestige of the file server kernel's origins.
-.SH Multiple Configurations
+.SS Multiple Configurations
 .PP
 A
 .B plan9.ini
@@ -902,6 +914,8 @@ The line
 .EE
 is prefixed to the selected configuration as an aid to
 user-level initialization scripts.
+.br
+.ne 4
 .SH EXAMPLES
 .PP
 A representative

+ 2 - 2
sys/src/9/boot/boot.c

@@ -116,8 +116,8 @@ boot(int argc, char *argv[])
 	 * parse them and create partitions.
 	 */
 	rdparts = getenv("readparts");
-//	if(rdparts)
-//		readparts();
+	if(rdparts)
+		readparts();
 	free(rdparts);
 
 	/*

+ 1 - 1
sys/src/9/boot/bootmkfile

@@ -12,7 +12,7 @@ BOOTFILES=\
 	settime.$O\
 	sac.$O\
 	paq.$O\
-#	parts.$O\
+	parts.$O\
 	printstub.$O\
 	usb.$O\
 

+ 596 - 0
sys/src/9/boot/parts.c

@@ -0,0 +1,596 @@
+/*
+ * read disk partition tables, intended for early use on systems
+ * that don't use 9load.  borrowed from 9load.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include <bio.h>
+#include "../boot/boot.h"
+
+typedef struct Fs Fs;
+#include "/sys/src/boot/pc/dosfs.h"
+
+#define	GSHORT(p)	(((p)[1]<<8)|(p)[0])
+#define	GLONG(p)	((GSHORT((p)+2)<<16)|GSHORT(p))
+
+#define trace 0
+
+enum {
+	parttrace = 0,
+
+	Npart = 64,
+	SDnpart = Npart,
+
+	Maxsec = 2048,
+	Cdsec = 2048,
+	Normsec = 512,			/* disks */
+
+	NAMELEN = 256,			/* hack */
+};
+
+typedef struct SDpart SDpart;
+typedef struct SDunit SDunit;
+
+typedef struct SDpart {
+	uvlong	start;
+	uvlong	end;
+	char	name[NAMELEN];
+	int	valid;
+} SDpart;
+
+typedef struct SDunit {
+	int	ctl;			/* fds */
+	int	data;
+
+	char	name[NAMELEN];
+
+	uvlong	sectors;
+	ulong	secsize;
+	SDpart*	part;
+	int	npart;			/* of valid partitions */
+} SDunit;
+
+static uchar *mbrbuf, *partbuf;
+
+static void
+sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
+{
+	SDpart *pp;
+	int i, partno;
+
+	if(parttrace)
+		print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);
+	/*
+	 * Check name not already used
+	 * and look for a free slot.
+	 */
+	if(unit->part != nil){
+		partno = -1;
+		for(i = 0; i < SDnpart; i++){
+			pp = &unit->part[i];
+			if(!pp->valid){
+				if(partno == -1)
+					partno = i;
+				break;
+			}
+			if(strcmp(name, pp->name) == 0){
+				if(pp->start == start && pp->end == end){
+					if(parttrace)
+						print("already present\n");
+					return;
+				}
+			}
+		}
+	}else{
+		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){
+			if(parttrace)
+				print("malloc failed\n");
+			return;
+		}
+		partno = 0;
+	}
+
+	/*
+	 * Check there is a free slot and size and extent are valid.
+	 */
+	if(partno == -1 || start > end || end > unit->sectors){
+		print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",
+			unit->name, name, start, end, unit->sectors, 
+			partno==-1 ? "no free partitions" : "partition boundaries out of range");
+		return;
+	}
+	pp = &unit->part[partno];
+	pp->start = start;
+	pp->end = end;
+	strncpy(pp->name, name, NAMELEN);
+	pp->valid = 1;
+	unit->npart++;
+
+	/* update devsd's in-memory partition table */
+	if (fprint(unit->ctl, "part %s %lld %lld\n", name, start, end) < 0)
+		fprint(2, "can't update devsd's partition table\n");
+}
+
+static long
+sdread(SDunit *unit, SDpart *pp, void* va, long len, vlong off)
+{
+	long l;
+	uvlong bno, nb;
+
+	/*
+	 * Check the request is within partition bounds.
+	 */
+	if (unit->secsize == 0)
+		sysfatal("sdread: zero sector size");
+	bno = (off/unit->secsize) + pp->start;
+	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
+	if(bno+nb > pp->end)
+		nb = pp->end - bno;
+	if(bno >= pp->end || nb == 0)
+		return 0;
+
+	seek(unit->data, off, 0);
+	assert(va);				/* "sdread" */
+	l = read(unit->data, va, len);
+	if (l < 0)
+		return 0;
+	return l;
+}
+
+static int
+sdreadblk(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
+{
+	uchar *b;
+
+	assert(a);			/* sdreadblk */
+	if(sdread(unit, part, a, unit->secsize, off) != unit->secsize){
+		if(trace)
+			print("%s: read %lud at %lld failed\n", unit->name,
+				unit->secsize, (vlong)part->start*unit->secsize+off);
+		return -1;
+	}
+	b = a;
+	if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
+		if(trace)
+			print("%s: bad magic %.2ux %.2ux at %lld\n",
+				unit->name, b[0x1FE], b[0x1FF],
+				(vlong)part->start*unit->secsize+off);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ *  read partition table.  The partition table is just ascii strings.
+ */
+#define MAGIC "plan9 partitions"
+static void
+oldp9part(SDunit *unit)
+{
+	SDpart *pp;
+	char *field[3], *line[Npart+1];
+	ulong n, start, end;
+	int i;
+
+	/*
+	 *  We have some partitions already.
+	 */
+	pp = &unit->part[unit->npart];
+
+	/*
+	 * We prefer partition tables on the second to last sector,
+	 * but some old disks use the last sector instead.
+	 */
+	strcpy(pp->name, "partition");
+	pp->start = unit->sectors - 2;
+	pp->end = unit->sectors - 1;
+
+	if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
+		return;
+
+	if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
+		/* not found on 2nd last sector; look on last sector */
+		pp->start++;
+		pp->end++;
+		if(sdreadblk(unit, pp, partbuf, 0, 0) < 0)
+			return;
+		if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
+			return;
+		print("%s: using old plan9 partition table on last sector\n", unit->name);
+	}else
+		print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->name);
+
+	/* we found a partition table, so add a partition partition */
+	unit->npart++;
+	partbuf[unit->secsize-1] = '\0';
+
+	/*
+	 * parse partition table
+	 */
+	n = gettokens((char*)partbuf, line, Npart+1, "\n");
+	if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
+		for(i = 1; i < n && unit->npart < SDnpart; i++){
+			if(gettokens(line[i], field, 3, " ") != 3)
+				break;
+			start = strtoull(field[1], 0, 0);
+			end = strtoull(field[2], 0, 0);
+			if(start >= end || end > unit->sectors)
+				break;
+			sdaddpart(unit, field[0], start, end);
+		}
+	}	
+}
+
+static SDpart*
+sdfindpart(SDunit *unit, char *name)
+{
+	int i;
+
+	if(parttrace)
+		print("findpart %d %s %s\t\n", unit->npart, unit->name, name);
+	for(i=0; i<unit->npart; i++) {
+		if(parttrace)
+			print("%s...", unit->part[i].name);
+		if(strcmp(unit->part[i].name, name) == 0){
+			if(parttrace)
+				print("\n");
+			return &unit->part[i];
+		}
+	}
+	if(parttrace)
+		print("not found\n");
+	return nil;
+}
+
+static void
+p9part(SDunit *unit, char *name)
+{
+	SDpart *p;
+	char *field[4], *line[Npart+1];
+	uvlong start, end;
+	int i, n;
+
+	p = sdfindpart(unit, name);
+	if(p == nil)
+		return;
+
+	if(sdreadblk(unit, p, partbuf, unit->secsize, 0) < 0)
+		return;
+	partbuf[unit->secsize-1] = '\0';
+
+	if(strncmp((char*)partbuf, "part ", 5) != 0)
+		return;
+
+	n = gettokens((char*)partbuf, line, Npart+1, "\n");
+	if(n == 0)
+		return;
+	for(i = 0; i < n && unit->npart < SDnpart; i++){
+		if(strncmp(line[i], "part ", 5) != 0)
+			break;
+		if(gettokens(line[i], field, 4, " ") != 4)
+			break;
+		start = strtoull(field[2], 0, 0);
+		end   = strtoull(field[3], 0, 0);
+		if(start >= end || end > unit->sectors)
+			break;
+		sdaddpart(unit, field[1], p->start+start, p->start+end);
+	}
+}
+
+static int
+isdos(int t)
+{
+	return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
+}
+
+static int
+isextend(int t)
+{
+	return t==EXTEND || t==EXTHUGE || t==LEXTEND;
+}
+
+/* 
+ * Fetch the first dos and all plan9 partitions out of the MBR partition table.
+ * We return -1 if we did not find a plan9 partition.
+ */
+static int
+mbrpart(SDunit *unit)
+{
+	Dospart *dp;
+	ulong taboffset, start, end;
+	ulong firstxpart, nxtxpart;
+	int havedos, i, nplan9;
+	char name[10];
+
+	taboffset = 0;
+	dp = (Dospart*)&mbrbuf[0x1BE];
+	{
+		/* get the MBR (allowing for DMDDO) */
+		if(sdreadblk(unit, &unit->part[0], mbrbuf,
+		    (vlong)taboffset * unit->secsize, 1) < 0)
+			return -1;
+		for(i=0; i<4; i++)
+			if(dp[i].type == DMDDO) {
+				if(trace)
+					print("DMDDO partition found\n");
+				taboffset = 63;
+				if(sdreadblk(unit, &unit->part[0], mbrbuf,
+				    (vlong)taboffset * unit->secsize, 1) < 0)
+					return -1;
+				i = -1;	/* start over */
+			}
+	}
+
+	/*
+	 * Read the partitions, first from the MBR and then
+	 * from successive extended partition tables.
+	 */
+	nplan9 = 0;
+	havedos = 0;
+	firstxpart = 0;
+	for(;;) {
+		if(sdreadblk(unit, &unit->part[0], mbrbuf,
+		    (vlong)taboffset * unit->secsize, 1) < 0)
+			return -1;
+		if(trace) {
+			if(firstxpart)
+				print("%s ext %lud ", unit->name, taboffset);
+			else
+				print("%s mbr ", unit->name);
+		}
+		nxtxpart = 0;
+		for(i=0; i<4; i++) {
+			if(trace)
+				print("dp %d...", dp[i].type);
+			start = taboffset+GLONG(dp[i].start);
+			end = start+GLONG(dp[i].len);
+
+			if(dp[i].type == PLAN9) {
+				if(nplan9 == 0)
+					strcpy(name, "plan9");
+				else
+					sprint(name, "plan9.%d", nplan9);
+				sdaddpart(unit, name, start, end);
+				p9part(unit, name);
+				nplan9++;
+			}
+
+			/*
+			 * We used to take the active partition (and then the first
+			 * when none are active).  We have to take the first here,
+			 * so that the partition we call ``dos'' agrees with the
+			 * partition disk/fdisk calls ``dos''. 
+			 */
+			if(havedos==0 && isdos(dp[i].type)){
+				havedos = 1;
+				sdaddpart(unit, "dos", start, end);
+			}
+
+			/* nxtxpart is relative to firstxpart (or 0), not taboffset */
+			if(isextend(dp[i].type)){
+				nxtxpart = start-taboffset+firstxpart;
+				if(trace)
+					print("link %lud...", nxtxpart);
+			}
+		}
+		if(trace)
+			print("\n");
+
+		if(!nxtxpart)
+			break;
+		if(!firstxpart)
+			firstxpart = nxtxpart;
+		taboffset = nxtxpart;
+	}	
+	return nplan9 ? 0 : -1;
+}
+
+/*
+ * To facilitate booting from CDs, we create a partition for
+ * the boot floppy image embedded in a bootable CD.
+ */
+static int
+part9660(SDunit *unit)
+{
+	uchar buf[Maxsec];
+	ulong a, n;
+	uchar *p;
+
+	if(unit->secsize != Cdsec)
+		return -1;
+
+	if(sdread(unit, &unit->part[0], buf, Cdsec, 17*Cdsec) < 0)
+		return -1;
+
+	if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
+		return -1;
+
+	
+	p = buf+0x47;
+	a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+
+	if(sdread(unit, &unit->part[0], buf, Cdsec, a*Cdsec) < 0)
+		return -1;
+
+	if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
+	|| memcmp(buf+30, "\x55\xAA", 2) != 0
+	|| buf[0x20] != 0x88)
+		return -1;
+
+	p = buf+0x28;
+	a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+
+	switch(buf[0x21]){
+	case 0x01:
+		n = 1200*1024;
+		break;
+	case 0x02:
+		n = 1440*1024;
+		break;
+	case 0x03:
+		n = 2880*1024;
+		break;
+	default:
+		return -1;
+	}
+	n /= Cdsec;
+
+	print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n);
+	sdaddpart(unit, "cdboot", a, a+n);
+	return 0;
+}
+
+enum {
+	NEW = 1<<0,
+	OLD = 1<<1
+};
+
+/*
+ * read unit->data to look for partition tables.
+ * if found, stash partitions in environment and write them to ctl too.
+ */
+static void
+partition(SDunit *unit)
+{
+	int type;
+	char *p;
+
+	if(unit->part == 0)
+		return;
+
+	if(part9660(unit) == 0)
+		return;
+
+	p = getenv("partition");
+	if(p != nil && strncmp(p, "new", 3) == 0)
+		type = NEW;
+	else if(p != nil && strncmp(p, "old", 3) == 0)
+		type = OLD;
+	else
+		type = NEW|OLD;
+
+	if(mbrbuf == nil) {
+		mbrbuf = malloc(Maxsec);
+		partbuf = malloc(Maxsec);
+		if(mbrbuf==nil || partbuf==nil) {
+			free(mbrbuf);
+			free(partbuf);
+			partbuf = mbrbuf = nil;
+			return;
+		}
+	}
+
+	/*
+	 * there might be no mbr (e.g. on a very large device), so look for
+	 * a bare plan 9 partition table if mbrpart fails.
+	 */
+	if((type & NEW) && mbrpart(unit) >= 0){
+		/* nothing to do */
+	}
+	else if (type & NEW)
+		p9part(unit, "data");
+	else if(type & OLD)
+		oldp9part(unit);
+}
+
+static void
+rdgeom(SDunit *unit)
+{
+	char *line;
+	char *flds[5];
+	Biobuf bb;
+	Biobuf *bp;
+	static char geom[] = "geometry ";
+
+	bp = &bb;
+	seek(unit->ctl, 0, 0);
+	Binit(bp, unit->ctl, OREAD);
+	while((line = Brdline(bp, '\n')) != nil){
+		line[Blinelen(bp) - 1] = '\0';
+		if (strncmp(line, geom, sizeof geom - 1) == 0)
+			break;
+	}
+	if (line != nil && tokenize(line, flds, nelem(flds)) >= 3) {
+		unit->sectors = atoll(flds[1]);
+		unit->secsize = atoll(flds[2]);
+	}
+	Bterm(bp);
+	seek(unit->ctl, 0, 0);
+}
+
+static void
+setpartitions(char *name, int ctl, int data)
+{
+	SDunit sdunit;
+	SDunit *unit;
+	SDpart *part0;
+
+	unit = &sdunit;
+	memset(unit, 0, sizeof *unit);
+	unit->ctl = ctl;
+	unit->data = data;
+
+	unit->secsize = Normsec;	/* default: won't work for CDs */
+	unit->sectors = ~0ull;
+	rdgeom(unit);
+	strncpy(unit->name, name, sizeof unit->name);
+	unit->part = mallocz(sizeof(SDpart) * SDnpart, 1);
+
+	part0 = &unit->part[0];
+	part0->end = unit->sectors - 1;
+	strcpy(part0->name, "data");
+	part0->valid = 1;
+	unit->npart++;
+
+	mbrbuf = malloc(Maxsec);
+	partbuf = malloc(Maxsec);
+	partition(unit);
+	free(unit->part);
+}
+
+/*
+ * read disk partition tables so that readnvram via factotum
+ * can see them.
+ */
+int
+readparts(void)
+{
+	int i, n, ctl, data, fd;
+	char *name, *ctlname, *dataname;
+	Dir *dir;
+
+	fd = open("/dev", OREAD);
+	if(fd < 0)
+		return -1;
+	n = dirreadall(fd, &dir);
+	close(fd);
+
+	for(i = 0; i < n; i++) {
+		name = dir[i].name;
+		if (strncmp(name, "sd", 2) != 0)
+			continue;
+
+		ctlname  = smprint("/dev/%s/ctl", name);
+		dataname = smprint("/dev/%s/data", name);
+		if (ctlname == nil || dataname == nil) {
+			free(ctlname);
+			free(dataname);
+			continue;
+		}
+
+		ctl  = open(ctlname, ORDWR);
+		data = open(dataname, OREAD);
+		free(ctlname);
+		free(dataname);
+
+		if (ctl >= 0 && data >= 0)
+			setpartitions(dataname, ctl, data);
+		close(ctl);
+		close(data);
+	}
+	free(dir);
+	return 0;
+}

+ 8 - 7
sys/src/9/pc/devether.c

@@ -182,12 +182,12 @@ etheriq(Ether* ether, Block* bp, int fromwire)
 				else if(xbp = iallocb(len)){
 					memmove(xbp->wp, pkt, len);
 					xbp->wp += len;
-					if(qpass(f->in, xbp) < 0) {
+					if(qpass(f->in, xbp) < 0){
 						// print("soverflow for f->in\n");
 						ether->soverflows++;
 					}
 				}
-				else {
+				else{
 					// print("soverflow iallocb\n");
 					ether->soverflows++;
 				}
@@ -198,7 +198,7 @@ etheriq(Ether* ether, Block* bp, int fromwire)
 	}
 
 	if(fx){
-		if(qpass(fx->in, bp) < 0) {
+		if(qpass(fx->in, bp) < 0){
 			// print("soverflow for fx->in\n");
 			ether->soverflows++;
 		}
@@ -274,13 +274,13 @@ etherwrite(Chan* chan, void* buf, long n, vlong)
 			return n;
 		}
 		free(cb);
-		if(ether->ctl!=nil)
-			return ether->ctl(ether,buf,n);
+		if(ether->ctl != nil)
+			return ether->ctl(ether, buf, n);
 
 		error(Ebadctl);
 	}
 
-	if(n > ether->maxmtu)
+	if(n > ether->mtu)
 		error(Etoobig);
 	if(n < ether->minmtu)
 		error(Etoosmall);
@@ -317,7 +317,7 @@ etherbwrite(Chan* chan, Block* bp, ulong)
 	}
 	ether = etherxx[chan->dev];
 
-	if(n > ether->maxmtu){
+	if(n > ether->mtu){
 		freeb(bp);
 		error(Etoobig);
 	}
@@ -386,6 +386,7 @@ etherprobe(int cardno, int ctlrno)
 	ether->mbps = 10;
 	ether->minmtu = ETHERMINTU;
 	ether->maxmtu = ETHERMAXTU;
+	ether->mtu = ETHERMAXTU;
 
 	if(cardno < 0){
 		if(isaconfig("ether", ctlrno, ether) == 0){

+ 1 - 0
sys/src/9/pc/ether82598.c

@@ -348,6 +348,7 @@ ifstat(Ether *e, void *a, long n, ulong offset)
 			p = seprint(p, q, "%.10s  %uld\n", stattab[i].name,					c->stats[i]);
 	t = c->speeds;
 	p = seprint(p, q, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]);
+	p = seprint(p, q, "mtu: min:%d max:%d\n", e->minmtu, e->maxmtu);
 	seprint(p, q, "rdfree %d rdh %d rdt %d\n", c->rdfree, c->reg[Rdt],
 		c->reg[Rdh]);
 	n = readstr(offset, a, n, s);

+ 0 - 2
sys/src/9/pc/etherif.h

@@ -9,8 +9,6 @@ struct Ether {
 
 	int	ctlrno;
 	int	tbdf;			/* type+busno+devno+funcno */
-	int	minmtu;
-	int 	maxmtu;
 	uchar	ea[Eaddrlen];
 
 	void	(*attach)(Ether*);	/* filled in by reset routine */

+ 1 - 0
sys/src/9/pc/fns.h

@@ -1,6 +1,7 @@
 #include "../port/portfns.h"
 
 void	aamloop(int);
+void	acpiscan(void (*func)(uchar *));
 Dirtab*	addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong));
 void	archinit(void);
 int	bios32call(BIOS32ci*, u16int[3]);

+ 9 - 1
sys/src/9/pc/main.c

@@ -843,6 +843,8 @@ cistrncmp(char *a, char *b, int n)
 	return 0;
 }
 
+int less_power_slower;
+
 /*
  *  put the processor in the halt state if we've no processes to run.
  *  an interrupt will get us going again.
@@ -850,6 +852,12 @@ cistrncmp(char *a, char *b, int n)
 void
 idlehands(void)
 {
-	if(conf.nmach == 1)
+	/*
+	 * we used to halt only on single-core setups. halting in an smp system 
+	 * can result in a startup latency for processes that become ready.
+	 * if less_power_slower is true, we care more about saving energy
+	 * than reducing this latency.
+	 */
+	if(conf.nmach == 1 || less_power_slower)
 		halt();
 }

+ 7 - 5
sys/src/9/pc/sdata.c

@@ -1923,13 +1923,15 @@ atapnp(void)
 			r &= ~0x2000;
 			pcicfgw32(p, 0x40, r);
 			break;
-		case (0x4D38<<16)|0x105A:	/* Promise PDC20262 */
+		case (0x4379<<16)|0x1002:	/* ATI 4379 SATA*/
+		case (0x439c<<16)|0x1002:	/* ATI 439c SATA*/
+		case (0x3373<<16)|0x105A:	/* Promise 20378 RAID */
 		case (0x4D30<<16)|0x105A:	/* Promise PDC202xx */
+		case (0x4D38<<16)|0x105A:	/* Promise PDC20262 */
 		case (0x4D68<<16)|0x105A:	/* Promise PDC20268 */
 		case (0x4D69<<16)|0x105A:	/* Promise Ultra/133 TX2 */
-		case (0x3373<<16)|0x105A:	/* Promise 20378 RAID */
-		case (0x3149<<16)|0x1106:	/* VIA VT8237 SATA/RAID */
 		case (0x3112<<16)|0x1095:	/* SiI 3112 SATA/RAID */
+		case (0x3149<<16)|0x1106:	/* VIA VT8237 SATA/RAID */
 			maxio = 15;
 			span = 8*1024;
 			/*FALLTHROUGH*/
@@ -1999,8 +2001,8 @@ atapnp(void)
 			 * address for the registers (0x50?).
 			 */
 			/*FALLTHROUGH*/
-		case (0x4376<<16)|0x1002:	/* ATI SB400 PATA */
-		case (0x4379<<16)|0x1002:	/* ATI SB400 SATA */
+		case (0x4372<<16)|0x1002:	/* ATI SB400 */
+		case (0x4376<<16)|0x1002:	/* ATI Radeon Xpress 200M */
 		case (0x437a<<16)|0x1002:	/* ATI SB400 SATA */
 			break;
 		case (0x0211<<16)|0x1166:	/* ServerWorks IB6566 */

+ 3 - 1
sys/src/9/pc/sdiahci.c

@@ -1894,8 +1894,10 @@ didtype(Pcidev *p)
 			return Tich;
 		break;
 	case Vatiamd:
-		if(p->did == 0x4380)
+		if(p->did == 0x4380 || p->did == 0x4390 || p->did == 0x4391){
+			print("detected sb600 vid 0x%ux did 0x%ux\n", p->vid, p->did);
 			return Tsb600;
+		}
 		break;
 	case Vmarvell:
 		/* can't cope with sata 3 yet; touching sd files will hang */

+ 1 - 1
sys/src/9/port/fault.c

@@ -14,7 +14,7 @@ fault(ulong addr, int read)
 	if(up == nil)
 		panic("fault: nil up");
 	if(up->nlocks.ref)
-		print("fault: nlocks %ld\n", up->nlocks.ref);
+		print("fault: addr %#p: nlocks %ld\n", addr, up->nlocks.ref);
 
 	sps = up->psstate;
 	up->psstate = "Fault";

+ 0 - 6
sys/src/cmd/disk/partfs.c

@@ -274,12 +274,6 @@ Have:
 	return 0;
 }
 
-void*
-evommem(void *a, void *b, ulong n)
-{
-	return memmove(b, a, n);
-}
-
 int
 rdwrpart(Req *r)
 {

+ 18 - 5
sys/src/libauthsrv/readnvram.c

@@ -4,6 +4,8 @@
 
 static long	finddosfile(int, char*);
 
+static int nvramdebug;
+
 static int
 check(void *x, int len, uchar sum, char *msg)
 {
@@ -137,11 +139,15 @@ static char *nvrfile = nil, *cputype = nil;
 static void
 findnvram(Nvrwhere *locp)
 {
-	char *nvrlen, *nvroff, *nvrcopy, *v[2];
+	char *nvrlen, *nvroff, *nvrcopy, *db, *v[2];
 	int fd, i, safeoff, safelen;
 
-	if (nvrfile == nil)
+	if (nvrfile == nil) {
 		nvrfile = getenv("nvram");
+		db = getenv("nvramdebug");
+		nvramdebug = db != nil;
+		free(db);
+	}
 	if (cputype == nil)
 		cputype = getenv("cputype");
 	if(cputype == nil)
@@ -163,6 +169,8 @@ findnvram(Nvrwhere *locp)
 			v[0] = "";
 			v[1] = nil;
 		}
+		if(nvramdebug)
+			fprint(2, "nvram at %s?...", v[0]);
 		fd = open(v[0], ORDWR);
 		if (fd < 0)
 			fd = open(v[0], OREAD);
@@ -193,7 +201,10 @@ findnvram(Nvrwhere *locp)
 		for(i=0; i<nelem(nvtab); i++){
 			if(strcmp(cputype, nvtab[i].cputype) != 0)
 				continue;
-			if((fd = open(nvtab[i].file, ORDWR)) < 0)
+			if(nvramdebug)
+				fprint(2, "nvram at %s?...", nvtab[i].file);
+			if((fd = open(nvtab[i].file, ORDWR)) < 0 &&
+			   (fd = open(nvtab[i].file, OREAD)) < 0)
 				continue;
 			safeoff = nvtab[i].off;
 			safelen = nvtab[i].len;
@@ -251,7 +262,8 @@ readnvram(Nvrsafe *safep, int flag)
 		safe = safep;
 	else {
 		memset(safep, 0, sizeof(*safep));
-		werrstr("");
+		if(loc.fd >= 0)
+			werrstr("");
 		if(loc.fd < 0
 		|| seek(loc.fd, loc.safeoff, 0) < 0
 		|| read(loc.fd, buf, loc.safelen) != loc.safelen){
@@ -316,7 +328,8 @@ readnvram(Nvrsafe *safep, int flag)
 		safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom);
 
 		*(Nvrsafe*)buf = *safe;
-		werrstr("");
+		if(loc.fd >= 0)
+			werrstr("");
 		if(loc.fd < 0
 		|| seek(loc.fd, loc.safeoff, 0) < 0
 		|| write(loc.fd, buf, loc.safelen) != loc.safelen){