Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/.gitignore b/.gitignore
- index 57774d1..331d3ce 100644
- --- a/.gitignore
- +++ b/.gitignore
- @@ -55,6 +55,7 @@ _darcs/
- /libraries/extensible-exceptions/
- /libraries/filepath/
- /libraries/ghc-prim/
- +/libraries/HaLVMCore
- /libraries/haskell2010/
- /libraries/haskell98/
- /libraries/hoopl/
- @@ -70,6 +71,7 @@ _darcs/
- /libraries/template-haskell/
- /libraries/unix/
- /libraries/utf8-string/
- +/libraries/XenDevice
- /nofib/
- /utils/haddock/
- /utils/hsc2hs/
- @@ -175,3 +177,12 @@ _darcs/
- /extra-gcc-opts
- .tm_properties
- +
- +rts/xen/include/xen
- +
- +.fixed-gmp
- +.halvm-base
- +.linked-gmp
- +.linked-rts
- +.linked-xen
- +.sync
- diff --git a/.gitmodules b/.gitmodules
- index d83bfd0..64ad714 100644
- --- a/.gitmodules
- +++ b/.gitmodules
- @@ -1,56 +1,59 @@
- [submodule "libraries/binary"]
- path = libraries/binary
- - url = ../packages/binary.git
- + url = git://git.haskell.org/packages/binary.git
- ignore = untracked
- [submodule "libraries/bytestring"]
- path = libraries/bytestring
- - url = ../packages/bytestring.git
- + url = git://git.haskell.org/packages/bytestring.git
- ignore = untracked
- [submodule "libraries/Cabal"]
- path = libraries/Cabal
- - url = ../packages/Cabal.git
- + url = git://git.haskell.org/packages/Cabal.git
- ignore = untracked
- [submodule "libraries/containers"]
- path = libraries/containers
- - url = ../packages/containers.git
- + url = git://git.haskell.org/packages/containers.git
- ignore = untracked
- [submodule "libraries/haskeline"]
- path = libraries/haskeline
- - url = ../packages/haskeline.git
- + url = git://git.haskell.org/packages/haskeline.git
- ignore = untracked
- [submodule "libraries/pretty"]
- path = libraries/pretty
- - url = ../packages/pretty.git
- + url = git://git.haskell.org/packages/pretty.git
- ignore = untracked
- [submodule "libraries/terminfo"]
- path = libraries/terminfo
- - url = ../packages/terminfo.git
- + url = git://git.haskell.org/packages/terminfo.git
- ignore = untracked
- [submodule "libraries/transformers"]
- path = libraries/transformers
- - url = ../packages/transformers.git
- + url = git://git.haskell.org/packages/transformers.git
- ignore = untracked
- [submodule "libraries/xhtml"]
- path = libraries/xhtml
- - url = ../packages/xhtml.git
- + url = git://git.haskell.org/packages/xhtml.git
- ignore = untracked
- [submodule "libraries/Win32"]
- path = libraries/Win32
- - url = ../packages/Win32.git
- + url = git://git.haskell.org/packages/Win32.git
- ignore = untracked
- [submodule "libraries/primitive"]
- path = libraries/primitive
- - url = ../packages/primitive.git
- + url = git://git.haskell.org/packages/primitive.git
- ignore = untracked
- [submodule "libraries/vector"]
- path = libraries/vector
- - url = ../packages/vector.git
- + url = git://git.haskell.org/packages/vector.git
- ignore = untracked
- [submodule "libraries/time"]
- path = libraries/time
- - url = ../packages/time.git
- + url = git://git.haskell.org/packages/time.git
- ignore = untracked
- [submodule "libraries/random"]
- path = libraries/random
- - url = ../packages/random.git
- + url = git://git.haskell.org/packages/random.git
- ignore = untracked
- +[submodule "rts/minlibc"]
- + path = rts/minlibc
- + url = git://github.com/GaloisInc/minlibc
- diff --git a/compiler/ghc.mk b/compiler/ghc.mk
- index 58b5ab3..742bcf1 100644
- --- a/compiler/ghc.mk
- +++ b/compiler/ghc.mk
- @@ -313,6 +313,10 @@ compiler_stage1_CONFIGURE_OPTS += --flags=stage1
- compiler_stage2_CONFIGURE_OPTS += --flags=stage2
- compiler_stage3_CONFIGURE_OPTS += --flags=stage3
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +compiler_stage1_CONFIGURE_OPTS += --flags=ghci
- +endif
- +
- ifeq "$(GhcThreaded)" "YES"
- # We pass THREADED_RTS to the stage2 C files so that cbits/genSym.c will bring
- # the threaded version of atomic_inc() into scope.
- diff --git a/configure.ac b/configure.ac
- index 2414a2f..76b95ef 100644
- --- a/configure.ac
- +++ b/configure.ac
- @@ -806,7 +809,12 @@ dnl off_t, because it will affect the result of that test.
- AC_SYS_LARGEFILE
- dnl ** check for specific header (.h) files that we are interested in
- +if test "$TargetOS" = "HaLVM"
- +then
- +AC_CHECK_HEADERS([bfd.h ctype.h dirent.h dlfcn.h errno.h fcntl.h grp.h limits.h locale.h nlist.h pwd.h sys/mman.h sys/resource.h sys/select.h sys/time.h sys/timeb.h sys/timers.h sys/times.h sys/utsname.h sys/wait.h termios.h time.h utime.h windows.h winsock.h sched.h])
- +else
- AC_CHECK_HEADERS([bfd.h ctype.h dirent.h dlfcn.h errno.h fcntl.h grp.h limits.h locale.h nlist.h pthread.h pwd.h signal.h sys/param.h sys/mman.h sys/resource.h sys/select.h sys/time.h sys/timeb.h sys/timers.h sys/times.h sys/utsname.h sys/wait.h termios.h time.h utime.h windows.h winsock.h sched.h])
- +fi
- dnl sys/cpuset.h needs sys/param.h to be included first on FreeBSD 9.1; #7708
- AC_CHECK_HEADERS([sys/cpuset.h], [], [],
- @@ -934,12 +942,17 @@ dnl ################################################################
- dnl ** check whether we need -ldl to get dlopen()
- +if test "$TargetOS" = "HaLVM"
- +then
- +HaveLibDL=NO
- +else
- AC_CHECK_LIB(dl, dlopen,
- [HaveLibDL=YES
- AC_DEFINE([HAVE_LIBDL], [1], [Define to 1 if you need -ldl to get dlopen().])
- LIBS="$LIBS -ldl"],
- [HaveLibDL=NO])
- AC_SUBST(HaveLibDL)
- +fi
- dnl --------------------------------------------------
- dnl * Miscellaneous feature tests
- @@ -964,9 +977,12 @@ FP_LEADING_UNDERSCORE
- FP_VISIBILITY_HIDDEN
- dnl ** check for librt
- +if test "$TargetOS" != "HaLVM"
- +then
- AC_CHECK_LIB(rt, clock_gettime)
- AC_CHECK_FUNCS(clock_gettime timer_settime)
- FP_CHECK_TIMER_CREATE
- +fi
- dnl ** check for Apple's "interesting" long double compatibility scheme
- AC_MSG_CHECKING(for printf\$LDBLStub)
- diff --git a/ghc.mk b/ghc.mk
- index 67d0cbd..525bcce 100644
- --- a/ghc.mk
- +++ b/ghc.mk
- @@ -405,17 +407,21 @@ PACKAGES_STAGE1 += Win32
- endif
- PACKAGES_STAGE1 += time
- ifeq "$(Windows_Host)" "NO"
- +ifneq "$(TargetOS_CPP)" "HaLVM"
- PACKAGES_STAGE1 += unix
- endif
- +endif
- +ifneq "$(TargetOS_CPP)" "HaLVM"
- PACKAGES_STAGE1 += directory
- PACKAGES_STAGE1 += process
- PACKAGES_STAGE1 += hpc
- +PACKAGES_STAGE1 += Cabal/Cabal
- +PACKAGES_STAGE1 += bin-package-db
- +endif
- PACKAGES_STAGE1 += pretty
- PACKAGES_STAGE1 += template-haskell
- -PACKAGES_STAGE1 += Cabal/Cabal
- PACKAGES_STAGE1 += binary
- -PACKAGES_STAGE1 += bin-package-db
- PACKAGES_STAGE1 += hoopl
- PACKAGES_STAGE1 += transformers
- @@ -425,13 +431,24 @@ PACKAGES_STAGE2 += haskell98
- PACKAGES_STAGE2 += haskell2010
- endif
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +PACKAGES_STAGE1 += old-time
- +PACKAGES_STAGE1 += haskell2010
- +PACKAGES_STAGE1 += HALVMCore
- +PACKAGES_STAGE1 += XenDevice
- +endif
- +
- PACKAGES_STAGE1 += xhtml
- ifeq "$(Windows_Target)" "NO"
- ifneq "$(TargetOS_CPP)" "ios"
- +ifneq "$(TargetOS_CPP)" "HaLVM"
- PACKAGES_STAGE1 += terminfo
- endif
- endif
- +endif
- +ifneq "$(TargetOS_CPP)" "HaLVM"
- PACKAGES_STAGE1 += haskeline
- +endif
- # We normally install only the packages down to this point
- REGULAR_INSTALL_PACKAGES := $(addprefix libraries/,$(PACKAGES_STAGE1))
- diff --git a/includes/ghc.mk b/includes/ghc.mk
- index 5342cc8..be9c775 100644
- --- a/includes/ghc.mk
- +++ b/includes/ghc.mk
- @@ -158,6 +158,9 @@ INSTALL_LIBS += $(includes_GHCCONSTANTS_HASKELL_VALUE)
- DERIVE_CONSTANTS_FLAGS += --gcc-program "$(WhatGccIsCalled)"
- DERIVE_CONSTANTS_FLAGS += $(addprefix --gcc-flag$(space),$(includes_CC_OPTS) -fcommon)
- DERIVE_CONSTANTS_FLAGS += --nm-program "$(NM)"
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +DERIVE_CONSTANTS_FLAGS += --gcc-flag -Irts/xen/include
- +endif
- ifneq "$(BINDIST)" "YES"
- $(includes_DERIVEDCONSTANTS): $$(includes_H_CONFIG) $$(includes_H_PLATFORM) $$(includes_H_FILES) $$(rts_H_FILES)
- diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h
- index 0d2404c..2e04b84 100644
- --- a/includes/rts/OSThreads.h
- +++ b/includes/rts/OSThreads.h
- @@ -156,6 +156,30 @@ typedef HANDLE Mutex;
- #endif // CMINUSMINUS
- +# elif defined(HaLVM_TARGET_OS)
- +
- +#if CMINUSMINUS
- +#define ACQUIRE_LOCK(mutex) foreign "C" halvm_acquire_lock(mutex)
- +#define RELEASE_LOCK(mutex) foreign "C" halvm_release_lock(mutex)
- +#define ASSERT_LOCK_HELD(mutex) /* nothing */
- +#else
- +
- +#include <locks.h>
- +
- +typedef halvm_condlock_t Condition;
- +typedef halvm_mutex_t Mutex;
- +typedef halvm_vcpu_t OSThreadId;
- +typedef halvm_vcpukey_t ThreadLocalKey;
- +
- +#define OSThreadProcAttr /* */
- +#define INIT_COND_VAR HALVM_CONDLOCK_INITIALIZER
- +
- +#define ACQUIRE_LOCK(mutex) halvm_acquire_lock(mutex)
- +#define TRY_ACQUIRE_LOCK(mutex) halvm_try_acquire_lock(mutex)
- +#define RELEASE_LOCK(mutex) halvm_release_lock(mutex)
- +#define ASSERT_LOCK_HELD(mutex) /* nothing */
- +#endif
- +
- # else
- # error "Threads not supported"
- # endif
- diff --git a/libffi/HaLVM.patch b/libffi/HaLVM.patch
- new file mode 100644
- index 0000000..bcd813e
- --- /dev/null
- +++ b/libffi/HaLVM.patch
- @@ -0,0 +1,11 @@
- +--- build/config.sub 2012-04-11 19:46:06.000000000 -0700
- ++++ libffi-3.0.11/config.sub 2013-04-09 16:24:12.181057454 -0700
- +@@ -1488,6 +1488,8 @@
- + ;;
- + -nacl*)
- + ;;
- ++ -HaLVM)
- ++ ;;
- + -none)
- + ;;
- + *)
- diff --git a/libffi/ghc.mk b/libffi/ghc.mk
- index 4e177d2..fcc5853 100644
- --- a/libffi/ghc.mk
- +++ b/libffi/ghc.mk
- @@ -58,6 +58,9 @@ $(libffi_STAMP_CONFIGURE): $(TOUCH_DEP)
- cat libffi-tarballs/libffi*.tar.gz | $(GZIP_CMD) -d | { cd libffi && $(TAR_CMD) -xf - ; }
- mv libffi/libffi-* libffi/build
- +# We need to apply a patch to libffi that makes HaLVM a valid build target
- + patch -d libffi/build -p1 < libffi/HaLVM.patch
- +
- # We have to fake a non-working ln for configure, so that the fallback
- # option (cp -p) gets used instead. Otherwise the libffi build system
- # will use cygwin symbolic links which cannot be read by mingw gcc.
- @@ -101,7 +104,7 @@ $(libffi_STAMP_CONFIGURE): $(TOUCH_DEP)
- --libdir=$(TOP)/libffi/build/inst/lib \
- --enable-static=yes \
- --enable-shared=$(libffi_EnableShared) \
- - --host=$(TargetPlatformFull)
- + --target=$(TargetPlatformFull)
- # wc on OS X has spaces in its output, which libffi's Makefile
- # doesn't expect, so we tweak it to sed them out
- diff --git a/libraries/Cabal b/libraries/Cabal
- index 5462f48..c226c0d 160000
- --- a/libraries/Cabal
- +++ b/libraries/Cabal
- @@ -1 +1 @@
- -Subproject commit 5462f486f0ac344b5714382b1a7498ad6d85d085
- +Subproject commit c226c0de042999bbe4c5c339c6c28a9be7f0c6d1
- diff --git a/mk/config.mk.in b/mk/config.mk.in
- index 7cc7aec..0481fec 100644
- --- a/mk/config.mk.in
- +++ b/mk/config.mk.in
- @@ -245,6 +245,10 @@ ifeq "$(PlatformSupportsSharedLibs)" "YES"
- GhcLibWays += dyn
- endif
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +GhcLibWays := v
- +endif
- +
- # Handy way to test whether we're building shared libs or not.
- BuildSharedLibs=$(strip $(if $(findstring dyn,$(GhcLibWays)),YES,NO))
- @@ -271,6 +275,11 @@ GhcRTSWays += thr thr_debug thr_l
- GhcRTSWays += $(if $(findstring p, $(GhcLibWays)),thr_p,)
- GhcRTSWays += $(if $(findstring dyn, $(GhcLibWays)),dyn debug_dyn thr_dyn thr_debug_dyn l_dyn thr_l_dyn,)
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +#GhcRTSWays := thr
- +GhcRTSWays :=
- +endif
- +
- # We can only build GHCi threaded if we have a threaded RTS:
- GhcThreaded = $(if $(findstring thr,$(GhcRTSWays)),YES,NO)
- @@ -299,7 +308,7 @@ StripLibraries=NO
- # doing object-file splitting
- ArchSupportsSplitObjs=$(strip $(if $(filter $(TargetArch_CPP),i386 x86_64 powerpc sparc),YES,NO))
- -OsSupportsSplitObjs=$(strip $(if $(filter $(TargetOS_CPP),mingw32 cygwin32 linux darwin solaris2 freebsd dragonfly netbsd openbsd),YES,NO))
- +OsSupportsSplitObjs=$(strip $(if $(filter $(TargetOS_CPP),mingw32 cygwin32 linux darwin solaris2 freebsd dragonfly netbsd openbsd HaLVM),YES,NO))
- SplitObjsBroken = @SplitObjsBroken@
- SupportsSplitObjs := $(strip \
- @@ -574,9 +583,11 @@ $(eval $(call set_stage_HSC2HS_OPTS,0))
- $(eval $(call set_stage_HSC2HS_OPTS,1))
- $(eval $(call set_stage_HSC2HS_OPTS,2))
- ifeq "$(CrossCompiling)" "YES"
- +ifneq "$(TargetOS_CPP)" "HaLVM"
- SRC_HSC2HS_OPTS_STAGE1 += --cross-compile
- SRC_HSC2HS_OPTS_STAGE2 += --cross-compile
- endif
- +endif
- SRC_HSC2HS_OPTS_STAGE0 += --cflag=-D$(HostArch_CPP)_HOST_ARCH=1 --cflag=-D$(HostOS_CPP)_HOST_OS=1
- SRC_HSC2HS_OPTS_STAGE1 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH=1 --cflag=-D$(TargetOS_CPP)_HOST_OS=1
- SRC_HSC2HS_OPTS_STAGE2 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH=1 --cflag=-D$(TargetOS_CPP)_HOST_OS=1
- diff --git a/mk/project.mk.in b/mk/project.mk.in
- index 69ed885..9083979 100644
- --- a/mk/project.mk.in
- +++ b/mk/project.mk.in
- @@ -145,6 +145,13 @@ else
- Windows_Target=NO
- endif
- +# Bare_Metal=YES if we are targeting a bare metal environment, like HaLVM/xen
- +ifneq "$(findstring $(TargetOS_CPP), HaLVM)" ""
- +Bare_Metal=YES
- +else
- +Bare_Metal=No
- +endif
- +
- # Tell the build system what the host operating system is
- # This distinguishes "msys" and "cygwin", which are not
- # not distinguished by HOST_OS_CPP
- diff --git a/rts/Linker.c b/rts/Linker.c
- index ceb6a4f..148658f 100644
- --- a/rts/Linker.c
- +++ b/rts/Linker.c
- @@ -31,7 +31,7 @@
- #include "GetEnv.h"
- #include "Stable.h"
- -#if !defined(mingw32_HOST_OS)
- +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- #include "posix/Signals.h"
- #endif
- @@ -73,6 +73,7 @@
- #endif
- #if (defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS)) \
- + || defined(HaLVM_TARGET_OS) \
- || (!defined(powerpc_HOST_ARCH) && \
- ( defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || \
- defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS ) || \
- @@ -341,7 +342,7 @@ typedef struct _RtsSymbolVal {
- SymI_HasProto(stg_makeStableNamezh) \
- SymI_HasProto(stg_finalizzeWeakzh)
- -#if !defined (mingw32_HOST_OS)
- +#if !defined (mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- #define RTS_POSIX_ONLY_SYMBOLS \
- SymI_HasProto(__hscore_get_saved_termios) \
- SymI_HasProto(__hscore_set_saved_termios) \
- @@ -353,6 +354,10 @@ typedef struct _RtsSymbolVal {
- SymI_NeedsProto(nocldstop)
- #endif
- +#if defined(HaLVM_TARGET_OS)
- +#define RTS_POSIX_ONLY_SYMBOLS
- +#endif
- +
- #if defined (cygwin32_HOST_OS)
- #define RTS_MINGW_ONLY_SYMBOLS /**/
- /* Don't have the ability to read import libs / archives, so
- diff --git a/rts/RtsSignals.h b/rts/RtsSignals.h
- index be21765..ad13b50 100644
- --- a/rts/RtsSignals.h
- +++ b/rts/RtsSignals.h
- @@ -9,7 +9,7 @@
- #ifndef RTSSIGNALS_H
- #define RTSSIGNALS_H
- -#if !defined(mingw32_HOST_OS)
- +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- #include "posix/Signals.h"
- @@ -17,6 +17,12 @@
- #include "win32/ConsoleHandler.h"
- +#elif defined(HaLVM_TARGET_OS)
- +
- +#include <signal.h>
- +#include <signals.h>
- +extern void startSignalHandlers(Capability *cap);
- +
- #else
- #define signals_pending() (rtsFalse)
- diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
- index 24d50ee..6286f8f 100644
- --- a/rts/RtsStartup.c
- +++ b/rts/RtsStartup.c
- @@ -128,7 +128,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
- return;
- }
- +#ifndef HaLVM_TARGET_OS
- setlocale(LC_CTYPE,"");
- +#endif
- /* Initialise the stats department, phase 0 */
- initStats0();
- @@ -213,7 +215,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
- getStablePtr((StgPtr)runSparks_closure);
- getStablePtr((StgPtr)ensureIOManagerIsRunning_closure);
- getStablePtr((StgPtr)ioManagerCapabilitiesChanged_closure);
- -#ifndef mingw32_HOST_OS
- +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- getStablePtr((StgPtr)runHandlersPtr_closure);
- #endif
- @@ -221,7 +223,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
- initGlobalStore();
- /* initialise file locking, if necessary */
- +#if !defined(HaLVM_TARGET_OS)
- initFileLocking();
- +#endif
- #if defined(DEBUG)
- /* initialise thread label table (tso->char*) */
- @@ -251,7 +255,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
- x86_init_fpu();
- #endif
- +#ifndef HaLVM_TARGET_OS
- startupHpc();
- +#endif
- // This must be done after module initialisation.
- // ToDo: make this work in the presence of multiple hs_add_root()s.
- @@ -351,7 +357,7 @@ hs_exit_(rtsBool wait_foreign)
- exitTimer(wait_foreign);
- // set the terminal settings back to what they were
- -#if !defined(mingw32_HOST_OS)
- +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- resetTerminalSettings();
- #endif
- @@ -364,9 +370,11 @@ hs_exit_(rtsBool wait_foreign)
- /* stop timing the shutdown, we're about to print stats */
- stat_endExit();
- -
- +
- +#ifndef HaLVM_TARGET_OS
- /* shutdown the hpc support (if needed) */
- exitHpc();
- +#endif
- // clean up things from the storage manager's point of view.
- // also outputs the stats (+RTS -s) info.
- @@ -382,7 +390,9 @@ hs_exit_(rtsBool wait_foreign)
- exitLinker();
- /* free file locking tables, if necessary */
- +#if !defined(HaLVM_TARGET_OS)
- freeFileLocking();
- +#endif
- /* free the stable pointer table */
- exitStableTables();
- diff --git a/rts/Schedule.c b/rts/Schedule.c
- index 7f8ced6..c4bdbe6 100644
- --- a/rts/Schedule.c
- +++ b/rts/Schedule.c
- @@ -105,7 +105,7 @@ StgTSO dummy_tso;
- Mutex sched_mutex;
- #endif
- -#if !defined(mingw32_HOST_OS)
- +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
- #define FORKPROCESS_PRIMOP_SUPPORTED
- #endif
- @@ -969,17 +969,16 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
- static void
- scheduleSendPendingMessages(void)
- {
- -
- # if defined(PAR) // global Mem.Mgmt., omit for now
- if (PendingFetches != END_BF_QUEUE) {
- processFetches();
- }
- # endif
- -
- +
- if (RtsFlags.ParFlags.BufferTime) {
- - // if we use message buffering, we must send away all message
- - // packets which have become too old...
- - sendOldBuffers();
- + // if we use message buffering, we must send away all message
- + // packets which have become too old...
- + sendOldBuffers();
- }
- }
- #endif
- diff --git a/rts/Timer.c b/rts/Timer.c
- index b7762f9..7f48414 100644
- --- a/rts/Timer.c
- +++ b/rts/Timer.c
- @@ -25,6 +25,10 @@
- #include "Capability.h"
- #include "RtsSignals.h"
- +#ifdef HaLVM_TARGET_OS
- +#include "iomanager.h"
- +#endif
- +
- /* ticks left before next pre-emptive context switch */
- static int ticks_to_ctxt_switch = 0;
- diff --git a/rts/Trace.c b/rts/Trace.c
- index 2190189..4ac378b 100644
- --- a/rts/Trace.c
- +++ b/rts/Trace.c
- @@ -460,7 +460,7 @@ void traceOSProcessInfo_(void) {
- CAPSET_OSPROCESS_DEFAULT,
- getpid());
- -#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS)
- +#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS) && !defined (HaLVM_TARGET_OS)
- /* Windows has no strong concept of process heirarchy, so no getppid().
- * In any case, this trace event is mainly useful for tracing programs
- * that use 'forkProcess' which Windows doesn't support anyway.
- diff --git a/rts/ghc.mk b/rts/ghc.mk
- index 0d2b341..c442900 100644
- --- a/rts/ghc.mk
- +++ b/rts/ghc.mk
- @@ -33,6 +33,8 @@ ALL_DIRS = hooks sm eventlog
- ifeq "$(HostOS_CPP)" "mingw32"
- ALL_DIRS += win32
- +else ifeq "$(TargetOS_CPP)" "HaLVM"
- +ALL_DIRS += xen minlibc
- else
- ALL_DIRS += posix
- endif
- @@ -311,6 +313,10 @@ ifeq "$(BeConservative)" "YES"
- rts_CC_OPTS += -DBE_CONSERVATIVE
- endif
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +rts_CC_OPTS += -nostdinc -Irts/minlibc/include -Irts/xen/include -Ilibraries/HALVMCore/cbits/include
- +endif
- +
- #-----------------------------------------------------------------------------
- # Flags for compiling specific files
- @@ -556,6 +562,12 @@ ifeq "$(HaveLibMingwEx)" "YES"
- rts_PACKAGE_CPP_OPTS += -DHAVE_LIBMINGWEX
- endif
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +rts_PACKAGE_CPP_OPTS += -DHALVM_SYSTEM_INCLUDES=$(ghcheaderdir)/minlibc
- +else
- +rts_PACKAGE_CPP_OPTS += -DHALVM_SYSTEM_INCLUDES=
- +endif
- +
- $(eval $(call manual-package-config,rts))
- rts/package.conf.inplace : $(includes_H_CONFIG) $(includes_H_PLATFORM)
- diff --git a/rts/minlibc b/rts/minlibc
- new file mode 160000
- index 0000000..6aa83b7
- --- /dev/null
- +++ b/rts/minlibc
- @@ -0,0 +1 @@
- +Subproject commit 6aa83b701308019506732c6a1ae1bde7815550a1
- diff --git a/rts/package.conf.in b/rts/package.conf.in
- index a364fd3..2755758 100644
- --- a/rts/package.conf.in
- +++ b/rts/package.conf.in
- @@ -23,6 +23,7 @@ library-dirs: TOP"/rts/dist/build" PAPI_LIB_DIR FFI_LIB_DIR
- hs-libraries: "HSrts" FFI_LIB
- +#if !defined(HaLVM_TARGET_OS)
- extra-libraries:
- #ifdef HAVE_LIBM
- "m" /* for ldexp() */
- @@ -56,15 +57,21 @@ extra-libraries:
- , "papi"
- #endif
- +#endif /* !defined(HaLVM_TARGET_OS) */
- +
- #ifdef INSTALLING
- -include-dirs: INCLUDE_DIR PAPI_INCLUDE_DIR FFI_INCLUDE_DIR
- +include-dirs: INCLUDE_DIR HALVM_SYSTEM_INCLUDES PAPI_INCLUDE_DIR FFI_INCLUDE_DIR
- #else /* !INSTALLING */
- include-dirs: TOP"/rts/dist/build" TOP"/includes" TOP"/includes/dist-derivedconstants/header" FFI_INCLUDE_DIR
- #endif
- includes: Stg.h
- hugs-options:
- +#ifdef HaLVM_TARGET_OS
- +cc-options: -DHaLVM_TARGET_OS -nostdinc
- +#else
- cc-options:
- +#endif
- ld-options:
- #ifdef LEADING_UNDERSCORE
- diff --git a/rts/sm/Sanity.c b/rts/sm/Sanity.c
- index c653331..95afecd 100644
- --- a/rts/sm/Sanity.c
- +++ b/rts/sm/Sanity.c
- @@ -664,8 +664,13 @@ checkStaticObjects ( StgClosure* static_objects )
- break;
- default:
- - barf("checkStaticObjetcs: strange closure %p (%s)",
- - p, info_type(p));
- + barf("checkStaticObjetcs: strange closure %p (%s)", p,
- +#ifndef HaLVM_TARGET_OS
- + info_type(p)
- +#else
- + "[HaLVM has no info_type()]"
- +#endif
- + );
- }
- }
- }
- diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
- index d002fec..a521800 100644
- --- a/rts/sm/Storage.c
- +++ b/rts/sm/Storage.c
- @@ -35,7 +35,9 @@
- #include <string.h>
- +#ifndef HaLVM_TARGET_OS
- #include "ffi.h"
- +#endif
- /*
- * All these globals require sm_mutex to access in THREADED_RTS mode.
- diff --git a/rts/xen/GetEnv.c b/rts/xen/GetEnv.c
- new file mode 100644
- index 0000000..813ebab
- --- /dev/null
- +++ b/rts/xen/GetEnv.c
- @@ -0,0 +1,14 @@
- +
- +#include "Rts.h"
- +#include "GetEnv.h"
- +
- +void getProgEnvv(int *out_envc, char **out_envv[]) {
- + *out_envc = 0;
- + *out_envv = NULL;
- +
- + return;
- +}
- +
- +void freeProgEnvv(int envc STG_UNUSED, char *envv[] STG_UNUSED) {
- + return;
- +}
- diff --git a/rts/xen/GetTime.c b/rts/xen/GetTime.c
- new file mode 100644
- index 0000000..60ff1f5
- --- /dev/null
- +++ b/rts/xen/GetTime.c
- @@ -0,0 +1,12 @@
- +#include "Rts.h"
- +#include "GetTime.h"
- +
- +#include <sys/time.h>
- +
- +
- +void getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec) {
- + struct timeval tv;
- + gettimeofday(&tv, (struct timezone *) NULL);
- + *sec = tv.tv_sec;
- + *nsec = tv.tv_usec * 1000;
- +}
- diff --git a/rts/xen/OSThreads.c b/rts/xen/OSThreads.c
- new file mode 100644
- index 0000000..2bf14c2
- --- /dev/null
- +++ b/rts/xen/OSThreads.c
- @@ -0,0 +1,6 @@
- +#include "Rts.h"
- +
- +
- +KernelThreadId kernelThreadId(void) {
- + return 0;
- +}
- diff --git a/rts/xen/console.c b/rts/xen/console.c
- new file mode 100644
- index 0000000..1015fd7
- --- /dev/null
- +++ b/rts/xen/console.c
- @@ -0,0 +1,8 @@
- +#include <runtime_reqs.h>
- +#include <hypercalls.h>
- +#include <xen/xen.h>
- +
- +void runtime_write(size_t count, char *msg)
- +{
- + (void)HYPERCALL_console_io(CONSOLEIO_write, count, msg);
- +}
- diff --git a/rts/xen/entryexit.c b/rts/xen/entryexit.c
- new file mode 100644
- index 0000000..ee2f6b8
- --- /dev/null
- +++ b/rts/xen/entryexit.c
- @@ -0,0 +1,220 @@
- +#define __XEN__
- +#include <sys/types.h>
- +#include <stdint.h>
- +#include <stdlib.h>
- +#include <stdio.h>
- +#include <string.h>
- +#include <xen/xen.h>
- +#include <hypercalls.h>
- +#include <xen/sched.h>
- +#include <xen/vcpu.h>
- +#include <errno.h>
- +#include <assert.h>
- +#include <runtime_reqs.h>
- +#include "memory.h"
- +#include "smp.h"
- +#include "locks.h"
- +#include "time_rts.h"
- +#include "signals.h"
- +#include "grants.h"
- +#include <sys/mman.h>
- +
- +void main(int, char**);
- +void runtime_entry(start_info_t *, void *) __attribute__((noreturn));
- +void shutdown(int) __attribute__((noreturn));
- +
- +struct start_info *system_start_info = NULL;
- +struct shared_info *HYPERVISOR_shared_info = NULL;
- +
- +extern void divide_error(void);
- +extern void debug(void);
- +extern void int3(void);
- +extern void overflow(void);
- +extern void bounds(void);
- +extern void invalid_op(void);
- +extern void device_not_available(void);
- +extern void coprocessor_segment_overrun(void);
- +extern void invalid_TSS(void);
- +extern void segment_not_present(void);
- +extern void stack_segment(void);
- +extern void general_protection(void);
- +extern void page_fault(void);
- +extern void spurious_interrupt_bug(void);
- +extern void coprocessor_error(void);
- +extern void alignment_check(void);
- +extern void machine_check(void);
- +extern void simd_coprocessor_error(void);
- +extern void hypervisor_callback(void);
- +extern void failsafe_callback(void);
- +
- +#if 0
- +static trap_info_t trap_table[] = {
- + { 0, 0, FLAT_KERNEL_CS, (unsigned long)divide_error },
- + { 1, 0, FLAT_KERNEL_CS, (unsigned long)debug },
- + { 3, 3, FLAT_KERNEL_CS, (unsigned long)int3 },
- + { 4, 3, FLAT_KERNEL_CS, (unsigned long)overflow },
- + { 5, 3, FLAT_KERNEL_CS, (unsigned long)bounds },
- + { 6, 0, FLAT_KERNEL_CS, (unsigned long)invalid_op },
- + { 7, 0, FLAT_KERNEL_CS, (unsigned long)device_not_available },
- + { 9, 0, FLAT_KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
- + { 10, 0, FLAT_KERNEL_CS, (unsigned long)invalid_TSS },
- + { 11, 0, FLAT_KERNEL_CS, (unsigned long)segment_not_present },
- + { 12, 0, FLAT_KERNEL_CS, (unsigned long)stack_segment },
- + { 13, 0, FLAT_KERNEL_CS, (unsigned long)general_protection },
- + { 14, 0, FLAT_KERNEL_CS, (unsigned long)page_fault },
- + { 15, 0, FLAT_KERNEL_CS, (unsigned long)spurious_interrupt_bug },
- + { 16, 0, FLAT_KERNEL_CS, (unsigned long)coprocessor_error },
- + { 17, 0, FLAT_KERNEL_CS, (unsigned long)alignment_check },
- + { 18, 0, FLAT_KERNEL_CS, (unsigned long)machine_check },
- + { 19, 0, FLAT_KERNEL_CS, (unsigned long)simd_coprocessor_error },
- + { 0, 0, 0, 0 }
- +};
- +#endif
- +
- +enum cmdline_parse_state {
- + stateEmpty,
- + stateSingle,
- + stateDouble
- +};
- +
- +static inline uint32_t get_num_vcpus(void)
- +{
- + uint32_t i;
- +
- + for(i = 0; i < 16384; i++) {
- + vcpu_runstate_info_t rstate_info;
- + long res = HYPERCALL_vcpu_op(VCPUOP_get_runstate_info, i, &rstate_info);
- + if(res < 0)
- + break;
- + }
- +
- + return i;
- +}
- +
- +static char **argv = NULL;
- +static int argc = 0;
- +static void *runtime_stack = NULL;
- +
- +void runtime_entry(start_info_t *start_info, void *init_sp)
- +{
- + enum cmdline_parse_state state;
- + uint32_t num_vcpus, i, pos;
- + unsigned long maxpages;
- + mfn_t shared_info_mfn;
- + size_t cmdline_size;
- +
- + /* system startup stuff, that must occur before we go to GHC */
- + system_start_info = start_info;
- + num_vcpus = get_num_vcpus();
- + assert(num_vcpus > 0);
- + printf("Starting %d-CPU HaLVM\n", num_vcpus);
- + maxpages = initialize_memory(start_info, init_sp);
- + shared_info_mfn = (mfn_t)start_info->shared_info >> PAGE_SHIFT;
- + // just for my own sanity, make sure that the machine address we're
- + // given for the shared info struct is page aligned.
- + assert(!((uintptr_t)start_info->shared_info & (PAGE_SIZE-1)));
- + HYPERVISOR_shared_info = map_frames(&shared_info_mfn,1);
- + runtime_stack = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
- +#ifdef __x86_64__
- + asm("mov %0, %%rsp" :
- + : "r"((uintptr_t)runtime_stack + VCPU_STACK_SIZE - PAGE_SIZE));
- +#else
- + asm("mov %0, %%esp" :
- + : "r"((uintptr_t)runtime_stack + VCPU_STACK_SIZE - PAGE_SIZE));
- +#endif
- + init_signals(HYPERVISOR_shared_info);
- +#ifdef THREADED_RTS
- + init_smp_system(num_vcpus);
- +#else
- + if(num_vcpus > 1)
- + printf("WARNING: Allocated >1 CPUs in the non-threaded RTS.\n");
- +#endif
- + /* Don't register our trap table, as Xen's default gives more useful
- + * information */
- + /* assert(HYPERCALL_set_trap_table(trap_table) >= 0); */
- + assert(HYPERCALL_set_callbacks(hypervisor_callback, failsafe_callback) >= 0);
- + allow_signals(1);
- + init_time(HYPERVISOR_shared_info);
- + init_grants();
- +
- + /* OK, now we need to figure out what command line to give GHC. */
- + cmdline_size = strlen((const char *)start_info->cmd_line) + 1;
- + argc = 0; argv = malloc((6 + cmdline_size) * sizeof(char *));
- + memset(argv, 0, (6 + cmdline_size) * sizeof(char *));
- + /* these are constant ... */
- + argv[argc++] = "HaLVM";
- + argv[argc++] = "+RTS";
- + argv[argc++] = "-c";
- + /* tell GHC how much memory to use */
- + argv[argc] = malloc(16);
- + snprintf(argv[argc],16,"-M%dm", (maxpages - used_frames() - 128) / 256);
- + argc++;
- +#ifdef THREADED_RTS
- + argv[argc++] = "-N";
- +#endif
- + /* close off the RTS section */
- + argv[argc++] = "-RTS";
- + /* copy over the command line arguments */
- + for(i = 0, state = stateEmpty, pos = 0; start_info->cmd_line[i]; i++) {
- + switch(start_info->cmd_line[i]) {
- + case ' ':
- + if(state == stateEmpty) {
- + if(argv[argc])
- + argv[argc++][pos] = '\0'; pos = 0;
- + } else {
- + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
- + argv[argc][pos++] = ' ';
- + }
- + break;
- +
- + case '\'':
- + if(state == stateSingle) {
- + argv[argc++][pos] = '\0'; pos = 0; state = stateEmpty;
- + } else if(state == stateDouble) {
- + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
- + argv[argc][pos++] = '\'';
- + } else {
- + state = stateSingle;
- + }
- + break;
- +
- + case '"':
- + if(state == stateDouble) {
- + argv[argc++][pos] = '\0'; pos = 0; state = stateEmpty;
- + } else if(state == stateSingle) {
- + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
- + argv[argc][pos++] = '\"';
- + } else {
- + state = stateDouble;
- + }
- + break;
- +
- + default:
- + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
- + argv[argc][pos++] = start_info->cmd_line[i];
- + break;
- + }
- + }
- + if(argv[argc]) {
- + argv[argc][pos++] = '\0';
- + argc++;
- + }
- +
- + /* Jump to GHC */
- + main(argc, argv);
- +
- + /* Ideally we should never get here, but just in case GHC returns ... */
- + runtime_exit();
- +}
- +
- +void runtime_exit(void)
- +{
- + shutdown(SHUTDOWN_poweroff);
- +}
- +
- +/* SCHEDOP_shutdown tells Xen not to schedule us anymore. Toolstack cleans up */
- +void shutdown(int reason)
- +{
- + sched_shutdown_t op ={ .reason = reason ? SHUTDOWN_crash : SHUTDOWN_poweroff};
- + for( ;; ) HYPERCALL_sched_op(SCHEDOP_shutdown, &op);
- +}
- diff --git a/rts/xen/faults.c b/rts/xen/faults.c
- new file mode 100644
- index 0000000..b9a84e8
- --- /dev/null
- +++ b/rts/xen/faults.c
- @@ -0,0 +1,85 @@
- +#include <stdio.h>
- +#include <runtime_reqs.h>
- +
- +#ifdef __i386__
- +struct pt_regs {
- + long ebx;
- + long ecx;
- + long edx;
- + long esi;
- + long edi;
- + long ebp;
- + long eax;
- + long xds;
- + long xes;
- + long orig_eax;
- + long ip;
- + long xcs;
- + long eflags;
- + long esp;
- + long xss;
- +};
- +#endif
- +
- +#ifdef __x86_64__
- +struct pt_regs {
- + unsigned long r15;
- + unsigned long r14;
- + unsigned long r13;
- + unsigned long r12;
- + unsigned long rbp;
- + unsigned long rbx;
- + unsigned long r11;
- + unsigned long r10;
- + unsigned long r9;
- + unsigned long r8;
- + unsigned long rax;
- + unsigned long rcx;
- + unsigned long rdx;
- + unsigned long rsi;
- + unsigned long rdi;
- + unsigned long orig_rax;
- + unsigned long ip;
- + unsigned long cs;
- + unsigned long eflags;
- + unsigned long rsp;
- + unsigned long ss;
- +};
- +#endif
- +
- +#define DEFINE_FAULT2(name, str) \
- +void name(struct pt_regs *, unsigned long) __attribute__((noreturn)); \
- +void name(struct pt_regs *regs, unsigned long code) \
- +{ \
- + printf("FAULT: %s at %p, error code %lx\n", str, (void*)regs->ip, code); \
- + runtime_exit(); \
- +}
- +
- +#define DEFINE_FAULT1(name, str) \
- +void name(struct pt_regs *) __attribute__((noreturn)); \
- +void name(struct pt_regs *regs) \
- +{ \
- + printf("FAULT: %s at %p\n", str, (void*)regs->ip); \
- + runtime_exit(); \
- +}
- +
- +DEFINE_FAULT2(do_divide_error, "divide error")
- +DEFINE_FAULT2(do_int3, "int3")
- +DEFINE_FAULT2(do_overflow, "overflow")
- +DEFINE_FAULT2(do_bounds, "bounds error")
- +DEFINE_FAULT2(do_invalid_op, "invalid operation")
- +DEFINE_FAULT2(do_device_not_available, "device not available")
- +DEFINE_FAULT2(do_coprocessor_segment_overrun, "coprocessor segment overrun")
- +DEFINE_FAULT2(do_invalid_TSS, "invalid TSS")
- +DEFINE_FAULT2(do_segment_not_present, "segment not present")
- +DEFINE_FAULT2(do_stack_segment, "stack segment")
- +DEFINE_FAULT2(do_alignment_check, "alignment check")
- +DEFINE_FAULT2(do_machine_check, "machine check")
- +DEFINE_FAULT2(do_page_fault, "page fault")
- +DEFINE_FAULT2(do_general_protection, "general protection")
- +
- +DEFINE_FAULT1(do_debug, "debug")
- +DEFINE_FAULT1(do_coprocessor_error, "coprocessor error")
- +DEFINE_FAULT1(simd_math_error, "SIMD math error")
- +DEFINE_FAULT1(do_simd_coprocessor_error, "SIMD coprocessor error")
- +DEFINE_FAULT1(do_spurious_interrupt_bug, "spurious interrupt")
- diff --git a/rts/xen/grants.c b/rts/xen/grants.c
- new file mode 100644
- index 0000000..d7905eb
- --- /dev/null
- +++ b/rts/xen/grants.c
- @@ -0,0 +1,502 @@
- +#define __XEN__
- +#include <stdint.h>
- +#include <stdlib.h>
- +#include <alloca.h>
- +#include <xen/xen.h>
- +#include <xen/grant_table.h>
- +#include <xen/memory.h>
- +#include "grants.h"
- +#include "hypercalls.h"
- +#include <assert.h>
- +#include "memory.h"
- +#include <string.h>
- +#include <errno.h>
- +#include "vmm.h"
- +
- +#define min(a,b) (((a)<(b)) ? (a) : (b))
- +
- +static int grant_table_interface_verson = 0;
- +
- +/*******************************************************************************
- + *
- + * VERSION 2 INTERFACE (PREFERRED)
- + *
- + ******************************************************************************/
- +
- +static grant_entry_v2_t *grant_table = NULL;
- +static grant_status_t *status_table = NULL;
- +static grant_ref_t max_ref = 0;
- +
- +static void init_grants_v2(void)
- +{
- + gnttab_query_size_t qsize = { .dom = DOMID_SELF };
- + gnttab_setup_table_t stable = { .dom = DOMID_SELF };
- + gnttab_get_status_frames_t gsf = { .dom = DOMID_SELF };
- + uint32_t i, num_stat_frames;
- + xen_pfn_t *table_pfns;
- + uint64_t *stat_pfns;
- + mfn_t *mframes;
- +
- + /* figure out how big we can make our grant table */
- + assert(HYPERCALL_grant_table_op(GNTTABOP_query_size, &qsize, 1) >= 0);
- + assert(qsize.status == GNTST_okay);
- +
- + /* allocate the grant table */
- + table_pfns = alloca(qsize.max_nr_frames * sizeof(xen_pfn_t));
- + memset(table_pfns, 0, qsize.max_nr_frames * sizeof(xen_pfn_t));
- + stable.nr_frames = qsize.max_nr_frames;
- + stable.frame_list.p = table_pfns;
- + assert( HYPERCALL_grant_table_op(GNTTABOP_setup_table, &stable, 1) >= 0);
- + assert( stable.status == GNTST_okay );
- +
- + /* map it into our address space */
- + mframes = alloca(qsize.max_nr_frames * sizeof(mfn_t));
- + memset(mframes, 0, qsize.max_nr_frames * sizeof(mfn_t));
- + for(i = 0; i < qsize.max_nr_frames; i++)
- + mframes[i] = table_pfns[i];
- + grant_table = map_frames(mframes, qsize.max_nr_frames);
- +
- + /* note down the maximum grant reference */
- + max_ref = (qsize.max_nr_frames * PAGE_SIZE) / sizeof(grant_entry_v2_t);
- + num_stat_frames = qsize.nr_frames;
- + max_ref = min(max_ref, (qsize.nr_frames * PAGE_SIZE) / sizeof(uint16_t));
- +
- + /* allocate the status table */
- + stat_pfns = alloca(qsize.max_nr_frames * sizeof(uint64_t));
- + memset(stat_pfns, 0, qsize.max_nr_frames * sizeof(uint64_t));
- + gsf.nr_frames = num_stat_frames;
- + gsf.frame_list.p = stat_pfns;
- + assert(HYPERCALL_grant_table_op(GNTTABOP_get_status_frames, &gsf, 1) >= 0);
- + assert(gsf.status == GNTST_okay);
- +
- + /* map it into our address space */
- + memset(mframes, 0, qsize.max_nr_frames * sizeof(mfn_t));
- + for(i = 0; i < qsize.max_nr_frames; i++)
- + mframes[i] = stat_pfns[i];
- + status_table = map_frames(mframes, num_stat_frames);
- +}
- +
- +static long alloc_grant_v2(domid_t dom, void *p, uint16_t len, int ro,
- + grant_ref_t *pref)
- +{
- + uint16_t offset;
- + grant_ref_t i;
- + pte_t pte;
- + mfn_t mfn;
- +
- + offset = (uint16_t)((uintptr_t)p & (PAGE_SIZE-1));
- + if( (offset + len) > 4096 ) return -EINVAL;
- + pte = get_pt_entry(p);
- + if( !ENTRY_PRESENT(pte) ) return -EINVAL;
- + mfn = pte >> PAGE_SHIFT;
- +
- + for(i = 0; i < max_ref; i++) {
- + if( (grant_table[i].hdr.flags & GTF_type_mask) == GTF_invalid ) {
- + uint16_t flags = GTF_permit_access;
- +
- + grant_table[i].hdr.domid = dom;
- + if(len == 4096) {
- + grant_table[i].full_page.frame = mfn;
- + } else {
- + grant_table[i].sub_page.page_off = offset;
- + grant_table[i].sub_page.length = len;
- + grant_table[i].sub_page.frame = mfn;
- + flags |= GTF_sub_page;
- + }
- +
- + if(ro) flags |= GTF_readonly;
- + system_wmb();
- + grant_table[i].hdr.flags = flags;
- +
- + *pref = i;
- + return 0;
- + }
- + }
- +
- + return -EXFULL;
- +}
- +
- +static long end_grant_v2(grant_ref_t gref)
- +{
- + if(gref >= max_ref)
- + return -EINVAL;
- +
- + grant_table[gref].hdr.flags = 0;
- + system_mb();
- +
- + if( status_table[gref] & (GTF_reading | GTF_writing) )
- + return -EAGAIN;
- +
- + system_mb();
- + return 1;
- +}
- +
- +static long prepare_transfer_v2(domid_t dom)
- +{
- + grant_ref_t i;
- +
- + for(i = 0; i < max_ref; i++)
- + if( (grant_table[i].hdr.flags & GTF_type_mask) == GTF_invalid ) {
- + grant_table[i].hdr.domid = dom;
- + grant_table[i].hdr.flags = GTF_accept_transfer;
- + return i;
- + }
- +
- + return -EXFULL;
- +}
- +
- +static long complete_transfer_v2(grant_ref_t ref, int reset)
- +{
- + xen_pfn_t mfn;
- + uint16_t flags;
- +
- + if(ref >= max_ref)
- + return -EINVAL;
- +
- + flags = grant_table[ref].hdr.flags;
- + if( !(flags & GTF_transfer_committed) )
- + return -EAGAIN;
- +
- + while( !(flags & GTF_transfer_completed) ) {
- + flags = grant_table[ref].hdr.flags;
- + }
- +
- + mfn = grant_table[ref].full_page.frame;
- + assert(mfn);
- +
- + if(reset) {
- + grant_table[ref].hdr.flags = GTF_accept_transfer;
- + } else {
- + grant_table[ref].hdr.flags = 0;
- + }
- +
- + return mfn;
- +}
- +
- +/*******************************************************************************
- + *
- + * VERSION 1 INTERFACE (DEPRECATED, BUT REQUIRED BY AMAZON)
- + *
- + ******************************************************************************/
- +
- +#define V1_NR_GRANT_FRAMES 4
- +#define V1_NUM_ENTRIES (V1_NR_GRANT_FRAMES*PAGE_SIZE / sizeof(grant_entry_v1_t))
- +
- +static grant_entry_v1_t *v1_grant_table;
- +
- +static void init_grants_v1(void)
- +{
- + struct gnttab_setup_table setup;
- + mfn_t frames[V1_NR_GRANT_FRAMES];
- +
- + setup.dom = DOMID_SELF;
- + setup.nr_frames = V1_NR_GRANT_FRAMES;
- + setup.frame_list.p = (unsigned long*)frames;
- +
- + assert(HYPERCALL_grant_table_op(GNTTABOP_setup_table, &setup, 1) >= 0);
- + v1_grant_table = map_frames(frames, V1_NR_GRANT_FRAMES);
- +}
- +
- +static long alloc_grant_v1(domid_t dom, void *p,
- + uint16_t len __attribute__((unused)),
- + int ro,
- + grant_ref_t *pref)
- +{
- + grant_ref_t i;
- + pte_t pte;
- + mfn_t mfn;
- +
- + pte = get_pt_entry(p);
- + if( !ENTRY_PRESENT(pte) ) return -EINVAL;
- + mfn = pte >> PAGE_SHIFT;
- +
- + for(i = 0; i < V1_NUM_ENTRIES; i++)
- + {
- + if( (v1_grant_table[i].flags & GTF_type_mask) == GTF_invalid )
- + {
- + v1_grant_table[i].frame = mfn;
- + v1_grant_table[i].domid = dom;
- + system_wmb();
- + v1_grant_table[i].flags = GTF_permit_access | (ro ? GTF_readonly : 0);
- + system_wmb();
- +
- + *pref = i;
- + return 0;
- + }
- + }
- +
- + return -EXFULL;
- +}
- +
- +static long end_grant_v1(grant_ref_t gref)
- +{
- + uint16_t flags;
- + int done = 0;
- +
- + if(gref >= V1_NUM_ENTRIES)
- + return -EINVAL;
- +
- + flags = v1_grant_table[gref].flags;
- + do {
- + if(flags & (GTF_reading | GTF_writing))
- + return -EAGAIN;
- + done =
- + __atomic_compare_exchange_n(&v1_grant_table[gref].flags, &flags, 0,
- + 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
- + } while(!done);
- +
- + return 1;
- +}
- +
- +static long prepare_transfer_v1(domid_t dom)
- +{
- + grant_ref_t i;
- +
- + for(i = 0; i < V1_NUM_ENTRIES; i++)
- + {
- + if( (v1_grant_table[i].flags & GTF_type_mask) == GTF_invalid )
- + {
- + v1_grant_table[i].domid = dom;
- + v1_grant_table[i].flags = GTF_accept_transfer;
- + return i;
- + }
- + }
- +
- + return -EXFULL;
- +}
- +
- +static long complete_transfer_v1(grant_ref_t ref, int reset)
- +{
- + xen_pfn_t mfn;
- + uint16_t flags;
- +
- + if(ref >= V1_NUM_ENTRIES)
- + return -EINVAL;
- +
- + flags = v1_grant_table[ref].flags;
- + if( !(flags & GTF_transfer_committed) )
- + return -EAGAIN;
- +
- + mfn = v1_grant_table[ref].frame;
- + assert(mfn);
- +
- + v1_grant_table[ref].flags = reset ? GTF_accept_transfer : GTF_invalid;
- + return mfn;
- +}
- +
- +/*******************************************************************************
- + *
- + * High-Level Interface
- + *
- + ******************************************************************************/
- +
- +void init_grants(void)
- +{
- + gnttab_set_version_t svers = { .version = 2 };
- +
- + /* we really want to use version 2 of the grant table API */
- + if(HYPERCALL_grant_table_op(GNTTABOP_set_version, &svers, 1) >= 0) {
- + /* that should have worked, but let's double check, for sanity */
- + gnttab_get_version_t gvers = { .dom = DOMID_SELF };
- + assert(HYPERCALL_grant_table_op(GNTTABOP_get_version, &gvers, 1) >= 0);
- + assert(gvers.version == 2);
- + grant_table_interface_verson = 2;
- + init_grants_v2();
- + } else {
- + grant_table_interface_verson = 1;
- + init_grants_v1();
- + }
- +}
- +
- +long alloc_grant(domid_t dom, void *p, uint16_t len, int ro, grant_ref_t *pref)
- +{
- + if(grant_table_interface_verson == 2)
- + return alloc_grant_v2(dom, p, len, ro, pref);
- + else
- + return alloc_grant_v1(dom, p, len, ro, pref);
- +}
- +
- +long end_grant(grant_ref_t gref)
- +{
- + if(grant_table_interface_verson == 2)
- + return end_grant_v2(gref);
- + else
- + return end_grant_v1(gref);
- +}
- +
- +long map_grants(domid_t dom, int readonly,
- + grant_ref_t *refs, size_t count,
- + void **outptr, uint32_t *outhndls,
- + uint64_t *outpaddrs)
- +{
- + gnttab_map_grant_ref_t *args;
- + uintptr_t addr;
- + uint16_t flags;
- + size_t i;
- + long res;
- +
- + if(!outptr)
- + return -EINVAL;
- + *outptr = NULL;
- +
- + if(!outhndls)
- + return -EINVAL;
- + memset(outhndls, 0, sizeof(uint32_t) * count);
- +
- + args = calloc(count, sizeof(gnttab_map_grant_ref_t));
- + if(!args)
- + return -ENOMEM;
- +
- + addr = (uintptr_t)claim_shared_space(count * 4096);
- +
- + flags = GNTMAP_host_map | GNTMAP_application_map;
- + if(readonly)
- + flags |= GNTMAP_readonly;
- + if(outpaddrs)
- + flags |= GNTMAP_device_map;
- +
- + for(i = 0; i < count; i++) {
- + args[i].host_addr = addr + (i * PAGE_SIZE);
- + args[i].flags = flags;
- + args[i].ref = refs[i];
- + args[i].dom = dom;
- + }
- +
- + res = HYPERCALL_grant_table_op(GNTTABOP_map_grant_ref, args, count);
- + if(res < 0) {
- + free(args);
- + return res;
- + }
- +
- + for(i = 0; i < count; i++)
- + if(args[i].status != GNTST_okay) {
- + free(args);
- + return -args[i].status;
- + }
- +
- + *outptr = (void*)addr;
- + for(i = 0; i < count; i++) {
- + outhndls[i] = args[i].handle;
- + if(outpaddrs) outpaddrs[i] = args[i].dev_bus_addr;
- + }
- +
- + free(args);
- + return 0;
- +}
- +
- +long unmap_grants(grant_handle_t *handles, size_t count)
- +{
- + gnttab_unmap_grant_ref_t *args;
- + size_t i;
- + long res;
- +
- + args = calloc(count, sizeof(gnttab_unmap_grant_ref_t));
- + if(!args) {
- + return -ENOMEM;
- + }
- +
- + for(i = 0; i < count; i++)
- + args[i].handle = handles[i];
- +
- + res = HYPERCALL_grant_table_op(GNTTABOP_unmap_grant_ref, args, count);
- + if(res < 0) {
- + free(args);
- + return res;
- + }
- +
- + for(i = 0; i < count; i++)
- + if(args[i].status != GNTST_okay) {
- + free(args);
- + return -args[i].status;
- + }
- +
- + free(args);
- + return 0;
- +}
- +
- +long prepare_transfer(domid_t dom)
- +{
- + if(grant_table_interface_verson == 2)
- + return prepare_transfer_v2(dom);
- + else
- + return prepare_transfer_v1(dom);
- +}
- +
- +long transfer_frame(domid_t dom, grant_ref_t ref, void *ptr)
- +{
- + xen_memory_reservation_t rsv;
- + gnttab_transfer_t trans;
- + xen_pfn_t pfn, mfn, new_mfn;
- + pte_t pte;
- + long res;
- +
- + if( (uintptr_t)ptr & (PAGE_SIZE-1) ) {
- + return -EINVAL; /* this needs to be page aligned */
- + }
- +
- + pte = get_pt_entry(ptr);
- + if( !ENTRY_PRESENT(pte) ) {
- + return -EINVAL; /* and it must be mapped */
- + }
- +
- + mfn = pte >> PAGE_SHIFT;
- + set_pt_entry(ptr, NULL); /* unmap it */
- +
- + /* replace the PFN we're using */
- + pfn = machine_to_phys_mapping[mfn];
- + assert(pfn);
- + rsv.extent_start.p = &new_mfn;
- + rsv.nr_extents = 1;
- + rsv.extent_order = 0;
- + rsv.mem_flags = 0;
- + rsv.domid = DOMID_SELF;
- + res = HYPERCALL_memory_op(XENMEM_increase_reservation, &rsv);
- + if( res < 0 ) {
- + return res;
- + }
- + p2m_map[pfn] = new_mfn;
- +
- + /* do the transfer */
- + trans.mfn = mfn;
- + trans.domid = dom;
- + trans.ref = ref;
- + res = HYPERCALL_grant_table_op(GNTTABOP_transfer, &trans, 1);
- + return (res < 0) ? res : trans.status;
- +}
- +
- +long complete_transfer(grant_ref_t ref, int reset)
- +{
- + if(grant_table_interface_verson == 2)
- + return complete_transfer_v2(ref, reset);
- + else
- + return complete_transfer_v1(ref, reset);
- +}
- +
- +long copy_frame(unsigned long src, int src_is_ref, domid_t sdom, uint16_t soff,
- + unsigned long dst, int dst_is_ref, domid_t ddom, uint16_t doff,
- + uint16_t length)
- +{
- + gnttab_copy_t copy;
- + long res;
- +
- + memset(©, 0, sizeof(gnttab_copy_t));
- +
- + if(src_is_ref) {
- + copy.source.u.ref = src;
- + copy.flags = GNTCOPY_source_gref;
- + } else copy.source.u.gmfn = src;
- +
- + if(dst_is_ref) {
- + copy.dest.u.ref = dst;
- + copy.flags |= GNTCOPY_dest_gref;
- + } else copy.dest.u.gmfn = dst;
- +
- + copy.source.domid = sdom;
- + copy.source.offset = soff;
- + copy.dest.domid = ddom;
- + copy.dest.offset = doff;
- + copy.len = length;
- +
- + res = HYPERCALL_grant_table_op(GNTTABOP_copy, ©, 1);
- + return (res < 0) ? res : copy.status;
- +}
- diff --git a/rts/xen/hypercalls.c b/rts/xen/hypercalls.c
- new file mode 100644
- index 0000000..bbb0fd5
- --- /dev/null
- +++ b/rts/xen/hypercalls.c
- @@ -0,0 +1,113 @@
- +#define __XEN__
- +#include <hypercalls.h>
- +#include <xen/xen.h>
- +
- +#ifdef __i386__
- +#define HC_RET "eax"
- +#define HC_ARG1 "ebx"
- +#define HC_ARG2 "ecx"
- +#define HC_ARG3 "edx"
- +#define HC_ARG4 "esi"
- +#define HC_ARG5 "edi"
- +#endif
- +
- +#ifdef __x86_64__
- +#define HC_RET "rax"
- +#define HC_ARG1 "rdi"
- +#define HC_ARG2 "rsi"
- +#define HC_ARG3 "rdx"
- +#define HC_ARG4 "r10"
- +#define HC_ARG5 "r8"
- +#endif
- +
- +extern struct { char _entry[32]; } hypercall_page[];
- +
- +#define hypercall(x, a1, a2, a3, a4, a5) \
- + ({ \
- + register unsigned long __res asm(HC_RET); \
- + register unsigned long __arg1 asm(HC_ARG1) = __arg1; \
- + register unsigned long __arg2 asm(HC_ARG2) = __arg2; \
- + register unsigned long __arg3 asm(HC_ARG3) = __arg3; \
- + register unsigned long __arg4 asm(HC_ARG4) = __arg4; \
- + register unsigned long __arg5 asm(HC_ARG5) = __arg5; \
- + __arg1 = (unsigned long)(a1); \
- + __arg2 = (unsigned long)(a2); \
- + __arg3 = (unsigned long)(a3); \
- + __arg4 = (unsigned long)(a4); \
- + __arg5 = (unsigned long)(a5); \
- + asm volatile ("call hypercall_page+%c[offset]" \
- + : "=r"(__res), "+r"(__arg1), "+r"(__arg2), "+r"(__arg3), \
- + "+r"(__arg4), "+r"(__arg5) \
- + : [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))\
- + : "memory"); \
- + __res; \
- + })
- +
- +long HYPERCALL_mmu_update(const struct mmu_update reqs[],
- + unsigned count, unsigned *done_out,
- + unsigned dom)
- +{
- + return hypercall(mmu_update, (uintptr_t)reqs, count,
- + (uintptr_t)done_out, dom, 0);
- +}
- +
- +long HYPERCALL_memory_op(unsigned int cmd, void *arg)
- +{
- + return hypercall(memory_op, cmd, (uintptr_t)arg, 0, 0, 0);
- +}
- +
- +long HYPERCALL_console_io(int cmd, int count, char *buffer)
- +{
- + return hypercall(console_io, cmd, count,(uintptr_t)buffer,0,0);
- +}
- +
- +long HYPERCALL_vcpu_op(int cmd, int vcpuid, void *extra)
- +{
- + return hypercall(vcpu_op, cmd, vcpuid, (uintptr_t)extra, 0, 0);
- +}
- +
- +long HYPERCALL_mmuext_op(struct mmuext_op *op, unsigned int count,
- + unsigned int *pdone, unsigned int foreigndom)
- +{
- + return hypercall(mmuext_op, (uintptr_t)op, count,
- + (uintptr_t)pdone, foreigndom, 0);
- +}
- +
- +long HYPERCALL_sched_op(int cmd, void *arg)
- +{
- + return hypercall(sched_op, cmd, (uintptr_t)arg, 0, 0, 0);
- +}
- +
- +long HYPERCALL_domctl(xen_domctl_t *op)
- +{
- + return hypercall(domctl, (uintptr_t)op, 0, 0, 0, 0);
- +}
- +
- +long HYPERCALL_grant_table_op(int cmd, void *args, unsigned int count)
- +{
- + return hypercall(grant_table_op, cmd, args, count, 0, 0);
- +}
- +
- +long HYPERCALL_set_trap_table(const struct trap_info traps[])
- +{
- + return hypercall(set_trap_table, traps, 0, 0, 0, 0);
- +}
- +
- +long HYPERCALL_set_callbacks(void *event, void *fail)
- +{
- +#ifdef __x86_64__
- + return hypercall(set_callbacks, event, fail, 0, 0, 0);
- +#else
- + return hypercall(set_callbacks,FLAT_KERNEL_CS,event,FLAT_KERNEL_CS,fail,0);
- +#endif
- +}
- +
- +long HYPERCALL_event_channel_op(int cmd, void *arg)
- +{
- + return hypercall(event_channel_op, cmd, arg, 0, 0, 0);
- +}
- +
- +long HYPERCALL_set_timer_op(uint64_t until)
- +{
- + return hypercall(set_timer_op, until, 0, 0, 0, 0);
- +}
- diff --git a/rts/xen/include/grants.h b/rts/xen/include/grants.h
- new file mode 100644
- index 0000000..582a2bd
- --- /dev/null
- +++ b/rts/xen/include/grants.h
- @@ -0,0 +1,26 @@
- +#ifndef RTS_XEN_GRANTS_H
- +#define RTS_XEN_GRANTS_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <xen/xen.h>
- +#include <xen/grant_table.h>
- +
- +void init_grants(void);
- +
- +long alloc_grant(domid_t, void *, uint16_t, int, grant_ref_t *);
- +long end_grant(grant_ref_t);
- +
- +long map_grants(domid_t,int,grant_ref_t*,size_t,void**,uint32_t*,uint64_t*);
- +long unmap_grants(grant_handle_t *, size_t);
- +
- +long prepare_transfer(domid_t);
- +long transfer_frame(domid_t, grant_ref_t, void*);
- +long complete_transfer(grant_ref_t, int);
- +long copy_frame(unsigned long src, int src_is_ref, domid_t sdom, uint16_t soff,
- + unsigned long dst, int dst_is_ref, domid_t ddom, uint16_t doff,
- + uint16_t length);
- +
- +#endif
- diff --git a/rts/xen/include/hypercalls.h b/rts/xen/include/hypercalls.h
- new file mode 100644
- index 0000000..9127ba9
- --- /dev/null
- +++ b/rts/xen/include/hypercalls.h
- @@ -0,0 +1,63 @@
- +#ifndef RTS_XEN_HYPERCALLS_H
- +#define RTS_XEN_HYPERCALLS_H
- +
- +#include <assert.h>
- +#include <stdint.h>
- +#include <sys/types.h>
- +#include <xen/xen.h>
- +#include <xen/platform.h>
- +#include <xen/tmem.h>
- +#include <xen/event_channel.h>
- +#include <xen/xsm/flask_op.h>
- +
- +typedef struct xen_domctl xen_domctl_t;
- +typedef struct xen_sysctl xen_sysctl_t;
- +
- +long HYPERCALL_set_trap_table(const struct trap_info traps[]);
- +long HYPERCALL_mmu_update(const struct mmu_update reqs[],
- + unsigned count, unsigned *done_out,
- + unsigned foreigndom);
- +long HYPERCALL_set_gdt(const xen_pfn_t frames[], unsigned int entries);
- +long HYPERCALL_stack_switch(unsigned long ss, unsigned long esp);
- +long HYPERCALL_set_callbacks(void *event_addr, void *fail_addr);
- +long HYPERCALL_fpu_taskswitch(int set);
- +long HYPERCALL_platform_op(const struct xen_platform_op*);
- +long HYPERCALL_set_debugreg(int regno, unsigned long val);
- +unsigned long HYPERCALL_get_debugreg(int regno);
- +long HYPERCALL_update_descriptor(uint64_t ma, uint64_t desc);
- +long HYPERCALL_memory_op(unsigned int cmd, void *arg);
- +long HYPERCALL_multicall(multicall_entry_t *entries, int nr_calls);
- +long HYPERCALL_update_va_mapping(unsigned long va, uint64_t val,
- + unsigned long fl);
- +long HYPERCALL_set_timer_op(uint64_t timeout);
- +long HYPERCALL_xen_version(int cmd, void *buffer);
- +long HYPERCALL_console_io(int cmd, int count, char *buffer);
- +long HYPERCALL_grant_table_op(int cmd, void *args, unsigned int count);
- +long HYPERCALL_vm_assist(unsigned int cmd, unsigned int type);
- +long HYPERCALL_update_va_mapping_otherdomain(unsigned long va, uint64_t val,
- + unsigned long fl, domid_t domid);
- +long HYPERCALL_iret(void);
- +long HYPERCALL_vcpu_op(int cmd, int vcpuid, void *extra);
- +#ifdef __x86_64__
- +long HYPERCALL_set_segment_base(unsigned int which, unsigned long base);
- +#endif
- +long HYPERCALL_mmuext_op(struct mmuext_op *op, unsigned int count,
- + unsigned int *pdone, unsigned int foreigndom);
- +#ifdef XEN_FLASK_INTERFACE_VERSION
- +long HYPERCALL_xsm_op(xen_flask_op_t *op);
- +#else
- +long HYPERCALL_xsm_op(flask_op_t *op);
- +#endif
- +long HYPERCALL_nmi_op(int cmd, void *arg);
- +long HYPERCALL_sched_op(int cmd, void *arg);
- +long HYPERCALL_callback_op(int cmd, void *arg);
- +long HYPERCALL_xenoprof_op(int op, void *arg);
- +long HYPERCALL_event_channel_op(int cmd, void *arg);
- +long HYPERCALL_physdev_op(int cmd, void *arg);
- +long HYPERCALL_hvm_op(int op, void *arg);
- +long HYPERCALL_sysctl(xen_sysctl_t *op);
- +long HYPERCALL_domctl(xen_domctl_t *op);
- +long HYPERCALL_kexec_op(unsigned long op, int arg1, void *arg);
- +long HYPERCALL_tmem_op(tmem_op_t *ops);
- +
- +#endif
- diff --git a/rts/xen/include/iomanager.h b/rts/xen/include/iomanager.h
- new file mode 100644
- index 0000000..c0b3886
- --- /dev/null
- +++ b/rts/xen/include/iomanager.h
- @@ -0,0 +1,9 @@
- +#ifndef RTS_XEN_IOMANAGER_H
- +#define RTS_XEN_IOMANAGER_H
- +
- +#include "Rts.h"
- +
- +StgWord waitForWaiter(StgStablePtr *out);
- +void registerWaiter(HsInt, StgStablePtr);
- +
- +#endif
- diff --git a/rts/xen/include/locks.h b/rts/xen/include/locks.h
- new file mode 100644
- index 0000000..56d581e
- --- /dev/null
- +++ b/rts/xen/include/locks.h
- @@ -0,0 +1,31 @@
- +#ifndef RTS_XEN_LOCKS_H
- +#define RTS_XEN_LOCKS_H
- +
- +#include <stdint.h>
- +
- +typedef uint32_t halvm_mutex_t;
- +typedef struct _vcpu_thread *halvm_vcpu_t;
- +
- +struct condlock {
- + halvm_mutex_t lock;
- + struct _vcpu_thread *waiter;
- + uint32_t state;
- +};
- +
- +#define CONDLOCK_EMPTY 1
- +#define CONDLOCK_WAITING 2
- +#define CONDLOCK_SIGNALED 3
- +
- +typedef struct condlock halvm_condlock_t;
- +typedef uintptr_t halvm_vcpukey_t;
- +
- +int halvm_acquire_lock(halvm_mutex_t *mutex);
- +int halvm_try_acquire_lock(halvm_mutex_t *mutex);
- +int halvm_release_lock(halvm_mutex_t *mutex);
- +
- +#ifndef THREADED_RTS
- +void initMutex(halvm_mutex_t *);
- +void closeMutex(halvm_mutex_t *);
- +#endif
- +
- +#endif
- diff --git a/rts/xen/include/memory.h b/rts/xen/include/memory.h
- new file mode 100644
- index 0000000..3b7d2db
- --- /dev/null
- +++ b/rts/xen/include/memory.h
- @@ -0,0 +1,70 @@
- +#ifndef RTS_XEN_MEMORY_H
- +#define RTS_XEN_MEMORY_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <stdint.h>
- +#include <sys/types.h>
- +#include <xen/xen.h>
- +
- +// start the haskell heap at 64M
- +#define HASKELL_HEAP_START ((char *)0x4000000)
- +
- +#define PAGE_SHIFT 12
- +#define PAGE_SIZE (1 << PAGE_SHIFT)
- +#define VCPU_STACK_SIZE (256 * PAGE_SIZE)
- +#define IRQ_STACK_SIZE (8 * PAGE_SIZE)
- +
- +
- +#ifdef CONFIG_X86_32
- +#error "Pure 32-bit mode is no longer supported!"
- +#endif
- +
- +#ifdef CONFIG_X86_PAE
- +typedef uint32_t mfn_t;
- +typedef uint32_t pfn_t;
- +typedef uint64_t maddr_t;
- +#define PFN_SET_BIT (1 << 31)
- +#define CPU_LOCAL_MEM_START 0x4000
- +#define CPU_LOCAL_MEM_END (512 * 4096)
- +#define IN_HYPERVISOR_SPACE(x) ((uintptr_t)(x) >= HYPERVISOR_VIRT_START)
- +#define MEMORY_TYPES_DECLARED
- +#endif
- +
- +#ifdef CONFIG_X86_64
- +typedef uint64_t mfn_t;
- +typedef uint64_t pfn_t;
- +typedef uint64_t maddr_t;
- +#define PFN_SET_BIT (1UL << 63)
- +#define CPU_LOCAL_MEM_START 0x4000
- +#define CPU_LOCAL_MEM_END (512 * 4096)
- +#define IN_HYPERVISOR_SPACE(x) (((uintptr_t)(x) >= HYPERVISOR_VIRT_START) &&\
- + ((uintptr_t)(x) < HYPERVISOR_VIRT_END))
- +#define MEMORY_TYPES_DECLARED
- +#endif
- +
- +#ifndef MEMORY_TYPES_DECLARED
- +#error "Need to be compiled with CONFIG_X86_32, 64, or PAE."
- +#endif
- +
- +extern mfn_t *p2m_map;
- +extern unsigned long cur_pages;
- +extern unsigned long max_pages;
- +
- +void set_pframe_used(pfn_t);
- +void set_pframe_unused(pfn_t);
- +mfn_t get_free_frame(void);
- +unsigned long used_frames(void);
- +
- +unsigned long initialize_memory(start_info_t *, void *);
- +void *claim_shared_space(size_t);
- +void *map_frames(mfn_t *, size_t);
- +long pin_frame(int, mfn_t, domid_t);
- +
- +void system_wmb(void);
- +void system_rmb(void);
- +void system_mb(void);
- +
- +#endif
- diff --git a/rts/xen/include/signals.h b/rts/xen/include/signals.h
- new file mode 100644
- index 0000000..c705af2
- --- /dev/null
- +++ b/rts/xen/include/signals.h
- @@ -0,0 +1,36 @@
- +#ifndef RTS_XEN_SIGNALS_H
- +#define RTS_XEN_SIGNALS_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <stdint.h>
- +#include <xen/xen.h>
- +#include <Rts.h>
- +
- +void init_signals(struct shared_info *);
- +
- +long bind_virq(uint32_t, uint32_t);
- +long bind_pirq(uint32_t, int);
- +long bind_ipi(uint32_t);
- +void set_c_handler(uint32_t, void (*)(int));
- +void clear_c_handler(uint32_t);
- +void set_haskell_handler(uint32_t, StgStablePtr);
- +StgStablePtr clear_haskell_handler(uint32_t);
- +long channel_send(uint32_t);
- +long channel_alloc(uint32_t, uint32_t);
- +long channel_bind(uint32_t, uint32_t);
- +long channel_close(uint32_t);
- +
- +void mask_channel(uint32_t);
- +void unmask_channel(uint32_t);
- +
- +void do_hypervisor_callback(void *);
- +
- +rtsBool anyUserHandlers(void);
- +int signals_pending(void);
- +int allow_signals(int);
- +StgStablePtr dequeueSignalHandler(void);
- +
- +#endif
- diff --git a/rts/xen/include/smp.h b/rts/xen/include/smp.h
- new file mode 100644
- index 0000000..9467d11
- --- /dev/null
- +++ b/rts/xen/include/smp.h
- @@ -0,0 +1,66 @@
- +#ifndef RTS_XEN_SMP_H
- +#define RTS_XEN_SMP_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <stdint.h>
- +#include <xen/xen.h>
- +#include <xen/event_channel.h>
- +#include "locks.h"
- +
- +#ifdef THREADED_RTS
- +#define MUNUSED
- +#else
- +#define MUNUSED __attribute__((unused))
- +#endif
- +
- +#ifdef THREADED_RTS
- +typedef struct _vcpu_thread vcpu_thread_t;
- +
- +struct _vcpu_local_info {
- + uint32_t num;
- + evtchn_port_t ipi_port;
- + vcpu_thread_t *cur_thread;
- + unsigned long local_evt_bits[sizeof(unsigned long) * 8];
- + struct vcpu_info info;
- +} __attribute__((aligned(512)));
- +
- +typedef struct _vcpu_local_info vcpu_local_info_t;
- +
- +struct _per_vcpu_data {
- + vcpu_local_info_t *cpuinfo;
- + void *irqstack;
- +} __attribute__((aligned(16)));
- +
- +typedef struct _per_vcpu_data per_vcpu_data_t;
- +
- +static inline vcpu_local_info_t *cpu_info(void)
- +{
- + vcpu_local_info_t *out;
- + asm("mov %%fs:0, %0" : "=r"(out));
- + return out;
- +}
- +
- +#define vcpu_num() (cpu_info()->num)
- +#define vcpu_ipi_port() (cpu_info()->ipi_port)
- +#define vcpu_cur_thread() (cpu_info()->cur_thread)
- +#define vcpu_evt_bits(x) (cpu_info()->local_evt_bits[x])
- +#define vcpu_info() (cpu_info()->info)
- +
- +void init_smp_system(uint32_t);
- +void unlockThread(vcpu_thread_t *);
- +void lockCurrentThread(halvm_mutex_t*);
- +void pokeSleepThread(void);
- +#else
- +extern struct shared_info *HYPERVISOR_shared_info;
- +
- +#define vcpu_num() (0)
- +#define vcpu_info() (HYPERVISOR_shared_info->vcpu_info[0])
- +#define vcpu_evt_bits(x) (0)
- +#endif
- +
- +void sleepUntilWaiter(unsigned long);
- +
- +#endif
- diff --git a/rts/xen/include/time_rts.h b/rts/xen/include/time_rts.h
- new file mode 100644
- index 0000000..3709470
- --- /dev/null
- +++ b/rts/xen/include/time_rts.h
- @@ -0,0 +1,15 @@
- +#ifndef RTS_XEN_TIME_H
- +#define RTS_XEN_TIME_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <xen/xen.h>
- +#include "Rts.h"
- +
- +void init_time(struct shared_info *);
- +StgWord getDelayTarget(HsInt /* microseconds */);
- +uint64_t monotonic_clock(void);
- +
- +#endif
- diff --git a/rts/xen/include/vmm.h b/rts/xen/include/vmm.h
- new file mode 100644
- index 0000000..5404fc3
- --- /dev/null
- +++ b/rts/xen/include/vmm.h
- @@ -0,0 +1,77 @@
- +#ifndef RTS_XEN_VMM_H
- +#define RTS_XEN_VMM_H
- +
- +#ifndef __XEN__
- +#define __XEN__
- +#endif
- +
- +#include <stdint.h>
- +#include <sys/types.h>
- +#include <xen/xen.h>
- +
- +#define PG_PRESENT (1 << 0)
- +#define PG_READWRITE (1 << 1)
- +#define PG_USER (1 << 2)
- +#define PG_WRITETHROUGH (1 << 3)
- +#define PG_CACHEDISABLE (1 << 4)
- +#define PG_ACCESSED (1 << 5)
- +#define PG_DIRTY (1 << 6)
- +#define PG_SIZE (1 << 7)
- +#define PG_GLOBAL (1 << 8)
- +#define PG_CLAIMED (1 << 9)
- +#define PG_UNUSED1 (1 << 10)
- +#define PG_UNUSED2 (1 << 11)
- +
- +#define STANDARD_PERMS (PG_PRESENT | PG_USER | PG_CLAIMED)
- +#define STANDARD_RW_PERMS (STANDARD_PERMS | PG_READWRITE)
- +
- +#ifdef CONFIG_X86_PAE
- +typedef uint64_t pte_t;
- +
- +#define NUM_PT_ENTRIES 512
- +#define MADDR_MASK 0x0000000FFFFFF000ULL
- +#define PG_EXECUTABLE 0xFFFFFFFFFFFFFFFFULL
- +#define NUM_PT_LEVELS 3
- +
- +#define BUILD_ADDR(b,c,d) ((void*)((((uintptr_t)(b)) << 30) | \
- + (((uintptr_t)(c)) << 21) | \
- + (((uintptr_t)(d)) << 12)))
- +#define CANONICALIZE(x) (x)
- +#define DECANONICALIZE(x) (x)
- +#endif
- +
- +#ifdef CONFIG_X86_64
- +typedef uint64_t pte_t;
- +
- +#define NUM_PT_ENTRIES 512
- +#define MADDR_MASK 0x000FFFFFFFFFF000ULL
- +#define PG_EXECUTABLE 0x7FFFFFFFFFFFFFFFULL
- +#define NUM_PT_LEVELS 4
- +
- +#define BUILD_ADDR(a,b,c,d) ((void*)((((uintptr_t)(a)) << 39) | \
- + (((uintptr_t)(b)) << 30) | \
- + (((uintptr_t)(c)) << 21) | \
- + (((uintptr_t)(d)) << 12)))
- +#define CANONICALIZE(x) (void*)((((uintptr_t)(x)) & (1UL << 49)) \
- + ? ((uintptr_t)x | 0xffff000000000000) \
- + : ((uintptr_t)x & 0xFFFFFFFFFFFF))
- +#define DECANONICALIZE(x) ((void*)((uintptr_t)(x) & 0xFFFFFFFFFFFF))
- +#endif
- +
- +#define INDEX_MASK ((NUM_PT_ENTRIES) - 1)
- +
- +#define VADDR_L1_IDX(x) ((((uintptr_t)(x)) >> 12) & INDEX_MASK)
- +#define VADDR_L2_IDX(x) ((((uintptr_t)(x)) >> 21) & INDEX_MASK)
- +#define VADDR_L3_IDX(x) ((((uintptr_t)(x)) >> 30) & INDEX_MASK)
- +#define VADDR_L4_IDX(x) ((((uintptr_t)(x)) >> 39) & INDEX_MASK)
- +
- +#define ENTRY_PRESENT(x) ((x) & PG_PRESENT)
- +#define ENTRY_CLAIMED(x) ((x) & PG_CLAIMED)
- +#define ENTRY_MADDR(x) ((pte_t)(x) & MADDR_MASK)
- +
- +void *initialize_vmm(start_info_t *, void *);
- +pte_t get_pt_entry(void *addr);
- +void set_pt_entry(void *addr, pte_t entry);
- +void *machine_to_virtual(uint64_t maddr);
- +
- +#endif
- diff --git a/rts/xen/iomanager.c b/rts/xen/iomanager.c
- new file mode 100644
- index 0000000..8a19611
- --- /dev/null
- +++ b/rts/xen/iomanager.c
- @@ -0,0 +1,110 @@
- +#include "Rts.h"
- +#include "Prelude.h"
- +#include <assert.h>
- +#include "iomanager.h"
- +#include "time_rts.h"
- +#include "signals.h"
- +#include "Task.h"
- +#include "Schedule.h"
- +#include "smp.h"
- +
- +void setIOManagerControlFd(int fd)
- +{
- + printf("ERROR: Someone called setIOManagerControlFd(%d)\n", fd);
- +}
- +
- +void setIOManagerWakeupFd(int fd)
- +{
- + printf("ERROR: Someone called setIOManagerWakeupFd(%d)\n", fd);
- +}
- +
- +void ioManagerWakeup(void)
- +{
- + /* nothin'! */
- +}
- +
- +#ifdef THREADED_RTS
- +typedef struct waiter {
- + struct waiter *next;
- + StgWord target;
- + StgStablePtr action;
- +} waiter_t;
- +
- +static halvm_mutex_t waiters_lock;
- +static waiter_t *waiters = NULL;
- +#endif
- +
- +void registerWaiter(HsInt usecs MUNUSED, StgStablePtr action MUNUSED)
- +{
- +#ifdef THREADED_RTS
- + waiter_t *newWaiter = malloc(sizeof(waiter_t));
- + waiter_t *cur, *prev;
- +
- + newWaiter->target = getDelayTarget(usecs);
- + newWaiter->action = action;
- +
- + halvm_acquire_lock(&waiters_lock);
- + for(cur = waiters, prev = NULL; cur; prev = cur, cur = cur->next)
- + if(cur->target > newWaiter->target) {
- + newWaiter->next = cur;
- + if(prev) prev->next = newWaiter; else waiters = newWaiter;
- + halvm_release_lock(&waiters_lock);
- + return;
- + }
- +
- + newWaiter->next = NULL;
- + if(prev) prev->next = newWaiter; else waiters = newWaiter;
- + halvm_release_lock(&waiters_lock);
- + pokeSleepThread();
- +#endif
- +}
- +
- +StgWord waitForWaiter(StgStablePtr *out MUNUSED)
- +{
- +#ifdef THREADED_RTS
- + StgStablePtr signal = dequeueSignalHandler();
- + unsigned long target;
- +
- + if(signal) {
- + *out = signal;
- + return 0;
- + }
- +
- + halvm_acquire_lock(&waiters_lock);
- + if(waiters && waiters->target <= getDelayTarget(0)) {
- + waiter_t *dead = waiters;
- +
- + *out = waiters->action;
- + waiters = waiters->next;
- + halvm_release_lock(&waiters_lock);
- + free(dead);
- +
- + return 0;
- + }
- + target = waiters ? waiters->target : getDelayTarget(6000000);
- + halvm_release_lock(&waiters_lock);
- +
- + return target;
- +#else
- + return NULL;
- +#endif
- +}
- +
- +#ifdef THREADED_RTS
- +void ioManagerDie(void)
- +{
- + if(waiters) {
- + printf("WARNING: IO Manager is dying with people waiting to run.\n");
- + }
- +}
- +
- +void ioManagerStart(void)
- +{
- + Capability *cap;
- +
- + initMutex(&waiters_lock);
- + cap = rts_lock();
- + rts_evalIO(&cap, &base_GHCziConcziIO_ensureIOManagerIsRunning_closure, NULL);
- + rts_unlock(cap);
- +}
- +#endif
- diff --git a/rts/xen/locks.c b/rts/xen/locks.c
- new file mode 100644
- index 0000000..f750858
- --- /dev/null
- +++ b/rts/xen/locks.c
- @@ -0,0 +1,139 @@
- +#include <errno.h>
- +#include "locks.h"
- +#include "smp.h"
- +#include "signals.h"
- +#include "Rts.h"
- +#include "sm/GC.h"
- +#include "RtsSignals.h"
- +#include "Task.h"
- +#include <runtime_reqs.h>
- +#include <assert.h>
- +
- +#define LOCK_FREE 0
- +#define LOCK_TAKEN 1
- +#define LOCK_CLOSED 0xbadbadFF
- +
- +int halvm_acquire_lock(halvm_mutex_t *mutex)
- +{
- + unsigned long count = 1;
- +
- + while(1) {
- + switch(__sync_val_compare_and_swap(mutex, LOCK_FREE, LOCK_TAKEN)) {
- + case LOCK_FREE:
- + return 0;
- + case LOCK_TAKEN:
- + break;
- + case LOCK_CLOSED:
- + return EINVAL;
- + default:
- + printf("ERROR: Lock in weird state!\n");
- + return EINVAL;
- + }
- +
- + if(!(count && 0xFFF)) {
- + runtime_block(0);
- + }
- + }
- +}
- +
- +int halvm_try_acquire_lock(halvm_mutex_t *mutex)
- +{
- + switch(__sync_val_compare_and_swap(mutex, LOCK_FREE, LOCK_TAKEN)) {
- + case LOCK_FREE:
- + return 0;
- + case LOCK_TAKEN:
- + return EBUSY;
- + case LOCK_CLOSED:
- + return EINVAL;
- + default:
- + printf("ERROR: Lock in weird state (2)\n");
- + return EINVAL;
- + }
- +}
- +
- +int halvm_release_lock(halvm_mutex_t *mutex)
- +{
- + switch(__sync_val_compare_and_swap(mutex, LOCK_TAKEN, LOCK_FREE)) {
- + case LOCK_FREE:
- + return EINVAL;
- + case LOCK_TAKEN:
- + return 0;
- + case LOCK_CLOSED:
- + return EINVAL;
- + default:
- + printf("ERROR: Lock in weird state (3)\n");
- + return EINVAL;
- + }
- +}
- +
- +/* ************************************************************************* */
- +
- +void initMutex(halvm_mutex_t *mut)
- +{
- + *mut = LOCK_FREE;
- +}
- +
- +void closeMutex(halvm_mutex_t *mut)
- +{
- + *mut = LOCK_CLOSED;
- +}
- +
- +/* ************************************************************************* */
- +
- +/* ************************************************************************* */
- +
- +#ifdef THREADED_RTS
- +/* the GHC RTS doesn't use the full power of conditional locks. instead, */
- +/* it uses them as a handy way to go to sleep or get woken up when a task */
- +/* runs out of things to do, while ensuring that a particular lock is held */
- +/* when it wakes up. This means, for example, that there's always a maximum */
- +/* of one person waiting on the lock, which in turn means we can greatly */
- +/* simplify our implementation. */
- +void initCondition(halvm_condlock_t *cond)
- +{
- + initMutex( &(cond->lock) );
- + cond->waiter = 0;
- + cond->state = CONDLOCK_EMPTY;
- +}
- +
- +void closeCondition(halvm_condlock_t *cond)
- +{
- + closeMutex( &(cond->lock) );
- +}
- +
- +
- +rtsBool broadcastCondition(halvm_condlock_t *cond __attribute__((unused)))
- +{
- + return rtsTrue;
- +}
- +
- +rtsBool signalCondition(halvm_condlock_t *cond)
- +{
- + halvm_acquire_lock( &(cond->lock) );
- + if(cond->state == CONDLOCK_WAITING) {
- + cond->state = CONDLOCK_SIGNALED;
- + unlockThread(cond->waiter);
- + cond->waiter = NULL;
- + }
- + halvm_release_lock( &(cond->lock) );
- + return rtsTrue;
- +}
- +
- +rtsBool waitCondition(halvm_condlock_t *cond, Mutex *mut)
- +{
- + halvm_acquire_lock( &(cond->lock) );
- + halvm_release_lock( mut );
- + assert(cond->state != CONDLOCK_WAITING);
- + assert(cond->state != CONDLOCK_SIGNALED);
- + cond->waiter = vcpu_cur_thread();
- + cond->state = CONDLOCK_WAITING;
- + lockCurrentThread( &(cond->lock) );
- + assert(cond->state == CONDLOCK_SIGNALED);
- + cond->state = CONDLOCK_EMPTY;
- + halvm_release_lock( &(cond->lock) );
- + halvm_acquire_lock(mut);
- + return rtsTrue;
- +}
- +
- +#endif
- +
- diff --git a/rts/xen/memory.c b/rts/xen/memory.c
- new file mode 100644
- index 0000000..5a6ec93
- --- /dev/null
- +++ b/rts/xen/memory.c
- @@ -0,0 +1,548 @@
- +#define __XEN__
- +#include "Rts.h"
- +#include "RtsUtils.h"
- +#include "sm/OSMem.h"
- +#include <runtime_reqs.h>
- +#include <xen/xen.h>
- +#include <xen/memory.h>
- +#include "vmm.h"
- +#include "memory.h"
- +#include <assert.h>
- +#include "hypercalls.h"
- +#include <sys/mman.h>
- +#include "locks.h"
- +#include <errno.h>
- +#include <string.h>
- +
- +#define PAGE_ALIGN(t1,t2,x) (t1)(((t2)x + (PAGE_SIZE-1)) & (~(PAGE_SIZE-1)))
- +#define PAGE_ALIGNED(a) (0 == ((uintptr_t)a & (PAGE_SIZE - 1)))
- +
- +extern int _text;
- +extern char _mem_start[];
- +unsigned long cur_pages = 0;
- +unsigned long max_pages = 0;
- +
- +
- +/** Stats *********************************************************************/
- +
- +struct {
- + int num_pg_allocs;
- + int num_pg_frees;
- + int num_mb_allocs;
- + int num_mb_frees;
- +} stats;
- +
- +static void dump_stats(void) {
- + printf("GC Stats:\n");
- + printf("\tnum_pg_allocs: %d\n", stats.num_pg_allocs);
- + printf("\tnum_pg_frees: %d\n", stats.num_pg_frees);
- + printf("\tnum_mb_allocs: %d\n", stats.num_mb_allocs);
- + printf("\tnum_mb_frees: %d\n", stats.num_mb_frees);
- +
- + printf("\tmalloc heap: %dkb\n",
- + (stats.num_pg_allocs - (stats.num_mb_allocs * 256)) * 4);
- + printf("\tmblocks: %dkb\n", stats.num_mb_allocs * 256 * 4);
- +
- + return;
- +}
- +
- +/******************************************************************************/
- +
- +mfn_t *p2m_map = NULL;
- +
- +void set_pframe_used(pfn_t pfn)
- +{
- + assert(pfn < cur_pages);
- + assert(p2m_map);
- + assert(p2m_map[pfn]);
- + p2m_map[pfn] = p2m_map[pfn] | PFN_SET_BIT;
- +}
- +
- +void set_pframe_unused(pfn_t pfn)
- +{
- + assert(pfn < cur_pages);
- + assert(p2m_map);
- + assert(p2m_map[pfn]);
- + p2m_map[pfn] = p2m_map[pfn] & (~PFN_SET_BIT);
- +}
- +
- +mfn_t get_free_frame()
- +{
- + unsigned long i;
- +
- + assert(p2m_map);
- + for(i = 0; i < cur_pages; i++)
- + if(!(p2m_map[i] & PFN_SET_BIT)) {
- + mfn_t retval = p2m_map[i];
- + p2m_map[i] = p2m_map[i] | PFN_SET_BIT;
- + return retval;
- + }
- +
- + return 0;
- +}
- +
- +unsigned long used_frames(void)
- +{
- + unsigned long i, retval;
- +
- + for(i = 0, retval = 0; i < cur_pages; i++)
- + if(p2m_map[i] & PFN_SET_BIT)
- + retval += 1;
- +
- + return retval;
- +}
- +
- +/******************************************************************************/
- +
- +static halvm_mutex_t memory_search_lock;
- +
- +unsigned long initialize_memory(start_info_t *start_info, void *init_sp)
- +{
- + domid_t self = DOMID_SELF;
- + void *free_space_start, *init_alloc_end, *cur;
- + uint32_t i, used_frames;
- +
- + /* gather some basic information about ourselves */
- + p2m_map = (mfn_t*)start_info->mfn_list;
- + max_pages = HYPERCALL_memory_op(XENMEM_maximum_reservation, &self);
- + cur_pages = HYPERCALL_memory_op(XENMEM_current_reservation, &self);
- +
- + printf("init_sp: 0x%p\n", init_sp);
- + printf("self: 0x%p\n", &self);
- +
- + /* sanity checks */
- + assert(p2m_map);
- + assert((long)cur_pages > 0);
- + assert((long)max_pages > 0);
- +
- + /* basic setup */
- + init_alloc_end = (void*)(((uintptr_t)init_sp + 0x3FFFFF) & (~0x3FFFFF));
- + if( ((uintptr_t)init_alloc_end - (uintptr_t)init_sp) < (512 * 1024) ) {
- + /* Xen guarantees at least 4MB alignment and 512kB padding after */
- + /* the stack. So the above does the alignment, and this if does */
- + /* the edge case. */
- + init_alloc_end = (void*)((uintptr_t)init_alloc_end + (4 * 1024 * 1024));
- + }
- + used_frames = ((uintptr_t)init_alloc_end - (uintptr_t)&_text) >> PAGE_SHIFT;
- + for(i = 0; i < used_frames; i++)
- + set_pframe_used(i);
- +
- + free_space_start = initialize_vmm(start_info, init_sp);
- + free_space_start = PAGE_ALIGN(void*,uintptr_t,free_space_start);
- + i = ((uintptr_t)free_space_start - (uintptr_t)&_text) >> PAGE_SHIFT;
- + for(cur = free_space_start;
- + i < used_frames;
- + i++, cur = (void*)((uintptr_t)cur + PAGE_SIZE)) {
- + set_pframe_unused(i);
- + set_pt_entry(cur, 0);
- + }
- +
- + /* Finally, initialize the lock */
- + initMutex(&memory_search_lock);
- +
- + return max_pages;
- +}
- +
- +/******************************************************************************/
- +
- +static inline void *advance_page(void *p)
- +{
- + return CANONICALIZE((void*)((uintptr_t)DECANONICALIZE(p) + PAGE_SIZE));
- +}
- +
- +/*
- + * INVARIANTS:
- + * * start is already aligned WRT align
- + * * align is a multiple of PAGE_SIZE
- + */
- +static void *run_search_loop(void *start, size_t length, size_t align)
- +{
- + char *cur = start, *block_start = start, *retval = NULL;
- + size_t needed_space = length;
- +
- + /* printf("searching from: 0x%x\n", start); */
- +
- + assert(NULL != start);
- + while(needed_space > 0) {
- + pte_t ent = get_pt_entry(cur);
- +
- + if(ENTRY_PRESENT(ent) || ENTRY_CLAIMED(ent)) {
- + /* nevermind, we can't use anything we've found up until now */
- + needed_space = length;
- + retval = NULL;
- +
- + /* increment by the target address by the alignemnt required */
- + block_start += align;
- + cur = block_start;
- +
- + continue;
- + }
- +
- + /* we can start or extend the current run */
- + if(!retval) retval = cur;
- + needed_space = needed_space - PAGE_SIZE;
- +
- + if(needed_space > 0) {
- + cur = advance_page(cur);
- +
- + /* check for wraparound, which is bad */
- + if( cur < retval ) {
- + needed_space = length;
- + retval = NULL;
- + }
- +
- + /* if we're back where we started from, give up */
- + if( cur == start )
- + return NULL;
- + }
- + }
- +
- + /* printf("found: 0x%x\n", retval); */
- +
- + return retval;
- +}
- +
- +static inline void *find_new_addr(void *start_in, size_t length)
- +{
- + static void *glob_search_hint = (void*)_mem_start;
- + void *p = PAGE_ALIGN(void*,uintptr_t,start_in);
- +
- + /* and if they didn't give us any info (or it's junk, see above), */
- + /* let's use a reasonable hint about where to start our search. */
- + if(!p) p = glob_search_hint;
- + p = run_search_loop(p, length, PAGE_SIZE);
- + glob_search_hint = PAGE_ALIGN(void*,uintptr_t,((uintptr_t)p + length));
- + return p;
- +}
- +
- +static void *internal_alloc(void *, size_t, int);
- +
- +void *runtime_alloc(void *dest_in, size_t length_in, int prot)
- +{
- + size_t length = PAGE_ALIGN(size_t, size_t, length_in);
- + void * dest = NULL;
- +
- + assert(dest = find_new_addr(dest_in, length));
- +
- + return internal_alloc(dest, length, prot);
- +}
- +
- +/* Always allocate with a destination address already found, an amount that is
- + * already page aligned.
- + */
- +static void *internal_alloc(void *dest, size_t length, int prot)
- +{
- + void *cur, *end;
- +
- + assert(PAGE_ALIGNED(dest));
- + assert(PAGE_ALIGNED(length));
- +
- + halvm_acquire_lock(&memory_search_lock);
- +
- + cur = dest;
- + end = (void*)((uintptr_t)dest + length);
- + while( (uintptr_t)cur < (uintptr_t)end ) {
- + pte_t entry = ((pte_t)get_free_frame()) << PAGE_SHIFT;
- +
- + if(!entry) {
- + /* ACK! We're out of memory */
- + cur = dest;
- + end = cur;
- +
- + /* Free anything we've allocated for this request */
- + while( (uintptr_t)cur < (uintptr_t)end ) {
- + pte_t entry = get_pt_entry(cur);
- + set_pframe_unused(entry >> PAGE_SHIFT);
- + set_pt_entry(cur, 0);
- + }
- +
- + /* and return failure */
- + halvm_release_lock(&memory_search_lock);
- + return NULL;
- + } else {
- + entry = entry | PG_PRESENT | PG_USER;
- + if(prot & PROT_WRITE)
- + entry = entry | PG_READWRITE;
- + set_pt_entry(cur, entry);
- + }
- +
- + ++stats.num_pg_allocs;
- + cur = advance_page(cur);
- + }
- +
- + /* done! */
- + halvm_release_lock(&memory_search_lock);
- + memset(dest, 0, length);
- + return dest;
- +}
- +
- +void *map_frames(mfn_t *frames, size_t num_frames)
- +{
- + void *dest;
- + size_t i;
- +
- + halvm_acquire_lock(&memory_search_lock);
- + assert(dest = find_new_addr(NULL, num_frames * PAGE_SIZE));
- + for(i = 0; i < num_frames; i++)
- + set_pt_entry((void*)((uintptr_t)dest + (i * PAGE_SIZE)),
- + ((pte_t)frames[i] << PAGE_SHIFT) | STANDARD_RW_PERMS);
- + halvm_release_lock(&memory_search_lock);
- + return dest;
- +}
- +
- +long pin_frame(int level, mfn_t mfn, domid_t dom)
- +{
- + mmuext_op_t op;
- +
- + switch(level) {
- + case 1: op.cmd = MMUEXT_PIN_L1_TABLE; break;
- + case 2: op.cmd = MMUEXT_PIN_L2_TABLE; break;
- + case 3: op.cmd = MMUEXT_PIN_L3_TABLE; break;
- + case 4: op.cmd = MMUEXT_PIN_L4_TABLE; break;
- + default:
- + return -EINVAL;
- + }
- + op.arg1.mfn = mfn;
- +
- + return HYPERCALL_mmuext_op(&op, 1, NULL, dom);
- +}
- +
- +void *runtime_realloc(void *start, int can_move, size_t oldlen, size_t newlen)
- +{
- + void *retval, *oldcur, *oldend, *newcur, *newend;
- + pte_t page_flags, ent;
- +
- + if(!start)
- + return NULL;
- +
- + /* special case, when we're shrinking */
- + if(newlen < oldlen) {
- + runtime_free((void*)((uintptr_t)start + newlen), oldlen - newlen);
- + return start;
- + }
- +
- + /* weird case, when things are equal */
- + if(newlen == oldlen)
- + return start;
- +
- + /* get the flags that this entry uses */
- + page_flags = get_pt_entry(start);
- + page_flags = page_flags & (PAGE_SIZE-1);
- + if( !ENTRY_PRESENT(page_flags) && !ENTRY_CLAIMED(page_flags) )
- + return NULL;
- +
- + /* find where to put the new stuff */
- + halvm_acquire_lock(&memory_search_lock);
- + oldend = (void*)((uintptr_t)start + oldlen);
- + newend = (void*)((uintptr_t)start + newlen);
- + while(oldend < newend) {
- + ent = get_pt_entry(oldend);
- + if( ENTRY_CLAIMED(ent) || ENTRY_PRESENT(ent) )
- + break;
- + oldend = (void*)((uintptr_t)oldend + PAGE_SIZE);
- + }
- +
- + if(oldend >= newend) {
- + /* in this case, we have sufficient room to map the new stuff at the end */
- + oldend = (void*)((uintptr_t)start + oldlen);
- + while(oldend < newend)
- + set_pt_entry(oldend, (get_free_frame() << PAGE_SHIFT) | page_flags);
- + return start;
- + }
- +
- + /* there isn't room at the end. can we move the pointer? */
- + if(!can_move) {
- + printf("WARNING: Can't realloc without moving, and !can_move\n");
- + halvm_release_lock(&memory_search_lock);
- + return NULL;
- + }
- +
- + /* we can, so we need to find a place to put it */
- + retval = find_new_addr(start, newlen);
- + if(!retval) {
- + halvm_release_lock(&memory_search_lock);
- + printf("WARNING: No room for mremap()!\n");
- + return NULL;
- + }
- +
- + /* shift the pages over */
- + oldcur = start; oldend = (void*)((uintptr_t)oldcur + oldlen);
- + newcur = retval; newend = (void*)((uintptr_t)newcur + newlen);
- + while(newcur < newend) {
- + if(oldcur < oldend) {
- + ent = get_pt_entry(oldcur);
- + set_pt_entry(oldcur, 0);
- + set_pt_entry(newcur, ENTRY_MADDR(ent) | page_flags);
- + } else {
- + ent = get_free_frame();
- + if(!ent) {
- + halvm_release_lock(&memory_search_lock);
- + printf("WARNING: Ran out of free frames in mremap()\n");
- + return NULL;
- + }
- + set_pt_entry(newcur, (ent << PAGE_SHIFT) | page_flags);
- + }
- + oldcur = (void*)((uintptr_t)oldcur + PAGE_SIZE);
- + newcur = (void*)((uintptr_t)newcur + PAGE_SIZE);
- + }
- + halvm_release_lock(&memory_search_lock);
- +
- + return retval;
- +}
- +
- +void *claim_shared_space(size_t amt)
- +{
- + void *retval;
- + size_t i;
- +
- + halvm_acquire_lock(&memory_search_lock);
- + amt = (amt + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
- + retval = find_new_addr(NULL, amt);
- + for(i = 0; i < (amt / PAGE_SIZE); i++)
- + set_pt_entry((void*)((uintptr_t)retval + (i * PAGE_SIZE)), PG_CLAIMED);
- + halvm_release_lock(&memory_search_lock);
- + return retval;
- +}
- +
- +void runtime_free(void *start, size_t length)
- +{
- + void *end = (void*)((uintptr_t)start + length);
- +
- + halvm_acquire_lock(&memory_search_lock);
- + while(start < end) {
- + pte_t pte = get_pt_entry(start);
- +
- + if(ENTRY_PRESENT(pte)) {
- + mfn_t mfn = pte >> PAGE_SHIFT;
- + pfn_t pfn = machine_to_phys_mapping[mfn];
- + if(pfn) set_pframe_unused(pfn);
- + }
- + set_pt_entry(start, 0);
- + start = (void*)((uintptr_t)start + PAGE_SIZE);
- +
- + ++stats.num_pg_frees;
- + }
- + halvm_release_lock(&memory_search_lock);
- +}
- +
- +int runtime_memprotect(void *addr, size_t length, int prot)
- +{
- + printf("runtime_memprotect(%p, %d, %d)\n", addr, length, prot);
- + return 0; // FIXME
- +}
- +
- +int runtime_pagesize()
- +{
- + return PAGE_SIZE;
- +}
- +
- +/******************************************************************************/
- +
- +W_ getPageFaults(void);
- +
- +W_ getPageSize(void)
- +{
- + return runtime_pagesize();
- +}
- +
- +W_ getPageFaults(void)
- +{
- + return 0;
- +}
- +
- +static char * next_request = HASKELL_HEAP_START;
- +
- +void *osGetMBlocks(nat n)
- +{
- + char * allocp = NULL;
- + int len = n * MBLOCK_SIZE;
- + char * addr = run_search_loop(next_request, len, MBLOCK_SIZE);
- +
- + allocp = internal_alloc(addr, len, PROT_READWRITE);
- + if(NULL == allocp) {
- + printf("WARNING: Out of memory. The GHC RTS is about to go nuts.\n");
- + dump_stats();
- + return NULL;
- + }
- +
- + next_request = allocp + len;
- +
- + stats.num_mb_allocs += n;
- +
- + /* printf("osGetMBlocks: %d -> 0x%x\n", n, allocp); */
- +
- + return allocp;
- +}
- +
- +void osFreeAllMBlocks(void)
- +{
- + /* ignore this */
- +}
- +
- +void osMemInit(void)
- +{
- + /* ignore this */
- +}
- +
- +void osFreeMBlocks(char *addr, nat n)
- +{
- + /* printf("osFreeMBlocks: 0x%x + %d\n", addr, n); */
- + runtime_free(addr, n * MBLOCK_SIZE);
- +
- + /* next time, start allocation from this block */
- + next_request = addr;
- +
- + stats.num_mb_frees += n;
- +}
- +
- +void osReleaseFreeMemory(void)
- +{
- + /* ignore this */
- +}
- +
- +void setExecutable(void *p, W_ len, rtsBool exec)
- +{
- + void *end = (void*)((uintptr_t)p + len);
- +
- + printf("setExecutable(%p, %d, %d)\n", p, len, exec);
- + while((uintptr_t)p < (uintptr_t)end) {
- + pte_t entry = get_pt_entry(p);
- +
- + if(entry & PG_PRESENT)
- + set_pt_entry(p, entry & PG_EXECUTABLE);
- + p = (void*)((uintptr_t)p + 4096);
- + }
- +}
- +
- +StgWord64 getPhysicalMemorySize(void)
- +{
- + return (max_pages * PAGE_SIZE);
- +}
- +
- +void system_wmb()
- +{
- +#ifdef __x86_64__
- + asm volatile ("sfence" : : : "memory");
- +#else
- + asm volatile ("" : : : "memory");
- +#endif
- +}
- +
- +void system_rmb()
- +{
- +#ifdef __x86_64__
- + asm volatile ("lfence" : : : "memory");
- +#else
- + asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory");
- +#endif
- +}
- +
- +void system_mb()
- +{
- +#ifdef __x86_64__
- + asm volatile ("mfence" : : : "memory");
- +#else
- + asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory");
- +#endif
- +}
- +
- diff --git a/rts/xen/profiling.c b/rts/xen/profiling.c
- new file mode 100644
- index 0000000..fecd50d
- --- /dev/null
- +++ b/rts/xen/profiling.c
- @@ -0,0 +1,519 @@
- +#ifdef PROFILING
- +#include <runtime_reqs.h>
- +#include <errno.h>
- +#include <stdio.h>
- +#include <stdint.h>
- +#include <string.h>
- +#include <sys/mman.h>
- +#include <assert.h>
- +#define XEN_HAVE_PV_GUEST_ENTRY 1
- +#include <xen/xen.h>
- +#include <xen/io/xenbus.h>
- +#include <xen/io/xs_wire.h>
- +#include <xen/io/blkif.h>
- +#include <signals.h>
- +#include <grants.h>
- +#include <memory.h>
- +#include <vmm.h>
- +
- +#ifdef __x86_64__
- +#define wmb() asm volatile ("sfence" : : : "memory")
- +#define rmb() asm volatile ("lfence" : : : "memory")
- +#define mb() asm volatile ("mfence" : : : "memory")
- +#else
- +#define wmb() asm volatile ("" : : : "memory")
- +#define rmb() asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory")
- +#define mb() asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory")
- +#endif
- +
- +struct FILE {
- + size_t fsize;
- + size_t cur_block_num;
- + size_t cur_block_off;
- + grant_ref_t ring_grant, block_grant;
- + uint32_t chan;
- + char *block;
- + blkif_vdev_t disk_handle;
- + blkif_front_ring_t ring;
- +};
- +
- +struct xenStorePaths {
- + char *feDir;
- + char *beDir;
- +};
- +typedef struct xenStorePaths XenStorePaths;
- +
- +extern struct start_info *system_start_info;
- +static struct xenstore_domain_interface *xsint = NULL;
- +
- +static int push_out_block(FILE *p, int closed);
- +static int write_block(FILE *p, blkif_sector_t, size_t);
- +static XenStorePaths *find_xs_paths(char *, char *, uint32_t);
- +
- +static char *xenstore_getkey(char *);
- +static long xenstore_setkey(char *, char *, size_t);
- +static uint32_t xenstore_write(uint32_t, uint32_t, void *);
- +static uint32_t xenstore_read(uint32_t, uint32_t *, void **);
- +
- +#define min(a,b) ((a) < (b) ? (a) : (b))
- +
- +static void handler(int x __attribute__((unused))) { }
- +
- +FILE *profile_fopen(const char *fname, const char *mode)
- +{
- + char *key = NULL, *val = NULL, *rsp = NULL, *domStr = NULL, *diskname = NULL;
- + uint32_t req, rsptype, rsplen, domId;
- + XenStorePaths *xsp = NULL;
- + uint64_t store_mptr;
- + FILE *retval = NULL;
- + int vallen;
- + long res;
- +
- + if(strncmp(mode, "w", 1) != 0)
- + goto fail;
- +
- + if(strncmp(fname, "HaLVM.prof", 11) == 0)
- + diskname = "xvdp1";
- + if(strncmp(fname, "HaLVM.hp", 9) == 0)
- + diskname = "xvdp2";
- + if(!diskname)
- + goto fail;
- +
- + store_mptr = (uint64_t)system_start_info->store_mfn << 12;
- + unmask_channel(system_start_info->store_evtchn);
- + xsint = (struct xenstore_domain_interface*)machine_to_virtual(store_mptr);
- + if(!xsint) {
- + printf("PROFILING ERROR: Could not map XenStore page.\n");
- + goto fail;
- + }
- +
- + /* Try to run "ls devices/vbd" */
- + req = xenstore_write(XS_DIRECTORY, strlen("device/vbd") + 1, "device/vbd");
- + rsplen = xenstore_read(req, &rsptype, (void**)&rsp);
- + if(rsptype == XS_ERROR) {
- + printf("PROFILING: XenStore read error. Did you forget to add a disk?\n");
- + goto fail;
- + }
- + if(rsptype != XS_DIRECTORY) {
- + printf("PROFILING: XenStore has gone weird. Giving up.\n");
- + goto fail;
- + }
- +
- + /* Find the XenStore paths associated with the disk we want */
- + xsp = find_xs_paths(diskname, rsp, rsplen);
- + if(!xsp) {
- + printf("PROFILING: Couldn't find file to open.\n");
- + goto fail;
- + }
- +
- + /* Pull out the other's domId */
- + key = malloc(256);
- + snprintf(key, 256, "%s/backend-id", xsp->feDir);
- + domStr = xenstore_getkey(key);
- + domId = atoi(domStr);
- +
- + /* allocate the return structure and buffers */
- + retval = malloc(sizeof(FILE));
- + if(!retval)
- + goto fail;
- + memset(retval, 0, sizeof(FILE));
- + retval->cur_block_num = 1;
- + retval->block = runtime_alloc(NULL, 4096, PROT_READ|PROT_WRITE);
- + if(!retval->block)
- + goto fail;
- + assert( (((uintptr_t)retval->block) & 4095) == 0 );
- + retval->ring.sring = runtime_alloc(NULL, 4096, PROT_READ|PROT_WRITE);
- + if(!retval->ring.sring)
- + goto fail;
- + assert( (((uintptr_t)retval->ring.sring) & 4095) == 0 );
- + SHARED_RING_INIT(retval->ring.sring);
- + FRONT_RING_INIT(&(retval->ring), retval->ring.sring, 4096);
- +
- + /* get the device handle */
- + snprintf(key, 256, "%s/virtual-device", xsp->feDir);
- + val = xenstore_getkey(key);
- + retval->disk_handle = atoi(val);
- +
- + /* allocate the grant references and event channel */
- + res = alloc_grant(domId, retval->ring.sring, 4096, 0, &retval->ring_grant);
- + if(res) {
- + printf("PROFILING: Failed to allocate ring grant reference: %d\n", res);
- + goto fail;
- + }
- + res = alloc_grant(domId, retval->block, 4096, 0, &retval->block_grant);
- + if(res) {
- + printf("PROFILING: Failed to allocate block grant reference: %d\n", res);
- + goto fail;
- + }
- + res = channel_alloc(DOMID_SELF, domId);
- + if(res < 0) {
- + printf("PROFILING: Failed to allocate grant reference: %d\n", res);
- + goto fail;
- + }
- + retval->chan = (uint32_t)res;
- + set_c_handler(retval->chan, handler);
- +
- + /* write them into our tree */
- + val = malloc(256);
- + /* */ snprintf(key, 256, "%s/ring-ref", xsp->feDir);
- + vallen = snprintf(val, 256, "%d", retval->ring_grant);
- + if(!xenstore_setkey(key, val, vallen)) goto fail;
- + /* */ snprintf(key, 256, "%s/event-channel", xsp->feDir);
- + vallen = snprintf(val, 256, "%d", retval->chan);
- + if(!xenstore_setkey(key, val, vallen)) goto fail;
- + /* */ snprintf(key, 256, "%s/state", xsp->feDir);
- + vallen = snprintf(val, 256, "%d", XenbusStateInitialised);
- + if(!xenstore_setkey(key, val, vallen)) goto fail;
- +
- + /* wait for the other side to sync up */
- + do {
- + char *state;
- +
- + runtime_block(1);
- + snprintf(key, 256, "%s/state", xsp->beDir);
- + state = xenstore_getkey(key);
- + res = atoi(state);
- + free(state);
- + } while(res != XenbusStateConnected);
- +
- + /* write out that we're good */
- + /* */ snprintf(key, 256, "%s/state", xsp->feDir);
- + vallen = snprintf(val, 256, "%d", XenbusStateConnected);
- + if(!xenstore_setkey(key, val, vallen)) goto fail;
- +
- + return retval;
- +
- +fail:
- + if(key) free(key);
- + if(val) free(val);
- + if(rsp) free(rsp);
- + if(xsp) {
- + free(xsp->feDir);
- + free(xsp->beDir);
- + free(xsp);
- + }
- + if(domStr) free(domStr);
- + if(retval) {
- + if(retval->block_grant) end_grant(retval->block_grant);
- + if(retval->ring_grant) end_grant(retval->ring_grant);
- + if(retval->block) runtime_free(retval->block, 4096);
- + if(retval->ring.sring) runtime_free(retval->ring.sring, 4096);
- + if(retval->chan) channel_close(retval->chan);
- + free(retval);
- + }
- + errno = -EACCES;
- + return NULL;
- +}
- +
- +void profile_write(FILE *p, void *buf, int amt)
- +{
- + while(p->cur_block_off + amt > 4096) {
- + int amt1 = 4096 - p->cur_block_off;
- + memcpy(p->block + p->cur_block_off, buf, amt1);
- + p->fsize += amt1;
- + p->cur_block_off = 4096;
- + push_out_block(p, 0);
- +
- + buf = (void*)((uintptr_t)buf + amt1);
- + amt = amt - amt1;
- + }
- +
- + memcpy(p->block + p->cur_block_off, buf, amt);
- + p->fsize += amt;
- + p->cur_block_off += amt;
- +
- + if(p->cur_block_off == 4096)
- + push_out_block(p, 0);
- +}
- +
- +void profile_flush(FILE *p)
- +{
- + if(p->cur_block_off) {
- + void *copy = malloc(p->cur_block_off);
- + size_t copy_size = p->cur_block_off;
- + size_t skip_amt, i;
- +
- + memcpy(copy, p->block, p->cur_block_off);
- + write_block(p, p->cur_block_num, p->cur_block_off);
- + for(i = 0; i < 512 / sizeof(size_t); i += 2) {
- + ((size_t*)p->block)[i+0] = p->fsize ^ i;
- + ((size_t*)p->block)[i+1] = 0 ^ i;
- + }
- + write_block(p, 0, 512);
- + skip_amt = (copy_size / 512) * 512;
- + p->cur_block_num += copy_size / 512;
- + p->cur_block_off = copy_size % 512;
- + memcpy(p->block, (void*)((uintptr_t)copy + skip_amt), p->cur_block_off);
- + free(copy);
- + }
- +}
- +
- +void profile_fclose(FILE *p)
- +{
- + push_out_block(p, 1);
- +}
- +
- +/******************************************************************************
- + ******************************************************************************/
- +
- +/* WARNING WARNING WARNING: This overwrites the data in FILE->block */
- +static int push_out_block(FILE *p, int closed)
- +{
- + size_t i;
- + int res;
- +
- + assert( (p->cur_block_off % 512 == 0) || closed );
- + /* write out the block, if there's any data */
- + if(p->cur_block_off) {
- + res = write_block(p, p->cur_block_num, p->cur_block_off);
- + if(!res) return 0;
- + }
- + /* write out the new header */
- + for(i = 0; i < 512 / sizeof(size_t); i += 2) {
- + ((size_t*)p->block)[i+0] = p->fsize ^ i;
- + ((size_t*)p->block)[i+1] = closed ^ i;
- + }
- + res = write_block(p, 0, 512);
- + if(!res) return 0;
- + /* reinitialize the state */
- + memset(p->block, 0, 4096);
- + p->cur_block_num += p->cur_block_off / 512;
- + p->cur_block_off = 0;
- +
- + return 1;
- +}
- +
- +static int write_block(FILE *p, blkif_sector_t sector, size_t amt)
- +{
- + static uint64_t next_reqid = 1;
- + blkif_response_t *rsp;
- + blkif_request_t *req;
- + int notify, work_to_do;
- + uint64_t reqid;
- + RING_IDX i;
- +
- + /* wait until we can write something */
- + while(RING_FULL(&p->ring)) runtime_block(1);
- +
- + /* write out the request */
- + i = p->ring.req_prod_pvt++;
- + req = RING_GET_REQUEST(&p->ring, i);
- + memset(req, 0, sizeof(blkif_request_t));
- + req->operation = BLKIF_OP_WRITE;
- + req->nr_segments = 1;
- + req->handle = p->disk_handle;
- + req->id = reqid = next_reqid++;
- + req->sector_number = sector;
- + req->seg[0].gref = p->block_grant;
- + req->seg[0].first_sect = 0;
- + req->seg[0].last_sect = (amt - 1) / 512;
- + wmb();
- + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&p->ring, notify);
- + if(notify) channel_send(p->chan);
- +
- + /* wait for it to be satisfied */
- + do {
- + while(!RING_HAS_UNCONSUMED_RESPONSES(&p->ring))
- + runtime_block(1);
- + i = p->ring.rsp_cons++;
- + rsp = RING_GET_RESPONSE(&p->ring, i);
- + } while(rsp->id != reqid);
- +
- + /* was it successful? */
- + if(rsp->status != BLKIF_RSP_OKAY) {
- + printf("PROFILING: Block write failed!\n");
- + return 0;
- + }
- +
- + /* we do writes one at a time, synchronously, so work_to_do should always
- + be false */
- + RING_FINAL_CHECK_FOR_RESPONSES(&p->ring, work_to_do);
- + assert(!work_to_do);
- +
- + return 1;
- +}
- +
- +static XenStorePaths *find_xs_paths(char *fname, char *dir, uint32_t dirlen)
- +{
- + uint32_t i;
- + char *cur;
- +
- + /* parse the responses, trying to find one with the name 'HaLVM.prof' */
- + for(i = dirlen, cur = dir; i > 0; ) {
- + char *key = malloc(256), *backend, *dev;
- +
- + /* get the backend key */
- + snprintf(key, 256, "device/vbd/%s/backend", cur);
- + backend = xenstore_getkey(key);
- + if(!backend) continue;
- +
- + /* get the device name */
- + snprintf(key, 256, "%s/dev", backend);
- + dev = xenstore_getkey(key);
- + if(!dev) continue;
- +
- + /* is this what we're looking for */
- + if(strncmp(fname, dev, strlen(fname)) == 0) {
- + XenStorePaths *out = malloc(sizeof(XenStorePaths));
- +
- + out->feDir = malloc(256);
- + snprintf(out->feDir, 256, "device/vbd/%s", cur);
- + out->beDir = backend;
- +
- + free(key);
- + free(dev);
- +
- + return out;
- + }
- +
- + /* advance to the next word */
- + while( (i > 0) && (cur[0] != 0) ) { i -= 1; cur += 1; }
- + if(i > 0) { i -= 1; cur += 1; }
- + }
- +
- + return NULL;
- +}
- +
- +/******************************************************************************
- + ******************************************************************************/
- +
- +static char *xenstore_getkey(char *key)
- +{
- + uint32_t req_id, type, len;
- + char *res, *buffer;
- +
- + req_id = xenstore_write(XS_READ, strlen(key) + 1, key);
- + len = xenstore_read(req_id, &type, (void**)&buffer);
- + if(type == XS_ERROR) {
- + printf("PROFILING: Error reading key |%s|: %s\n", key, buffer);
- + free(buffer);
- + return NULL;
- + }
- + if(type != XS_READ) {
- + printf("PROFILING: Error reading key |%s|: %d\n", key, type);
- + free(buffer);
- + return NULL;
- + }
- +
- + /* the Xenstore doesn't send back 0-terminated values on reads, so
- + make our result zero terminated */
- + res = malloc(len + 1);
- + memcpy(res, buffer, len);
- + res[len] = 0;
- + free(buffer);
- +
- + return res;
- +}
- +
- +static long xenstore_setkey(char *key, char *val, size_t val_len)
- +{
- + uint32_t req_id, key_len, res, type;
- + char *outbuf, *resbuf;
- +
- + /* convert our inputs into KEY0VAL */
- + key_len = strlen(key);
- + outbuf = malloc(key_len + 1 + val_len);
- + memcpy(outbuf, key, key_len);
- + memcpy(outbuf + key_len + 1, val, val_len);
- + outbuf[key_len] = 0;
- +
- + req_id = xenstore_write(XS_WRITE, key_len + 1 + val_len, outbuf);
- + res = xenstore_read(req_id, &type, (void**)&resbuf);
- + if(type == XS_ERROR) {
- + printf("PROFILING: Error writing key |%s|: %s\n", key, resbuf);
- + res = 0;
- + } else if(type != XS_WRITE) {
- + printf("PROFILING: Error writing key |%s|: %d\n", key, type);
- + res = 0;
- + } else res = 1;
- +
- + free(outbuf);
- + free(resbuf);
- +
- + return res;
- +}
- +
- +static uint32_t xenstore_write(uint32_t type, uint32_t len, void *inbuf)
- +{
- + static uint32_t req_id = 1;
- + struct xsd_sockmsg m;
- + void *buffer, *cur;
- + uint32_t prod;
- +
- + /* build out the header and adjust the final length */
- + m.type = type;
- + m.req_id = req_id++;
- + m.tx_id = 0;
- + m.len = len;
- + len += sizeof(struct xsd_sockmsg);
- +
- + /* wait until we can send out the data all at once */
- + while( (XENSTORE_RING_SIZE - (xsint->req_prod - xsint->req_cons)) < len )
- + runtime_block(1);
- + assert( (xsint->req_prod + len - xsint->req_cons) < XENSTORE_RING_SIZE);
- +
- + /* Combine the data into one block */
- + cur = buffer = malloc(len);
- + memcpy(buffer, &m, sizeof(struct xsd_sockmsg));
- + memcpy((void*)((uintptr_t)buffer + sizeof(struct xsd_sockmsg)), inbuf, m.len);
- +
- + /* dump it out to the ring */
- + prod = xsint->req_prod;
- + while(len != 0) {
- + uint32_t nextbit = min(len, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
- + memcpy(xsint->req + MASK_XENSTORE_IDX(prod), cur, nextbit);
- + prod += nextbit;
- + cur = (void*)((uintptr_t)cur + nextbit);
- + len -= nextbit;
- + }
- +
- + /* notify the other size */
- + wmb();
- + xsint->req_prod = prod;
- + channel_send(system_start_info->store_evtchn);
- +
- + /* free our buffer and return the request id */
- + free(buffer);
- + return m.req_id;
- +}
- +
- +static uint32_t xenstore_read(uint32_t req_id, uint32_t *rtype, void **buffer)
- +{
- + struct xsd_sockmsg m;
- + char *mbuf;
- + uint32_t cons, i;
- +
- + *buffer = NULL; /* safety */
- + *rtype = 0xDEADBEEF;
- +again:
- + /* wait until there's some data available */
- + while( (xsint->rsp_prod - xsint->rsp_cons) < sizeof(struct xsd_sockmsg) )
- + runtime_block(1);
- +
- + /* copy off the header */
- + cons = xsint->rsp_cons;
- + for(i = 0; i < sizeof(struct xsd_sockmsg); i++)
- + ((char*)(&m))[i] = xsint->rsp[MASK_XENSTORE_IDX(cons++)];
- +
- + /* is this the item we were looking for? */
- + if(m.req_id != req_id) {
- + /* no ... so ignore this message and restart */
- + cons += m.len;
- + xsint->rsp_cons = cons;
- + goto again;
- + }
- +
- + /* it is! allocate and copy off the result */
- + mbuf = malloc(m.len);
- + while( (xsint->rsp_prod - cons) < m.len )
- + runtime_block(1);
- + for(i = 0; i < m.len; i++)
- + mbuf[i] = xsint->rsp[MASK_XENSTORE_IDX(cons++)];
- +
- + /* update the other size and return the buffer and length */
- + xsint->rsp_cons = cons;
- + *buffer = mbuf;
- + *rtype = m.type;
- + return m.len;
- +}
- +#endif
- diff --git a/rts/xen/signals.c b/rts/xen/signals.c
- new file mode 100644
- index 0000000..1088e0d
- --- /dev/null
- +++ b/rts/xen/signals.c
- @@ -0,0 +1,502 @@
- +#define __XEN__
- +#include "Rts.h"
- +#include "Schedule.h"
- +#include "RtsSignals.h"
- +#include "RtsUtils.h"
- +#include "Task.h"
- +#include "signals.h"
- +#include <runtime_reqs.h>
- +#include <string.h>
- +#include <sys/mman.h>
- +#include <xen/xen.h>
- +#include <xen/event_channel.h>
- +#include <xen/sched.h>
- +#include <xen/vcpu.h>
- +#include "hypercalls.h"
- +#include <assert.h>
- +#include "locks.h"
- +#include "memory.h"
- +#include "smp.h"
- +#include "time_rts.h"
- +
- +#ifndef THREADED_RTS
- +#include "AwaitEvent.h"
- +#endif
- +
- +static void force_hypervisor_callback(void);
- +
- +#define sync_swap __sync_lock_test_and_set
- +
- +
- +/* ************************************************************************ */
- +
- +#define MAX_EVTCHANS ((sizeof(long) * 8) * (sizeof(long) * 8))
- +#define MAX_PENDING_HANDLERS MAX_EVTCHANS
- +
- +typedef struct signal_handler {
- + void (*c_handler)(int);
- + StgStablePtr haskell_handler;
- +} signal_handler_t;
- +
- +static signal_handler_t *signal_handlers;
- +static struct shared_info *shared_info;
- +static unsigned long *ipi_mask;
- +
- +#if defined(__x86_64__) && !defined(THREADED_RTS)
- +static struct pda
- +{
- + int irqcount; /* offset 0 (used in x86_64.S) */
- + char *irqstackptr; /* 8 */
- +} cpu0_pda;
- +#endif
- +
- +void init_signals(struct shared_info *sinfo)
- +{
- + shared_info = sinfo;
- + signal_handlers = calloc(MAX_EVTCHANS, sizeof(signal_handler_t));
- + memset(shared_info->evtchn_mask, 0xFF, sizeof(shared_info->evtchn_mask));
- + ipi_mask = calloc(sizeof(unsigned long) * 8, sizeof(unsigned long));
- + memset(ipi_mask, 0, sizeof(unsigned long) * 8 * sizeof(unsigned long));
- +}
- +
- +long bind_virq(uint32_t virq, uint32_t vcpu)
- +{
- + evtchn_bind_virq_t arg = { .virq = virq, .vcpu = vcpu, .port = 0 };
- + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_virq, &arg);
- + return (res >= 0) ? arg.port : res;
- +}
- +
- +long bind_pirq(uint32_t pirq, int will_share)
- +{
- + evtchn_bind_pirq_t arg = { .pirq = pirq,
- + .flags = will_share ? BIND_PIRQ__WILL_SHARE : 0,
- + .port = 0 };
- + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_pirq, &arg);
- + return (res >= 0) ? arg.port : res;
- +}
- +
- +long bind_ipi(uint32_t vcpu)
- +{
- + evtchn_bind_ipi_t arg = { .vcpu = vcpu, .port = 0 };
- + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_ipi, &arg);
- + unsigned long bit;
- + int offset;
- +
- + if(res < 0)
- + return res;
- +
- + offset = arg.port / (sizeof(unsigned long) * 8);
- + bit = 1 << (arg.port % (sizeof(unsigned long) * 8));
- + __sync_fetch_and_or( &(ipi_mask[offset]), bit);
- +
- + return arg.port;
- +}
- +
- +void set_c_handler(uint32_t chan, void (handler)(int))
- +{
- + assert(chan < MAX_EVTCHANS);
- + (void)sync_swap(&(signal_handlers[chan].c_handler), handler);
- + unmask_channel(chan);
- +}
- +
- +void clear_c_handler(uint32_t chan)
- +{
- + assert(chan < MAX_EVTCHANS);
- + mask_channel(chan);
- + (void)sync_swap(&(signal_handlers[chan].c_handler), NULL);
- +}
- +
- +void set_haskell_handler(uint32_t chan, StgStablePtr handler)
- +{
- + assert(chan < MAX_EVTCHANS);
- + (void)sync_swap(&(signal_handlers[chan].haskell_handler), handler);
- + unmask_channel(chan);
- +}
- +
- +StgStablePtr clear_haskell_handler(uint32_t chan)
- +{
- + assert(chan < MAX_EVTCHANS);
- + mask_channel(chan);
- + return sync_swap(&(signal_handlers[chan].haskell_handler), NULL);
- +}
- +
- +void mask_channel(uint32_t chan)
- +{
- + asm volatile("lock btsl %1, %0"
- + : "=m"(shared_info->evtchn_mask)
- + : "r"(chan) : "memory");
- +}
- +
- +void unmask_channel(uint32_t chan)
- +{
- + int was_set = 0;
- +
- + asm volatile("lock btrl %1, %0"
- + : "=m"(shared_info->evtchn_mask)
- + : "r"(chan) : "memory");
- + /* it appears that masking off a channel simply forbids the interrupt */
- + /* from being sent to us, not from the event being set pending. so */
- + /* running this clears out any undelivered events before we unmask an */
- + /* event. */
- + asm volatile("btl %2,%1 ; sbbl %0,%0"
- + : "=r"(was_set), "=m"(shared_info->evtchn_pending)
- + : "r"(chan));
- + if(was_set) {
- + asm volatile("lock btsl %k2, %1 ; sbbl %0, %0"
- + : "=r"(was_set), "=m"(vcpu_info().evtchn_pending_sel)
- + : "r"(chan / (sizeof(unsigned long) * 8)) : "memory");
- + if(!was_set) {
- + vcpu_info().evtchn_upcall_pending = 1;
- + if(!vcpu_info().evtchn_upcall_mask) force_hypervisor_callback();
- + }
- + }
- +}
- +
- +static inline void clear_channel(uint32_t chan)
- +{
- + asm volatile("lock btrl %1, %0"
- + : "=m"(shared_info->evtchn_pending)
- + : "r"(chan) : "memory");
- +}
- +
- +long channel_send(uint32_t chan)
- +{
- + return HYPERCALL_event_channel_op(EVTCHNOP_send, &chan);
- +}
- +
- +long channel_alloc(uint32_t local, uint32_t remote)
- +{
- + evtchn_alloc_unbound_t arg = { .dom = local, .remote_dom = remote, .port = 0};
- + long res = HYPERCALL_event_channel_op(EVTCHNOP_alloc_unbound, &arg);
- + return res ? res : arg.port;
- +}
- +
- +long channel_bind(uint32_t rdom, uint32_t rport)
- +{
- + evtchn_bind_interdomain_t arg = { .remote_dom = rdom, .remote_port = rport };
- + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_interdomain, &arg);
- + return res ? res : arg.local_port;
- +}
- +
- +long channel_close(uint32_t chan)
- +{
- + return HYPERCALL_event_channel_op(EVTCHNOP_close, &chan);
- +}
- +
- +/* ************************************************************************ */
- +
- +void initDefaultHandlers(void)
- +{
- + /* nothing! */
- +}
- +
- +void resetDefaultHandlers(void)
- +{
- + /* nothing! */
- +}
- +
- +/* ************************************************************************ */
- +
- +static StgStablePtr *pending_handler_queue = NULL;
- +static unsigned int pending_handler_head = 0;
- +static unsigned int pending_handler_tail = 0;
- +#ifdef THREADED_RTS
- +static halvm_mutex_t pending_handler_lock;
- +#define PENDING_HANDLERS_LOCK() halvm_acquire_lock(&pending_handler_lock);
- +#define PENDING_HANDLERS_UNLOCK() halvm_release_lock(&pending_handler_lock);
- +
- +#else
- +#define PENDING_HANDLERS_LOCK() ;
- +#define PENDING_HANDLERS_UNLOCK() ;
- +#endif
- +
- +void initUserSignals(void)
- +{
- + pending_handler_queue = calloc(MAX_PENDING_HANDLERS, sizeof(StgStablePtr));
- + pending_handler_head = pending_handler_tail = 0;
- +#ifdef THREADED_RTS
- + initMutex(&pending_handler_lock);
- +#endif
- +}
- +
- +int signals_pending(void)
- +{
- + int res, orig_allowed;
- +
- + force_hypervisor_callback();
- + orig_allowed = allow_signals(0);
- + PENDING_HANDLERS_LOCK();
- + res = pending_handler_head != pending_handler_tail;
- + PENDING_HANDLERS_UNLOCK();
- + allow_signals(orig_allowed);
- + return res;
- +}
- +
- +static void enqueueSignalHandler(StgStablePtr handler)
- +{
- + PENDING_HANDLERS_LOCK();
- + pending_handler_queue[pending_handler_tail] = handler;
- + pending_handler_tail = (pending_handler_tail + 1) % MAX_PENDING_HANDLERS;
- + assert(pending_handler_tail != pending_handler_head);
- + PENDING_HANDLERS_UNLOCK();
- +}
- +
- +StgStablePtr dequeueSignalHandler(void)
- +{
- + StgStablePtr retval;
- + int orig_allowed;
- +
- + orig_allowed = allow_signals(0);
- + PENDING_HANDLERS_LOCK();
- + if(pending_handler_head == pending_handler_tail) {
- + retval = NULL;
- + } else {
- + retval = pending_handler_queue[pending_handler_head];
- + pending_handler_head = (pending_handler_head + 1) % MAX_PENDING_HANDLERS;
- + }
- + PENDING_HANDLERS_UNLOCK();
- + allow_signals(orig_allowed);
- +
- + return retval;
- +}
- +
- +#include "vmm.h"
- +
- +int allow_signals(int allow)
- +{
- + int orig_val;
- +
- +#if defined(__x86_64__) && !defined(THREADED_RTS)
- + static int initialized = 0;
- + if(!initialized) {
- + asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
- + asm volatile("wrmsr" : : "c"(0xc0000100), /* MSR_FS_BASE */
- + "a"((uintptr_t)&cpu0_pda & 0xFFFFFFFF),
- + "d"((uintptr_t)&cpu0_pda >> 32));
- + cpu0_pda.irqcount = -1;
- + cpu0_pda.irqstackptr = runtime_alloc(NULL, IRQ_STACK_SIZE, PROT_READWRITE);
- + initialized = 1;
- + }
- +#endif
- + orig_val = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask,!!!allow);
- + asm volatile("" : : : "memory");
- + if(allow && vcpu_info().evtchn_upcall_pending)
- + force_hypervisor_callback();
- +
- + return orig_val;
- +}
- +
- +#ifndef THREADED_RTS
- +void awaitUserSignals(void)
- +{
- + force_hypervisor_callback();
- + while(!signals_pending() && sched_state == SCHED_RUNNING)
- + runtime_block(10 * 60 * 1000); // 10 minutes
- +}
- +#endif
- +
- +rtsBool anyUserHandlers(void)
- +{
- + int i;
- +
- + for(i = 0; i < (int)MAX_EVTCHANS; i++)
- + if(signal_handlers[i].haskell_handler) {
- + return rtsTrue;
- + }
- +
- + return rtsFalse;
- +}
- +
- +void blockUserSignals(void)
- +{
- + /* nothing to do */
- +}
- +
- +void unblockUserSignals(void)
- +{
- + /* nothing to do */
- +}
- +
- +void markSignalHandlers(evac_fn evac __attribute__((unused)),
- + void *user __attribute__((unused)))
- +{
- + /* nothing -- stable pointers should prevent GC */
- +}
- +
- +void freeSignalHandlers(void)
- +{
- + /* nothing */
- +}
- +
- +/* ************************************************************************ */
- +
- +#ifndef THREADED_RTS
- +void startSignalHandlers(Capability *cap)
- +{
- + StgStablePtr next;
- +
- + while( (next = dequeueSignalHandler()) ) {
- + StgClosure *h = (StgClosure*)deRefStablePtr(next);
- + scheduleThread(cap, createIOThread(cap,RtsFlags.GcFlags.initialStkSize,h));
- + }
- +}
- +
- +static rtsBool wakeUpSleepingThreads(StgWord now)
- +{
- + rtsBool retval = rtsFalse;
- +
- + /* wake up anyone that's sleeping */
- + while((sleeping_queue != END_TSO_QUEUE) &&
- + (sleeping_queue->block_info.target <= now))
- + {
- + StgTSO *tso = sleeping_queue;
- + retval = rtsTrue;
- + sleeping_queue = tso->_link;
- + tso->why_blocked = NotBlocked;
- + tso->_link = END_TSO_QUEUE;
- + pushOnRunQueue(&MainCapability, tso);
- + }
- +
- + return retval;
- +}
- +
- +void awaitEvent(rtsBool wait)
- +{
- + do {
- + StgWord now = getDelayTarget(0);
- +
- + if(wakeUpSleepingThreads(now))
- + return;
- +
- + if(signals_pending()) {
- + startSignalHandlers(&MainCapability);
- + return;
- + }
- +
- + /* if we're supposed to wait, try blocking for awhile */
- + if(wait) {
- + lnat block_time = ~0;
- +
- + if(sleeping_queue != END_TSO_QUEUE) {
- + StgWord target = sleeping_queue->block_info.target; /* in us */
- +
- + assert(target > now);
- + block_time = (target - now) / 1000; /* us -> ms */
- + }
- + runtime_block(block_time);
- + }
- +
- + if(sched_state >= SCHED_INTERRUPTING)
- + return;
- +
- + wakeUpSleepingThreads(getDelayTarget(0));
- + } while(wait && (sched_state == SCHED_RUNNING)
- + && emptyRunQueue(&MainCapability));
- +}
- +#endif
- +
- +#define one_day (1 * 24 * 60 * 60 * 1000)
- +
- +void runtime_block(unsigned long milliseconds)
- +{
- + int orig_allowed;
- +
- + if(!signals_pending()) {
- + orig_allowed = allow_signals(0);
- + force_hypervisor_callback();
- +
- + if(!signals_pending()) {
- + uint64_t now, until;
- + int result;
- +
- + milliseconds = (milliseconds > one_day) ? one_day : milliseconds;
- + now = monotonic_clock();
- + until = now + (milliseconds * 1000000UL);
- + if(monotonic_clock() < until) {
- + vcpu_set_singleshot_timer_t t = { .timeout_abs_ns = until, .flags = VCPU_SSHOTTMR_future };
- + result = HYPERCALL_vcpu_op(VCPUOP_set_singleshot_timer,vcpu_num(),&t);
- + if (result >= 0) {
- + assert(HYPERCALL_sched_op(SCHEDOP_block, 0) >= 0);
- + force_hypervisor_callback();
- + now = monotonic_clock();
- + }
- + }
- + }
- +
- + allow_signals(orig_allowed);
- + }
- +}
- +
- +int stg_sig_install(int sig, int spi, void *mask __attribute__((unused)))
- +{
- + assert(sig == 2);
- + return spi;
- +}
- +
- +/* ************************************************************************ */
- +
- +static void force_hypervisor_callback(void)
- +{
- + uint8_t save;
- +
- + while(vcpu_info().evtchn_upcall_pending) {
- + save = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask, 1);
- + do_hypervisor_callback(NULL);
- + save = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask, save);
- + }
- +}
- +
- +void do_hypervisor_callback(void *u __attribute__((unused)))
- +{
- + unsigned long lev1, lev2;
- +
- + while( sync_swap(&vcpu_info().evtchn_upcall_pending, 0) ) {
- + while( (lev1 = sync_swap(&vcpu_info().evtchn_pending_sel, 0)) ) {
- + while(lev1) {
- + unsigned long idx = __builtin_ffsl(lev1), ipi_filter;
- + unsigned long *pending;
- +
- + assert(idx);
- + idx = idx - 1; /* ffsl returns offset + 1 */
- + lev1 = lev1 & ~(1UL << idx);
- + /* ipi_mask[idx] contains 1s for all IPI channels, so xor the
- + current VCPU's event channel bits to get "all but the current"
- + set. */
- + ipi_filter = ipi_mask[idx] ^ vcpu_evt_bits(idx);
- + pending = &(shared_info->evtchn_pending[idx]);
- + /* we then want lev2 to set the pending bits to include everything
- + in lev2 except for items in ipi_filter, because we'll handle
- + all non-IPIs and IPIs directed at us */
- + while( (lev2 = __sync_fetch_and_and(pending, ipi_filter))) {
- + /* this is the value that existed before the and, above, so it
- + includes all the events. so mask off the IPIs we don't care
- + about. */
- + lev2 = lev2 & ~ipi_filter;
- + /* there exists the chance that this leaves nothing, which
- + can get is in an awkward loop. so we need to explicitly
- + break to get out of here. */
- + if(!lev2) break;
- + /* and now we can process as normal. */
- + while(lev2) {
- + unsigned long idx2 = __builtin_ffsl(lev2), chn;
- +
- + assert(idx2);
- + idx2 = idx2 - 1;
- + chn = (idx * sizeof(unsigned long) * 8) + idx2;
- + lev2 = lev2 & ~(1UL << idx2);
- +
- + if(signal_handlers[chn].c_handler) {
- + signal_handlers[chn].c_handler(chn);
- + }
- +
- + if(signal_handlers[chn].haskell_handler) {
- + enqueueSignalHandler(signal_handlers[chn].haskell_handler);
- + }
- + }
- + }
- + }
- + }
- + }
- +}
- +
- +
- diff --git a/rts/xen/smp.c b/rts/xen/smp.c
- new file mode 100644
- index 0000000..6cc55d1
- --- /dev/null
- +++ b/rts/xen/smp.c
- @@ -0,0 +1,613 @@
- +#define __XEN__
- +#include <assert.h>
- +#include <errno.h>
- +#include <runtime_reqs.h>
- +#include <sys/mman.h>
- +#include <stdint.h>
- +#include <string.h>
- +#include <xen/xen.h>
- +#include <xen/vcpu.h>
- +
- +#include "Rts.h"
- +#include "RtsUtils.h"
- +#include "rts/OSThreads.h"
- +
- +#include "hypercalls.h"
- +#include "locks.h"
- +#include "memory.h"
- +#include "signals.h"
- +#include "smp.h"
- +#include "time_rts.h"
- +#include "vmm.h"
- +
- +#define INIT_KEYTAB_SIZE 1024
- +
- +#ifdef THREADED_RTS
- +enum thread_state {
- + threadRunning,
- + threadReadyToRun,
- + threadBlocked,
- + threadSleeping,
- + threadCreated,
- + threadDead
- +};
- +
- +struct _vcpu_thread {
- + struct _vcpu_thread *prev;
- + struct _vcpu_thread *next;
- + enum thread_state state;
- + void **localKeys;
- + uintptr_t numKeys;
- + /* savedStack: valid iff state in [threadBlocked,threadSleeping] */
- + void *savedStack;
- + /* wakeTarget: valid iff state in [threadSleeping] */
- + unsigned long wakeTarget;
- + /* startProc/param: validd iff state in [threadCreated] */
- + OSThreadProc *startProc;
- + void *param;
- +};
- +
- +struct _desc {
- + uint16_t limit_low;
- + uint16_t base_low;
- + uint8_t base_mid;
- + uint8_t type : 4;
- + uint8_t s : 1;
- + uint8_t dpl : 2;
- + uint8_t p : 1;
- + uint8_t limit_high : 4;
- + uint8_t avl : 1;
- + uint8_t l : 1;
- + uint8_t db : 1;
- + uint8_t g : 1;
- + uint8_t base_high;
- +} __attribute__((packed));
- +typedef struct _desc desc_t;
- +
- +#define vcpu_selector(x) (((x) << 3) | (1 << 2))
- +
- +static halvm_mutex_t thread_lists_lock;
- +static vcpu_thread_t *run_queue_start; /* threads waiting to run */
- +static vcpu_thread_t *run_queue_end; /* threads waiting to run */
- +static vcpu_thread_t *sleeping_queue;
- +static evtchn_port_t *waiting_vcpus;
- +static uint32_t num_vcpus;
- +
- +static halvm_mutex_t key_table_lock;
- +static uint32_t key_table_size;
- +static uint8_t *used_keys;
- +
- +static void startSubordinateVCPU(void);
- +static void subordinateQuit(void);
- +static void runNextTask(void);
- +extern void hypervisor_callback(void);
- +extern void failsafe_callback(void);
- +
- +void saveContextAndGo(vcpu_thread_t *);
- +void restoreContext(vcpu_thread_t *);
- +
- +void init_smp_system(uint32_t ncpus)
- +{
- + per_vcpu_data_t *percpudata;
- + vcpu_thread_t *initialThread;
- + vcpu_local_info_t *infos;
- + mmuext_op_t setldt;
- + desc_t *ldt;
- + uint32_t i;
- +
- + assert(ncpus < 8192); /* max LDT entries */
- + num_vcpus = ncpus;
- +
- + initMutex(&thread_lists_lock);
- + run_queue_start = NULL;
- + run_queue_end = NULL;
- + sleeping_queue = NULL;
- + waiting_vcpus = calloc(ncpus, sizeof(evtchn_port_t));
- + /* we use runtime_alloc here because it gives us back page-aligned addrs */
- + percpudata = runtime_alloc(NULL,ncpus*sizeof(per_vcpu_data_t),PROT_READWRITE);
- + infos = runtime_alloc(NULL, ncpus*sizeof(vcpu_local_info_t), PROT_READWRITE);
- + ldt = runtime_alloc(NULL, ncpus * sizeof(desc_t), PROT_READWRITE);
- + memset(percpudata, 0, ncpus * sizeof(per_vcpu_data_t));
- + memset(infos, 0, ncpus * sizeof(vcpu_local_info_t));
- + memset(ldt, 0, ncpus * sizeof(desc_t));
- +
- + initMutex(&key_table_lock);
- + key_table_size = INIT_KEYTAB_SIZE;
- + used_keys = calloc(key_table_size, sizeof(uint8_t));
- +
- + initialThread = malloc(sizeof(vcpu_thread_t));
- + initialThread->next = initialThread->prev = NULL;
- + initialThread->state = threadRunning;
- +
- + for(i = 0; i < ncpus; i++) {
- + uintptr_t cpuptr = (uintptr_t)(&percpudata[i]);
- + vcpu_register_vcpu_info_t inforeg;
- + unsigned long offset, modulus;
- + evtchn_port_t ipi_port;
- +
- + percpudata[i].cpuinfo = &infos[i];
- + percpudata[i].irqstack = runtime_alloc(NULL,IRQ_STACK_SIZE,PROT_READWRITE);
- +
- + ipi_port = bind_ipi(i);
- + offset = ipi_port / (sizeof(unsigned long) * 8);
- + modulus = ipi_port % (sizeof(unsigned long) * 8);
- +
- + infos[i].num = i;
- + infos[i].cur_thread = initialThread;
- + infos[i].ipi_port = ipi_port;
- + infos[i].local_evt_bits[offset] = 1 << modulus;
- +
- + inforeg.mfn = (uint64_t)get_pt_entry(&(infos[i].info)) >> PAGE_SHIFT;
- + inforeg.offset = (uintptr_t)&(infos[i].info) & (PAGE_SIZE-1);
- + assert(HYPERCALL_vcpu_op(VCPUOP_register_vcpu_info, i, &inforeg) >= 0);
- +
- + ldt[i].limit_low = sizeof(per_vcpu_data_t);
- + ldt[i].type = 2; /* Data, Read/Write */
- + ldt[i].s = 1; /* code or, in this case, data segment */
- + ldt[i].p = 1; /* present */
- + ldt[i].base_low = cpuptr & 0xFFFF; /* low 16 */
- + ldt[i].base_mid = (cpuptr >> 16) & 0xFF;
- + ldt[i].base_high = (cpuptr >> 24) & 0xFF;
- + }
- +
- + /* the LDT cannot be read/write, so adjust its entries in the page tables */
- + for(i = 0; i < ((ncpus * sizeof(desc_t)) + (PAGE_SIZE-1)) / PAGE_SIZE; i++) {
- + void *addr = (void*)((uintptr_t)ldt + (i * PAGE_SIZE));
- + set_pt_entry(addr, get_pt_entry(addr) & ~PG_READWRITE);
- + }
- +
- + /* set the LDT in place and load VCPU#0's FS entry */
- + setldt.cmd = MMUEXT_SET_LDT;
- + setldt.arg1.linear_addr = (unsigned long)ldt;
- + setldt.arg2.nr_ents = ncpus;
- + assert(HYPERCALL_mmuext_op(&setldt, 1, NULL, DOMID_SELF) >= 0);
- + asm("movl %0, %%fs" : : "r"(vcpu_selector(0)));
- + assert(cpu_info() == &infos[0]);
- +
- + for(i = 1; i < ncpus; i++) {
- + vcpu_guest_context_t *context = malloc(sizeof(vcpu_guest_context_t));
- + unsigned long creg;
- + void **stack;
- +
- + stack = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
- + memset(context, 0, sizeof(vcpu_guest_context_t));
- + memset(stack, 0, VCPU_STACK_SIZE);
- + context->flags = VGCF_i387_valid;
- + context->flags |= VGCF_in_kernel;
- + context->flags |= VGCF_failsafe_disables_events;
- +#ifdef __x86_64__
- + context->flags |= VGCF_syscall_disables_events;
- +#endif
- + /* set up the user registers */
- + context->user_regs.eip = (unsigned long)&startSubordinateVCPU;
- + context->user_regs.cs = FLAT_KERNEL_CS;
- + context->user_regs.ss = FLAT_KERNEL_SS;
- + context->user_regs.ds = FLAT_KERNEL_DS;
- + context->user_regs.es = FLAT_KERNEL_DS;
- + context->user_regs.fs = vcpu_selector(i);
- + context->user_regs.gs = FLAT_KERNEL_DS;
- + stack = (void**)((uintptr_t)stack + VCPU_STACK_SIZE);
- + stack[-1] = subordinateQuit; /* works as a return point */
- + context->user_regs.esp = (unsigned long)&(stack[-1]);
- + /* set the control registers */
- + asm("mov %%cr0, %0" : "=r"(creg)); context->ctrlreg[0] = creg;
- + asm("mov %%cr2, %0" : "=r"(creg)); context->ctrlreg[2] = creg;
- + asm("mov %%cr3, %0" : "=r"(creg)); context->ctrlreg[3] = creg;
- + asm("mov %%cr4, %0" : "=r"(creg)); context->ctrlreg[4] = creg;
- + /* set the LDT */
- + context->ldt_base = (unsigned long)ldt;
- + context->ldt_ents = ncpus;
- + /* set the callback pointers */
- +#ifdef __i386__
- + context->event_callback_cs = FLAT_KERNEL_CS;
- + context->event_callback_eip = (unsigned long)&hypervisor_callback;
- + context->failsafe_callback_cs = FLAT_KERNEL_CS;
- + context->failsafe_callback_eip = (unsigned long)&failsafe_callback;
- +#else
- + context->event_callback_eip = (unsigned long)&hypervisor_callback;
- + context->failsafe_callback_eip = (unsigned long)&failsafe_callback;
- +#endif
- + assert( HYPERCALL_vcpu_op(VCPUOP_initialise, i, context) >= 0);
- + free(context);
- + assert( HYPERCALL_vcpu_op(VCPUOP_up, i, context) >= 0);
- + }
- +}
- +
- +#define VCPU_LOCAL_STARTU ((uintptr_t)VCPU_LOCAL_START)
- +
- +static void startSubordinateVCPU()
- +{
- + runNextTask();
- +}
- +
- +static void subordinateQuit()
- +{
- + while(1) (void)HYPERCALL_vcpu_op(VCPUOP_down, vcpu_num(), 0);
- +}
- +
- +static unsigned long get_sleep_time(void)
- +{
- + unsigned long target = 24 * 60 * 60 * 1000;
- + unsigned long now = getDelayTarget(0);
- + vcpu_thread_t *thr;
- +
- + halvm_acquire_lock(&thread_lists_lock);
- + for(thr = sleeping_queue; thr; thr = thr->next) {
- + unsigned long candidate = (thr->wakeTarget - now) / 1000;
- + if(thr->wakeTarget < now) target = 0;
- + if(candidate < target) target = candidate;
- + }
- + halvm_release_lock(&thread_lists_lock);
- +
- + return target;
- +}
- +
- +static void runNextTask()
- +{
- + void *p;
- +
- + while(1) {
- + halvm_acquire_lock(&thread_lists_lock);
- + if(run_queue_start) {
- + vcpu_thread_t *next_task = run_queue_start;
- +
- + /* adjust the head and tail pointers */
- + run_queue_start = next_task->next;
- + next_task->prev = next_task->next = NULL;
- + if(run_queue_start)
- + run_queue_start->prev = NULL;
- + else
- + run_queue_end = NULL;
- + /* we're either going to jump somewhere else or die at this point,
- + so be nice and release the lock */
- + halvm_release_lock(&thread_lists_lock);
- +
- + switch(next_task->state) {
- + case threadRunning:
- + printf("ERROR: Running thread on run queue.\n");
- + assert(0);
- + case threadReadyToRun:
- + next_task->state = threadRunning;
- + vcpu_cur_thread() = next_task;
- + restoreContext(next_task);
- + assert(0); /* should not get here */
- + case threadBlocked:
- + printf("ERROR: Blocked thread on run queue.\n");
- + assert(0);
- + case threadSleeping:
- + printf("ERROR: Sleeping thread on run queue.\n");
- + assert(0);
- + case threadCreated:
- + vcpu_cur_thread() = next_task;
- + p = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
- +#ifdef __x86_64__
- + asm("mov %0, %%rsp" : : "r"((uintptr_t)p + VCPU_STACK_SIZE));
- +#else
- + asm("mov %0, %%esp" : : "r"((uintptr_t)p + VCPU_STACK_SIZE));
- +#endif
- + /* I'm not sure enough of the disposition of local variables to */
- + /* really trust using them after the stack swap */
- + vcpu_cur_thread()->state = threadRunning;
- + vcpu_cur_thread()->startProc(
- + vcpu_cur_thread()->param);
- + shutdownThread(); /* if we get back here, we should just die */
- + case threadDead:
- + printf("ERROR: Dead thread on run queue.\n");
- + assert(0);
- + default:
- + printf("ERROR: Unacceptable task state on sleeping queue: %d\n",
- + next_task->state);
- + assert(0);
- + }
- + }
- +
- + /* block signals before we release the lock, to avoid a signalling race */
- + allow_signals(0);
- + waiting_vcpus[vcpu_num()] = vcpu_ipi_port();
- + __sync_synchronize();
- + halvm_release_lock(&thread_lists_lock);
- + runtime_block(get_sleep_time()); /* will turn signals back on */
- + pokeSleepThread();
- + }
- +}
- +
- +void newThreadLocalKey(halvm_vcpukey_t *key)
- +{
- + uint32_t i;
- +
- + halvm_acquire_lock(&key_table_lock);
- + for(i = 0; i < key_table_size; i++)
- + if(!used_keys[i]) {
- + used_keys[i] = 1;
- + *key = i;
- + halvm_release_lock(&key_table_lock);
- + return;
- + }
- +
- + /* need to resize */
- + used_keys = realloc(used_keys, (key_table_size * 2) * sizeof(uint8_t));
- + for(i = key_table_size; i < (key_table_size * 2); i++)
- + used_keys[i] = 0;
- + *key = key_table_size;
- + used_keys[key_table_size] = 1;
- + key_table_size = key_table_size * 2;
- + halvm_release_lock(&key_table_lock);
- +}
- +
- +void *getThreadLocalVar(halvm_vcpukey_t *key)
- +{
- + vcpu_thread_t *me = vcpu_cur_thread();
- + uintptr_t index = *key, i;
- +
- + assert(me);
- + assert(me->state == threadRunning);
- +
- + if(me->numKeys > index) {
- + return me->localKeys[index];
- + }
- +
- + me->localKeys = realloc(me->localKeys, (index+1) * sizeof(void*));
- + for(i = me->numKeys; i <= index; i++)
- + me->localKeys[i] = NULL;
- + me->numKeys = index + 1;
- +
- + return NULL;
- +}
- +
- +void setThreadLocalVar(halvm_vcpukey_t *key, void *value)
- +{
- + vcpu_thread_t *me = vcpu_cur_thread();
- + uintptr_t index = *key, i;
- +
- + assert(me);
- + assert(me->state == threadRunning);
- +
- + if(me->numKeys > index) {
- + me->localKeys[index] = value;
- + return;
- + }
- +
- + me->localKeys =
- + realloc(me->localKeys, (index+1) * sizeof(void*));
- + for(i = me->numKeys; i < index; i++)
- + me->localKeys[i] = NULL;
- + me->numKeys = index + 1;
- + me->localKeys[index] = value;
- +}
- +
- +void freeThreadLocalKey(halvm_vcpukey_t *key)
- +{
- + /* this is a bit incorrect, as free/get will still get the old value,
- + but I don't think it matters in the current GHC usage */
- + halvm_acquire_lock(&key_table_lock);
- + used_keys[*key] = 0;
- + halvm_release_lock(&key_table_lock);
- +}
- +
- +nat getNumberOfProcessors(void)
- +{
- + return num_vcpus;
- +}
- +
- +int forkOS_createThread(HsStablePtr entry __attribute__((unused)))
- +{
- + printf("ERROR: forkOS_createThread called.\n");
- + return 0;
- +}
- +
- +int createOSThread(OSThreadId *pid, OSThreadProc *startProc, void *param)
- +{
- + vcpu_thread_t *newt = malloc(sizeof(vcpu_thread_t));
- + uint32_t i;
- +
- + if(!newt)
- + return EAGAIN;
- +
- + memset(newt, 0, sizeof(vcpu_thread_t));
- + newt->state = threadCreated;
- + newt->numKeys = key_table_size;
- + newt->localKeys = calloc(newt->numKeys, sizeof(void*));
- + newt->startProc = startProc;
- + newt->param = param;
- + newt->next = newt->prev = NULL;
- +
- + halvm_acquire_lock(&thread_lists_lock);
- + if(run_queue_start) {
- + assert(run_queue_end);
- + run_queue_end->next = newt;
- + newt->prev = run_queue_end;
- + run_queue_end = newt;
- + } else {
- + assert(!run_queue_end);
- + run_queue_start = run_queue_end = newt;
- + }
- + halvm_release_lock(&thread_lists_lock);
- +
- + for(i = 0; i < num_vcpus; i++) {
- + evtchn_port_t sleeping = __sync_lock_test_and_set(&(waiting_vcpus[i]), 0);
- + if(sleeping) {
- + channel_send(sleeping);
- + break;
- + }
- + }
- +
- + *pid = newt;
- + return 0;
- +}
- +
- +OSThreadId osThreadId(void)
- +{
- + return vcpu_cur_thread();
- +}
- +
- +void interruptOSThread(OSThreadId id __attribute__((unused)))
- +{
- + printf("ERROR: interruptOSThread called.\n");
- +}
- +
- +void shutdownThread(void)
- +{
- + assert(vcpu_cur_thread());
- + assert(vcpu_cur_thread()->state == threadRunning);
- + assert(!vcpu_cur_thread()->next);
- + assert(!vcpu_cur_thread()->prev);
- + vcpu_cur_thread()->state = threadDead;
- + /* this leaks memory in order to make osThreadIsAlive work ... bad plan? */
- + runNextTask();
- + __builtin_unreachable();
- +}
- +
- +void __attribute__((noinline,noclone)) saveContextAndGo(vcpu_thread_t *thr)
- +{
- +#ifdef __x86_64__
- + asm volatile ("push %%rbx ;"
- + "push %%rbp ;"
- + "push %%r12 ;"
- + "push %%r13 ;"
- + "push %%r14 ;"
- + "push %%r15 ;"
- + "movq %%rsp, %0 ;"
- + "jmp runNextTask"
- + : "=m"(thr->savedStack) : : "memory");
- +#else
- + asm volatile ("push %%ebx ;"
- + "push %%ebp ;"
- + "mov %%esp, %0 ;"
- + "jmp runNextTask"
- + : "=m"(thr->savedStack) : : "memory");
- +#endif
- +}
- +
- +void __attribute__((noinline)) restoreContext(vcpu_thread_t *thr)
- +{
- +#ifdef __x86_64__
- + asm volatile ("mov %0, %%rsp ; "
- + "pop %%r15 ; "
- + "pop %%r14 ; "
- + "pop %%r13 ; "
- + "pop %%r12 ; "
- + "pop %%rbp ;"
- + "pop %%rbx ;"
- + : : "m"(thr->savedStack) : "memory");
- +#else
- + asm volatile ("mov %0, %%esp ; "
- + "pop %%ebp ;"
- + "pop %%ebx ;"
- + : : "m"(thr->savedStack) : "memory");
- +#endif
- +}
- +
- +void yieldThread(void)
- +{
- + vcpu_thread_t *me = vcpu_cur_thread();
- +
- + halvm_acquire_lock(&thread_lists_lock);
- + if(run_queue_end) {
- + me->prev = run_queue_end;
- + me->next = NULL;
- + run_queue_end->next = me;
- + run_queue_end = me;
- + } else {
- + run_queue_start = run_queue_end = me;
- + }
- + halvm_release_lock(&thread_lists_lock);
- + me->state = threadReadyToRun;
- + vcpu_cur_thread() = NULL;
- + saveContextAndGo(me);
- +}
- +
- +void unlockThread(vcpu_thread_t *thr)
- +{
- + halvm_acquire_lock(&thread_lists_lock);
- + if(run_queue_end) {
- + run_queue_end->next = thr;
- + thr->prev = run_queue_end;
- + thr->next = NULL;
- + run_queue_end = thr;
- + } else {
- + run_queue_start = run_queue_end = thr;
- + thr->next = thr->prev = NULL;
- + }
- + thr->state = threadReadyToRun;
- + halvm_release_lock(&thread_lists_lock);
- +}
- +
- +void lockCurrentThread(halvm_mutex_t *lock)
- +{
- + vcpu_thread_t *me = vcpu_cur_thread();
- +
- + vcpu_cur_thread() = NULL;
- + me->prev = me->next = NULL;
- + me->state = threadBlocked;
- + halvm_release_lock(lock);
- + saveContextAndGo(me);
- + halvm_acquire_lock(lock);
- +}
- +
- +void sleepUntilWaiter(unsigned long target_us)
- +{
- + vcpu_thread_t *me = vcpu_cur_thread();
- +
- + vcpu_cur_thread() = NULL;
- + me->prev = NULL;
- + me->state = threadSleeping;
- + me->wakeTarget = target_us;
- +
- + halvm_acquire_lock(&thread_lists_lock);
- + me->next = sleeping_queue;
- + if(sleeping_queue)
- + sleeping_queue->prev = me;
- + sleeping_queue = me;
- + halvm_release_lock(&thread_lists_lock);
- +
- + saveContextAndGo(me);
- +}
- +
- +void pokeSleepThread(void)
- +{
- + halvm_acquire_lock(&thread_lists_lock);
- + while(sleeping_queue) {
- + vcpu_thread_t *cur = sleeping_queue;
- +
- + assert(cur->state == threadSleeping);
- + cur->state = threadReadyToRun;
- + sleeping_queue = sleeping_queue->next;
- + if(run_queue_end) {
- + cur->prev = run_queue_end;
- + cur->next = NULL;
- + run_queue_end->next = cur;
- + run_queue_end = cur;
- + } else {
- + run_queue_start = run_queue_end = cur;
- + cur->next = cur->prev = NULL;
- + }
- + }
- + halvm_release_lock(&thread_lists_lock);
- +}
- +
- +rtsBool osThreadIsAlive(OSThreadId id)
- +{
- + return (id->state != threadDead);
- +}
- +
- +void setThreadAffinity(nat n, nat m)
- +{
- + printf("setThreadAffinity(%d, %d)\n", n, m); // FIXME
- +}
- +#else
- +int forkOS_createThread(HsStablePtr entry __attribute__((unused)))
- +{
- + printf("ERROR: forkOS_createThread called.\n");
- + return 0;
- +}
- +
- +nat getNumberOfProcessors(void)
- +{
- + return 1;
- +}
- +
- +void sleepUntilWaiter(unsigned long target_us __attribute__((unused)))
- +{
- +}
- +
- +#endif
- diff --git a/rts/xen/time.c b/rts/xen/time.c
- new file mode 100644
- index 0000000..4a1db29
- --- /dev/null
- +++ b/rts/xen/time.c
- @@ -0,0 +1,217 @@
- +#define __XEN__
- +#include <stdint.h>
- +#include "Rts.h"
- +#include "Ticker.h"
- +#include "GetTime.h"
- +#include <stdlib.h>
- +#include <string.h>
- +#include <time.h>
- +#include <runtime_reqs.h>
- +#include "time_rts.h"
- +#include <signals.h>
- +#include <xen/xen.h>
- +#include <xen/vcpu.h>
- +#include <assert.h>
- +#include "hypercalls.h"
- +#include "memory.h"
- +#include "smp.h"
- +#include <errno.h>
- +
- +#ifdef __x86_64
- +# define rmb() asm volatile("lfence" : : : "memory")
- +#else
- +# define rmb() asm volatile("lock; addl $0, 0(%%esp)" : : : "memory")
- +#endif
- +
- +/* ************************************************************************* */
- +
- +static uint64_t start_time = 0;
- +static uint32_t timer_echan = 0;
- +static struct shared_info *shared_info = NULL;
- +
- +void init_time(struct shared_info *sinfo)
- +{
- + long res = bind_virq(VIRQ_TIMER, 0);
- + assert(res >= 0);
- + timer_echan = res;
- + shared_info = sinfo;
- + start_time = monotonic_clock();
- +}
- +
- +static inline uint64_t rdtscll(void)
- +{
- + uint32_t highbits, lowbits;
- + uint64_t retval;
- +
- + asm volatile("rdtsc" : "=a"(lowbits), "=d"(highbits));
- + retval = (((uint64_t)highbits) << 32) | ((uint64_t)lowbits);
- + return retval;
- +}
- +
- +uint64_t monotonic_clock(void)
- +{
- + struct vcpu_time_info *time = &vcpu_info().time;
- + uint32_t start_version, end_version;
- + uint64_t now, delta, retval = 0;
- +
- + do {
- + /* if the low bit in the version is set, an update is in progress */
- + do { start_version = time->version; } while (start_version & 0x1);
- + __sync_synchronize();
- + /* pull in the base system time */
- + retval = time->system_time;
- + /* now we figure out the difference between now and when that was written */
- + now = rdtscll();
- + delta = now - time->tsc_timestamp;
- + if(time->tsc_shift < 0)
- + delta >>= -time->tsc_shift;
- + else
- + delta <<= time->tsc_shift;
- + retval += (delta * time->tsc_to_system_mul) >> 32;
- + __sync_synchronize();
- + /* get our end version */
- + end_version = time->version;
- + __sync_synchronize();
- + /* if the two values are different, we my have an inconsistent time */
- + } while(start_version != end_version);
- +
- + return retval;
- +}
- +
- +/* ************************************************************************* */
- +
- +time_t runtime_time()
- +{
- + uint32_t start_version, end_version;
- + time_t retval;
- +
- + do {
- + /* if the low bit in the version is set, an update is in progress */
- + do { start_version = vcpu_info().time.version; }
- + while (start_version & 0x1);
- + rmb();
- + retval = shared_info->wc_sec;
- + retval += shared_info->wc_nsec / 1000000000ULL; /* ns -> s */
- + rmb();
- + end_version = vcpu_info().time.version;
- + rmb();
- + } while(start_version != end_version);
- +
- + return retval;
- +}
- +
- +int runtime_gettimeofday(struct timeval *tv)
- +{
- + uint32_t start_version, end_version;
- + uint64_t offset = monotonic_clock();
- +
- + if(!tv) return EFAULT;
- +
- + do {
- + /* if the low bit in the version is set, an update is in progress */
- + do { start_version = vcpu_info().time.version; }
- + while (start_version & 0x1);
- + rmb();
- + tv->tv_sec = shared_info->wc_sec + (offset / 1000000000ULL);
- + tv->tv_usec = (shared_info->wc_nsec + (offset % 1000000000ULL)) / 1000ULL;
- + rmb();
- + end_version = vcpu_info().time.version;
- + rmb();
- + } while(start_version != end_version);
- +
- + return 0;
- +}
- +
- +int runtime_rusage(int who __attribute__((unused)), struct rusage *usage)
- +{
- + uint64_t now = monotonic_clock();
- + uint64_t diff = now - start_time;
- +
- + assert(now >= start_time);
- + memset(usage, 0, sizeof(struct rusage));
- + usage->ru_utime.tv_sec = diff / 1000000000;
- + usage->ru_utime.tv_usec = (diff % 1000000000) / 1000;
- + usage->ru_maxrss = max_pages * 4096;
- + usage->ru_ixrss = cur_pages * 4096;
- + usage->ru_idrss = cur_pages * 4096;
- + usage->ru_isrss = VCPU_STACK_SIZE;
- +
- + return 0;
- +}
- +
- +void getProcessTimes(Time *user, Time *elapsed)
- +{
- + uint64_t now = monotonic_clock();
- + if(user) *user = NSToTime(now);
- + if(elapsed) *elapsed = NSToTime(now);
- +}
- +
- +/* ************************************************************************* */
- +
- +void initializeTimer()
- +{
- + /* nothing for the HaLVM */
- +}
- +
- +Time getProcessElapsedTime()
- +{
- + return NSToTime(monotonic_clock());
- +}
- +
- +Time getProcessCPUTime()
- +{
- + return NSToTime(monotonic_clock());
- +}
- +
- +Time getThreadCPUTime()
- +{
- + return NSToTime(monotonic_clock());
- +}
- +
- +StgWord64 getMonotonicNSec()
- +{
- + return NSToTime(monotonic_clock());
- +}
- +
- +/* ************************************************************************* */
- +
- +StgWord getDelayTarget(HsInt us /* microseconds */)
- +{
- + Time now = (Time)((uint64_t)monotonic_clock() / (uint64_t)1000); /* ns->us */
- +
- + if( (now + us) < now ) {
- + printf("Exceptional case in getDelayTarget.\n");
- + return 0;
- + }
- +
- + return now + us;
- +}
- +
- +/* ************************************************************************* */
- +
- +static uint64_t timer_interval = 0;
- +
- +void initTicker(Time interval, TickProc handle_tick)
- +{
- + /* the interval is given in units of TIME_RESOLUTION, which is essentially */
- + /* provided as a hertz value. I could probably assume that it'll remain at */
- + /* nanoseconds, but this is a bit more reasonable ... */
- + timer_interval = (interval * TIME_RESOLUTION) / 1000000000;
- + set_c_handler(timer_echan, handle_tick);
- +}
- +
- +void startTicker(void)
- +{
- + HYPERCALL_vcpu_op(VCPUOP_set_periodic_timer, vcpu_num(), &timer_interval);
- +}
- +
- +void stopTicker(void)
- +{
- + HYPERCALL_vcpu_op(VCPUOP_stop_periodic_timer, vcpu_num(), &timer_interval);
- +}
- +
- +void exitTicker(rtsBool wait __attribute__((unused)))
- +{
- + timer_interval = 0;
- + clear_c_handler(timer_echan);
- +}
- diff --git a/rts/xen/vmm_32p.c b/rts/xen/vmm_32p.c
- new file mode 100644
- index 0000000..e7b289a
- --- /dev/null
- +++ b/rts/xen/vmm_32p.c
- @@ -0,0 +1,182 @@
- +#ifdef CONFIG_X86_PAE
- +#include "vmm.h"
- +#include "memory.h"
- +#include <stdio.h>
- +#include <stdlib.h>
- +#include <assert.h>
- +#include <string.h>
- +#include "hypercalls.h"
- +#include "locks.h"
- +#include "smp.h"
- +
- +static halvm_mutex_t vmm_lock;
- +// Information regarding the handy temporary space we use
- +static pte_t *temp_table;
- +static maddr_t temp_table_pt_entry;
- +static maddr_t l3_phys_base;
- +// The start of where we've been mapped
- +extern int _text;
- +
- +static inline int mmu_update(uint64_t ptr, uint64_t val)
- +{
- + mmu_update_t update;
- + update.ptr = ptr;
- + update.val = val;
- + return HYPERCALL_mmu_update(&update, 1, NULL, DOMID_SELF) >= 0;
- +}
- +
- +static void temporarily_map(maddr_t maddr, maddr_t flags)
- +{
- + mmuext_op_t flush;
- + int res;
- +
- + flush.cmd = MMUEXT_INVLPG_LOCAL;
- + flush.arg1.linear_addr = (unsigned long)temp_table;
- + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
- +
- + res = mmu_update(temp_table_pt_entry,
- + ENTRY_MADDR(maddr)|PG_PRESENT|PG_USER|flags);
- + if(res <= 0) {
- + assert(*(void**)(0));
- + }
- +}
- +
- +void *initialize_vmm(start_info_t *sinfo, void *init_sp)
- +{
- + uintptr_t l3vb_off = (uintptr_t)sinfo->pt_base - (uintptr_t)&_text;
- + uintptr_t l3vb_poff = l3vb_off >> PAGE_SHIFT;
- + pte_t *l3_virt_base = (pte_t*)sinfo->pt_base;
- + pte_t *table, entry;
- + mfn_t mfn;
- + pfn_t pfn;
- +
- + l3_phys_base = ((pte_t)(p2m_map[l3vb_poff] & 0x7FFFFFFF)) << PAGE_SHIFT;
- + // Figure out where the temporary table's page table entry is.
- + temp_table = init_sp;
- + entry = l3_virt_base[VADDR_L3_IDX(temp_table)];
- + mfn = entry >> PAGE_SHIFT;
- + pfn = machine_to_phys_mapping[mfn];
- + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L2 table
- + entry = table[VADDR_L2_IDX(temp_table)];
- + temp_table_pt_entry = ENTRY_MADDR(entry) + (8 * VADDR_L1_IDX(temp_table));
- + initMutex(&vmm_lock);
- + return (void*)((uintptr_t)init_sp + PAGE_SIZE);
- +}
- +
- +static pte_t create_table_entry(maddr_t table_base, int idx, int level)
- +{
- + mfn_t mfn = get_free_frame();
- + mmuext_op_t extreq;
- + pte_t retval;
- +
- + assert(mfn);
- +
- + /* clear the new page table */
- + temporarily_map((maddr_t)mfn << PAGE_SHIFT, PG_READWRITE);
- + memset(temp_table, 0, PAGE_SIZE);
- +
- + /* unmap it; we can't have any writable links mapped */
- + assert(mmu_update(temp_table_pt_entry, 0));
- +
- + /* pin it */
- + extreq.cmd = level;
- + extreq.arg1.mfn = mfn;
- + assert(HYPERCALL_mmuext_op(&extreq, 1, NULL, DOMID_SELF) >= 0);
- +
- + /* write in the value */
- + retval = (((pte_t)mfn) << PAGE_SHIFT) | PG_USER | PG_PRESENT | PG_READWRITE;
- + assert(mmu_update(table_base + (sizeof(pte_t) * idx), retval));
- +
- + return retval;
- +}
- +
- +pte_t get_pt_entry(void *addr)
- +{
- + pte_t entry;
- +
- + halvm_acquire_lock(&vmm_lock);
- + temporarily_map(l3_phys_base, 0);
- + entry = temp_table[VADDR_L3_IDX(addr)];
- + if(ENTRY_PRESENT(entry)) {
- + temporarily_map(ENTRY_MADDR(entry), 0);
- + entry = temp_table[VADDR_L2_IDX(addr)];
- + if(ENTRY_PRESENT(entry)) {
- + temporarily_map(ENTRY_MADDR(entry), 0);
- + entry = temp_table[VADDR_L1_IDX(addr)];
- + halvm_release_lock(&vmm_lock);
- + return entry;
- + }
- + }
- +
- + halvm_release_lock(&vmm_lock);
- + return 0;
- +}
- +
- +void set_pt_entry(void *addr, pte_t val)
- +{
- + pte_t l3ent, l2ent;
- +
- + halvm_acquire_lock(&vmm_lock);
- + temporarily_map(l3_phys_base, 0);
- + l3ent = temp_table[VADDR_L3_IDX(addr)];
- + if(!ENTRY_PRESENT(l3ent)) {
- + l3ent = create_table_entry(l3_phys_base, VADDR_L3_IDX(addr),
- + MMUEXT_PIN_L2_TABLE);
- + }
- +
- + temporarily_map(ENTRY_MADDR(l3ent), 0);
- + l2ent = temp_table[VADDR_L2_IDX(addr)];
- + if(!ENTRY_PRESENT(l2ent)) {
- + l2ent = create_table_entry(ENTRY_MADDR(l3ent), VADDR_L2_IDX(addr),
- + MMUEXT_PIN_L1_TABLE);
- + }
- + assert(mmu_update(ENTRY_MADDR(l2ent)+(VADDR_L1_IDX(addr)*sizeof(pte_t)),val));
- + halvm_release_lock(&vmm_lock);
- +
- + /* if(ENTRY_PRESENT(val)) { */
- + mmuext_op_t flush;
- + flush.cmd = MMUEXT_INVLPG_ALL;
- + flush.arg1.linear_addr = (unsigned long)addr;
- + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
- + /* } */
- +}
- +
- +void *machine_to_virtual(uint64_t maddr)
- +{
- + pte_t l3_entry, l2_entry;
- + int i, j, k;
- +
- + for(i = 0; i < 512; i++) {
- + if(i == VADDR_L3_IDX(HYPERVISOR_VIRT_START))
- + break;
- +
- + temporarily_map(l3_phys_base, 0);
- + l3_entry = temp_table[i];
- + if(ENTRY_PRESENT(l3_entry)) {
- + pte_t l2_table_base = ENTRY_MADDR(l3_entry);
- +
- + for(j = 0; j < 512; j++) {
- + temporarily_map(l2_table_base, 0);
- + l2_entry = temp_table[j];
- +
- + if(ENTRY_PRESENT(l2_entry)) {
- + pte_t l1_table_base = ENTRY_MADDR(l2_entry);
- +
- + temporarily_map(l1_table_base, 0);
- + for(k = 0; k < 512; k++) {
- + if(ENTRY_PRESENT(temp_table[k])) {
- + if(ENTRY_MADDR(maddr) == ENTRY_MADDR(temp_table[k])) {
- + void *base = BUILD_ADDR(i, j, k);
- + uintptr_t offset = maddr & (PAGE_SIZE-1);
- + return (void*)((uintptr_t)base + offset);
- + }
- + }
- + }
- + }
- + }
- + }
- + }
- +
- + return NULL;
- +}
- +#endif
- diff --git a/rts/xen/vmm_64.c b/rts/xen/vmm_64.c
- new file mode 100644
- index 0000000..50a503a
- --- /dev/null
- +++ b/rts/xen/vmm_64.c
- @@ -0,0 +1,212 @@
- +#ifdef CONFIG_X86_64
- +#include "vmm.h"
- +#include "memory.h"
- +#include <stdio.h>
- +#include <stdlib.h>
- +#include <assert.h>
- +#include <string.h>
- +#include "hypercalls.h"
- +#include "locks.h"
- +#include "smp.h"
- +
- +#include "Rts.h"
- +#include "RtsUtils.h"
- +#include "rts/OSThreads.h"
- +
- +static halvm_mutex_t vmm_lock;
- +// Information regarding the handy temporary space we use
- +static pte_t *temp_table;
- +static maddr_t temp_table_pt_entry;
- +static maddr_t l4_phys_base;
- +// The start of where we've been mapped
- +extern int _text;
- +
- +static inline int mmu_update(uint64_t ptr, uint64_t val)
- +{
- + mmu_update_t update;
- + update.ptr = ptr;
- + update.val = val;
- + return HYPERCALL_mmu_update(&update, 1, NULL, DOMID_SELF) >= 0;
- +}
- +
- +static void temporarily_map(maddr_t maddr, maddr_t flags)
- +{
- + mmuext_op_t flush;
- + int res;
- +
- + flush.cmd = MMUEXT_INVLPG_LOCAL;
- + flush.arg1.linear_addr = (unsigned long)temp_table;
- + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
- +
- + res = mmu_update(temp_table_pt_entry,
- + ENTRY_MADDR(maddr)|PG_PRESENT|PG_USER|flags);
- + if(res <= 0) {
- + assert(*(void**)(0));
- + }
- +
- +}
- +
- +void *initialize_vmm(start_info_t *sinfo, void *init_sp)
- +{
- + uintptr_t l4vb_off = (uintptr_t)sinfo->pt_base - (uintptr_t)&_text;
- + uintptr_t l4vb_poff = l4vb_off >> PAGE_SHIFT;
- + pte_t *l4_virt_base = (pte_t*)sinfo->pt_base;
- + pte_t *table, entry;
- + mfn_t mfn;
- + pfn_t pfn;
- +
- + l4_phys_base = p2m_map[l4vb_poff] << PAGE_SHIFT;
- + // Figure out where the temporary table's page table entry is.
- + temp_table = init_sp;
- + entry = l4_virt_base[VADDR_L4_IDX(temp_table)];
- + mfn = entry >> PAGE_SHIFT;
- + pfn = machine_to_phys_mapping[mfn];
- + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L3
- + entry = table[VADDR_L3_IDX(temp_table)];
- + mfn = entry >> PAGE_SHIFT;
- + pfn = machine_to_phys_mapping[mfn];
- + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L2
- + entry = table[VADDR_L2_IDX(temp_table)];
- + temp_table_pt_entry = ENTRY_MADDR(entry) + (8 * VADDR_L1_IDX(temp_table));
- + initMutex(&vmm_lock);
- + return (void*)((uintptr_t)init_sp + PAGE_SIZE);
- +}
- +
- +static pte_t create_table_entry(maddr_t table_base, int idx, int level)
- +{
- + mfn_t mfn = get_free_frame();
- + mmuext_op_t extreq;
- + pte_t retval;
- +
- + assert(mfn);
- +
- + /* clear the new page table */
- + temporarily_map(mfn << PAGE_SHIFT, PG_READWRITE);
- + memset(temp_table, 0, PAGE_SIZE);
- +
- + /* unmap it; we can't have any writable links mapped */
- + assert(mmu_update(temp_table_pt_entry, 0));
- +
- + /* pin it */
- + extreq.cmd = level;
- + extreq.arg1.mfn = mfn;
- + assert(HYPERCALL_mmuext_op(&extreq, 1, NULL, DOMID_SELF) >= 0);
- +
- + /* write in the value */
- + retval = (mfn << PAGE_SHIFT) | PG_USER | PG_PRESENT | PG_READWRITE;
- + assert(mmu_update(table_base + (sizeof(pte_t) * idx), retval));
- +
- + return retval;
- +}
- +
- +pte_t get_pt_entry(void *addr)
- +{
- + pte_t entry;
- +
- + halvm_acquire_lock(&vmm_lock);
- + temporarily_map(l4_phys_base, 0);
- + entry = temp_table[VADDR_L4_IDX(addr)];
- + if(ENTRY_PRESENT(entry)) {
- + temporarily_map(ENTRY_MADDR(entry), 0);
- + entry = temp_table[VADDR_L3_IDX(addr)];
- + if(ENTRY_PRESENT(entry)) {
- + temporarily_map(ENTRY_MADDR(entry), 0);
- + entry = temp_table[VADDR_L2_IDX(addr)];
- + if(ENTRY_PRESENT(entry)) {
- + pte_t retval;
- +
- + temporarily_map(ENTRY_MADDR(entry), 0);
- + retval = temp_table[VADDR_L1_IDX(addr)];
- + halvm_release_lock(&vmm_lock);
- + return retval;
- + }
- + }
- + }
- +
- + halvm_release_lock(&vmm_lock);
- + return 0;
- +}
- +
- +void set_pt_entry(void *addr, pte_t val)
- +{
- + pte_t l4ent, l3ent, l2ent;
- +
- + halvm_acquire_lock(&vmm_lock);
- + temporarily_map(l4_phys_base, 0);
- + l4ent = temp_table[VADDR_L4_IDX(addr)];
- + if(!ENTRY_PRESENT(l4ent)) {
- + l4ent = create_table_entry(l4_phys_base, VADDR_L4_IDX(addr),
- + MMUEXT_PIN_L3_TABLE);
- + }
- +
- + temporarily_map(ENTRY_MADDR(l4ent), 0);
- + l3ent = temp_table[VADDR_L3_IDX(addr)];
- + if(!ENTRY_PRESENT(l3ent)) {
- + l3ent = create_table_entry(ENTRY_MADDR(l4ent), VADDR_L3_IDX(addr),
- + MMUEXT_PIN_L2_TABLE);
- + }
- +
- + temporarily_map(ENTRY_MADDR(l3ent), 0);
- + l2ent = temp_table[VADDR_L2_IDX(addr)];
- + if(!ENTRY_PRESENT(l2ent)) {
- + l2ent = create_table_entry(ENTRY_MADDR(l3ent), VADDR_L2_IDX(addr),
- + MMUEXT_PIN_L1_TABLE);
- + }
- + assert(mmu_update(ENTRY_MADDR(l2ent)+(VADDR_L1_IDX(addr)*sizeof(pte_t)),val));
- + halvm_release_lock(&vmm_lock);
- +
- + /* if(ENTRY_PRESENT(val)) { */
- + mmuext_op_t flush;
- + flush.cmd = MMUEXT_INVLPG_ALL;
- + flush.arg1.linear_addr = (unsigned long)addr;
- + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
- + /* } */
- +}
- +
- +void *machine_to_virtual(uint64_t maddr)
- +{
- + pte_t l4_entry, l3_entry, l2_entry;
- + int i, j, k, l;
- +
- + for(i = 0; i < 512; i++) {
- + if(i == VADDR_L4_IDX(HYPERVISOR_VIRT_START))
- + i = VADDR_L4_IDX(HYPERVISOR_VIRT_END);
- +
- + temporarily_map(l4_phys_base, 0);
- + l4_entry = temp_table[i];
- + if(ENTRY_PRESENT(l4_entry)) {
- + pte_t l3_table_base = ENTRY_MADDR(l4_entry);
- +
- + for(j = 0; j < 512; j++) {
- + temporarily_map(l3_table_base, 0);
- + l3_entry = temp_table[j];
- +
- + if(ENTRY_PRESENT(l3_entry)) {
- + pte_t l2_table_base = ENTRY_MADDR(l3_entry);
- +
- + for(k = 0; k < 512; k++) {
- + temporarily_map(l2_table_base, 0);
- + l2_entry = temp_table[k];
- +
- + if(ENTRY_PRESENT(l2_entry)) {
- + pte_t l1_table_base = ENTRY_MADDR(l2_entry);
- +
- + temporarily_map(l1_table_base, 0);
- + for(l = 0; l < 512; l++) {
- + if(ENTRY_PRESENT(temp_table[l]))
- + if(ENTRY_MADDR(maddr) == ENTRY_MADDR(temp_table[l])) {
- + void *base = BUILD_ADDR(i, j, k, l);
- + uintptr_t offset = maddr & (PAGE_SIZE-1);
- + return (void*)((uintptr_t)base + offset);
- + }
- + }
- + }
- + }
- + }
- + }
- + }
- + }
- +
- + return NULL;
- +}
- +#endif
- diff --git a/rules/build-package-way.mk b/rules/build-package-way.mk
- index 294e432..413de9d 100644
- --- a/rules/build-package-way.mk
- +++ b/rules/build-package-way.mk
- @@ -94,7 +94,7 @@ $$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS) $$(ALL_RTS_LIBS) $$($1_$2_$3_DEPS_LIBS)
- endif
- else
- # Build the ordinary .a library
- -$$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS)
- +$$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS) $$($1_$2_$3_DEPS_LIBS)
- $$(call removeFiles,$$@ $$@.contents)
- ifeq "$$($1_$2_SplitObjs)" "YES"
- $$(FIND) $$(patsubst %.$$($3_osuf),%_$$($3_osuf)_split,$$($1_$2_$3_HS_OBJS)) -name '*.$$($3_osuf)' -print >> $$@.contents
- diff --git a/rules/build-package.mk b/rules/build-package.mk
- index 34997cc..d6f81a4 100644
- --- a/rules/build-package.mk
- +++ b/rules/build-package.mk
- @@ -28,7 +28,14 @@
- # libraries/base_dist_CC_OPTS = -Iinclude ...
- # libraries/base_dist_LD_OPTS = -package ghc-prim-0.1.0.0
- +
- +# Stage1Only => ("compiler" => stage == 0) \/ (stage == 0 \/ stage == 1)
- +build-package-cond = $(if $(findstring $(Stage1Only),YES),$(if $(findstring $1,"compiler"),$(if $(findstring $2,0),YES,NO),$(if $(findstring $2,0 1),YES,NO)),YES)
- +
- define build-package
- +
- +ifeq "$$(call build-package-cond,$1,$3)" "YES"
- +
- $(call trace, build-package($1,$2,$3))
- $(call profStart, build-package($1,$2,$3))
- # $1 = dir
- @@ -52,6 +59,9 @@ ifneq "$$($1_$2_NOT_NEEDED)" "YES"
- $$(eval $$(call build-package-helper,$1,$2,$3))
- endif
- $(call profEnd, build-package($1,$2,$3))
- +
- +endif
- +
- endef
- diff --git a/rules/build-prog.mk b/rules/build-prog.mk
- index 399369e..82c854d 100644
- --- a/rules/build-prog.mk
- +++ b/rules/build-prog.mk
- @@ -19,7 +19,15 @@
- #
- # $(eval $(call build-prog,utils/genapply,dist-install,1))
- +str-equal = $(if $(findstring $1,$2),YES)
- +cond-neg = $(if $(call str-equal,$1,YES),,YES)
- +
- +build-cond = $(if $(call str-equal,$(Stage1Only),YES),$(if $(call str-equal,$1,0),YES,NO),YES)
- +
- define build-prog
- +
- +ifeq "$$(call build-cond,$3)" "YES"
- +
- $(call trace, build-prog($1,$2,$3))
- $(call profStart, build-prog($1,$2,$3))
- # $1 = dir
- @@ -48,6 +56,9 @@ ifneq "$$($1_$2_NOT_NEEDED)" "YES"
- $$(eval $$(call build-prog-helper,$1,$2,$3))
- endif
- $(call profEnd, build-prog($1,$2,$3))
- +
- +endif
- +
- endef
- diff --git a/sync-all b/sync-all
- index 4b4b7a3..c9ffd92 100755
- --- a/sync-all
- +++ b/sync-all
- @@ -881,7 +881,7 @@ sub main {
- }
- # check for ghc repositories in cwd
- - my $checked_out_found = 1 if (-d ".git" && -d "compiler");
- + my $checked_out_found = 1 if (-e ".git" && -d "compiler");
- my $bare_found = 1 if (-d "ghc.git");
- if ($bare_flag && ! $bare_found && ! $defaultrepo) {
- diff --git a/utils/runghc/ghc.mk b/utils/runghc/ghc.mk
- index 31bf089..c5f4c21 100644
- --- a/utils/runghc/ghc.mk
- +++ b/utils/runghc/ghc.mk
- @@ -34,10 +34,14 @@ ifeq "$(Windows_Host)" "YES"
- install_runhaskell: install_bins
- "$(CP)" $(DESTDIR)$(bindir)/runghc$(exeext1) $(DESTDIR)$(bindir)/runhaskell$(exeext1)
- else
- +ifeq "$(TargetOS_CPP)" "HaLVM"
- +install_runhaskell:
- +
- +else
- install_runhaskell:
- $(call removeFiles,"$(DESTDIR)$(bindir)/runhaskell")
- $(LN_S) runghc "$(DESTDIR)$(bindir)/runhaskell"
- $(call removeFiles,"$(DESTDIR)$(bindir)/runghc")
- $(LN_S) runghc-$(ProjectVersion) "$(DESTDIR)$(bindir)/runghc"
- endif
- -
- +endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement