summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorEmery Hemingway <emery@vfemail.net>2018-05-17 12:56:18 +0200
committerEmery Hemingway <emery@vfemail.net>2018-06-07 07:21:20 +0200
commit22f714585b943d0b2457c66a78917113072f4503 (patch)
treef346be91bab4f267527043057ec3a5c5276eb7af
parentbf394ed1a1d27d8d38d4bc386946e3442736cd75 (diff)
downloadNim-22f714585b943d0b2457c66a78917113072f4503.tar.gz
Native access to Genode environment
Add a 'GenodeEnv' type and a 'componentConstructHook' to the system
module. The 'componentConstructHook' allows for detection of POSIX style
programs that exit implicitly or native Genode components that
initialize to serve RPC requests and OS signals.

This hook takes a 'GenodeEnv' argument so that the environment interface
is passed cleanly to application code after globals are initialized.
This is an typed pointer to a C++ object, procedures for accessing the
environment will be available from a Nimble library and not included in
the standard library.

The standard library has an internal pointer to the environment object
but this is not for external use, the undocumented global environment
pointer has been removed.
-rw-r--r--compiler/cgen.nim10
-rw-r--r--lib/genode/alloc.nim (renamed from lib/system/genodealloc.nim)43
-rw-r--r--lib/genode/env.nim29
-rw-r--r--lib/genode_cpp/threads.h1
-rw-r--r--lib/nimbase.h5
-rw-r--r--lib/pure/concurrency/cpuinfo.nim8
-rw-r--r--lib/pure/os.nim2
-rw-r--r--lib/system.nim37
-rw-r--r--lib/system/osalloc.nim2
-rw-r--r--lib/system/threads.nim7
10 files changed, 107 insertions, 37 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 6a16474c0..e749c78db 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1035,14 +1035,19 @@ proc genMainProc(m: BModule) =
       "}$N$N"
 
     GenodeNimMain =
-      "Libc::Env *genodeEnv;$N" &
+      "extern Genode::Env *nim_runtime_env;$N" &
+      "extern void nim_component_construct(Genode::Env*);$N$N" &
       NimMainBody
 
     ComponentConstruct =
       "void Libc::Component::construct(Libc::Env &env) {$N" &
-      "\tgenodeEnv = &env;$N" &
+      "\t// Set Env used during runtime initialization$N" &
+      "\tnim_runtime_env = &env;$N" &
       "\tLibc::with_libc([&] () {$N\t" &
+      "\t// Initialize runtime and globals$N" &
       MainProcs &
+      "\t// Call application construct$N" &
+      "\t\tnim_component_construct(&env);$N" &
       "\t});$N" &
       "}$N$N"
 
@@ -1059,6 +1064,7 @@ proc genMainProc(m: BModule) =
   elif platform.targetOS == osGenode:
     nimMain = GenodeNimMain
     otherMain = ComponentConstruct
+    m.includeHeader("<libc/component.h>")
   elif optGenDynLib in m.config.globalOptions:
     nimMain = PosixNimDllMain
     otherMain = PosixCDllMain
diff --git a/lib/system/genodealloc.nim b/lib/genode/alloc.nim
index 3646a842d..52dc1c32c 100644
--- a/lib/system/genodealloc.nim
+++ b/lib/genode/alloc.nim
@@ -8,10 +8,15 @@
 #
 
 # Low level dataspace allocator for Genode.
+# For interacting with dataspaces outside of the
+# standard library see the Genode Nimble package.
 
 when not defined(genode):
   {.error: "Genode only module".}
 
+when not declared(GenodeEnv):
+  include genode/env
+
 type DataspaceCapability {.
   importcpp: "Genode::Dataspace_capability", pure.} = object
 
@@ -31,35 +36,35 @@ type
 
 const SlabBackendSize = 4096
 
-proc ramAvail(): int {.
-  importcpp: "genodeEnv->pd().avail_ram().value".}
+proc ramAvail(env: GenodeEnv): int {.
+  importcpp: "#->pd().avail_ram().value".}
   ## Return number of bytes available for allocation.
 
-proc capsAvail(): int {.
-  importcpp: "genodeEnv->pd().avail_caps().value".}
+proc capsAvail(env: GenodeEnv): int {.
+  importcpp: "#->pd().avail_caps().value".}
   ## Return the number of available capabilities.
   ## Each dataspace allocation consumes a capability.
 
-proc allocDataspace(size: int): DataspaceCapability {.
-  importcpp: "genodeEnv->pd().alloc(@)".}
+proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {.
+  importcpp: "#->pd().alloc(@)".}
   ## Allocate a dataspace and its capability.
 
-proc attachDataspace(ds: DataspaceCapability): pointer {.
-  importcpp: "genodeEnv->rm().attach(@)".}
+proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {.
+  importcpp: "#->rm().attach(@)".}
   ## Attach a dataspace into the component address-space.
 
-proc detachAddress(p: pointer) {.
-  importcpp: "genodeEnv->rm().detach(@)".}
+proc detachAddress(env: GenodeEnv; p: pointer) {.
+  importcpp: "#->rm().detach(@)".}
   ## Detach a dataspace from the component address-space.
 
-proc freeDataspace(ds: DataspaceCapability) {.
-  importcpp: "genodeEnv->pd().free(@)".}
+proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {.
+  importcpp: "#->pd().free(@)".}
   ## Free a dataspace.
 
 proc newMapSlab(): ptr MapSlab =
   let
-    ds = allocDataspace SlabBackendSize
-    p = attachDataspace ds
+    ds = runtimeEnv.allocDataspace SlabBackendSize
+    p = runtimeEnv.attachDataspace ds
   result = cast[ptr MapSlab](p)
   result.meta.ds = ds
 
@@ -89,13 +94,13 @@ proc osAllocPages(size: int): pointer =
           # tack a new slab on the tail
       slab = slab.meta.next
         # move to next slab in linked list
-  map.ds = allocDataspace size
+  map.ds = runtimeEnv.allocDataspace size
   map.size = size
-  map.attachment = attachDataspace map.ds
+  map.attachment = runtimeEnv.attachDataspace map.ds
   result = map.attachment
 
 proc osTryAllocPages(size: int): pointer =
-  if ramAvail() >= size and capsAvail() > 1:
+  if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
     result = osAllocPages size
 
 proc osDeallocPages(p: pointer; size: int) =
@@ -107,8 +112,8 @@ proc osDeallocPages(p: pointer; size: int) =
         if m.size != size:
           echo "cannot partially detach dataspace"
           quit -1
-        detachAddress m.attachment
-        freeDataspace m.ds
+        runtimeEnv.detachAddress m.attachment
+        runtimeEnv.freeDataspace m.ds
         m[] = Map()
         return
     slab = slab.meta.next
diff --git a/lib/genode/env.nim b/lib/genode/env.nim
new file mode 100644
index 000000000..2b180d1b3
--- /dev/null
+++ b/lib/genode/env.nim
@@ -0,0 +1,29 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Emery Hemingway
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#
+# This file contains the minimum required definitions
+# for interacting with the initial Genode environment.
+# It is reserved for use only within the standard
+# library. See ``componentConstructHook`` in the system
+# module for accessing the Genode environment after the
+# standard library has finished initializating.
+#
+
+when not defined(genode):
+  {.error: "Genode only include".}
+
+type
+  GenodeEnvObj {.importcpp: "Genode::Env", header: "<base/env.h>", pure.} = object
+  GenodeEnvPtr = ptr GenodeEnvObj
+
+const runtimeEnvSym = "nim_runtime_env"
+
+when not defined(nimscript):
+  var runtimeEnv {.importcpp: runtimeEnvSym.}: GenodeEnvPtr
diff --git a/lib/genode_cpp/threads.h b/lib/genode_cpp/threads.h
index a7cb2f17b..c901efb45 100644
--- a/lib/genode_cpp/threads.h
+++ b/lib/genode_cpp/threads.h
@@ -13,6 +13,7 @@
 #define _GENODE_CPP__THREAD_H_
 
 #include <base/thread.h>
+#include <base/env.h>
 #include <util/reconstructible.h>
 
 namespace Nim { struct SysThread; }
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 20ac9979b..6dc742910 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -502,11 +502,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz
 #  include <sys/types.h>
 #endif
 
-#if defined(__GENODE__)
-#include <libc/component.h>
-extern Libc::Env *genodeEnv;
-#endif
-
 /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
 #define NIM_CHECK_SIZE(typ, sz) \
   _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index f01488811..6d41aa1b2 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -38,8 +38,10 @@ when defined(macosx) or defined(bsd):
               importc: "sysctl", nodecl.}
 
 when defined(genode):
-  proc affinitySpaceTotal(): cuint {.
-    importcpp: "genodeEnv->cpu().affinity_space().total()".}
+  include genode/env
+
+  proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
+    importcpp: "@->cpu().affinity_space().total()".}
 
 proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
   ## returns the numer of the processors/cores the machine has.
@@ -83,7 +85,7 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
     result = sysconf(SC_NPROC_ONLN)
   elif defined(genode):
-    result = affinitySpaceTotal().int
+    result = runtimeEnv.affinitySpaceTotal().int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
   if result <= 0: result = 0
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 04afb1eff..5008b904c 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1440,7 +1440,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     elif defined(solaris):
       result = getApplAux("/proc/" & $getpid() & "/path/a.out")
     elif defined(genode):
-      raiseOSError("POSIX command line not supported")
+      raiseOSError(OSErrorCode(-1), "POSIX command line not supported")
     elif defined(freebsd) or defined(dragonfly):
       result = getApplFreebsd()
     # little heuristic that may work on other POSIX-like systems:
diff --git a/lib/system.nim b/lib/system.nim
index fee9dc314..fb02fde23 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1498,11 +1498,21 @@ when defined(nimdoc):
     ## macro, use the `error <manual.html#error-pragma>`_ or `fatal
     ## <manual.html#fatal-pragma>`_ pragmas.
 
-
 elif defined(genode):
-  proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn,
-    importcpp: "genodeEnv->parent().exit(@); Genode::sleep_forever()",
-    header: "<base/sleep.h>".}
+  include genode/env
+
+  var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr
+
+  type GenodeEnv* = GenodeEnvPtr
+    ## Opaque type representing Genode environment.
+
+  proc quit*(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn,
+    importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "<base/sleep.h>".}
+
+  proc quit*(errorcode: int = QuitSuccess) =
+    systemEnv.quit(errorCode)
+
+
 
 elif defined(nodejs):
   proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
@@ -4215,3 +4225,22 @@ when not defined(js):
 type
   ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro
                                          ## as a `for-loop macro`:idx:
+
+when defined(genode):
+  var componentConstructHook*: proc (env: GenodeEnv) {.nimcall.}
+      ## Hook into the Genode component bootstrap process.
+      ## This hook is called after all globals are initialized.
+      ## When this hook is set the component will not automatically exit,
+      ## call ``quit`` explicitly to do so. This is the only available method
+      ## of accessing the initial Genode environment.
+
+  proc nim_component_construct(env: GenodeEnv) {.exportc.} =
+    ## Procedure called during ``Component::construct`` by the loader.
+    if componentConstructHook.isNil:
+      env.quit(programResult)
+        # No native Genode application initialization,
+        # exit as would POSIX.
+    else:
+      componentConstructHook(env)
+        # Perform application initialization
+        # and return to thread entrypoint.
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index 9609b6d39..a63eadf8e 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -78,7 +78,7 @@ when defined(emscripten):
     munmap(mmapDescr.realPointer, mmapDescr.realSize)
 
 elif defined(genode):
-  include genodealloc # osAllocPages, osTryAllocPages, osDeallocPages
+  include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages
 
 elif defined(posix):
   const
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 861bde13f..c8ea03f92 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -116,6 +116,7 @@ when defined(windows):
     importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}
 
 elif defined(genode):
+  import genode/env
   const
     GenodeHeader = "genode_cpp/threads.h"
   type
@@ -125,11 +126,12 @@ elif defined(genode):
     ThreadVarSlot = int
 
   proc initThread(s: var SysThread,
+                  env: GenodeEnv,
                   stackSize: culonglong,
                   entry: GenodeThreadProc,
                   arg: pointer,
                   affinity: cuint) {.
-    importcpp: "#.initThread(genodeEnv, @)".}
+    importcpp: "#.initThread(@)".}
 
   proc threadVarAlloc(): ThreadVarSlot = 0
 
@@ -569,7 +571,7 @@ when hostOS == "windows":
 
 elif defined(genode):
   var affinityOffset: cuint = 1
-  # CPU affinity offset for next thread, safe to roll-over
+    ## CPU affinity offset for next thread, safe to roll-over
 
   proc createThread*[TArg](t: var Thread[TArg],
                            tp: proc (arg: TArg) {.thread, nimcall.},
@@ -580,6 +582,7 @@ elif defined(genode):
     t.dataFn = tp
     when hasSharedHeap: t.stackSize = ThreadStackSize
     t.sys.initThread(
+      runtimeEnv,
       ThreadStackSize.culonglong,
       threadProcWrapper[TArg], addr(t), affinityOffset)
     inc affinityOffset