]> Cypherpunks repositories - gostls13.git/commitdiff
8l, runtime: initial support for Plan 9
authorYuval Pavel Zholkover <paulzhol@gmail.com>
Mon, 18 Oct 2010 16:32:55 +0000 (12:32 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 18 Oct 2010 16:32:55 +0000 (12:32 -0400)
No multiple processes/locks, managed to compile
and run a hello.go (with print not fmt).  Also test/sieve.go
seems to run until 439 and stops with a
'throw: all goroutines are asleep - deadlock!'
- just like runtime/tiny.

based on Russ's suggestions at:
http://groups.google.com/group/comp.os.plan9/browse_thread/thread/cfda8b82535d2d68/243777a597ec1612

Build instructions:
cd src/pkg/runtime
make clean && GOOS=plan9 make install
this will build and install the runtime.

When linking with 8l, you should pass -s to suppress symbol
generation in the a.out, otherwise the generated executable will not run.

This is runtime only, the porting of the toolchain has already
been done: http://code.google.com/p/go-plan9/source/browse
in the plan9-quanstro branch.

R=rsc
CC=golang-dev
https://golang.org/cl/2273041

16 files changed:
src/Make.inc
src/cmd/8l/asm.c
src/cmd/8l/obj.c
src/cmd/8l/pass.c
src/pkg/runtime/386/asm.s
src/pkg/runtime/mkasmh.sh
src/pkg/runtime/plan9/386/defs.h [new file with mode: 0644]
src/pkg/runtime/plan9/386/rt0.s [new file with mode: 0644]
src/pkg/runtime/plan9/386/signal.c [new file with mode: 0644]
src/pkg/runtime/plan9/386/sys.s [new file with mode: 0644]
src/pkg/runtime/plan9/mem.c [new file with mode: 0644]
src/pkg/runtime/plan9/os.h [new file with mode: 0644]
src/pkg/runtime/plan9/signals.h [new file with mode: 0644]
src/pkg/runtime/plan9/thread.c [new file with mode: 0644]
src/pkg/runtime/runtime.c
src/pkg/runtime/runtime.h

index 3334c2cf15922c90d10657296e943a5e089ea20a..f9a3ee28738d88e63a934ffaed9be5bcb6234549 100644 (file)
@@ -34,9 +34,10 @@ else ifeq ($(GOOS),freebsd)
 else ifeq ($(GOOS),linux)
 else ifeq ($(GOOS),nacl)
 else ifeq ($(GOOS),tiny)
+else ifeq ($(GOOS),plan9)
 else ifeq ($(GOOS),windows)
 else
-$(error Invalid $$GOOS '$(GOOS)'; must be darwin, freebsd, linux, nacl, tiny, or windows)
+$(error Invalid $$GOOS '$(GOOS)'; must be darwin, freebsd, linux, nacl, tiny, plan9, or windows)
 endif
 
 ifeq ($(GOHOSTARCH),)
index 74b4e9b7632b3383d82fff512d317b4336808674..b9998b1fbe8901c05845378aa57ae50fee98d419 100644 (file)
@@ -441,6 +441,7 @@ asmb(void)
                        break;
                case 2:
                        seek(cout, HEADR+textsize+segdata.filelen, 0);
+                       symo = HEADR+textsize+segdata.filelen;
                        break;
                case 3:
                case 4:
index 722857e9be4f82ce3f4e8a691bf8e745696588c7..b1574fc2b5a6d35fb1e0c56e2d70192e716618a3 100644 (file)
@@ -144,6 +144,9 @@ main(int argc, char *argv[])
                else
                if(strcmp(goos, "tiny") == 0)
                        HEADTYPE = 11;
+               else
+               if(strcmp(goos, "plan9") == 0)
+                       HEADTYPE = 2;
                else
                        print("goos is not known: %s\n", goos);
        }
index 329a87094b83a1c6708ade4449ca5593b59e2e3f..264771f5702730d57c72b77d42ccf94dfb2fd219 100644 (file)
@@ -293,6 +293,14 @@ patch(void)
                                        p->from.offset = 0;
                                }
                        }
+                       if(HEADTYPE == 2) {     // Plan 9
+                               if(p->from.type == D_INDIR+D_GS
+                               && p->to.type >= D_AX && p->to.type <= D_DI) {
+                                       p->as = AMOVL;
+                                       p->from.type = D_ADDR+D_STATIC;
+                                       p->from.offset += 0xdfffefc0;
+                               }
+                       }
                        if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
                                s = p->to.sym;
                                if(s) {
@@ -418,7 +426,14 @@ dostkoff(void)
                                p->from.offset = tlsoffset + 0;
                                p->to.type = D_CX;
                                break;
-
+                       
+                       case 2: // Plan 9
+                               p->as = AMOVL;
+                               p->from.type = D_ADDR+D_STATIC;
+                               p->from.offset = 0xdfffefc0;
+                               p->to.type = D_CX;
+                               break;
+                       
                        default:
                                p->as = AMOVL;
                                p->from.type = D_INDIR+D_GS;
index 614c026eafd786c21ffc195d2253882ab5841c37..5f0d0ed46821437ef21b494fef8ef6070c38998e 100644 (file)
@@ -26,6 +26,8 @@ TEXT _rt0_386(SB),7,$0
        CALL    ldt0setup(SB)
 
        // store through it, to make sure it works
+       CMPL    isplan9(SB), $1
+       JEQ     ok
        get_tls(BX)
        MOVL    $0x123, g(BX)
        MOVL    tls0(SB), AX
@@ -414,4 +416,4 @@ GLOBL m0(SB), $1024
 GLOBL g0(SB), $1024
 GLOBL tls0(SB), $32
 GLOBL initcgo(SB), $4
-
+GLOBL isplan9(SB), $4
index 8544d15d84a7e8df3921b0316d859290c5597417..3ed5f74c901245b56ee6b5c1404cb3767b48effd 100755 (executable)
@@ -24,6 +24,11 @@ case "$GOARCH" in
                echo '#define   g(r)    0(r)'
                echo '#define   m(r)    4(r)'
                ;;
+       plan9)
+               echo '#define   get_tls(r)'
+               echo '#define   g(r)    0xdfffefc0'
+               echo '#define   m(r)    0xdfffefc4'
+               ;;
        linux)
                # On Linux systems, what we call 0(GS) and 4(GS) for g and m
                # turn into %gs:-8 and %gs:-4 (using gcc syntax to denote
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h
new file mode 100644 (file)
index 0000000..5df7576
--- /dev/null
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/plan9/386/rt0.s
new file mode 100644 (file)
index 0000000..e8d65d3
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2010 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.
+
+TEXT   _rt0_386_plan9(SB),7, $0
+       MOVL    AX, _tos(SB)
+       
+       // move arguments down to make room for
+       // m and g at top of stack, right before Tos.
+       MOVL    SP, SI
+       SUBL    $8, SP
+       MOVL    SP, DI
+               
+       MOVL    AX, CX
+       SUBL    SI, CX
+       CLD
+       REP; MOVSB
+       
+       // adjust argv
+       SUBL    SI, DI
+       MOVL    newargc+0(SP), CX
+       LEAL    newargv+4(SP), BP
+argv_fix:
+       ADDL    DI, 0(BP)
+       ADDL    $4, BP
+       LOOP    argv_fix
+       
+       JMP     _rt0_386(SB)
+
+DATA  isplan9+0(SB)/4, $1
+GLOBL isplan9(SB), $4
+GLOBL _tos(SB), $4
diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/plan9/386/signal.c
new file mode 100644 (file)
index 0000000..e7c9844
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2010 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"
+
+void
+gettime(int64*, int32*) 
+{
+}
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
new file mode 100644 (file)
index 0000000..8dbacc0
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2010 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 "defs.h"
+#include "386/asm.h"
+
+// setldt(int entry, int address, int limit)
+TEXT setldt(SB),7,$0
+       RET
+
+TEXT write(SB),7,$0
+       MOVL    $20, AX
+       INT     $64
+       RET
+
+TEXT exits(SB),7,$0
+       MOVL    $8, AX
+       INT     $64
+       RET
+
+TEXT brk_(SB),7,$0
+       MOVL    $24, AX
+       INT     $64
+       RET
+
+TEXT plan9_semacquire(SB),7,$0
+       MOVL    $37, AX
+       INT     $64
+       RET
+       
+TEXT plan9_semrelease(SB),7,$0
+       MOVL    $38, AX
+       INT     $64
+       RET
+       
+TEXT rfork(SB),7,$0
+       MOVL    $19, AX // rfork
+       INT     $64
+
+       // In parent, return.
+       CMPL    AX, $0
+       JEQ     2(PC)
+       RET
+
+       // In child on old stack.
+       MOVL    mm+12(SP), BX   // m
+       MOVL    gg+16(SP), DX   // g
+       MOVL    fn+20(SP), SI   // fn
+
+       // set SP to be on the new child stack
+       MOVL    stack+8(SP), CX
+       MOVL    CX, SP
+
+       // Initialize m, g.
+       get_tls(AX)
+       MOVL    DX, g(AX)
+       MOVL    BX, m(AX)
+
+       // Initialize AX from _tos->pid
+       MOVL    0xdfffeff8, AX
+       MOVL    AX, m_procid(BX)        // save pid as m->procid
+
+       CALL    stackcheck(SB)  // smashes AX, CX
+       
+       MOVL    0(DX), DX       // paranoia; check they are not nil
+       MOVL    0(BX), BX
+       
+       // more paranoia; check that stack splitting code works
+       PUSHAL
+       CALL    emptyfunc(SB)
+       POPAL
+       
+       CALL    SI      // fn()
+       CALL    exit(SB)
+       RET
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
new file mode 100644 (file)
index 0000000..7d214c3
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2010 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 "malloc.h"
+
+extern byte end[];
+static byte *bloc = { end };
+
+enum
+{
+       Round = 7
+};
+
+void*
+SysAlloc(uintptr ask)
+{
+       uintptr bl;
+       
+       // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+       bl = ((uintptr)bloc + Round) & ~Round;
+       if(brk_((void*)(bl + ask)) < 0)
+               return (void*)-1;
+       bloc = (byte*)bl + ask;
+       return (void*)bl;
+}
+
+void
+SysFree(void *v, uintptr n)
+{
+       // from tiny/mem.c
+       // Push pointer back if this is a free
+       // of the most recent SysAlloc.
+       n += (n + Round) & ~Round;
+       if(bloc == (byte*)v+n)
+               bloc -= n;      
+}
+
+void
+SysUnused(void *v, uintptr n)
+{
+       USED(v, n);
+}
+
+void
+SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h
new file mode 100644 (file)
index 0000000..748cf7a
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2010 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.
+
+extern int32 write(int32 fd, void* buffer, int32 nbytes);
+extern void exits(int8* msg);
+extern int32 brk_(void*);
+
+/* rfork */
+enum
+{
+       RFNAMEG         = (1<<0),
+       RFENVG          = (1<<1),
+       RFFDG           = (1<<2),
+       RFNOTEG         = (1<<3),
+       RFPROC          = (1<<4),
+       RFMEM           = (1<<5),
+       RFNOWAIT        = (1<<6),
+       RFCNAMEG        = (1<<10),
+       RFCENVG         = (1<<11),
+       RFCFDG          = (1<<12),
+       RFREND          = (1<<13),
+       RFNOMNT         = (1<<14)
+};
+extern int32 rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
+extern int32 plan9_semacquire(uint32 *addr, int32 block);
+extern int32 plan9_semrelease(uint32 *addr, int32 count);
diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/plan9/signals.h
new file mode 100644 (file)
index 0000000..5df7576
--- /dev/null
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
new file mode 100644 (file)
index 0000000..96e83fc
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2010 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 "os.h"
+
+int8 *goos = "plan9";
+
+void
+minit(void)
+{
+}
+
+void
+osinit(void)
+{
+}
+
+void
+initsig(int32 queue)
+{
+}
+
+void
+exit(int32)
+{
+       exits(nil);
+}
+
+void
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+       USED(m, g, stk, fn);
+       
+       m->tls[0] = m->id;      // so 386 asm can find it
+       if(0){
+               printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
+                       stk, m, g, fn, rfork, m->id, m->tls[0], &m);
+       }        
+       
+       if (rfork(RFPROC | RFMEM, stk, m, g, fn) < 0 )
+               throw("newosproc: rfork failed");
+}
+
+// Blocking locks.
+
+// Implement Locks, using semaphores.
+// l->key is the number of threads who want the lock.
+// In a race, one thread increments l->key from 0 to 1
+// and the others increment it from >0 to >1.  The thread
+// who does the 0->1 increment gets the lock, and the
+// others wait on the semaphore.  When the 0->1 thread
+// releases the lock by decrementing l->key, l->key will
+// be >0, so it will increment the semaphore to wake up
+// one of the others.  This is the same algorithm used
+// in Plan 9's user-level locks.
+
+void
+lock(Lock *l)
+{
+       if(m->locks < 0)
+               throw("lock count");
+       m->locks++;
+       
+       if(xadd(&l->key, 1) == 1)
+               return; // changed from 0 -> 1; we hold lock
+       // otherwise wait in kernel
+       while(plan9_semacquire(&l->sema, 1) < 0) {
+               /* interrupted; try again */
+       }
+}
+
+void
+unlock(Lock *l)
+{
+       m->locks--;
+       if(m->locks < 0)
+               throw("lock count");
+
+       if(xadd(&l->key, -1) == 0)
+               return; // changed from 1 -> 0: no contention
+       
+       plan9_semrelease(&l->sema, 1);
+}
+
+
+void 
+destroylock(Lock *l)
+{
+       // nothing
+}
+
+// User-level semaphore implementation:
+// try to do the operations in user space on u,
+// but when it's time to block, fall back on the kernel semaphore k.
+// This is the same algorithm used in Plan 9.
+void
+usemacquire(Usema *s)
+{
+       if((int32)xadd(&s->u, -1) < 0)
+               while(plan9_semacquire(&s->k, 1) < 0) {
+                       /* interrupted; try again */
+               }
+}
+
+void
+usemrelease(Usema *s)
+{
+       if((int32)xadd(&s->u, 1) <= 0)
+               plan9_semrelease(&s->k, 1);
+}
+
+
+// Event notifications.
+void
+noteclear(Note *n)
+{
+       n->wakeup = 0;
+}
+
+void
+notesleep(Note *n)
+{
+       while(!n->wakeup)
+               usemacquire(&n->sema);
+}
+
+void
+notewakeup(Note *n)
+{
+       n->wakeup = 1;
+       usemrelease(&n->sema);
+}
+
index 4b09f7bcf7e61acd6d2d8d5f2fcfe737e6bc4949..a8f817733150d5ce731ee72c39526036715b59d8 100644 (file)
@@ -147,15 +147,20 @@ args(int32 c, uint8 **v)
        argv = v;
 }
 
+extern int32 isplan9;
+
 void
 goargs(void)
 {
        String *gargv;
        String *genvv;
        int32 i, envc;
-
-       for(envc=0; argv[argc+1+envc] != 0; envc++)
-               ;
+       
+       if(isplan9)
+               envc=0;
+       else
+               for(envc=0; argv[argc+1+envc] != 0; envc++)
+                       ;
 
        gargv = malloc(argc*sizeof gargv[0]);
        genvv = malloc(envc*sizeof genvv[0]);
index 88f53e2a2efe722ceb06269ff0cb90e613d42d52..92da669d7fdfd4d12be1c7fe6bb4d60278fc4cb4 100644 (file)
@@ -76,7 +76,7 @@ typedef       struct  Complex128      Complex128;
  * segment register.
  *
  * amd64: allocated downwards from R15
- * x86: allocated upwards from 0(FS)
+ * x86: allocated upwards from 0(GS)
  * arm: allocated downwards from R10
  *
  * every C file linked into a Go program must include runtime.h