~kris/9p

9hist

8eb8147866d18bcb14155aab3b7eeb61f99747e7 — David du Colombier 25 years ago 1865821
Plan 9 from Bell Labs 2001-08-22
M alphapc/trap.c => alphapc/trap.c +2 -0
@@ 703,6 703,8 @@ print("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
	poperror();

error:
	/* failure: save the error buffer for errstr */
	kstrcpy(up->syserror, up->error, sizeof up->syserror);
	up->nerrlab = 0;
	up->psstate = 0;
	up->insyscall = 0;

M bitsy/devpenmouse.c => bitsy/devpenmouse.c +4 -1
@@ 92,7 92,10 @@ extern	Memimage*	gscreen;

void
penbutton(int up, int b) {
	if (b & 0x20) {
	// button 5 (side button) immediately causes an event
	// when the pen is down (button 1), other buttons also
	// cause events, allowing chording with button 1
	if ((b & 0x20) || (mouse.buttons & 0x1)) {
		if (up)
			mouse.buttons &= ~b;
		else

M bitsy/l.s => bitsy/l.s +2 -1
@@ 688,7 688,8 @@ TEXT power_down(SB), $-4
	MOVW	R2,0x10(R3)
	MOVW	$0,R2
	MOVW	R2,0x18(R3)
	MOVW	$power_resume+0(SB),R2
/*	MOVW	$power_resume+0(SB),R2	*/
	MOVW	$0,R2
	MOVW	R2,0x8(R3)
	MOVW	$0,R2
	MOVW	R2,0x4(R6)

M bitsy/power.c => bitsy/power.c +0 -2
@@ 275,7 275,6 @@ powerinit(void)
void
idlehands(void)
{
#ifdef notdef
	char *msgb = "idlehands called with splhi\n";
	char *msga = "doze returns with splhi\n";



@@ 288,6 287,5 @@ idlehands(void)
		serialputs(msgb, strlen(msgb));
		spllo();
	}
#endif
}


M bitsy/trap.c => bitsy/trap.c +3 -0
@@ 462,6 462,9 @@ syscall(Ureg* ureg)

		ret = systab[scallnr](up->s.args);
		poperror();
	}else{
		/* failure: save the error buffer for errstr */
		kstrcpy(up->syserror, up->error, sizeof up->syserror);
	}
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);

M mtx/trap.c => mtx/trap.c +3 -0
@@ 653,6 653,9 @@ syscall(Ureg* ureg)

		ret = systab[scallnr](up->s.args);
		poperror();
	}else{
		/* failure: save the error buffer for errstr */
		kstrcpy(up->syserror, up->error, sizeof up->syserror);
	}
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);

M pc/devvga.c => pc/devvga.c +1 -0
@@ 276,6 276,7 @@ vgactl(char* a)
		return;
	}
	else if(strcmp(field[0], "drawinit") == 0){
		memimagedraw(scr->gscreen, scr->gscreen->r, memblack, ZP, nil, ZP);
		if(scr && scr->dev && scr->dev->drawinit)
			scr->dev->drawinit(scr);
		return;

M pc/ether79c970.c => pc/ether79c970.c +112 -63
@@ 1,5 1,5 @@
/*
 * AM79C970
 * AMD79C970
 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
 * To do:
 *	finish this rewrite


@@ 108,7 108,7 @@ enum {					/* md2 */
};

typedef struct Ctlr Ctlr;
typedef struct Ctlr {
struct Ctlr {
	Lock;
	int	port;
	Pcidev*	pcidev;


@@ 140,28 140,49 @@ typedef struct Ctlr {
	ulong	merr;			/* bobf is such a whiner */
	ulong	miss;
	ulong	babl;
} Ctlr;

	int	(*ior)(Ctlr*, int);
	void	(*iow)(Ctlr*, int, int);
};

static Ctlr* ctlrhead;
static Ctlr* ctlrtail;

#define csr32r(c, r)	(inl((c)->port+(r)))
#define csr32w(c, r, l)	(outl((c)->port+(r), (ulong)(l)))
/*
 * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
 * To get to 16-bit offsets, scale down with 0x10 staying the same.
 */
static int
io16r(Ctlr *c, int r)
{
	if(r >= Rdp)
		r = (r-Rdp)/2+Rdp;
	return ins(c->port+r);
}

static void
attach(Ether* ether)
io16w(Ctlr *c, int r, int v)
{
	Ctlr *ctlr;
	if(r >= Rdp)
		r = (r-Rdp)/2+Rdp;
	outs(c->port+r, v);
}

	ctlr = ether->ctlr;
static int
io32r(Ctlr *c, int r)
{
	return inl(c->port+r);
}

	ilock(ctlr);
	if(ctlr->init){
		iunlock(ctlr);
		return;
	}
	csr32w(ctlr, Rdp, Iena|Strt);
	iunlock(ctlr);
static void
io32w(Ctlr *c, int r, int v)
{
	outl(c->port+r, v);
}

static void
attach(Ether*)
{
}

static long


@@ 260,20 281,20 @@ promiscuous(void* arg, int on)
	while(ctlr->ntq)
		;

	csr32w(ctlr, Rdp, Stop);
	ctlr->iow(ctlr, Rdp, Stop);

	csr32w(ctlr, Rap, 15);
	x = csr32r(ctlr, Rdp) & ~Prom;
	ctlr->iow(ctlr, Rap, 15);
	x = ctlr->ior(ctlr, Rdp) & ~Prom;
	if(on)
		x |= Prom;
	csr32w(ctlr, Rdp, x);
	csr32w(ctlr, Rap, 0);
	ctlr->iow(ctlr, Rdp, x);
	ctlr->iow(ctlr, Rap, 0);

	ringinit(ctlr);

	ilock(ctlr);
	ctlr->init = 0;
	csr32w(ctlr, Rdp, Iena|Strt);
	ctlr->iow(ctlr, Rdp, Iena|Strt);
	iunlock(ctlr);
}



@@ 299,7 320,7 @@ txstart(Ether* ether)
		 * increment the software ring descriptor pointer
		 * and tell the chip to poll.
		 * There's no need to pad to ETHERMINTU
		 * here as ApadXmit is set in CSR4.
		 * here as ApadXmt is set in CSR4.
		 */
		dre = &ctlr->tdr[ctlr->tdrh];
		dre->bp = bp;


@@ 307,7 328,7 @@ txstart(Ether* ether)
		dre->md2 = 0;
		dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
		ctlr->ntq++;
		csr32w(ctlr, Rdp, Iena|Tdmd);
		ctlr->iow(ctlr, Rdp, Iena|Tdmd);
		ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
	}
}


@@ 340,8 361,8 @@ interrupt(Ureg*, void* arg)
	 * happen.
	 */
intrloop:
	csr0 = csr32r(ctlr, Rdp) & 0xFFFF;
	csr32w(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
	csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
	ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
	if(csr0 & Merr)
		ctlr->merr++;
	if(csr0 & Miss)


@@ 488,46 509,67 @@ reset(Ether* ether)
	ilock(ctlr);
	ctlr->init = 1;

	io32r(ctlr, Sreset);
	io16r(ctlr, Sreset);

	if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
		ctlr->ior = io16r;
		ctlr->iow = io16w;
	}else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
		ctlr->ior = io32r;
		ctlr->iow = io32w;
	}else{
		print("#l%d: card doesn't talk right\n", ether->ctlrno);
		iunlock(ctlr);
		return -1;
	}

	ctlr->iow(ctlr, Rap, 88);
	x = ctlr->ior(ctlr, Rdp);
	ctlr->iow(ctlr, Rap, 89);
	x |= ctlr->ior(ctlr, Rdp)<<16;

	switch(x&0xFFFFFFF){
	case 0x2420003:	/* PCnet/PCI 79C970 */
	case 0x2621003:	/* PCnet/PCI II 79C970A */
		break;
	default:
		print("#l%d: unknown PCnet card version %.7ux\n",
			ether->ctlrno, x&0xFFFFFFF);
		iunlock(ctlr);
		return -1;
	}

	/*
	 * How to tell what mode the chip is in at this point - if it's in WORD
	 * mode then the only 32-bit access allowed is a write to the RDP, which
	 * forces the chip to DWORD mode; if it's in DWORD mode then only DWORD
	 * accesses are allowed?
	 * Assuming a DWORD write is done to the RDP, what will be overwritten as
	 * the RAP can't reliably be accessed?
	 *
	 * Force DWORD mode by writing to RDP, doing a reset then writing to RDP
	 * again. The value of RAP after a reset is 0, so the second DWORD write
	 * will be to CSR0.
	 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
	 * Set the auto pad transmit in CSR4.
	 */
	csr32w(ctlr, Rdp, 0x00);
	csr32r(ctlr, Sreset);
	csr32w(ctlr, Rdp, Stop);

	csr32w(ctlr, Rap, 20);
	csr32w(ctlr, Bdp, 0x0002);
	ctlr->iow(ctlr, Rap, 20);
	ctlr->iow(ctlr, Bdp, 0x0002);

	csr32w(ctlr, Rap, 4);
	x = csr32r(ctlr, Rdp) & 0xFFFF;
	csr32w(ctlr, Rdp, ApadXmt|x);
	ctlr->iow(ctlr, Rap, 4);
	x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
	ctlr->iow(ctlr, Rdp, ApadXmt|x);

	csr32w(ctlr, Rap, 0);
	ctlr->iow(ctlr, Rap, 0);

	/*
	 * Check if the adapter's station address is to be over-ridden.
	 * If not, read it from the I/O-space and set in ether->ea prior to loading the
	 * station address in the initialisation block.
	 * Check if the adapter's station address is to be overridden.
	 * If not, read it from the I/O-space and set in ether->ea prior to
	 * loading the station address in the initialisation block.
	 */
	memset(ea, 0, Eaddrlen);
	if(!memcmp(ea, ether->ea, Eaddrlen)){
		x = csr32r(ctlr, Aprom);
		x = ctlr->ior(ctlr, Aprom);
		ether->ea[0] = x;
		ether->ea[1] = x>>8;
		ether->ea[2] = x>>16;
		ether->ea[3] = x>>24;
		x = csr32r(ctlr, Aprom+4);
		if(ctlr->ior == io16r)
			x = ctlr->ior(ctlr, Aprom+2);
		else
			x >>= 16;
		ether->ea[2] = x;
		ether->ea[3] = x>>8;
		x = ctlr->ior(ctlr, Aprom+4);
		ether->ea[4] = x;
		ether->ea[5] = x>>8;
	}


@@ 550,18 592,25 @@ reset(Ether* ether)
	 * enables will be set later when attaching to the network.
	 */
	x = PADDR(&ctlr->iblock);
	csr32w(ctlr, Rap, 1);
	csr32w(ctlr, Rdp, x & 0xFFFF);
	csr32w(ctlr, Rap, 2);
	csr32w(ctlr, Rdp, (x>>16) & 0xFFFF);
	csr32w(ctlr, Rap, 3);
	csr32w(ctlr, Rdp, Idon);
	csr32w(ctlr, Rap, 0);
	csr32w(ctlr, Rdp, Init);

	while(!(csr32r(ctlr, Rdp) & Idon))
	ctlr->iow(ctlr, Rap, 1);
	ctlr->iow(ctlr, Rdp, x & 0xFFFF);
	ctlr->iow(ctlr, Rap, 2);
	ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
	ctlr->iow(ctlr, Rap, 3);
	ctlr->iow(ctlr, Rdp, Idon);
	ctlr->iow(ctlr, Rap, 0);
	ctlr->iow(ctlr, Rdp, Init);

	while(!(ctlr->ior(ctlr, Rdp) & Idon))
		;
	csr32w(ctlr, Rdp, Idon|Stop);

	/*
	 * We used to set CSR0 to Idon|Stop here, and then
	 * in attach change it to Iena|Strt.  Apparently the simulated
	 * 79C970 in VMware never enables after a write of Idon|Stop,
	 * so we enable the device here now.
	 */
	ctlr->iow(ctlr, Rdp, Iena|Strt);
	ctlr->init = 0;
	iunlock(ctlr);


M pc/screen.c => pc/screen.c +0 -3
@@ 72,9 72,6 @@ screensize(int x, int y, int z, ulong chan)
	if(gscreen == nil)
		return -1;

/*	memset(gscreen->data->bdata, 0x15, (x*y*z+7)/8);	/* RSC BUG */
	memfillcolor(gscreen, DRed);

	scr->palettedepth = 6;	/* default */
	scr->gscreendata = &gscreendata;
	scr->memdefont = getmemdefont();

M pc/sdata.c => pc/sdata.c +0 -5
@@ 1590,14 1590,12 @@ atapnp(void)
	Pcidev *p;
	int channel, ispc87415, pi, r;
	SDev *legacy[2], *sdev, *head, *tail;
//int i;

	legacy[0] = legacy[1] = head = tail = nil;
	if(sdev = ataprobe(0x1F0, 0x3F4, IrqATA0)){
		head = tail = sdev;
		legacy[0] = sdev;
	}
//print("probe 1, sdev %p\n", sdev);
	if(sdev = ataprobe(0x170, 0x374, IrqATA1)){
		if(head != nil)
			tail->next = sdev;


@@ 1606,7 1604,6 @@ atapnp(void)
		tail = sdev;
		legacy[1] = sdev;
	}
//print("probe 2, sdev %p\n", sdev);

	p = nil;
	while(p = pcimatch(p, 0, 0)){


@@ 1662,8 1659,6 @@ atapnp(void)
			 */
			break;
		case (0x0646<<16)|0x1095:	/* CMD 646 */
//for(i = 0; i <= 4; i++) print("bar%d: addr %lux size %d\n", i, p->mem[i].bar, p->mem[i].size);
			break;
		case (0x0571<<16)|0x1106:	/* VIA 82C686 */
		case (0x0211<<16)|0x1166:	/* ServerWorks IB6566 */
		case (0x1230<<16)|0x8086:	/* 82371FB (PIIX) */

M pc/trap.c => pc/trap.c +3 -0
@@ 502,6 502,9 @@ syscall(Ureg* ureg)

		ret = systab[scallnr](up->s.args);
		poperror();
	}else{
		/* failure: save the error buffer for errstr */
		kstrcpy(up->syserror, up->error, sizeof up->syserror);
	}
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);

M pc/uarti8250.c => pc/uarti8250.c +2 -2
@@ 135,14 135,14 @@ static Uart i8250uart[2] = {
	.name	= "COM1",
	.freq	= UartFREQ,
	.phys	= &i8250physuart,
	.special=0,
	.special= 0,
	.next	= &i8250uart[1], },

{	.regs	= &i8250ctlr[1],
	.name	= "COM2",
	.freq	= UartFREQ,
	.phys	= &i8250physuart,
	.special=0,
	.special= 0,
	.next	= nil, },
};


M pc/vga.c => pc/vga.c +1 -0
@@ 189,6 189,7 @@ vgascreenwin(VGAscr* scr)
	curpos = window.min;

	screenputs = vgascreenputs;

}

/*

A pc/vgavmware.c => pc/vgavmware.c +194 -0
@@ 0,0 1,194 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"

enum {
	PCIVMWARE	= 0x15AD,	/* PCI VID */

	VMWARE1		= 0x0710,	/* PCI DID */
	VMWARE2		= 0x0405,
};

enum {
	Rid = 0,
	Renable,
	Rwidth,
	Rheight,
	Rmaxwidth,
	Rmaxheight,
	Rdepth,
	Rbpp,
	Rpseudocolor,
	Rrmask,
	Rgmask,
	Rbmask,
	Rbpl,
	Rfbstart,
	Rfboffset,
	Rfbmaxsize,
	Rfbsize,
	Rcap,
	Rmemstart,
	Rmemsize,
	Rconfigdone,
	Rsync,
	Rbusy,
	Rguestid,
	Rcursorid,
	Rcursorx,
	Rcursory,
	Rcursoron,
	Nreg,

	Rpalette = 1024,
};

typedef struct Vmware	Vmware;
struct Vmware {
	ulong	mmio;
	ulong	fb;

	ulong	ra;
	ulong	rd;

	ulong	r[Nreg];

	char	chan[32];
	int	depth;
};

Vmware xvm;
Vmware *vm=&xvm;

static ulong
vmrd(Vmware *vm, int i)
{
	outl(vm->ra, i);
	return inl(vm->rd);
}

static void
vmwr(Vmware *vm, int i, ulong v)
{
	outl(vm->ra, i);
	outl(vm->rd, v);
}

static ulong
vmwarelinear(VGAscr* scr, int* size, int* align)
{
	char err[64];
	ulong aperture, oaperture;
	int osize, oapsize, wasupamem;
	Pcidev *p;
	Physseg seg;

	osize = *size;
	oaperture = scr->aperture;
	oapsize = scr->apsize;
	wasupamem = scr->isupamem;

	p = pcimatch(nil, PCIVMWARE, 0);
	if(p == nil)
		error("no vmware card found");

	switch(p->did){
	default:
		snprint(err, sizeof err, "unknown vmware id %.4ux", p->did);
		error(err);
		
	case VMWARE1:
		vm->ra = 0x4560;
		vm->rd = 0x4560+4;
		break;

	case VMWARE2:
		vm->ra = p->mem[0].bar&~3;
		vm->rd = vm->ra + 1;
	}

	aperture = (ulong)(vmrd(vm, Rfbstart));
	*size = vmrd(vm, Rfbsize);

	if(wasupamem)
		upafree(oaperture, oapsize);
	scr->isupamem = 0;

	aperture = upamalloc(aperture, *size, *align);
	if(aperture == 0){
		if(wasupamem && upamalloc(oaperture, oapsize, 0))
			scr->isupamem = 1;
	}else
		scr->isupamem = 1;

	if(oaperture)
		print("warning (BUG): redefinition of aperture does not change vmwarescreen segment\n");
	memset(&seg, 0, sizeof(seg));
	seg.attr = SG_PHYSICAL;
	seg.name = smalloc(32);
	snprint(seg.name, 32, "vmwarescreen");
	seg.pa = aperture;
	seg.size = osize;
	addphysseg(&seg);
	return aperture;
}

static void
vmwaredisable(VGAscr*)
{
}

static void
vmwareload(VGAscr*, Cursor*)
{
}

static int
vmwaremove(VGAscr*, Point)
{
	return 0;
}

static void
vmwareenable(VGAscr*)
{
}

static void
vmwareblank(int)
{
}

static void
vmwaredrawinit(VGAscr*)
{
}

VGAdev vgavmwaredev = {
	"vmware",

	0,
	0,
	0,
	vmwarelinear,
	vmwaredrawinit,
};

VGAcur vgavmwarecur = {
	"vmwarehwgc",

	vmwareenable,
	vmwaredisable,
	vmwareload,
	vmwaremove,
};

M port/allocb.c => port/allocb.c +4 -5
@@ 62,12 62,11 @@ allocb(int size)
	 */
	if(up == nil)
		panic("allocb without up: %uX\n", getcallerpc(&size));
	if((b = _allocb(size)) == nil)
{
xsummary();
mallocsummary();
	if((b = _allocb(size)) == nil){
		xsummary();
		mallocsummary();
		panic("allocb: no memory for %d bytes\n", size);
}
	}
	setmalloctag(b, getcallerpc(&size));

	return b;

M port/chan.c => port/chan.c +28 -16
@@ 237,6 237,7 @@ newchan(void)
	c->iounit = 0;
	c->umh = 0;
	c->uri = 0;
	c->dri = 0;
	c->aux = 0;
	c->mchan = 0;
	c->mcp = 0;


@@ 546,9 547,9 @@ cunmount(Chan *mnt, Chan *mounted)
	Mount *f, **p;

if(mnt->umh)	/* should not happen */
	print("cunmount newp extra umh\n");
	print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
if(mounted && mounted->umh)
	print("cunmount old extra umh\n");
	print("cunmount old extra umh %p has %p\n", mounted, mounted->umh);

	pg = up->pgrp;
	wlock(&pg->ns);


@@ 771,7 772,7 @@ walk(Chan **cp, char **names, int nnames, int nomount)
				runlock(&mh->lock);
				nexterror();
			}
			for(f = mh->mount; f; f = f->next)
			for(f = mh->mount->next; f; f = f->next)
				if((wq = devtab[f->to->type]->walk(f->to, nil, names, ntry)) != nil)
					break;
			poperror();


@@ 969,6 970,7 @@ namec(char *aname, int amode, int omode, ulong perm)
	Elemlist e;
	Rune r;
	Mhead *m;
	char createerr[ERRMAX];
	char *name;

	name = aname;


@@ 1086,29 1088,36 @@ namec(char *aname, int amode, int omode, ulong perm)
		cnameclose(c->name);
		c->name = cname;

		if(amode == Aremove){
		switch(amode){
		case Aremove:
			putmhead(m);
			break;
		}

		case Aopen:
		case Acreate:
if(c->umh != nil){
	print("cunique umh\n");
	putmhead(c->umh);
}
		c->umh = m;
			if(c->qid.type&QTDIR)
				c->umh = m;
			else
				putmhead(m);

		/* save registers else error() in open has wrong value of c saved */
		saveregisters();
			/* save registers else error() in open has wrong value of c saved */
			saveregisters();

		if(omode == OEXEC)
			c->flag &= ~CCACHE;
			if(omode == OEXEC)
				c->flag &= ~CCACHE;

		c = devtab[c->type]->open(c, omode&~OCEXEC);
			c = devtab[c->type]->open(c, omode&~OCEXEC);

		if(omode & OCEXEC)
			c->flag |= CCEXEC;
		if(omode & ORCLOSE)
			c->flag |= CRCLOSE;
			if(omode & OCEXEC)
				c->flag |= CCEXEC;
			if(omode & ORCLOSE)
				c->flag |= CRCLOSE;
			break;
		}
		break;

	case Atodir:


@@ 1222,8 1231,10 @@ if(c->umh != nil){
				putmhead(m);
			if(omode & OEXCL)
				nexterror();
			/* save error */
			kstrcpy(createerr, up->error, sizeof createerr);
			if(walk(&c, e.elems+e.nelems-1, 1, nomount) < 0)
				nexterror();
				error(createerr);	/* report true error */
			omode |= OTRUNC;
			goto Open;
		}


@@ 1242,6 1253,7 @@ if(c->umh != nil){
		kstrcpy(up->genbuf, ".", sizeof up->genbuf);
	free(e.name);
	free(e.elems);

	return c;
}


M port/dev.c => port/dev.c +3 -5
@@ 254,20 254,18 @@ devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
long
devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
{
	long k, m, dsz;
	long m, dsz;
	struct{
		Dir;
		char slop[100];
	}dir;

	k = c->offset;
	for(m=0; m<n; k++) {
		switch((*gen)(c, nil, tab, ntab, k, &dir)){
	for(m=0; m<n; c->dri++) {
		switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
		case -1:
			return m;

		case 0:
			c->offset++;	/* BUG??? (was DIRLEN: skip entry) */
			break;

		case 1:

M port/devdup.c => port/devdup.c +1 -1
@@ 103,7 103,7 @@ dupread(Chan *c, void *va, long n, vlong offset)
{
	char *a = va;
	char buf[256];
	int fd, twicefd, m;
	int fd, twicefd;
	Fgrp *f;

	if(c->qid.type == QTDIR)

M port/devmnt.c => port/devmnt.c +0 -1
@@ 410,7 410,6 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname)
	if(waserror()) {
		mntfree(r);
		nexterror();
		return nil;
	}
	r->request.type = Twalk;
	r->request.fid = c->fid;

M port/portdat.h => port/portdat.h +3 -1
@@ 155,6 155,7 @@ struct Chan
	Chan*	umc;			/* channel in union; held for union read */
	QLock	umqlock;		/* serialize unionreads */
	int	uri;			/* union read index */
	int	dri;			/* devdirread index */
	ulong	mountid;
	Mntcache *mcp;			/* Mount cache pointer */
	Mnt		*mux;		/* Mnt for clients using me for messages */


@@ 609,7 610,8 @@ struct Proc
	Sargs	s;		/* address of this is known by db */
	int	nerrlab;
	Label	errlab[NERR];
	char	error[ERRMAX];
	char	syserror[ERRMAX];	/* last error from a system call */
	char	error[ERRMAX];		/* reason we're unwinding the error stack */
	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
	Chan	*slash;
	Chan	*dot;

M port/proc.c => port/proc.c +2 -1
@@ 339,6 339,7 @@ newproc(void)
	p->wired = 0;
	p->ureg = 0;
	p->error[0] = '\0';
	p->syserror[0] = '\0';
	kstrdup(&p->user, "*nouser");
	kstrdup(&p->text, "*notext");
	kstrdup(&p->args, "");


@@ 1108,7 1109,7 @@ void
error(char *err)
{
	spllo();
	strncpy(up->error, err, ERRMAX);
	kstrcpy(up->error, err, sizeof up->error);
	nexterror();
}


M port/sysfile.c => port/sysfile.c +2 -1
@@ 557,6 557,7 @@ sseek(ulong *arg)
	}
	*(vlong*)arg[0] = off;
	c->uri = 0;
	c->dri = 0;
	cclose(c);
	poperror();
}


@@ 783,7 784,7 @@ sysunmount(ulong *arg)
			nexterror();
		}
		validaddr(arg[0], 1, 0);
		cmounted = namec((char*)arg[0], Aopen, OREAD, 0);
		cmounted = namec((char*)arg[0], Aaccess, OREAD, 0);
		poperror();
	}


M port/sysproc.c => port/sysproc.c +18 -23
@@ 633,41 633,36 @@ werrstr(char *fmt, ...)
	va_end(va);
}

long
syserrstr(ulong *arg)
static long
generrstr(char *buf, uint nbuf)
{
	char *e, tmp[sizeof up->error];
	uint n;
	char tmp[sizeof up->syserror];

	n = arg[1];
	if(n > sizeof tmp)
		n = sizeof tmp;
	validaddr(arg[0], n, 1);
	e = (char*)arg[0];
	memmove(tmp, e, n);
	validaddr((ulong)buf, nbuf, 1);
	if(nbuf > sizeof tmp)
		nbuf = sizeof tmp;
	memmove(tmp, buf, nbuf);
	/* make sure it's NUL-terminated */
	tmp[n-1] = '\0';
	memmove(e, up->error, n);
	e[n-1] = '\0';
	memmove(up->error, tmp, n);
	tmp[nbuf-1] = '\0';
	memmove(buf, up->syserror, nbuf);
	buf[nbuf-1] = '\0';
	memmove(up->syserror, tmp, nbuf);
	return 0;
}

long
syserrstr(ulong *arg)
{
	return generrstr((char*)arg[0], arg[1]);
}

/* compatibility for old binaries */
long
sys_errstr(ulong *arg)
{
	char *e, tmp[64];

	validaddr(arg[0], 64, 1);
	e = (char*)arg[0];
	memmove(tmp, e, 64);
	memmove(e, up->error, 64);
	memmove(up->error, tmp, 64);
	return 0;
	return generrstr((char*)arg[0], 64);
}


long
sysnotify(ulong *arg)
{