Browse Source

Plan 9 from Bell Labs 2010-05-20

David du Colombier 9 years ago
parent
commit
e4214038b6

+ 0 - 3
sys/man/2/atof

@@ -135,9 +135,6 @@ Zero is returned if the beginning of the input string is not
 interpretable as a number; even in this case,
 .I rptr
 will be updated.
-.br
-These routines set
-.IR errstr .
 .SH BUGS
 .I Atoi,
 .I atol,

+ 6 - 7
sys/src/9/kw/plug.words

@@ -1,6 +1,6 @@
-global scale sheevaplug
+global scale sheevaplug & guruplug
 
-marvell 88f6281 (feroceon kirkwood) SoC; ours are revision A0
+marvell 88f6281 (feroceon kirkwood) SoC
 arm926ej-s rev 1 [56251311] (armv5tejl) 1.2GHz cpu
 
 l1 I & D VIVT caches 16K each: 4-way, 128 sets, 32-byte lines
@@ -33,11 +33,10 @@ see http://www.marvell.com/files/products/embedded_processors/kirkwood/\
 	/public/doc/marvell/88f61xx.kirkwood.pdf
 
 If you plan to use flash, it would be wise to avoid touching the first
-few megabytes, which contain u-boot and the distributed linux kernel.
-u-boot occupies flash up to 0x100000, and there's a linux kernel from
-there to 0x400000.  You'll also likely want to use paqfs rather than
-fossil or kfs for file systems in flash since there is no
-wear-levelling.
+megabyte, which contains u-boot, right up to 0x100000.  There's a
+linux kernel from there to 0x400000, if you care.  You'll also likely
+want to use paqfs rather than fossil or kfs for file systems in flash
+since there is no wear-levelling.
 
 The code is fairly heavy-handed with the use of barrier instructions
 (BARRIERS in assembler, coherence in C), partly in reaction to bad

+ 134 - 21
sys/src/9/omap/archomap.c

@@ -90,7 +90,7 @@ enum {
  * an array of these structs is preceded by error_log at 0x20, control,
  * error_clear_single, error_clear_multi.  first struct is at offset 0x48.
  */
-struct L3protreg {		/* an L3 protection region */
+struct L3protreg {		/* hw: an L3 protection region */
 	uvlong	req_info_perm;
 	uvlong	read_perm;
 	uvlong	write_perm;
@@ -105,7 +105,7 @@ enum {
 	Permmpu		= 1<<1,
 };
 
-struct L3agent {
+struct L3agent {		/* hw registers */
 	uchar	_pad0[0x20];
 	uvlong	ctl;
 	uvlong	sts;
@@ -245,7 +245,7 @@ log2(ulong n)
 	int i;
 
 	i = 31 - clz(n);
-	if (!ispow2(n))
+	if (!ispow2(n) || n == 0)
 		i++;
 	return i;
 }
@@ -254,13 +254,16 @@ void
 archconfinit(void)
 {
 	char *p;
+	ulong mhz;
 
 	assert(m != nil);
+	m->cpuhz = 500 * 1000 * 1000;		/* beagle speed */
 	p = getconf("*cpumhz");
-	if (p)
-		m->cpuhz = atoi(p) * 1000 * 1000;
-	else
-		m->cpuhz = 500 * 1000 * 1000;	/* beagle speed */
+	if (p) {
+		mhz = atoi(p) * 1000 * 1000;
+		if (mhz >= 100*1000*1000 && mhz <= 3000UL*1000*1000)
+			m->cpuhz = mhz;
+	}
 	m->delayloop = m->cpuhz/2000;		/* initial estimate */
 }
 
@@ -832,9 +835,9 @@ prcachecfg(void)
 		if (mc.linelen != CACHELINESZ)
 			iprint(" *should* be %d", CACHELINESZ);
 		if (mc.setsways & Cawt)
-			iprint("; can write-through");
+			iprint("; can WT");
 		if (mc.setsways & Cawb)
-			iprint("; can write-back");
+			iprint("; can WB");
 #ifdef COMPULSIVE			/* both caches can do this */
 		if (mc.setsways & Cara)
 			iprint("; can read-allocate");
@@ -875,7 +878,7 @@ subarch(int impl, uint sa)
 }
 
 /*
- * padconf bits in a short, 2 per register
+ * padconf bits in a short, 2 per long register
  *	15	wakeupevent
  *	14	wakeupenable
  *	13	offpulltypeselect
@@ -890,7 +893,61 @@ subarch(int impl, uint sa)
  */
 
 enum {
-	Muxmode		= MASK(3),
+	/* pad config register bits */
+	Inena	= 1 << 8,		/* input enable */
+	Indis	= 0 << 8,		/* input disable */
+	Ptup	= 1 << 4,		/* pull type up */
+	Ptdown	= 0 << 4,		/* pull type down */
+	Ptena	= 1 << 3,		/* pull type selection is active */
+	Ptdis	= 0 << 3,		/* pull type selection is inactive */
+	Muxmode	= MASK(3),
+
+	/* pad config registers relevant to flash */
+	GpmcA1		= 0x4800207A,
+	GpmcA2		= 0x4800207C,
+	GpmcA3		= 0x4800207E,
+	GpmcA4		= 0x48002080,
+	GpmcA5		= 0x48002082,
+	GpmcA6		= 0x48002084,
+	GpmcA7		= 0x48002086,
+	GpmcA8		= 0x48002088,
+	GpmcA9		= 0x4800208A,
+	GpmcA10		= 0x4800208C,
+	GpmcD0		= 0x4800208E,
+	GpmcD1		= 0x48002090,
+	GpmcD2		= 0x48002092,
+	GpmcD3		= 0x48002094,
+	GpmcD4		= 0x48002096,
+	GpmcD5		= 0x48002098,
+	GpmcD6		= 0x4800209A,
+	GpmcD7		= 0x4800209C,
+	GpmcD8		= 0x4800209E,
+	GpmcD9		= 0x480020A0,
+	GpmcD10		= 0x480020A2,
+	GpmcD11		= 0x480020A4,
+	GpmcD12		= 0x480020A6,
+	GpmcD13		= 0x480020A8,
+	GpmcD14		= 0x480020AA,
+	GpmcD15		= 0x480020AC,
+	GpmcNCS0	= 0x480020AE,
+	GpmcNCS1	= 0x480020B0,
+	GpmcNCS2	= 0x480020B2,
+	GpmcNCS3	= 0x480020B4,
+	GpmcNCS4	= 0x480020B6,
+	GpmcNCS5	= 0x480020B8,
+	GpmcNCS6	= 0x480020BA,
+	GpmcNCS7	= 0x480020BC,
+	GpmcCLK		= 0x480020BE,
+	GpmcNADV_ALE	= 0x480020C0,
+	GpmcNOE		= 0x480020C2,
+	GpmcNWE		= 0x480020C4,
+	GpmcNBE0_CLE	= 0x480020C6,
+	GpmcNBE1	= 0x480020C8,
+	GpmcNWP		= 0x480020CA,
+	GpmcWAIT0	= 0x480020CC,
+	GpmcWAIT1	= 0x480020CE,
+	GpmcWAIT2	= 0x480020D0,
+	GpmcWAIT3	= 0x480020D2,
 };
 
 /* set SCM pad config mux mode */
@@ -902,12 +959,8 @@ setmuxmode(ulong addr, int shorts, int mode)
 
 	for (ptr = (ushort *)addr; shorts-- > 0; ptr++) {
 		omode = *ptr & Muxmode;
-		if (omode != mode) {
-//			print("scm pad %#p was mux mode %d, now %d\n",
-//				ptr, omode, mode);
-//			delay(10);
+		if (omode != mode)
 			*ptr = *ptr & ~Muxmode | mode & Muxmode;
-		}
 	}
 	coherence();
 }
@@ -915,7 +968,7 @@ setmuxmode(ulong addr, int shorts, int mode)
 static void
 setpadmodes(void)
 {
-	ushort *ptr;
+	int off;
 
 	/* set scm pad modes for usb; hasn't made any difference yet */
 	setmuxmode(0x48002166, 7, 5);	/* hsusb3_tll; is mode 4 */
@@ -931,10 +984,70 @@ setpadmodes(void)
 	 * igep only: mode 4 of 21d2 is gpio_176 (smsc9221 ether irq).
 	 * see ether9221.c for more.
 	 */
-	ptr = (ushort *)0x480021d2;
-//	setmuxmode((uintptr)ptr, 1, 4);
-	/* input enable, pu/pd = 3, muxmode 4 */
-	*ptr = 1 << 8 | 3 << 3 | 4;
+	*(ushort *)0x480021d2 = Inena | Ptup | Ptena | 4;
+
+	/* magic from u-boot */
+	*(ushort *)GpmcA1	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA2	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA3	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA4	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA5	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA6	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA7	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA8	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA9	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcA10	= Indis | Ptup | Ptena | 0;
+
+	*(ushort *)GpmcD0	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD1	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD2	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD3	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD4	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD5	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD6	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD7	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD8	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD9	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD10	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD11	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD12	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD13	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD14	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcD15	= Inena | Ptup | Ptena | 0;
+
+	*(ushort *)GpmcNCS0	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS1	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS2	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS3	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS4	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS5	= Indis | Ptup | Ptena | 0;
+	*(ushort *)GpmcNCS6	= Indis | Ptup | Ptena | 0;
+
+	*(ushort *)GpmcNOE	= Indis | Ptdown | Ptdis | 0;
+	*(ushort *)GpmcNWE	= Indis | Ptdown | Ptdis | 0;
+
+	*(ushort *)GpmcWAIT2	= Inena | Ptup | Ptena | 4; /* GPIO_64 -ETH_NRESET */
+	*(ushort *)GpmcNCS7	= Inena | Ptup | Ptena | 1; /* SYS_nDMA_REQ3 */
+
+	*(ushort *)GpmcCLK	= Indis | Ptdown | Ptdis | 0;
+
+	*(ushort *)GpmcNBE1	= Inena | Ptdown | Ptdis | 0;
+
+	*(ushort *)GpmcNADV_ALE	= Indis | Ptdown | Ptdis | 0;
+	*(ushort *)GpmcNBE0_CLE	= Indis | Ptdown | Ptdis | 0;
+
+	*(ushort *)GpmcNWP	= Inena | Ptdown | Ptdis | 0;
+
+	*(ushort *)GpmcWAIT0	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcWAIT1	= Inena | Ptup | Ptena | 0;
+	*(ushort *)GpmcWAIT3	= Inena | Ptup | Ptena | 0;
+
+	/*
+	 * magic from u-boot: set 0xe00 bits in gpmc_(nwe|noe|nadv_ale)
+	 * to enable `off' mode for each.
+	 */
+	for (off = 0xc0; off <= 0xc4; off += sizeof(short))
+		*((ushort *)(PHYSSCM + off)) |= 0xe00;
 	coherence();
 }
 

+ 82 - 0
sys/src/9/omap/io.h

@@ -0,0 +1,82 @@
+/*
+ * the ``general-purpose'' memory controller.
+ * only works with flash memory.
+ */
+
+enum {
+	/* syscfg bits */
+	Idlemask	= MASK(2) << 3,
+	Noidle		= 1 << 3,
+
+	/* config bits */
+	Postnandwrites	= 1<<0,	/* force nand reg. writes to be posted */
+
+	/* indices of cscfg[].cfg[] */
+	Csctl		= 1 - 1,		/* chip-select signal ctl */
+	Csmap		= 7 - 1,		/* chip-select addr map cfg */
+
+	/* Csctl bits */
+	Muxadddata	= 1 << 9,
+	Devtypemask	= MASK(2) << 10,
+	Devtypenor	= 0 << 10,
+	Devtypenand	= 2 << 10,
+	Devsizemask	= 1 << 12,
+	Devsize8	= 0 << 12,
+	Devsize16	= 1 << 12,
+	Writesync	= 1 << 27,
+	Readsync	= 1 << 29,
+
+	/* Csmap bits */
+	Csvalid		= 1 << 6,
+	MB16		= 017 << 8,		/* 16MB size */
+	MB128		= 010 << 8,		/* 128MB size */
+};
+
+typedef struct Gpmc Gpmc;
+typedef struct Gpmccs Gpmccs;
+
+/*
+ * configuration for non-dram (e.g., flash) memory
+ */
+struct Gpmc {				/* hw registers */
+	uchar	_pad0[0x10];
+	ulong	syscfg;
+	ulong	syssts;
+	ulong	irqsts;
+	ulong	irqenable;
+	uchar	_pad1[0x40 - 0x20];
+	ulong	tmout_ctl;
+	ulong	erraddr;
+	ulong	errtype;
+	ulong	_pad7;
+	ulong	config;
+	ulong	sts;
+	uchar	_pad2[0x60 - 0x58];
+
+	/* chip-select config */
+	struct Gpmccs {
+		ulong	cfg[7];
+		ulong	nandcmd;
+		ulong	nandaddr;
+		ulong	nanddata;
+		ulong	_pad6[2];
+	} cscfg[8];
+
+	/* prefetch */
+	ulong	prefcfg[2];
+	ulong	_pad8;
+	ulong	prefctl;
+	ulong	prefsts;
+
+	/* ecc */
+	ulong	ecccfg;
+	ulong	eccctl;
+	ulong	eccsize;
+	ulong	eccres[9];
+	uchar	_pad3[0x240 - 0x224];
+
+	/* bch */
+	ulong	bchres[8][4];
+	uchar	_pad4[0x2d0 - 0x2c0];
+	ulong	bchswdata;
+};

+ 4 - 3
sys/src/9/omap/mem.h

@@ -117,12 +117,13 @@
  */
 
 /* gpmc-controlled address space 0—1G */
-#define PHYSNAND	0x20000000	/* mapped here by u-boot or flashomap */
+#define PHYSNAND	1		/* cs0 is onenand flash */
 #define PHYSETHER	0x2c000000
 
 #define PHYSIO		0x48000000	/* L4 ctl */
 
 #define PHYSSCM		0x48002000	/* system control module */
+
 /* core control pad cfg		0x48002030—0x480021e4, */
 /* core control d2d pad cfg	0x480021e4—0x48002264 */
 #define PHYSSCMPCONF	0x48002270	/* general device config */
@@ -130,6 +131,7 @@
 /* core control pad cfg (2)	0x480025d8—0x480025fc */
 #define PHYSSWBOOTCFG	0x48002910	/* sw booting config */
 /* wakeup control pad cfg	0x48002a00—0x48002a54 */
+
 #define PHYSSCMMPU	0x48004900	/* actually CPU */
 #define PHYSSCMCORE	0x48004a00
 #define PHYSSCMWKUP	0x48004c00
@@ -196,6 +198,5 @@
 
 #define PHYSDRAM	0x80000000
 
+#define VIRTNAND	0x20000000	/* fixed by u-boot */
 #define VIRTIO		PHYSIO
-
-#define NANDSIZE	(512*MB)	/* or 256 on beagle */

+ 16 - 10
sys/src/9/omap/mmu.c

@@ -68,25 +68,33 @@ idmap(PTE *l1, ulong va)
 	l1[L1X(va)] = va | Dom0 | L1AP(Krw) | Section;
 }
 
-/* identity map `mbs' megabytes from phys */
+/* map `mbs' megabytes from virt to phys */
 void
-mmuidmap(uintptr phys, int mbs)
+mmumap(uintptr virt, uintptr phys, int mbs)
 {
+	uint off;
 	PTE *l1;
-	uintptr fpa;
 
+	phys &= ~(MB-1);
+	virt &= ~(MB-1);
 	l1 = KADDR(ttbget());
-	for (fpa = phys; mbs-- > 0; fpa += MiB)
-		idmap(l1, fpa);
-	mmuinvalidate();
+	for (off = 0; mbs-- > 0; off += MB)
+		l1[L1X(virt + off)] = (phys + off) | Dom0 | L1AP(Krw) | Section;
 	cacheuwbinv();
 	l2cacheuwbinv();
+	mmuinvalidate();
+}
+
+/* identity map `mbs' megabytes from phys */
+void
+mmuidmap(uintptr phys, int mbs)
+{
+	mmumap(phys, phys, mbs);
 }
 
 void
 mmuinit(void)
 {
-//	int i;
 	uintptr pa;
 	PTE *l1, *l2;
 
@@ -102,8 +110,6 @@ mmuinit(void)
 	idmap(l1, PHYSSMS);
 	idmap(l1, PHYSDRC);
 	idmap(l1, PHYSGPMC);
-//	for (i = 0; i < 16; i++)	/* just need 16MB */
-//		idmap(l1, PHYSNAND + i*MB);
 
 	/* map high vectors to start of dram, but only 4K, not 1MB */
 	pa -= MACHSIZE+2*1024;
@@ -114,9 +120,9 @@ mmuinit(void)
 	l1[L1X(HVECTORS)] = pa|Dom0|Coarse;	/* vectors -> ttb-machsize-2k */
 	coherence();
 
-	mmuinvalidate();
 	cacheuwbinv();
 	l2cacheuwbinv();
+	mmuinvalidate();
 
 	m->mmul1 = l1;
 //	mmudump(l1);			/* DEBUG */

+ 27 - 9
sys/src/9/omap/trap.c

@@ -420,6 +420,8 @@ writetomem(ulong inst)
 	return 1;
 }
 
+void	prgpmcerrs(void);
+
 /*
  *  here on all exceptions other than syscall (SWI)
  */
@@ -478,7 +480,9 @@ trap(Ureg *ureg)
 		ldrexvalid = 0;
 		va = farget();
 		inst = *(ulong*)(ureg->pc);
-		fsr = fsrget() & 0xf;
+		/* bits 12 and 10 have to be concatenated with status */
+		x = fsrget();
+		fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
 		if (probing && !user) {
 			if (trapped++ > 0)
 				panic("trap: recursive probe %#lux", va);
@@ -486,11 +490,15 @@ trap(Ureg *ureg)
 			break;
 		}
 		switch(fsr){
+		default:
+		case 0xa:		/* ? was under external abort */
+			panic("unknown data fault, 6b fsr %#lux", fsr);
+			break;
 		case 0x0:
 			panic("vector exception at %#lux", ureg->pc);
 			break;
-		case 0x1:
-		case 0x3:
+		case 0x1:		/* alignment fault */
+		case 0x3:		/* access flag fault (section) */
 			if(user){
 				snprint(buf, sizeof buf,
 					"sys: alignment: pc %#lux va %#p\n",
@@ -502,15 +510,25 @@ trap(Ureg *ureg)
 		case 0x2:
 			panic("terminal exception at %#lux", ureg->pc);
 			break;
-		case 0x4:
-		case 0x6:
-		case 0x8:
-		case 0xa:
-		case 0xc:
-		case 0xe:
+		case 0x4:		/* icache maint fault */
+		case 0x6:		/* access flag fault (page) */
+		case 0x8:		/* precise external abort, non-xlat'n */
+		case 0x28:
+		case 0xc:		/* l1 translation, precise ext. abort */
+		case 0x2c:
+		case 0xe:		/* l2 translation, precise ext. abort */
+		case 0x2e:
+		case 0x16:		/* imprecise ext. abort, non-xlt'n */
+		case 0x36:
 			panic("external abort %#lux pc %#lux addr %#p",
 				fsr, ureg->pc, va);
 			break;
+		case 0x1c:		/* l1 translation, precise parity err */
+		case 0x1e:		/* l2 translation, precise parity err */
+		case 0x18:		/* imprecise parity or ecc err */
+			panic("translation parity error %#lux pc %#lux addr %#p",
+				fsr, ureg->pc, va);
+			break;
 		case 0x5:		/* translation fault, no section entry */
 		case 0x7:		/* translation fault, no page entry */
 			faultarm(ureg, va, user, !writetomem(inst));

+ 8 - 6
sys/src/9/omap/words

@@ -77,14 +77,14 @@ There are four USB errata that need to be looked into for the igepv2
 
 Flash
 
-access to nand or spi flash would be handy for nvram and small
-fossils.  flash access isn't well documented.  inferno implements
-these software layers: ecc, translation (for wear-levelling and bad
-sectors), common flash code and specific drivers for flash chips.
+access to nand flash would be handy for nvram and paqfs or sacfs file
+systems.
 
 In the flash, x-loader occupies up to 0x20000, then u-boot from
-0x80000 to 0x1e0000.  The flash chip is a micron pop 2Gb nand
-mt29f2g16abdhc-et (physical marking jw256).
+0x80000 to 0x1e0000, and there's a linux kernel after that (if you
+care).  The beagle's flash chip is a micron pop 2Gb nand
+mt29f2g16abdhc-et (physical marking jw256), and the igep's is a
+samsung onenand.
 
 VFPv3 Floating Point
 
@@ -133,6 +133,8 @@ ___
 	memory map (mostly from omap35x ref)
 hex addr	size	what
 ----
+0		16MB	physical address of flash registers, buffers
+20000000	16MB	virtual address of flash registers, buffers
 2c000000	?	smc 9221 ethernet
 38000000	16MB	256MB (beagle) or 512MB (igep) nand flash mapped here
 

+ 8 - 2
sys/src/cmd/fossil/cache.c

@@ -737,9 +737,15 @@ cacheAllocBlock(Cache *c, int type, u32int tag, u32int epoch, u32int epochLow)
 			addr = 0;
 			if(++nwrap >= 2){
 				blockPut(b);
-				fl->last = 0;
 				vtSetError("disk is full");
-				fprint(2, "%s: cacheAllocBlock: xxx1 %R\n", argv0);
+				/*
+				 * try to avoid a continuous spew of console
+				 * messages.
+				 */
+				if (fl->last != 0)
+					fprint(2, "%s: cacheAllocBlock: xxx1 %R\n",
+						argv0);
+				fl->last = 0;
 				vtUnlock(fl->lk);
 				return nil;
 			}

+ 11 - 0
sys/src/cmd/ramfs.c

@@ -16,6 +16,7 @@ enum
 	Nram	= 2048,
 	Maxsize	= 768*1024*1024,
 	Maxfdata	= 8192,
+	Maxulong= (1ULL << 32) - 1,
 };
 
 typedef struct Fid Fid;
@@ -504,11 +505,16 @@ rread(Fid *f)
 		return Enotexist;
 	n = 0;
 	rhdr.count = 0;
+	rhdr.data = (char*)rdata;
+	if (thdr.offset < 0 || thdr.offset > Maxulong)
+		return "whacko seek offset";
 	off = thdr.offset;
 	buf = rdata;
 	cnt = thdr.count;
 	if(cnt > messagesize)	/* shouldn't happen, anyway */
 		cnt = messagesize;
+	if(cnt < 0)
+		return "negative read count";
 	if(f->ram->qid.type & QTDIR){
 		for(r=ram+1; off > 0; r++){
 			if(r->busy && r->parent==f->ram-ram)
@@ -548,12 +554,17 @@ rwrite(Fid *f)
 	int cnt;
 
 	r = f->ram;
+	rhdr.count = 0;
 	if(r->busy == 0)
 		return Enotexist;
+	if (thdr.offset < 0 || thdr.offset > Maxulong)
+		return "whacko seek offset";
 	off = thdr.offset;
 	if(r->perm & DMAPPEND)
 		off = r->ndata;
 	cnt = thdr.count;
+	if(cnt < 0)
+		return "negative write count";
 	if(r->qid.type & QTDIR)
 		return Eisdir;
 	if(memlim && off+cnt >= Maxsize)		/* sanity check */