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.
This commit is contained in:
Emery Hemingway 2018-05-17 12:56:18 +02:00
commit 22f714585b
10 changed files with 107 additions and 37 deletions

View file

@ -1035,14 +1035,19 @@ proc genMainProc(m: BModule) =
"}$N$N" "}$N$N"
GenodeNimMain = GenodeNimMain =
"Libc::Env *genodeEnv;$N" & "extern Genode::Env *nim_runtime_env;$N" &
"extern void nim_component_construct(Genode::Env*);$N$N" &
NimMainBody NimMainBody
ComponentConstruct = ComponentConstruct =
"void Libc::Component::construct(Libc::Env &env) {$N" & "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" & "\tLibc::with_libc([&] () {$N\t" &
"\t// Initialize runtime and globals$N" &
MainProcs & MainProcs &
"\t// Call application construct$N" &
"\t\tnim_component_construct(&env);$N" &
"\t});$N" & "\t});$N" &
"}$N$N" "}$N$N"
@ -1059,6 +1064,7 @@ proc genMainProc(m: BModule) =
elif platform.targetOS == osGenode: elif platform.targetOS == osGenode:
nimMain = GenodeNimMain nimMain = GenodeNimMain
otherMain = ComponentConstruct otherMain = ComponentConstruct
m.includeHeader("<libc/component.h>")
elif optGenDynLib in m.config.globalOptions: elif optGenDynLib in m.config.globalOptions:
nimMain = PosixNimDllMain nimMain = PosixNimDllMain
otherMain = PosixCDllMain otherMain = PosixCDllMain

View file

@ -8,10 +8,15 @@
# #
# Low level dataspace allocator for Genode. # Low level dataspace allocator for Genode.
# For interacting with dataspaces outside of the
# standard library see the Genode Nimble package.
when not defined(genode): when not defined(genode):
{.error: "Genode only module".} {.error: "Genode only module".}
when not declared(GenodeEnv):
include genode/env
type DataspaceCapability {. type DataspaceCapability {.
importcpp: "Genode::Dataspace_capability", pure.} = object importcpp: "Genode::Dataspace_capability", pure.} = object
@ -31,35 +36,35 @@ type
const SlabBackendSize = 4096 const SlabBackendSize = 4096
proc ramAvail(): int {. proc ramAvail(env: GenodeEnv): int {.
importcpp: "genodeEnv->pd().avail_ram().value".} importcpp: "#->pd().avail_ram().value".}
## Return number of bytes available for allocation. ## Return number of bytes available for allocation.
proc capsAvail(): int {. proc capsAvail(env: GenodeEnv): int {.
importcpp: "genodeEnv->pd().avail_caps().value".} importcpp: "#->pd().avail_caps().value".}
## Return the number of available capabilities. ## Return the number of available capabilities.
## Each dataspace allocation consumes a capability. ## Each dataspace allocation consumes a capability.
proc allocDataspace(size: int): DataspaceCapability {. proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {.
importcpp: "genodeEnv->pd().alloc(@)".} importcpp: "#->pd().alloc(@)".}
## Allocate a dataspace and its capability. ## Allocate a dataspace and its capability.
proc attachDataspace(ds: DataspaceCapability): pointer {. proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {.
importcpp: "genodeEnv->rm().attach(@)".} importcpp: "#->rm().attach(@)".}
## Attach a dataspace into the component address-space. ## Attach a dataspace into the component address-space.
proc detachAddress(p: pointer) {. proc detachAddress(env: GenodeEnv; p: pointer) {.
importcpp: "genodeEnv->rm().detach(@)".} importcpp: "#->rm().detach(@)".}
## Detach a dataspace from the component address-space. ## Detach a dataspace from the component address-space.
proc freeDataspace(ds: DataspaceCapability) {. proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {.
importcpp: "genodeEnv->pd().free(@)".} importcpp: "#->pd().free(@)".}
## Free a dataspace. ## Free a dataspace.
proc newMapSlab(): ptr MapSlab = proc newMapSlab(): ptr MapSlab =
let let
ds = allocDataspace SlabBackendSize ds = runtimeEnv.allocDataspace SlabBackendSize
p = attachDataspace ds p = runtimeEnv.attachDataspace ds
result = cast[ptr MapSlab](p) result = cast[ptr MapSlab](p)
result.meta.ds = ds result.meta.ds = ds
@ -89,13 +94,13 @@ proc osAllocPages(size: int): pointer =
# tack a new slab on the tail # tack a new slab on the tail
slab = slab.meta.next slab = slab.meta.next
# move to next slab in linked list # move to next slab in linked list
map.ds = allocDataspace size map.ds = runtimeEnv.allocDataspace size
map.size = size map.size = size
map.attachment = attachDataspace map.ds map.attachment = runtimeEnv.attachDataspace map.ds
result = map.attachment result = map.attachment
proc osTryAllocPages(size: int): pointer = proc osTryAllocPages(size: int): pointer =
if ramAvail() >= size and capsAvail() > 1: if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
result = osAllocPages size result = osAllocPages size
proc osDeallocPages(p: pointer; size: int) = proc osDeallocPages(p: pointer; size: int) =
@ -107,8 +112,8 @@ proc osDeallocPages(p: pointer; size: int) =
if m.size != size: if m.size != size:
echo "cannot partially detach dataspace" echo "cannot partially detach dataspace"
quit -1 quit -1
detachAddress m.attachment runtimeEnv.detachAddress m.attachment
freeDataspace m.ds runtimeEnv.freeDataspace m.ds
m[] = Map() m[] = Map()
return return
slab = slab.meta.next slab = slab.meta.next

29
lib/genode/env.nim Normal file
View file

@ -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

View file

@ -13,6 +13,7 @@
#define _GENODE_CPP__THREAD_H_ #define _GENODE_CPP__THREAD_H_
#include <base/thread.h> #include <base/thread.h>
#include <base/env.h>
#include <util/reconstructible.h> #include <util/reconstructible.h>
namespace Nim { struct SysThread; } namespace Nim { struct SysThread; }

View file

@ -502,11 +502,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz
# include <sys/types.h> # include <sys/types.h>
#endif #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 */ /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
#define NIM_CHECK_SIZE(typ, sz) \ #define NIM_CHECK_SIZE(typ, sz) \
_Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")

View file

@ -38,8 +38,10 @@ when defined(macosx) or defined(bsd):
importc: "sysctl", nodecl.} importc: "sysctl", nodecl.}
when defined(genode): when defined(genode):
proc affinitySpaceTotal(): cuint {. include genode/env
importcpp: "genodeEnv->cpu().affinity_space().total()".}
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
importcpp: "@->cpu().affinity_space().total()".}
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
## returns the numer of the processors/cores the machine has. ## 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 var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
result = sysconf(SC_NPROC_ONLN) result = sysconf(SC_NPROC_ONLN)
elif defined(genode): elif defined(genode):
result = affinitySpaceTotal().int result = runtimeEnv.affinitySpaceTotal().int
else: else:
result = sysconf(SC_NPROCESSORS_ONLN) result = sysconf(SC_NPROCESSORS_ONLN)
if result <= 0: result = 0 if result <= 0: result = 0

View file

@ -1440,7 +1440,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
elif defined(solaris): elif defined(solaris):
result = getApplAux("/proc/" & $getpid() & "/path/a.out") result = getApplAux("/proc/" & $getpid() & "/path/a.out")
elif defined(genode): elif defined(genode):
raiseOSError("POSIX command line not supported") raiseOSError(OSErrorCode(-1), "POSIX command line not supported")
elif defined(freebsd) or defined(dragonfly): elif defined(freebsd) or defined(dragonfly):
result = getApplFreebsd() result = getApplFreebsd()
# little heuristic that may work on other POSIX-like systems: # little heuristic that may work on other POSIX-like systems:

View file

@ -1498,11 +1498,21 @@ when defined(nimdoc):
## macro, use the `error <manual.html#error-pragma>`_ or `fatal ## macro, use the `error <manual.html#error-pragma>`_ or `fatal
## <manual.html#fatal-pragma>`_ pragmas. ## <manual.html#fatal-pragma>`_ pragmas.
elif defined(genode): elif defined(genode):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn, include genode/env
importcpp: "genodeEnv->parent().exit(@); Genode::sleep_forever()",
header: "<base/sleep.h>".} 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): elif defined(nodejs):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
@ -4215,3 +4225,22 @@ when not defined(js):
type type
ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro
## as a `for-loop macro`:idx: ## 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.

View file

@ -78,7 +78,7 @@ when defined(emscripten):
munmap(mmapDescr.realPointer, mmapDescr.realSize) munmap(mmapDescr.realPointer, mmapDescr.realSize)
elif defined(genode): elif defined(genode):
include genodealloc # osAllocPages, osTryAllocPages, osDeallocPages include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages
elif defined(posix): elif defined(posix):
const const

View file

@ -116,6 +116,7 @@ when defined(windows):
importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".} importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}
elif defined(genode): elif defined(genode):
import genode/env
const const
GenodeHeader = "genode_cpp/threads.h" GenodeHeader = "genode_cpp/threads.h"
type type
@ -125,11 +126,12 @@ elif defined(genode):
ThreadVarSlot = int ThreadVarSlot = int
proc initThread(s: var SysThread, proc initThread(s: var SysThread,
env: GenodeEnv,
stackSize: culonglong, stackSize: culonglong,
entry: GenodeThreadProc, entry: GenodeThreadProc,
arg: pointer, arg: pointer,
affinity: cuint) {. affinity: cuint) {.
importcpp: "#.initThread(genodeEnv, @)".} importcpp: "#.initThread(@)".}
proc threadVarAlloc(): ThreadVarSlot = 0 proc threadVarAlloc(): ThreadVarSlot = 0
@ -569,7 +571,7 @@ when hostOS == "windows":
elif defined(genode): elif defined(genode):
var affinityOffset: cuint = 1 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], proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread, nimcall.}, tp: proc (arg: TArg) {.thread, nimcall.},
@ -580,6 +582,7 @@ elif defined(genode):
t.dataFn = tp t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize when hasSharedHeap: t.stackSize = ThreadStackSize
t.sys.initThread( t.sys.initThread(
runtimeEnv,
ThreadStackSize.culonglong, ThreadStackSize.culonglong,
threadProcWrapper[TArg], addr(t), affinityOffset) threadProcWrapper[TArg], addr(t), affinityOffset)
inc affinityOffset inc affinityOffset