Browse Source

Plan 9 from Bell Labs 2013-01-25

David du Colombier 11 years ago
parent
commit
91d8c86336
65 changed files with 958 additions and 210 deletions
  1. 15 0
      adm/timezone/Uruguay
  2. 73 3
      lib/ndb/common
  3. 1 1
      sys/lib/dist/cmd/bargraph.c
  4. 0 1
      sys/lib/dist/cmd/bzfs/unbzip.c
  5. 10 0
      sys/man/1/8l
  6. 5 2
      sys/man/1/pcc
  7. 4 8
      sys/man/8/init
  8. BIN
      sys/src/9/bitsy/clock.5
  9. BIN
      sys/src/9/bitsy/defont.5
  10. BIN
      sys/src/9/bitsy/fpi.5
  11. BIN
      sys/src/9/bitsy/l.5
  12. 0 2
      sys/src/9/mtx/etherif.h
  13. 9 0
      sys/src/9/mtx/mem.h
  14. 2 1
      sys/src/9/mtx/trap.c
  15. 6 0
      sys/src/9/omap/arm.h
  16. 1 0
      sys/src/9/omap/fns.h
  17. 6 2
      sys/src/9/omap/l.s
  18. 17 1
      sys/src/9/omap/trap.c
  19. 23 8
      sys/src/9/pc/ether82563.c
  20. 2 2
      sys/src/9/port/devtls.c
  21. 2 2
      sys/src/9/teg2/_announce
  22. 2 1
      sys/src/9/teg2/dat.h
  23. 6 2
      sys/src/9/teg2/fpiarm.c
  24. 21 6
      sys/src/9/teg2/trap.c
  25. 4 4
      sys/src/9/teg2/ts
  26. 66 39
      sys/src/9/teg2/vfp3.c
  27. 2 2
      sys/src/9/teg2/words
  28. 9 7
      sys/src/ape/cmd/make/defs.h
  29. 1 1
      sys/src/ape/cmd/make/doname.c
  30. 2 1
      sys/src/ape/cmd/make/gram.y
  31. 4 2
      sys/src/ape/cmd/make/misc.c
  32. 1 1
      sys/src/ape/lib/bsd/_sock_ingetaddr.c
  33. 9 3
      sys/src/cmd/5c/txt.c
  34. 118 0
      sys/src/cmd/5l/asm.c
  35. 3 0
      sys/src/cmd/5l/l.h
  36. 24 0
      sys/src/cmd/5l/noop.c
  37. 8 0
      sys/src/cmd/5l/optab.c
  38. 10 1
      sys/src/cmd/5l/span.c
  39. 35 24
      sys/src/cmd/acme/xfid.c
  40. 6 2
      sys/src/cmd/disk/9660/dump9660.c
  41. 8 2
      sys/src/cmd/htmlfmt/html.c
  42. 3 3
      sys/src/cmd/jpg/readpng.c
  43. 1 1
      sys/src/cmd/jpg/writepng.c
  44. 1 1
      sys/src/cmd/mk/archive.c
  45. 4 3
      sys/src/cmd/pcc.c
  46. 0 1
      sys/src/cmd/pic/makefile
  47. 1 0
      sys/src/cmd/plumb/plumber.c
  48. 3 0
      sys/src/cmd/plumb/rules.c
  49. 2 1
      sys/src/cmd/unix/u9fs/fcallconv.c
  50. 18 7
      sys/src/cmd/usb/kb/hid.c
  51. 5 3
      sys/src/cmd/usb/kb/hid.h
  52. 30 30
      sys/src/cmd/usb/kb/kb.c
  53. 2 1
      sys/src/cmd/usb/serial/main.c
  54. 1 1
      sys/src/cmd/usb/serial/mkfile
  55. 16 5
      sys/src/cmd/usb/serial/serial.c
  56. 146 0
      sys/src/cmd/usb/serial/silabs.c
  57. 3 0
      sys/src/cmd/usb/serial/silabs.h
  58. 3 1
      sys/src/libc/fmt/runevsmprint.c
  59. 3 1
      sys/src/libc/fmt/vsmprint.c
  60. 1 0
      sys/src/libc/port/runestrdup.c
  61. 1 0
      sys/src/libc/port/strdup.c
  62. 1 1
      sys/src/libdraw/init.c
  63. 165 1
      sys/src/libmach/5db.c
  64. 27 18
      sys/src/libplumb/mesg.c
  65. 6 0
      sys/src/libventi/rpc.c

+ 15 - 0
adm/timezone/Uruguay

@@ -0,0 +1,15 @@
+UYT -10800 UYST -7200
+ 250052400  260244000  307594800  325994400  566449200  574308000 
+ 597812400  605671200  625633200  636516000  656478000  667965600 
+ 688532400  699415200  719377200  730864800 1095562800 1111896000
+1128834000 1142136000 1159678800 1173585600 1191733200 1205035200
+1223182800 1236484800 1254632400 1268539200 1286082000 1299988800
+1317531600 1331438400 1349586000 1362888000 1381035600 1394337600
+1412485200 1425787200 1443934800 1457841600 1475384400 1489291200
+1506834000 1520740800 1538888400 1552190400 1570338000 1583640000
+1601787600 1615694400 1633237200 1647144000 1664686800 1678593600
+1696136400 1710043200 1728190800 1741492800 1759640400 1772942400
+1791090000 1804996800 1822539600 1836446400 1853989200 1867896000
+1886043600 1899345600 1917493200 1930795200 1948942800 1962849600
+1980392400 1994299200 2011842000 2025748800 2043291600 2057198400
+2075346000 2088648000 2106795600 2120097600

+ 73 - 3
lib/ndb/common

@@ -6,20 +6,21 @@
 # real dns root server ips
 #
 dom=a.root-servers.net ip=198.41.0.4
-dom=b.root-servers.net ip=128.9.0.107
+dom=b.root-servers.net ip=192.228.79.201
 dom=c.root-servers.net ip=192.33.4.12
-dom=d.root-servers.net ip=128.8.10.90
+dom=d.root-servers.net ip=199.7.91.13
 dom=e.root-servers.net ip=192.203.230.10
 dom=f.root-servers.net ip=192.5.5.241
 dom=g.root-servers.net ip=192.112.36.4
 dom=h.root-servers.net ip=128.63.2.53
 dom=i.root-servers.net ip=192.36.148.17
-dom=j.root-servers.net ip=198.41.0.10
+dom=j.root-servers.net ip=192.58.128.30
 dom=k.root-servers.net ip=193.0.14.129
 dom=l.root-servers.net ip=199.7.83.42		# nov 2007
 dom=m.root-servers.net ip=202.12.27.33
 
 # dom=a.root-servers.net ipv6=2001:503:ba3e::2:30
+# dom=d.root-servers.net ipv6=2001:500:2d::d
 # dom=f.root-servers.net ipv6=2001:500:2f::f
 # dom=h.root-servers.net ipv6=2001:500:1::803f:235
 # dom=i.root-servers.net ipv6=2001:7fe::53
@@ -202,6 +203,7 @@ tcp=time port=37
 tcp=whois port=43
 tcp=dns port=53
 tcp=domain port=53
+tcp=dns-test port=54	# localism
 tcp=uucp port=64
 tcp=gopher port=70
 tcp=rje port=77
@@ -248,6 +250,7 @@ tcp=guard port=566
 tcp=ticket port=567
 tcp=ldaps port=636
 tcp=fmclient port=729
+tcp=iscsi-system port=860
 tcp=ftps-data port=989
 tcp=ftps port=990
 tcp=imaps port=993
@@ -257,6 +260,7 @@ tcp=pptp port=1723
 tcp=nfs port=2049
 tcp=webster port=2627
 tcp=weather port=3000
+tcp=iscsi port=3260
 tcp=mysql port=3306
 tcp=sip port=5060
 tcp=sips port=5061
@@ -275,6 +279,7 @@ tcp=inflogin port=6673
 tcp=bandt port=7330
 tcp=ccnx port=9695
 tcp=dhashgate port=11978
+tcp=piepea port=13146	# πp
 tcp=exportfs port=17007
 tcp=rexexec port=17009
 tcp=ncpu port=17010
@@ -308,6 +313,7 @@ udp=bootp port=67
 udp=bootps port=67
 udp=domain port=53
 udp=dns port=53
+udp=dns-test port=54		# localism
 udp=portmap port=111
 udp=ntp port=123
 udp=netbios-ns port=137
@@ -330,6 +336,7 @@ udp=dhash port=11977
 udp=ulctl port=12666
 udp=uldata port=12667
 udp=dldata port=12668
+udp=piepea port=13146	# πp
 
 gre=ppp port=34827
 
@@ -358,6 +365,69 @@ auth=whale.lsub.org
 # for jmk
 auth=tor.texas.9grid.us authdom=9grid.us
 auth=9grid.net authdom=9grid.net
+auth=ibmremote.dyndns.org
+	authdom=ibmremote.dyndns.org
+	authdom=austin.ibm.com
 
 # for sape
 auth=130.89.145.31 authdom=cs.utwente.nl
+
+# for quanstro
+auth=tyty.coraid.com authdom=coraid.com
+auth=ladd.quanstro.net authdom=plan9.quanstro.net
+
+# for noah
+auth=172.17.3.23 authdom=plan9.anl.gov
+
+#
+# ipv6 networks
+#
+ipnet=all-v6 ip=:: ipmask=/0
+	fs=pie.cs.bell-labs.com			# was v6
+	venti=pie.cs.bell-labs.com		# was v6
+	cpu=fish				# was v6
+	ntp=chips
+	ntp=time1.net.lucent.com
+	dnsdomain=cs.bell-labs.com
+	dnsdomain=research.bell-labs.com
+	dnsdomain=bell-labs.com
+	radius=lra-radius
+	smtp=chipsv6.cs.bell-labs.com
+	dns=chipsv6
+	auth=p9authv6.cs.bell-labs.com
+	authdom=cs.bell-labs.com
+#
+# contact: Deborah Hogan
+# sub-allocations done by thomas.galuschka@hp.com
+#
+ipnet=lucent-v6 ip=2620:0:60:: ipmask=/48
+	fs=pie.cs.bell-labs.com			# was v6
+	venti=pie.cs.bell-labs.com		# was v6
+	cpu=fish				# was v6
+	ntp=chips
+	ntp=time1.net.lucent.com
+	dnsdomain=cs.bell-labs.com
+	dnsdomain=research.bell-labs.com
+	dnsdomain=bell-labs.com
+	radius=lra-radius
+	smtp=chipsv6.cs.bell-labs.com
+	dns=chipsv6
+	auth=p9authv6.cs.bell-labs.com
+	authdom=cs.bell-labs.com
+#
+# contact: Alastair Johnson
+#
+ipnet=alu-asia-pac-v6 ip=2406:c800:: ipmask=/32
+	fs=pie.cs.bell-labs.com			# was v6
+	venti=pie.cs.bell-labs.com		# was v6
+	cpu=fish				# was v6
+	ntp=chips
+	ntp=time1.net.lucent.com
+	dnsdomain=cs.bell-labs.com
+	dnsdomain=research.bell-labs.com
+	dnsdomain=bell-labs.com
+	radius=lra-radius
+	smtp=chipsv6.cs.bell-labs.com
+	dns=chipsv6
+	auth=p9authv6.cs.bell-labs.com
+	authdom=cs.bell-labs.com

+ 1 - 1
sys/lib/dist/cmd/bargraph.c

@@ -40,7 +40,7 @@ drawbar(void)
 {
 	int i, j;
 	int p;
-	char buf[200], bar[100], *s;
+	char buf[200], bar[100];
 	static char lastbar[100];
 
 	if(n > d || n < 0 || d <= 0)

+ 0 - 1
sys/lib/dist/cmd/bzfs/unbzip.c

@@ -302,7 +302,6 @@ getbits(DState *s, int lll, int *vvv, int nnn)
 		if (s->strm->total_in_lo32 == 0)
 			s->strm->total_in_hi32++;
 	}
-	return -1;	/* KEN */
 }
 
 #define GET_UCHAR(lll,uuu)                        \

+ 10 - 0
sys/man/1/8l

@@ -150,6 +150,16 @@ and
 only)
 Move strings into the text segment.
 .TP
+.B -f
+(\c
+.I 5l
+only)
+Generate VFP hardware floating-point instructions.
+Without this option,
+.I 5l
+generates arm7500 floating-point
+instructions which are emulated in the kernel.
+.TP
 .BI -H n
 Executable header is type
 .IR n .

+ 5 - 2
sys/man/1/pcc

@@ -24,7 +24,7 @@ as specified by the environment variable
 The object files are then loaded using one of the loaders described in
 .IR 8l (1).
 The options are:
-.TP \w'\fL-D\ \fIname=def\ 'u
+.TP \w'\fL-D\ \fIname\ 'u
 .B "-+
 Accept C++
 .B //
@@ -137,6 +137,9 @@ Enable vararg type checking as described in
 This is of limited use without the appropriate 
 .B #pragma 
 definitions.
+.TP
+.B -f
+(ARM only) Generate VFP hardware floating point instructions.
 .PP
 The APE environment contains all of the include
 files and library routines specified in the ANSI C standard
@@ -170,7 +173,7 @@ ANSI C/POSIX library.
 .IR acid (1),
 .IR db (1),
 .IR prof (1)
-.PP
+.br
 Howard Trickey,
 ``APE \(em The ANSI/POSIX Environment''
 .SH SOURCE

+ 4 - 8
sys/man/8/init

@@ -37,19 +37,15 @@ and
 .B -c
 (CPU)
 force the behavior to correspond to the specified service class.
-Otherwise
-.I init
-uses the value of the environment variable
-.B $service
-to decide the service class.
+Otherwise the default is CPU.
 .PP
 .I Init
 sets environment variables
 .B $service
-(either to the incoming value or according to
-.B -t
+(to
+.L terminal
 or
-.BR -c ),
+.LR cpu ),
 .B $objtype
 (to the value of
 .BR $cputype ),

BIN
sys/src/9/bitsy/clock.5


BIN
sys/src/9/bitsy/defont.5


BIN
sys/src/9/bitsy/fpi.5


BIN
sys/src/9/bitsy/l.5


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

@@ -31,5 +31,3 @@ extern ulong ethercrc(uchar*, int);
 
 #define NEXT(x, l)	(((x)+1)%(l))
 #define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1)
-#define	HOWMANY(x, y)	(((x)+((y)-1))/(y))
-#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))

+ 9 - 0
sys/src/9/mtx/mem.h

@@ -1,6 +1,15 @@
 /*
  * Memory and machine-specific definitions.  Used in C and assembler.
  */
+#define KiB		1024u			/* Kibi 0x0000000000000400 */
+#define MiB		1048576u		/* Mebi 0x0000000000100000 */
+#define GiB		1073741824u		/* Gibi 000000000040000000 */
+
+#define HOWMANY(x, y)	(((x)+((y)-1))/(y))
+#define ROUNDUP(x, y)	(HOWMANY((x), (y))*(y))	/* ceiling */
+#define ROUNDDN(x, y)	(((x)/(y))*(y))		/* floor */
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#define MAX(a, b)	((a) > (b)? (a): (b))
 
 /*
  * Sizes

+ 2 - 1
sys/src/9/mtx/trap.c

@@ -640,7 +640,8 @@ syscall(Ureg* ureg)
 	ret = -1;
 	if(!waserror()){
 		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
+			pprint("bad sys call number %lud pc %lux\n",
+				scallnr, ureg->pc);
 			postnote(up, 1, "sys: bad sys call", NDebug);
 			error(Ebadarg);
 		}

+ 6 - 0
sys/src/9/omap/arm.h

@@ -57,6 +57,12 @@
 #define CpTTB1		1			/* cortex */
 #define CpTTBctl	2			/* cortex */
 
+/*
+ * CpFSR op1==0, Crm==0 opcode 2 values.
+ */
+#define CpDFSR		0			/* data fault status */
+#define CpIFSR		1			/* instruction fault status */
+
 /*
  * CpID Secondary (CRm) registers.
  */

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

@@ -50,6 +50,7 @@ extern u32int fsrget(void);
 extern u32int getscr(void);
 extern u32int getpsr(void);
 extern ulong getwayssets(void);
+extern u32int ifsrget(void);
 extern void intrsoff(void);
 extern int isaconfig(char*, int, ISAConf*);
 extern int isdmadone(int);

+ 6 - 2
sys/src/9/omap/l.s

@@ -474,8 +474,12 @@ TEXT dacput(SB), 1, $-4				/* domain access control */
 	ISB
 	RET
 
-TEXT fsrget(SB), 1, $-4				/* fault status */
-	MRC	CpSC, 0, R0, C(CpFSR), C(0)
+TEXT fsrget(SB), 1, $-4				/* data fault status */
+	MRC	CpSC, 0, R0, C(CpFSR), C(0), CpDFSR
+	RET
+
+TEXT ifsrget(SB), 1, $-4			/* instruction fault status */
+	MRC	CpSC, 0, R0, C(CpFSR), C(0), CpIFSR
 	RET
 
 TEXT farget(SB), 1, $-4				/* fault address */

+ 17 - 1
sys/src/9/omap/trap.c

@@ -493,7 +493,23 @@ trap(Ureg *ureg)
 		break;
 	case PsrMabt:			/* prefetch fault */
 		ldrexvalid = 0;
-		faultarm(ureg, ureg->pc, user, 1);
+		x = ifsrget();
+		fsr = (x>>7) & 0x8 | x & 0x7;
+		switch(fsr){
+		case 0x02:		/* instruction debug event (BKPT) */
+			if(user){
+				snprint(buf, sizeof buf, "sys: breakpoint");
+				postnote(up, 1, buf, NDebug);
+			}else{
+				iprint("kernel bkpt: pc %#lux inst %#ux\n",
+					ureg->pc, *(u32int*)ureg->pc);
+				panic("kernel bkpt");
+			}
+			break;
+		default:
+			faultarm(ureg, ureg->pc, user, 1);
+			break;
+		}
 		break;
 	case PsrMabt+1:			/* data fault */
 		ldrexvalid = 0;

+ 23 - 8
sys/src/9/pc/ether82563.c

@@ -1,7 +1,6 @@
 /*
  * Intel Gigabit Ethernet PCI-Express Controllers.
- *	8256[36], 8257[124], 82573[ev]
- *	82575eb, 82576, 82577
+ *	8256[36], 8257[1-79]
  * Pretty basic, does not use many of the chip smarts.
  * The interrupt mitigation tuning for each chip variant
  * is probably different. The reset/initialisation
@@ -59,7 +58,7 @@ enum {
 	/* Receive */
 
 	Rctl		= 0x0100,	/* Control */
-	Ert		= 0x2008,	/* Early Receive Threshold (573[EVL] only) */
+	Ert		= 0x2008,	/* Early Receive Threshold (573[EVL], 579 only) */
 	Fcrtl		= 0x2160,	/* Flow Control RX Threshold Low */
 	Fcrth		= 0x2168,	/* Flow Control Rx Threshold High */
 	Psrctl		= 0x2170,	/* Packet Split Receive Control */
@@ -427,6 +426,7 @@ enum {
 	i82575,
 	i82576,
 	i82577,
+	i82579,
 };
 
 static int rbtab[] = {
@@ -441,6 +441,7 @@ static int rbtab[] = {
 	1514,
 	1514,
 	1514,
+	9018,
 };
 
 static char *tname[] = {
@@ -455,6 +456,7 @@ static char *tname[] = {
 	"i82575",
 	"i82576",
 	"i82577",
+	"i82579",
 };
 
 typedef struct Ctlr Ctlr;
@@ -995,7 +997,7 @@ i82563rxinit(Ctlr* ctlr)
 	}
 	csr32w(ctlr, Rctl, rctl);
 
-	if(ctlr->type == i82573 || ctlr->type == i82577)
+	if(ctlr->type == i82573 || ctlr->type == i82577 || ctlr->type == i82579)
 		csr32w(ctlr, Ert, 1024/8);
 
 	if(ctlr->type == i82566 || ctlr->type == i82567)
@@ -1375,7 +1377,7 @@ i82563detach(Ctlr* ctlr)
 	delay(10);
 
 	r = csr32r(ctlr, Ctrl);
-	if(ctlr->type == i82566 || ctlr->type == i82567)
+	if(ctlr->type == i82566 || ctlr->type == i82567 || ctlr->type == i82579)
 		r |= Phyrst;
 	csr32w(ctlr, Ctrl, Devrst | r);
 	delay(1);
@@ -1519,7 +1521,7 @@ fload(Ctlr *c)
 	f.sz = f.reg32[Bfpr];
 	r = f.sz & 0x1fff;
 	if(csr32r(c, Eec) & (1<<22))
-		++r;
+		r += c->type == i82579? 16 : 1;
 	r <<= 12;
 
 	sum = 0;
@@ -1541,7 +1543,8 @@ i82563reset(Ctlr *ctlr)
 
 	if(i82563detach(ctlr))
 		return -1;
-	if(ctlr->type == i82566 || ctlr->type == i82567 || ctlr->type == i82577)
+	if(ctlr->type == i82566 || ctlr->type == i82567 ||
+	   ctlr->type == i82577 || ctlr->type == i82579)
 		r = fload(ctlr);
 	else
 		r = eeload(ctlr);
@@ -1578,7 +1581,8 @@ i82563reset(Ctlr *ctlr)
 	 */
 	csr32w(ctlr, Fcal, 0x00C28001);
 	csr32w(ctlr, Fcah, 0x0100);
-	csr32w(ctlr, Fct, 0x8808);
+	if(ctlr->type != i82579)
+		csr32w(ctlr, Fct, 0x8808);
 	csr32w(ctlr, Fcttv, 0x0100);
 
 	ctlr->fcrtl = ctlr->fcrth = 0;
@@ -1648,6 +1652,10 @@ i82563pci(void)
 		case 0x10ea:		/* 82577lm */
 			type = i82577;
 			break;
+		case 0x1502:		/* 82579lm */
+		case 0x1503:		/* 82579v */
+			type = i82579;
+			break;
 		}
 
 		io = p->mem[0].bar & ~0x0F;
@@ -1779,6 +1787,12 @@ i82575pnp(Ether *e)
 	return pnp(e, i82575);
 }
 
+static int
+i82579pnp(Ether *e)
+{
+	return pnp(e, i82579);
+}
+
 void
 ether82563link(void)
 {
@@ -1789,5 +1803,6 @@ ether82563link(void)
 	addethercard("i82572", i82572pnp);
 	addethercard("i82573", i82573pnp);
 	addethercard("i82575", i82575pnp);
+	addethercard("i82579", i82579pnp);
 	addethercard("igbepcie", anypnp);
 }

+ 2 - 2
sys/src/9/port/devtls.c

@@ -732,7 +732,7 @@ tlsrecread(TlsRec *tr)
 {
 	OneWay *volatile in;
 	Block *volatile b;
-	uchar *p, seq[8], header[RecHdrLen], hmac[MD5dlen];
+	uchar *p, seq[8], header[RecHdrLen], hmac[MaxMacLen];
 	int volatile nconsumed;
 	int len, type, ver, unpad_len;
 
@@ -1323,7 +1323,7 @@ tlsbwrite(Chan *c, Block *b, ulong offset)
 
 	tr = tlsdevs[CONV(c->qid)];
 	if(tr == nil)
-		panic("tlsbread");
+		panic("tlsbwrite");
 
 	ty = TYPE(c->qid);
 	switch(ty) {

+ 2 - 2
sys/src/9/teg2/_announce

@@ -31,8 +31,8 @@ VFP3 floating point.  The go 5l generates VFP 3 floating-point
 instructions (among other changes).  Attempts to transplant just that
 code into our 5l failed to generate correct code.  Eventually someone
 will get this to work, and then we'll be able to use the hardware
-floating-point.  Even with only software emulation of floating-point,
-astro runs in under 3 seconds.
+floating-point.  [Eventually someone did, thanks.]  Even with only
+software emulation of floating-point, astro runs in under 3 seconds.
 
 In-line 64-bit arithmetic in 5[cl].
 

+ 2 - 1
sys/src/9/teg2/dat.h

@@ -95,13 +95,14 @@ struct FPsave
 };
 
 /*
- * FPsave.status
+ * FPsave.fpstate
  */
 enum
 {
 	FPinit,
 	FPactive,
 	FPinactive,
+	FPemu,
 
 	/* bit or'd with the state */
 	FPillegal= 0x100,

+ 6 - 2
sys/src/9/teg2/fpiarm.c

@@ -475,9 +475,13 @@ fpiarm(Ureg *ur)
 	 * because all the emulated fp state is in the proc structure,
 	 * it need not be saved/restored
 	 */
-	if(up->fpstate != FPactive){
+	switch(up->fpstate){
+	case FPactive:
+	case FPinactive:
+		error("illegal instruction: emulated fpu opcode in VFP mode");
+	case FPinit:
 		assert(sizeof(Internal) <= sizeof(ufp->regs[0]));
-		up->fpstate = FPactive;
+		up->fpstate = FPemu;
 		ufp->control = 0;
 		ufp->status = (0x01<<28)|(1<<12); /* sw emulation, alt. C flag */
 		for(n = 0; n < 8; n++)

+ 21 - 6
sys/src/9/teg2/trap.c

@@ -815,7 +815,7 @@ void
 trap(Ureg *ureg)
 {
 	int clockintr, user, rem;
-	uintptr va, ifar;
+	uintptr va, ifar, ifsr;
 
 	splhi();			/* paranoia */
 	if(up != nil)
@@ -860,11 +860,26 @@ trap(Ureg *ureg)
 		break;
 	case PsrMabt:			/* prefetch (instruction) fault */
 		va = ureg->pc;
-		ifar = cprdsc(0, CpFAR, 0, CpIFAR);
-		if (va != ifar)
-			iprint("trap: cpu%d: i-fault va %#p != ifar %#p\n",
-				m->machno, va, ifar);
-		faultarm(ureg, va, user, 1);
+		ifsr = cprdsc(0, CpFSR, 0, CpIFSR);
+		ifsr = (ifsr>>7) & 0x8 | ifsr & 0x7;
+		switch(ifsr){
+		case 0x02:		/* instruction debug event (BKPT) */
+			if(user)
+				postnote(up, 1, "sys: breakpoint", NDebug);
+			else{
+				iprint("kernel bkpt: pc %#lux inst %#ux\n",
+					va, *(u32int*)va);
+				panic("kernel bkpt");
+			}
+			break;
+		default:
+			ifar = cprdsc(0, CpFAR, 0, CpIFAR);
+			if (va != ifar)
+				iprint("trap: cpu%d: i-fault va %#p != ifar %#p\n",
+					m->machno, va, ifar);
+			faultarm(ureg, va, user, 1);
+			break;
+		}
 		break;
 	case PsrMabt+1:			/* data fault */
 		datafault(ureg, user);

+ 4 - 4
sys/src/9/teg2/ts

@@ -68,13 +68,13 @@ misc
 	uarti8250
 	ucalloc
 	ucallocb
-# hardware fp; can't get 5l to generate the right opcodes
-#	vfp3
-# emulated fp
+# include vfp3 to use hardware fp, otherwise include softfpu
+	vfp3
+#	softfpu
+# emulated arm7500 fp
 	fpi
 	fpiarm
 	fpimem
-	softfpu
 
 port
 	int cpuserver = 1;

+ 66 - 39
sys/src/9/teg2/vfp3.c

@@ -1,5 +1,5 @@
 /*
- * VFPv3 floating point unit
+ * VFPv2 or VFPv3 floating point unit
  */
 #include "u.h"
 #include "../port/lib.h"
@@ -9,6 +9,12 @@
 #include "ureg.h"
 #include "arm.h"
 
+/* subarchitecture code in m->havefp */
+enum {
+	VFPv2	= 2,
+	VFPv3	= 3,
+};
+
 /* fp control regs.  most are read-only */
 enum {
 	Fpsid =	0,
@@ -16,8 +22,8 @@ enum {
 	Mvfr1 =	6,
 	Mvfr0 =	7,
 	Fpexc =	8,			/* rw */
-	Fpinst =9,			/* optional, for exceptions */
-	Fpinst2 =10,
+	Fpinst= 9,			/* optional, for exceptions */
+	Fpinst2=10,
 };
 enum {
 	/* Fpexc bits */
@@ -34,12 +40,16 @@ enum {
 	/* Fpscr bits; see u.h for more */
 	Stride =	MASK(2) << 20,
 	Len =		MASK(3) << 16,
+	Dn=		1 << 25,
+	Fz=		1 << 24,
 	/* trap exception enables (not allowed in vfp3) */
 	FPIDNRM =	1 << 15,	/* input denormal */
 	Alltraps = FPIDNRM | FPINEX | FPUNFL | FPOVFL | FPZDIV | FPINVAL,
 	/* pending exceptions */
 	FPAIDNRM =	1 << 7,		/* input denormal */
-#define Allexc (FPAIDNRM | FPAINEX | FPAUNFL | FPAOVFL | FPAZDIV | FPAINVAL)
+	Allexc = FPAIDNRM | FPAINEX | FPAUNFL | FPAOVFL | FPAZDIV | FPAINVAL,
+	/* condition codes */
+	Allcc =		MASK(4) << 28,
 };
 enum {
 	/* CpCPaccess bits */
@@ -51,8 +61,8 @@ static char *
 subarch(int impl, uint sa)
 {
 	static char *armarchs[] = {
-		"VFPv1 (pre-armv7)",
-		"VFPv2 (pre-armv7)",
+		"VFPv1 (unsupported)",
+		"VFPv2",
 		"VFPv3+ with common VFP subarch v2",
 		"VFPv3+ with null subarch",
 		"VFPv3+ with common VFP subarch v3",
@@ -77,7 +87,7 @@ static int
 havefp(void)
 {
 	int gotfp;
-	ulong acc;
+	ulong acc, sid;
 
 	if (m->havefpvalid)
 		return m->havefp;
@@ -99,14 +109,24 @@ havefp(void)
 		m->havefpvalid = 1;
 		return 0;
 	}
-	if (acc & Cpaccd16)
+	m->fpon = 1;			/* don't panic */
+	sid = fprd(Fpsid);
+	m->fpon = 0;
+	switch((sid >> 16) & MASK(7)){
+	case 0:				/* VFPv1 */
+		break;
+	case 1:				/* VFPv2 */
+		m->havefp = VFPv2;
 		m->fpnregs = 16;
-	else
-		m->fpnregs = 32;
+		break;
+	default:			/* VFPv3 or later */
+		m->havefp = VFPv3;
+		m->fpnregs = (acc & Cpaccd16) ? 16 : 32;
+		break;
+	}
 	if (m->machno == 0)
 		print("fp: %d registers,%s simd\n", m->fpnregs,
 			(acc & Cpaccnosimd? " no": ""));
-	m->havefp = 1;
 	m->havefpvalid = 1;
 	return 1;
 }
@@ -143,7 +163,7 @@ fpcfg(void)
 	static int printed;
 
 	/* clear pending exceptions; no traps in vfp3; all v7 ops are scalar */
-	m->fpscr = FPRNR | (FPINVAL | FPZDIV | FPOVFL) & ~Alltraps;
+	m->fpscr = Dn | Fz | FPRNR | (FPINVAL | FPZDIV | FPOVFL) & ~Alltraps;
 	fpwr(Fpscr, m->fpscr);
 	m->fpconfiged = 1;
 
@@ -151,7 +171,7 @@ fpcfg(void)
 		return;
 	sid = fprd(Fpsid);
 	impl = sid >> 24;
-	print("fp: %s arch %s; r%ld\n", implement(impl),
+	print("fp: %s arch %s; rev %ld\n", implement(impl),
 		subarch(impl, (sid >> 16) & MASK(7)), sid & MASK(4));
 	printed = 1;
 }
@@ -171,7 +191,7 @@ fpon(void)
 	if (havefp()) {
 	 	fpononly();
 		if (m->fpconfiged)
-			fpwr(Fpscr, m->fpscr);
+			fpwr(Fpscr, (fprd(Fpscr) & Allcc) | m->fpscr);
 		else
 			fpcfg();	/* 1st time on this fpu; configure it */
 	}
@@ -260,6 +280,19 @@ fpsave(FPsave *fps)
 	fpoff();
 }
 
+static void
+fprestore(Proc *p)
+{
+	int n;
+
+	fpon();
+	fpwr(Fpscr, p->fpsave.control);
+	m->fpscr = fprd(Fpscr) & ~Allcc;
+	assert(m->fpnregs);
+	for (n = 0; n < m->fpnregs; n++)
+		fprestreg(n, *(uvlong *)p->fpsave.regs[n]);
+}
+
 /*
  * Called from sched() and sleep() via the machine-dependent
  * procsave() routine.
@@ -295,18 +328,8 @@ fpuprocsave(Proc *p)
  * exception and the state will then be restored.
  */
 void
-fpuprocrestore(Proc *p)
+fpuprocrestore(Proc *)
 {
-	int n;
-
-	if (p->fpstate == FPactive) {
-		fpon();
-		fpwr(Fpscr, p->fpsave.control);
-		m->fpscr = fprd(Fpscr);
-		assert(m->fpnregs);
-		for (n = 0; n < m->fpnregs; n++)
-			fprestreg(n, *(uvlong *)p->fpsave.regs[n]);
-	}
 }
 
 /*
@@ -353,9 +376,9 @@ mathnote(void)
 static void
 mathemu(Ureg *)
 {
-	if (!(fprd(Fpexc) & (Fpex|Fpdex)))
-		iprint("mathemu: not an FP exception but an unknown FP opcode\n");
 	switch(up->fpstate){
+	case FPemu:
+		error("illegal instruction: VFP opcode in emulated mode");
 	case FPinit:
 		fpinit();
 		up->fpstate = FPactive;
@@ -372,7 +395,7 @@ mathemu(Ureg *)
 			mathnote();
 			break;
 		}
-		fpuprocrestore(up);
+		fprestore(up);
 		up->fpstate = FPactive;
 		break;
 	case FPactive:
@@ -450,13 +473,10 @@ condok(int cc, int c)
 int
 fpuemu(Ureg* ureg)
 {
-	int s, nfp;
-	int cop, op;
+	int s, nfp, cop, op;
 	uintptr pc;
 
-	s = spllo();
 	if(waserror()){
-		splx(s);
 		postnote(up, 1, up->errstr, NDebug);
 		return 1;
 	}
@@ -471,18 +491,25 @@ fpuemu(Ureg* ureg)
 		iprint("fpuemu: conditional instr shouldn't have got here\n");
 	op  = (*(ulong *)pc >> 24) & MASK(4);
 	cop = (*(ulong *)pc >>  8) & MASK(4);
-	fpstuck(pc);			/* debugging; could move down 1 line */
+	if(m->fpon)
+		fpstuck(pc);		/* debugging; could move down 1 line */
 	if (ISFPAOP(cop, op)) {		/* old arm 7500 fpa opcode? */
-		iprint("fpuemu: fpa instr %#8.8lux at %#p\n", *(ulong *)pc, pc);
-		error("illegal instruction: old arm 7500 fpa opcode");
-//		nfp = fpiarm(ureg);	/* advances pc past emulated instr(s) */
-//		if (nfp > 1)		/* could adjust this threshold */
-//			m->fppc = m->fpcnt = 0;
+//		iprint("fpuemu: fpa instr %#8.8lux at %#p\n", *(ulong *)pc, pc);
+//		error("illegal instruction: old arm 7500 fpa opcode");
+		s = spllo();
+		if(waserror()){
+			splx(s);
+			nexterror();
+		}
+		nfp = fpiarm(ureg);	/* advances pc past emulated instr(s) */
+		if (nfp > 1)		/* could adjust this threshold */
+			m->fppc = m->fpcnt = 0;
+		splx(s);
+		poperror();
 	} else 	if (ISVFPOP(cop, op)) {	/* if vfp, fpu must be off */
 		mathemu(ureg);		/* enable fpu & retry */
 		nfp = 1;
 	}
-	splx(s);
 
 	poperror();
 	return nfp;

+ 2 - 2
sys/src/9/teg2/words

@@ -5,7 +5,7 @@ dram is 1GB at 0.
 linux believes that u-boot runs in the bottom 4MB.
 the l2 cache is a non-architectural bag nailed on the side.
 mp arm systems have a generic interrupt controller; this one is gic v1(!).
-vfp 3 floating-point is present.  5l doesn't yet generate those instructions.
+vfp 3 floating-point is present.
 
 section numbers (§) are in the tegra 2 tech. ref. man.
 for a minimal cpu server, need these devices to work:
@@ -19,7 +19,7 @@ for a minimal cpu server, need these devices to work:
 then add these:
 ☑	2nd cpu (cortex.a9.mpcore.pdf),
 ☑	l2 cache (l2cache.pl310.pdf, errata),
-☹	fpu (cortex.a9.fp.pdf): kernel done, 5l isn't,
+☑	fpu (cortex.a9.fp.pdf),
 ☑	user profiling,
 	kprof,
 	in-line 64-bit arithmetic,

+ 9 - 7
sys/src/ape/cmd/make/defs.h

@@ -27,12 +27,14 @@ typedef char flag;	/* represent a few bit flag */
 #define NLEFTS	512
 #define NCHARS	500
 #define NINTS	250
-#define INMAX	20000
-#define OUTMAX	20000
-#define QBUFMAX	20000
-#define MAXDIR	10
-#define MAXPROC	100
-#define MAXINCLUDE	17
+
+/* cranked these up, we're not on the pdp-11 any more */
+#define INMAX	80000
+#define OUTMAX	80000
+#define QBUFMAX	80000
+#define MAXDIR	30
+#define MAXPROC	200
+#define MAXINCLUDE	32
 #define PROCLIMIT	3
 
 #define ALLDEPS	1
@@ -196,7 +198,7 @@ extern char	*copys(char *);
 extern char	*concat(char *, char *, char *);
 extern int	suffix(char *, char *, char *);
 extern int	*ckalloc(int);
-extern char	*subst(char *, char *);
+extern char	*subst(char *, char *, char *);
 extern void	setvar(char *, char *, int);
 extern void	set3var(char *, char *);
 extern int	eqsign(char *);

+ 1 - 1
sys/src/ape/cmd/make/doname.c

@@ -288,7 +288,7 @@ if(nproc1 < nproc)
 
 for( ; q ; q = q->nxtshblock )
 	{
-	subst(q->shbp,string);
+	subst(q->shbp, string, &string[sizeof string - 1]);
 	ign = ignerr;
 	nopr = NO;
 	doit = NO;

+ 2 - 1
sys/src/ape/cmd/make/gram.y

@@ -377,7 +377,8 @@ lastchp = t;
 lastch = *t;
 *t = '\0';	/* replace the semi with a null so subst will stop */
 
-subst(yytext, templin);		/* Substitute for macros on dependency lines */
+/* Substitute for macros on dependency lines */
+subst(yytext, templin, &templin[sizeof templin - 1]);
 
 if(lastch)	/* copy the stuff after the semicolon */
 	{

+ 4 - 2
sys/src/ape/cmd/make/misc.c

@@ -195,7 +195,7 @@ return 0;
 
 /* copy string a into b, substituting for arguments */
 char *
-subst(char *a, char *b)
+subst(char *a, char *b, char *e)
 {
 static depth	= 0;
 char *s;
@@ -226,10 +226,12 @@ if(a)  while(*a)
 		*s = '\0';
 		if( (vbp = varptr(vname)) ->varval != 0)
 			{
-			b = subst(vbp->varval, b);
+			b = subst(vbp->varval, b, e);
 			vbp->used = YES;
 			}
 		}
+		if(b >= e)
+			fatal("macro expanded too far");
 	}
 
 *b = '\0';

+ 1 - 1
sys/src/ape/lib/bsd/_sock_ingetaddr.c

@@ -35,7 +35,7 @@ _sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
 			if(p){
 				*p++ = 0;
 				ip->sin_family = AF_INET;
-				ip->sin_port = atoi(p);
+				ip->sin_port = htons(atoi(p));
 				ip->sin_addr.s_addr = inet_addr(name);
 				if(alen)
 					*alen = sizeof(struct sockaddr_in);

+ 9 - 3
sys/src/cmd/5c/txt.c

@@ -721,8 +721,13 @@ gmove(Node *f, Node *t)
 			regfree(&nod1);
 			p1 = p;
 			regalloc(&nod, t, Z);
-			gins(AMOVF, nodfconst(2147483648.), &nod);
-			gins(AADDF, &nod, t);
+			if(tt == TFLOAT) {
+				gins(AMOVF, nodfconst(2147483648.), &nod);
+				gins(AADDF, &nod, t);
+			} else {
+				gins(AMOVD, nodfconst(2147483648.), &nod);
+				gins(AADDD, &nod, t);
+			}
 			regfree(&nod);
 			patch(p1, pc);
 			return;
@@ -1056,7 +1061,8 @@ gopcode(int o, Node *f1, Node *f2, Node *t)
 		nextpc();
 		p->as = a;
 		naddr(f1, &p->from);
-		if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
+		if(a == ACMP && f1->op == OCONST && p->from.offset < 0 &&
+		    p->from.offset != 0x80000000) {
 			p->as = ACMN;
 			p->from.offset = -p->from.offset;
 		}

+ 118 - 0
sys/src/cmd/5l/asm.c

@@ -1365,6 +1365,53 @@ PP = p;
 		else if(p->as == AMOVH)
 			o2 ^= (1<<6);
 		break;
+
+	/* VFP ops: */
+	case 74:	/* vfp floating point arith */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		if(p->from.type == D_FCONST) {
+			diag("invalid floating-point immediate\n%P", p);
+			rf = 0;
+		}
+		rt = p->to.reg;
+		r = p->reg;
+		if(r == NREG)
+			r = rt;
+		o1 |= rt<<12;
+		if(((o1>>20)&0xf) == 0xb)
+			o1 |= rf<<0;
+		else
+			o1 |= r<<16 | rf<<0;
+		break;
+	case 75:	/* vfp floating point compare */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		if(p->from.type == D_FCONST) {
+			if(p->from.ieee->h != 0 || p->from.ieee->l != 0)
+				diag("invalid floating-point immediate\n%P", p);
+			o1 |= 1<<16;
+			rf = 0;
+		}
+		rt = p->reg;
+		o1 |= rt<<12 | rf<<0;
+		o2 = 0x0ef1fa10;	/* MRS APSR_nzcv, FPSCR */
+		o2 |= (p->scond & C_SCOND) << 28;
+		break;
+	case 76:	/* vfp floating point fix and float */
+		o1 = opvfprrr(p->as, p->scond);
+		rf = p->from.reg;
+		rt = p->to.reg;
+		if(p->from.type == D_REG) {
+			o2 = o1 | rt<<12 | rt<<0;
+			o1 = 0x0e000a10;	/* VMOV F,R */
+			o1 |= (p->scond & C_SCOND) << 28 | rt<<16 | rf<<12;
+		} else {
+			o1 |= FREGTMP<<12 | rf<<0;
+			o2 = 0x0e100a10;	/* VMOV R,F */
+			o2 |= (p->scond & C_SCOND) << 28 | FREGTMP<<16 | rt<<12;
+		}
+		break;
 	}
 
 	if(debug['a'] > 1)
@@ -1493,6 +1540,40 @@ oprrr(int a, int sc)
 	return 0;
 }
 
+long
+opvfprrr(int a, int sc)
+{
+	long o;
+
+	o = (sc & C_SCOND) << 28;
+	if(sc & (C_SBIT|C_PBIT|C_WBIT))
+		diag(".S/.P/.W on vfp instruction");
+	o |= 0xe<<24;
+	switch(a) {
+	case AMOVWD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+	case AMOVWF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x8<<16 | 1<<7;
+	case AMOVDW:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+	case AMOVFW:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0xD<<16 | 1<<7;
+	case AMOVFD:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+	case AMOVDF:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x7<<16 | 1<<7;
+	case AMOVF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+	case AMOVD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x0<<16 | 0<<7;
+	case ACMPF:	return o | 0xa<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+	case ACMPD:	return o | 0xb<<8 | 0xb<<20 | 1<<6 | 0x4<<16 | 0<<7;
+	case AADDF:	return o | 0xa<<8 | 0x3<<20;
+	case AADDD:	return o | 0xb<<8 | 0x3<<20;
+	case ASUBF:	return o | 0xa<<8 | 0x3<<20 | 1<<6;
+	case ASUBD:	return o | 0xb<<8 | 0x3<<20 | 1<<6;
+	case AMULF:	return o | 0xa<<8 | 0x2<<20;
+	case AMULD:	return o | 0xb<<8 | 0x2<<20;
+	case ADIVF:	return o | 0xa<<8 | 0x8<<20;
+	case ADIVD:	return o | 0xb<<8 | 0x8<<20;
+	}
+	diag("bad vfp rrr %d", a);
+	prasm(curp);
+	return 0;
+}
+
 long
 opbra(int a, int sc)
 {
@@ -1627,11 +1708,46 @@ olhrr(int i, int b, int r, int sc)
 	return olhr(i, b, r, sc) ^ (1<<22);
 }
 
+long
+ovfpmem(int a, int r, long v, int b, int sc, Prog *p)
+{
+	long o;
+
+	if(sc & (C_SBIT|C_PBIT|C_WBIT))
+		diag(".S/.P/.W on VLDR/VSTR instruction");
+	o = (sc & C_SCOND) << 28;
+	o |= 0xd<<24 | (1<<23);
+	if(v < 0) {
+		v = -v;
+		o ^= 1 << 23;
+	}
+	if(v & 3)
+		diag("odd offset for floating point op: %ld\n%P", v, p);
+	else if(v >= (1<<10))
+		diag("literal span too large: %ld\n%P", v, p);
+	o |= (v>>2) & 0xFF;
+	o |= b << 16;
+	o |= r << 12;
+	switch(a) {
+	default:
+		diag("bad fst %A", a);
+	case AMOVD:
+		o |= 0xb<<8;
+		break;
+	case AMOVF:
+		o |= 0xa<<8;
+		break;
+	}
+	return o;
+}
+
 long
 ofsr(int a, int r, long v, int b, int sc, Prog *p)
 {
 	long o;
 
+	if(vfp)
+		return ovfpmem(a, r, v, b, sc, p);
 	if(sc & C_SBIT)
 		diag(".S on FLDR/FSTR instruction");
 	o = (sc & C_SCOND) << 28;
@@ -1703,6 +1819,8 @@ chipfloat(Ieee *e)
 	Ieee *p;
 	int n;
 
+	if(vfp)
+		return -1;
 	for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
 		p = &chipfloats[n];
 		if(p->l == e->l && p->h == e->h)

+ 3 - 0
sys/src/cmd/5l/l.h

@@ -139,6 +139,7 @@ enum
 	LTO		= 1<<1,
 	LPOOL		= 1<<2,
 	V4		= 1<<3,	/* arm v4 arch */
+	VFP		= 1<<4,	/* arm vfpv3 floating point */
 
 	C_NONE		= 0,
 	C_REG,
@@ -274,6 +275,7 @@ EXTERN	char	xcmp[C_GOK+1][C_GOK+1];
 EXTERN	Prog	zprg;
 EXTERN	int	dtype;
 EXTERN	int	armv4;
+EXTERN	int vfp;
 
 EXTERN	int	doexp, dlm;
 EXTERN	int	imports, nimports;
@@ -369,6 +371,7 @@ int	ocmp(const void*, const void*);
 long	opirr(int);
 Optab*	oplook(Prog*);
 long	oprrr(int, int);
+long	opvfprrr(int, int);
 long	olr(long, int, int, int);
 long	olhr(long, int, int, int);
 long	olrr(int, int, int, int);

+ 24 - 0
sys/src/cmd/5l/noop.c

@@ -302,6 +302,30 @@ noops(void)
 
 			break;
 
+		/*
+		 * 5c code generation for unsigned -> double made the
+		 * unfortunate assumption that single and double floating
+		 * point registers are aliased - true for emulated 7500
+		 * but not for vfp.  Now corrected, but this test is
+		 * insurance against old 5c compiled code in libraries.
+		 */
+		case AMOVWD:
+			if((q = p->link) != P && q->as == ACMP)
+			if((q = q->link) != P && q->as == AMOVF)
+			if((q1 = q->link) != P && q1->as == AADDF)
+			if(q1->to.type == D_FREG && q1->to.reg == p->to.reg) {
+				q1->as = AADDD;
+				q1 = prg();
+				q1->scond = q->scond;
+				q1->line = q->line;
+				q1->as = AMOVFD;
+				q1->from = q->to;
+				q1->to = q1->from;
+				q1->link = q->link;
+				q->link = q1;
+			}
+			break;
+
 		case ADIV:
 		case ADIVU:
 		case AMOD:

+ 8 - 0
sys/src/cmd/5l/optab.c

@@ -211,6 +211,14 @@ Optab	optab[] =
 	{ ACASE,	C_REG,	C_NONE,	C_NONE,		62, 4, 0 },
 	{ ABCASE,	C_NONE, C_NONE, C_SBRA,		63, 4, 0 },
 
+	{ AADDF,	C_FREG,	C_NONE,	C_FREG,		74, 4, 0, VFP },
+	{ AADDF,	C_FREG,	C_REG,	C_FREG,		74, 4, 0, VFP },
+	{ AMOVF,	C_FREG, C_NONE, C_FREG,		74, 4, 0, VFP },
+	{ ACMPF,	C_FREG,	C_REG,	C_NONE,		75, 8, 0, VFP },
+	{ ACMPF,	C_FCON,	C_REG,	C_NONE,		75, 8, 0, VFP },
+	{ AMOVFW,	C_FREG,	C_NONE,	C_REG,		76, 8, 0, VFP },
+	{ AMOVFW,	C_REG,	C_NONE,	C_FREG,		76, 8, 0, VFP },
+
 	{ AMOVH,	C_REG,	C_NONE,	C_HEXT,		70, 4, REGSB,	V4 },
 	{ AMOVH,	C_REG,	C_NONE, C_HAUTO,	70, 4, REGSP,	V4 },
 	{ AMOVH,	C_REG,	C_NONE,	C_HOREG,	70, 4, 0,	V4 },

+ 10 - 1
sys/src/cmd/5l/span.c

@@ -637,6 +637,9 @@ ocmp(const void *a1, const void *a2)
 	if(n)
 		return n;
 	n = (p2->flag&V4) - (p1->flag&V4);	/* architecture version */
+	if(n)
+		return n;
+	n = (p2->flag&VFP) - (p1->flag&VFP);	/* floating point arch */
 	if(n)
 		return n;
 	n = p1->a1 - p2->a1;
@@ -657,14 +660,18 @@ buildop(void)
 	int i, n, r;
 
 	armv4 = !debug['h'];
+	vfp = debug['f'];
 	for(i=0; i<C_GOK; i++)
 		for(n=0; n<C_GOK; n++)
 			xcmp[i][n] = cmp(n, i);
-	for(n=0; optab[n].as != AXXX; n++)
+	for(n=0; optab[n].as != AXXX; n++) {
+		if((optab[n].flag & VFP) && !vfp)
+			optab[n].as = AXXX;
 		if((optab[n].flag & V4) && !armv4) {
 			optab[n].as = AXXX;
 			break;
 		}
+	}
 	qsort(optab, n, sizeof(optab[0]), ocmp);
 	for(i=0; i<n; i++) {
 		r = optab[i].as;
@@ -679,6 +686,8 @@ buildop(void)
 		default:
 			diag("unknown op in build: %A", r);
 			errorexit();
+		case AXXX:
+			break;
 		case AADD:
 			oprange[AAND] = oprange[r];
 			oprange[AEOR] = oprange[r];

+ 35 - 24
sys/src/cmd/acme/xfid.c

@@ -260,7 +260,7 @@ xfidread(Xfid *x)
 	int n, q;
 	uint off;
 	char *b;
-	char buf[128];
+	char buf[256];
 	Window *w;
 
 	q = FILE(x->f->qid);
@@ -369,11 +369,42 @@ xfidread(Xfid *x)
 	winunlock(w);
 }
 
+static Rune*
+fullrunewrite(Xfid *x, int *inr)
+{
+	int q, cnt, c, nb, nr;
+	Rune *r;
+
+	q = x->f->nrpart;
+	cnt = x->count;
+	if(q > 0){
+		memmove(x->data+q, x->data, cnt);	/* there's room; see fsysproc */
+		memmove(x->data, x->f->rpart, q);
+		cnt += q;
+		x->f->nrpart = 0;
+	}
+	r = runemalloc(cnt);
+	cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
+	/* approach end of buffer */
+	while(fullrune(x->data+nb, cnt-nb)){
+		c = nb;
+		nb += chartorune(&r[nr], x->data+c);
+		if(r[nr])
+			nr++;
+	}
+	if(nb < cnt){
+		memmove(x->f->rpart, x->data+nb, cnt-nb);
+		x->f->nrpart = cnt-nb;
+	}
+	*inr = nr;
+	return r;
+}
+
 void
 xfidwrite(Xfid *x)
 {
 	Fcall fc;
-	int c, cnt, qid, q, nb, nr, eval;
+	int c, qid, nb, nr, eval;
 	char buf[64], *err;
 	Window *w;
 	Rune *r;
@@ -429,7 +460,7 @@ xfidwrite(Xfid *x)
 
 	case Qeditout:
 	case QWeditout:
-		r = bytetorune(x->data, &nr);
+		r = fullrunewrite(x, &nr);
 		if(w)
 			err = edittext(w, w->wrselrange.q1, r, nr);
 		else
@@ -504,27 +535,7 @@ xfidwrite(Xfid *x)
 		goto BodyTag;
 
 	BodyTag:
-		q = x->f->nrpart;
-		cnt = x->count;
-		if(q > 0){
-			memmove(x->data+q, x->data, cnt);	/* there's room; see fsysproc */
-			memmove(x->data, x->f->rpart, q);
-			cnt += q;
-			x->f->nrpart = 0;
-		}
-		r = runemalloc(cnt);
-		cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
-		/* approach end of buffer */
-		while(fullrune(x->data+nb, cnt-nb)){
-			c = nb;
-			nb += chartorune(&r[nr], x->data+c);
-			if(r[nr])
-				nr++;
-		}
-		if(nb < cnt){
-			memmove(x->f->rpart, x->data+nb, cnt-nb);
-			x->f->nrpart = cnt-nb;
-		}
+		r = fullrunewrite(x, &nr);
 		if(nr > 0){
 			wincommit(w, t);
 			if(qid == QWwrsel){

+ 6 - 2
sys/src/cmd/disk/9660/dump9660.c

@@ -23,9 +23,13 @@ void
 usage(void)
 {
 	if(mk9660)
-		fprint(2, "usage: disk/mk9660 [-D:] [-9cjr] [-b bootfile] [-o offset blocksize] [-p proto] [-s src] cdimage\n");
+		fprint(2, "usage: disk/mk9660 [-D:] [-9cjr] "
+			"[-[bB] bootfile] [-o offset blocksize] "
+			"[-p proto] [-s src] cdimage\n");
 	else
-		fprint(2, "usage: disk/dump9660 [-D:] [-9cjr] [-m maxsize] [-n now] [-p proto] [-s src] cdimage\n");
+		fprint(2, "usage: disk/dump9660 [-D:] [-9cjr] "
+			"[-m maxsize] [-n now] "
+			"[-p proto] [-s src] cdimage\n");
 	exits("usage");
 }
 

+ 8 - 2
sys/src/cmd/htmlfmt/html.c

@@ -12,6 +12,7 @@ char urlexpr[] =
 	"://([a-zA-Z0-9_@\\-]+([.:][a-zA-Z0-9_@\\-]+)*)";
 Reprog	*urlprog;
 
+int newitextitem;
 int inword = 0;
 int col = 0;
 int wordi = 0;
@@ -68,7 +69,7 @@ emitword(Bytes *b, Rune *r, int nr)
 	if(nr == 0)
 		return;
 	s = smprint("%.*S", nr, r);
-	space = b->n > 0 && !isspace(b->b[b->n-1]) && !closingpunct(*s);
+	space = b->n > 0 && !isspace(b->b[b->n-1]) && (!newitextitem || !closingpunct(*s));
 	if(col > 0 && col+space+nr > width){
 		growbytes(b, "\n", 1);
 		space = 0;
@@ -82,6 +83,7 @@ emitword(Bytes *b, Rune *r, int nr)
 	col += nr;
 	free(s);
 	inword = 0;
+	newitextitem = 0;
 }
 
 void
@@ -89,6 +91,8 @@ renderrunes(Bytes *b, Rune *r)
 {
 	int i, n;
 
+	newitextitem = 1;
+
 	n = runestrlen(r);
 	for(i=0; i<n; i++){
 		switch(r[i]){
@@ -212,8 +216,10 @@ render(URLwin *u, Bytes *t, Item *items, int curanchor)
 			it = (Itext*)il;
 			if(it->state & IFwrap)
 				renderrunes(t, it->s);
-			else
+			else {
+				newitextitem = 1;
 				emitword(t, it->s, runestrlen(it->s));
+			}
 			break;
 		case Iruletag:
 			if(t->n>0 && t->b[t->n-1]!='\n')

+ 3 - 3
sys/src/cmd/jpg/readpng.c

@@ -15,7 +15,7 @@ enum
 	/* filtering algorithms */
 	FilterNone =	0,	/* new[x][y] = buf[x][y] */
 	FilterSub =	1,	/* new[x][y] = buf[x][y] + new[x-1][y] */ 
-	FilterUp =		2,	/* new[x][y] = buf[x][y] + new[x][y-1] */ 
+	FilterUp =	2,	/* new[x][y] = buf[x][y] + new[x][y-1] */ 
 	FilterAvg =	3,	/* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */ 
 	FilterPaeth =	4,	/* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
 	FilterLast =	5,
@@ -389,8 +389,8 @@ readslave(Biobuf *b)
 	ZlibW zw;
 
 	buf = pngmalloc(IDATSIZE, 0);
-	Bread(b, buf, sizeof PNGmagic);
-	if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
+	if(Bread(b, buf, sizeof PNGmagic) != sizeof PNGmagic ||
+	    memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
 		sysfatal("bad PNGmagic");
 
 	n = getchunk(b, type, buf, IDATSIZE);

+ 1 - 1
sys/src/cmd/jpg/writepng.c

@@ -79,7 +79,7 @@ zread(void *va, void *buf, int n)
 	pixwid = z->pixwid;
 	b = buf;
 	e = b+n;
-	while(b+pixwid <= e){
+	while(b+pixwid < e){	/* one less for filter alg byte */
 		if(z->y >= z->dy)
 			break;
 		if(z->x == 0)

+ 1 - 1
sys/src/cmd/mk/archive.c

@@ -101,7 +101,7 @@ atimes(char *ar)
 	}
 	at = d->mtime;
 	free(d);
-	while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
+	while(read(fd, (char *)&h, SAR_HDR) == SAR_HDR){
 		t = atol(h.date);
 		if(t >= at)	/* new things in old archives confuses mk */
 			t = at-1;

+ 4 - 3
sys/src/cmd/pcc.c

@@ -12,11 +12,8 @@ typedef struct Objtype {
 
 Objtype objtype[] = {
 	{"spim",	"0c", "0l", "0", "0.out"},
-	{"68000",	"1c", "1l", "1", "1.out"},
-	{"68020",	"2c", "2l", "2", "2.out"},
 	{"arm",		"5c", "5l", "5", "5.out"},
 	{"amd64",	"6c", "6l", "6", "6.out"},
-	{"alpha",	"7c", "7l", "7", "7.out"},
 	{"386",		"8c", "8l", "8", "8.out"},
 	{"power64",	"9c", "9l", "9", "9.out"},
 	{"sparc",	"kc", "kl", "k", "k.out"},
@@ -111,6 +108,10 @@ main(int argc, char *argv[])
 		case 'p':
 			append(&ldargs, "-p");
 			break;
+		case 'f':
+			if(strcmp(ot->name, "arm") == 0)
+				append(&ldargs, "-f");
+			break;
 		case 'a':
 			/* hacky look inside ARGBEGIN insides, to see if we have -aa */
 			if(*_args == 'a') {

+ 0 - 1
sys/src/cmd/pic/makefile

@@ -1,7 +1,6 @@
 CC = cc     # the usual situation
 CFLAGS =    # the usual situation
 
-CC = lcc        # you will probably want to remove this 
 CFLAGS = -g -N -I/usr/include/lcc -I/usr/include       # and this
 
 YFLAGS = -d

+ 1 - 0
sys/src/cmd/plumb/plumber.c

@@ -144,5 +144,6 @@ estrdup(char *s)
 	t = strdup(s);
 	if(t == nil)
 		error("estrdup failed: %r");
+	setmalloctag(t, getcallerpc(&s));
 	return t;
 }

+ 3 - 0
sys/src/cmd/plumb/rules.c

@@ -123,6 +123,7 @@ popinput(void)
 		Bterm(in->fd);
 		free(in->fd);
 	}
+	free(in->file);
 	free(in);
 	return 1;
 }
@@ -572,6 +573,8 @@ readruleset(void)
 					parseerror("too many ports");
 				if(lookup(r->qarg, badports) >= 0)
 					parseerror("illegal port name %s", r->qarg);
+				if(rs->port)
+					free(rs->port);
 				rs->port = estrdup(r->qarg);
 			}else
 				ncmd++;	/* start or client rule */

+ 2 - 1
sys/src/cmd/unix/u9fs/fcallconv.c

@@ -76,7 +76,8 @@ fcallconv(va_list *arg, Fconv *f1)
 			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
 		break;
 	case Tcreate:	/* 114 */
-		sprint(buf, "Tcreate tag %ud fid %ud perm %M mode %d", tag, fid, (ulong)f->perm, f->mode);
+		sprint(buf, "Tcreate tag %ud fid %ud name %s perm %M mode %d",
+			tag, fid, f->name, (ulong)f->perm, f->mode);
 		break;
 	case Rcreate:
 		sprint(buf, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,

+ 18 - 7
sys/src/cmd/usb/kb/hid.c

@@ -55,8 +55,8 @@ getbits(void *p, Chain *ch, int nbits)
 int
 parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 {
-	int i, j, l, n, isptr, hasxy, hasbut, nk, ncoll;
-	int ks[MaxVals];
+	int i, j, l, n, isptr, hasxy, hasbut, nk, ncoll, dsize;
+	uchar ks[MaxVals+1];
 	HidInterface *ifs;
 
 	ifs = temp->ifcs;
@@ -66,11 +66,15 @@ parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 	n = 0;
 	nk = 0;
 	memset(ifs, 0, sizeof *ifs * MaxIfc);
-	for(i = 0; i < repsz; i += 2){
+	for(i = 0; i < repsz; i += dsize+1){
+		dsize = (1 << (repdesc[i] & 03)) >> 1;
+		if(nk > MaxVals){
+			fprint(2, "bad report: too many input types\n");
+			return -1;
+		}
 		if(n == MaxIfc)
 			break;
 		if(repdesc[i] == HidEnd){
-			i--;
 			ncoll--;
 			if(ncoll == 0)
 				break;
@@ -79,7 +83,7 @@ parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 		switch(repdesc[i]){
 		case HidReportId:
 			switch(repdesc[i+1]){
-			case HidReportApp:
+			case HidReportIdPtr:
 				temp->id = repdesc[i+1];
 				break;
 			default:
@@ -98,6 +102,9 @@ parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 				hasxy++;
 				ks[nk++] = KindY;
 				break;
+			case HidZ:
+				ks[nk++] = KindPad;
+				break;
 			case HidWheel:
 				ks[nk++] = KindWheel;
 				break;
@@ -121,6 +128,10 @@ parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 			ifs[n].count = repdesc[i+1];
 			break;
 		case HidInput:
+			if(ifs[n].count > MaxVals){
+				fprint(2, "bad report: input count too big\n");
+				return -1;
+			}
 			for(j = 0; j <nk; j++)
 				ifs[n].kind[j] = ks[j];
 			if(nk != 0 && nk < ifs[n].count)
@@ -130,9 +141,9 @@ parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
 			if(n < MaxIfc){
 				ifs[n].count = ifs[n-1].count;	/* inherit values */
 				ifs[n].nbits = ifs[n-1].nbits;
+				if(ifs[n].nbits == 0)
+					ifs[n].nbits = 1;
 			}
-			if(ifs[n].nbits == 0)
-				ifs[n].nbits = 1;
 			nk = 0;
 			break;
 		case HidCollection:

+ 5 - 3
sys/src/cmd/usb/kb/hid.h

@@ -64,7 +64,7 @@ enum {
 int kbmain(Dev *d, int argc, char*argv[]);
 
 enum{
-	MaxChLen	= 16,	/* bytes */
+	MaxChLen	= 64,	/* bytes */
 };
 
 struct Chain {
@@ -83,13 +83,13 @@ enum {
 	KindY,
 	KindWheel,
 
-	MaxVals	= 8,
+	MaxVals	= 16,
 	MaxIfc	= 8,
 };
 
 struct HidInterface {
 	ulong	v[MaxVals];	/* one ulong per val should be enough */
-	int	kind[MaxVals];
+	uchar	kind[MaxVals];
 	int	nbits;
 	int	count;
 };
@@ -116,10 +116,12 @@ enum {
 	HidPtr		= 0x01,
 	HidX		= 0x30,
 	HidY		= 0x31,
+	HidZ		= 0x32,
 	HidWheel	= 0x38,
 
 	HidInput	= 0x81,
 	HidReportId	= 0x85,
+	HidReportIdPtr	= 0x01,
 
 	HidEnd		= 0xc0,
 };

+ 30 - 30
sys/src/cmd/usb/kb/kb.c

@@ -36,6 +36,7 @@ struct KDev
 	Channel*repeatc;	/* only for keyboard */
 	int	accel;		/* only for mouse */
 	int	bootp;		/* has associated keyboard */
+	int	debug;
 	HidRepTempl templ;
 	int	(*ptrvals)(KDev *kd, Chain *ch, int *px, int *py, int *pb);
 };
@@ -118,8 +119,6 @@ static Kin ptrin =
 	.fd = -1,
 };
 
-static int kbdebug;
-
 static int ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb);
 static int ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb);
 
@@ -153,7 +152,7 @@ setfirstconfig(KDev* f, int eid, uchar *desc, int descsz)
 	}
 	id = f->dev->usb->ep[eid]->iface->id;
 	r = Rh2d | Rstd | Rdev;
-	nr =usbcmd(f->dev,  r, Rsetconf, 1, id, nil, 0);
+	nr = usbcmd(f->dev,  r, Rsetconf, 1, 0, nil, 0);
 	if(nr < 0)
 		return -1;
 	r = Rh2d | Rclass | Riface;
@@ -162,9 +161,9 @@ setfirstconfig(KDev* f, int eid, uchar *desc, int descsz)
 		return -1;
 	r = Rd2h | Rstd | Riface;
 	nr=usbcmd(f->dev,  r, Rgetdesc, Dreport<<8, id, desc, descsz);
-	if(nr < 0)
+	if(nr <= 0)
 		return -1;
-	if(kbdebug && nr > 0){
+	if(f->debug){
 		fprint(2, "report descriptor:");
 		for(i = 0; i < nr; i++){
 			if(i%8 == 0)
@@ -290,7 +289,7 @@ ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb)
 			return -1;
 	parsereport(&kd->templ, ch);
 
-	if(kbdebug)
+	if(kd->debug > 1)
 		dumpreport(&kd->templ);
 	if(c < 3)
 		return -1;
@@ -378,7 +377,7 @@ ptrwork(void* a)
 			x = scale(f, x);
 			y = scale(f, y);
 		}
-		if(kbdebug > 1)
+		if(f->debug > 1)
 			fprint(2, "kb: m%11d %11d %11d\n", x, y, b);
 		seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b);
 		if(write(mfd, mbuf, strlen(mbuf)) < 0)
@@ -409,19 +408,21 @@ startrepeat(KDev *f, uchar esc1, uchar sc)
 }
 
 static void
-putscan(int kbinfd, uchar esc, uchar sc)
+putscan(KDev *f, uchar esc, uchar sc)
 {
+	int kbinfd;
 	uchar s[2] = {SCesc1, 0};
 
+	kbinfd = f->in->fd;
 	if(sc == 0x41){
-		kbdebug += 2;
+		f->debug += 2;
 		return;
 	}
 	if(sc == 0x42){
-		kbdebug = 0;
+		f->debug = 0;
 		return;
 	}
-	if(kbdebug)
+	if(f->debug > 1)
 		fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc);
 	s[1] = sc;
 	if(esc && sc != 0)
@@ -435,7 +436,6 @@ repeatproc(void* a)
 {
 	KDev *f;
 	Channel *repeatc;
-	int kbdinfd;
 	ulong l, t, i;
 	uchar esc1, sc;
 
@@ -446,7 +446,6 @@ repeatproc(void* a)
 	 */
 	f = a;
 	repeatc = f->repeatc;
-	kbdinfd = f->in->fd;
 	l = Awakemsg;
 Repeat:
 	if(l == Diemsg)
@@ -464,7 +463,7 @@ Repeat:
 				goto Repeat;
 			sleep(5);
 		}
-		putscan(kbdinfd, esc1, sc);
+		putscan(f, esc1, sc);
 		t = 30;
 	}
 Abort:
@@ -477,13 +476,13 @@ Abort:
 #define hasesc1(sc)	(((sc) > 0x47) || ((sc) == 0x38))
 
 static void
-putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc)
+putmod(KDev *f, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc)
 {
 	/* BUG: Should be a single write */
 	if((mods&mask) && !(omods&mask))
-		putscan(fd, esc, sc);
+		putscan(f, esc, sc);
 	if(!(mods&mask) && (omods&mask))
-		putscan(fd, esc, Keyup|sc);
+		putscan(f, esc, Keyup|sc);
 }
 
 /*
@@ -499,14 +498,12 @@ putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk)
 {
 	int i, j;
 	uchar uk;
-	int fd;
 
-	fd = f->in->fd;
-	putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl);
-	putmod(fd, buf[0], obuf[0], (1<<Mlshift), 0, SClshift);
-	putmod(fd, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift);
-	putmod(fd, buf[0], obuf[0], Mcompose, 0, SCcompose);
-	putmod(fd, buf[0], obuf[0], Maltgr, 1, SCcompose);
+	putmod(f, buf[0], obuf[0], Mctrl, 0, SCctrl);
+	putmod(f, buf[0], obuf[0], (1<<Mlshift), 0, SClshift);
+	putmod(f, buf[0], obuf[0], (1<<Mrshift), 0, SCrshift);
+	putmod(f, buf[0], obuf[0], Mcompose, 0, SCcompose);
+	putmod(f, buf[0], obuf[0], Maltgr, 1, SCcompose);
 
 	/* Report key downs */
 	for(i = 2; i < n; i++){
@@ -515,7 +512,7 @@ putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk)
 			 	break;
 		if(j == n && buf[i] != 0){
 			dk = sctab[buf[i]];
-			putscan(fd, hasesc1(dk), dk);
+			putscan(f, hasesc1(dk), dk);
 			startrepeat(f, hasesc1(dk), dk);
 		}
 	}
@@ -528,7 +525,7 @@ putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk)
 				break;
 		if(j == n && obuf[i] != 0){
 			uk = sctab[obuf[i]];
-			putscan(fd, hasesc1(uk), uk|Keyup);
+			putscan(f, hasesc1(uk), uk|Keyup);
 		}
 	}
 	if(uk && (dk == 0 || dk == uk)){
@@ -589,7 +586,7 @@ kbdwork(void *a)
 			continue;
 		if(kbdbusy(buf + 2, c - 2))
 			continue;
-		if(usbdebug > 2 || kbdebug > 1){
+		if(usbdebug > 2 || f->debug > 1){
 			fprint(2, "kbd mod %x: ", buf[0]);
 			for(i = 2; i < c; i++)
 				fprint(2, "kc %x ", buf[i]);
@@ -669,7 +666,7 @@ kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), KDev *kd)
 			fprint(2, "kb: %s: bootproto: %r\n", d->dir);
 			return;
 		}
-	}else if(kbdebug)
+	}else if(kd->debug)
 		dumpreport(&kd->templ);
 	if(opendevdata(kd->ep, OREAD) < 0){
 		fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir);
@@ -692,7 +689,7 @@ usage(void)
 int
 kbmain(Dev *d, int argc, char* argv[])
 {
-	int bootp, i, kena, pena, accel, devid;
+	int bootp, i, kena, pena, accel, devid, debug;
 	Ep *ep;
 	KDev *kd;
 	Usbdev *ud;
@@ -700,13 +697,14 @@ kbmain(Dev *d, int argc, char* argv[])
 	kena = pena = 1;
 	bootp = 0;
 	accel = 0;
+	debug = 0;
 	devid = d->id;
 	ARGBEGIN{
 	case 'a':
 		accel = strtol(EARGF(usage()), nil, 0);
 		break;
 	case 'd':
-		kbdebug++;
+		debug++;
 		break;
 	case 'k':
 		kena = 1;
@@ -747,6 +745,7 @@ kbmain(Dev *d, int argc, char* argv[])
 			kd = d->aux = emallocz(sizeof(KDev), 1);
 			kd->accel = 0;
 			kd->bootp = 1;
+			kd->debug = debug;
 			kbstart(d, ep, &kbdin, kbdwork, kd);
 		}
 		if(pena && ep->type == Eintr && ep->dir == Ein &&
@@ -754,6 +753,7 @@ kbmain(Dev *d, int argc, char* argv[])
 			kd = d->aux = emallocz(sizeof(KDev), 1);
 			kd->accel = accel;
 			kd->bootp = bootp;
+			kd->debug = debug;
 			kbstart(d, ep, &ptrin, ptrwork, kd);
 		}
 	}

+ 2 - 1
sys/src/cmd/usb/serial/main.c

@@ -7,6 +7,7 @@
 #include "ucons.h"
 #include "prolific.h"
 #include "ftdi.h"
+#include "silabs.h"
 
 enum {
 	Arglen = 80,
@@ -26,7 +27,7 @@ static int
 matchserial(char *info, void*)
 {
 	if(uconsmatch(info) == 0 || plmatch(info) == 0 ||
-	    ftmatch(nil, info) == 0)
+	    ftmatch(nil, info) == 0 || slmatch(info) == 0)
 		return 0;
 	return -1;
 }

+ 1 - 1
sys/src/cmd/usb/serial/mkfile

@@ -2,7 +2,7 @@
 
 TARG=serial
 OFILES=main.$O
-LIBDOFILES=ftdi.$O serial.$O prolific.$O ucons.$O
+LIBDOFILES=ftdi.$O serial.$O prolific.$O ucons.$O silabs.$O
 HFILES=\
 	../lib/usb.h\
 	ftdi.h\

+ 16 - 5
sys/src/cmd/usb/serial/serial.c

@@ -13,6 +13,7 @@
 #include "prolific.h"
 #include "ucons.h"
 #include "ftdi.h"
+#include "silabs.h"
 
 int serialdebug;
 
@@ -646,7 +647,11 @@ openeps(Serialport *p, int epin, int epout, int epintr)
 		fprint(2, "serial: openep %d: %r\n", epin);
 		return -1;
 	}
-	p->epout = openep(ser->dev, epout);
+	if(epout == epin){
+		incref(p->epin);
+		p->epout = p->epin;
+	}else
+		p->epout = openep(ser->dev, epout);
 	if(p->epout == nil){
 		fprint(2, "serial: openep %d: %r\n", epout);
 		closedev(p->epin);
@@ -672,8 +677,12 @@ openeps(Serialport *p, int epin, int epout, int epintr)
 
 	if(ser->seteps!= nil)
 		ser->seteps(p);
-	opendevdata(p->epin, OREAD);
-	opendevdata(p->epout, OWRITE);
+	if(p->epin == p->epout)
+		opendevdata(p->epin, ORDWR);
+	else{
+		opendevdata(p->epin, OREAD);
+		opendevdata(p->epout, OWRITE);
+	}
 	if(p->epin->dfd < 0 ||p->epout->dfd < 0 ||
 	    (ser->hasepintr && p->epintr->dfd < 0)){
 		fprint(2, "serial: open i/o ep data: %r\n");
@@ -707,9 +716,9 @@ findendpoints(Serial *ser, int ifc)
 		    ep->dir == Ein && epintr == -1)
 			epintr = ep->id;
 		if(ep->type == Ebulk){
-			if(ep->dir == Ein && epin == -1)
+			if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
 				epin = ep->id;
-			if(ep->dir == Eout && epout == -1)
+			if((ep->dir == Ein || ep->dir == Eboth) && epout == -1)
 				epout = ep->id;
 		}
 	}
@@ -833,6 +842,8 @@ serialmain(Dev *dev, int argc, char* argv[])
 		ser->Serialops = uconsops;
 	else if(ftmatch(ser, buf) == 0)
 		ser->Serialops = ftops;
+	else if(slmatch(buf) == 0)
+		ser->Serialops = slops;
 	else {
 		werrstr("serial: no serial devices found");
 		return -1;

+ 146 - 0
sys/src/cmd/usb/serial/silabs.c

@@ -0,0 +1,146 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+#include "usbfs.h"
+#include "serial.h"
+#include "silabs.h"
+
+static Cinfo slinfo[] = {
+	{ 0x10c4, 0xea60, },		/* CP210x */
+	{ 0x10c4, 0xea61, },		/* CP210x */
+	{ 0,	0, },
+};
+
+enum {
+	Enable		= 0x00,
+
+	Getbaud		= 0x1D,
+	Setbaud		= 0x1E,
+	Setlcr		= 0x03,
+	Getlcr		= 0x04,
+		Bitsmask	= 0x0F00,
+		Bitsshift	= 8,
+		Parmask		= 0x00F0,
+		Parshift	= 4,
+		Stopmask	= 0x000F,
+		Stop1		= 0x0000,
+		Stop1_5		= 0x0001,
+		Stop2		= 0x0002,
+};
+
+slmatch(char *info)
+{
+	Cinfo *ip;
+	char buf[50];
+
+	for(ip = slinfo; ip->vid != 0; ip++){
+		snprint(buf, sizeof buf, "vid %#06x did %#06x",
+			ip->vid, ip->did);
+		if(strstr(info, buf) != nil)
+			return 0;
+	}
+	return -1;
+}
+
+static int
+slwrite(Serialport *p, int req, void *buf, int len)
+{
+	Serial *ser;
+
+	ser = p->s;
+	return usbcmd(ser->dev, Rh2d | Rvendor | Riface, req, 0, p->interfc,
+		buf, len);
+}
+
+static int
+slput(Serialport *p, uint op, uint val)
+{
+	Serial *ser;
+
+	ser = p->s;
+	return usbcmd(ser->dev, Rh2d | Rvendor | Riface, op, val, p->interfc,
+		nil, 0);
+}
+
+static int
+slread(Serialport *p, int req, void *buf, int len)
+{
+	Serial *ser;
+
+	ser = p->s;
+	return usbcmd(ser->dev, Rd2h | Rvendor | Riface, req, 0, p->interfc,
+		buf, len);
+}
+
+static int
+slinit(Serialport *p)
+{
+	Serial *ser;
+
+	ser = p->s;
+	dsprint(2, "slinit\n");
+
+	slput(p, Enable, 1);
+
+	slops.getparam(p);
+
+	/* p gets freed by closedev, the process has a reference */
+	incref(ser->dev);
+	return 0;
+}
+
+static int
+slgetparam(Serialport *p)
+{
+	u16int lcr;
+
+	slread(p, Getbaud, &p->baud, sizeof(p->baud));
+	slread(p, Getlcr, &lcr, sizeof(lcr));
+	p->bits = (lcr&Bitsmask)>>Bitsshift;
+	p->parity = (lcr&Parmask)>>Parshift;
+	p->stop = (lcr&Stopmask) == Stop1? 1 : 2;
+	return 0;
+}
+
+static int
+slsetparam(Serialport *p)
+{
+	u16int lcr;
+
+	lcr = p->stop == 1? Stop1 : Stop2;
+	lcr |= (p->bits<<Bitsshift) | (p->parity<<Parshift);
+	slput(p, Setlcr, lcr);
+	slwrite(p, Setbaud, &p->baud, sizeof(p->baud));
+	return 0;
+}
+
+static int
+seteps(Serialport *p)
+{
+	if(devctl(p->epin, "timeout 0") < 0){
+		fprint(2, "can't set timeout on %s: %r\n", p->epin->dir);
+		return -1;
+	}
+	return 0;
+}
+
+static int
+wait4data(Serialport *p, uchar *data, int count)
+{
+	int n;
+
+	qunlock(p->s);
+	while ((n = read(p->epin->dfd, data, count)) == 0)
+		;
+	qlock(p->s);
+	return n;
+}
+
+Serialops slops = {
+	.init		= slinit,
+	.getparam	= slgetparam,
+	.setparam	= slsetparam,
+	.seteps		= seteps,
+	.wait4data	= wait4data,
+};

+ 3 - 0
sys/src/cmd/usb/serial/silabs.h

@@ -0,0 +1,3 @@
+extern Serialops slops;
+
+int slmatch(char *info);

+ 3 - 1
sys/src/libc/fmt/runevsmprint.c

@@ -38,6 +38,7 @@ runefmtstrinit(Fmt *f)
 	f->start = malloc(sizeof(Rune)*n);
 	if(f->start == nil)
 		return -1;
+	setmalloctag(f->start, getcallerpc(&f));
 	f->to = f->start;
 	f->stop = (Rune*)f->start + n - 1;
 	f->flush = runeFmtStrFlush;
@@ -59,12 +60,13 @@ runevsmprint(char *fmt, va_list args)
 		return nil;
 	f.args = args;
 	n = dofmt(&f, fmt);
-	if(f.start == nil)
+	if(f.start == nil)		/* realloc failed? */
 		return nil;
 	if(n < 0){
 		free(f.start);
 		return nil;
 	}
+	setmalloctag(f.start, getcallerpc(&fmt));
 	*(Rune*)f.to = '\0';
 	return f.start;
 }

+ 3 - 1
sys/src/libc/fmt/vsmprint.c

@@ -38,6 +38,7 @@ fmtstrinit(Fmt *f)
 	f->start = malloc(n);
 	if(f->start == nil)
 		return -1;
+	setmalloctag(f->start, getcallerpc(&f));
 	f->to = f->start;
 	f->stop = (char*)f->start + n - 1;
 	f->flush = fmtStrFlush;
@@ -59,12 +60,13 @@ vsmprint(char *fmt, va_list args)
 		return nil;
 	f.args = args;
 	n = dofmt(&f, fmt);
-	if(f.start == nil)
+	if(f.start == nil)		/* realloc failed? */
 		return nil;
 	if(n < 0){
 		free(f.start);
 		return nil;
 	}
+	setmalloctag(f.start, getcallerpc(&fmt));
 	*(char*)f.to = '\0';
 	return f.start;
 }

+ 1 - 0
sys/src/libc/port/runestrdup.c

@@ -9,6 +9,7 @@ runestrdup(Rune *s)
 	ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
 	if(ns == 0)
 		return 0;
+	setmalloctag(ns, getcallerpc(&s));
 
 	return runestrcpy(ns, s);
 }

+ 1 - 0
sys/src/libc/port/strdup.c

@@ -9,6 +9,7 @@ strdup(char *s)
 	ns = malloc(strlen(s) + 1);
 	if(ns == 0)
 		return 0;
+	setmalloctag(ns, getcallerpc(&s));
 
 	return strcpy(ns, s);
 }

+ 1 - 1
sys/src/libdraw/init.c

@@ -200,7 +200,7 @@ getwindow(Display *d, int ref)
 Display*
 initdisplay(char *dev, char *win, void(*error)(Display*, char*))
 {
-	char buf[128], info[NINFO+1], *t, isnew;
+	char buf[NINFO+1], info[NINFO+1], *t, isnew;
 	int n, datafd, ctlfd, reffd;
 	Display *disp;
 	Dir *dir;

+ 165 - 1
sys/src/libmach/5db.c

@@ -135,7 +135,7 @@ char*	addsub[2] =
 int
 armclass(long w)
 {
-	int op, done;
+	int op, done, cp;
 
 	op = (w >> 25) & 0x7;
 	switch(op) {
@@ -220,8 +220,62 @@ armclass(long w)
 		op = (48+24+4+4+2) + ((w >> 24) & 0x1);
 		break;
 	case 7:	/* coprocessor crap */
+		cp = (w >> 8) & 0xF;
+		if(cp == 10 || cp == 11){	/* vfp */
+			if((w >> 4) & 0x1){
+				/* vfp register transfer */
+				switch((w >> 21) & 0x7){
+				case 0:
+					op = 118 + ((w >> 20) & 0x1);
+					break;
+				case 7:
+					op = 118+2 + ((w >> 20) & 0x1);
+					break;
+				default:
+					op = (48+24+4+4+2+2+4+4);
+					break;
+				}
+				break;
+			}
+			/* vfp data processing */
+			if(((w >> 23) & 0x1) == 0){
+				op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1);
+				break;
+			}
+			switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){
+			case 0:
+				op = 108;
+				break;
+			case 7:
+				if(((w >> 19) & 0x1) == 0)
+					if(((w >> 17) & 0x1) == 0)
+						op = 109 + ((w >> 16) & 0x4) +
+							((w >> 15) & 0x2) +
+							((w >> 7) & 0x1);
+					else if(((w >> 16) & 0x7) == 0x7)
+						op = 117;
+				else
+					switch((w >> 16) & 0x7){
+					case 0:
+					case 4:
+					case 5:
+						op = 117;
+						break;
+					}
+				break;
+			}
+			if(op == 7)
+				op = (48+24+4+4+2+2+4+4);
+			break;
+		}
 		op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
 		break;
+	case 6:	/* vfp load / store */
+		if(((w >> 21) &0x9) == 0x8){
+			op = 122 + ((w >> 20) & 0x1);
+			break;
+		}
+		/* fall through */
 	default:	  
 		op = (48+24+4+4+2+2+4+4);
 		break;
@@ -405,6 +459,20 @@ armsdti(Opcode *o, Instr *i)
 	format(o->o, i, o->a);
 }
 
+static void
+armvstdi(Opcode *o, Instr *i)
+{
+	ulong v;
+
+	v = (i->w & 0xff) << 2;
+	if(!(i->w & (1<<23)))
+		v = -v;
+	i->imm = v;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	format(o->o, i, o->a);
+}
+
 /* arm V4 ld/st halfword, signed byte */
 static void
 armhwby(Opcode *o, Instr *i)
@@ -870,6 +938,40 @@ static Opcode opcodes[] =
 
 /* 99 */
 	"RFEV7%P%a",	armbdt, 0,	"(R%n)",
+
+/* 100 */
+	"MLA%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"MLS%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMLS%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMLA%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"MUL%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"NMUL%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"ADD%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"SUB%f%C",	armdps,	0,	"F%s,F%n,F%d",
+	"DIV%f%C",	armdps,	0,	"F%s,F%n,F%d",
+
+/* 109 */
+	"MOV%f%C",	armdps,	0,	"F%s,F%d",
+	"ABS%f%C",	armdps,	0,	"F%s,F%d",
+	"NEG%f%C",	armdps,	0,	"F%s,F%d",
+	"SQRT%f%C",	armdps,	0,	"F%s,F%d",
+	"CMP%f%C",	armdps,	0,	"F%s,F%d",
+	"CMPE%f%C",	armdps,	0,	"F%s,F%d",
+	"CMP%f%C",	armdps,	0,	"$0.0,F%d",
+	"CMPE%f%C",	armdps,	0,	"$0.0,F%d",
+
+/* 117 */
+	"MOV%F%R%C",	armdps, 0,	"F%s,F%d",
+
+/* 118 */
+	"MOVW%C",	armdps, 0,	"R%d,F%n",
+	"MOVW%C",	armdps, 0,	"F%n,R%d",
+	"MOVW%C",	armdps, 0,	"R%d,%x",
+	"MOVW%C",	armdps, 0,	"%x,R%d",
+
+/* 122 */
+	"MOV%f%C",	armvstdi,	0,	"F%d,%I",
+	"MOV%f%C",	armvstdi,	0,	"%I,F%d",
 };
 
 static void
@@ -1019,6 +1121,68 @@ format(char *mnemonic, Instr *i, char *f)
 				i->imm, CANY);
 			break;
 
+		case 'f':
+			switch((i->w >> 8) & 0xF){
+			case 10:
+				bprint(i, "F");
+				break;
+			case 11:
+				bprint(i, "D");
+				break;
+			}
+			break;
+
+		case 'F':
+			switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){
+			case 0x0:
+				bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U");
+				break;
+			case 0x1:
+				bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U");
+				break;
+			case 0x8:
+				bprint(i, "FW.U");
+				break;
+			case 0x9:
+				bprint(i, "DW.U");
+				break;
+			case 0xA:
+				bprint(i, "FW");
+				break;
+			case 0xB:
+				bprint(i, "DW");
+				break;
+			case 0xE:
+				bprint(i, "FD");
+				break;
+			case 0xF:
+				bprint(i, "DF");
+				break;
+			}
+			break;
+
+		case 'R':
+			if(((i->w >> 7) & 0x1) == 0)
+				bprint(i, "R");
+			break;
+
+		case 'x':
+			switch(i->rn){
+			case 0:
+				bprint(i, "FPSID");
+				break;
+			case 1:
+				bprint(i, "FPSCR");
+				break;
+			case 2:
+				bprint(i, "FPEXC");
+				break;
+			default:
+				bprint(i, "FPS(%d)", i->rn);
+				break;
+			}
+			break;
+
 		case 'r':
 			n = i->imm&0xffff;
 			j = 0;

+ 27 - 18
sys/src/libplumb/mesg.c

@@ -2,8 +2,6 @@
 #include <libc.h>
 #include "plumb.h"
 
-static char attrbuf[4096];
-
 int
 plumbopen(char *name, int omode)
 {
@@ -70,20 +68,20 @@ Strcpy(char *s, char *t)
 
 /* quote attribute value, if necessary */
 static char*
-quote(char *s)
+quote(char *s, char *buf, char *bufe)
 {
 	char *t;
 	int c;
 
 	if(s == nil){
-		attrbuf[0] = '\0';
-		return attrbuf;
+		buf[0] = '\0';
+		return buf;
 	}
 	if(strpbrk(s, " '=\t") == nil)
 		return s;
-	t = attrbuf;
+	t = buf;
 	*t++ = '\'';
-	while(t < attrbuf+sizeof attrbuf-2){
+	while(t < bufe-2){
 		c = *s++;
 		if(c == '\0')
 			break;
@@ -93,7 +91,7 @@ quote(char *s)
 	}
 	*t++ = '\'';
 	*t = '\0';
-	return attrbuf;
+	return buf;
 }
 
 char*
@@ -101,16 +99,21 @@ plumbpackattr(Plumbattr *attr)
 {
 	int n;
 	Plumbattr *a;
-	char *s, *t;
+	char *s, *t, *buf, *bufe;
 
 	if(attr == nil)
 		return nil;
+	if((buf = malloc(4096)) == nil)
+		return nil;
+	bufe = buf + 4096;
 	n = 0;
 	for(a=attr; a!=nil; a=a->next)
-		n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;
+		n += Strlen(a->name) + 1 + Strlen(quote(a->value, buf, bufe)) + 1;
 	s = malloc(n);
-	if(s == nil)
+	if(s == nil) {
+		free(buf);
 		return nil;
+	}
 	t = s;
 	*t = '\0';
 	for(a=attr; a!=nil; a=a->next){
@@ -118,11 +121,12 @@ plumbpackattr(Plumbattr *attr)
 			*t++ = ' ';
 		strcpy(t, a->name);
 		strcat(t, "=");
-		strcat(t, quote(a->value));
+		strcat(t, quote(a->value, buf, bufe));
 		t += strlen(t);
 	}
 	if(t > s+n)
 		abort();
+	free(buf);
 	return s;
 }
 
@@ -236,9 +240,13 @@ Plumbattr*
 plumbunpackattr(char *p)
 {
 	Plumbattr *attr, *prev, *a;
-	char *q, *v;
+	char *q, *v, *buf, *bufe;
 	int c, quoting;
 
+	buf = malloc(4096);
+	if(buf == nil)
+		return nil;
+	bufe = buf + 4096;
 	attr = prev = nil;
 	while(*p!='\0' && *p!='\n'){
 		while(*p==' ' || *p=='\t')
@@ -262,10 +270,10 @@ plumbunpackattr(char *p)
 		a->name[q-p] = '\0';
 		/* process quotes in value */
 		q++;	/* skip '=' */
-		v = attrbuf;
+		v = buf;
 		quoting = 0;
 		while(*q!='\0' && *q!='\n'){
-			if(v >= attrbuf+sizeof attrbuf)
+			if(v >= bufe)
 				break;
 			c = *q++;
 			if(quoting){
@@ -287,14 +295,14 @@ plumbunpackattr(char *p)
 			}
 			*v++ = c;
 		}
-		a->value = malloc(v-attrbuf+1);
+		a->value = malloc(v-buf+1);
 		if(a->value == nil){
 			free(a->name);
 			free(a);
 			break;
 		}
-		memmove(a->value, attrbuf, v-attrbuf);
-		a->value[v-attrbuf] = '\0';
+		memmove(a->value, buf, v-buf);
+		a->value[v-buf] = '\0';
 		a->next = nil;
 		if(prev == nil)
 			attr = a;
@@ -303,6 +311,7 @@ plumbunpackattr(char *p)
 		prev = a;
 		p = q;
 	}
+	free(buf);
 	return attr;
 }
 

+ 6 - 0
sys/src/libventi/rpc.c

@@ -37,6 +37,12 @@ _vtrpc(VtConn *z, Packet *p, VtFcall *tx)
 	uchar tag, buf[2], *top;
 	Rwait *r, *rr;
 
+	if(z == nil){
+		werrstr("not connected");
+		packetfree(p);
+		return nil;
+	}
+
 	/* must malloc because stack could be private */
 	r = vtmallocz(sizeof(Rwait));