~kris/9p

9hist

c7d82362a66316c86085abfc4003b6228023eefe — David du Colombier 35 years ago b915535
Plan 9 from Bell Labs 1990-12-23
M gnot/mem.h => gnot/mem.h +1 -1
@@ 37,7 37,7 @@
#define	CENABLE		0x01

/*
 * Magic registers
 * Magic registers (unused in current system)
 */

#define	MACH		A5		/* A5 is m-> */

A ss/boot.c => ss/boot.c +211 -0
@@ 0,0 1,211 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>

Fcall	hdr;
char	buf[100];
char	bootline[64];
char	bootdevice;
char	bootserver[64];

void	error(char*);
void	sendmsg(int, char*);

main(int argc, char *argv[])
{
	int cfd, fd, n, fu, f, i;
	char buf[256];
	int p[2];

	open("#c/cons", OREAD);
	open("#c/cons", OWRITE);
	open("#c/cons", OWRITE);

	fd = open("#e/bootline", OREAD);
	if(fd >= 0){
		read(fd, bootline, sizeof bootline);
		close(fd);
	}
	fd = open("#e/bootdevice", OREAD);
	if(fd >= 0){
		read(fd, &bootdevice, 1);
		close(fd);
	}
	fd = open("#e/bootserver", OREAD);
	if(fd >= 0){
		read(fd, bootserver, 64);
		close(fd);
	} else
		strcpy(bootserver, "nfs");

	switch(bootdevice){
	case 'A':
		/*
		 *  grab the rs232 line,
		 *  make it 9600 baud,
		 *  push the async protocol onto it,
		 */
		cfd = open("#c/rs232ctl", 2);
		if(cfd < 0)
			error("opening #c/rs232ctl");
		sendmsg(cfd, "B9600");
		sendmsg(cfd, "push async");
		break;
	case 'a':
		/*
		 *  grab the rs232 line,
		 *  make it 19200 baud,
		 *  push the async protocol onto it,
		 */
		cfd = open("#c/rs232ctl", 2);
		if(cfd < 0)
			error("opening #c/rs232ctl");
		sendmsg(cfd, "B19200");
		sendmsg(cfd, "push async");
		break;
	default:
		/*
		 *  grab the incon,
		 */
		cfd = open("#i/ctl", 2);
		if(cfd < 0)
			error("opening #i/ctl");
		break;
	}

	/*
	 *  push the dk multiplexor onto the communications link,
	 *  and use line 1 as the signalling channel.
	 */
	sendmsg(cfd, "push dkmux");
	sendmsg(cfd, "config 1 16 norestart");

	/*
	 *  fork a process to hold the device channel open
	 */
	switch(fork()){
	case -1:
		break;
	case 0:
		for(;;)
			sleep(60*1000);
		exit(0);
	default:
		close(cfd);
		break;
	}

	/*
	 *  open a datakit channel and call ken, leave the
	 *  incon ctl channel open
	 */
	for(i = 0; ; i++){
		fd = open("#k/2/data", 2);
		if(fd < 0)
			error("opening #k/2/data");
		cfd = open("#k/2/ctl", 2);
		if(cfd < 0)
			error("opening #k/2/ctl");
		sprint(buf, "connect %s", bootserver);
		n = strlen(buf);
		if(write(cfd, buf, n) == n)
			break;
		if(i == 5)
			error("dialing");
		print("error dialing, retrying ...\n");
		close(fd);
		close(cfd);
	}
	print("connected to %s\n", bootserver);
	close(cfd);

	/*
	 *  talk to the file server
	 */
	print("nop...");
	hdr.type = Tnop;
	hdr.tag = ~0;
	n = convS2M(&hdr, buf);
	if(write(fd, buf, n) != n)
		error("write nop");
	n = read(fd, buf, sizeof buf);
	if(n==2 && buf[0]=='O' && buf[1]=='K')
		n = read(fd, buf, sizeof buf);
	if(n <= 0)
		error("read nop");
	if(convM2S(buf, &hdr, n) == 0) {
		print("n = %d; buf = %.2x %.2x %.2x %.2x\n",
			n, buf[0], buf[1], buf[2], buf[3]);
		error("format nop");
	}
	if(hdr.type != Rnop)
		error("not Rnop");

	print("session...");
	hdr.type = Tsession;
	hdr.tag = ~0;
	n = convS2M(&hdr, buf);
	if(write(fd, buf, n) != n)
		error("write session");
	n = read(fd, buf, sizeof buf);
	if(n <= 0)
		error("read session");
	if(convM2S(buf, &hdr, n) == 0)
		error("format session");
	if(hdr.type == Rerror){
		print("error %s;", hdr.ename);
		error(hdr.ename);
	}
	if(hdr.type != Rsession)
		error("not Rsession");

	print("post...");
	sprint(buf, "#s/%s", "bootes");
	f = create(buf, 1, 0666);
	if(f < 0)
		error("create");
	sprint(buf, "%d", fd);
	if(write(f, buf, strlen(buf)) != strlen(buf))
		error("write");
	close(f);
	sprint(buf, "#s/%s", "bootes");
	f = create("#s/boot", 1, 0666);
	if(f < 0)
		error("create");
	sprint(buf, "%d", fd);
	if(write(f, buf, strlen(buf)) != strlen(buf))
		error("write");
	close(f);
	
	print("mount...");
	if(bind("/", "/", MREPL) < 0)
		error("bind");
	if(mount(fd, "/", MAFTER|MCREATE, "", "") < 0)
		error("mount");
	print("success\n");
	if(strchr(bootline, ' '))
		execl("/68020/init", "init", "-m", 0);
	else
		execl("/68020/init", "init", 0);
	error("/68020/init");
}

void
sendmsg(int fd, char *msg)
{
	int n;

	n = strlen(msg);
	if(write(fd, msg, n) != n)
		error(msg);
}

void
error(char *s)
{
	char buf[64];

	errstr(buf);
	fprint(2, "boot: %s: %s\n", s, buf);
	exits(0);
}

A ss/boot.h => ss/boot.h +2662 -0
@@ 0,0 1,2662 @@
ulong bootcode[]={
	0x000000107,
	0x000002504,
	0x000000464,
	0x0000001e4,
	0x000000000,
	0x000002020,
	0x000000000,
	0x000000000,
	0x04feffff0,
	0x02c7c0000,
	0x0dffe486f,
	0x000142f2f,
	0x00014610c,
	0x02f006100,
	0x006884fef,
	0x0001c4e75,
	0x04feffee0,
	0x042a7486e,
	0x081166100,
	0x0151e4878,
	0x00001486e,
	0x0811e6100,
	0x015124878,
	0x00001486e,
	0x081266100,
	0x0150642a7,
	0x0486e812e,
	0x0610014fc,
	0x04a806d1e,
	0x048780040,
	0x0486e860a,
	0x02f002f40,
	0x001446100,
	0x014ec2f2f,
	0x001446100,
	0x014c04fef,
	0x0001042a7,
	0x0486e813a,
	0x0610014d0,
	0x04a806d1e,
	0x048780001,
	0x0486e8002,
	0x02f002f40,
	0x0014c6100,
	0x014c02f2f,
	0x0014c6100,
	0x014944fef,
	0x0001042a7,
	0x0486e8148,
	0x0610014a4,
	0x04a806d00,
	0x005324878,
	0x00040486e,
	0x084ea2f00,
	0x02f400154,
	0x061001492,
	0x02f2f0154,
	0x061001466,
	0x0102e8002,
	0x049c04fef,
	0x000407241,
	0x0b2006700,
	0x004cc7261,
	0x0b2006700,
	0x004884878,
	0x00002486e,
	0x081bd6100,
	0x0145e2f40,
	0x001244aaf,
	0x00124508f,
	0x06c0a486e,
	0x081c46100,
	0x00520588f,
	0x0486e81d3,
	0x02f2f0120,
	0x0610004e2,
	0x0486e81de,
	0x02f2f0128,
	0x0610004d6,
	0x061001420,
	0x04fef0010,
	0x072ffb280,
	0x06700043a,
	0x04281b280,
	0x067000424,
	0x02f2f011c,
	0x0610013f2,
	0x0588f42af,
	0x001084878,
	0x00002486e,
	0x081f46100,
	0x013fe4a80,
	0x042e72f40,
	0x0012244df,
	0x06c0a486e,
	0x081fe6100,
	0x004c0588f,
	0x048780002,
	0x0486e8210,
	0x0610013dc,
	0x04a8042e7,
	0x02f40012e,
	0x044df6c0a,
	0x0486e8219,
	0x06100049e,
	0x0588f486e,
	0x084ea486e,
	0x0822a486f,
	0x000206100,
	0x0062a486f,
	0x000246100,
	0x0136c2f00,
	0x02f400138,
	0x0486f002c,
	0x02f2f0144,
	0x0610013ae,
	0x0b0af0140,
	0x06600036a,
	0x0486e84ea,
	0x0486e825a,
	0x06100052c,
	0x02f2f0150,
	0x061001362,
	0x0486e826b,
	0x06100051c,
	0x01d7c0032,
	0x0858e3d7c,
	0x0ffff8592,
	0x0486f0044,
	0x0486e858e,
	0x06100137e,
	0x02f002f40,
	0x0015c486f,
	0x000502f2f,
	0x001646100,
	0x01360b0af,
	0x00164670a,
	0x0486e8272,
	0x061000416,
	0x0588f4878,
	0x00100486f,
	0x0005c2f2f,
	0x001706100,
	0x013342400,
	0x07002b082,
	0x0660a0c2f,
	0x0004f0064,
	0x0670002ce,
	0x04a8242e7,
	0x02f420172,
	0x044df6e0e,
	0x0486e827c,
	0x0610003de,
	0x0242f0174,
	0x0588f2f02,
	0x0486e858e,
	0x0486f006c,
	0x061001ace,
	0x04a806638,
	0x0102f0073,
	0x049c02f00,
	0x0102f0076,
	0x049c02f00,
	0x0102f0079,
	0x049c02f00,
	0x0102f007c,
	0x049c02f00,
	0x02f2f018c,
	0x0486e8285,
	0x061000468,
	0x0486e82a8,
	0x061000392,
	0x04fef001c,
	0x00c2e0033,
	0x0858e670a,
	0x0486e82b3,
	0x06100037e,
	0x0588f486e,
	0x082bc6100,
	0x004421d7c,
	0x00034858e,
	0x03d7cffff,
	0x08592486f,
	0x00074486e,
	0x0858e6100,
	0x012a42f00,
	0x02f40018c,
	0x0486f0080,
	0x02f2f0194,
	0x061001286,
	0x0b0af0194,
	0x0670a486e,
	0x082c76100,
	0x0033c588f,
	0x048780100,
	0x0486f008c,
	0x02f2f01a0,
	0x06100125a,
	0x02f4001a0,
	0x04aaf01a0,
	0x06e0a486e,
	0x082d56100,
	0x00318588f,
	0x02f2f01a0,
	0x0486e858e,
	0x0486f009c,
	0x061001a0a,
	0x04a80660a,
	0x0486e82e2,
	0x0610002fa,
	0x0588f0c2e,
	0x00037858e,
	0x06618486e,
	0x08594486e,
	0x082f16100,
	0x003b2486e,
	0x085946100,
	0x002dc4fef,
	0x0000c0c2e,
	0x00035858e,
	0x0670a486e,
	0x082fb6100,
	0x002c8588f,
	0x0486e8308,
	0x06100038c,
	0x0486e8316,
	0x0486e8310,
	0x0486f00ac,
	0x06100044c,
	0x0487801b6,
	0x048780001,
	0x0486f00b8,
	0x0610011b0,
	0x04a8042e7,
	0x02f4001c2,
	0x044df6c0a,
	0x0486e831d,
	0x06100028a,
	0x0588f2f2f,
	0x001cc486e,
	0x08324486f,
	0x000c46100,
	0x00416486f,
	0x000c86100,
	0x01158588f,
	0x02f00486f,
	0x000cc2f2f,
	0x001d46100,
	0x0119c2f00,
	0x0486f00d8,
	0x06100113e,
	0x0588f221f,
	0x0b280670a,
	0x0486e8327,
	0x061000246,
	0x0588f2f2f,
	0x001d86100,
	0x01148486e,
	0x08333486e,
	0x0832d486f,
	0x000e06100,
	0x003ca4878,
	0x001b64878,
	0x00001486e,
	0x0833a6100,
	0x0112e4a80,
	0x042e72f40,
	0x001f644df,
	0x06c0a486e,
	0x083426100,
	0x00208588f,
	0x02f2f0200,
	0x0486e8349,
	0x0486f00f8,
	0x061000394,
	0x0486f00fc,
	0x0610010d6,
	0x0588f2f00,
	0x0486f0100,
	0x02f2f0208,
	0x06100111a,
	0x02f00486f,
	0x0010c6100,
	0x010bc588f,
	0x0221fb280,
	0x0670a486e,
	0x0834c6100,
	0x001c4588f,
	0x02f2f020c,
	0x0610010c6,
	0x0486e8352,
	0x061000280,
	0x042a7486e,
	0x0835d486e,
	0x0835b6100,
	0x010a44a80,
	0x06c0a486e,
	0x0835f6100,
	0x00198588f,
	0x0486e8367,
	0x0486e8366,
	0x048780006,
	0x0486e8364,
	0x02f2f023c,
	0x0610010a2,
	0x04a806c0a,
	0x0486e8368,
	0x061000172,
	0x0588f486e,
	0x0836e6100,
	0x002364878,
	0x00020486e,
	0x0860a6100,
	0x0100c4a80,
	0x0672042a7,
	0x0486e8388,
	0x0486e8383,
	0x0486e8377,
	0x061000f56,
	0x0486e839c,
	0x06100013e,
	0x04fef0268,
	0x04e7542a7,
	0x0486e8397,
	0x0486e838b,
	0x061000f3a,
	0x0598f60e0,
	0x00c2f004b,
	0x000656600,
	0x0fd2c4878,
	0x00100486f,
	0x000682f2f,
	0x0017c6100,
	0x0103c2400,
	0x04fef000c,
	0x06000fd12,
	0x07005b0af,
	0x00134660a,
	0x0486e8235,
	0x0610000f2,
	0x0588f486e,
	0x0823d6100,
	0x001b62f2f,
	0x001486100,
	0x00fec2f2f,
	0x001506100,
	0x00fe452af,
	0x001404fef,
	0x000386000,
	0x0fbee4879,
	0x00000ea60,
	0x061000ff8,
	0x0588f60f2,
	0x06000fbd8,
	0x048780002,
	0x0486e818b,
	0x061000fd8,
	0x02f400124,
	0x04aaf0124,
	0x06c0a486e,
	0x081976100,
	0x0009c588f,
	0x0486e81ab,
	0x02f2f0128,
	0x0615e486e,
	0x081b22f2f,
	0x001306154,
	0x04fef0018,
	0x06000fb62,
	0x048780002,
	0x0486e815a,
	0x061000f9c,
	0x02f400124,
	0x04aaf0124,
	0x06c08486e,
	0x081666160,
	0x0588f486e,
	0x0817a2f2f,
	0x001286124,
	0x0486e8180,
	0x02f2f0130,
	0x0611a4fef,
	0x000186000,
	0x0fb28486e,
	0x08156486e,
	0x084ea6100,
	0x00f0e518f,
	0x06000fada,
	0x0598f2f2f,
	0x0000c6100,
	0x00f102f00,
	0x02f400008,
	0x02f2f0014,
	0x02f2f0014,
	0x061000f52,
	0x0b0af0010,
	0x067082f2f,
	0x0001c6108,
	0x0588f4fef,
	0x000144e75,
	0x04fefffc0,
	0x048576100,
	0x00f3a486f,
	0x000042f2f,
	0x0004c486e,
	0x083a84878,
	0x000026100,
	0x0011a42a7,
	0x061744fef,
	0x000584e75,
	0x0598f4281,
	0x07021b081,
	0x06f1e4ab6,
	0x01d208466,
	0x0660e2daf,
	0x000081d20,
	0x084667001,
	0x0588f4e75,
	0x052817021,
	0x0b0816ee2,
	0x04280588f,
	0x04e75598f,
	0x0206f0008,
	0x042827021,
	0x0b0826f18,
	0x020362d20,
	0x08466b088,
	0x0660642b6,
	0x02d208466,
	0x052827021,
	0x0b0826ee8,
	0x0588f4e75,
	0x04aaf0004,
	0x0660642a7,
	0x0610c588f,
	0x0486e844e,
	0x06104588f,
	0x04e75518f,
	0x072204a81,
	0x06d222eb6,
	0x01d208466,
	0x04a976712,
	0x02f410004,
	0x042b61d20,
	0x084664eb7,
	0x00151222f,
	0x000045381,
	0x04a816cde,
	0x02f2f000c,
	0x061000e40,
	0x04fef000c,
	0x04e754fef,
	0x0eff841ef,
	0x0100c5888,
	0x02f082f2f,
	0x0101041ef,
	0x00010d1fc,
	0x000001000,
	0x02f08486f,
	0x000146100,
	0x0011a2200,
	0x041ef0018,
	0x092882f01,
	0x0486f001c,
	0x048780001,
	0x061000e36,
	0x0240042e7,
	0x02f40001e,
	0x044df6c1a,
	0x052ae8012,
	0x0700ab0ae,
	0x080126e0e,
	0x048780001,
	0x06100ff5a,
	0x0242f0020,
	0x0588f2002,
	0x04fef1024,
	0x04e754fef,
	0x0eff841ef,
	0x010105888,
	0x02f082f2f,
	0x0101441ef,
	0x00010d1fc,
	0x000001000,
	0x02f08486f,
	0x000146100,
	0x000b22200,
	0x041ef0018,
	0x092882f01,
	0x0486f001c,
	0x02f2f1024,
	0x061000dce,
	0x0240042e7,
	0x02f40001e,
	0x044df6c1a,
	0x052ae8012,
	0x0700ab0ae,
	0x080126e0e,
	0x048780001,
	0x06100fef2,
	0x0242f0020,
	0x0588f2002,
	0x04fef1024,
	0x04e75518f,
	0x0226f000c,
	0x02eae8016,
	0x041ef0010,
	0x058882f08,
	0x02f2f0014,
	0x048691000,
	0x02f09614e,
	0x02d6f0010,
	0x0801690af,
	0x0001c4fef,
	0x000184e75,
	0x0142f0007,
	0x0c43c007f,
	0x0701eb0ae,
	0x0801a6e04,
	0x070014e75,
	0x0202e801a,
	0x0120249c1,
	0x01d801920,
	0x0809652ae,
	0x0801a1202,
	0x049c11036,
	0x019208096,
	0x049c02daf,
	0x000080d20,
	0x0801e4280,
	0x04e754fef,
	0x0ffe4282f,
	0x0002c246f,
	0x000282f6e,
	0x0800a0004,
	0x02eae8006,
	0x02d6f0020,
	0x0800a202f,
	0x000245380,
	0x02d408006,
	0x0101a49c0,
	0x024007025,
	0x0b0826768,
	0x04a826628,
	0x0202e800a,
	0x0b0ae8006,
	0x0650453ae,
	0x0800a4236,
	0x00161800a,
	0x0202e800a,
	0x02d6f0004,
	0x0800a2d57,
	0x080064fef,
	0x0001c4e75,
	0x0202e800a,
	0x0b0ae8006,
	0x0640a1d82,
	0x00161800a,
	0x052ae800a,
	0x052ae8016,
	0x0700ab082,
	0x0660642ae,
	0x0801660a4,
	0x07009b082,
	0x0669e7007,
	0x0d0ae8016,
	0x0c0bcffff,
	0x0fff82d40,
	0x08016608c,
	0x0327cfc18,
	0x02f7cffff,
	0x0fc180014,
	0x042af0010,
	0x0101a49c0,
	0x024002f4a,
	0x000284a82,
	0x06606538a,
	0x06000ff6a,
	0x0702eb082,
	0x06610b2fc,
	0x0fc186604,
	0x0327c0000,
	0x042af0014,
	0x060d67031,
	0x0b0826e46,
	0x07039b082,
	0x06d404283,
	0x07030b082,
	0x06e067039,
	0x0b0826c10,
	0x0b2fcfc18,
	0x066042243,
	0x060bc2f43,
	0x0001460b6,
	0x020032203,
	0x0d281d281,
	0x0d081d080,
	0x0d08290bc,
	0x000000030,
	0x02600101a,
	0x049c02400,
	0x02f4a0028,
	0x060c27030,
	0x0b0826606,
	0x0b2fcfc18,
	0x066b4702a,
	0x0b082661c,
	0x024304990,
	0x058842004,
	0x0b2fcfc18,
	0x066062242,
	0x06000ff66,
	0x02f420014,
	0x06000ff5e,
	0x0c4bc0000,
	0x0007f2f02,
	0x02f2f0014,
	0x02f2f001c,
	0x02f092f49,
	0x000282f04,
	0x02f440040,
	0x010362920,
	0x0809649c0,
	0x020760d20,
	0x0801e4e90,
	0x0282f0040,
	0x0246f003c,
	0x0226f002c,
	0x04a806c0e,
	0x0448081af,
	0x000244fef,
	0x000146000,
	0x0ff14d880,
	0x020044fef,
	0x000146000,
	0x0fe84222f,
	0x000080c81,
	0x0fffffc18,
	0x067087002,
	0x0c0af0010,
	0x066142f2f,
	0x0000c2f01,
	0x02f2f000c,
	0x061000218,
	0x04fef000c,
	0x04e754481,
	0x060e84fef,
	0x0ffbc2a2f,
	0x00058226f,
	0x00048206f,
	0x000502e2f,
	0x000542c2f,
	0x000042817,
	0x0367c0000,
	0x020052405,
	0x0726fb081,
	0x06d0001ce,
	0x06e0001a6,
	0x070082a00,
	0x0347c0000,
	0x07078c087,
	0x07228b081,
	0x06d000156,
	0x06e00011c,
	0x02c117004,
	0x02f400014,
	0x07020c087,
	0x066064a86,
	0x06d0000fe,
	0x0422f0041,
	0x0741c7040,
	0x0c0876700,
	0x000da2004,
	0x04c450801,
	0x026017030,
	0x0d6807039,
	0x0b0836c04,
	0x07027d680,
	0x022021f83,
	0x029200024,
	0x07002b082,
	0x06f7c7004,
	0x0c087671a,
	0x00c370030,
	0x029200024,
	0x067107008,
	0x0b0856638,
	0x053821fbc,
	0x000302920,
	0x00024b4fc,
	0x00000670a,
	0x053821fbc,
	0x0002d2920,
	0x000242f07,
	0x04878fc18,
	0x02f2f0054,
	0x048772920,
	0x000306100,
	0x0ff06202f,
	0x000244fef,
	0x000544e75,
	0x07010b085,
	0x066ccb6fc,
	0x000006716,
	0x053821fbc,
	0x000582920,
	0x000245382,
	0x01fbc0030,
	0x029200024,
	0x060b05382,
	0x01fbc0078,
	0x029200024,
	0x060e87040,
	0x0c087673e,
	0x020044c45,
	0x008012800,
	0x0b0fcfc18,
	0x06708701e,
	0x09088b082,
	0x06f127040,
	0x0c0876706,
	0x04a846f00,
	0x0ff5e4a86,
	0x06f00ff58,
	0x053827040,
	0x0c0876600,
	0x0ff2a2006,
	0x04c450001,
	0x026016000,
	0x0ff262006,
	0x04c450001,
	0x02c0060c0,
	0x04486347c,
	0x000016000,
	0x0fefc7230,
	0x0b280671e,
	0x07248b280,
	0x0670c2c11,
	0x070042f40,
	0x000146000,
	0x0fed82811,
	0x070042f40,
	0x000146000,
	0x0fecc2c11,
	0x034064286,
	0x03c027004,
	0x02f400014,
	0x06000feba,
	0x07208b280,
	0x0672a7210,
	0x0b2806712,
	0x07220b280,
	0x066c42c11,
	0x070042f40,
	0x000146000,
	0x0fe9c2c11,
	0x034063c02,
	0x048c67004,
	0x02f400014,
	0x06000fe8a,
	0x02c117004,
	0x02f400014,
	0x06000fe7e,
	0x07275b280,
	0x067107278,
	0x0b2806600,
	0x0fe547010,
	0x02a006000,
	0x0fe4c8ebc,
	0x000000020,
	0x0700a2a00,
	0x06000fe3e,
	0x07258b280,
	0x0670a7264,
	0x0b2806600,
	0x0fe3060e8,
	0x070012640,
	0x060d4518f,
	0x02f2f000c,
	0x0610008fa,
	0x0266f0010,
	0x0246e8006,
	0x0262f0014,
	0x0226f0018,
	0x0206e800a,
	0x022000c83,
	0x0fffffc18,
	0x067064a83,
	0x06c000084,
	0x0101b49c0,
	0x024006734,
	0x0b2fcfc18,
	0x06706b2fc,
	0x000006fec,
	0x0b1ca6406,
	0x010c22d48,
	0x0800a52ae,
	0x08016700a,
	0x0b0826642,
	0x042ae8016,
	0x0b2fcfc18,
	0x067ce5389,
	0x0101b49c0,
	0x0240066cc,
	0x00c83ffff,
	0x0fc186704,
	0x04a836d06,
	0x04fef000c,
	0x04e752403,
	0x04482b282,
	0x06cf2b1ca,
	0x0640810fc,
	0x000202d48,
	0x0800a52ae,
	0x080165281,
	0x060e87009,
	0x0b08266bc,
	0x07007d0ae,
	0x08016c0bc,
	0x0fffffff8,
	0x02d408016,
	0x060aa2001,
	0x0b2836c00,
	0x0ff78b1ca,
	0x0640810fc,
	0x000202d48,
	0x0800a52ae,
	0x080165281,
	0x060e4598f,
	0x01ebc002a,
	0x0202f0018,
	0x01f400001,
	0x01f7c002a,
	0x00002422f,
	0x000034878,
	0x0fc1842a7,
	0x0486f0008,
	0x06100ff10,
	0x042804fef,
	0x000104e75,
	0x0598f2037,
	0x001610008,
	0x01e80422f,
	0x000014878,
	0x0fc182f2f,
	0x00010486f,
	0x000086100,
	0x0feea7004,
	0x04fef0010,
	0x04e752f2f,
	0x000102f2f,
	0x000102f2f,
	0x000102f37,
	0x001610010,
	0x06100fc94,
	0x070044fef,
	0x000104e75,
	0x0202e800a,
	0x0b0ae8006,
	0x0640c1dbc,
	0x000250161,
	0x0800a52ae,
	0x0800a4280,
	0x04e75202f,
	0x000147268,
	0x0b0816d2a,
	0x06e0470f0,
	0x04e75726c,
	0x0b280670e,
	0x07275b280,
	0x067044280,
	0x04e7570e0,
	0x04e757008,
	0x0c0af0010,
	0x0670470c0,
	0x04e7570f8,
	0x04e757223,
	0x0b2806714,
	0x0722bb280,
	0x0670a722d,
	0x0b28066d6,
	0x070fe4e75,
	0x070ff4e75,
	0x070fc4e75,
	0x04fefff74,
	0x0f2375400,
	0x001610090,
	0x0f22f7400,
	0x0003442af,
	0x00010f22f,
	0x0543a0034,
	0x0f2930016,
	0x0f22f5400,
	0x00034f200,
	0x0001af22f,
	0x074000034,
	0x052af0010,
	0x042977041,
	0x0b0af00a0,
	0x06e0a705a,
	0x0b0af00a0,
	0x06c0004d2,
	0x042af0020,
	0x0f23c4000,
	0x000000000,
	0x0f22f543a,
	0x00034f281,
	0x000e2486f,
	0x00020f22f,
	0x054000038,
	0x0f2277400,
	0x0610004b8,
	0x0f22f4000,
	0x0002cf23c,
	0x054233fd3,
	0x044135547,
	0x05a32f22f,
	0x06000002c,
	0x0202f002c,
	0x0e2802f40,
	0x000284480,
	0x02f006100,
	0x005e0f22f,
	0x054230044,
	0x0f22f7400,
	0x00034202f,
	0x0002c90af,
	0x000302f00,
	0x0610005c6,
	0x0f22f5423,
	0x00038f200,
	0x00100f23c,
	0x040000000,
	0x00001f200,
	0x00838f295,
	0x0003053af,
	0x00034202f,
	0x0003090af,
	0x000342f00,
	0x06100059a,
	0x0f22f5423,
	0x0003cf200,
	0x00100f23c,
	0x040000000,
	0x00001f200,
	0x00838588f,
	0x0f292ffd4,
	0x0f23c4000,
	0x00000000a,
	0x0f2000838,
	0x04fef0014,
	0x0f2920030,
	0x052af0020,
	0x0202f001c,
	0x090af0020,
	0x02f006100,
	0x00558f22f,
	0x054230028,
	0x0f2000100,
	0x0f23c4000,
	0x00000000a,
	0x0f2000838,
	0x0588ff295,
	0x0ffd40caf,
	0x0fffffc18,
	0x000986606,
	0x070062f40,
	0x000987067,
	0x0b0af00a0,
	0x066084aaf,
	0x000986e00,
	0x003b4701e,
	0x0b0af0098,
	0x06c06701e,
	0x02f400098,
	0x07802d8af,
	0x000987066,
	0x0b0af00a0,
	0x06612202f,
	0x00020d880,
	0x06e0a7801,
	0x0f23c4000,
	0x000000000,
	0x07020b084,
	0x042e72f44,
	0x0001644df,
	0x06e187065,
	0x0b0af00a0,
	0x0660670ff,
	0x02f400098,
	0x070652f40,
	0x000a06000,
	0x0fe98f22f,
	0x054000034,
	0x0f22f7400,
	0x0002c4aaf,
	0x000206c26,
	0x070ff90af,
	0x000202f00,
	0x0610004aa,
	0x0282f0018,
	0x0f2277400,
	0x0f22f5400,
	0x00038f21f,
	0x05423f22f,
	0x074000030,
	0x0588f4283,
	0x0b6846c6a,
	0x0202f0020,
	0x090832f43,
	0x000184a80,
	0x06d0002d0,
	0x02f006100,
	0x00474f22f,
	0x054800030,
	0x0f20000a0,
	0x0f22f7400,
	0x00028f227,
	0x074806100,
	0x00478262f,
	0x00024282f,
	0x00020f202,
	0x06000f202,
	0x04000f22f,
	0x054230030,
	0x0f22f5480,
	0x00038f200,
	0x000a8f22f,
	0x074800038,
	0x07030d082,
	0x022031f80,
	0x039200071,
	0x05283b684,
	0x04fef000c,
	0x06d967605,
	0x074ffd484,
	0x04a826d38,
	0x0200241f7,
	0x029200065,
	0x0101049c0,
	0x0d0831080,
	0x042830c37,
	0x000392920,
	0x000656f16,
	0x0200241f7,
	0x029200065,
	0x0101049c0,
	0x090bc0000,
	0x0000a1080,
	0x052835382,
	0x04a826cc8,
	0x07c014a83,
	0x0670c1f7c,
	0x000310064,
	0x052af0020,
	0x042864282,
	0x04aaf0010,
	0x067000200,
	0x01fbc002d,
	0x02920003c,
	0x052824283,
	0x07801d8af,
	0x000982a2f,
	0x000987067,
	0x0b0af00a0,
	0x0661470fb,
	0x0b0af0020,
	0x06e0c202f,
	0x00020b0af,
	0x000986f00,
	0x001b27066,
	0x0b0af00a0,
	0x0661c262f,
	0x000204483,
	0x06c024283,
	0x0b6af0098,
	0x06f022604,
	0x0202f0020,
	0x0d8806c02,
	0x042844a83,
	0x06f222003,
	0x0d084b085,
	0x0660a1fbc,
	0x0002e2920,
	0x0003c5282,
	0x01fbc0030,
	0x02920003c,
	0x052825383,
	0x04a836ede,
	0x04a846f28,
	0x02003d084,
	0x0b085660a,
	0x01fbc002e,
	0x02920003c,
	0x052822202,
	0x01fb76920,
	0x000642920,
	0x0003c5282,
	0x052865384,
	0x04a846ed8,
	0x07004c0af,
	0x0009c6700,
	0x000e62003,
	0x0d084b085,
	0x0660a1fbc,
	0x0002e2920,
	0x0003c5282,
	0x07065b0af,
	0x000a0672a,
	0x07067b0af,
	0x000a06722,
	0x042372920,
	0x0003c2f2f,
	0x0009c4878,
	0x0fc182f2f,
	0x0009c486f,
	0x000486100,
	0x0f87a7008,
	0x04fef009c,
	0x04e754a97,
	0x06700008e,
	0x01fbc0045,
	0x02920003c,
	0x05282262f,
	0x000206c70,
	0x01fbc002d,
	0x02920003c,
	0x052824483,
	0x07064b083,
	0x06e262003,
	0x04c7c0801,
	0x000000064,
	0x0d0bc0000,
	0x000302202,
	0x01f802920,
	0x0003c5282,
	0x020034c7c,
	0x008010000,
	0x000642601,
	0x020034c7c,
	0x008010000,
	0x0000ad0bc,
	0x000000030,
	0x022021f80,
	0x02920003c,
	0x052822003,
	0x04c7c0801,
	0x00000000a,
	0x02001d0bc,
	0x000000030,
	0x01f802920,
	0x0003c5282,
	0x06000ff5a,
	0x01fbc002b,
	0x02920003c,
	0x052826090,
	0x01fbc0065,
	0x02920003c,
	0x052826000,
	0x0ff727067,
	0x0b0af00a0,
	0x0670a7068,
	0x0b0af00a0,
	0x06600ff1e,
	0x076ffd682,
	0x04a836d0a,
	0x00c370030,
	0x03920003c,
	0x067242803,
	0x04a846d00,
	0x0ff040c37,
	0x0002e4920,
	0x0003c660e,
	0x02403b883,
	0x06700fef2,
	0x052826000,
	0x0feec5384,
	0x060de5383,
	0x060ca76ff,
	0x096af0020,
	0x06c024283,
	0x02a2f0098,
	0x09aaf0020,
	0x070682f40,
	0x000a06000,
	0x0fe367001,
	0x0c0af009c,
	0x06700fe04,
	0x01fbc002b,
	0x02920003c,
	0x052826000,
	0x0fdf6f22f,
	0x05400002c,
	0x0f23c4023,
	0x00000000a,
	0x0f22f7400,
	0x0002cf227,
	0x074006100,
	0x001ac262f,
	0x00020282f,
	0x0001cf202,
	0x06000f202,
	0x04000f22f,
	0x054800034,
	0x0f20000a8,
	0x0f22f7480,
	0x00034598f,
	0x06000fd36,
	0x053af0098,
	0x06000fc48,
	0x070012e80,
	0x07020d1af,
	0x000a06000,
	0x0fb24518f,
	0x0f22f5500,
	0x0000c206f,
	0x00014f200,
	0x0083af28e,
	0x000104290,
	0x0f23c4000,
	0x000000000,
	0x0508f4e75,
	0x0f2177500,
	0x020177214,
	0x0e2a0c0bc,
	0x0000007ff,
	0x090bc0000,
	0x003fe2080,
	0x00297800f,
	0x0ffff0097,
	0x03fe00000,
	0x0f2175400,
	0x0508f4e75,
	0x0518ff22f,
	0x05500000c,
	0x0242f0014,
	0x0f200083a,
	0x0f28e000e,
	0x0f23c4000,
	0x000000000,
	0x0508f4e75,
	0x0f2177500,
	0x020177214,
	0x0e2a0c0bc,
	0x0000007ff,
	0x0d4806e0c,
	0x0f23c4000,
	0x000000000,
	0x0508f4e75,
	0x00c820000,
	0x007ff6d0c,
	0x0f23c4000,
	0x000000000,
	0x0508f4e75,
	0x00297800f,
	0x0ffff2002,
	0x07214e3a0,
	0x08197f217,
	0x05400508f,
	0x04e754fef,
	0x0fff4206f,
	0x00018f22f,
	0x055000010,
	0x0f23c4000,
	0x000000001,
	0x0f2000838,
	0x0f2950018,
	0x0f23c4000,
	0x000000000,
	0x0f2107400,
	0x0f2000800,
	0x04fef000c,
	0x04e75f22f,
	0x075000004,
	0x0242f0004,
	0x07214e2a2,
	0x0c4bc0000,
	0x007ff94bc,
	0x0000003fe,
	0x07015b082,
	0x06d2c203c,
	0x0001fffff,
	0x0e4a04680,
	0x0c1af0004,
	0x042af0008,
	0x0f22f5400,
	0x00004f210,
	0x07400f200,
	0x00800f22f,
	0x054280004,
	0x04fef000c,
	0x04e757035,
	0x0b0826de0,
	0x072ead282,
	0x0203c7fff,
	0x0ffffe2a0,
	0x04680c1af,
	0x0000860cc,
	0x0f22f4012,
	0x000044e75,
	0x041ef0004,
	0x058882f08,
	0x02f2f0008,
	0x0610000fa,
	0x0508f4e75,
	0x0518ff22f,
	0x0543a000c,
	0x0f2930054,
	0x0486f000c,
	0x0f22f5400,
	0x00010f200,
	0x0001af227,
	0x074006100,
	0x0ff2af200,
	0x00100f200,
	0x0003af281,
	0x00016f22f,
	0x054000018,
	0x0f23c4022,
	0x000000001,
	0x0f22f7400,
	0x00018f22f,
	0x054000018,
	0x0f200001a,
	0x0f22f7400,
	0x00018f22f,
	0x054000018,
	0x04fef0014,
	0x04e75486f,
	0x0000cf22f,
	0x054000010,
	0x0f2277400,
	0x06100fedc,
	0x060e0f22f,
	0x054800004,
	0x0f200049a,
	0x0f2277480,
	0x06100ff7e,
	0x0f200001a,
	0x0508f4e75,
	0x0206f0004,
	0x0142f000b,
	0x067121218,
	0x0670ab202,
	0x066f82008,
	0x053804e75,
	0x042804e75,
	0x04a1866fc,
	0x020085380,
	0x04e75246f,
	0x00004226f,
	0x0000814d9,
	0x066fc202f,
	0x000044e75,
	0x0226f0004,
	0x04a19670c,
	0x024494a19,
	0x066fc93ca,
	0x020094e75,
	0x070004e75,
	0x070024e40,
	0x04e757008,
	0x04e404e75,
	0x070044e40,
	0x04e757016,
	0x04e404e75,
	0x070074e40,
	0x04e757009,
	0x04e404e75,
	0x0700d4e40,
	0x04e75700e,
	0x04e404e75,
	0x0700f4e40,
	0x04e757011,
	0x04e404e75,
	0x070144e40,
	0x04e757001,
	0x04e404e75,
	0x0598f226f,
	0x00008206f,
	0x0000c10d1,
	0x030290004,
	0x010803029,
	0x0000448c0,
	0x0e0801140,
	0x000015488,
	0x0101149c0,
	0x07232b001,
	0x06d0005d4,
	0x0724fb001,
	0x06e0005cc,
	0x030360b20,
	0x083724efb,
	0x000002008,
	0x090af000c,
	0x0588f4e75,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x060e03029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054884878,
	0x000744869,
	0x000062f08,
	0x02f48000c,
	0x061000ecc,
	0x0206f000c,
	0x07074d1c0,
	0x04fef000c,
	0x060ac3029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054884878,
	0x000744869,
	0x000062f08,
	0x02f48000c,
	0x061000e98,
	0x0206f000c,
	0x07074d1c0,
	0x04fef000c,
	0x06000ff78,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x06000ff60,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x06000ff48,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x06000ff30,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x06000ff18,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x06000ff00,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x02029000a,
	0x010802029,
	0x0000ae080,
	0x011400001,
	0x054886000,
	0x0fed63029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054882029,
	0x000061080,
	0x020290006,
	0x0e0801140,
	0x000012029,
	0x000067210,
	0x0e2a01140,
	0x000022029,
	0x000067218,
	0x0e2a01140,
	0x000034228,
	0x000044228,
	0x000054228,
	0x000064228,
	0x000075088,
	0x02029000a,
	0x010802029,
	0x0000ae080,
	0x011400001,
	0x054885288,
	0x02f29000a,
	0x02f29000e,
	0x02f082f48,
	0x0000c6100,
	0x00d72206f,
	0x0000c2037,
	0x001620014,
	0x0000ad1c0,
	0x04fef000c,
	0x06000fe4c,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x02029000a,
	0x010802029,
	0x0000ae080,
	0x011400001,
	0x054885288,
	0x02f29000a,
	0x02f29000e,
	0x02f082f48,
	0x0000c6100,
	0x00d22206f,
	0x0000c2037,
	0x001620014,
	0x0000ad1c0,
	0x04fef000c,
	0x06000fdfc,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x020290006,
	0x010802029,
	0x00006e080,
	0x011400001,
	0x020290006,
	0x07210e2a0,
	0x011400002,
	0x020290006,
	0x07218e2a0,
	0x011400003,
	0x042280004,
	0x042280005,
	0x042280006,
	0x042280007,
	0x050882029,
	0x0000a1080,
	0x02029000a,
	0x0e0801140,
	0x000015488,
	0x06000fd98,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x02029000a,
	0x010802029,
	0x0000ae088,
	0x011400001,
	0x02029000a,
	0x07210e2a8,
	0x011400002,
	0x02029000a,
	0x07218e2a8,
	0x011400003,
	0x058882029,
	0x0000e1080,
	0x02029000e,
	0x0e0881140,
	0x000012029,
	0x0000e7210,
	0x0e2a81140,
	0x000022029,
	0x0000e7218,
	0x0e2a81140,
	0x000035888,
	0x06000fd2c,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x04878001c,
	0x04869000a,
	0x02f082f48,
	0x0000c6100,
	0x00c16226f,
	0x00014206f,
	0x0000c701c,
	0x0d1c02029,
	0x000061080,
	0x020290006,
	0x0e0801140,
	0x000012029,
	0x000067210,
	0x0e2a01140,
	0x000022029,
	0x000067218,
	0x0e2a01140,
	0x000035888,
	0x010e90026,
	0x04fef000c,
	0x06000fcc4,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x02029000a,
	0x010802029,
	0x0000ae088,
	0x011400001,
	0x02029000a,
	0x07210e2a8,
	0x011400002,
	0x02029000a,
	0x07218e2a8,
	0x011400003,
	0x058882029,
	0x0000e1080,
	0x02029000e,
	0x0e0881140,
	0x000012029,
	0x0000e7210,
	0x0e2a81140,
	0x000022029,
	0x0000e7218,
	0x0e2a81140,
	0x000035888,
	0x06000fc58,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x010e90026,
	0x06000fc3c,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x02029000a,
	0x010802029,
	0x0000ae088,
	0x011400001,
	0x02029000a,
	0x07210e2a8,
	0x011400002,
	0x02029000a,
	0x07218e2a8,
	0x011400003,
	0x058882029,
	0x0000e1080,
	0x02029000e,
	0x0e0881140,
	0x000012029,
	0x0000e7210,
	0x0e2a81140,
	0x000022029,
	0x0000e7218,
	0x0e2a81140,
	0x000035888,
	0x06000fbd0,
	0x030290002,
	0x010803029,
	0x0000248c0,
	0x0e0801140,
	0x000015488,
	0x04878001c,
	0x04869000a,
	0x02f082f48,
	0x0000c6100,
	0x00aba206f,
	0x0000c701c,
	0x0d1c04fef,
	0x0000c6000,
	0x0fb9a3029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054886000,
	0x0fb823029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054883029,
	0x000061080,
	0x030290006,
	0x048c0e080,
	0x011400001,
	0x054886000,
	0x0fb563029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054882029,
	0x0000a1080,
	0x02029000a,
	0x0e0881140,
	0x000012029,
	0x0000a7210,
	0x0e2a81140,
	0x000022029,
	0x0000a7218,
	0x0e2a81140,
	0x000035888,
	0x02029000e,
	0x010802029,
	0x0000ee088,
	0x011400001,
	0x02029000e,
	0x07210e2a8,
	0x011400002,
	0x02029000e,
	0x07218e2a8,
	0x011400003,
	0x058886000,
	0x0faea3029,
	0x000021080,
	0x030290002,
	0x048c0e080,
	0x011400001,
	0x054884878,
	0x0001c4869,
	0x000062f08,
	0x02f48000c,
	0x0610009d4,
	0x0701cd1af,
	0x0000c4878,
	0x0001c4877,
	0x001620018,
	0x000222f2f,
	0x000146100,
	0x009ba701c,
	0x0d1af0018,
	0x04878001c,
	0x048770162,
	0x00024003e,
	0x02f2f0020,
	0x0610009a0,
	0x0206f0024,
	0x0701cd1c0,
	0x04fef0024,
	0x06000fa80,
	0x06000fa7c,
	0x030290008,
	0x010803029,
	0x0000848c0,
	0x0e0801140,
	0x000015488,
	0x06000fa64,
	0x048780040,
	0x048690006,
	0x02f082f48,
	0x0000c6100,
	0x00962206f,
	0x0000c7040,
	0x0d1c04fef,
	0x0000c6000,
	0x0fa421011,
	0x049c02f00,
	0x0486e83b6,
	0x06100eb7c,
	0x042804fef,
	0x0000c4e75,
	0x06000fa28,
	0x06000fa24,
	0x06000fa20,
	0x06000fa1c,
	0x0598f206f,
	0x0000c4878,
	0x0001c2f2f,
	0x0000c2f08,
	0x02f48000c,
	0x061000914,
	0x0701cd1af,
	0x0000c4878,
	0x0001c4877,
	0x001620018,
	0x0001c2f2f,
	0x000146100,
	0x008fa701c,
	0x0d1af0018,
	0x04878001c,
	0x048770162,
	0x000240038,
	0x02f2f0020,
	0x0610008e0,
	0x0226f002c,
	0x0206f0024,
	0x0701cd1c0,
	0x020290054,
	0x010802029,
	0x00054e088,
	0x011400001,
	0x020290054,
	0x07210e2a8,
	0x011400002,
	0x020290054,
	0x07218e2a8,
	0x011400003,
	0x058882029,
	0x000581080,
	0x020290058,
	0x0e0881140,
	0x000012029,
	0x000587210,
	0x0e2a81140,
	0x000022029,
	0x000587218,
	0x0e2a81140,
	0x000035888,
	0x02029005c,
	0x010802029,
	0x0005ce088,
	0x011400001,
	0x02029005c,
	0x07210e2a8,
	0x011400002,
	0x02029005c,
	0x07218e2a8,
	0x011400003,
	0x058882029,
	0x000601080,
	0x020290060,
	0x0e0801140,
	0x000012029,
	0x000607210,
	0x0e2a01140,
	0x000022029,
	0x000607218,
	0x0e2a01140,
	0x000035888,
	0x020290064,
	0x010802029,
	0x00064e080,
	0x011400001,
	0x020290064,
	0x07210e2a0,
	0x011400002,
	0x020290064,
	0x07218e2a0,
	0x011400003,
	0x058882029,
	0x0006c1080,
	0x02029006c,
	0x0e0801140,
	0x000012029,
	0x0006c7210,
	0x0e2a01140,
	0x000022029,
	0x0006c7218,
	0x0e2a01140,
	0x000034228,
	0x000044228,
	0x000054228,
	0x000064228,
	0x000075088,
	0x030290070,
	0x010803029,
	0x0007048c0,
	0x0e0801140,
	0x000015488,
	0x030290072,
	0x010803029,
	0x0007248c0,
	0x0e0801140,
	0x000015488,
	0x0200890af,
	0x000304fef,
	0x000284e75,
	0x0598f226f,
	0x0000c206f,
	0x000081298,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000045488,
	0x0101149c0,
	0x07232b001,
	0x06d0005ae,
	0x0724fb001,
	0x06e0005a6,
	0x030360b20,
	0x083ae4efb,
	0x00000202f,
	0x00008d0af,
	0x00010b088,
	0x06608202f,
	0x00010588f,
	0x04e754280,
	0x0588f4e75,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x060d04280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054884878,
	0x000742f08,
	0x02f480008,
	0x048690006,
	0x061000700,
	0x0206f000c,
	0x07074d1c0,
	0x04fef000c,
	0x0609c4280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054884878,
	0x000742f08,
	0x02f480008,
	0x048690006,
	0x0610006cc,
	0x0206f000c,
	0x07074d1c0,
	0x04fef000c,
	0x06000ff68,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000ff50,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000ff38,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000ff20,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000ff08,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000fef0,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080812340,
	0x0000a5488,
	0x06000fec4,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x000065088,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080812340,
	0x0000a5488,
	0x052882348,
	0x0000e2029,
	0x0000ad1c0,
	0x06000fe60,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080812340,
	0x0000a5488,
	0x052882348,
	0x0000e2029,
	0x0000ad1c0,
	0x06000fe28,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x000065088,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080812340,
	0x0000a5488,
	0x06000fdd0,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x0000a5888,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x0000e5888,
	0x06000fd60,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x04878001c,
	0x02f082f48,
	0x000084869,
	0x0000a6100,
	0x0048e226f,
	0x00018206f,
	0x0000c701c,
	0x0d1c04280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x023400006,
	0x058881358,
	0x000264fef,
	0x0000c6000,
	0x0fcf64280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340000a,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340000e,
	0x058886000,
	0x0fc864280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054881358,
	0x000266000,
	0x0fc6a4280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340000a,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340000e,
	0x058886000,
	0x0fbfa4280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400002,
	0x054884878,
	0x0001c2f08,
	0x02f480008,
	0x04869000a,
	0x061000328,
	0x0206f000c,
	0x0701cd1c0,
	0x04fef000c,
	0x06000fbc4,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x06000fbac,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000065488,
	0x06000fb80,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x0000a5888,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080814281,
	0x012280002,
	0x07410e5a1,
	0x080814281,
	0x012280003,
	0x07418e5a1,
	0x080812340,
	0x0000e5888,
	0x06000fb10,
	0x042801010,
	0x042811228,
	0x00001e181,
	0x080813340,
	0x000025488,
	0x04878001c,
	0x02f082f48,
	0x000084869,
	0x000066100,
	0x0023e701c,
	0x0d1af000c,
	0x04878001c,
	0x02f2f0010,
	0x048770162,
	0x000200022,
	0x061000224,
	0x0701cd1af,
	0x000184878,
	0x0001c2f2f,
	0x0001c4877,
	0x00162002c,
	0x0003e6100,
	0x0020a206f,
	0x00024701c,
	0x0d1c04fef,
	0x000246000,
	0x0faa66000,
	0x0faa24280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400008,
	0x054886000,
	0x0fa8a4878,
	0x000402f08,
	0x02f480008,
	0x048690006,
	0x0610001cc,
	0x0206f000c,
	0x07040d1c0,
	0x04fef000c,
	0x06000fa68,
	0x0101149c0,
	0x02f00486e,
	0x083c46100,
	0x0e3e64280,
	0x04fef000c,
	0x04e756000,
	0x0fa4e6000,
	0x0fa4a6000,
	0x0fa466000,
	0x0fa42598f,
	0x0206f0008,
	0x04878001c,
	0x02f082f48,
	0x000082f2f,
	0x000146100,
	0x0017e701c,
	0x0d1af000c,
	0x04878001c,
	0x02f2f0010,
	0x048770162,
	0x00020001c,
	0x061000164,
	0x0701cd1af,
	0x000184878,
	0x0001c2f2f,
	0x0001c4877,
	0x00162002c,
	0x000386100,
	0x0014a226f,
	0x00030206f,
	0x00024701c,
	0x0d1c04280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x023400054,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x023400058,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340005c,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x023400060,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x023400064,
	0x058884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x042811228,
	0x000027410,
	0x0e5a18081,
	0x042811228,
	0x000037418,
	0x0e5a18081,
	0x02340006c,
	0x050884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400070,
	0x054884280,
	0x010104281,
	0x012280001,
	0x0e1818081,
	0x033400072,
	0x054882008,
	0x090af002c,
	0x04fef0028,
	0x04e75518f,
	0x0242f0010,
	0x0222f000c,
	0x0206f0014,
	0x0b2826320,
	0x02441d5c8,
	0x02242d3c8,
	0x05388b0fc,
	0x000006d0a,
	0x015215388,
	0x0b0fc0000,
	0x06cf62001,
	0x0508f4e75,
	0x024412242,
	0x05388b0fc,
	0x000006d0a,
	0x014d95388,
	0x0b0fc0000,
	0x06cf62001,
	0x0508f4e75,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000007,
	0x000002cf2,
	0x000002d7e,
	0x000002a1a,
	0x000002dd0,
	0x000002d20,
	0x000002d46,
	0x000002d64,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000001,
	0x000060000,
	0x000000001,
	0x000010000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000030003,
	0x000000000,
	0x000000000,
	0x000000000,
	0x000000000,
	0x002000000,
	0x000000000,
	0x000000004,
	0x002030303,
	0x001000000,
	0x001000002,
	0x000000005,
	0x000010000,
	0x002000000,
	0x000000000,
	0x023632f63,
	0x06f6e7300,
	0x023632f63,
	0x06f6e7300,
	0x023632f63,
	0x06f6e7300,
	0x023652f62,
	0x06f6f746c,
	0x0696e6500,
	0x023652f62,
	0x06f6f7464,
	0x065766963,
	0x065002365,
	0x02f626f6f,
	0x074736572,
	0x076657200,
	0x06e667300,
	0x023632f72,
	0x073323332,
	0x063746c00,
	0x06f70656e,
	0x0696e6720,
	0x023632f72,
	0x073323332,
	0x063746c00,
	0x042393630,
	0x030007075,
	0x073682061,
	0x073796e63,
	0x00023632f,
	0x072733233,
	0x03263746c,
	0x0006f7065,
	0x06e696e67,
	0x02023632f,
	0x072733233,
	0x03263746c,
	0x000423139,
	0x032303000,
	0x070757368,
	0x020617379,
	0x06e630023,
	0x0692f6374,
	0x06c006f70,
	0x0656e696e,
	0x067202369,
	0x02f63746c,
	0x000707573,
	0x06820646b,
	0x06d757800,
	0x0636f6e66,
	0x069672031,
	0x020313620,
	0x06e6f7265,
	0x073746172,
	0x07400236b,
	0x02f322f64,
	0x061746100,
	0x06f70656e,
	0x0696e6720,
	0x0236b2f32,
	0x02f646174,
	0x06100236b,
	0x02f322f63,
	0x0746c006f,
	0x070656e69,
	0x06e672023,
	0x06b2f322f,
	0x063746c00,
	0x0636f6e6e,
	0x065637420,
	0x025730064,
	0x069616c69,
	0x06e670065,
	0x072726f72,
	0x020646961,
	0x06c696e67,
	0x02c207265,
	0x074727969,
	0x06e67202e,
	0x02e2e0a00,
	0x0636f6e6e,
	0x065637465,
	0x06420746f,
	0x02025730a,
	0x0006e6f70,
	0x02e2e2e00,
	0x077726974,
	0x065206e6f,
	0x070007265,
	0x06164206e,
	0x06f70006e,
	0x0203d2025,
	0x0643b2062,
	0x07566203d,
	0x020252e32,
	0x07820252e,
	0x032782025,
	0x02e327820,
	0x0252e3278,
	0x00a00666f,
	0x0726d6174,
	0x0206e6f70,
	0x0006e6f74,
	0x020526e6f,
	0x070007365,
	0x07373696f,
	0x06e2e2e2e,
	0x000777269,
	0x074652073,
	0x065737369,
	0x06f6e0072,
	0x065616420,
	0x073657373,
	0x0696f6e00,
	0x0666f726d,
	0x061742073,
	0x065737369,
	0x06f6e0065,
	0x072726f72,
	0x02025733b,
	0x0006e6f74,
	0x020527365,
	0x07373696f,
	0x06e00706f,
	0x073742e2e,
	0x02e002373,
	0x02f257300,
	0x0626f6f74,
	0x065730063,
	0x072656174,
	0x065002564,
	0x000777269,
	0x074650023,
	0x0732f2573,
	0x000626f6f,
	0x074657300,
	0x023732f62,
	0x06f6f7400,
	0x063726561,
	0x074650025,
	0x064007772,
	0x069746500,
	0x06d6f756e,
	0x0742e2e2e,
	0x0002f002f,
	0x00062696e,
	0x064002f00,
	0x000006d6f,
	0x0756e7400,
	0x073756363,
	0x06573730a,
	0x0002f3638,
	0x03032302f,
	0x0696e6974,
	0x000696e69,
	0x074002d6d,
	0x0002f3638,
	0x03032302f,
	0x0696e6974,
	0x000696e69,
	0x074002f36,
	0x038303230,
	0x02f696e69,
	0x07400626f,
	0x06f743a20,
	0x025733a20,
	0x025730a00,
	0x062616420,
	0x074797065,
	0x03a202564,
	0x00a006261,
	0x064207479,
	0x070653a20,
	0x025640a00,
	0x000000000,
	0x005e405e0,
	0x005dc05d8,
	0x005c205a0,
	0x005880584,
	0x0051a04ae,
	0x00482046a,
	0x0043403c8,
	0x003ac0340,
	0x002d8026c,
	0x0020801b8,
	0x0012e0104,
	0x000ec00d4,
	0x000bc00a4,
	0x0008c0056,
	0x00022000c,
	0x005be05ba,
	0x005b605b2,
	0x0059c057a,
	0x00562055e,
	0x004f40484,
	0x004580440,
	0x0040a039a,
	0x0037e030e,
	0x002a40234,
	0x001dc01a4,
	0x001400114,
	0x000fc00e4,
	0x000cc00b4,
	0x0009c0066,
	0x00032001c,
	0x06e6f6e2d,
	0x07a65726f,
	0x020657869,
	0x074207374,
	0x061747573,
	0x000000000,
	0x00002988,
	0x0,
};

A ss/clock.c => ss/clock.c +42 -0
@@ 0,0 1,42 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

#include	"ureg.h"

void
delay(int ms)
{
	ulong t, *p;
	int i;

	ms *= 1000;	/* experimentally determined */
	for(i=0; i<ms; i++)
		;
}

void
clock(Ureg *ur)
{
	Proc *p;

	SYNCREG[1] = 0x5F;	/* clear interrupt */
	m->ticks++;
	p = m->proc;
	if(p){
		p->pc = ur->pc;
		if (p->state==Running)
			p->time[p->insyscall]++;
	}
	checkalarms();
	kbdclock();
	mouseclock();
	if((ur->sr&SPL(7)) == 0 && p && p->state==Running){
		sched();
		if(u->nnote && (ur->sr&SUPER)==0)
			notify(ur);
	}
}

A ss/crc_16.h => ss/crc_16.h +35 -0
@@ 0,0 1,35 @@
/*
 *	CRC 0120001
 */
    0x0, 0xc0c1, 0xc181, 0x140, 0xc301, 0x3c0, 0x280, 0xc241, 
    0xc601, 0x6c0, 0x780, 0xc741, 0x500, 0xc5c1, 0xc481, 0x440, 
    0xcc01, 0xcc0, 0xd80, 0xcd41, 0xf00, 0xcfc1, 0xce81, 0xe40, 
    0xa00, 0xcac1, 0xcb81, 0xb40, 0xc901, 0x9c0, 0x880, 0xc841, 
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 

A ss/dat.h => ss/dat.h +613 -0
@@ 0,0 1,613 @@
typedef struct Alarm	Alarm;
typedef struct Block	Block;
typedef struct Blist	Blist;
typedef struct Chan	Chan;
typedef struct Conf	Conf;
typedef struct Dev	Dev;
typedef struct Dirtab	Dirtab;
typedef struct Env	Env;
typedef struct Envp	Envp;
typedef struct Envval	Envval;
typedef struct FFrame	FFrame;
typedef struct FPsave	FPsave;
typedef struct KMap	KMap;
typedef struct Label	Label;
typedef struct List	List;
typedef struct Lock	Lock;
typedef struct MMU	MMU;
typedef struct MMUCache	MMUCache;
typedef struct Mach	Mach;
typedef struct Mount	Mount;
typedef struct Mtab	Mtab;
typedef struct Note	Note;
typedef struct Orig	Orig;
typedef struct PTE	PTE;
typedef struct Page	Page;
typedef struct Pgrp	Pgrp;
typedef struct Proc	Proc;
typedef struct Qinfo	Qinfo;
typedef struct QLock	QLock;
typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct Seg	Seg;
typedef struct Service	Service;
typedef struct Stream	Stream;
typedef struct Ureg	Ureg;
typedef struct User	User;

typedef int Devgen(Chan*, Dirtab*, int, int, Dir*);

struct List
{
	void	*next;
};

struct Lock
{
	char	key;			/* addr of sync bus semaphore */
	ulong	pc;
};

struct Ref
{
	Lock;
	int	ref;
};

struct QLock
{
	Proc	*head;			/* next process waiting for object */
	Proc	*tail;			/* last process waiting for object */
	Lock	use;			/* to use object */
	Lock	queue;			/* to access list */
};

struct Label
{
	ulong	sp;
	ulong	pc;
	ushort	sr;
};

struct Alarm
{
	List;
	Lock;
	int	busy;
	long	dt;		/* may underflow in clock(); must be signed */
	void	(*f)(void*);
	void	*arg;
};

#define	CHDIR	0x80000000L
#define	CHAPPEND 0x40000000L
#define	CHEXCL	0x20000000L
struct Chan
{
	QLock;				/* general access */
	Ref;
	union{
		Chan	*next;		/* allocation */
		ulong	offset;		/* in file */
	};
	ushort	type;
	ushort	dev;
	ushort	mode;			/* read/write */
	ushort	flag;
	Qid	qid;
	Mount	*mnt;			/* mount point that derived Chan */
	ulong	mountid;
	int	fid;			/* for devmnt */
	union {
		Stream	*stream;	/* for stream channels */
		void	*aux;
		Qid	pgrpid;		/* for #p/notepg */
	};
	Chan	*mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
};

struct	FPsave
{
	uchar	type;
	uchar	size;
	short	reserved;
	char	junk[212];	/* 68881: sizes 24, 180; 68882: 56, 212 */
	char	reg[3*4+8*12];
};

struct Conf
{
	int	nmach;		/* processors */
	int	nproc;		/* processes */
	int	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages of memory, bank 0 */
	ulong	npage1;		/* total physical pages of memory, bank 1 */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	npage;		/* total physical pages of memory */
	ulong	norig;		/* origins */
	ulong	npte;		/* contiguous page table entries */
	ulong	nmod;		/* single (modifying) page table entries */
	int	nalarm;		/* alarms */
	int	nchan;		/* channels */
	int	nenv;		/* distinct environment values */
	int	nenvchar;	/* environment text storage */
	int	npgenv;		/* environment files per process group */
	int	nmtab;		/* mounted-upon channels per process group */
	int	nmount;		/* mounts */
	int	nmntdev;	/* mounted devices (devmnt.c) */
	int	nmntbuf;	/* buffers for devmnt.c messages */
	int	nmnthdr;	/* headers for devmnt.c messages */
	int	nstream;	/* streams */
	int	nqueue;		/* stream queues */
	int	nblock;		/* stream blocks */
	int	nsrv;		/* public servers (devsrv.c) */
	int	nbitmap;	/* bitmap structs (devbit.c) */
	int	nbitbyte;	/* bytes of bitmap data (devbit.c) */
	int	nfont;		/* font structs (devbit.c) */
	int	nurp;		/* max urp conversations */
	int	nasync;		/* number of async protocol modules */
	int	npipe;		/* number of pipes */
	int	nservice;	/* number of services */
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
};

struct Dev
{
	void	 (*reset)(void);
	void	 (*init)(void);
	Chan	*(*attach)(char*);
	Chan	*(*clone)(Chan*, Chan*);
	int	 (*walk)(Chan*, char*);
	void	 (*stat)(Chan*, char*);
	Chan	*(*open)(Chan*, int);
	void	 (*create)(Chan*, char*, int, ulong);
	void	 (*close)(Chan*);
	long	 (*read)(Chan*, void*, long);
	long	 (*write)(Chan*, void*, long);
	void	 (*remove)(Chan*);
	void	 (*wstat)(Chan*, char*);
};

struct Dirtab
{
	char	name[NAMELEN];
	Qid	qid;
	long	length;
	long	perm;
};

struct Env
{
	Lock;
	Envval	*val;
	char	name[NAMELEN];
	Env	*next;			/* in chain of Envs for a pgrp */
	int	pgref;			/* # pgrps pointing here */
};

struct Envp
{
	Env	*env;
	int	chref;			/* # chans from pgrp pointing here */
};

struct KMap
{
	KMap	*next;
	ulong	pa;
	ulong	va;
};
#define	VA(k)	((k)->va)

struct Mach
{
	int	machno;			/* physical id of processor */
	ulong	splpc;			/* pc of last caller to splhi */
	int	mmask;			/* 1<<m->machno */
	ulong	ticks;			/* of the clock since boot time */
	Proc	*proc;			/* current process on this processor */
	Proc	*lproc;			/* last process on this processor */
	Label	sched;			/* scheduler wakeup */
	Lock	alarmlock;		/* access to alarm list */
	void	*alarm;			/* alarms bound to this clock */
	int	fpstate;		/* state of fp registers on machine */
	void	(*intr)(ulong, ulong);	/* !!Compatability with mips!! */
	ulong	cause;			/*	... */
	ulong	pc;			/*	... */
	int	stack[1];
};

struct Mount
{
	Ref;				/* also used as a lock when playing lists */
	short	term;			/* terminates list */
	ulong	mountid;
	Mount	*next;
	Chan	*c;			/* channel replacing underlying channel */
};

struct Mtab
{
	Chan	*c;			/* channel mounted upon */
	Mount	*mnt;			/* what's mounted upon it */
};

enum{
	NUser,				/* note provided externally */
	NExit,				/* process should exit */
	NDebug,				/* process should hang */
};

struct Note
{
	char	msg[ERRLEN];
	int	flag;			/* whether system posted it */
};

struct Orig
{
	Lock;
	Orig	*next;			/* for allocation */
	ushort	nproc;			/* processes using it */
	ushort	npage;			/* sum of refs of pages in it */
	ushort	flag;
	ulong	va;			/* va of 0th pte */
	ulong	npte;			/* #pte's in list */
	PTE	*pte;
	Chan	*chan;			/* channel deriving segment (if open) */
	ushort	type;			/* of channel (which could be non-open) */
	Qid	qid;
	Chan	*mchan;
	Qid	mqid;
	ulong	minca;			/* base of region in chan */
	ulong	maxca;			/* end of region in chan */
};

struct Page
{
	Orig	*o;			/* origin of segment owning page */
	ulong	va;			/* virtual address */
	ulong	pa;			/* physical address */
	ushort	ref;
	Page	*next;
	Page	*prev;
};

struct Pgrp
{
	Ref;				/* also used as a lock when mounting */
	Pgrp	*next;
	int	index;			/* index in pgrp table */
	ulong	pgrpid;
	char	user[NAMELEN];
	int	nmtab;			/* highest active mount table entry, +1 */
	int	nenv;			/* highest active env table entry, +1 */
	Lock	debug;			/* single access via devproc.c */
	Mtab	*mtab;
	Envp	*etab;
};

struct PTE
{
	Proc	*proc;			/* process owning this PTE (0 in Orig) */
	PTE	*nextmod;		/* next at this va */
	PTE	*nextva;		/* next in this proc at higher va */
	Page	*page;
};

struct Rendez
{
	Lock;
	Proc	*p;
};

struct Seg
{
	Proc	*proc;			/* process owning this segment */
	Orig	*o;			/* root list of pte's */
	ulong	minva;			/* va of 0th pte (not necessarily Seg->o->va) */
	ulong	maxva;			/* va of last pte */
	PTE	*mod;			/* list of modified pte's */
	ulong	pad[3]; /**/
};

struct Proc
{
	Label	sched;
	Mach	*mach;			/* machine running this proc */
	char	text[NAMELEN];
	Proc	*rnext;			/* next process in run queue */
	Proc	*qnext;			/* next process on queue for a QLock */
	QLock	*qlock;			/* address of qlock being queued for DEBUG */
	int	state;
	int	spin;			/* spinning instead of unscheduled */
	Page	*upage;			/* BUG: should be unlinked from page list */
	Seg	seg[NSEG];
	ulong	bssend;			/* initial top of bss seg */
	ulong	pid;
	int	nchild;
	QLock	wait;			/* exiting children to be waited for */
	ulong	waitmsg;
	Proc	*child;
	Proc	*parent;
	Pgrp	*pgrp;
	ulong	parentpid;
	ulong	time[6];		/* User, Sys, Real; child U, S, R */
	short	exiting;
	short	insyscall;
	int	fpstate;
	Lock	debug;			/* to access debugging elements of User */
	Rendez	*r;			/* rendezvous point slept on */
	Rendez	sleep;			/* place for tsleep and syssleep */
	int	wokeup;			/* whether sleep was interrupted */
	ulong	pc;			/* DEBUG only */
	int	kp;			/* true if a kernel process */
	int	pidonmach[1];		/* !!Compatability with mips!! */
};

struct MMU
{
	ulong	va;
	ulong	pa;
};

#define NMMU 16
struct MMUCache
{
	ulong	next;
	MMU	mmu[NMMU];
};

#define	NERR	15
#define	NNOTE	5
#define	NFD	100
struct User
{
	Proc	*p;
	int	nerrlab;
	Label	errlab[NERR];
	char	error[ERRLEN];
	FPsave	fpsave;			/* address of this is known by vdb */
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Chan	*fd[NFD];
	int	maxfd;			/* highest fd in use */
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.
	 */
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	int	(*notify)(void*, char*);
	MMUCache mc;
	void	*ureg;
};

/*
 *  operations available to a queue
 */
struct Qinfo
{
	void (*iput)(Queue*, Block*);	/* input routine */
	void (*oput)(Queue*, Block*);	/* output routine */
	void (*open)(Queue*, Stream*);
	void (*close)(Queue*);
	char *name;
	void (*reset)(void);		/* initialization */
	Qinfo *next;
};

/*
 *  We reference lance buffers via descriptors kept in host memory
 */
struct Block
{
	Block	*next;
	uchar	*rptr;		/* first unconsumed byte */
	uchar	*wptr;		/* first empty byte */
	uchar	*lim;		/* 1 past the end of the buffer */
	uchar	*base;		/* start of the buffer */
	uchar	flags;
	uchar	type;
};

/* flag bits */
#define S_DELIM 0x80
#define S_CLASS 0x07

/* type values */
#define M_DATA 0
#define M_CTL 1
#define M_HANGUP 2

/*
 *  a list of blocks
 */
struct Blist {
	Lock;
	Block	*first;		/* first data block */
	Block	*last;		/* last data block */
	long	len;		/* length of list in bytes */
	int	nb;		/* number of blocks in list */
};

/*
 *  a queue of blocks
 */
struct Queue {
	Blist;
	int	flag;
	Qinfo	*info;		/* line discipline definition */
	Queue	*other;		/* opposite direction, same line discipline */
	Queue	*next;		/* next queue in the stream */
	void	(*put)(Queue*, Block*);
	QLock	rlock;		/* mutex for processes sleeping at r */
	Rendez	r;		/* standard place to wait for flow control */
	Rendez	*rp;		/* where flow control wakeups go to */
	void	*ptr;		/* private info for the queue */
};
#define QHUNGUP	0x1	/* flag bit meaning the stream has been hung up */
#define QINUSE	0x2
#define QHIWAT	0x4	/* queue has gone past the high water mark */	
#define QDEBUG	0x8

/*
 *  a stream head
 */
struct Stream {
	QLock;			/* structure lock */
	short	inuse;		/* number of processes in stream */
	short	opens;		/* number of processes with stream open */
	ushort	hread;		/* number of reads after hangup */
	ushort	type;		/* correlation with Chan */
	ushort	dev;		/* ... */
	ushort	id;		/* ... */
	QLock	rdlock;		/* read lock */
	Queue	*procq;		/* write queue at process end */
	Queue	*devq;		/* read queue at device end */
};
#define	RD(q)		((q)->other < (q) ? (q->other) : q)
#define	WR(q)		((q)->other > (q) ? (q->other) : q)
#define GLOBAL(a)	(((ulong)(a)) & 0x80000000)
#define STREAMTYPE(x)	((x)&0x1f)
#define STREAMID(x)	(((x)&~CHDIR)>>5)
#define STREAMQID(i,t)	(((i)<<5)|(t))
#define PUTNEXT(q,b)	(*(q)->next->put)((q)->next, b)
#define BLEN(b)		((b)->wptr - (b)->rptr)
#define QFULL(q)	((q)->flag & QHIWAT)
#define FLOWCTL(q)	{ if(QFULL(q->next)) flowctl(q); }

/*
 *  stream file qid's & high water mark
 */
enum {
	Shighqid = STREAMQID(1,0) - 1,
	Sdataqid = Shighqid,
	Sctlqid = Sdataqid-1,
	Slowqid = Sctlqid,
	Streamhi= (9*1024),	/* byte count high water mark */
	Streambhi= 32,		/* block count high water mark */
};

#define NSTUB 32
struct Service
{
	Ref;
	Service *next;
	QLock	alock;
	int	die;
	Chan	*inc;
	Chan	*outc;
	char	name[NAMELEN];
};


#define	PRINTSIZE	256

extern register Mach	*m;
extern register User	*u;

/*
 * Process states
 */
enum
{
	Dead = 0,
	Moribund,
	Zombie,
	Ready,
	Scheding,
	Running,
	Queueing,
	MMUing,
	Exiting,
	Inwait,
	Wakeme,
	Broken,
};
extern	char	*statename[];

/*
 * Chan flags
 */
#define	COPEN	1	/* for i/o */
#define	CMOUNT	2	/* is result of a mount/bind */
#define	CCREATE	4	/* permits creation if CMOUNT */
#define	CCEXEC	8	/* close on exec */
#define	CFREE	16	/* not in use */

/*
 * Proc.time
 */
enum
{
	TUser,
	TSys,
	TReal,
	TCUser,
	TCSys,
	TCReal,
};

/*
 * floating point registers
 */
enum
{
	FPinit,
	FPactive,
	FPdirty,
};

/*
 * Memory management
 */
#define	SSEG	0
#define	TSEG	1
#define	DSEG	2
#define	BSEG	3
#define	ESEG	4	/* used by exec to build new stack */

#define	OWRPERM	0x01	/* write permission */
#define	OPURE	0x02	/* original data mustn't be written */
#define	OCACHED	0x04	/* cached; don't discard on exit */

/*
 * Access types in namec
 */
enum
{
	Aaccess,	/* as in access, stat */
	Atodir,		/* as in chdir */
	Aopen,		/* for i/o */
	Amount,		/* to be mounted upon */
	Acreate,	/* file is to be created */
};

#define	NUMSIZE	12		/* size of formatted number */

#define	MACHP(n)	(n==0? &mach0 : *(Mach**)0)

extern	Conf	conf;
extern	ulong	initcode[];
extern	Dev	devtab[];
extern	char	devchar[];
extern	FPsave	initfp;
extern	Mach	mach0;
extern	char	user[NAMELEN];
extern	char	*errstrtab[];

extern  void	(*kprofp)(ulong);

/*
 *  parameters for sysproc.c
 */
#define AOUT_MAGIC	A_MAGIC
#define ENTRYOFFSET	0

A ss/devbit.c => ss/devbit.c +1153 -0
@@ 0,0 1,1153 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"

#include	"devtab.h"

#include	<libg.h>
#include	<gnot.h>

extern GFont	*defont;

/*
 * Device (#b/bitblt) is exclusive use on open, so no locks are necessary
 * for i/o
 */

/*
 * Some fields in GBitmaps are overloaded:
 *	ldepth = -1 means free.
 *	base is next pointer when free.
 * Arena is a word containing N, followed by a pointer to its bitmap,
 * followed by N blocks.  The bitmap pointer is zero if block is free. 
 */

struct
{
	Ref;
	GBitmap	*map;		/* arena */
	GBitmap	*free;		/* free list */
	ulong	*words;		/* storage */
	ulong	nwords;		/* total in arena */
	ulong	*wfree;		/* pointer to next free word */
	GFont	*font;		/* arena; looked up linearly BUG */
	int	lastid;		/* last allocated bitmap id */
	int	lastfid;	/* last allocated font id */
	int	init;		/* freshly opened; init message pending */
	int	rid;		/* read bitmap id */
	int	rminy;		/* read miny */
	int	rmaxy;		/* read maxy */
}bit;

#define	FREE	0x80000000
void	bitcompact(void);
void	bitfree(GBitmap*);
extern	GBitmap	gscreen;

struct{
	/*
	 * First three fields are known in l.s
	 */
	int	dx;		/* interrupt-time delta */
	int	dy;
	int	track;		/* update cursor on screen */
	Mouse;
	int	changed;	/* mouse structure changed since last read */
	int	newbuttons;	/* interrupt time access only */
	Rendez	r;
}mouse;

Cursor	arrow =
{
	{-1, -1},
	{0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00,
	 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0,
	 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE,
	 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08,
	},
	{0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00,
	 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0,
	 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
	 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00,
	}
};

struct{
	Cursor;
	Lock;
	int	visible;	/* on screen */
	Rectangle r;		/* location */
}cursor;

ulong setbits[16];
GBitmap	set =
{
	setbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

ulong clrbits[16];
GBitmap	clr =
{
	clrbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

ulong cursorbackbits[16];
GBitmap cursorback =
{
	cursorbackbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

void	Cursortocursor(Cursor*);
void	cursoron(int);
void	cursoroff(int);
int	mousechanged(void*);

enum{
	Qdir,
	Qbitblt,
	Qmouse,
	Qscreen,
};

Dirtab bitdir[]={
	"bitblt",	{Qbitblt},	0,			0600,
	"mouse",	{Qmouse},	0,			0600,
	"screen",	{Qscreen},	0,			0400,
};

#define	NBIT	(sizeof bitdir/sizeof(Dirtab))
#define	NINFO	257

void
bitreset(void)
{
	int i;
	GBitmap *bp;

	bit.map = ialloc(conf.nbitmap * sizeof(GBitmap), 0);
	for(i=0,bp=bit.map; i<conf.nbitmap; i++,bp++){
		bp->ldepth = -1;
		bp->base = (ulong*)(bp+1);
	}
	bp--;
	bp->base = 0;
	bit.map[0] = gscreen;	/* bitmap 0 is screen */
	bit.free = bit.map+1;
	bit.lastid = -1;
	bit.lastfid = -1;
	bit.words = ialloc(conf.nbitbyte, 0);
	bit.nwords = conf.nbitbyte/sizeof(ulong);
	bit.wfree = bit.words;
	bit.font = ialloc(conf.nfont * sizeof(GFont), 0);
	bit.font[0] = *defont;
	for(i=1; i<conf.nfont; i++)
		bit.font[i].info = ialloc((NINFO+1)*sizeof(Fontchar), 0);
	Cursortocursor(&arrow);
}

void
bitinit(void)
{
	lock(&bit);
	unlock(&bit);
	if(gscreen.ldepth > 1)
		panic("bitinit ldepth>1");
	cursorback.ldepth = gscreen.ldepth;
	cursoron(1);
}

Chan*
bitattach(char *spec)
{
	return devattach('b', spec);
}

Chan*
bitclone(Chan *c, Chan *nc)
{
	nc = devclone(c, nc);
	if(c->qid.path != CHDIR)
		incref(&bit);
}

int
bitwalk(Chan *c, char *name)
{
	return devwalk(c, name, bitdir, NBIT, devgen);
}

void
bitstat(Chan *c, char *db)
{
	devstat(c, db, bitdir, NBIT, devgen);
}

Chan *
bitopen(Chan *c, int omode)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else if(c->qid.path == Qbitblt){
		lock(&bit);
		if(bit.ref){
			unlock(&bit);
			error(Einuse);
		}
		bit.lastid = -1;
		bit.lastfid = -1;
		bit.rid = -1;
		bit.init = 0;
		bit.ref = 1;
		Cursortocursor(&arrow);
		unlock(&bit);
	}else
		incref(&bit);
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void
bitcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
bitremove(Chan *c)
{
	error(Eperm);
}

void
bitwstat(Chan *c, char *db)
{
	error(Eperm);
}

void
bitclose(Chan *c)
{
	int i;
	GBitmap *bp;
	GFont *fp;

	if(c->qid.path!=CHDIR && (c->flag&COPEN)){
		lock(&bit);
		if(--bit.ref == 0){
			for(i=1,bp=&bit.map[1]; i<conf.nbitmap; i++,bp++)
				if(bp->ldepth >= 0)
					bitfree(bp);
			for(i=1,fp=&bit.font[1]; i<conf.nfont; i++,fp++)
				fp->bits = 0;
		}
		unlock(&bit);
	}
}

#define	GSHORT(p)		(((p)[0]<<0) | ((p)[1]<<8))
#define	GLONG(p)		((GSHORT(p)<<0) | (GSHORT(p+2)<<16))
#define	PSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8))
#define	PLONG(p, v)		(PSHORT(p, (v)), PSHORT(p+2, (v)>>16))

/*
 * These macros turn user-level (high bit at left) into internal (whatever)
 * bit order.  On the gnot they're trivial.
 */
#define	U2K(x)	(x)
#define	K2U(x)	(x)

long
bitread(Chan *c, void *va, long n)
{
	uchar *p, *q;
	long miny, maxy, t, x, y;
	ulong l, nw, ws;
	int off, j;
	Fontchar *i;
	GBitmap *src;

	if(c->qid.path & CHDIR)
		return devdirread(c, va, n, bitdir, NBIT, devgen);

	switch(c->qid.path){
	case Qmouse:
		/*
		 * mouse:
		 *	'm'		1
		 *	buttons		1
		 * 	point		8
		 */
		if(n < 10)
			error(Ebadblt);
	    Again:
		while(mouse.changed == 0)
			sleep(&mouse.r, mousechanged, 0);
		lock(&cursor);
		if(mouse.changed == 0){
			unlock(&cursor);
			goto Again;
		}
		p = va;
		p[0] = 'm';
		p[1] = mouse.buttons;
		PLONG(p+2, mouse.xy.x);
		PLONG(p+6, mouse.xy.y);
		mouse.changed = 0;
		unlock(&cursor);
		n = 10;
		break;

	case Qbitblt:
		p = va;
		/*
		 * Fuss about and figure out what to say.
		 */
		if(bit.init){
			/*
			 * init:
			 *	'I'		1
			 *	ldepth		1
			 * 	rectangle	16
			 * if count great enough, also
			 *	font info	3*12
			 *	fontchars	6*(defont->n+1)
			 */
			if(n < 18)
				error(Ebadblt);
			p[0] = 'I';
			p[1] = gscreen.ldepth;
			PLONG(p+2, gscreen.r.min.x);
			PLONG(p+6, gscreen.r.min.y);
			PLONG(p+10, gscreen.r.max.x);
			PLONG(p+14, gscreen.r.max.y);
			if(n >= 18+3*12+6*(defont->n+1)){
				p += 18;
				sprint((char*)p, "%11d %11d %11d ", defont->n,
					defont->height, defont->ascent);
				p += 3*12;
				for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){
					PSHORT(p, i->x);
					p[2] = i->top;
					p[3] = i->bottom;
					p[4] = i->left;
					p[5] = i->width;
				}
				n = 18+3*12+6*(defont->n+1);
			}else
				n = 18;
			bit.init = 0;
			break;
		}
		if(bit.lastid > 0){
			/*
			 * allocate:
			 *	'A'		1
			 *	bitmap id	2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'A';
			PSHORT(p+1, bit.lastid);
			bit.lastid = -1;
			n = 3;
			break;
		}
		if(bit.lastfid > 0){
			/*
			 * allocate font:
			 *	'K'		1
			 *	font id		2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'K';
			PSHORT(p+1, bit.lastfid);
			bit.lastfid = -1;
			n = 3;
			break;
		}
		if(bit.rid >= 0){
			/*
			 * read
			 *	data		bytewidth*(maxy-miny)
			 */
			src = &bit.map[bit.rid];
			if(src->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(bit.rid == 0)
				off = 1;
			miny = bit.rminy;
			maxy = bit.rmaxy;
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
				error(Ebadblt);
			ws = 1<<(3-src->ldepth);	/* pixels per byte */
			/* set l to number of bytes of incoming data per scan line */
			if(src->r.min.x >= 0)
				l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
			else{	/* make positive before divide */
				t = (-src->r.min.x)+ws-1;
				t = (t/ws)*ws;
				l = (t+src->r.max.x+ws-1)/ws;
			}
			if(n < l*(maxy-miny))
				error(Ebadblt);
			if(off)
				cursoroff(1);
			n = 0;
			p = va;
			for(y=miny; y<maxy; y++){
				q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
				q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
				for(x=0; x<l; x++)
					*p++ = K2U(*q++);
				n += l;
			}
			if(off)
				cursoron(1);
			bit.rid = -1;
			break;
		}
		error(Ebadblt);

	case Qscreen:
		if(c->offset==0){
			if(n < 5*12)
				error(Eio);
			sprint(va, "%11d %11d %11d %11d %11d ",
				gscreen.ldepth, gscreen.r.min.x,
				gscreen.r.min.y, gscreen.r.max.x,
				gscreen.r.max.y);
			n = 5*12;
			break;
		}
		ws = 1<<(3-gscreen.ldepth);	/* pixels per byte */
		l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;
		t = c->offset-5*12;
		miny = t/l;
		maxy = (t+n)/l;
		if(miny >= gscreen.r.max.y)
			return 0;
		if(maxy >= gscreen.r.max.y)
			maxy = gscreen.r.max.y;
		n = 0;
		p = va;
		for(y=miny; y<maxy; y++){
			q = (uchar*)gaddr(&gscreen, Pt(0, y));
			for(x=0; x<l; x++)
				*p++ = K2U(*q++);
			n += l;
		}
		break;

	default:
		error(Egreg);
	}

	return n;
}


long
bitwrite(Chan *c, void *va, long n)
{
	uchar *p, *q;
	long m, v, miny, maxy, minx, maxx, t, x, y, tw, th;
	ulong l, nw, ws;
	int off, isoff, i;
	Point pt, pt1, pt2;
	Rectangle rect;
	Cursor curs;
	Fontchar *fcp;
	GBitmap *bp, *src, *dst;
	GFont *f;

	if(c->qid.path == CHDIR)
		error(Eisdir);

	if(c->qid.path != Qbitblt)
		error(Egreg);

	isoff = 0;
	if(waserror()){
		if(isoff)
			cursoron(1);
		nexterror();
	}
	p = va;
	m = n;
	while(m > 0)
		switch(*p){
		default:
			pprint("bitblt request 0x%x\n", *p);
			error(Ebadblt);

		case 'a':
			/*
			 * allocate:
			 *	'a'		1
			 *	ldepth		1
			 *	Rectangle	16
			 * next read returns allocated bitmap id
			 */
			if(m < 18)
				error(Ebadblt);
			v = *(p+1);
			if(v!=0 && v!=1)	/* BUG */
				error(Ebadblt);
			ws = 1<<(5-v);	/* pixels per word */
			if(bit.free == 0)
				error(Enobitmap);
			rect.min.x = GLONG(p+2);
			rect.min.y = GLONG(p+6);
			rect.max.x = GLONG(p+10);
			rect.max.y = GLONG(p+14);
			if(rect.min.x >= 0)
				l = (rect.max.x+ws-1)/ws - rect.min.x/ws;
			else{	/* make positive before divide */
				t = (-rect.min.x)+ws-1;
				t = (t/ws)*ws;
				l = (t+rect.max.x+ws-1)/ws;
			}
			nw = l*Dy(rect);
			if(bit.wfree+2+nw > bit.words+bit.nwords){
				bitcompact();
				if(bit.wfree+2+nw > bit.words+bit.nwords)
					error(Enobitstore);
			}
			bp = bit.free;
			bit.free = (GBitmap*)(bp->base);
			*bit.wfree++ = nw;
			*bit.wfree++ = (ulong)bp;
			bp->base = bit.wfree;
			memset(bp->base, 0, nw*sizeof(ulong));
			bit.wfree += nw;
			bp->zero = l*rect.min.y;
			if(rect.min.x >= 0)
				bp->zero += rect.min.x/ws;
			else
				bp->zero -= (-rect.min.x+ws-1)/ws;
			bp->zero = -bp->zero;
			bp->width = l;
			bp->ldepth = v;
			bp->r = rect;
			bp->cache = 0;
			bit.lastid = bp-bit.map;
			m -= 18;
			p += 18;
			break;

		case 'b':
			/*
			 * bitblt
			 *	'b'		1
			 *	dst id		2
			 *	dst Point	8
			 *	src id		2
			 *	src Rectangle	16
			 *	code		2
			 */
			if(m < 31)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth < 0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt.x = GLONG(p+3);
			pt.y = GLONG(p+7);
			v = GSHORT(p+11);
			src = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || src->ldepth < 0)
				error(Ebadbitmap);
			if(v == 0)
				off = 1;
			rect.min.x = GLONG(p+13);
			rect.min.y = GLONG(p+17);
			rect.max.x = GLONG(p+21);
			rect.max.y = GLONG(p+25);
			v = GSHORT(p+29);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			balubitblt(dst, pt, src, rect, v);
			m -= 31;
			p += 31;
			break;

		case 'c':
			/*
			 * cursorswitch
			 *	'c'		1
			 * nothing more: return to arrow; else
			 * 	Point		8
			 *	clr		32
			 *	set		32
			 */
			if(m == 1){
				if(!isoff){
					cursoroff(1);
					isoff = 1;
				}
				Cursortocursor(&arrow);
				m -= 1;
				p += 1;
				break;
			}
			if(m < 73)
				error(Ebadblt);
			curs.offset.x = GLONG(p+1);
			curs.offset.y = GLONG(p+5);
			memcpy(curs.clr, p+9, 2*16);
			memcpy(curs.set, p+41, 2*16);
			if(!isoff){
				cursoroff(1);
				isoff = 1;
			}
			Cursortocursor(&curs);
			m -= 73;
			p += 73;
			break;

		case 'f':
			/*
			 * free
			 *	'f'		1
			 *	id		2
			 */
			if(m < 3)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			bitfree(dst);
			m -= 3;
			p += 3;
			break;

		case 'g':
			/*
			 * free font (free bitmap separately)
			 *	'g'		1
			 *	id		2
			 */
			if(m < 3)
				error(Ebadblt);
			v = GSHORT(p+1);
			f = &bit.font[v];
			if(v<0 || v>=conf.nfont || f->bits==0)
				error(Ebadfont);
			f->bits = 0;
			m -= 3;
			p += 3;
			break;

		case 'i':
			/*
			 * init
			 *
			 *	'i'		1
			 */
			bit.init = 1;
			m -= 1;
			p += 1;
			break;

		case 'k':
			/*
			 * allocate font
			 *	'k'		1
			 *	n		2
			 *	height		1
			 *	ascent		1
			 *	bitmap id	2
			 *	fontchars	6*(n+1)
			 * next read returns allocated font id
			 */
			if(m < 7)
				error(Ebadblt);
			v = GSHORT(p+1);
			if(v<0 || v>NINFO || m<7+6*(v+1))	/* BUG */
				error(Ebadblt);
			for(i=1; i<conf.nfont; i++)
				if(bit.font[i].bits == 0)
					goto fontfound;
			error(Enofont);
		fontfound:
			f = &bit.font[i];
			f->n = v;
			f->height = p[3];
			f->ascent = p[4];
			v = GSHORT(p+5);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			m -= 7;
			p += 7;
			fcp = f->info;
			for(i=0; i<=f->n; i++,fcp++){
				fcp->x = GSHORT(p);
				fcp->top = p[2];
				fcp->bottom = p[3];
				fcp->left = p[4];
				fcp->width = p[5];
				fcp->top = p[2];
				p += 6;
				m -= 6;
			}
			bit.lastfid = f - bit.font;
			f->bits = dst;
			break;

		case 'l':
			/*
			 * line segment
			 *
			 *	'l'		1
			 *	id		2
			 *	pt1		8
			 *	pt2		8
			 *	value		1
			 *	code		2
			 */
			if(m < 22)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt1.x = GLONG(p+3);
			pt1.y = GLONG(p+7);
			pt2.x = GLONG(p+11);
			pt2.y = GLONG(p+15);
			t = p[19];
			v = GSHORT(p+20);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gsegment(dst, pt1, pt2, t, v);
			m -= 22;
			p += 22;
			break;

		case 'p':
			/*
			 * point
			 *
			 *	'p'		1
			 *	id		2
			 *	pt		8
			 *	value		1
			 *	code		2
			 */
			if(m < 14)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt1.x = GLONG(p+3);
			pt1.y = GLONG(p+7);
			t = p[11];
			v = GSHORT(p+12);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gpoint(dst, pt1, t, v);
			m -= 14;
			p += 14;
			break;

		case 'r':
			/*
			 * read
			 *	'r'		1
			 *	src id		2
			 *	miny		4
			 *	maxy		4
			 */
			if(m < 11)
				error(Ebadblt);
			v = GSHORT(p+1);
			src = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || src->ldepth<0)
				error(Ebadbitmap);
			miny = GLONG(p+3);
			maxy = GLONG(p+7);
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
				error(Ebadblt);
			bit.rid = v;
			bit.rminy = miny;
			bit.rmaxy = maxy;
			p += 11;
			m -= 11;
			break;

		case 's':
			/*
			 * string
			 *	's'		1
			 *	id		2
			 *	pt		8
			 *	font id		2
			 *	code		2
			 * 	string		n (null terminated)
			 */
			if(m < 16)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt.x = GLONG(p+3);
			pt.y = GLONG(p+7);
			v = GSHORT(p+11);
			f = &bit.font[v];
			if(v<0 || v>=conf.nfont || f->bits==0 || f->bits->ldepth<0)
				error(Ebadblt);
			v = GSHORT(p+13);
			p += 15;
			m -= 15;
			q = memchr(p, 0, m);
			if(q == 0)
				error(Ebadblt);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gstring(dst, pt, f, (char*)p, v);
			q++;
			m -= q-p;
			p = q;
			break;

		case 't':
			/*
			 * texture
			 *	't'		1
			 *	dst id		2
			 *	Rectangle	16
			 *	src id		2
			 *	fcode		2
			 */
			if(m < 23)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			rect.min.x = GLONG(p+3);
			rect.min.y = GLONG(p+7);
			rect.max.x = GLONG(p+11);
			rect.max.y = GLONG(p+15);
			v = GSHORT(p+19);
			src = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || src->ldepth<0)
				error(Ebadbitmap);
			v = GSHORT(p+21);
			x = src->r.min.x;
			y = src->r.min.y;
			tw = src->r.max.x - x;
			th = src->r.max.y - y;
			if(x==0 && y==0 && 16%tw == 0 && 16%th == 0){
				GTexture t;

				if(tw==16 && th==16)
					for(y=0; y<16; y++)
						t.bits[y] = src->base[y]>>16;
				else
					for(y=0; y<16; y++){
						l = src->base[y%th] >> (32-tw);
						for(i=16/tw, ws=l; i > 1; i--)
							ws = (ws<<tw) | l;
						t.bits[y] = ws;
					}
				if(off && !isoff){
					cursoroff(1);
					isoff = 1;
				}
				gtexture(dst, rect, &t, v);
			}else{
				GBitmap d;

				d = *dst;
				rect = rcanon(rect);
				if(rectclip(&d.r, rect)==0)
					return;
				/*
				 * Find x, maxx such that
				 * x <= rect.min.x < x+tw,
				 * maxx-tw < rect.max.x <= maxx
				 * and x, maxx are integral multiples of tw
				 * away from src->r.min.x
				 * Similarly for y, maxy
				 */
				if(x > rect.min.x)
					x -= ((x-rect.min.x+tw-1)/tw)*tw;
				else if(x+tw <= rect.min.x)
					x += ((rect.min.x-x)/tw)*tw;
				if(y > rect.min.y)
					y -= ((y-rect.min.y+th-1)/th)*th;
				else if(y+tw <= rect.min.y)
					y += ((rect.min.y-y)/th)*th;
				maxx = x+tw;
				if(maxx < rect.max.x)
					maxx += ((rect.max.x-maxx+tw-1)/tw)*tw;
				maxy = y+th;
				if(maxy < rect.max.y)
					maxy += ((rect.max.y-maxy+th-1)/th)*th;
				minx = x;
				if(off && !isoff){
					cursoroff(1);
					isoff = 1;
				}
				for( ; y<maxy; y+=th)
					for(x=minx; x<maxx; x+=tw)
						gbitblt(&d, Pt(x,y), src, src->r, v);
			}
			m -= 23;
			p += 23;
			break;

		case 'w':
			/*
			 * write
			 *	'w'		1
			 *	dst id		2
			 *	miny		4
			 *	maxy		4
			 *	data		bytewidth*(maxy-miny)
			 */
			if(m < 11)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			miny = GLONG(p+3);
			maxy = GLONG(p+7);
			if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y)
				error(Ebadblt);
			ws = 1<<(3-dst->ldepth);	/* pixels per byte */
			/* set l to number of bytes of incoming data per scan line */
			if(dst->r.min.x >= 0)
				l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws;
			else{	/* make positive before divide */
				t = (-dst->r.min.x)+ws-1;
				t = (t/ws)*ws;
				l = (t+dst->r.max.x+ws-1)/ws;
			}
			p += 11;
			m -= 11;
			if(m < l*(maxy-miny))
				error(Ebadblt);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			for(y=miny; y<maxy; y++){
				q = (uchar*)gaddr(dst, Pt(dst->r.min.x, y));
				q += (dst->r.min.x&((sizeof(ulong))*ws-1))/ws;
				for(x=0; x<l; x++)
					*q++ = U2K(*p++);
				m -= l;
			}
			break;

		case 'x':
			/*
			 * cursorset
			 *
			 *	'x'		1
			 *	pt		8
			 */
			if(m < 9)
				error(Ebadblt);
			pt1.x = GLONG(p+1);
			pt1.y = GLONG(p+5);
			mouse.xy = pt1;
			mouse.track = 1;
			mouseclock();
			m -= 9;
			p += 9;
			break;
		}

	if(isoff)
		cursoron(1);
	return n;
}

void
bitfree(GBitmap *bp)
{
	bp->base[-1] = 0;
	bp->ldepth = -1;
	bp->base = (ulong*)bit.free;
	bit.free = bp;
}

QLock	bitlock;

GBitmap *
id2bit(int k)
{
	GBitmap *bp;
	bp = &bit.map[k];
	if(k<0 || k>=conf.nbitmap || bp->ldepth < 0)
		error(Ebadbitmap);
	return bp;
}

void
bitcompact(void)
{
	ulong *p1, *p2;

	qlock(&bitlock);
	p1 = p2 = bit.words;
	while(p2 < bit.wfree){
		if(p2[1] == 0){
			p2 += 2 + p2[0];
			continue;
		}
		if(p1 != p2){
			memcpy(p1, p2, (2+p2[0])*sizeof(ulong));
			((GBitmap*)p1[1])->base = p1+2;
		}
		p2 += 2 + p1[0];
		p1 += 2 + p1[0];
	}
	bit.wfree = p1;
	qunlock(&bitlock);
}

void
Cursortocursor(Cursor *c)
{
	int i;

	lock(&cursor);
	memcpy(&cursor, c, sizeof(Cursor));
	for(i=0; i<16; i++){
		setbits[i] = (c->set[2*i]<<24) + (c->set[2*i+1]<<16);
		clrbits[i] = (c->clr[2*i]<<24) + (c->clr[2*i+1]<<16);
	}
	unlock(&cursor);
}

void
cursoron(int dolock)
{
	if(dolock)
		lock(&cursor);
	if(cursor.visible++ == 0){
		cursor.r.min = mouse.xy;
		cursor.r.max = add(mouse.xy, Pt(16, 16));
		cursor.r = raddp(cursor.r, cursor.offset);
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
		gbitblt(&gscreen, add(mouse.xy, cursor.offset),
			&clr, Rect(0, 0, 16, 16), D&~S);
		gbitblt(&gscreen, add(mouse.xy, cursor.offset),
			&set, Rect(0, 0, 16, 16), S|D);
	}
	if(dolock)
		unlock(&cursor);
}

void
cursoroff(int dolock)
{
	if(dolock)
		lock(&cursor);
	if(--cursor.visible == 0)
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
	if(dolock)
		unlock(&cursor);
}

void
mousebuttons(int b)	/* called spl5 */
{
	/*
	 * It is possible if you click very fast and get bad luck
	 * you could miss a button click (down up).  Doesn't seem
	 * likely or important enough to worry about.
	 */
	mouse.newbuttons = b;
	mouse.track = 1;		/* aggressive but o.k. */
	mouseclock();
}

void
mouseclock(void)	/* called spl6 */
{
	int x, y;
	if(mouse.track && canlock(&cursor)){
		x = mouse.xy.x + mouse.dx;
		if(x < gscreen.r.min.x)
			x = gscreen.r.min.x;
		if(x >= gscreen.r.max.x)
			x = gscreen.r.max.x;
		y = mouse.xy.y + mouse.dy;
		if(y < gscreen.r.min.y)
			y = gscreen.r.min.y;
		if(y >= gscreen.r.max.y)
			y = gscreen.r.max.y;
		cursoroff(0);
		mouse.xy = Pt(x, y);
		cursoron(0);
		mouse.dx = 0;
		mouse.dy = 0;
		mouse.track = 0;
		mouse.buttons = mouse.newbuttons;
		mouse.changed = 1;
		unlock(&cursor);
		wakeup(&mouse.r);
	}
}

int
mousechanged(void *m)
{
	return mouse.changed;
}

A ss/devcons.c => ss/devcons.c +1021 -0
@@ 0,0 1,1021 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#include	"devtab.h"

typedef struct IOQ	IOQ;

static struct
{
	Lock;
	int	printing;
	int	c;
}printq;

#define	NQ	2048
struct IOQ{
	union{
		Lock;
		QLock;
	};
	uchar	buf[NQ];
	uchar	*in;
	uchar	*out;
	int	state;
	Rendez	r;
};

IOQ	lineq;

struct{
	IOQ;
	Lock	put;
}klogq;

struct{
	IOQ;		/* qlock to getc; interrupt putc's */
	int	c;
	int	repeat;
	int	count;
}kbdq;

Ref	raw;		/* whether kbd i/o is raw (rcons is open) */

/*
 *  rs232 stream module
 */
typedef struct Rs232	Rs232;
typedef struct IOBQ	IOBQ;

#define NBQ 6
struct IOBQ{
	Block	*bp[NBQ];
	int	w;
	int	r;
	int	f;
};
#define NEXT(x) ((x+1)%NBQ)

struct Rs232{
	QLock;
	QLock	outlock;
	IOQ	in;
	IOBQ	out;
	int	kstarted;	/* true if kproc started */
	Queue	*wq;
	Alarm	*a;		/* alarm for waking the rs232 kernel process */
	int	started;
	int	delay;		/* time between character input and waking kproc */
	Rendez	r;
};

Rs232 rs232;

static void	rs232output(Rs232*);
static void	rs232input(Rs232*);
static void	rs232timer(Alarm*);
static void	rs232kproc(void*);
static void	rs232open(Queue*, Stream*);
static void	rs232close(Queue*);
static void	rs232oput(Queue*, Block*);
Qinfo rs232info =
{
	nullput,
	rs232oput,
	rs232open,
	rs232close,
	"rs232"
};

void
printinit(void)
{

	lock(&printq);		/* allocate lock */
	unlock(&printq);

	kbdq.in = kbdq.buf;
	kbdq.out = kbdq.buf;
	klogq.in = klogq.buf;
	klogq.out = klogq.buf;
	lineq.in = lineq.buf;
	lineq.out = lineq.buf;
	rs232.in.in = rs232.in.buf;
	rs232.in.out = rs232.in.buf;
	qlock(&kbdq);		/* allocate qlock */
	qunlock(&kbdq);
	lock(&lineq);		/* allocate lock */
	unlock(&lineq);
	lock(&klogq);		/* allocate lock */
	unlock(&klogq);
	lock(&klogq.put);	/* allocate lock */
	unlock(&klogq.put);

	screeninit();
}

/*
 * Print a string on the console.
 */
void
putstrn(char *str, long n)
{
	int s;

	s = splhi();
	lock(&printq);
	printq.printing = 1;
	while(--n >= 0)
		screenputc(*str++);
	printq.printing = 0;
	unlock(&printq);
	splx(s);
}

int
cangetc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	int n = q->in - q->out;
	if (n < 0)
		n += sizeof(q->buf);
	return n;
}

int
canputc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	return sizeof(q->buf)-cangetc(q)-1;
}

int
isbrkc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	uchar *p;

	for(p=q->out; p!=q->in; ){
		if(raw.ref)
			return 1;
		if(*p==0x04 || *p=='\n')
			return 1;
		p++;
		if(p >= q->buf+sizeof(q->buf))
			p = q->buf;
	}
	return 0;
}

int
getc(IOQ *q)
{
	int c;

	if(q->in == q->out)
		return -1;
	c = *q->out++;
	if(q->out == q->buf+sizeof(q->buf))
		q->out = q->buf;
	return c;
}

int
putc(IOQ *q, int c)
{
	uchar *nextin;
	if(q->in >= &q->buf[sizeof(q->buf)-1])
		nextin = q->buf;
	else
		nextin = q->in+1;
	if(nextin == q->out)
		return -1;
	*q->in = c;
	q->in = nextin;
	return 0;
}

void
putstrk(char *str, long n)
{
	int s;

	s = splhi();
	lock(&klogq.put);
	while(--n >= 0){
		*klogq.in++ = *str++;
		if(klogq.in == klogq.buf+sizeof(klogq.buf))
			klogq.in = klogq.buf;
	}
	unlock(&klogq.put);
	splx(s);
	wakeup(&klogq.r);
}

int
sprint(char *s, char *fmt, ...)
{
	return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
}

int
print(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	putstrn(buf, n);
	return n;
}

int
kprint(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	putstrk(buf, n);
	return n;
}

void
panic(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	strcpy(buf, "panic: ");
	n = doprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	buf[n] = '\n';
	putstrn(buf, n+1);
	exit();
}
int
pprint(char *fmt, ...)
{
	char buf[2*PRINTSIZE];
	Chan *c;
	int n;

	c = u->fd[2];
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	qlock(c);
	if(waserror()){
		qunlock(c);
		return 0;
	}
	(*devtab[c->type].write)(c, buf, n);
	c->offset += n;
	qunlock(c);
	poperror();
	return n;
}

void
prflush(void)
{
	while(printq.printing)
		delay(100);
}

void
echo(int c)
{
	char ch;
	static int ctrlt;

	/*
	 * ^t hack BUG
	 */
	if(ctrlt == 2){
		ctrlt = 0;
		switch(c){
		case 0x14:
			break;	/* pass it on */
		case 'p':
			DEBUG();
			return;
		case 'q':
			dumpqueues();
			return;
		case 'm':
			mntdump();
			return;
		case 'i':
			incontoggle();
			return;
		}
	}else if(c == 0x14){
		ctrlt++;
		return;
	}
	ctrlt = 0;
	if(raw.ref)
		return;
	if(c == 0x15)
		putstrn("^U\n", 3);
	else{
		ch = c;
		putstrn(&ch, 1);
	}
}

/*
 * Put character into read queue at interrupt time.
 * Always called splhi from proc 0.
 */
void
kbdchar(int c)
{
	if(kbdq.repeat == 1){
		kbdq.c = c;
		kbdq.count = 0;
		kbdq.repeat = 2;
	}
	echo(c);
	*kbdq.in++ = c;
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
		kbdq.in = kbdq.buf;
	if(raw.ref || c=='\n' || c==0x04)
		wakeup(&kbdq.r);
}

void
kbdrepeat(int rep)
{
	if(rep)
		kbdq.repeat = 1;
	else
		kbdq.repeat = 0;
}

void
kbdclock(void)
{
	if(kbdq.repeat==2 && (++kbdq.count&1))
		kbdchar(kbdq.c);
}

int
consactive(void)
{
	return printq.printing;
}

/*
 * I/O interface
 */
enum{
	Qdir,
	Qcons,
	Qcputime,
	Qnull,
	Qpgrpid,
	Qpid,
	Qppid,
	Qrcons,
	Qtime,
	Quser,
	Qklog,
	Qmsec,
	Qclock,
	Qrs232ctl = STREAMQID(1, Sctlqid),
	Qrs232 = STREAMQID(1, Sdataqid),
};

Dirtab consdir[]={
	"cons",		{Qcons},	0,		0600,
	"cputime",	{Qcputime},	6*NUMSIZE,	0600,
	"null",		{Qnull},	0,		0600,
	"pgrpid",	{Qpgrpid},	NUMSIZE,	0600,
	"pid",		{Qpid},		NUMSIZE,	0600,
	"ppid",		{Qppid},	NUMSIZE,	0600,
	"rcons",	{Qrcons},	0,		0600,
	"rs232",	{Qrs232},	0,		0600,
	"rs232ctl",	{Qrs232ctl},	0,		0600,
	"time",		{Qtime},	NUMSIZE,	0600,
	"user",		{Quser},	0,		0600,
	"klog",		{Qklog},	0,		0400,
	"msec",		{Qmsec},	NUMSIZE,	0400,
	"clock",	{Qclock},	2*NUMSIZE,	0400,
};

#define	NCONS	(sizeof consdir/sizeof(Dirtab))

static int
consgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
{
	if(tab==0 || i>=ntab)
		return -1;
	tab += i;
	devdir(c, tab->qid, tab->name, tab->length, tab->perm, dp);
	return 1;
}

ulong	boottime;		/* seconds since epoch at boot */

long
seconds(void)
{
	return boottime + TK2SEC(MACHP(0)->ticks);
}

int
readnum(ulong off, char *buf, ulong n, ulong val, int size)
{
	char tmp[64];
	Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG };

	numbconv(&op, 10);
	tmp[size-1] = ' ';
	if(off >= size)
		return 0;
	if(off+n > size)
		n = size-off;
	memcpy(buf, tmp+off, n);
	return n;
}

int
readstr(ulong off, char *buf, ulong n, char *str)
{
	int size;

	size = strlen(str);
	if(off >= size)
		return 0;
	if(off+n > size)
		n = size-off;
	memcpy(buf, str+off, n);
	return n;
}

void
consreset(void)
{
}

void
consinit(void)
{
}

Chan*
consattach(char *spec)
{
	return devattach('c', spec);
}

Chan*
consclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
conswalk(Chan *c, char *name)
{
	return devwalk(c, name, consdir, NCONS, consgen);
}

void
consstat(Chan *c, char *dp)
{
	switch(c->qid.path){
	case Qrs232:
		streamstat(c, dp, "rs232");
		break;
	default:
		devstat(c, dp, consdir, NCONS, consgen);
		break;
	}
}

Chan*
consopen(Chan *c, int omode)
{
	int ch;

	switch(c->qid.path){
	case Quser:
		if(omode==(OWRITE|OTRUNC)){
			/* truncate? */
			if(strcmp(u->p->pgrp->user, "bootes") == 0)	/* BUG */
				u->p->pgrp->user[0] = 0;
			else
				error(Eperm);
		}
		break;
	case Qrcons:
		if(incref(&raw) == 1){
			lock(&lineq);
			while((ch=getc(&kbdq)) != -1){
				*lineq.in++ = ch;
				if(lineq.in == lineq.buf+sizeof(lineq.buf))
					lineq.in = lineq.buf;
			}
			unlock(&lineq);
		}
		break;
	case Qrs232:
	case Qrs232ctl:
		streamopen(c, &rs232info);
		break;
	}
	return devopen(c, omode, consdir, NCONS, consgen);
}

void
conscreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
consclose(Chan *c)
{
	if(c->qid.path==Qrcons && (c->flag&COPEN))
		decref(&raw);
	if(c->stream)
		streamclose(c);
}

long
consread(Chan *c, void *buf, long n)
{
	int ch, i, j, k;
	ulong l;
	uchar *out;
	char *cbuf = buf;
	char *user;
	int userlen;
	char tmp[6*NUMSIZE];

	if(n <= 0)
		return n;
	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, consdir, NCONS, consgen);

	case Qrcons:
	case Qcons:
		qlock(&kbdq);
		if(waserror()){
			qunlock(&kbdq);
			nexterror();
		}
		while(!cangetc(&lineq)){
			sleep(&kbdq.r, isbrkc, &kbdq);
			do{
				lock(&lineq);
				ch = getc(&kbdq);
				if(raw.ref){
					unlock(&lineq);
					goto Default;
				}
				switch(ch){
				case '\b':
					if(lineq.in != lineq.out){
						if(lineq.in == lineq.buf)
							lineq.in = lineq.buf+sizeof(lineq.buf);
						lineq.in--;
					}
					break;
				case 0x15:
					lineq.in = lineq.out;
					break;
				Default:
				default:
					*lineq.in++ = ch;
					if(lineq.in == lineq.buf+sizeof(lineq.buf))
						lineq.in = lineq.buf;
				}
				unlock(&lineq);
			}while(raw.ref==0 && ch!='\n' && ch!=0x04);
		}
		i = 0;
		while(n > 0){
			ch = getc(&lineq);
			if(ch==-1 || (raw.ref==0 && ch==0x04))
				break;
			i++;
			*cbuf++ = ch;
			--n;
		}
		qunlock(&kbdq);
		return i;

	case Qrs232:
		return streamread(c, buf, n);

	case Qrs232ctl:
		if(c->offset)
			return 0;
		*(char *)buf = duartinputport();
		return 1;

	case Qcputime:
		k = c->offset;
		if(k >= sizeof tmp)
			return 0;
		if(k+n > sizeof tmp)
			n = sizeof tmp - k;
		/* easiest to format in a separate buffer and copy out */
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
			l = u->p->time[i];
			if(i == TReal)
				l = MACHP(0)->ticks - l;
			l = TK2MS(l);
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
		}
		memcpy(buf, tmp+k, n);
		return n;

	case Qpgrpid:
		return readnum(c->offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE);

	case Qpid:
		return readnum(c->offset, buf, n, u->p->pid, NUMSIZE);

	case Qppid:
		return readnum(c->offset, buf, n, u->p->parentpid, NUMSIZE);

	case Qtime:
		return readnum(c->offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), NUMSIZE);

	case Qmsec:
		return readnum(c->offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
	case Qclock:
		k = c->offset;
		if(k >= 2*NUMSIZE)
			return 0;
		if(k+n > 2*NUMSIZE)
			n = 2*NUMSIZE - k;
		readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE);
		readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE);
		memcpy(buf, tmp+k, n);
		return n;

	case Quser:
		return readstr(c->offset, buf, n, u->p->pgrp->user);

	case Qnull:
		return 0;

	case Qklog:
		qlock(&klogq);
		if(waserror()){
			qunlock(&klogq);
			nexterror();
		}
		while(!cangetc(&klogq))
			sleep(&klogq.r, cangetc, &klogq);
		for(i=0; i<n; i++){
			if((ch=getc(&klogq)) == -1)
				break;
			*cbuf++ = ch;
		}
		poperror();
		qunlock(&klogq);
		return i;

	default:
		panic("consread %lux\n", c->qid);
		return 0;
	}
}

long
conswrite(Chan *c, void *va, long n)
{
	char cbuf[64];
	char buf[256];
	long l, m;
	char *a = va;

	switch(c->qid.path){
	case Qcons:
	case Qrcons:
		/*
		 * Damn. Can't page fault in putstrn, so copy the data locally.
		 */
		l = n;
		while(l > 0){
			m = l;
			if(m > sizeof buf)
				m = sizeof buf;
			memcpy(buf, a, m);
			putstrn(a, m);
			a += m;
			l -= m;
		}
		break;

	case Qrs232:
	case Qrs232ctl:
		n = streamwrite(c, va, n, 1);
		break;

	case Qtime:
		if(n<=0 || boottime!=0)	/* only one write please */
			return 0;
		if(n >= sizeof cbuf)
			n = sizeof cbuf - 1;
		memcpy(cbuf, a, n);
		cbuf[n-1] = 0;
		boottime = strtoul(a, 0, 0);
		break;

	case Quser:
		if(u->p->pgrp->user[0])		/* trying to overwrite /dev/user */
			error(Eperm);
		if(c->offset >= NAMELEN-1)
			return 0;
		if(c->offset+n >= NAMELEN-1)
			n = NAMELEN-1 - c->offset;
		memcpy(u->p->pgrp->user+c->offset, a, n);
		u->p->pgrp->user[c->offset+n] = 0;
		break;

	case Qcputime:
	case Qpgrpid:
	case Qpid:
	case Qppid:
		error(Eperm);

	case Qnull:
		break;
	default:
		error(Egreg);
	}
	return n;
}

void
consremove(Chan *c)
{
	error(Eperm);
}

void
conswstat(Chan *c, char *dp)
{
	error(Eperm);
}

/*
 *  rs232 stream routines
 *
 *  A kernel process, rs232kproc, stages blocks to be output and
 *  packages input bytes into stream blocks to send upstream.
 *  The process is awakened whenever the interrupt side is almost
 *  out of bytes to xmit or 1/16 second has elapsed since a byte
 *  was input.
 */
static int
rs232empty(void *a)
{
	Rs232 *r;

	r = a;
	return r->out.w == r->out.r;
}

static void
rs232output(Rs232 *r)
{
	int next;
	Queue *q;
	Block *bp;
	long l;

	qlock(&r->outlock);
	q = r->wq;

	/*
	 *  free old blocks
	 */
	for(next = r->out.f; next != r->out.r; next = NEXT(next)){
		freeb(r->out.bp[next]);
		r->out.bp[next] = 0;
	}
	r->out.f = next;

	/*
	 *  stage new blocks
	 *
	 *  if we run into a control block, wait till the queue
	 *  is empty before doing the control.
	 */
	for(next = NEXT(r->out.w); next != r->out.f; next = NEXT(next)){
		bp = getq(q);
		if(bp == 0)
			break;
		if(bp->type == M_CTL){
			while(!rs232empty(r))
				sleep(&r->r, rs232empty, r);
			l = strtoul((char *)(bp->rptr+1), 0, 0);
			switch(*bp->rptr){
			case 'B':
			case 'b':
				duartbaud(l);
				break;
			case 'D':
			case 'd':
				duartdtr(l);
				break;
			case 'K':
			case 'k':
				duartbreak(l);
				break;
			case 'W':
			case 'w':
				if(l>=0 && l<1000)
					r->delay = l;
				break;
			}
			freeb(bp);
			break;
		}
		r->out.bp[r->out.w] = bp;
		r->out.w = next;
	}

	/*
	 *  start output, the spl's sync with interrupt level
	 *  this wouldn't work on a multi-processor
	 */
	splhi();
	if(r->started == 0){
		r->started = 1;
		duartstartrs232o();
	}
	spllo();
	qunlock(&r->outlock);
}

static void
rs232input(Rs232 *r)
{
	Queue *q;
	int c;
	Block *bp;

	q = RD(r->wq);
	bp = 0;
	while((c = getc(&r->in)) >= 0){
		if(bp == 0){
			bp = allocb(64);
			bp->flags |= S_DELIM;
		}
		*bp->wptr++ = c;
		if(bp->wptr == bp->lim){
			if(QFULL(q->next))
				freeb(bp);
			else
				PUTNEXT(q, bp);
			bp = 0;
		}
	}
	if(bp){
		if(QFULL(q->next))
			freeb(bp);
		else
			PUTNEXT(q, bp);
	}
}

static int
rs232stuff(void *arg)
{
	Rs232 *r;

	r = arg;
	return (r->in.in != r->in.out) || (r->out.r != r->out.w)
		|| (r->out.f != r->out.r);
}

static void
rs232kproc(void *a)
{
	Rs232 *r;

	r = a;
	for(;;){
		qlock(r);
		if(r->wq != 0){
			rs232output(r);
			rs232input(r);
		}
		qunlock(r);
		sleep(&r->r, rs232stuff, r);
	}
}

static void
rs232open(Queue *q, Stream *c)
{
	Rs232 *r;

	r = &rs232;

	RD(q)->ptr = r;
	WR(q)->ptr = r;
	r->wq = WR(q);

	if(r->kstarted == 0){
		r->in.in = r->in.out = r->in.buf;
		kproc("rs232", rs232kproc, r);
		r->kstarted = 1;
	}
}

static void
rs232close(Queue *q)
{
	Rs232 *r;

	r = q->ptr;
	qlock(r);
	r->wq = 0;
	qunlock(r);
}

static void
rs232oput(Queue *q, Block *bp)
{
	if(bp->rptr >= bp->wptr)
		freeb(bp);
	else
		putq(q, bp);
	rs232output(q->ptr);
}

static void
rs232timer(Alarm *a)
{
	Rs232 *r;

	r = a->arg;
	cancel(a);
	r->a = 0;
	wakeup(&r->r);
}

/*
 *  called by input interrupt.  runs splhi
 */
void
rs232ichar(int c)
{
	Rs232 *r;

	r = &rs232;
	if(putc(&r->in, c) < 0)
		screenputc('^');

	/*
	 *  pass upstream within 1/16 second
	 */
	if(r->a==0){
		if(r->delay == 0)
			wakeup(&r->r);
		else
			r->a = alarm(r->delay, rs232timer, r);
	}
}

/*
 *  called by output interrupt.  runs splhi
 */
int
getrs232o(void)
{
	uchar c;
	Rs232 *r;
	Block *bp;

	r = &rs232;
	if(r->out.r == r->out.w){
		r->started = 0;
		return -1;
	}
	bp = r->out.bp[r->out.r];
	c = *bp->rptr++;
	if(bp->rptr >= bp->wptr){
		r->out.r = NEXT(r->out.r);
		if(r->out.r==r->out.w || NEXT(r->out.r)==r->out.w)
			wakeup(&r->r);
	}
	return c;
}

A ss/devincon.c => ss/devincon.c +883 -0
@@ 0,0 1,883 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include	"devtab.h"

#include	"io.h"
#include	"ureg.h"

typedef struct Incon	Incon;
typedef struct Device	Device;

#define NOW (MACHP(0)->ticks*MS2HZ)

#define MICROSECOND USED(NOW)

#define DPRINT if(0)

enum {
	Minstation=	2,	/* lowest station # to poll */
	Maxstation=	15,	/* highest station # to poll */
	Nincon=		1,	/* number of incons */
	Nin=		32,	/* Blocks in the input ring */
	Bsize=		128,	/* size of an input ring block */
	Mfifo=		0xff	/* a mask, must be 2^n-1, must be > Nin */
};

/*
 *  incon datakit board
 */
struct Device {
	uchar	cdata;
#define	cpolln	cdata
	uchar	u0;
	uchar	cstatus;
	uchar	u1;
	uchar	creset;
	uchar	u2;
	uchar	csend;
	uchar	u3;
	ushort	data_cntl;	/* data is high byte, cntl is low byte */
	uchar	status;
#define cmd	status
	uchar	u5;
	uchar	reset;
	uchar	u6;
	uchar	send;
	uchar	u7;
};
#define	INCON	((Device *)0x40700000)

struct Incon {
	QLock;

	QLock	xmit;		/* transmit lock */
	QLock	reslock;	/* reset lock */
	Device	*dev;
	int	station;	/* station number */
	int	state;		/* chip state */
	Rendez	r;		/* output process */
	Rendez	kr;		/* input kernel process */
	ushort	chan;		/* current input channel */
	Queue	*rq;		/* read queue */
	int	kstarted;	/* true if kernel process started */

	/*  input blocks */

	Block	*inb[Nin];
	ushort	wi;		
	ushort	ri;

	/* statistics */

	ulong	overflow;	/* overflow errors */
	ulong	pack0;		/* channel 0 */
	ulong	crc;		/* crc errors */
	ulong	in;		/* bytes in */
	ulong	out;		/* bytes out */
};

Incon incon[Nincon];

/*
 *  chip state
 */
enum {
	Selecting,
	Selected,
	Notliving,
};

/*
 *  internal chip registers
 */
#define	sel_polln	0
#define	sel_station	1
#define	sel_poll0	2
#define sel_rcv_cnt	3
#define sel_rcv_tim	4
#define sel_tx_cnt	5

/*
 *  CSR bits
 */
#define INCON_RUN	0x80
#define INCON_STOP	0x00
#define ENABLE_IRQ	0x40
#define ENABLE_TX_IRQ	0x20
#define INCON_ALIVE	0x80
#define TX_FULL		0x10
#define TX_EMPTY	0x08
#define RCV_EMPTY	0x04
#define OVERFLOW	0x02
#define CRC_ERROR	0x01

/*
 *  polling constants
 */
#define HT_GNOT	0x30
#define ST_UNIX 0x04
#define NCHAN 16

static void inconkproc(void*);

/*
 *  incon stream module definition
 */
static void inconoput(Queue*, Block*);
static void inconstopen(Queue*, Stream*);
static void inconstclose(Queue*);
Qinfo inconinfo =
{
	nullput,
	inconoput,
	inconstopen,
	inconstclose,
	"incon"
};

int incondebug;

/*
 *  set the incon parameters
 */
void
inconset(Incon *ip, int cnt, int del)
{
	Device *dev;

	if (cnt<1 || cnt>14 || del<1 || del>15)
		error(Ebadarg);

	dev = ip->dev;
	dev->cmd = sel_rcv_cnt | INCON_RUN;
	MICROSECOND;
	*(uchar *)&dev->data_cntl = cnt;
	MICROSECOND;
	dev->cmd = sel_rcv_tim | INCON_RUN;
	MICROSECOND;
	*(uchar *)&dev->data_cntl = del;
	MICROSECOND;
	dev->cmd = INCON_RUN | ENABLE_IRQ;
}

/*
 *  parse a set request
 */
void
inconsetctl(Incon *ip, Block *bp)
{
	char *field[3];
	int n;
	int del;
	int cnt;

	del = 15;
	n = getfields((char *)bp->rptr, field, 3, ' ');
	switch(n){
	default:
		freeb(bp);
		error(Ebadarg);
	case 2:
		del = strtol(field[1], 0, 0);
		if(del<0 || del>15){
			freeb(bp);
			error(Ebadarg);
		}
		/* fall through */
	case 1:
		cnt = strtol(field[0], 0, 0);
		if(cnt<0 || cnt>15){
			freeb(bp);
			error(Ebadarg);
		}
	}
	inconset(ip, cnt, del);
	freeb(bp);
}

static void
nop(void)
{
}

/*
 *  poll for a station number
 */
void 
inconpoll(Incon *ip, int station)
{
	ulong timer;
	Device *dev;

	dev = ip->dev;

	/*
	 *  get us to a known state
	 */
	ip->state = Notliving;
	dev->cmd = INCON_STOP;

	/*
	 * try a station number
	 */
	dev->cmd = sel_station;
	*(uchar *)&dev->data_cntl = station;
	dev->cmd = sel_poll0;
	*(uchar *)&dev->data_cntl = HT_GNOT;
	dev->cmd = sel_rcv_cnt;
	*(uchar *)&dev->data_cntl = 3;
	dev->cmd = sel_rcv_tim;
	*(uchar *)&dev->data_cntl = 15;
	dev->cmd = sel_tx_cnt;
	*(uchar *)&dev->data_cntl = 1;
	dev->cmd = sel_polln;
	*(uchar *)&dev->data_cntl = 0x00;
	*(uchar *)&dev->data_cntl = ST_UNIX;
	*(uchar *)&dev->data_cntl = NCHAN;
	*(uchar *)&dev->data_cntl = 'g';
	*(uchar *)&dev->data_cntl = 'n';
	*(uchar *)&dev->data_cntl = 'o';
	*(uchar *)&dev->data_cntl = 't';
	dev->cpolln = 0;

	/*
	 *  poll and wait for ready (or 1/4 second)
	 */
	ip->state = Selecting;
	dev->cmd = INCON_RUN | ENABLE_IRQ;
	timer = NOW + 250;
	while (NOW < timer) {
		nop();
		if(dev->status & INCON_ALIVE){
			ip->station = station;
			ip->state = Selected;
			break;
		}
	}
}

/*
 *  reset the chip and find a new staion number
 */
void
inconrestart(Incon *ip)
{
	Device *dev;
	int i;

	if(!canqlock(&ip->reslock))
		return;

	print("inconrestart\n");

	/*
	 *  poll for incon station numbers
	 */
	for(i = Minstation; i <= Maxstation; i++){
		inconpoll(ip, i);
		if(ip->state == Selected)
			break;
	}
	switch(ip->state) {
	case Selecting:
		print("incon[%d] not polled\n", ip-incon);
		break;
	case Selected:
		print("incon[%d] station %d\n", ip-incon, ip->station);
		inconset(ip, 3, 15);
		break;
	default:
		print("incon[%d] bollixed\n", ip-incon);
		break;
	}
	qunlock(&ip->reslock);
}

/*
 *  reset all incon chips.
 */
void
inconreset(void)
{
	int i;
	Incon *ip;

	incon[0].dev = INCON;
	incon[0].state = Selected;
	incon[0].ri = incon[0].wi = 0;
/*	inconset(&incon[0], 3, 15); /**/
	for(i=1; i<Nincon; i++){
		incon[i].dev = INCON+i;
		incon[i].state = Notliving;
		incon[i].dev->cmd = INCON_STOP;
		incon[i].ri = incon[i].wi = 0;
	}
}

void
inconinit(void)
{
}

/*
 *  enable the device for interrupts, spec is the device number
 */
Chan*
inconattach(char *spec)
{
	Incon *ip;
	int i;
	Chan *c;

	i = strtoul(spec, 0, 0);
	if(i >= Nincon)
		error(Ebadarg);
	ip = &incon[i];
	if(ip->state != Selected)
		inconrestart(ip);

	c = devattach('i', spec);
	c->dev = i;
	c->qid.path = CHDIR;
	c->qid.vers = 0;
	return c;
}

Chan*
inconclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int	 
inconwalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, streamgen);
}

void	 
inconstat(Chan *c, char *dp)
{
	devstat(c, dp, 0, 0, streamgen);
}

Chan*
inconopen(Chan *c, int omode)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else
		streamopen(c, &inconinfo);
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void	 
inconcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void	 
inconclose(Chan *c)
{
	if(c->qid.path != CHDIR)
		streamclose(c);
}

long	 
inconread(Chan *c, void *buf, long n)
{
	return streamread(c, buf, n);
}

long	 
inconwrite(Chan *c, void *buf, long n)
{
	return streamwrite(c, buf, n, 0);
}

void	 
inconremove(Chan *c)
{
	error(Eperm);
}

void	 
inconwstat(Chan *c, char *dp)
{
	error(Eperm);
}

/*
 *	the stream routines
 */

/*
 *  create the kernel process for input
 */
static void
inconstopen(Queue *q, Stream *s)
{
	Incon *ip;
	char name[32];

	ip = &incon[s->dev];
	sprint(name, "incon%d", s->dev);
	q->ptr = q->other->ptr = ip;
	ip->rq = q;
	kproc(name, inconkproc, ip);
}

/*
 *  kill off the kernel process
 */
static int
kNotliving(void *arg)
{
	Incon *ip;

	ip = (Incon *)arg;
	return ip->kstarted == 0;
}
static void
inconstclose(Queue * q)
{
	Incon *ip;

	ip = (Incon *)q->ptr;
	qlock(ip);
	ip->rq = 0;
	qunlock(ip);
	wakeup(&ip->kr);
	sleep(&ip->r, kNotliving, ip);
}

/*
 *  free all blocks of a message in `q', `bp' is the first block
 *  of the message
 */
static void
freemsg(Queue *q, Block *bp)
{
	for(; bp; bp = getq(q)){
		if(bp->flags & S_DELIM){
			freeb(bp);
			return;
		}
		freeb(bp);
	}
}

/*
 *  output a block
 *
 *  the first 2 bytes of every message are the channel number,
 *  low order byte first.  the third is a possible trailing control
 *  character.
 */
void
inconoput(Queue *q, Block *bp)
{
	Device *dev;
	Incon *ip;
	ulong end;
	int chan;
	int ctl;
	int n, size;

	ip = (Incon *)q->ptr;

	if(bp->type != M_DATA){
		if(streamparse("inconset", bp))
			inconsetctl(ip, bp);
		else
			freeb(bp);
		return;
	}

	/*
	 *  get a whole message before handing bytes to the device
	 */
	if(!putq(q, bp))
		return;

	/*
	 *  one transmitter at a time
	 */
	qlock(&ip->xmit);
	dev = ip->dev;

	/*
	 *  parse message
	 */
	bp = getq(q);
	if(bp->wptr - bp->rptr < 3){
		freemsg(q, bp);
		qunlock(&ip->xmit);
		return;
	}
	chan = bp->rptr[0] | (bp->rptr[1]<<8);
	ctl = bp->rptr[2];
	bp->rptr += 3;
	if(chan<=0)
		print("bad channel %d\n", chan);

	if(incondebug)
		print("->(%d)%uo %d\n", chan, ctl, bp->wptr - bp->rptr);

	/*
	 *  make sure there's an incon out there
	 */
	if(!(dev->status&INCON_ALIVE) || ip->state==Notliving){
		inconrestart(ip);
		freemsg(q, bp);
		qunlock(&ip->xmit);
		return;
	}

	/*
	 *  send the 8 bit data
	 */
	for(;;){
		/*
		 *  spin till there is room
		 */
		for(end = NOW+1000; dev->status & TX_FULL;){
			nop();	/* make sure we don't optimize too much */
			if(NOW > end){
				print("incon output stuck\n");
				freemsg(q, bp);
				qunlock(&ip->xmit);
				return;
			}
		}

		/*
		 *  put in next packet
		 */
		n = bp->wptr - bp->rptr;
		if(n > 16)
			n = 16;
		size = n;
		dev->cdata = chan;
		while(n--){
			*(uchar *)&dev->data_cntl = *bp->rptr++;
		}

		/*
		 *  get next block 
		 */
		if(bp->rptr >= bp->wptr){
			if(bp->flags & S_DELIM){
				freeb(bp);
				break;
			}
			freeb(bp);
			bp = getq(q);
			if(bp==0)
				break;
		}

		/*
		 *  end packet
		 */
		dev->cdata = 0;
	}

	/*
	 *  send the control byte if there is one
	 */
	if(ctl){
		if(size >= 16){
			dev->cdata = 0;
			MICROSECOND;
			for(end = NOW+1000; dev->status & TX_FULL;){
				nop();	/* make sure we don't optimize too much */
				if(NOW > end){
					print("incon output stuck\n");
					freemsg(q, bp);
					qunlock(&ip->xmit);
					return;
				}
			}
			dev->cdata = chan;
			MICROSECOND;
		}
		if(dev->status & TX_FULL)
			print("inconfull\n");
		dev->cdata = ctl;
	}
	MICROSECOND;
	dev->cdata = 0;

	qunlock(&ip->xmit);
	return;
}

/*
 *  return true if the raw fifo is non-empty
 */
static int
notempty(void *arg)
{
	Incon *ip;

	ip = (Incon *)arg;
	return ip->ri!=ip->wi;
}

/*
 *  Read bytes from the raw input circular buffer.
 */
static void
inconkproc(void *arg)
{
	Incon *ip;
	Block *bp, *nbp;
	int i;
	int locked;

	ip = (Incon *)arg;
	ip->kstarted = 1;

	/*
	 *  create a number of blocks for input
	 */
	for(i = 0; i < Nin; i++){
		bp = ip->inb[i] = allocb(Bsize);
		bp->wptr += 3;
	}

	locked = 0;
	if(waserror()){
		if(locked)
			qunlock(ip);
		ip->kstarted = 0;
		wakeup(&ip->r);
		return;
	}

	for(;;){
		/*
		 *  sleep if input fifo empty
		 */
		sleep(&ip->kr, notempty, ip);

		/*
		 *  die if the device is closed
		 */
		USED(locked);
		qlock(ip);
		locked = 1;
		if(ip->rq == 0){
			qunlock(ip);
			ip->kstarted = 0;
			wakeup(&ip->r);
			poperror();
			return;
		}

		/*
		 *  send blocks upstream and stage new blocks.  if the block is small
		 *  (< 64 bytes) copy into a smaller buffer.
		 */
		while(ip->ri != ip->wi){
			bp = ip->inb[ip->ri];
			PUTNEXT(ip->rq, bp);
			bp = ip->inb[ip->ri] = allocb(Bsize);
			bp->wptr += 3;
			ip->ri = (ip->ri+1)%Nin;
		}
		USED(locked);
		qunlock(ip);
		locked = 0;
	}
}

/*
 *  drop a single packet
 */
static void
droppacket(Device *dev)
{
	int i;
	int c;

	for(i = 0; i < 17; i++){
		c = dev->data_cntl;
		if(c==0)
			break;
	}
}

/*
 *  flush the input fifo
 */
static void
flushfifo(Device *dev)
{
	while(!(dev->status & RCV_EMPTY))
		droppacket(dev);
}

/*
 *  advance the queue. if we've run out of staged input blocks,
 *  drop the packet and return 0.  otherwise return the next input
 *  block to fill.
 */
static Block *
nextin(Incon *ip, unsigned int c)
{
	Block *bp;
	int next;

	bp = ip->inb[ip->wi];
	bp->base[0] = ip->chan;
	bp->base[1] = ip->chan>>8;
	bp->base[2] = c;
	if(incondebug)
		print("<-(%d)%uo %d\n", ip->chan, c, bp->wptr-bp->rptr);

	next = (ip->wi+1)%Nin;
	if(next == ip->ri){
		bp->wptr = bp->base+3;
		return bp;
	}
	ip->wi = next;

	return ip->inb[ip->wi];
}

/*
 *  read the packets from the device into the staged input blocks.
 *  we have to do this at interrupt tevel to turn off the interrupts.
 */
static void
rdpackets(Incon *ip)
{
	Block *bp;
	unsigned int c;
	Device *dev;
	uchar *p;
	int first = ip->wi;

	dev = ip->dev;
	bp = ip->inb[ip->wi];
	if(bp==0){
		flushfifo(ip->dev);
		return;
	}
	p = bp->wptr;
	while(!(dev->status & RCV_EMPTY)){
		/*
		 *  get channel number
		 */
		c = (dev->data_cntl)>>8;
		if(c == 0){
			droppacket(dev);
			continue;
		}
		if(ip->chan != c){
			if(p - bp->rptr > 3){
				bp->wptr = p;
				bp = nextin(ip, 0);
				p = bp->wptr;
			}
			ip->chan = c;
		}

		/*
		 *  null byte marks end of packet
		 */
		for(;;){
			if((c=dev->data_cntl)&1) {
				/*
				 *  data byte, put in local buffer
				 */
				*p++ = c>>8;
			} else if (c>>=8) {
				/*
				 *  control byte ends block
				 */
				bp->wptr = p;
				bp = nextin(ip, c);
				p = bp->wptr;
			} else {
				/* end of packet */
				break;
			}
		}

		/*
		 *  pass a block on if it doesn't have room for one more
		 *  packet.  this way we don't have to check per byte.
		 */
		if(p + 16 > bp->lim){
			bp->wptr = p;
			bp = nextin(ip, 0);
			p = bp->wptr;
		}
	}	
	bp->wptr = p;
	if(bp->wptr != bp->base+3)
		nextin(ip, 0);

	if(first != ip->wi)/**/
		wakeup(&ip->kr);
}

/*
 *  Receive an incon interrupt.  One entry point
 *  for all types of interrupt.  Until we figure out
 *  how to use more than one incon, this routine only
 *  is for incon[0].
 */
inconintr(Ureg *ur)
{
	uchar status;
	Incon *ip;

	ip = &incon[0];

	status = ip->dev->status;
	if(!(status & RCV_EMPTY))
		rdpackets(ip);

	/* check for exceptional conditions */
	if(status&(OVERFLOW|CRC_ERROR)){
		if(status&OVERFLOW)
			ip->overflow++;
		if(status&CRC_ERROR)
			ip->crc++;
	}

	/* see if it died underneath us */
	if(!(status&INCON_ALIVE)){
		switch(ip->state){
		case Selected:
			ip->dev->cmd = INCON_STOP;
			print("Incon died\n");
			break;
		case Selecting:
			print("rejected\n");
			break;
		default:
			ip->dev->cmd = INCON_STOP;
			break;
		}
		ip->state = Notliving;
	}
}

incontoggle()
{
	incondebug ^= 1;
}

A ss/devkprof.c => ss/devkprof.c +177 -0
@@ 0,0 1,177 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"

#include	"devtab.h"

#define	MAXPC	(100*1024L)
#define	RES	8
#define	LRES	3
#define	NBUF	(MAXPC>>LRES)

long		timerbuf[NBUF];

enum{
	Kprofdirqid,
	Kprofdataqid,
	Kprofstartqid,
	Kprofstartclrqid,
	Kprofstopqid,
	Nkproftab=Kprofstopqid,
	Kprofmaxqid,
};
Dirtab kproftab[Nkproftab]={
	"kpdata",	Kprofdataqid,		NBUF*sizeof timerbuf[0],	0600,
	"kpstart",	Kprofstartqid,		0,		0600,
	"kpstartclr",	Kprofstartclrqid,	0,		0600,
	"kpstop",	Kprofstopqid,		0,		0600,
};

void kproftimer(ulong);

void
kprofreset(void)
{
	kprofp = kproftimer;
}

void
kprofinit(void)
{
	extern void *etext;
	if((((unsigned long)&etext)-KTZERO)>MAXPC)
		print("kernel profiling limited to %lud\n", MAXPC);
}

Chan *
kprofattach(char *spec)
{
	return devattach('t', spec);
}
Chan *
kprofclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
kprofwalk(Chan *c, char *name)
{
	return devwalk(c, name, kproftab, (long)Nkproftab, devgen);
}

void
kprofstat(Chan *c, char *db)
{
	devstat(c, db, kproftab, (long)Nkproftab, devgen);
}

Chan *
kprofopen(Chan *c, int omode)
{
	if(c->qid == CHDIR){
		if(omode != OREAD)
			error(0, Eperm);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void
kprofcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(0, Eperm);
}

void
kprofremove(Chan *c)
{
	error(0, Eperm);
}

void
kprofwstat(Chan *c, char *dp)
{
	error(0, Eperm);
}

void
kprofclose(Chan *c)
{
}

void
kprofuserstr(Error *e, char *buf)
{
	consuserstr(e, buf);
}

void	 
kproferrstr(Error *e, char *buf)
{
	rooterrstr(e, buf);
}

long
kprofread(Chan *c, void *a, long n)
{
	switch((int)(c->qid&~CHDIR)){
	case Kprofdirqid:
		return devdirread(c, a, n, kproftab, Nkproftab, devgen);
	case Kprofdataqid:
		if(c->offset >= NBUF*sizeof timerbuf[0]){
			n = 0;
			break;
		}
		if(c->offset+n > NBUF*sizeof timerbuf[0])
			n = NBUF*sizeof timerbuf[0]-c->offset;
		memcpy(a, ((char *)timerbuf)+c->offset, n);
		break;
	default:
		n=0;
		break;
	}
	return n;
}

long
kprofwrite(Chan *c, char *a, long n)
{
	switch((int)(c->qid&~CHDIR)){
	case Kprofstartclrqid:
		memset((char *)timerbuf, 0, NBUF*sizeof timerbuf[0]);
	case Kprofstartqid:
		duartstarttimer();
		break;
	case Kprofstopqid:
		duartstoptimer();
		break;
	default:
		error(0, Ebadusefd);
	}
	return n;
}

void
kproftimer(ulong pc)
{
	/*
	 *  if the pc is coming out of slplo pr splx, then use
	 *  the pc saved when we went splhi.
	 */
	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
		pc = m->splpc;

	timerbuf[0]++;
	if(KTZERO<=pc && pc<KTZERO+MAXPC){
		pc -= KTZERO;
		pc >>= LRES;
		timerbuf[pc]++;
	} else
		timerbuf[1]++;
}

A ss/errno.h => ss/errno.h +63 -0
@@ 0,0 1,63 @@
enum{
	Enevermind,	/* never mind */
	Enofd,		/* no free file descriptors */
	Ebadfd,		/* fd out of range or not open */
	Ebadusefd,	/* inappropriate use of fd */
	Ebadarg,	/* bad arg in system call */
	Enonexist,	/* file does not exist */
	Efilename,	/* file name syntax */
	Ebadchar,	/* bad character in file name */
	Ebadsharp,	/* unknown device in # filename */
	Ebadexec,	/* a.out header invalid */
	Eioload,	/* i/o error in demand load */
	Eperm,		/* permission denied */
	Enotdir,	/* not a directory */
	Enochild,	/* no living children */
	Enoseg,		/* no free segments */
	Ebadmount,	/* inconsistent mount */
	Enomount,	/* mount table full */
	Enomntdev,	/* no free mount devices */
	Eshutdown,	/* mounted device shut down */
	Einuse,		/* device or object already in use */
	Eio,		/* i/o error */
	Eisdir,		/* file is a directory */
	Ebaddirread,	/* directory read not quantized */
	Esegaddr,	/* illegal segment addresses or size */
	Enoenv,		/* no free environment resources */
	Eprocdied,	/* process exited */
	Enocreate,	/* mounted directory forbids creation */
	Enotunion,	/* attempt to union with non-mounted directory */
	Emount,		/* inconsistent mount */
	Enosrv,		/* no free server slots */
	Enoqueue,	/* no free stream queues */
	Ebadld,		/* illegal line discipline */
	Enostream,	/* no free stream heads */
	Etoobig,	/* read or write too large */
	Etoosmall,	/* read or write too small */
	Ehungup,	/* write to hungup stream */
	Ebadnet,	/* illegal network address */
	Enoifc,		/* bad interface or no free interface slots */
	Enodev,		/* no free devices */
	Ebadctl,	/* bad process or stream control request */
	Enonote,	/* note overflow */
	Eintr,		/* interrupted */
	Edestbusy,	/* datakit destination busy */
	Enetbusy,	/* datakit controller busy */
	Edestotl,	/* datakit destination out to lunch */
	Enetotl,	/* datakit controller out to lunch */
	Erejected,	/* datakit destination rejected call */
	Ebadblt,	/* bad bitblt or bitmap request */
	Enobitmap,	/* out of bitmap descriptors */
	Enobitstore,	/* out of bitmap storage */
	Ebadbitmap,	/* unallocated bitmap */
	Ebadfont,	/* unallocated font */
	Eshortmsg,	/* short message */
	Ebadmsg,	/* format error or mismatch in message */
	Ebadcnt,	/* read count greater than requested */
	Enofont,	/* out of font descriptors */
	Enovmem,	/* virtual memory allocation failed */
	Enoasync,	/* out of async stream modules */
	Enopipe,	/* out of pipes */
	Enofilsys,	/* out of filsys resources */
	Egreg,		/* ken has implemented datakit */
};

A ss/faultsparc.c => ss/faultsparc.c +98 -0
@@ 0,0 1,98 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

#define	FORMAT(ur)	((((ur)->vo)>>12)&0xF)
#define	OFFSET(ur)	(((ur)->vo)&0xFFF)


struct FFrame
{
	ushort	ireg0;			/* internal register */
	ushort	ssw;			/* special status word */
	ushort	ipsc;			/* instr. pipe stage c */
	ushort	ipsb;			/* instr. pipe stage b */
	ulong	addr;			/* data cycle fault address */
	ushort	ireg1;			/* internal register */
	ushort	ireg2;			/* internal register */
	ulong	dob;			/* data output buffer */
	ushort	ireg3[4];		/* more stuff */
	ulong	baddr;			/* stage b address */
	ushort	ireg4[26];		/* more more stuff */
};

/*
 * SSW bits
 */
#define	RW	0x0040		/* read/write for data cycle */
#define	FC	0x8000		/* fault on stage C of instruction pipe */
#define	FB	0x4000		/* fault on stage B of instruction pipe */
#define	RC	0x2000		/* rerun flag for stage C of instruction pipe */
#define	RB	0x1000		/* rerun flag for stage B of instruction pipe */
#define	DF	0x0100		/* fault/rerun flag for data cycle */
#define	RM	0x0080		/* read-modify-write on data cycle */
#define	READ	0x0040
#define	WRITE	0x0000
#define	SIZ	0x0030		/* size code for data cycle */
#define	FC2	0x0004		/* address space for data cycle */
#define	FC1	0x0002
#define	FC0	0x0001

void
fault68020(Ureg *ur, FFrame *f)
{
	ulong addr, badvaddr;
	int user, read, insyscall;

	if(u == 0){
		dumpregs(ur);
		panic("fault u==0 pc=%lux", ur->pc);
	}
	insyscall = u->p->insyscall;
	u->p->insyscall = 1;
	addr = 0;	/* set */
	if(f->ssw & DF)
		addr = f->addr;
	else if(FORMAT(ur) == 0xA){
		if(f->ssw & FC)
			addr = ur->pc+2;
		else if(f->ssw & FB)
			addr = ur->pc+4;
		else
			panic("prefetch pagefault");
	}else if(FORMAT(ur) == 0xB){
		if(f->ssw & FC)
			addr = f->baddr-2;
		else if(f->ssw & FB)
			addr = f->baddr;
		else
			panic("prefetch pagefault");
	}else
		panic("prefetch format");
	addr &= VAMASK;
	badvaddr = addr;
	addr &= ~(BY2PG-1);
	user = !(ur->sr&SUPER);
	if(f->ssw & DF)
		read = (f->ssw&READ) && !(f->ssw&RM);
	else
		read = f->ssw&(FB|FC);
/* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/

	if(fault(addr, read) < 0){
		if(user){
			pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
			pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp);
			pexit("Suicide", 0);
		}
		u->p->state = MMUing;
		dumpregs(ur);
		panic("fault: 0x%lux", badvaddr);
		exit();
	}
	u->p->insyscall = insyscall;
}

A ss/fcall.h => ss/fcall.h +88 -0
@@ 0,0 1,88 @@
typedef	struct	Fcall	Fcall;

struct	Fcall
{
	char	type;
	short	fid;
	short	tag;
	union
	{
		struct
		{
			short	newfid;		/* T-Clone */
			short	oldtag;		/* T-Flush */
			Qid	qid;		/* R-Attach, R-Walk, R-Open, R-Create */
		};
		struct
		{
			char	uname[NAMELEN];	/* T-Attach */
			char	aname[NAMELEN];	/* T-Attach */
			char	auth[NAMELEN];	/* T-Attach */
		};
		struct
		{
			char	ename[ERRLEN];	/* R-Error */
		};
		struct
		{
			long	perm;		/* T-Create */ 
			char	name[NAMELEN];	/* T-Walk, T-Create */
			char	mode;		/* T-Create, T-Open */
		};
		struct
		{
			long	offset;		/* T-Read, T-Write */
			long	count;		/* T-Read, T-Write, R-Read */
			char	*data;		/* T-Write, R-Read */
		};
		struct
		{
			char	stat[DIRLEN];	/* T-Wstat, R-Stat */
		};
	};
};

#define	MAXFDATA	8192

enum
{
	Tnop =		50,
	Rnop,
	Tsession =	52,
	Rsession,
/*	Terror =	54,	illegal */
	Rerror =	55,
	Tflush =	56,
	Rflush,
	Tattach =	58,
	Rattach,
	Tclone =	60,
	Rclone,
	Twalk =		62,
	Rwalk,
	Topen =		64,
	Ropen,
	Tcreate =	66,
	Rcreate,
	Tread =		68,
	Rread,
	Twrite =	70,
	Rwrite,
	Tclunk =	72,
	Rclunk,
	Tremove =	74,
	Rremove,
	Tstat =		76,
	Rstat,
	Twstat =	78,
	Rwstat,
};

int	convM2S(char*, Fcall*, int);
int	convS2M(Fcall*, char*);

int	convM2D(char*, Dir*);
int	convD2M(Dir*, char*);

int	fcallconv(void *, int, int, int, int);
int	dirconv(void *, int, int, int, int);

A ss/fns.h => ss/fns.h +204 -0
@@ 0,0 1,204 @@
Alarm	*alarm(int, void (*)(Alarm*), void*);
void	alarminit(void);
Block	*allocb(ulong);
void	append(List**, List*);
void	cancel(Alarm*);
int	canlock(Lock*);
int	canqlock(QLock*);
void	chaninit(void);
void	chandevreset(void);
void	chandevinit(void);
void	checkalarms(void);
void	clearmmucache(void);
void	clock(Ureg*);
Chan	*clone(Chan*, Chan*);
void	close(Chan*);
void	closemount(Mount*);
void	closepgrp(Pgrp*);
long	clrfpintr(void);
int	compactpte(Orig*, ulong);
void	confinit(void);
Env	*copyenv(Env*, int);
Chan	*createdir(Chan*);
int	decref(Ref*);
void	delay(int);
void	delete(List**, List*, List*);
void	delete0(List**, List*);
Chan	*devattach(int, char*);
Chan	*devclone(Chan*, Chan*);
void	devdir(Chan*, Qid, char*, long, long, Dir*);
long	devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
Devgen	devgen;
int	devno(int, int);
Chan	*devopen(Chan*, int, Dirtab*, int, Devgen*);
void	devstat(Chan*, char*, Dirtab*, int, Devgen*);
int	devwalk(Chan*, char*, Dirtab*, int, Devgen*);
Chan	*domount(Chan*);
void	duartbaud(int);
void	duartbreak(int);
void	duartdtr(int);
int	duartinputport(void);
void	duartstartrs232o(void);
void	duartstarttimer(void);
void	duartstoptimer(void);
void	dumpregs(Ureg*);
void	dumpstack(void);
int	eqchan(Chan*, Chan*, long);
int	eqqid(Qid, Qid);
void	envpgclose(Env *);
void	error(int);
void	errors(char*);
void	exit(void);
int	fault(ulong, int);
void	fault68020(Ureg*, FFrame*);
void	fdclose(int);
Chan	*fdtochan(int, int);
void	filsys(Chan*, char*, long);
void	filsysinit(void);
void	firmware(void);
void	flowctl(Queue*);
void	flushcpucache(void);
void	flushmmu(void);
void	forkmod(Seg*, Seg*, Proc*);
int	fpcr(int);
void	fpsave(FPsave*);
void	fpregsave(char*);
void	fprestore(FPsave*);
void	fpregrestore(char*);
void	freeb(Block*);
int	freebroken(void);
void	freenextmod(PTE*);
void	freepage(Orig*, int);
void	freepte(Orig*);
void	freesegs(int);
void	freealarm(Alarm*);
Block	*getb(Blist*);
int	getfields(char*, char**, int, char);
Block	*getq(Queue*);
int	getrs232o(void);
void	gotolabel(Label*);
void	growpte(Orig*, ulong);
void	*ialloc(ulong, int);
int	incref(Ref*);
void	insert(List**, List*, List*);
void	invalidateu(void);
void	isdir(Chan*);
void	kbdchar(int);
void	kbdrepeat(int);
void	kbdclock(void);
void	kmapinit(void);
KMap	*kmap(Page*);
int	kprint(char*, ...);
void	kproc(char*, void(*)(void*), void*);
void	kunmap(KMap*);
void	lock(Lock*);
void	lockinit(void);
Orig	*lookorig(ulong, ulong, int, Chan*);
void	machinit(void);
void	mapstack(Proc*);
void	mmuinit(void);
int	mount(Chan*, Chan*, int);
void	mousebuttons(int);
void	mouseclock(void);
Chan	*namec(char*, int, int, ulong);
void	nexterror(void);
Alarm	*newalarm(void);
Chan	*newchan(void);
PTE	*newmod(Orig *o);
Mount	*newmount(void);
Orig	*neworig(ulong, ulong, int, Chan*);
Page	*newpage(int, Orig*, ulong);
Pgrp	*newpgrp(void);
Proc	*newproc(void);
void	newqinfo(Qinfo*);
char	*nextelem(char*, char*);
void	notify(Ureg*);
void	nullput(Queue*, Block*);
int	openmode(ulong);
Block	*padb(Block*, int);
void	pageinit(void);
void	panic(char*, ...);
void	pexit(char*, int);
void	pgrpcpy(Pgrp*, Pgrp*);
void	pgrpinit(void);
void	pgrpnote(Pgrp*, char*, long, int);
Pgrp	*pgrptab(int);
int	postnote(Proc*, int, char*, int);
int	pprint(char*, ...);
void	printinit(void);
void	printslave(void);
void	procinit0(void);
void	procrestore(Proc*, uchar*);
void	procsave(uchar*, int);
void	procsetup(Proc*);
Proc	*proctab(int);
Queue	*pushq(Stream*, Qinfo*);
void	putbq(Blist*, Block*);
void	putkmmu(ulong, ulong);
void	putmmu(ulong, ulong);
int	putq(Queue*, Block*);
void	putstr(char*);
void	putstrn(char*, long);
ulong	pwait(Waitmsg*);
int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
void	reset(void);
int	return0(void*);
void	rs232ichar(int);
Proc	*runproc(void);
void	qlock(QLock*);
void	qunlock(QLock*);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
void	savefpregs(FPsave*);
void	sched(void);
void	schedinit(void);
void	screeninit(void);
void	screenputc(int);
long	seconds(void);
Seg	*seg(Proc*, ulong);
int	segaddr(Seg*, ulong, ulong);
void	serviceinit(void);
void	service(char*, Chan*, Chan*, void (*)(Chan*, char*, long));
int	setlabel(Label*);
char	*skipslash(char*);
void	sleep(Rendez*, int(*)(void*), void*);
int	splhi(void);
int	spllo(void);
void	splx(int);
void	spldone(void);
Devgen	streamgen;
int	streamclose(Chan*);
int	streamclose1(Stream*);
int	streamenter(Stream*);
int	streamexit(Stream*, int);
void	streaminit(void);
long	streamread(Chan*, void*, long);
long	streamwrite(Chan*, void*, long, int);
Stream	*streamnew(ushort, ushort, ushort, Qinfo*, int);
void	streamopen(Chan*, Qinfo*);
int	streamparse(char*, Block*);
void	streamstat(Chan*, char*, char*);
long	stringread(Chan*, void*, long, char*);
long	syscall(Ureg*);
int	tas(char*);
void	touser(void);
void	tsleep(Rendez*, int (*)(void*), void*, int);
void	twakeme(Alarm*);
long	unionread(Chan*, void*, long);
void	unlock(Lock*);
void	usepage(Page*, int);
void	unusepage(Page*, int);
void	userinit(void);
void	validaddr(ulong, ulong, int);
void	*vmemchr(void*, int, int);
void	wakeme(Alarm*);
void	wakeup(Rendez*);
Chan	*walk(Chan*, char*, int);

#define	waserror()	(u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1]))
#define	poperror()	u->nerrlab--

#define	evenaddr(x)	/* 68020 doesn't care */

#define USED(x) if(x)

A ss/io.h => ss/io.h +6 -0
@@ 0,0 1,6 @@
typedef struct	Duart	Duart;

#define	SYNCREG		((char*)0x40400000)
#define	DISPLAYRAM	0x02000000
#define	DUARTREG	((Duart*)0x40100000)
#define	PORT		((uchar *)0x40300000)

A ss/l.s => ss/l.s +81 -0
@@ 0,0 1,81 @@
#include "mem.h"

TEXT	start(SB), $-4

	/* get virtual, fast */
	/* we are executing in segment 0, mapped to pmeg 0. stack is there too */
	/* get virtual by mapping segment(KZERO) to pmeg 0. */
	MOVW	$KZERO, R1
	MOVB	R0, (R1, 3)
	/* now mapped correctly.  jmpl to where we want to be */
	MOVW	$setR30(SB), R30
	MOVW	$startvirt(SB), R1
	JMPL	(R1)
	RETURN			/* can't get here */

TEXT	startvirt(SB), $-4

	MOVW	$0x4000, R29
	MOVW	$mach0(SB), R(MACH)
	JMPL	main(SB)
	UNIMP
	RETURN

TEXT	pc(SB), $0
	MOVW	R15, R1
	RETURN

TEXT	setlabel(SB), $0
	MOVW	b+0(FP), R2
	MOVW	R29, (R2)
	MOVW	R15, 4(R2)
	MOVW	$0, R1
	RETURN

TEXT	gotolabel(SB), $0
	MOVW	r+4(FP), R1
	MOVW	b+0(FP), R2
	MOVW	(R2), R29
	MOVW	4(R2), R15
	MOVW	R15, 0(R29)
	RETURN

TEXT	crash(SB), $0

	MOVW	0(FP), R8		/* context */
	MOVW	4(FP), R9		/* segment addr */
	MOVW	8(FP), R10		/* segment value */
	MOVW	$0xFFE80118, R1
	JMPL	(R1)
	RETURN

TEXT	putb2(SB), $0

	MOVW	0(FP), R1
	MOVW	4(FP), R2
	MOVB	R2, (R1, 2)
	RETURN

TEXT	putw3(SB), $0

	MOVW	0(FP), R1
	MOVW	4(FP), R2
	MOVW	R2, (R1, 3)
	RETURN

TEXT	putpmeg(SB), $0

	MOVW	0(FP), R1
	MOVW	4(FP), R2
	MOVW	R2, (R1, 4)
	RETURN

TEXT	putwd(SB), $0

	MOVW	0(FP), R1
	MOVW	4(FP), R2
	MOVW	R2, (R1, 0xD)
	RETURN


GLOBL	mach0+0(SB), $MACHSIZE

A ss/lib.h => ss/lib.h +112 -0
@@ 0,0 1,112 @@
/*
 * functions (possibly) linked in, complete, from libc.
 */

/*
 * mem routines
 */
extern	void	*memccpy(void*, void*, int, long);
extern	void	*memset(void*, int, long);
extern	int	memcmp(void*, void*, long);
extern	void	*memcpy(void*, void*, long);
extern	void	*memchr(void*, int, long);

/*
 * string routines
 */
extern	char	*strcat(char*, char*);
extern	char	*strchr(char*, char);
extern	int	strcmp(char*, char*);
extern	char	*strcpy(char*, char*);
extern	char	*strncat(char*, char*, long);
extern	char	*strncpy(char*, char*, long);
extern	int	strncmp(char*, char*, long);
extern	long	strlen(char*);

/*
 * print routines
 */

#define	FUNSIGN	4
#define	FSHORT	2
#define	FLONG	1

typedef struct Op	Op;
struct Op
{
	char	*p;
	char	*ep;
	void	*argp;
	int	f1;
	int	f2;
	int	f3;
};
extern	void	strconv(char*, Op*, int, int);
extern	int	numbconv(Op*, int);
extern	char	*doprint(char*, char*, char*, void*);
extern	int	fmtinstall(char, int (*)(Op*));
extern	int	sprint(char*, char*, ...);
extern	int	print(char*, ...);

/*
 * one-of-a-kind
 */
extern	long	strtol(char*, char**, int);
extern	ulong	strtoul(char*, char**, int);
extern	long	etext;
extern	long	edata;
extern	long	end;
/*
 * Syscall data structures
 */

#define	MORDER	0x0003	/* mask for bits defining order of mounting */
#define	MREPL	0x0000	/* mount replaces object */
#define	MBEFORE	0x0001	/* mount goes before others in union directory */
#define	MAFTER	0x0002	/* mount goes after others in union directory */
#define	MCREATE	0x0004	/* permit creation in mounted directory */
#define	MMASK	0x0007	/* all bits on */

#define	OREAD	0	/* open for read */
#define	OWRITE	1	/* write */
#define	ORDWR	2	/* read and write */
#define	OEXEC	3	/* execute, == read but check execute permission */
#define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */
#define	OCEXEC	32	/* or'ed in, close on exec */
#define	ORCLOSE	64	/* or'ed in, remove on close */

typedef struct Qid	Qid;
typedef struct Dir	Dir;
typedef struct Waitmsg	Waitmsg;

#define	ERRLEN	64
#define	DIRLEN	116
#define	NAMELEN	28

struct Qid
{
	ulong	path;
	ulong	vers;
};

struct Dir
{
	char	name[NAMELEN];
	char	uid[NAMELEN];
	char	gid[NAMELEN];
	Qid	qid;
	ulong	mode;
	long	atime;
	long	mtime;
	Length;
	short	type;
	short	dev;
};

struct Waitmsg
{
	int	pid;		/* of loved one */
	int	status;		/* unused; a placeholder */
	ulong	time[3];	/* of loved one */
	char	msg[ERRLEN];
};

A ss/lock.c => ss/lock.c +111 -0
@@ 0,0 1,111 @@
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"

#define PCOFF -1

/*
 *  N.B.  Ken's compiler generates a TAS instruction for the sequence:
 *
 *  	if(l->key >= 0){
 *		l->key |= 0x80;
 *		...
 *
 *	DO NOT TAKE THE ADDRESS OF l->key or the TAS will disappear.
 */
void
lock(Lock *l)
{
	Lock *ll = l;	/* do NOT take the address of l */
	int i;

	/*
	 * Try the fast grab first
	 */
    	if(ll->key >= 0){
		ll->key |= 0x80;
		ll->pc = ((ulong*)&l)[PCOFF];
		return;
	}
	for(i=0; i<10000000; i++)
    		if(ll->key >= 0){
			ll->key |= 0x80;
			ll->pc = ((ulong*)&l)[PCOFF];
			return;
		}
	ll->key = 0;
dumpstack();
	panic("lock loop %lux pc %lux held by pc %lux\n", l, ((ulong*)&l)[PCOFF], l->pc);
}

int
canlock(Lock *l)
{
	Lock *ll = l;	/* do NOT take the address of l */
	if(ll->key >= 0){
		ll->key |= 0x80;
		ll->pc = ((ulong*)&l)[PCOFF];
		return 1;
	}
	return 0;
}

void
unlock(Lock *l)
{
	l->pc = 0;
	l->key = 0;
}

void
qlock(QLock *q)
{
	Proc *p;

	if(canlock(&q->use))
		return;
	lock(&q->queue);
	if(canlock(&q->use)){
		unlock(&q->queue);
		return;
	}
	p = q->tail;
	if(p == 0)
		q->head = u->p;
	else
		p->qnext = u->p;
	q->tail = u->p;
	u->p->qnext = 0;
	u->p->state = Queueing;
	u->p->qlock = q;	/* DEBUG */
	unlock(&q->queue);
	sched();
}

int
canqlock(QLock *q)
{
	return canlock(&q->use);
}

void
qunlock(QLock *q)
{
	Proc *p;

	lock(&q->queue);
	u->p->qlock = 0;
	if(q->head){
		p = q->head;
		q->head = p->qnext;
		if(q->head == 0)
			q->tail = 0;
		unlock(&q->queue);
		ready(p);
	}else{
		unlock(&q->use);
		unlock(&q->queue);
	}
}

A ss/main.c => ss/main.c +450 -0
@@ 0,0 1,450 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"
#include	"init.h"

#include	<libg.h>
#include	<gnot.h>

char user[NAMELEN];
char bootline[64];
char bootserver[64];
char bootdevice[64];
int bank[2];

void unloadboot(void);

int
Xprint(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	sccputs(buf);
	return n;
}

void
putx(ulong x)
{
	int i;

	for(i=0; i<8; i++){
		sccputc("0123456789ABCDEF"[x>>28]);
		x <<= 4;
	}
	sccputc('\n');
}

void
main(void)
{
	int a;

	u = 0;
	memset(&edata, 0, (char*)&end-(char*)&edata);

	unloadboot();
	machinit();
#ifdef adsf
	mmuinit();
	confinit();
	kmapinit();
#endif
	sccsetup();
	Xprint("hello world addr %lux pc %lux\n", &a, pc());
	reset();
#ifdef asdf
	print("bank 0: %dM  bank 1: %dM\n", bank[0], bank[1]);
	flushmmu();
	procinit0();
	pgrpinit();
	chaninit();
	alarminit();
	chandevreset();
	streaminit();
/*	serviceinit(); /**/
/*	filsysinit(); /**/
	pageinit();
	kmapinit();
	userinit();
	schedinit();
#endif
}

void
reset(void)
{
	delay(100);
	putb2(0x40000000, 4);
}

void
unloadboot(void)
{
	strncpy(user, "rob", sizeof user);
	memcpy(bootline, "9s", sizeof bootline);
	memcpy(bootserver, "bootes", sizeof bootserver);
	memcpy(bootdevice, "parnfucky", sizeof bootserver);
}

void
machinit(void)
{
	int n;

	n = m->machno;
	memset(m, 0, sizeof(Mach));
	m->machno = n;
	m->mmask = 1<<m->machno;
#ifdef adsf
	m->fpstate = FPinit;
	fprestore(&initfp);
#endif
}

void
mmuinit(void)
{
	ulong l, d, i;

	/*
	 * Invalidate user addresses
	 */
	for(l=0; l<4*1024*1024; l+=BY2PG)
		putmmu(l, INVALIDPTE);
	/*
	 * Four meg of usable memory, with top 256K for screen
	 */
	for(i=1,l=KTZERO; i<(4*1024*1024-256*1024)/BY2PG; l+=BY2PG,i++)
		putkmmu(l, PPN(l)|PTEVALID|PTEKERNEL);
	/*
	 * Screen at top of memory
	 */
	for(i=0,d=DISPLAYRAM; i<256*1024/BY2PG; d+=BY2PG,l+=BY2PG,i++)
		putkmmu(l, PPN(d)|PTEVALID|PTEKERNEL);
}

void
init0(void)
{
	Chan *c;

	u->nerrlab = 0;
	m->proc = u->p;
	u->p->state = Running;
	u->p->mach = m;
	spllo();

	chandevinit();
	
	u->slash = (*devtab[0].attach)(0);
	u->dot = clone(u->slash, 0);
	if(!waserror()){
		c = namec("#e/bootline", Acreate, OWRITE, 0600);
		(*devtab[c->type].write)(c, bootline, 64);
		close(c);
		c = namec("#e/bootserver", Acreate, OWRITE, 0600);
		(*devtab[c->type].write)(c, bootserver, 64);
		close(c);
		c = namec("#e/bootdevice", Acreate, OWRITE, 0600);
		(*devtab[c->type].write)(c, bootdevice, 2);
		close(c);
	}
	poperror();
	touser();
}

FPsave	initfp;

void
userinit(void)
{
	Proc *p;
	Seg *s;
	User *up;
	KMap *k;

	p = newproc();
	p->pgrp = newpgrp();
	strcpy(p->text, "*init*");
	strcpy(p->pgrp->user, user);
	p->fpstate = FPinit;

	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR+BY2PG-20;	/* BUG */
	p->sched.sr = SUPER|SPL(0);
	p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF));

	/*
	 * User
	 */
	k = kmap(p->upage);
	up = (User*)VA(k);
	up->p = p;
	kunmap(k);

	/*
	 * User Stack
	 */
	s = &p->seg[SSEG];
	s->proc = p;
	s->o = neworig(USTKTOP-BY2PG, 1, OWRPERM, 0);
	s->minva = USTKTOP-BY2PG;
	s->maxva = USTKTOP;

	/*
	 * Text
	 */
	s = &p->seg[TSEG];
	s->proc = p;
	s->o = neworig(UTZERO, 1, 0, 0);
	s->o->pte[0].page = newpage(0, 0, UTZERO);
	s->o->npage = 1;
	k = kmap(s->o->pte[0].page);
	memcpy((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);
	s->minva = UTZERO;
	s->maxva = UTZERO+BY2PG;

	ready(p);
}

void
exit(void)
{
	int i;

	u = 0;
	splhi();
	print("exiting\n");
	for(;;)
		;
}

/*
 * Insert new into list after where
 */
void
insert(List **head, List *where, List *new)
{
	if(where == 0){
		new->next = *head;
		*head = new;
	}else{
		new->next = where->next;
		where->next = new;
	}
		
}

/*
 * Insert new into list at end
 */
void
append(List **head, List *new)
{
	List *where;

	where = *head;
	if(where == 0)
		*head = new;
	else{
		while(where->next)
			where = where->next;
		where->next = new;
	}
	new->next = 0;
}

/*
 * Delete old from list
 */
void
delete0(List **head, List *old)
{
	List *l;

	l = *head;
	if(l == old){
		*head = old->next;
		return;
	}
	while(l->next != old)
		l = l->next;
	l->next = old->next;
}

/*
 * Delete old from list.  where->next is known to be old.
 */
void
delete(List **head, List *where, List *old)
{
	if(where == 0){
		*head = old->next;
		return;
	}
	where->next = old->next;
}

banksize(int base)
{
	ulong va;

	if(&end > (int *)((KZERO|1024L*1024L)-BY2PG))
		return 0;
	va = UZERO;	/* user page 1 is free to play with */
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG);
	*(ulong*)va = 0;	/* 0 at 0M */
	putmmu(va, PTEVALID|(base+1)*1024L*1024L/BY2PG);
	*(ulong*)va = 1;	/* 1 at 1M */
	putmmu(va, PTEVALID|(base+4)*1024L*1024L/BY2PG);
	*(ulong*)va = 4;	/* 4 at 4M */
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG);
	if(*(ulong*)va == 0)
		return 16;
	putmmu(va, PTEVALID|(base+1)*1024L*1024L/BY2PG);
	if(*(ulong*)va == 1)
		return 4;
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG);
	if(*(ulong*)va == 4)
		return 1;
	return 0;
}

Conf	conf;

void
confinit(void)
{
	int mul;
	conf.nmach = 1;
	if(conf.nmach > MAXMACH)
		panic("confinit");
	bank[0] = banksize(0);
	bank[1] = banksize(16);
	conf.npage0 = (bank[0]*1024*1024)/BY2PG;
	conf.base0 = 0;
	conf.npage1 = (bank[1]*1024*1024)/BY2PG;
	conf.base1 = 16*1024*1024;
	conf.npage = conf.npage0+conf.npage1;
	conf.maxialloc = (4*1024*1024-256*1024-BY2PG);
	mul = 1 + (conf.npage1>0);
	conf.nproc = 50*mul;
	conf.npgrp = 12*mul;
	conf.npte = 700*mul;
	conf.nmod = 400*mul;
	conf.nalarm = 1000;
	conf.norig = 150*mul;
	conf.nchan = 200*mul;
	conf.nenv = 100*mul;
	conf.nenvchar = 8000*mul;
	conf.npgenv = 200*mul;
	conf.nmtab = 50*mul;
	conf.nmount = 80*mul;
	conf.nmntdev = 10*mul;
	conf.nmntbuf = conf.nmntdev+3;
	conf.nmnthdr = 2*conf.nmntdev;
	conf.nstream = 40 + 32*mul;
	conf.nqueue = 5 * conf.nstream;
	conf.nblock = 24 * conf.nstream;
	conf.nsrv = 16*mul;			/* was 32 */
	conf.nbitmap = 300*mul;
	conf.nbitbyte = 300*1024*mul;
	if(*(uchar*)MOUSE & (1<<4))
		conf.nbitbyte *= 2;	/* ldepth 1 */
	conf.nfont = 10*mul;
	conf.nurp = 32;
	conf.nasync = 1;
	conf.npipe = conf.nstream/2;
	conf.nservice = 3*mul;			/* was conf.nproc/5 */
	conf.nfsyschan = 31 + conf.nchan/20;
	conf.copymode = 0;		/* copy on write */
}

/*
 *  set up floating point for a new process
 */
void
procsetup(Proc *p)
{
#ifdef asdf
	long fpnull;

	fpnull = 0;
	splhi();
	m->fpstate = FPinit;
	p->fpstate = FPinit;
	fprestore((FPsave*)&fpnull);
	spllo();
#endif
	panic("procsetup");
}

/*
 * Save the part of the process state.
 */
void
procsave(uchar *state, int len)
{
	panic("procsave");
#ifdef asdf
	Balu *balu;

	if(len < sizeof(Balu))
		panic("save state too small");
	balu = (Balu *)state;
	fpsave(&u->fpsave);
	if(u->fpsave.type){
		if(u->fpsave.size > sizeof u->fpsave.junk)
			panic("fpsize %d max %d\n", u->fpsave.size, sizeof u->fpsave.junk);
		fpregsave(u->fpsave.reg);
		u->p->fpstate = FPactive;
		m->fpstate = FPdirty;
	}
	if(BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(balu, BALU, sizeof(Balu));
	else{
		balu->cr0 = 0xFFFFFFFF;
		BALU->cr0 = 0xFFFFFFFF;
	}
#endif
}

/*
 *  Restore what procsave() saves
 *
 *  Procsave() makes sure that what state points to is long enough
 */
void
procrestore(Proc *p, uchar *state)
{
	panic("procrestore");
#ifdef asdf
	Balu *balu;

	balu = (Balu *)state;
	if(p->fpstate != m->fpstate){
		if(p->fpstate == FPinit){
			u->p->fpstate = FPinit;
			fprestore(&initfp);
			m->fpstate = FPinit;
		}else{
			fpregrestore(u->fpsave.reg);
			fprestore(&u->fpsave);
			m->fpstate = FPdirty;
		}
	}
	if(balu->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(BALU, balu, sizeof balu);
#endif
}

A ss/malloc.h => ss/malloc.h +15 -0
@@ 0,0 1,15 @@
struct tbl_entry {
	struct tbl_entry *next;		/* free list */
	int *data;			/* data */
};

struct table {
	int size;			/* # entries */
	struct tbl_entry *entries;	/* the entries */
	struct tbl_entry *free;		/* the free list */
};

void *tbl_alloc(struct table *, int);
void tbl_free(struct table *, void *);
int tbl_index(struct table *, void *);
void *tbl_data(struct table *, int);

A ss/mem.h => ss/mem.h +106 -0
@@ 0,0 1,106 @@
/*
 * Memory and machine-specific definitions.  Used in C and assembler.
 */

/*
 * Sizes
 */

#define	BI2BY		8			/* bits per byte */
#define BI2WD		32			/* bits per word */
#define	BY2WD		4			/* bytes per word */
#define	BY2PG		4096			/* bytes per page */
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */

#define	MAXMACH		1			/* max # cpus system can run */

/*
 * Time
 */
#define	HZ		(60)			/* clock frequency */
#define	MS2HZ		(1000/HZ)		/* millisec per clock tick */
#define	TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
#define	TK2MS(t)	((((ulong)(t))*1000)/HZ)	/* ticks to milliseconds */
#define	MS2TK(t)	((((ulong)(t))*HZ)/1000)	/* milliseconds to ticks */

/*
 * SR bits
 */
#define SUPER		0x2000
#define SPL(n)		(n<<8)

/*
 * CACR
 */
#define	CCLEAR		0x08
#define	CENABLE		0x01

/*
 * Magic registers
 */

#define	MACH		28		/* R28 is m-> */
#define	USER		27		/* R27 is u-> */

/*
 * Fundamental addresses
 */

#define	USERADDR	0x80000000
#define	UREGADDR	(USERADDR+BY2PG-(2+4+2+(8+8+1)*BY2WD))

/*
 * Devices poked during bootstrap
 */
#define	TACADDR		0x40600000
#define	MOUSE		0x40200000

/*
 * MMU
 */

#define	VAMASK	0x1FFFFFFF

/*
 * MMU entries
 */
#define	PTEVALID	(1<<31)
#define	PTEWRITE	(1<<30)
#define	PTEKERNEL	(1<<29)
#define	PTENOCACHE	(1<<28)
#define	PTEMAINMEM	(0<<26)
#define	PTEIO		(1<<26)
#define	PTEACCESS	(1<<25)
#define	PTEMODIFY	(1<<24)

#define	PTERONLY	0		/* BUG */
#define	INVALIDPTE	0
#define	PPN(pa)		((pa>>12)&0xFFFF)

#define	KMAP	((unsigned long *)0xD0000000)
#define	UMAP	((unsigned long *)0x50000000)

/*
 * Virtual addresses
 */
#define	VTAG(va)	((va>>22)&0x03F)
#define	VPN(va)		((va>>13)&0x1FF)

#define	PARAM		((char*)0x40500000)
#define	TLBFLUSH_	0x01

/*
 * Address spaces
 */

#define	UZERO	0x00000000			/* base of user address space */
#define	UTZERO	(UZERO+BY2PG)		/* first address in user text */
#define	TSTKTOP	0x10000000		/* end of new stack in sysexec */
#define	USTKTOP	(TSTKTOP-100*BY2PG)	/* byte just beyond user stack */
#define	KZERO	0x10000000		/* base of kernel address space */
#define	KTZERO	(KZERO+4*BY2PG)		/* first address in kernel text */
#define	USTACKSIZE	(4*1024*1024)	/* size of user stack */

#define	NSEG		5
#define	MACHSIZE	4096

A ss/mmu.c => ss/mmu.c +159 -0
@@ 0,0 1,159 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

struct
{
	Lock;
	int	init;
	KMap	*free;
	KMap	arena[4*1024*1024/BY2PG];	/* kernel mmu maps up to 4MB */
}kmapalloc;

/*
 * Called splhi, not in Running state
 */
void
mapstack(Proc *p)
{
	ulong tlbvirt, tlbphys;
	ulong next;
	MMU *mm, *mn, *me;

	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)))
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
	tlbvirt = USERADDR;
	tlbphys = PPN(p->upage->pa) | PTEVALID | PTEKERNEL;
	putkmmu(tlbvirt, tlbphys);
	u = (User*)USERADDR;

	/*
	 *  if not a kernel process and this process was not the 
	 *  last process on this machine, flush & preload mmu
	 */
	if(!p->kp && p!=m->lproc){
		flushmmu();

		/*
		 *  preload the MMU with the last (up to) NMMU user entries
		 *  previously faulted into it for this process.
		 */
		mn = &u->mc.mmu[u->mc.next&(NMMU-1)];
		me = &u->mc.mmu[NMMU];
		if(u->mc.next >= NMMU){
			for(mm = mn; mm < me; mm++)
				UMAP[mm->va] = mm->pa;
		}
		for(mm = u->mc.mmu; mm < mn; mm++)
			UMAP[mm->va] = mm->pa;

		m->lproc = p;
	}
}

void
putkmmu(ulong tlbvirt, ulong tlbphys)
{
	if(!(tlbvirt&KZERO))
		panic("putkmmu");
	tlbvirt &= ~KZERO;
	KMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys;
}

void
putmmu(ulong tlbvirt, ulong tlbphys)
{
	if(tlbvirt&KZERO)
		panic("putmmu");
	tlbphys |= VTAG(tlbvirt)<<24;
	tlbvirt = (tlbvirt&0x003FE000L)>>2;
	if(u){
		MMU *mp;
		int s;

		s = splhi();
		mp = &(u->mc.mmu[u->mc.next&(NMMU-1)]);
		mp->pa = tlbphys;
		mp->va = tlbvirt;
		u->mc.next++;
		splx(s);
	}
	UMAP[tlbvirt] = tlbphys;
}

void
flushmmu(void)
{
	flushcpucache();
	*PARAM &= ~TLBFLUSH_;
	*PARAM |= TLBFLUSH_;
}

void
clearmmucache(void)
{
	if(u == 0)
		panic("flushmmucache");
	u->mc.next = 0;
}

void
kmapinit(void)
{
	KMap *k;
	int i, e;

	if(kmapalloc.init == 0){
		k = &kmapalloc.arena[0];
		k->va = KZERO|(4*1024*1024-256*1024-BY2PG);
		k->next = 0;
		kmapalloc.free = k;
		kmapalloc.init = 1;
		return;
	}
	e = (4*1024*1024 - 256*1024)/BY2PG;	/* screen lives at top 256K */
	i = (((ulong)ialloc(0, 0))&~KZERO)/BY2PG;
	print("%lud free map registers\n", e-i);
	kmapalloc.free = 0;
	for(k=&kmapalloc.arena[i]; i<e; i++,k++){
		k->va = i*BY2PG|KZERO;
		kunmap(k);
	}
}

KMap*
kmap(Page *pg)
{
	KMap *k;

	lock(&kmapalloc);
	k = kmapalloc.free;
	if(k == 0){
		dumpstack();
		panic("kmap");
	}
	kmapalloc.free = k->next;
	unlock(&kmapalloc);
	k->pa = pg->pa;
	putkmmu(k->va, PPN(k->pa) | PTEVALID | PTEKERNEL);
	return k;
}

void
kunmap(KMap *k)
{
	k->pa = 0;
	lock(&kmapalloc);
	k->next = kmapalloc.free;
	kmapalloc.free = k;
	putkmmu(k->va, INVALIDPTE);
	unlock(&kmapalloc);
}

void
invalidateu(void)
{
	putkmmu(USERADDR, INVALIDPTE);
}

A ss/screen.c => ss/screen.c +407 -0
@@ 0,0 1,407 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"
#include	"errno.h"

#include	<libg.h>
#include	<gnot.h>

#define	MINX	8

extern	GFont	defont0;
GFont		*defont;

struct{
	Point	pos;
	int	bwid;
}out;

void	duartinit(void);
int	duartacr;
int	duartimr;

void	(*kprofp)(ulong);

GBitmap	gscreen =
{
	(ulong*)((4*1024*1024-256*1024)|KZERO),	/* BUG */
	0,
	64,
	0,
	0, 0, 1024, 1024,
	0
};

void
screeninit(void)
{
	duartinit();
	/*
	 * Read HEX switch to set ldepth
	 */
	if(*(uchar*)MOUSE & (1<<4))
		gscreen.ldepth = 1;
	defont = &defont0;	/* save space; let bitblt do the conversion work */
	gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, 0);
	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;
}

void
screenputc(int c)
{
	char buf[2];
	int nx;

	if(c == '\n'){
		out.pos.x = MINX;
		out.pos.y += defont0.height;
		if(out.pos.y > gscreen.r.max.y-defont0.height)
			out.pos.y = gscreen.r.min.y;
		gbitblt(&gscreen, Pt(0, out.pos.y), &gscreen,
		    Rect(0, out.pos.y, gscreen.r.max.x, out.pos.y+2*defont0.height), 0);
	}else if(c == '\t'){
		out.pos.x += (8-((out.pos.x-MINX)/out.bwid&7))*out.bwid;
		if(out.pos.x >= gscreen.r.max.x)
			screenputc('\n');
	}else if(c == '\b'){
		if(out.pos.x >= out.bwid+MINX){
			out.pos.x -= out.bwid;
			screenputc(' ');
			out.pos.x -= out.bwid;
		}
	}else{
		if(out.pos.x >= gscreen.r.max.x-out.bwid)
			screenputc('\n');
		buf[0] = c&0x7F;
		buf[1] = 0;
		out.pos = gbitbltstring(&gscreen, out.pos, defont, buf, S);
	}
}

/*
 * Register set for half the duart.  There are really two sets.
 */
struct Duart{
	uchar	mr1_2;		/* Mode Register Channels 1 & 2 */
	uchar	sr_csr;		/* Status Register/Clock Select Register */
	uchar	cmnd;		/* Command Register */
	uchar	data;		/* RX Holding / TX Holding Register */
	uchar	ipc_acr;	/* Input Port Change/Aux. Control Register */
#define	ivr	ivr		/* Interrupt Vector Register */
	uchar	is_imr;		/* Interrupt Status/Interrupt Mask Register */
#define	ip_opcr	is_imr		/* Input Port/Output Port Configuration Register */
	uchar	ctur;		/* Counter/Timer Upper Register */
#define	scc_sopbc ctur		/* Start Counter Command/Set Output Port Bits Command */
	uchar	ctlr;		/* Counter/Timer Lower Register */
#define	scc_ropbc ctlr		/* Stop Counter Command/Reset Output Port Bits Command */
};

enum{
	CHAR_ERR	=0x00,	/* MR1x - Mode Register 1 */
	PAR_ENB		=0x00,
	EVEN_PAR	=0x00,
	ODD_PAR		=0x04,
	NO_PAR		=0x10,
	CBITS8		=0x03,
	CBITS7		=0x02,
	CBITS6		=0x01,
	CBITS5		=0x00,
	NORM_OP		=0x00,	/* MR2x - Mode Register 2 */
	TWOSTOPB	=0x0F,
	ONESTOPB	=0x07,
	ENB_RX		=0x01,	/* CRx - Command Register */
	DIS_RX		=0x02,
	ENB_TX		=0x04,
	DIS_TX		=0x08,
	RESET_MR 	=0x10,
	RESET_RCV  	=0x20,
	RESET_TRANS  	=0x30,
	RESET_ERR  	=0x40,
	RESET_BCH	=0x50,
	STRT_BRK	=0x60,
	STOP_BRK	=0x70,
	RCV_RDY		=0x01,	/* SRx - Channel Status Register */
	FIFOFULL	=0x02,
	XMT_RDY		=0x04,
	XMT_EMT		=0x08,
	OVR_ERR		=0x10,
	PAR_ERR		=0x20,
	FRM_ERR		=0x40,
	RCVD_BRK	=0x80,
	BD38400		=0xCC|0x0000,
	BD19200		=0xCC|0x0100,
	BD9600		=0xBB|0x0000,
	BD4800		=0x99|0x0000,
	BD2400		=0x88|0x0000,
	BD1200		=0x66|0x0000,
	BD300		=0x44|0x0000,
	IM_IPC		=0x80,	/* IMRx/ISRx - Interrupt Mask/Interrupt Status */
	IM_DBB		=0x40,
	IM_RRDYB	=0x20,
	IM_XRDYB	=0x10,
	IM_CRDY		=0x08,
	IM_DBA		=0x04,
	IM_RRDYA	=0x02,
	IM_XRDYA	=0x01,
};

uchar keymap[]={
/*80*/	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x8e,	0x58,
/*90*/	0x90,	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,	0x97,
	0x98,	0x99,	0x9a,	0x9b,	0x58,	0x58,	0x58,	0x58,
/*A0*/	0x58,	0xa1,	0xa2,	0xa3,	0xa4,	0xa5,	0xa6,	0xa7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0xae,	0xaf,
/*B0*/	0xb0,	0xb1,	0xb2,	0xb3,	0xb4,	0xb5,	0x80,	0xb7,
	0xb8,	0xb9,	0x00,	0xbb,	0x1e,	0xbd,	0x60,	0x1f,
/*C0*/	0xc0,	0xc1,	0xc2,	0xc3,	0xc4,	0x58,	0xc6,	0x0a,
	0xc8,	0xc9,	0xca,	0xcb,	0xcc,	0xcd,	0xce,	0xcf,
/*D0*/	0x09,	0x08,	0xd2,	0xd3,	0xd4,	0xd5,	0xd6,	0xd7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0x58,
/*E0*/	0x58,	0x58,	0xe2,	0x1b,	0x0d,	0xe5,	0x58,	0x0a,
	0xe8,	0xe9,	0xea,	0xeb,	0xec,	0xed,	0xee,	0xef,
/*F0*/	0x09,	0x08,	0xb2,	0x1b,	0x0d,	0xf5,	0x81,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0xb2,
};

void
duartinit(void)
{
	Duart *duart;

	duart  =  DUARTREG;

	/*
	 * Keyboard
	 */
	duart[0].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[0].cmnd = RESET_TRANS;
	duart[0].cmnd = RESET_ERR;
	duart[0].cmnd = RESET_MR;
	duart[0].mr1_2 = CHAR_ERR|PAR_ENB|EVEN_PAR|CBITS8;
	duart[0].mr1_2 = NORM_OP|ONESTOPB;
	duart[0].sr_csr = BD4800;

	/*
	 * RS232
	 */
	duart[1].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[1].cmnd = RESET_TRANS;
	duart[1].cmnd = RESET_ERR;
	duart[1].cmnd = RESET_MR;
	duart[1].mr1_2 = CHAR_ERR|NO_PAR|CBITS8;
	duart[1].mr1_2 = NORM_OP|ONESTOPB;
	duart[1].sr_csr = BD9600;

	/*
	 * Output port
	 */
	duart[0].ipc_acr = duartacr = 0xB7;	/* allow change	of state interrupt */
	duart[1].ip_opcr = 0x00;
	duart[1].scc_ropbc = 0xFF;	/* make sure the port is reset first */
	duart[1].scc_sopbc = 0x04;	/* dtr = 1, pp = 01 */
	duart[0].is_imr = duartimr = IM_IPC|IM_RRDYB|IM_XRDYB|IM_RRDYA|IM_XRDYA;
	duart[0].cmnd = ENB_TX|ENB_RX;	/* enable TX and RX last */
	duart[1].cmnd = ENB_TX|ENB_RX;

	/*
	 * Initialize keyboard
	 */
	while (!(duart[0].sr_csr & (XMT_EMT|XMT_RDY)))
		;
	duart[0].data = 0x02;
}

int
duartinputport(void)
{
	Duart *duart = DUARTREG;
	return duart[1].ip_opcr;
}
void
duartbaud(int b)
{
	int x;
	Duart *duart = DUARTREG;

	x = 0;		/* set */
	switch(b){
	case 38400:
		x = BD38400;
		break;
	case 19200:
		x = BD19200;
		break;
	case 9600:
		x = BD9600;
		break;
	case 4800:
		x = BD4800;
		break;
	case 2400:
		x = BD2400;
		break;
	case 1200:
		x = BD1200;
		break;
	case 300:
		x = BD300;
		break;
	default:
		error(Ebadarg);
	}
	if(x & 0x0100)
		duart[0].ipc_acr = duartacr |= 0x80;
	else
		duart[0].ipc_acr = duartacr &= ~0x80;
	duart[1].sr_csr = x;
}

void
duartdtr(int val)
{
	Duart *duart = DUARTREG;
	if (val)
		duart[1].scc_ropbc=0x01;
	else
		duart[1].scc_sopbc=0x01;
}

void
duartbreak(int ms)
{
	static QLock brk;
	Duart *duart = DUARTREG;
	if (ms<=0 || ms >20000)
		error(Ebadarg);
	qlock(&brk);
	duart[0].is_imr = duartimr &= ~IM_XRDYB;
	duart[1].cmnd = STRT_BRK|ENB_TX;
	tsleep(&u->p->sleep, return0, 0, ms);
	duart[1].cmnd = STOP_BRK|ENB_TX;
	duart[0].is_imr = duartimr |= IM_XRDYB;
	qunlock(&brk);
}

enum{
	Kptime=200
};
void
duartstarttimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	duart[0].ctur = (Kptime)>>8;
	duart[0].ctlr = (Kptime)&255;
	duart[0].is_imr = duartimr |= IM_CRDY;
	x = duart[1].scc_sopbc;
}

void
duartstoptimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	x = duart[1].scc_ropbc;
	duart[0].is_imr = duartimr &= ~IM_CRDY;
}

void
duartrs232intr(void)
{
	int c;
	Duart *duart;

	duart = DUARTREG;
	c = getrs232o();
	if(c == -1)
		duart[1].cmnd = DIS_TX;
	else
		duart[1].data = c;
}

void
duartstartrs232o(void)
{
	DUARTREG[1].cmnd = ENB_TX;
	duartrs232intr();
}

void
duartintr(Ureg *ur)
{
	int cause, status, c;
	Duart *duart;

	duart = DUARTREG;
	cause = duart->is_imr;
	/*
	 * I can guess your interrupt.
	 */
	/*
	 * Is it 0?
	 */
	if(cause & IM_CRDY){
		if(kprofp)
			(*kprofp)(ur->pc);
		c = duart[1].scc_ropbc;
		duart[0].ctur = (Kptime)>>8;
		duart[0].ctlr = (Kptime)&255;
		c = duart[1].scc_sopbc;
		return;
	}
	/*
	 * Is it 1?
	 */
	if(cause & IM_RRDYA){		/* keyboard input */
		status = duart->sr_csr;
		c = duart->data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart->cmnd = RESET_ERR;
		if(status & PAR_ERR) /* control word: caps lock (0x4) or repeat (0x10) */
			kbdrepeat((c&0x10) == 0);
		else{
			if(c == 0x7F)
				c = 0xFF;	/* VIEW key (bizarre) */
			if(c & 0x80)
				c = keymap[c&0x7F];
			kbdchar(c);
		}
	}
	/*
	 * Is it 2?
	 */
	if(cause & IM_RRDYB){		/* rs232 input */
		status = duart[1].sr_csr;
		c = duart[1].data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart[1].cmnd = RESET_ERR;
		else
			rs232ichar(c);
	}
	/*
	 * Is it 3?
	 */
	if(cause & IM_XRDYB)		/* rs232 output */
		duartrs232intr();
	/*
	 * Is it 4?
	 */
	if(cause & IM_XRDYA)
		duart[0].cmnd = DIS_TX;
	/*
	 * Is it 5?
	 */
	if(cause & IM_IPC)
		mousebuttons((~duart[0].ipc_acr) & 7);
}

A ss/stream.h => ss/stream.h +5 -0
@@ 0,0 1,5 @@
extern	Qinfo 	 asyncinfo;

void streaminit0(void){
	newqinfo(&asyncinfo);
}

A ss/trap.c => ss/trap.c +320 -0
@@ 0,0 1,320 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"errno.h"

void	notify(Ureg*);
void	noted(Ureg**);
void	rfnote(Ureg**);

char *regname[]={
	"R0",
	"R1",
	"R2",
	"R3",
	"R4",
	"R5",
	"R6",
	"R7",
	"A0",
	"A1",
	"A2",
	"A3",
	"A4",
	"A5",
	"A6",
	"A7",
};

long	ticks;

char *trapname[]={
	"reset isp",
	"reset ipc",
	"bus error",
	"address error",
	"illegal instruction",
	"zero divide",
	"chk, chk2 instruction",
	"cptrapcc, trapcc, trapv instruction",
	"privilege violation",
	"trace",
	"line 1010 emulator",
	"line 1111 emulator",
	"reserved",
	"coprocessor protocol violation",
	"format error",
	"uninitialized interrupt",
	"unassigned 0x40",
	"unassigned 0x44",
	"unassigned 0x48",
	"unassigned 0x4C",
	"unassigned 0x50",
	"unassigned 0x54",
	"unassigned 0x58",
	"unassigned 0x5C",
	"spurious interrupt",
	"level 1 autovector (tac)",
	"level 2 autovector (port)",
	"level 3 autovector (incon)",
	"level 4 autovector (mouse)",
	"level 5 autovector (uart)",
	"level 6 autovector (sync)",
	"level 7 autovector",
};

char*
excname(unsigned vo)
{
	static char buf[32];	/* BUG: not reentrant! */

	vo &= 0x0FFF;
	vo >>= 2;
	if(vo < sizeof trapname/sizeof(char*))
		return trapname[vo];
	sprint(buf, "offset 0x%ux", vo<<2);
	return buf;
}

void
trap(Ureg *ur)
{
	int user;
	char buf[64];

	user = !(ur->sr&SUPER);

	if(u)
		u->p->pc = ur->pc;		/* BUG */
	if(user){
		sprint(buf, "sys: trap: pc=0x%lux %s", ur->pc, excname(ur->vo));
		postnote(u->p, 1, buf, NDebug);
	}else{
		print("kernel trap vo=0x%ux pc=0x%lux\n", ur->vo, ur->pc);
		dumpregs(ur);
		exit();
	}
	if(user && u->nnote)
		notify(ur);
}

void
dumpstack(void)
{
	ulong l, v;
	extern ulong etext;

	if(u)
		for(l=(ulong)&l; l<USERADDR+BY2PG; l+=4){
			v = *(ulong*)l;
			if(KTZERO < v && v < (ulong)&etext)
				print("%lux=%lux\n", l, v);
		}
}

void
dumpregs(Ureg *ur)
{
	int i;
	ulong *l;

	if(u)
		print("registers for %s %d\n", u->p->text, u->p->pid);
	else
		print("registers for kernel\n");
	print("SR=%ux PC=%lux VO=%lux, USP=%lux\n", ur->sr, ur->pc, ur->vo, ur->usp);
	l = &ur->r0;
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
	dumpstack();
}

/*
 * Call user, if necessary, with note
 */
void
notify(Ureg *ur)
{
	ulong sp;

	lock(&u->p->debug);
	if(u->nnote==0){
		unlock(&u->p->debug);
		return;
	}
	if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){
		if(u->note[0].flag == NDebug)
			pprint("suicide: %s\n", u->note[0].msg);
    Die:
		unlock(&u->p->debug);
		pexit(u->note[0].msg, u->note[0].flag!=NDebug);
	}
	if(!u->notified){
		if(!u->notify)
			goto Die;
		sp = ur->usp;
		sp -= sizeof(Ureg);
		u->ureg = (void*)sp;
		memcpy((Ureg*)sp, ur, sizeof(Ureg));
		sp -= ERRLEN;
		memcpy((char*)sp, u->note[0].msg, ERRLEN);
		sp -= 3*BY2WD;
		*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
		*(ulong*)(sp+1*BY2WD) = (ulong)u->ureg;	/* arg 1 is ureg* */
		*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */
		ur->usp = sp;
		ur->pc = (ulong)u->notify;
		u->notified = 1;
		u->nnote--;
		memcpy(&u->note[0], &u->note[1], u->nnote*sizeof(Note));
	}
	unlock(&u->p->debug);
}

/*
 * Return user to state before notify()
 */
void
noted(Ureg **urp)
{
	lock(&u->p->debug);
	if(!u->notified){
		unlock(&u->p->debug);
		return;
	}
	u->notified = 0;
	memcpy(*urp, u->ureg, sizeof(Ureg));
	unlock(&u->p->debug);
	splhi();
	rfnote(urp);
}

#undef	CHDIR	/* BUG */
#include "/sys/src/libc/680209sys/sys.h"

typedef long Syscall(ulong*);
Syscall	sysr1, sysfork, sysexec, sysgetpid, syssleep, sysexits, sysdeath, syswait;
Syscall	sysopen, sysclose, sysread, syswrite, sysseek, syserrstr, sysaccess, sysstat, sysfstat;
Syscall sysdup, syschdir, sysforkpgrp, sysbind, sysmount, syspipe, syscreate;
Syscall	sysbrk_, sysremove, syswstat, sysfwstat, sysnotify, sysnoted;

Syscall *systab[]={
	sysr1,
	syserrstr,
	sysbind,
	syschdir,
	sysclose,
	sysdup,
	sysdeath,
	sysexec,
	sysexits,
	sysfork,
	sysforkpgrp,
	sysfstat,
	sysdeath,
	sysmount,
	sysopen,
	sysread,
	sysseek,
	syssleep,
	sysstat,
	syswait,
	syswrite,
	syspipe,
	syscreate,
	sysdeath,
	sysbrk_,
	sysremove,
	syswstat,
	sysfwstat,
	sysnotify,
	sysnoted,
	sysdeath,	/* sysfilsys */
};

long
syscall(Ureg *aur)
{
	long ret;
	ulong sp;
	ulong r0;
	Ureg *ur;
	char *msg;

	u->p->insyscall = 1;
	ur = aur;
	u->p->pc = ur->pc;
	if(ur->sr & SUPER)
		panic("recursive system call");
	/*
	 * since the system call interface does not
	 * guarantee anything about registers, but the fpcr is more than
	 * just a register...  BUG
	 */
	splhi();
	fpsave(&u->fpsave);
	if(u->p->fpstate==FPactive || u->fpsave.type){
		fprestore(&initfp);
		u->p->fpstate = FPinit;
		m->fpstate = FPinit;
	}
	spllo();
	r0 = ur->r0;
	sp = ur->usp;

	u->nerrlab = 0;
	ret = -1;
	if(!waserror()){
		if(r0 >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", r0, ((Ureg*)UREGADDR)->pc);
			msg = "sys: bad sys call";
	    Bad:
			postnote(u->p, 1, msg, NDebug);
			error(Ebadarg);
		}
		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "sys: odd stack";
			goto Bad;
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-5*BY2WD))
			validaddr(sp, 5*BY2WD, 0);
		ret = (*systab[r0])((ulong*)(sp+BY2WD));
	}
	u->nerrlab = 0;
	u->p->insyscall = 0;
	if(r0 == NOTED)	/* ugly hack */
		noted(&aur);	/* doesn't return */
	if(u->nnote){
		ur->r0 = ret;
		notify(ur);
	}
	return ret;
}

#include "errstr.h"

void
error(int code)
{
	strncpy(u->error, errstrtab[code], NAMELEN);
	nexterror();
}

void
errors(char *err)
{
	strncpy(u->error, err, NAMELEN);
	nexterror();
}


void
nexterror(void)
{
	gotolabel(&u->errlab[--u->nerrlab]);
}

A ss/u.h => ss/u.h +15 -0
@@ 0,0 1,15 @@
typedef	unsigned short	ushort;
typedef	unsigned char	uchar;
typedef unsigned long	ulong;
typedef	long		vlong;
typedef union Length	Length;

union Length
{
	char	clength[8];
	vlong	vlength;
	struct{
		long	hlength;
		long	length;
	};
};

A ss/uart.c => ss/uart.c +155 -0
@@ 0,0 1,155 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

enum
{
	/* wr 0 */
	ResExtPend=	2<<3,
	ResTxPend=	5<<3,
	ResErr=		6<<3,

	/* wr 1 */
	TxIntEna=	1<<1,
	RxIntDis=	0<<3,
	RxIntFirstEna=	1<<3,
	RxIntAllEna=	2<<3,

	/* wr 3 */
	RxEna=		1,
	Rx5bits=	0<<6,
	Rx7bits=	1<<6,
	Rx6bits=	2<<6,
	Rx8bits=	3<<6,

	/* wr 4 */
	SyncMode=	0<<2,
	Rx1stop=	1<<2,
	Rx1hstop=	2<<2,
	Rx2stop=	3<<2,
	X16=		1<<6,

	/* wr 5 */
	TxRTS=		1<<1,
	TxEna=		1<<3,
	TxBreak=	1<<4,
	TxDTR=		1<<7,
	Tx5bits=	0<<5,
	Tx7bits=	1<<5,
	Tx6bits=	2<<5,
	Tx8bits=	3<<5,

	/* wr 9 */
	IntEna=		1<<3,
	ResetB=		1<<6,
	ResetA=		2<<6,
	HardReset=	3<<6,

	/* wr 11 */
	TRxCOutBR=	2,
	TxClockBR=	2<<3,
	RxClockBR=	2<<5,
	TRxCOI=		1<<2,

	/* wr 14 */
	BREna=		1,
	BRSource=	2,

	/* rr 0 */
	RxReady=	1,
	TxReady=	1<<2,
	RxDCD=		1<<3,
	RxCTS=		1<<5,
	RxBreak=	1<<7,

	/* rr 3 */
	ExtPendB=	1,	
	TxPendB=	1<<1,
	RxPendB=	1<<2,
	ExtPendA=	1<<3,	
	TxPendA=	1<<4,
	RxPendA=	1<<5,
};

typedef struct SCC	SCC;
struct SCC
{
	uchar	*ptr;		/* command/pointer register in Z8530 */
	uchar	*data;		/* data register in Z8530 */
};
SCC	scc[2];
#define	SCCV	(0x0F000000-0x1000)
#define	SCCP	0xF1000000

#define PRINTING	0x4
#define MASK		0x1

void
sccsetup(void)
{
	ulong pte;

	pte = 	PTEVALID |
		PTEWRITE |
		PTEKERNEL |
		PTENOCACHE |
		PTEIO |
		((SCCP>>PGSHIFT)&0xFFFF)
		;
	putpmeg(SCCV, pte);
	scc[0].ptr = (uchar*)(SCCV+0);
	scc[0].data = (uchar*)(SCCV+2);
	scc[1].ptr = (uchar*)(SCCV+4);
	scc[1].data = (uchar*)(SCCV+6);
}

/*
 *  Access registers using the pointer in register 0.
 *  This is a bit stupid when accessing register 0.
 */
void
sccwrreg(SCC *sp, int addr, int value)
{
	*sp->ptr = addr;
}

ushort
sccrdreg(SCC *sp, int addr)
{
	*sp->ptr = addr;
	return *sp->ptr;
}


/*
 *  non-spooling non-interrupting get and put
 */
int
sccgetc(void)
{
	uchar ch;
	SCC *sp;

	sp = &scc[1];
	while((*sp->ptr&RxReady) == 0)
		;
	return *sp->data;
}
void
sccputc(int ch)
{
	SCC *sp;

	sp = &scc[1];
	while((*sp->ptr&TxReady)==0)
		;
	*sp->data = ch;
}
void
sccputs(char *s)
{
	while(*s)
		sccputc(*s++);
}

A ss/ureg.h => ss/ureg.h +23 -0
@@ 0,0 1,23 @@
struct Ureg
{
	ulong	r0;
	ulong	r1;
	ulong	r2;
	ulong	r3;
	ulong	r4;
	ulong	r5;
	ulong	r6;
	ulong	r7;
	ulong	a0;
	ulong	a1;
	ulong	a2;
	ulong	a3;
	ulong	a4;
	ulong	a5;
	ulong	a6;
	ulong	sp;
	ulong	usp;
	ushort	sr;
	ulong	pc;
	ushort	vo;
};