diff --git a/repos/base/mk/generic.mk b/repos/base/mk/generic.mk
index f90b59fe8..88e3493a9 100644
--- a/repos/base/mk/generic.mk
+++ b/repos/base/mk/generic.mk
@@ -85,6 +85,41 @@ endif
$(MSG_CONVERT)$@
$(VERBOSE)ar p $< $*.0.o > $@
+#
+# Compiling Nim source code
+#
+ifneq ($(SRC_NIM),)
+
+ifeq ($(NIM_CPU),)
+$(warning NIM_CPU not defined for any of the following SPECS: $(SPECS))
+else
+
+NIM_MAKEFILES := $(foreach X,$(SRC_NIM),$(X).mk)
+NIM_ARGS = --compileOnly --os:genode --cpu:$(NIM_CPU)
+NIM_ARGS += --verbosity:0 --hint[Processing]:off --nimcache:.
+NIM_ARGS += $(NIM_OPT)
+
+# Generate the C++ sources and compilation info
+#
+# Unfortunately the existing sources must be purged
+# because of comma problems in the JSON recipe
+%.nim.mk: %.nim
+ $(MSG_BUILD)$(basename $@).cpp
+ $(VERBOSE) rm -f stdlib_*.cpp
+ $(VERBOSE)$(NIM) compileToCpp $(NIM_ARGS) $<
+ $(VERBOSE)$(JQ) --raw-output '"SRC_O_NIM +=" + (.link | join(" ")) +"\n" + (.compile | map((.[0] | sub("cpp$$";"o: ")) + .[0] + "\n\t"+(.[1] | sub("^g\\++";"$$(MSG_COMP)$$@\n\t$$(VERBOSE)$$(NIM_CC)"))) | join("\n"))' < $(basename $(basename $@)).json > $@
+
+NIM_CC := $(CXX) $(CXX_DEF) $(CC_CXX_OPT) $(INCLUDES) -D__GENODE__
+
+# Parse the generated makefiles
+-include $(NIM_MAKEFILES)
+
+# Append the new objects
+SRC_O += $(sort $(SRC_O_NIM))
+
+endif
+endif
+
#
# Assembler files that must be preprocessed are fed to the C compiler.
#
diff --git a/repos/base/mk/global.mk b/repos/base/mk/global.mk
index 246d90128..44c283b5b 100644
--- a/repos/base/mk/global.mk
+++ b/repos/base/mk/global.mk
@@ -50,6 +50,16 @@ STRIP = $(CUSTOM_STRIP)
GNATMAKE = $(CUSTOM_GNATMAKE)
HOST_CC = $(CUSTOM_HOST_CC)
+#
+# Nim toolchain
+#
+NIM ?= nim
+
+#
+# JSON parsing utility
+#
+JQ ?= jq
+
#
# Compiler and Linker options
#
diff --git a/repos/base/mk/spec/arm.mk b/repos/base/mk/spec/arm.mk
index c2d42ead8..6b320482a 100644
--- a/repos/base/mk/spec/arm.mk
+++ b/repos/base/mk/spec/arm.mk
@@ -5,6 +5,8 @@ REP_INC_DIR += include/spec/arm
SPECS += 32bit
+NIM_CPU ?= arm
+
#
# Prevent compiler message
# "note: the mangling of 'va_list' has changed in GCC 4.4"
diff --git a/repos/base/mk/spec/x86_32.mk b/repos/base/mk/spec/x86_32.mk
index 631e04c66..21a9f1208 100644
--- a/repos/base/mk/spec/x86_32.mk
+++ b/repos/base/mk/spec/x86_32.mk
@@ -16,5 +16,7 @@ CC_MARCH ?= -march=i686 -m32
LD_MARCH ?= -melf_i386
AS_MARCH ?= -march=i686 --32
+NIM_CPU ?= i386
+
include $(BASE_DIR)/mk/spec/32bit.mk
include $(BASE_DIR)/mk/spec/x86.mk
diff --git a/repos/base/mk/spec/x86_64.mk b/repos/base/mk/spec/x86_64.mk
index 0c7c95fdd..1d131adf3 100644
--- a/repos/base/mk/spec/x86_64.mk
+++ b/repos/base/mk/spec/x86_64.mk
@@ -20,5 +20,7 @@ CC_MARCH ?= -m64
#
LD_MARCH ?= -melf_x86_64
+NIM_CPU ?= amd64
+
include $(BASE_DIR)/mk/spec/64bit.mk
include $(BASE_DIR)/mk/spec/x86.mk
diff --git a/repos/libports/lib/import/import-libc.mk b/repos/libports/lib/import/import-libc.mk
index f579bc8ae..30ed33368 100644
--- a/repos/libports/lib/import/import-libc.mk
+++ b/repos/libports/lib/import/import-libc.mk
@@ -55,3 +55,8 @@ CC_OPT += -D__ISO_C_VISIBLE=1999
# or 'sincosf', which is a GNU extension, not provided by our libc.
#
CC_OPT += -fno-builtin-sin -fno-builtin-cos -fno-builtin-sinf -fno-builtin-cosf
+
+#
+# Enable Nim POSIX support when linking with this library
+#
+NIM_OPT += -d:posix
diff --git a/repos/libports/lib/import/import-nim-threads.mk b/repos/libports/lib/import/import-nim-threads.mk
new file mode 100644
index 000000000..c42b778e5
--- /dev/null
+++ b/repos/libports/lib/import/import-nim-threads.mk
@@ -0,0 +1 @@
+NIM_OPT += --threads:on --tlsEmulation:on
diff --git a/repos/libports/lib/mk/nim-threads.mk b/repos/libports/lib/mk/nim-threads.mk
new file mode 100644
index 000000000..e69de29bb
diff --git a/repos/libports/run/nim.run b/repos/libports/run/nim.run
new file mode 100644
index 000000000..73d6b9e5f
--- /dev/null
+++ b/repos/libports/run/nim.run
@@ -0,0 +1,62 @@
+set build_components {
+ core init
+ drivers/timer
+ drivers/rtc
+ test/nim
+}
+
+build $build_components
+
+create_boot_directory
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+set boot_modules {
+ core init ld.lib.so
+ libc.lib.so
+ rtc_drv
+ test-nim
+ timer
+}
+
+build_boot_image $boot_modules
+
+append qemu_args "-nographic"
+
+run_genode_until {child "test-nim" exited with exit value 0} 30
diff --git a/repos/libports/run/nim_netty.run b/repos/libports/run/nim_netty.run
new file mode 100644
index 000000000..f2a216b15
--- /dev/null
+++ b/repos/libports/run/nim_netty.run
@@ -0,0 +1,84 @@
+assert_spec linux
+
+set build_components {
+ core init
+ drivers/timer drivers/nic server/ram_fs server/vfs
+ test/nim_echo_server
+ lib/vfs/lxip
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append_platform_drv_config
+
+append config {
+
+}
+
+install_config $config
+
+set boot_modules {
+ core init timer linux_nic_drv ram_fs vfs
+ ld.lib.so libc.lib.so libm.lib.so
+ libc_resolv.lib.so stdcxx.lib.so libc_pipe.lib.so
+ vfs_lxip.lib.so lxip.lib.so
+ test-nim_echo_server
+}
+
+append_platform_drv_boot_modules
+
+build_boot_image $boot_modules
+
+run_genode_until forever
+
+# vi: set ft=tcl :
diff --git a/repos/libports/src/test/nim/main.nim b/repos/libports/src/test/nim/main.nim
new file mode 100644
index 000000000..8a15a299f
--- /dev/null
+++ b/repos/libports/src/test/nim/main.nim
@@ -0,0 +1,112 @@
+import unittest
+const
+ Text = "Hello world!"
+
+suite "echo":
+ echo Text
+
+suite "system":
+ echo "compile date: ", CompileDate, " - ", CompileTime
+ echo("endianness: ",
+ case cpuEndian:
+ of littleEndian:
+ "littleEndian"
+ of bigEndian:
+ "bigEndian"
+ )
+ echo "hostCPU: ", hostCPU
+ echo "NimVersion: ", NimVersion
+ echo "nativeStackTraceSupported: ", $nativeStackTraceSupported
+ echo "getStackTrace:\n", getStackTrace()
+ echo "getFreeMem: ", getFreeMem()
+ echo "getTotalMem: ", getTotalMem()
+ echo "getOccupiedMem: ", getOccupiedMem()
+
+ test "isMainModule":
+ assert isMainModule == true
+ test "hostOS == genode":
+ assert hostOS == "genode"
+
+ test "alloc/dealloc":
+ let p = alloc 768
+ assert(not p.isNil)
+ dealloc p
+
+ test "exception handling":
+ type NovelError = object of SystemError
+ try: raise newException(NovelError, "test exception")
+ except NovelError:
+ discard
+
+import locks, threadpool
+suite "threadpool":
+
+ test "spawn":
+ var L: Lock
+
+ proc threadProc(interval: tuple[a,b: int]) =
+ for i in interval.a..interval.b:
+ acquire L
+ echo i
+ release L
+
+ initLock L
+ for i in 0..3:
+ spawn threadProc((i*10, i*10+4))
+ sync()
+ deinitLock L
+
+ test "threadvar":
+ var
+ L: Lock
+ x {.threadvar.}: int
+ y: int
+
+ proc printVal(id: string) =
+ acquire L
+ echo(
+ id,
+ " x: ", repr(addr(x)),
+ " y: ", repr(addr(y))
+ )
+ inc x
+ inc y
+ release L
+
+ initLock L
+ release L
+ printVal("main thread")
+ for i in 1..4:
+ spawn printVal("spawn "& $i)
+ sync()
+ deinitLock L
+
+suite "I/O":
+ const
+ TestFile = "/testfile"
+ Text = NimVersion & " - " & CompileDate & " - " & CompileTime
+ test "writeFile":
+ writeFile(TestFile, Text)
+ test "readFile":
+ assert readFile(TestFile) == Text
+
+suite "staticExec":
+ const rev = staticExec("git describe")
+ echo "compile time 'git describe': ", rev
+
+import times
+suite "time":
+
+ echo "epochTime() float value: ", epochTime()
+ echo "getTime() float value: ", toSeconds(getTime())
+ echo "cpuTime() float value: ", cpuTime()
+ echo "An hour from now : ", getLocalTime(getTime()) + 1.hours
+ echo "An hour from (UTC) now: ", getGmTime(getTime()) + initInterval(0,0,0,1)
+
+ test "getTime":
+ assert(getTime() != 0.Time)
+
+suite "garbage collector":
+ echo GC_getStatistics()
+
+echo "done"
diff --git a/repos/libports/src/test/nim/target.mk b/repos/libports/src/test/nim/target.mk
new file mode 100644
index 000000000..1aed479ef
--- /dev/null
+++ b/repos/libports/src/test/nim/target.mk
@@ -0,0 +1,6 @@
+TARGET = test-nim
+LIBS = nim-threads libc
+SRC_NIM = main.nim
+
+# Enable extra system assertions
+NIM_OPT += -d:useSysAssert
diff --git a/repos/libports/src/test/nim_echo_server/main.nim b/repos/libports/src/test/nim_echo_server/main.nim
new file mode 100644
index 000000000..cb8ca32c2
--- /dev/null
+++ b/repos/libports/src/test/nim_echo_server/main.nim
@@ -0,0 +1,27 @@
+import asyncnet, asyncdispatch
+
+const
+ CRLF* = "\c\L"
+
+proc processClient(address: string, client: AsyncSocket) {.async.} =
+ echo "accepted connection from ", address
+ while not client.isClosed():
+ let line = await client.recvLine()
+ if line == "":
+ break
+ await client.send(line & CRLF)
+ echo address, " closed connection"
+
+proc serve() {.async.} =
+ let server = newAsyncSocket()
+ server.bindAddr(7.Port)
+ server.listen()
+
+ echo "echo service listening on port 7"
+
+ while true:
+ let res = await server.acceptAddr()
+ asyncCheck processClient(res[0], res[1])
+
+asyncCheck serve()
+runForever()
diff --git a/repos/libports/src/test/nim_echo_server/target.mk b/repos/libports/src/test/nim_echo_server/target.mk
new file mode 100644
index 000000000..99fd281e3
--- /dev/null
+++ b/repos/libports/src/test/nim_echo_server/target.mk
@@ -0,0 +1,6 @@
+TARGET = test-nim_echo_server
+LIBS = libc libc_resolv
+SRC_NIM = main.nim
+
+# Enable extra system assertions
+NIM_OPT += -d:useSysAssert