syscall: Plan 9: use lightweight errstr in entersyscall mode

Change 231af8ac63aa (CL 7314062) made runtime.enteryscall()
set m->mcache = nil, which means that we can no longer use
syscall.errstr in syscall.Syscall and syscall.Syscall6, since it
requires a new buffer to be allocated for holding the error string.
Instead, we use pre-allocated per-M storage to hold error strings
from syscalls made while in entersyscall mode, and call
runtime.findnull to calculate the lengths.

Fixes #4994.

R=rsc, rminnich, ality, dvyukov, rminnich, r
CC=golang-dev
https://golang.org/cl/7567043
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index e44064f..66bcf60 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -320,6 +320,7 @@
 #endif
 #ifdef GOOS_plan9
 	int8*		notesig;
+	byte*	errstr;
 #endif
 	SEH*	seh;
 	uintptr	end[];
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index 3385b08..09211e8 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -170,3 +170,23 @@
 // Only used by the 64-bit runtime.
 TEXT runtime·setfpmasks(SB),7,$0
 	RET
+
+#define ERRMAX 128	/* from os_plan9.h */
+
+// func errstr() String
+// Only used by package syscall.
+// Grab error string due to a syscall made
+// in entersyscall mode, without going
+// through the allocator (issue 4994).
+// See ../syscall/asm_plan9_386.s:/·Syscall/
+TEXT runtime·errstr(SB),7,$0
+	get_tls(AX)
+	MOVL	m(AX), BX
+	MOVL	m_errstr(BX), CX
+	MOVL	CX, 4(SP)
+	MOVL	$ERRMAX, 8(SP)
+	MOVL	$41, AX
+	INT	$64
+	CALL	runtime·findnull(SB)
+	MOVL	AX, 8(SP)
+	RET
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index b34f98a..68563f3 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -206,3 +206,24 @@
 	MOVL	AX, 0(SP)
 	LDMXCSR	0(SP)
 	RET
+
+#define ERRMAX 128	/* from os_plan9.h */
+
+// func errstr() String
+// Only used by package syscall.
+// Grab error string due to a syscall made
+// in entersyscall mode, without going
+// through the allocator (issue 4994).
+// See ../syscall/asm_plan9_386.s:/·Syscall/
+TEXT runtime·errstr(SB),7,$0
+	get_tls(AX)
+	MOVQ	m(AX), BX
+	MOVQ	m_errstr(BX), CX
+	MOVQ	CX, 8(SP)
+	MOVQ	$ERRMAX, 16(SP)
+	MOVQ	$0x8000, AX
+	MOVQ	$41, BP
+	SYSCALL
+	CALL	runtime·findnull(SB)
+	MOVQ	AX, 16(SP)
+	RET
diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c
index 7f94623..524dbf6 100644
--- a/src/pkg/runtime/thread_plan9.c
+++ b/src/pkg/runtime/thread_plan9.c
@@ -19,6 +19,10 @@
 	// Initialize stack and goroutine for note handling.
 	mp->gsignal = runtime·malg(32*1024);
 	mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8));
+
+	// Initialize stack for handling strings from the
+	// errstr system call, as used in package syscall.
+	mp->errstr = (byte*)runtime·malloc(ERRMAX*sizeof(byte));
 }
 
 // Called to initialize a new m (including the bootstrap m).