* change ldt0setup to set GS itself; nacl won't let us do it.
* change breakpoint to INT $3 so 8l can translate to HLT for nacl.
* panic if closure is needed on nacl.
* do not try to access symbol table on nacl.
* mmap in 64kB chunks.
nacl support:
* system calls, threading, locks.
R=r
DELTA=365 (357 added, 5 deleted, 3 changed)
OCL=34880
CL=34906
MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP)
+ // set up %gs
CALL ldt0setup(SB)
- // set up %gs to refer to that ldt entry
- MOVL $(7*8+7), AX
- MOVW AX, GS
-
// store through it, to make sure it works
MOVL $0x123, 0(GS)
MOVL tls0(SB), AX
RET
TEXT breakpoint(SB),7,$0
- BYTE $0xcc
+ INT $3
RET
/*
TEXT ldt0setup(SB),7,$16
// set up ldt 7 to point at tls0
// ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
+ // the entry number is just a hint. setldt will set up GS with what it used.
MOVL $7, 0(SP)
LEAL tls0(SB), AX
MOVL AX, 4(SP)
TEXT abort(SB),7,$0
INT $0x3
-
int32 i, n;
int32 pcrel;
+ if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
+ throw("no closures in native client yet");
+
if(siz < 0 || siz%4 != 0)
throw("bad closure size");
MOVL AX, 4(SP)
MOVL $1, 8(SP)
CALL i386_set_ldt(SB)
+
+ // compute segment selector - (entry*8+7)
+ MOVL entry+0(FP), AX
+ SHLL $3, AX
+ ADDL $7, AX
+ MOVW AX, GS
RET
TEXT i386_set_ldt(SB),7,$0
CMPL AX, $0xfffff001
JLS 2(PC)
INT $3
+
+ // compute segment selector - (entry*8+7)
+ MOVL entry+0(FP), AX
+ SHLL $3, AX
+ ADDL $7, AX
+ MOVW AX, GS
+
RET
// Ask for a big chunk, to reduce the number of mappings
// the operating system needs to track; also amortizes
// the overhead of an operating system mapping.
+ // For Native Client, allocate a multiple of 64kB (16 pages).
+ npage = (npage+15)&~15;
ask = npage<<PageShift;
if(ask < HeapAllocChunk)
ask = HeapAllocChunk;
case "$GOARCH" in
386)
+ # The offsets 0 and 4 are known to nacl/thread.c:/^newosproc too.
echo '#define g 0(GS)'
echo '#define m 4(GS)'
;;
--- /dev/null
+// godefs -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+};
+
+// Types
+#pragma pack on
+#pragma pack off
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Native Client and Linux use the same linkage to main
+
+TEXT _rt0_386_nacl(SB),7,$0
+ JMP _rt0_386(SB)
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+void
+initsig(void)
+{
+}
+
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for 386, Linux
+//
+
+#include "386/asm.h"
+
+// http://code.google.com/p/nativeclient/source/browse/trunk/src/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
+#define SYS_exit 30
+#define SYS_mmap 21
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_write 13
+#define SYS_close 11
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_unlock 73
+
+#define SYSCALL(x) $(0x10000+SYS_/**/x * 32)
+
+TEXT exit(SB),7,$4
+ MOVL code+0(FP), AX
+ MOVL AX, 0(SP)
+ CALL SYSCALL(exit)
+ INT $3 // not reached
+ RET
+
+TEXT exit1(SB),7,$4
+ MOVL code+0(FP), AX
+ MOVL AX, 0(SP)
+ CALL SYSCALL(thread_exit)
+ INT $3 // not reached
+ RET
+
+TEXT write(SB),7,$0
+ JMP SYSCALL(write)
+
+TEXT close(SB),7,$0
+ JMP SYSCALL(close)
+
+TEXT mutex_create(SB),7,$0
+ JMP SYSCALL(mutex_create)
+
+TEXT mutex_lock(SB),7,$0
+ JMP SYSCALL(mutex_lock)
+
+TEXT mutex_unlock(SB),7,$0
+ JMP SYSCALL(mutex_unlock)
+
+TEXT thread_create(SB),7,$0
+ JMP SYSCALL(thread_create)
+
+TEXT sys·mmap(SB),7,$24
+ MOVL a1+0(FP), BX
+ MOVL a2+4(FP), CX // round up to 64 kB boundary; silences nacl warning
+ ADDL $(64*1024-1), CX
+ ANDL $~(64*1024-1), CX
+ MOVL a3+8(FP), DX
+ MOVL a4+12(FP), SI
+ MOVL a5+16(FP), DI
+ MOVL a6+20(FP), BP
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
+ MOVL SI, 12(SP)
+ MOVL DI, 16(SP)
+ MOVL BP, 20(SP)
+ CALL SYSCALL(mmap)
+ CMPL AX, $0xfffff001
+ JLS 6(PC)
+ MOVL $1, 0(SP)
+ MOVL $mmap_failed(SB), 4(SP)
+ MOVL $12, 8(SP) // "mmap failed\n"
+ CALL SYSCALL(write)
+ INT $3
+ RET
+
+// setldt(int entry, int address, int limit)
+TEXT setldt(SB),7,$32
+ // entry is ignored - nacl tells us the
+ // segment selector to use and stores it in GS.
+ MOVL address+4(FP), BX
+ MOVL limit+8(FP), CX
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ CALL SYSCALL(tls_init)
+ CMPL AX, $0xfffff001
+ JLS 6(PC)
+ MOVL $1, 0(SP)
+ MOVL $tls_init_failed(SB), 4(SP)
+ MOVL $16, 8(SP) // "tls_init failed\n"
+ CALL SYSCALL(write)
+ INT $3
+ RET
+
+// There's no good way (yet?) to get stack traces out of a
+// broken NaCl process, so if something goes wrong,
+// print an error string before dying.
+
+DATA mmap_failed(SB)/8, $"mmap fai"
+DATA mmap_failed+8(SB)/4, $"led\n"
+GLOBL mmap_failed(SB), $12
+
+DATA tls_init_failed(SB)/8, $"tls_init"
+DATA tls_init_failed+8(SB)/8, $" failed\n"
+GLOBL tls_init_failed(SB), $16
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+int32 thread_create(void(*fn)(void), void *stk, void *tls, int32 tlssize);
+void close(int32);
+int32 mutex_create(void);
+int32 mutex_lock(int32);
+int32 mutex_unlock(int32);
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+int8 *goos = "nacl";
+
+// Thread-safe allocation of a mutex.
+// (The name sema is left over from the Darwin implementation.
+// Native Client implements semaphores too, but it is just a shim
+// over the host implementation, which on some hosts imposes a very
+// low limit on how many semaphores can be created.)
+//
+// Psema points at a mutex descriptor.
+// It starts out zero, meaning no mutex.
+// Fill it in, being careful of others calling initsema
+// simultaneously.
+static void
+initsema(uint32 *psema)
+{
+ uint32 sema;
+
+ if(*psema != 0) // already have one
+ return;
+
+ sema = mutex_create();
+ if((int32)sema < 0) {
+ printf("mutex_create failed\n");
+ breakpoint();
+ }
+ // mutex_create returns a file descriptor;
+ // shift it up and add the 1 bit so that can
+ // distinguish unintialized from fd 0.
+ sema = (sema<<1) | 1;
+ if(!cas(psema, 0, sema)){
+ // Someone else filled it in. Use theirs.
+ close(sema);
+ return;
+ }
+}
+
+// Lock and unlock.
+// Defer entirely to Native Client.
+// The expense of a call into Native Client is more like
+// a function call than a system call, so as long as the
+// Native Client lock implementation is good, we can't
+// do better ourselves.
+
+static void
+xlock(int32 fd)
+{
+ if(mutex_lock(fd) < 0) {
+ printf("mutex_lock failed\n");
+ breakpoint();
+ }
+}
+
+static void
+xunlock(int32 fd)
+{
+ if(mutex_unlock(fd) < 0) {
+ printf("mutex_lock failed\n");
+ breakpoint();
+ }
+}
+
+void
+lock(Lock *l)
+{
+ if(m->locks < 0)
+ throw("lock count");
+ m->locks++;
+ if(l->sema == 0)
+ initsema(&l->sema);
+ xlock(l->sema>>1);
+}
+
+void
+unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ throw("lock count");
+ xunlock(l->sema>>1);
+}
+
+
+// One-time notifications.
+//
+// Since the lock/unlock implementation already
+// takes care of sleeping in the kernel, we just reuse it.
+// (But it's a weird use, so it gets its own interface.)
+//
+// We use a lock to represent the event:
+// unlocked == event has happened.
+// Thus the lock starts out locked, and to wait for the
+// event you try to lock the lock. To signal the event,
+// you unlock the lock.
+//
+// Native Client does not require that the thread acquiring
+// a lock be the thread that releases the lock, so this is safe.
+
+void
+noteclear(Note *n)
+{
+ if(n->lock.sema == 0)
+ initsema(&n->lock.sema);
+ xlock(n->lock.sema>>1);
+}
+
+void
+notewakeup(Note *n)
+{
+ if(n->lock.sema == 0) {
+ printf("notewakeup without noteclear");
+ breakpoint();
+ }
+ xunlock(n->lock.sema>>1);
+}
+
+void
+notesleep(Note *n)
+{
+ if(n->lock.sema == 0) {
+ printf("notesleep without noteclear");
+ breakpoint();
+ }
+ xlock(n->lock.sema>>1);
+ xunlock(n->lock.sema>>1); // Let other sleepers find out too.
+}
+
+void
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ void **vstk;
+
+ // I wish every OS made thread creation this easy.
+ m->tls[0] = (uint32)g;
+ m->tls[1] = (uint32)m;
+ vstk = stk;
+ *--vstk = nil;
+ if(thread_create(fn, vstk, m->tls, sizeof m->tls) < 0) {
+ printf("thread_create failed\n");
+ breakpoint();
+ }
+}
+
+void
+osinit(void)
+{
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+minit(void)
+{
+}
extern int32 gomaxprocs;
extern int32 panicking;
extern int32 maxround;
+int8* goos;
/*
* common functions and data
Slice *a;
int32 *v;
+ // TODO(rsc): Remove once TODO at top of file is done.
+ if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0) {
+ symtab = mal(sizeof *a);
+ pclntab = mal(sizeof *a);
+ FLUSH(&symtab);
+ FLUSH(&pclntab);
+ return;
+ }
+
v = SYMCOUNTS;
a = mal(sizeof *a);
byte *p, *ep, *q;
Sym s;
+ // TODO(rsc): Remove once TODO at top of file is done.
+ if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
+ return;
+
v = SYMCOUNTS;
p = SYMDATA;
ep = p + v[0];
Func *f, *ef;
int32 *v;
+ // TODO(rsc): Remove once TODO at top of file is done.
+ if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
+ return;
+
// pc/ln table bounds
v = SYMCOUNTS;
p = SYMDATA;