Advertisement
Guest User

Untitled

a guest
Dec 8th, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 150.29 KB | None | 0 0
  1. diff --git a/.gitignore b/.gitignore
  2. index 57774d1..331d3ce 100644
  3. --- a/.gitignore
  4. +++ b/.gitignore
  5. @@ -55,6 +55,7 @@ _darcs/
  6. /libraries/extensible-exceptions/
  7. /libraries/filepath/
  8. /libraries/ghc-prim/
  9. +/libraries/HaLVMCore
  10. /libraries/haskell2010/
  11. /libraries/haskell98/
  12. /libraries/hoopl/
  13. @@ -70,6 +71,7 @@ _darcs/
  14. /libraries/template-haskell/
  15. /libraries/unix/
  16. /libraries/utf8-string/
  17. +/libraries/XenDevice
  18. /nofib/
  19. /utils/haddock/
  20. /utils/hsc2hs/
  21. @@ -175,3 +177,12 @@ _darcs/
  22. /extra-gcc-opts
  23.  
  24. .tm_properties
  25. +
  26. +rts/xen/include/xen
  27. +
  28. +.fixed-gmp
  29. +.halvm-base
  30. +.linked-gmp
  31. +.linked-rts
  32. +.linked-xen
  33. +.sync
  34.  
  35. diff --git a/.gitmodules b/.gitmodules
  36. index d83bfd0..64ad714 100644
  37. --- a/.gitmodules
  38. +++ b/.gitmodules
  39. @@ -1,56 +1,59 @@
  40. [submodule "libraries/binary"]
  41. path = libraries/binary
  42. - url = ../packages/binary.git
  43. + url = git://git.haskell.org/packages/binary.git
  44. ignore = untracked
  45. [submodule "libraries/bytestring"]
  46. path = libraries/bytestring
  47. - url = ../packages/bytestring.git
  48. + url = git://git.haskell.org/packages/bytestring.git
  49. ignore = untracked
  50. [submodule "libraries/Cabal"]
  51. path = libraries/Cabal
  52. - url = ../packages/Cabal.git
  53. + url = git://git.haskell.org/packages/Cabal.git
  54. ignore = untracked
  55. [submodule "libraries/containers"]
  56. path = libraries/containers
  57. - url = ../packages/containers.git
  58. + url = git://git.haskell.org/packages/containers.git
  59. ignore = untracked
  60. [submodule "libraries/haskeline"]
  61. path = libraries/haskeline
  62. - url = ../packages/haskeline.git
  63. + url = git://git.haskell.org/packages/haskeline.git
  64. ignore = untracked
  65. [submodule "libraries/pretty"]
  66. path = libraries/pretty
  67. - url = ../packages/pretty.git
  68. + url = git://git.haskell.org/packages/pretty.git
  69. ignore = untracked
  70. [submodule "libraries/terminfo"]
  71. path = libraries/terminfo
  72. - url = ../packages/terminfo.git
  73. + url = git://git.haskell.org/packages/terminfo.git
  74. ignore = untracked
  75. [submodule "libraries/transformers"]
  76. path = libraries/transformers
  77. - url = ../packages/transformers.git
  78. + url = git://git.haskell.org/packages/transformers.git
  79. ignore = untracked
  80. [submodule "libraries/xhtml"]
  81. path = libraries/xhtml
  82. - url = ../packages/xhtml.git
  83. + url = git://git.haskell.org/packages/xhtml.git
  84. ignore = untracked
  85. [submodule "libraries/Win32"]
  86. path = libraries/Win32
  87. - url = ../packages/Win32.git
  88. + url = git://git.haskell.org/packages/Win32.git
  89. ignore = untracked
  90. [submodule "libraries/primitive"]
  91. path = libraries/primitive
  92. - url = ../packages/primitive.git
  93. + url = git://git.haskell.org/packages/primitive.git
  94. ignore = untracked
  95. [submodule "libraries/vector"]
  96. path = libraries/vector
  97. - url = ../packages/vector.git
  98. + url = git://git.haskell.org/packages/vector.git
  99. ignore = untracked
  100. [submodule "libraries/time"]
  101. path = libraries/time
  102. - url = ../packages/time.git
  103. + url = git://git.haskell.org/packages/time.git
  104. ignore = untracked
  105. [submodule "libraries/random"]
  106. path = libraries/random
  107. - url = ../packages/random.git
  108. + url = git://git.haskell.org/packages/random.git
  109. ignore = untracked
  110. +[submodule "rts/minlibc"]
  111. + path = rts/minlibc
  112. + url = git://github.com/GaloisInc/minlibc
  113.  
  114. diff --git a/compiler/ghc.mk b/compiler/ghc.mk
  115. index 58b5ab3..742bcf1 100644
  116. --- a/compiler/ghc.mk
  117. +++ b/compiler/ghc.mk
  118. @@ -313,6 +313,10 @@ compiler_stage1_CONFIGURE_OPTS += --flags=stage1
  119. compiler_stage2_CONFIGURE_OPTS += --flags=stage2
  120. compiler_stage3_CONFIGURE_OPTS += --flags=stage3
  121.  
  122. +ifeq "$(TargetOS_CPP)" "HaLVM"
  123. +compiler_stage1_CONFIGURE_OPTS += --flags=ghci
  124. +endif
  125. +
  126. ifeq "$(GhcThreaded)" "YES"
  127. # We pass THREADED_RTS to the stage2 C files so that cbits/genSym.c will bring
  128. # the threaded version of atomic_inc() into scope.
  129.  
  130. diff --git a/configure.ac b/configure.ac
  131. index 2414a2f..76b95ef 100644
  132. --- a/configure.ac
  133. +++ b/configure.ac
  134. @@ -806,7 +809,12 @@ dnl off_t, because it will affect the result of that test.
  135. AC_SYS_LARGEFILE
  136.  
  137. dnl ** check for specific header (.h) files that we are interested in
  138. +if test "$TargetOS" = "HaLVM"
  139. +then
  140. +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])
  141. +else
  142. 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])
  143. +fi
  144.  
  145. dnl sys/cpuset.h needs sys/param.h to be included first on FreeBSD 9.1; #7708
  146. AC_CHECK_HEADERS([sys/cpuset.h], [], [],
  147. @@ -934,12 +942,17 @@ dnl ################################################################
  148.  
  149. dnl ** check whether we need -ldl to get dlopen()
  150.  
  151. +if test "$TargetOS" = "HaLVM"
  152. +then
  153. +HaveLibDL=NO
  154. +else
  155. AC_CHECK_LIB(dl, dlopen,
  156. [HaveLibDL=YES
  157. AC_DEFINE([HAVE_LIBDL], [1], [Define to 1 if you need -ldl to get dlopen().])
  158. LIBS="$LIBS -ldl"],
  159. [HaveLibDL=NO])
  160. AC_SUBST(HaveLibDL)
  161. +fi
  162.  
  163. dnl --------------------------------------------------
  164. dnl * Miscellaneous feature tests
  165. @@ -964,9 +977,12 @@ FP_LEADING_UNDERSCORE
  166. FP_VISIBILITY_HIDDEN
  167.  
  168. dnl ** check for librt
  169. +if test "$TargetOS" != "HaLVM"
  170. +then
  171. AC_CHECK_LIB(rt, clock_gettime)
  172. AC_CHECK_FUNCS(clock_gettime timer_settime)
  173. FP_CHECK_TIMER_CREATE
  174. +fi
  175.  
  176. dnl ** check for Apple's "interesting" long double compatibility scheme
  177. AC_MSG_CHECKING(for printf\$LDBLStub)
  178. diff --git a/ghc.mk b/ghc.mk
  179. index 67d0cbd..525bcce 100644
  180. --- a/ghc.mk
  181. +++ b/ghc.mk
  182. @@ -405,17 +407,21 @@ PACKAGES_STAGE1 += Win32
  183. endif
  184. PACKAGES_STAGE1 += time
  185. ifeq "$(Windows_Host)" "NO"
  186. +ifneq "$(TargetOS_CPP)" "HaLVM"
  187. PACKAGES_STAGE1 += unix
  188. endif
  189. +endif
  190.  
  191. +ifneq "$(TargetOS_CPP)" "HaLVM"
  192. PACKAGES_STAGE1 += directory
  193. PACKAGES_STAGE1 += process
  194. PACKAGES_STAGE1 += hpc
  195. +PACKAGES_STAGE1 += Cabal/Cabal
  196. +PACKAGES_STAGE1 += bin-package-db
  197. +endif
  198. PACKAGES_STAGE1 += pretty
  199. PACKAGES_STAGE1 += template-haskell
  200. -PACKAGES_STAGE1 += Cabal/Cabal
  201. PACKAGES_STAGE1 += binary
  202. -PACKAGES_STAGE1 += bin-package-db
  203. PACKAGES_STAGE1 += hoopl
  204. PACKAGES_STAGE1 += transformers
  205.  
  206. @@ -425,13 +431,24 @@ PACKAGES_STAGE2 += haskell98
  207. PACKAGES_STAGE2 += haskell2010
  208. endif
  209.  
  210. +ifeq "$(TargetOS_CPP)" "HaLVM"
  211. +PACKAGES_STAGE1 += old-time
  212. +PACKAGES_STAGE1 += haskell2010
  213. +PACKAGES_STAGE1 += HALVMCore
  214. +PACKAGES_STAGE1 += XenDevice
  215. +endif
  216. +
  217. PACKAGES_STAGE1 += xhtml
  218. ifeq "$(Windows_Target)" "NO"
  219. ifneq "$(TargetOS_CPP)" "ios"
  220. +ifneq "$(TargetOS_CPP)" "HaLVM"
  221. PACKAGES_STAGE1 += terminfo
  222. endif
  223. endif
  224. +endif
  225. +ifneq "$(TargetOS_CPP)" "HaLVM"
  226. PACKAGES_STAGE1 += haskeline
  227. +endif
  228.  
  229. # We normally install only the packages down to this point
  230. REGULAR_INSTALL_PACKAGES := $(addprefix libraries/,$(PACKAGES_STAGE1))
  231. diff --git a/includes/ghc.mk b/includes/ghc.mk
  232. index 5342cc8..be9c775 100644
  233. --- a/includes/ghc.mk
  234. +++ b/includes/ghc.mk
  235. @@ -158,6 +158,9 @@ INSTALL_LIBS += $(includes_GHCCONSTANTS_HASKELL_VALUE)
  236. DERIVE_CONSTANTS_FLAGS += --gcc-program "$(WhatGccIsCalled)"
  237. DERIVE_CONSTANTS_FLAGS += $(addprefix --gcc-flag$(space),$(includes_CC_OPTS) -fcommon)
  238. DERIVE_CONSTANTS_FLAGS += --nm-program "$(NM)"
  239. +ifeq "$(TargetOS_CPP)" "HaLVM"
  240. +DERIVE_CONSTANTS_FLAGS += --gcc-flag -Irts/xen/include
  241. +endif
  242.  
  243. ifneq "$(BINDIST)" "YES"
  244. $(includes_DERIVEDCONSTANTS): $$(includes_H_CONFIG) $$(includes_H_PLATFORM) $$(includes_H_FILES) $$(rts_H_FILES)
  245. diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h
  246. index 0d2404c..2e04b84 100644
  247. --- a/includes/rts/OSThreads.h
  248. +++ b/includes/rts/OSThreads.h
  249. @@ -156,6 +156,30 @@ typedef HANDLE Mutex;
  250.  
  251. #endif // CMINUSMINUS
  252.  
  253. +# elif defined(HaLVM_TARGET_OS)
  254. +
  255. +#if CMINUSMINUS
  256. +#define ACQUIRE_LOCK(mutex) foreign "C" halvm_acquire_lock(mutex)
  257. +#define RELEASE_LOCK(mutex) foreign "C" halvm_release_lock(mutex)
  258. +#define ASSERT_LOCK_HELD(mutex) /* nothing */
  259. +#else
  260. +
  261. +#include <locks.h>
  262. +
  263. +typedef halvm_condlock_t Condition;
  264. +typedef halvm_mutex_t Mutex;
  265. +typedef halvm_vcpu_t OSThreadId;
  266. +typedef halvm_vcpukey_t ThreadLocalKey;
  267. +
  268. +#define OSThreadProcAttr /* */
  269. +#define INIT_COND_VAR HALVM_CONDLOCK_INITIALIZER
  270. +
  271. +#define ACQUIRE_LOCK(mutex) halvm_acquire_lock(mutex)
  272. +#define TRY_ACQUIRE_LOCK(mutex) halvm_try_acquire_lock(mutex)
  273. +#define RELEASE_LOCK(mutex) halvm_release_lock(mutex)
  274. +#define ASSERT_LOCK_HELD(mutex) /* nothing */
  275. +#endif
  276. +
  277. # else
  278. # error "Threads not supported"
  279. # endif
  280. diff --git a/libffi/HaLVM.patch b/libffi/HaLVM.patch
  281. new file mode 100644
  282. index 0000000..bcd813e
  283. --- /dev/null
  284. +++ b/libffi/HaLVM.patch
  285. @@ -0,0 +1,11 @@
  286. +--- build/config.sub 2012-04-11 19:46:06.000000000 -0700
  287. ++++ libffi-3.0.11/config.sub 2013-04-09 16:24:12.181057454 -0700
  288. +@@ -1488,6 +1488,8 @@
  289. + ;;
  290. + -nacl*)
  291. + ;;
  292. ++ -HaLVM)
  293. ++ ;;
  294. + -none)
  295. + ;;
  296. + *)
  297. diff --git a/libffi/ghc.mk b/libffi/ghc.mk
  298. index 4e177d2..fcc5853 100644
  299. --- a/libffi/ghc.mk
  300. +++ b/libffi/ghc.mk
  301. @@ -58,6 +58,9 @@ $(libffi_STAMP_CONFIGURE): $(TOUCH_DEP)
  302. cat libffi-tarballs/libffi*.tar.gz | $(GZIP_CMD) -d | { cd libffi && $(TAR_CMD) -xf - ; }
  303. mv libffi/libffi-* libffi/build
  304.  
  305. +# We need to apply a patch to libffi that makes HaLVM a valid build target
  306. + patch -d libffi/build -p1 < libffi/HaLVM.patch
  307. +
  308. # We have to fake a non-working ln for configure, so that the fallback
  309. # option (cp -p) gets used instead. Otherwise the libffi build system
  310. # will use cygwin symbolic links which cannot be read by mingw gcc.
  311. @@ -101,7 +104,7 @@ $(libffi_STAMP_CONFIGURE): $(TOUCH_DEP)
  312. --libdir=$(TOP)/libffi/build/inst/lib \
  313. --enable-static=yes \
  314. --enable-shared=$(libffi_EnableShared) \
  315. - --host=$(TargetPlatformFull)
  316. + --target=$(TargetPlatformFull)
  317.  
  318. # wc on OS X has spaces in its output, which libffi's Makefile
  319. # doesn't expect, so we tweak it to sed them out
  320. diff --git a/libraries/Cabal b/libraries/Cabal
  321. index 5462f48..c226c0d 160000
  322. --- a/libraries/Cabal
  323. +++ b/libraries/Cabal
  324. @@ -1 +1 @@
  325. -Subproject commit 5462f486f0ac344b5714382b1a7498ad6d85d085
  326. +Subproject commit c226c0de042999bbe4c5c339c6c28a9be7f0c6d1
  327. diff --git a/mk/config.mk.in b/mk/config.mk.in
  328. index 7cc7aec..0481fec 100644
  329. --- a/mk/config.mk.in
  330. +++ b/mk/config.mk.in
  331. @@ -245,6 +245,10 @@ ifeq "$(PlatformSupportsSharedLibs)" "YES"
  332. GhcLibWays += dyn
  333. endif
  334.  
  335. +ifeq "$(TargetOS_CPP)" "HaLVM"
  336. +GhcLibWays := v
  337. +endif
  338. +
  339. # Handy way to test whether we're building shared libs or not.
  340. BuildSharedLibs=$(strip $(if $(findstring dyn,$(GhcLibWays)),YES,NO))
  341.  
  342. @@ -271,6 +275,11 @@ GhcRTSWays += thr thr_debug thr_l
  343. GhcRTSWays += $(if $(findstring p, $(GhcLibWays)),thr_p,)
  344. GhcRTSWays += $(if $(findstring dyn, $(GhcLibWays)),dyn debug_dyn thr_dyn thr_debug_dyn l_dyn thr_l_dyn,)
  345.  
  346. +ifeq "$(TargetOS_CPP)" "HaLVM"
  347. +#GhcRTSWays := thr
  348. +GhcRTSWays :=
  349. +endif
  350. +
  351. # We can only build GHCi threaded if we have a threaded RTS:
  352. GhcThreaded = $(if $(findstring thr,$(GhcRTSWays)),YES,NO)
  353.  
  354. @@ -299,7 +308,7 @@ StripLibraries=NO
  355. # doing object-file splitting
  356.  
  357. ArchSupportsSplitObjs=$(strip $(if $(filter $(TargetArch_CPP),i386 x86_64 powerpc sparc),YES,NO))
  358. -OsSupportsSplitObjs=$(strip $(if $(filter $(TargetOS_CPP),mingw32 cygwin32 linux darwin solaris2 freebsd dragonfly netbsd openbsd),YES,NO))
  359. +OsSupportsSplitObjs=$(strip $(if $(filter $(TargetOS_CPP),mingw32 cygwin32 linux darwin solaris2 freebsd dragonfly netbsd openbsd HaLVM),YES,NO))
  360. SplitObjsBroken = @SplitObjsBroken@
  361.  
  362. SupportsSplitObjs := $(strip \
  363. @@ -574,9 +583,11 @@ $(eval $(call set_stage_HSC2HS_OPTS,0))
  364. $(eval $(call set_stage_HSC2HS_OPTS,1))
  365. $(eval $(call set_stage_HSC2HS_OPTS,2))
  366. ifeq "$(CrossCompiling)" "YES"
  367. +ifneq "$(TargetOS_CPP)" "HaLVM"
  368. SRC_HSC2HS_OPTS_STAGE1 += --cross-compile
  369. SRC_HSC2HS_OPTS_STAGE2 += --cross-compile
  370. endif
  371. +endif
  372. SRC_HSC2HS_OPTS_STAGE0 += --cflag=-D$(HostArch_CPP)_HOST_ARCH=1 --cflag=-D$(HostOS_CPP)_HOST_OS=1
  373. SRC_HSC2HS_OPTS_STAGE1 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH=1 --cflag=-D$(TargetOS_CPP)_HOST_OS=1
  374. SRC_HSC2HS_OPTS_STAGE2 += --cflag=-D$(TargetArch_CPP)_HOST_ARCH=1 --cflag=-D$(TargetOS_CPP)_HOST_OS=1
  375. diff --git a/mk/project.mk.in b/mk/project.mk.in
  376. index 69ed885..9083979 100644
  377. --- a/mk/project.mk.in
  378. +++ b/mk/project.mk.in
  379. @@ -145,6 +145,13 @@ else
  380. Windows_Target=NO
  381. endif
  382.  
  383. +# Bare_Metal=YES if we are targeting a bare metal environment, like HaLVM/xen
  384. +ifneq "$(findstring $(TargetOS_CPP), HaLVM)" ""
  385. +Bare_Metal=YES
  386. +else
  387. +Bare_Metal=No
  388. +endif
  389. +
  390. # Tell the build system what the host operating system is
  391. # This distinguishes "msys" and "cygwin", which are not
  392. # not distinguished by HOST_OS_CPP
  393. diff --git a/rts/Linker.c b/rts/Linker.c
  394. index ceb6a4f..148658f 100644
  395. --- a/rts/Linker.c
  396. +++ b/rts/Linker.c
  397. @@ -31,7 +31,7 @@
  398. #include "GetEnv.h"
  399. #include "Stable.h"
  400.  
  401. -#if !defined(mingw32_HOST_OS)
  402. +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  403. #include "posix/Signals.h"
  404. #endif
  405.  
  406. @@ -73,6 +73,7 @@
  407. #endif
  408.  
  409. #if (defined(powerpc_HOST_ARCH) && defined(linux_HOST_OS)) \
  410. + || defined(HaLVM_TARGET_OS) \
  411. || (!defined(powerpc_HOST_ARCH) && \
  412. ( defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || \
  413. defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS ) || \
  414. @@ -341,7 +342,7 @@ typedef struct _RtsSymbolVal {
  415. SymI_HasProto(stg_makeStableNamezh) \
  416. SymI_HasProto(stg_finalizzeWeakzh)
  417.  
  418. -#if !defined (mingw32_HOST_OS)
  419. +#if !defined (mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  420. #define RTS_POSIX_ONLY_SYMBOLS \
  421. SymI_HasProto(__hscore_get_saved_termios) \
  422. SymI_HasProto(__hscore_set_saved_termios) \
  423. @@ -353,6 +354,10 @@ typedef struct _RtsSymbolVal {
  424. SymI_NeedsProto(nocldstop)
  425. #endif
  426.  
  427. +#if defined(HaLVM_TARGET_OS)
  428. +#define RTS_POSIX_ONLY_SYMBOLS
  429. +#endif
  430. +
  431. #if defined (cygwin32_HOST_OS)
  432. #define RTS_MINGW_ONLY_SYMBOLS /**/
  433. /* Don't have the ability to read import libs / archives, so
  434. diff --git a/rts/RtsSignals.h b/rts/RtsSignals.h
  435. index be21765..ad13b50 100644
  436. --- a/rts/RtsSignals.h
  437. +++ b/rts/RtsSignals.h
  438. @@ -9,7 +9,7 @@
  439. #ifndef RTSSIGNALS_H
  440. #define RTSSIGNALS_H
  441.  
  442. -#if !defined(mingw32_HOST_OS)
  443. +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  444.  
  445. #include "posix/Signals.h"
  446.  
  447. @@ -17,6 +17,12 @@
  448.  
  449. #include "win32/ConsoleHandler.h"
  450.  
  451. +#elif defined(HaLVM_TARGET_OS)
  452. +
  453. +#include <signal.h>
  454. +#include <signals.h>
  455. +extern void startSignalHandlers(Capability *cap);
  456. +
  457. #else
  458.  
  459. #define signals_pending() (rtsFalse)
  460. diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c
  461. index 24d50ee..6286f8f 100644
  462. --- a/rts/RtsStartup.c
  463. +++ b/rts/RtsStartup.c
  464. @@ -128,7 +128,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
  465. return;
  466. }
  467.  
  468. +#ifndef HaLVM_TARGET_OS
  469. setlocale(LC_CTYPE,"");
  470. +#endif
  471.  
  472. /* Initialise the stats department, phase 0 */
  473. initStats0();
  474. @@ -213,7 +215,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
  475. getStablePtr((StgPtr)runSparks_closure);
  476. getStablePtr((StgPtr)ensureIOManagerIsRunning_closure);
  477. getStablePtr((StgPtr)ioManagerCapabilitiesChanged_closure);
  478. -#ifndef mingw32_HOST_OS
  479. +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  480. getStablePtr((StgPtr)runHandlersPtr_closure);
  481. #endif
  482.  
  483. @@ -221,7 +223,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
  484. initGlobalStore();
  485.  
  486. /* initialise file locking, if necessary */
  487. +#if !defined(HaLVM_TARGET_OS)
  488. initFileLocking();
  489. +#endif
  490.  
  491. #if defined(DEBUG)
  492. /* initialise thread label table (tso->char*) */
  493. @@ -251,7 +255,9 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
  494. x86_init_fpu();
  495. #endif
  496.  
  497. +#ifndef HaLVM_TARGET_OS
  498. startupHpc();
  499. +#endif
  500.  
  501. // This must be done after module initialisation.
  502. // ToDo: make this work in the presence of multiple hs_add_root()s.
  503. @@ -351,7 +357,7 @@ hs_exit_(rtsBool wait_foreign)
  504. exitTimer(wait_foreign);
  505.  
  506. // set the terminal settings back to what they were
  507. -#if !defined(mingw32_HOST_OS)
  508. +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  509. resetTerminalSettings();
  510. #endif
  511.  
  512. @@ -364,9 +370,11 @@ hs_exit_(rtsBool wait_foreign)
  513.  
  514. /* stop timing the shutdown, we're about to print stats */
  515. stat_endExit();
  516. -
  517. +
  518. +#ifndef HaLVM_TARGET_OS
  519. /* shutdown the hpc support (if needed) */
  520. exitHpc();
  521. +#endif
  522.  
  523. // clean up things from the storage manager's point of view.
  524. // also outputs the stats (+RTS -s) info.
  525. @@ -382,7 +390,9 @@ hs_exit_(rtsBool wait_foreign)
  526. exitLinker();
  527.  
  528. /* free file locking tables, if necessary */
  529. +#if !defined(HaLVM_TARGET_OS)
  530. freeFileLocking();
  531. +#endif
  532.  
  533. /* free the stable pointer table */
  534. exitStableTables();
  535. diff --git a/rts/Schedule.c b/rts/Schedule.c
  536. index 7f8ced6..c4bdbe6 100644
  537. --- a/rts/Schedule.c
  538. +++ b/rts/Schedule.c
  539. @@ -105,7 +105,7 @@ StgTSO dummy_tso;
  540. Mutex sched_mutex;
  541. #endif
  542.  
  543. -#if !defined(mingw32_HOST_OS)
  544. +#if !defined(mingw32_HOST_OS) && !defined(HaLVM_TARGET_OS)
  545. #define FORKPROCESS_PRIMOP_SUPPORTED
  546. #endif
  547.  
  548. @@ -969,17 +969,16 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
  549. static void
  550. scheduleSendPendingMessages(void)
  551. {
  552. -
  553. # if defined(PAR) // global Mem.Mgmt., omit for now
  554. if (PendingFetches != END_BF_QUEUE) {
  555. processFetches();
  556. }
  557. # endif
  558. -
  559. +
  560. if (RtsFlags.ParFlags.BufferTime) {
  561. - // if we use message buffering, we must send away all message
  562. - // packets which have become too old...
  563. - sendOldBuffers();
  564. + // if we use message buffering, we must send away all message
  565. + // packets which have become too old...
  566. + sendOldBuffers();
  567. }
  568. }
  569. #endif
  570. diff --git a/rts/Timer.c b/rts/Timer.c
  571. index b7762f9..7f48414 100644
  572. --- a/rts/Timer.c
  573. +++ b/rts/Timer.c
  574. @@ -25,6 +25,10 @@
  575. #include "Capability.h"
  576. #include "RtsSignals.h"
  577.  
  578. +#ifdef HaLVM_TARGET_OS
  579. +#include "iomanager.h"
  580. +#endif
  581. +
  582. /* ticks left before next pre-emptive context switch */
  583. static int ticks_to_ctxt_switch = 0;
  584.  
  585. diff --git a/rts/Trace.c b/rts/Trace.c
  586. index 2190189..4ac378b 100644
  587. --- a/rts/Trace.c
  588. +++ b/rts/Trace.c
  589. @@ -460,7 +460,7 @@ void traceOSProcessInfo_(void) {
  590. CAPSET_OSPROCESS_DEFAULT,
  591. getpid());
  592.  
  593. -#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS)
  594. +#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS) && !defined (HaLVM_TARGET_OS)
  595. /* Windows has no strong concept of process heirarchy, so no getppid().
  596. * In any case, this trace event is mainly useful for tracing programs
  597. * that use 'forkProcess' which Windows doesn't support anyway.
  598. diff --git a/rts/ghc.mk b/rts/ghc.mk
  599. index 0d2b341..c442900 100644
  600. --- a/rts/ghc.mk
  601. +++ b/rts/ghc.mk
  602. @@ -33,6 +33,8 @@ ALL_DIRS = hooks sm eventlog
  603.  
  604. ifeq "$(HostOS_CPP)" "mingw32"
  605. ALL_DIRS += win32
  606. +else ifeq "$(TargetOS_CPP)" "HaLVM"
  607. +ALL_DIRS += xen minlibc
  608. else
  609. ALL_DIRS += posix
  610. endif
  611. @@ -311,6 +313,10 @@ ifeq "$(BeConservative)" "YES"
  612. rts_CC_OPTS += -DBE_CONSERVATIVE
  613. endif
  614.  
  615. +ifeq "$(TargetOS_CPP)" "HaLVM"
  616. +rts_CC_OPTS += -nostdinc -Irts/minlibc/include -Irts/xen/include -Ilibraries/HALVMCore/cbits/include
  617. +endif
  618. +
  619. #-----------------------------------------------------------------------------
  620. # Flags for compiling specific files
  621.  
  622. @@ -556,6 +562,12 @@ ifeq "$(HaveLibMingwEx)" "YES"
  623. rts_PACKAGE_CPP_OPTS += -DHAVE_LIBMINGWEX
  624. endif
  625.  
  626. +ifeq "$(TargetOS_CPP)" "HaLVM"
  627. +rts_PACKAGE_CPP_OPTS += -DHALVM_SYSTEM_INCLUDES=$(ghcheaderdir)/minlibc
  628. +else
  629. +rts_PACKAGE_CPP_OPTS += -DHALVM_SYSTEM_INCLUDES=
  630. +endif
  631. +
  632. $(eval $(call manual-package-config,rts))
  633.  
  634. rts/package.conf.inplace : $(includes_H_CONFIG) $(includes_H_PLATFORM)
  635. diff --git a/rts/minlibc b/rts/minlibc
  636. new file mode 160000
  637. index 0000000..6aa83b7
  638. --- /dev/null
  639. +++ b/rts/minlibc
  640. @@ -0,0 +1 @@
  641. +Subproject commit 6aa83b701308019506732c6a1ae1bde7815550a1
  642. diff --git a/rts/package.conf.in b/rts/package.conf.in
  643. index a364fd3..2755758 100644
  644. --- a/rts/package.conf.in
  645. +++ b/rts/package.conf.in
  646. @@ -23,6 +23,7 @@ library-dirs: TOP"/rts/dist/build" PAPI_LIB_DIR FFI_LIB_DIR
  647.  
  648. hs-libraries: "HSrts" FFI_LIB
  649.  
  650. +#if !defined(HaLVM_TARGET_OS)
  651. extra-libraries:
  652. #ifdef HAVE_LIBM
  653. "m" /* for ldexp() */
  654. @@ -56,15 +57,21 @@ extra-libraries:
  655. , "papi"
  656. #endif
  657.  
  658. +#endif /* !defined(HaLVM_TARGET_OS) */
  659. +
  660. #ifdef INSTALLING
  661. -include-dirs: INCLUDE_DIR PAPI_INCLUDE_DIR FFI_INCLUDE_DIR
  662. +include-dirs: INCLUDE_DIR HALVM_SYSTEM_INCLUDES PAPI_INCLUDE_DIR FFI_INCLUDE_DIR
  663. #else /* !INSTALLING */
  664. include-dirs: TOP"/rts/dist/build" TOP"/includes" TOP"/includes/dist-derivedconstants/header" FFI_INCLUDE_DIR
  665. #endif
  666.  
  667. includes: Stg.h
  668. hugs-options:
  669. +#ifdef HaLVM_TARGET_OS
  670. +cc-options: -DHaLVM_TARGET_OS -nostdinc
  671. +#else
  672. cc-options:
  673. +#endif
  674.  
  675. ld-options:
  676. #ifdef LEADING_UNDERSCORE
  677. diff --git a/rts/sm/Sanity.c b/rts/sm/Sanity.c
  678. index c653331..95afecd 100644
  679. --- a/rts/sm/Sanity.c
  680. +++ b/rts/sm/Sanity.c
  681. @@ -664,8 +664,13 @@ checkStaticObjects ( StgClosure* static_objects )
  682. break;
  683.  
  684. default:
  685. - barf("checkStaticObjetcs: strange closure %p (%s)",
  686. - p, info_type(p));
  687. + barf("checkStaticObjetcs: strange closure %p (%s)", p,
  688. +#ifndef HaLVM_TARGET_OS
  689. + info_type(p)
  690. +#else
  691. + "[HaLVM has no info_type()]"
  692. +#endif
  693. + );
  694. }
  695. }
  696. }
  697. diff --git a/rts/sm/Storage.c b/rts/sm/Storage.c
  698. index d002fec..a521800 100644
  699. --- a/rts/sm/Storage.c
  700. +++ b/rts/sm/Storage.c
  701. @@ -35,7 +35,9 @@
  702.  
  703. #include <string.h>
  704.  
  705. +#ifndef HaLVM_TARGET_OS
  706. #include "ffi.h"
  707. +#endif
  708.  
  709. /*
  710. * All these globals require sm_mutex to access in THREADED_RTS mode.
  711. diff --git a/rts/xen/GetEnv.c b/rts/xen/GetEnv.c
  712. new file mode 100644
  713. index 0000000..813ebab
  714. --- /dev/null
  715. +++ b/rts/xen/GetEnv.c
  716. @@ -0,0 +1,14 @@
  717. +
  718. +#include "Rts.h"
  719. +#include "GetEnv.h"
  720. +
  721. +void getProgEnvv(int *out_envc, char **out_envv[]) {
  722. + *out_envc = 0;
  723. + *out_envv = NULL;
  724. +
  725. + return;
  726. +}
  727. +
  728. +void freeProgEnvv(int envc STG_UNUSED, char *envv[] STG_UNUSED) {
  729. + return;
  730. +}
  731. diff --git a/rts/xen/GetTime.c b/rts/xen/GetTime.c
  732. new file mode 100644
  733. index 0000000..60ff1f5
  734. --- /dev/null
  735. +++ b/rts/xen/GetTime.c
  736. @@ -0,0 +1,12 @@
  737. +#include "Rts.h"
  738. +#include "GetTime.h"
  739. +
  740. +#include <sys/time.h>
  741. +
  742. +
  743. +void getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec) {
  744. + struct timeval tv;
  745. + gettimeofday(&tv, (struct timezone *) NULL);
  746. + *sec = tv.tv_sec;
  747. + *nsec = tv.tv_usec * 1000;
  748. +}
  749. diff --git a/rts/xen/OSThreads.c b/rts/xen/OSThreads.c
  750. new file mode 100644
  751. index 0000000..2bf14c2
  752. --- /dev/null
  753. +++ b/rts/xen/OSThreads.c
  754. @@ -0,0 +1,6 @@
  755. +#include "Rts.h"
  756. +
  757. +
  758. +KernelThreadId kernelThreadId(void) {
  759. + return 0;
  760. +}
  761. diff --git a/rts/xen/console.c b/rts/xen/console.c
  762. new file mode 100644
  763. index 0000000..1015fd7
  764. --- /dev/null
  765. +++ b/rts/xen/console.c
  766. @@ -0,0 +1,8 @@
  767. +#include <runtime_reqs.h>
  768. +#include <hypercalls.h>
  769. +#include <xen/xen.h>
  770. +
  771. +void runtime_write(size_t count, char *msg)
  772. +{
  773. + (void)HYPERCALL_console_io(CONSOLEIO_write, count, msg);
  774. +}
  775. diff --git a/rts/xen/entryexit.c b/rts/xen/entryexit.c
  776. new file mode 100644
  777. index 0000000..ee2f6b8
  778. --- /dev/null
  779. +++ b/rts/xen/entryexit.c
  780. @@ -0,0 +1,220 @@
  781. +#define __XEN__
  782. +#include <sys/types.h>
  783. +#include <stdint.h>
  784. +#include <stdlib.h>
  785. +#include <stdio.h>
  786. +#include <string.h>
  787. +#include <xen/xen.h>
  788. +#include <hypercalls.h>
  789. +#include <xen/sched.h>
  790. +#include <xen/vcpu.h>
  791. +#include <errno.h>
  792. +#include <assert.h>
  793. +#include <runtime_reqs.h>
  794. +#include "memory.h"
  795. +#include "smp.h"
  796. +#include "locks.h"
  797. +#include "time_rts.h"
  798. +#include "signals.h"
  799. +#include "grants.h"
  800. +#include <sys/mman.h>
  801. +
  802. +void main(int, char**);
  803. +void runtime_entry(start_info_t *, void *) __attribute__((noreturn));
  804. +void shutdown(int) __attribute__((noreturn));
  805. +
  806. +struct start_info *system_start_info = NULL;
  807. +struct shared_info *HYPERVISOR_shared_info = NULL;
  808. +
  809. +extern void divide_error(void);
  810. +extern void debug(void);
  811. +extern void int3(void);
  812. +extern void overflow(void);
  813. +extern void bounds(void);
  814. +extern void invalid_op(void);
  815. +extern void device_not_available(void);
  816. +extern void coprocessor_segment_overrun(void);
  817. +extern void invalid_TSS(void);
  818. +extern void segment_not_present(void);
  819. +extern void stack_segment(void);
  820. +extern void general_protection(void);
  821. +extern void page_fault(void);
  822. +extern void spurious_interrupt_bug(void);
  823. +extern void coprocessor_error(void);
  824. +extern void alignment_check(void);
  825. +extern void machine_check(void);
  826. +extern void simd_coprocessor_error(void);
  827. +extern void hypervisor_callback(void);
  828. +extern void failsafe_callback(void);
  829. +
  830. +#if 0
  831. +static trap_info_t trap_table[] = {
  832. + { 0, 0, FLAT_KERNEL_CS, (unsigned long)divide_error },
  833. + { 1, 0, FLAT_KERNEL_CS, (unsigned long)debug },
  834. + { 3, 3, FLAT_KERNEL_CS, (unsigned long)int3 },
  835. + { 4, 3, FLAT_KERNEL_CS, (unsigned long)overflow },
  836. + { 5, 3, FLAT_KERNEL_CS, (unsigned long)bounds },
  837. + { 6, 0, FLAT_KERNEL_CS, (unsigned long)invalid_op },
  838. + { 7, 0, FLAT_KERNEL_CS, (unsigned long)device_not_available },
  839. + { 9, 0, FLAT_KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
  840. + { 10, 0, FLAT_KERNEL_CS, (unsigned long)invalid_TSS },
  841. + { 11, 0, FLAT_KERNEL_CS, (unsigned long)segment_not_present },
  842. + { 12, 0, FLAT_KERNEL_CS, (unsigned long)stack_segment },
  843. + { 13, 0, FLAT_KERNEL_CS, (unsigned long)general_protection },
  844. + { 14, 0, FLAT_KERNEL_CS, (unsigned long)page_fault },
  845. + { 15, 0, FLAT_KERNEL_CS, (unsigned long)spurious_interrupt_bug },
  846. + { 16, 0, FLAT_KERNEL_CS, (unsigned long)coprocessor_error },
  847. + { 17, 0, FLAT_KERNEL_CS, (unsigned long)alignment_check },
  848. + { 18, 0, FLAT_KERNEL_CS, (unsigned long)machine_check },
  849. + { 19, 0, FLAT_KERNEL_CS, (unsigned long)simd_coprocessor_error },
  850. + { 0, 0, 0, 0 }
  851. +};
  852. +#endif
  853. +
  854. +enum cmdline_parse_state {
  855. + stateEmpty,
  856. + stateSingle,
  857. + stateDouble
  858. +};
  859. +
  860. +static inline uint32_t get_num_vcpus(void)
  861. +{
  862. + uint32_t i;
  863. +
  864. + for(i = 0; i < 16384; i++) {
  865. + vcpu_runstate_info_t rstate_info;
  866. + long res = HYPERCALL_vcpu_op(VCPUOP_get_runstate_info, i, &rstate_info);
  867. + if(res < 0)
  868. + break;
  869. + }
  870. +
  871. + return i;
  872. +}
  873. +
  874. +static char **argv = NULL;
  875. +static int argc = 0;
  876. +static void *runtime_stack = NULL;
  877. +
  878. +void runtime_entry(start_info_t *start_info, void *init_sp)
  879. +{
  880. + enum cmdline_parse_state state;
  881. + uint32_t num_vcpus, i, pos;
  882. + unsigned long maxpages;
  883. + mfn_t shared_info_mfn;
  884. + size_t cmdline_size;
  885. +
  886. + /* system startup stuff, that must occur before we go to GHC */
  887. + system_start_info = start_info;
  888. + num_vcpus = get_num_vcpus();
  889. + assert(num_vcpus > 0);
  890. + printf("Starting %d-CPU HaLVM\n", num_vcpus);
  891. + maxpages = initialize_memory(start_info, init_sp);
  892. + shared_info_mfn = (mfn_t)start_info->shared_info >> PAGE_SHIFT;
  893. + // just for my own sanity, make sure that the machine address we're
  894. + // given for the shared info struct is page aligned.
  895. + assert(!((uintptr_t)start_info->shared_info & (PAGE_SIZE-1)));
  896. + HYPERVISOR_shared_info = map_frames(&shared_info_mfn,1);
  897. + runtime_stack = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
  898. +#ifdef __x86_64__
  899. + asm("mov %0, %%rsp" :
  900. + : "r"((uintptr_t)runtime_stack + VCPU_STACK_SIZE - PAGE_SIZE));
  901. +#else
  902. + asm("mov %0, %%esp" :
  903. + : "r"((uintptr_t)runtime_stack + VCPU_STACK_SIZE - PAGE_SIZE));
  904. +#endif
  905. + init_signals(HYPERVISOR_shared_info);
  906. +#ifdef THREADED_RTS
  907. + init_smp_system(num_vcpus);
  908. +#else
  909. + if(num_vcpus > 1)
  910. + printf("WARNING: Allocated >1 CPUs in the non-threaded RTS.\n");
  911. +#endif
  912. + /* Don't register our trap table, as Xen's default gives more useful
  913. + * information */
  914. + /* assert(HYPERCALL_set_trap_table(trap_table) >= 0); */
  915. + assert(HYPERCALL_set_callbacks(hypervisor_callback, failsafe_callback) >= 0);
  916. + allow_signals(1);
  917. + init_time(HYPERVISOR_shared_info);
  918. + init_grants();
  919. +
  920. + /* OK, now we need to figure out what command line to give GHC. */
  921. + cmdline_size = strlen((const char *)start_info->cmd_line) + 1;
  922. + argc = 0; argv = malloc((6 + cmdline_size) * sizeof(char *));
  923. + memset(argv, 0, (6 + cmdline_size) * sizeof(char *));
  924. + /* these are constant ... */
  925. + argv[argc++] = "HaLVM";
  926. + argv[argc++] = "+RTS";
  927. + argv[argc++] = "-c";
  928. + /* tell GHC how much memory to use */
  929. + argv[argc] = malloc(16);
  930. + snprintf(argv[argc],16,"-M%dm", (maxpages - used_frames() - 128) / 256);
  931. + argc++;
  932. +#ifdef THREADED_RTS
  933. + argv[argc++] = "-N";
  934. +#endif
  935. + /* close off the RTS section */
  936. + argv[argc++] = "-RTS";
  937. + /* copy over the command line arguments */
  938. + for(i = 0, state = stateEmpty, pos = 0; start_info->cmd_line[i]; i++) {
  939. + switch(start_info->cmd_line[i]) {
  940. + case ' ':
  941. + if(state == stateEmpty) {
  942. + if(argv[argc])
  943. + argv[argc++][pos] = '\0'; pos = 0;
  944. + } else {
  945. + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
  946. + argv[argc][pos++] = ' ';
  947. + }
  948. + break;
  949. +
  950. + case '\'':
  951. + if(state == stateSingle) {
  952. + argv[argc++][pos] = '\0'; pos = 0; state = stateEmpty;
  953. + } else if(state == stateDouble) {
  954. + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
  955. + argv[argc][pos++] = '\'';
  956. + } else {
  957. + state = stateSingle;
  958. + }
  959. + break;
  960. +
  961. + case '"':
  962. + if(state == stateDouble) {
  963. + argv[argc++][pos] = '\0'; pos = 0; state = stateEmpty;
  964. + } else if(state == stateSingle) {
  965. + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
  966. + argv[argc][pos++] = '\"';
  967. + } else {
  968. + state = stateDouble;
  969. + }
  970. + break;
  971. +
  972. + default:
  973. + if(!argv[argc]) argv[argc] = malloc(cmdline_size);
  974. + argv[argc][pos++] = start_info->cmd_line[i];
  975. + break;
  976. + }
  977. + }
  978. + if(argv[argc]) {
  979. + argv[argc][pos++] = '\0';
  980. + argc++;
  981. + }
  982. +
  983. + /* Jump to GHC */
  984. + main(argc, argv);
  985. +
  986. + /* Ideally we should never get here, but just in case GHC returns ... */
  987. + runtime_exit();
  988. +}
  989. +
  990. +void runtime_exit(void)
  991. +{
  992. + shutdown(SHUTDOWN_poweroff);
  993. +}
  994. +
  995. +/* SCHEDOP_shutdown tells Xen not to schedule us anymore. Toolstack cleans up */
  996. +void shutdown(int reason)
  997. +{
  998. + sched_shutdown_t op ={ .reason = reason ? SHUTDOWN_crash : SHUTDOWN_poweroff};
  999. + for( ;; ) HYPERCALL_sched_op(SCHEDOP_shutdown, &op);
  1000. +}
  1001. diff --git a/rts/xen/faults.c b/rts/xen/faults.c
  1002. new file mode 100644
  1003. index 0000000..b9a84e8
  1004. --- /dev/null
  1005. +++ b/rts/xen/faults.c
  1006. @@ -0,0 +1,85 @@
  1007. +#include <stdio.h>
  1008. +#include <runtime_reqs.h>
  1009. +
  1010. +#ifdef __i386__
  1011. +struct pt_regs {
  1012. + long ebx;
  1013. + long ecx;
  1014. + long edx;
  1015. + long esi;
  1016. + long edi;
  1017. + long ebp;
  1018. + long eax;
  1019. + long xds;
  1020. + long xes;
  1021. + long orig_eax;
  1022. + long ip;
  1023. + long xcs;
  1024. + long eflags;
  1025. + long esp;
  1026. + long xss;
  1027. +};
  1028. +#endif
  1029. +
  1030. +#ifdef __x86_64__
  1031. +struct pt_regs {
  1032. + unsigned long r15;
  1033. + unsigned long r14;
  1034. + unsigned long r13;
  1035. + unsigned long r12;
  1036. + unsigned long rbp;
  1037. + unsigned long rbx;
  1038. + unsigned long r11;
  1039. + unsigned long r10;
  1040. + unsigned long r9;
  1041. + unsigned long r8;
  1042. + unsigned long rax;
  1043. + unsigned long rcx;
  1044. + unsigned long rdx;
  1045. + unsigned long rsi;
  1046. + unsigned long rdi;
  1047. + unsigned long orig_rax;
  1048. + unsigned long ip;
  1049. + unsigned long cs;
  1050. + unsigned long eflags;
  1051. + unsigned long rsp;
  1052. + unsigned long ss;
  1053. +};
  1054. +#endif
  1055. +
  1056. +#define DEFINE_FAULT2(name, str) \
  1057. +void name(struct pt_regs *, unsigned long) __attribute__((noreturn)); \
  1058. +void name(struct pt_regs *regs, unsigned long code) \
  1059. +{ \
  1060. + printf("FAULT: %s at %p, error code %lx\n", str, (void*)regs->ip, code); \
  1061. + runtime_exit(); \
  1062. +}
  1063. +
  1064. +#define DEFINE_FAULT1(name, str) \
  1065. +void name(struct pt_regs *) __attribute__((noreturn)); \
  1066. +void name(struct pt_regs *regs) \
  1067. +{ \
  1068. + printf("FAULT: %s at %p\n", str, (void*)regs->ip); \
  1069. + runtime_exit(); \
  1070. +}
  1071. +
  1072. +DEFINE_FAULT2(do_divide_error, "divide error")
  1073. +DEFINE_FAULT2(do_int3, "int3")
  1074. +DEFINE_FAULT2(do_overflow, "overflow")
  1075. +DEFINE_FAULT2(do_bounds, "bounds error")
  1076. +DEFINE_FAULT2(do_invalid_op, "invalid operation")
  1077. +DEFINE_FAULT2(do_device_not_available, "device not available")
  1078. +DEFINE_FAULT2(do_coprocessor_segment_overrun, "coprocessor segment overrun")
  1079. +DEFINE_FAULT2(do_invalid_TSS, "invalid TSS")
  1080. +DEFINE_FAULT2(do_segment_not_present, "segment not present")
  1081. +DEFINE_FAULT2(do_stack_segment, "stack segment")
  1082. +DEFINE_FAULT2(do_alignment_check, "alignment check")
  1083. +DEFINE_FAULT2(do_machine_check, "machine check")
  1084. +DEFINE_FAULT2(do_page_fault, "page fault")
  1085. +DEFINE_FAULT2(do_general_protection, "general protection")
  1086. +
  1087. +DEFINE_FAULT1(do_debug, "debug")
  1088. +DEFINE_FAULT1(do_coprocessor_error, "coprocessor error")
  1089. +DEFINE_FAULT1(simd_math_error, "SIMD math error")
  1090. +DEFINE_FAULT1(do_simd_coprocessor_error, "SIMD coprocessor error")
  1091. +DEFINE_FAULT1(do_spurious_interrupt_bug, "spurious interrupt")
  1092. diff --git a/rts/xen/grants.c b/rts/xen/grants.c
  1093. new file mode 100644
  1094. index 0000000..d7905eb
  1095. --- /dev/null
  1096. +++ b/rts/xen/grants.c
  1097. @@ -0,0 +1,502 @@
  1098. +#define __XEN__
  1099. +#include <stdint.h>
  1100. +#include <stdlib.h>
  1101. +#include <alloca.h>
  1102. +#include <xen/xen.h>
  1103. +#include <xen/grant_table.h>
  1104. +#include <xen/memory.h>
  1105. +#include "grants.h"
  1106. +#include "hypercalls.h"
  1107. +#include <assert.h>
  1108. +#include "memory.h"
  1109. +#include <string.h>
  1110. +#include <errno.h>
  1111. +#include "vmm.h"
  1112. +
  1113. +#define min(a,b) (((a)<(b)) ? (a) : (b))
  1114. +
  1115. +static int grant_table_interface_verson = 0;
  1116. +
  1117. +/*******************************************************************************
  1118. + *
  1119. + * VERSION 2 INTERFACE (PREFERRED)
  1120. + *
  1121. + ******************************************************************************/
  1122. +
  1123. +static grant_entry_v2_t *grant_table = NULL;
  1124. +static grant_status_t *status_table = NULL;
  1125. +static grant_ref_t max_ref = 0;
  1126. +
  1127. +static void init_grants_v2(void)
  1128. +{
  1129. + gnttab_query_size_t qsize = { .dom = DOMID_SELF };
  1130. + gnttab_setup_table_t stable = { .dom = DOMID_SELF };
  1131. + gnttab_get_status_frames_t gsf = { .dom = DOMID_SELF };
  1132. + uint32_t i, num_stat_frames;
  1133. + xen_pfn_t *table_pfns;
  1134. + uint64_t *stat_pfns;
  1135. + mfn_t *mframes;
  1136. +
  1137. + /* figure out how big we can make our grant table */
  1138. + assert(HYPERCALL_grant_table_op(GNTTABOP_query_size, &qsize, 1) >= 0);
  1139. + assert(qsize.status == GNTST_okay);
  1140. +
  1141. + /* allocate the grant table */
  1142. + table_pfns = alloca(qsize.max_nr_frames * sizeof(xen_pfn_t));
  1143. + memset(table_pfns, 0, qsize.max_nr_frames * sizeof(xen_pfn_t));
  1144. + stable.nr_frames = qsize.max_nr_frames;
  1145. + stable.frame_list.p = table_pfns;
  1146. + assert( HYPERCALL_grant_table_op(GNTTABOP_setup_table, &stable, 1) >= 0);
  1147. + assert( stable.status == GNTST_okay );
  1148. +
  1149. + /* map it into our address space */
  1150. + mframes = alloca(qsize.max_nr_frames * sizeof(mfn_t));
  1151. + memset(mframes, 0, qsize.max_nr_frames * sizeof(mfn_t));
  1152. + for(i = 0; i < qsize.max_nr_frames; i++)
  1153. + mframes[i] = table_pfns[i];
  1154. + grant_table = map_frames(mframes, qsize.max_nr_frames);
  1155. +
  1156. + /* note down the maximum grant reference */
  1157. + max_ref = (qsize.max_nr_frames * PAGE_SIZE) / sizeof(grant_entry_v2_t);
  1158. + num_stat_frames = qsize.nr_frames;
  1159. + max_ref = min(max_ref, (qsize.nr_frames * PAGE_SIZE) / sizeof(uint16_t));
  1160. +
  1161. + /* allocate the status table */
  1162. + stat_pfns = alloca(qsize.max_nr_frames * sizeof(uint64_t));
  1163. + memset(stat_pfns, 0, qsize.max_nr_frames * sizeof(uint64_t));
  1164. + gsf.nr_frames = num_stat_frames;
  1165. + gsf.frame_list.p = stat_pfns;
  1166. + assert(HYPERCALL_grant_table_op(GNTTABOP_get_status_frames, &gsf, 1) >= 0);
  1167. + assert(gsf.status == GNTST_okay);
  1168. +
  1169. + /* map it into our address space */
  1170. + memset(mframes, 0, qsize.max_nr_frames * sizeof(mfn_t));
  1171. + for(i = 0; i < qsize.max_nr_frames; i++)
  1172. + mframes[i] = stat_pfns[i];
  1173. + status_table = map_frames(mframes, num_stat_frames);
  1174. +}
  1175. +
  1176. +static long alloc_grant_v2(domid_t dom, void *p, uint16_t len, int ro,
  1177. + grant_ref_t *pref)
  1178. +{
  1179. + uint16_t offset;
  1180. + grant_ref_t i;
  1181. + pte_t pte;
  1182. + mfn_t mfn;
  1183. +
  1184. + offset = (uint16_t)((uintptr_t)p & (PAGE_SIZE-1));
  1185. + if( (offset + len) > 4096 ) return -EINVAL;
  1186. + pte = get_pt_entry(p);
  1187. + if( !ENTRY_PRESENT(pte) ) return -EINVAL;
  1188. + mfn = pte >> PAGE_SHIFT;
  1189. +
  1190. + for(i = 0; i < max_ref; i++) {
  1191. + if( (grant_table[i].hdr.flags & GTF_type_mask) == GTF_invalid ) {
  1192. + uint16_t flags = GTF_permit_access;
  1193. +
  1194. + grant_table[i].hdr.domid = dom;
  1195. + if(len == 4096) {
  1196. + grant_table[i].full_page.frame = mfn;
  1197. + } else {
  1198. + grant_table[i].sub_page.page_off = offset;
  1199. + grant_table[i].sub_page.length = len;
  1200. + grant_table[i].sub_page.frame = mfn;
  1201. + flags |= GTF_sub_page;
  1202. + }
  1203. +
  1204. + if(ro) flags |= GTF_readonly;
  1205. + system_wmb();
  1206. + grant_table[i].hdr.flags = flags;
  1207. +
  1208. + *pref = i;
  1209. + return 0;
  1210. + }
  1211. + }
  1212. +
  1213. + return -EXFULL;
  1214. +}
  1215. +
  1216. +static long end_grant_v2(grant_ref_t gref)
  1217. +{
  1218. + if(gref >= max_ref)
  1219. + return -EINVAL;
  1220. +
  1221. + grant_table[gref].hdr.flags = 0;
  1222. + system_mb();
  1223. +
  1224. + if( status_table[gref] & (GTF_reading | GTF_writing) )
  1225. + return -EAGAIN;
  1226. +
  1227. + system_mb();
  1228. + return 1;
  1229. +}
  1230. +
  1231. +static long prepare_transfer_v2(domid_t dom)
  1232. +{
  1233. + grant_ref_t i;
  1234. +
  1235. + for(i = 0; i < max_ref; i++)
  1236. + if( (grant_table[i].hdr.flags & GTF_type_mask) == GTF_invalid ) {
  1237. + grant_table[i].hdr.domid = dom;
  1238. + grant_table[i].hdr.flags = GTF_accept_transfer;
  1239. + return i;
  1240. + }
  1241. +
  1242. + return -EXFULL;
  1243. +}
  1244. +
  1245. +static long complete_transfer_v2(grant_ref_t ref, int reset)
  1246. +{
  1247. + xen_pfn_t mfn;
  1248. + uint16_t flags;
  1249. +
  1250. + if(ref >= max_ref)
  1251. + return -EINVAL;
  1252. +
  1253. + flags = grant_table[ref].hdr.flags;
  1254. + if( !(flags & GTF_transfer_committed) )
  1255. + return -EAGAIN;
  1256. +
  1257. + while( !(flags & GTF_transfer_completed) ) {
  1258. + flags = grant_table[ref].hdr.flags;
  1259. + }
  1260. +
  1261. + mfn = grant_table[ref].full_page.frame;
  1262. + assert(mfn);
  1263. +
  1264. + if(reset) {
  1265. + grant_table[ref].hdr.flags = GTF_accept_transfer;
  1266. + } else {
  1267. + grant_table[ref].hdr.flags = 0;
  1268. + }
  1269. +
  1270. + return mfn;
  1271. +}
  1272. +
  1273. +/*******************************************************************************
  1274. + *
  1275. + * VERSION 1 INTERFACE (DEPRECATED, BUT REQUIRED BY AMAZON)
  1276. + *
  1277. + ******************************************************************************/
  1278. +
  1279. +#define V1_NR_GRANT_FRAMES 4
  1280. +#define V1_NUM_ENTRIES (V1_NR_GRANT_FRAMES*PAGE_SIZE / sizeof(grant_entry_v1_t))
  1281. +
  1282. +static grant_entry_v1_t *v1_grant_table;
  1283. +
  1284. +static void init_grants_v1(void)
  1285. +{
  1286. + struct gnttab_setup_table setup;
  1287. + mfn_t frames[V1_NR_GRANT_FRAMES];
  1288. +
  1289. + setup.dom = DOMID_SELF;
  1290. + setup.nr_frames = V1_NR_GRANT_FRAMES;
  1291. + setup.frame_list.p = (unsigned long*)frames;
  1292. +
  1293. + assert(HYPERCALL_grant_table_op(GNTTABOP_setup_table, &setup, 1) >= 0);
  1294. + v1_grant_table = map_frames(frames, V1_NR_GRANT_FRAMES);
  1295. +}
  1296. +
  1297. +static long alloc_grant_v1(domid_t dom, void *p,
  1298. + uint16_t len __attribute__((unused)),
  1299. + int ro,
  1300. + grant_ref_t *pref)
  1301. +{
  1302. + grant_ref_t i;
  1303. + pte_t pte;
  1304. + mfn_t mfn;
  1305. +
  1306. + pte = get_pt_entry(p);
  1307. + if( !ENTRY_PRESENT(pte) ) return -EINVAL;
  1308. + mfn = pte >> PAGE_SHIFT;
  1309. +
  1310. + for(i = 0; i < V1_NUM_ENTRIES; i++)
  1311. + {
  1312. + if( (v1_grant_table[i].flags & GTF_type_mask) == GTF_invalid )
  1313. + {
  1314. + v1_grant_table[i].frame = mfn;
  1315. + v1_grant_table[i].domid = dom;
  1316. + system_wmb();
  1317. + v1_grant_table[i].flags = GTF_permit_access | (ro ? GTF_readonly : 0);
  1318. + system_wmb();
  1319. +
  1320. + *pref = i;
  1321. + return 0;
  1322. + }
  1323. + }
  1324. +
  1325. + return -EXFULL;
  1326. +}
  1327. +
  1328. +static long end_grant_v1(grant_ref_t gref)
  1329. +{
  1330. + uint16_t flags;
  1331. + int done = 0;
  1332. +
  1333. + if(gref >= V1_NUM_ENTRIES)
  1334. + return -EINVAL;
  1335. +
  1336. + flags = v1_grant_table[gref].flags;
  1337. + do {
  1338. + if(flags & (GTF_reading | GTF_writing))
  1339. + return -EAGAIN;
  1340. + done =
  1341. + __atomic_compare_exchange_n(&v1_grant_table[gref].flags, &flags, 0,
  1342. + 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
  1343. + } while(!done);
  1344. +
  1345. + return 1;
  1346. +}
  1347. +
  1348. +static long prepare_transfer_v1(domid_t dom)
  1349. +{
  1350. + grant_ref_t i;
  1351. +
  1352. + for(i = 0; i < V1_NUM_ENTRIES; i++)
  1353. + {
  1354. + if( (v1_grant_table[i].flags & GTF_type_mask) == GTF_invalid )
  1355. + {
  1356. + v1_grant_table[i].domid = dom;
  1357. + v1_grant_table[i].flags = GTF_accept_transfer;
  1358. + return i;
  1359. + }
  1360. + }
  1361. +
  1362. + return -EXFULL;
  1363. +}
  1364. +
  1365. +static long complete_transfer_v1(grant_ref_t ref, int reset)
  1366. +{
  1367. + xen_pfn_t mfn;
  1368. + uint16_t flags;
  1369. +
  1370. + if(ref >= V1_NUM_ENTRIES)
  1371. + return -EINVAL;
  1372. +
  1373. + flags = v1_grant_table[ref].flags;
  1374. + if( !(flags & GTF_transfer_committed) )
  1375. + return -EAGAIN;
  1376. +
  1377. + mfn = v1_grant_table[ref].frame;
  1378. + assert(mfn);
  1379. +
  1380. + v1_grant_table[ref].flags = reset ? GTF_accept_transfer : GTF_invalid;
  1381. + return mfn;
  1382. +}
  1383. +
  1384. +/*******************************************************************************
  1385. + *
  1386. + * High-Level Interface
  1387. + *
  1388. + ******************************************************************************/
  1389. +
  1390. +void init_grants(void)
  1391. +{
  1392. + gnttab_set_version_t svers = { .version = 2 };
  1393. +
  1394. + /* we really want to use version 2 of the grant table API */
  1395. + if(HYPERCALL_grant_table_op(GNTTABOP_set_version, &svers, 1) >= 0) {
  1396. + /* that should have worked, but let's double check, for sanity */
  1397. + gnttab_get_version_t gvers = { .dom = DOMID_SELF };
  1398. + assert(HYPERCALL_grant_table_op(GNTTABOP_get_version, &gvers, 1) >= 0);
  1399. + assert(gvers.version == 2);
  1400. + grant_table_interface_verson = 2;
  1401. + init_grants_v2();
  1402. + } else {
  1403. + grant_table_interface_verson = 1;
  1404. + init_grants_v1();
  1405. + }
  1406. +}
  1407. +
  1408. +long alloc_grant(domid_t dom, void *p, uint16_t len, int ro, grant_ref_t *pref)
  1409. +{
  1410. + if(grant_table_interface_verson == 2)
  1411. + return alloc_grant_v2(dom, p, len, ro, pref);
  1412. + else
  1413. + return alloc_grant_v1(dom, p, len, ro, pref);
  1414. +}
  1415. +
  1416. +long end_grant(grant_ref_t gref)
  1417. +{
  1418. + if(grant_table_interface_verson == 2)
  1419. + return end_grant_v2(gref);
  1420. + else
  1421. + return end_grant_v1(gref);
  1422. +}
  1423. +
  1424. +long map_grants(domid_t dom, int readonly,
  1425. + grant_ref_t *refs, size_t count,
  1426. + void **outptr, uint32_t *outhndls,
  1427. + uint64_t *outpaddrs)
  1428. +{
  1429. + gnttab_map_grant_ref_t *args;
  1430. + uintptr_t addr;
  1431. + uint16_t flags;
  1432. + size_t i;
  1433. + long res;
  1434. +
  1435. + if(!outptr)
  1436. + return -EINVAL;
  1437. + *outptr = NULL;
  1438. +
  1439. + if(!outhndls)
  1440. + return -EINVAL;
  1441. + memset(outhndls, 0, sizeof(uint32_t) * count);
  1442. +
  1443. + args = calloc(count, sizeof(gnttab_map_grant_ref_t));
  1444. + if(!args)
  1445. + return -ENOMEM;
  1446. +
  1447. + addr = (uintptr_t)claim_shared_space(count * 4096);
  1448. +
  1449. + flags = GNTMAP_host_map | GNTMAP_application_map;
  1450. + if(readonly)
  1451. + flags |= GNTMAP_readonly;
  1452. + if(outpaddrs)
  1453. + flags |= GNTMAP_device_map;
  1454. +
  1455. + for(i = 0; i < count; i++) {
  1456. + args[i].host_addr = addr + (i * PAGE_SIZE);
  1457. + args[i].flags = flags;
  1458. + args[i].ref = refs[i];
  1459. + args[i].dom = dom;
  1460. + }
  1461. +
  1462. + res = HYPERCALL_grant_table_op(GNTTABOP_map_grant_ref, args, count);
  1463. + if(res < 0) {
  1464. + free(args);
  1465. + return res;
  1466. + }
  1467. +
  1468. + for(i = 0; i < count; i++)
  1469. + if(args[i].status != GNTST_okay) {
  1470. + free(args);
  1471. + return -args[i].status;
  1472. + }
  1473. +
  1474. + *outptr = (void*)addr;
  1475. + for(i = 0; i < count; i++) {
  1476. + outhndls[i] = args[i].handle;
  1477. + if(outpaddrs) outpaddrs[i] = args[i].dev_bus_addr;
  1478. + }
  1479. +
  1480. + free(args);
  1481. + return 0;
  1482. +}
  1483. +
  1484. +long unmap_grants(grant_handle_t *handles, size_t count)
  1485. +{
  1486. + gnttab_unmap_grant_ref_t *args;
  1487. + size_t i;
  1488. + long res;
  1489. +
  1490. + args = calloc(count, sizeof(gnttab_unmap_grant_ref_t));
  1491. + if(!args) {
  1492. + return -ENOMEM;
  1493. + }
  1494. +
  1495. + for(i = 0; i < count; i++)
  1496. + args[i].handle = handles[i];
  1497. +
  1498. + res = HYPERCALL_grant_table_op(GNTTABOP_unmap_grant_ref, args, count);
  1499. + if(res < 0) {
  1500. + free(args);
  1501. + return res;
  1502. + }
  1503. +
  1504. + for(i = 0; i < count; i++)
  1505. + if(args[i].status != GNTST_okay) {
  1506. + free(args);
  1507. + return -args[i].status;
  1508. + }
  1509. +
  1510. + free(args);
  1511. + return 0;
  1512. +}
  1513. +
  1514. +long prepare_transfer(domid_t dom)
  1515. +{
  1516. + if(grant_table_interface_verson == 2)
  1517. + return prepare_transfer_v2(dom);
  1518. + else
  1519. + return prepare_transfer_v1(dom);
  1520. +}
  1521. +
  1522. +long transfer_frame(domid_t dom, grant_ref_t ref, void *ptr)
  1523. +{
  1524. + xen_memory_reservation_t rsv;
  1525. + gnttab_transfer_t trans;
  1526. + xen_pfn_t pfn, mfn, new_mfn;
  1527. + pte_t pte;
  1528. + long res;
  1529. +
  1530. + if( (uintptr_t)ptr & (PAGE_SIZE-1) ) {
  1531. + return -EINVAL; /* this needs to be page aligned */
  1532. + }
  1533. +
  1534. + pte = get_pt_entry(ptr);
  1535. + if( !ENTRY_PRESENT(pte) ) {
  1536. + return -EINVAL; /* and it must be mapped */
  1537. + }
  1538. +
  1539. + mfn = pte >> PAGE_SHIFT;
  1540. + set_pt_entry(ptr, NULL); /* unmap it */
  1541. +
  1542. + /* replace the PFN we're using */
  1543. + pfn = machine_to_phys_mapping[mfn];
  1544. + assert(pfn);
  1545. + rsv.extent_start.p = &new_mfn;
  1546. + rsv.nr_extents = 1;
  1547. + rsv.extent_order = 0;
  1548. + rsv.mem_flags = 0;
  1549. + rsv.domid = DOMID_SELF;
  1550. + res = HYPERCALL_memory_op(XENMEM_increase_reservation, &rsv);
  1551. + if( res < 0 ) {
  1552. + return res;
  1553. + }
  1554. + p2m_map[pfn] = new_mfn;
  1555. +
  1556. + /* do the transfer */
  1557. + trans.mfn = mfn;
  1558. + trans.domid = dom;
  1559. + trans.ref = ref;
  1560. + res = HYPERCALL_grant_table_op(GNTTABOP_transfer, &trans, 1);
  1561. + return (res < 0) ? res : trans.status;
  1562. +}
  1563. +
  1564. +long complete_transfer(grant_ref_t ref, int reset)
  1565. +{
  1566. + if(grant_table_interface_verson == 2)
  1567. + return complete_transfer_v2(ref, reset);
  1568. + else
  1569. + return complete_transfer_v1(ref, reset);
  1570. +}
  1571. +
  1572. +long copy_frame(unsigned long src, int src_is_ref, domid_t sdom, uint16_t soff,
  1573. + unsigned long dst, int dst_is_ref, domid_t ddom, uint16_t doff,
  1574. + uint16_t length)
  1575. +{
  1576. + gnttab_copy_t copy;
  1577. + long res;
  1578. +
  1579. + memset(&copy, 0, sizeof(gnttab_copy_t));
  1580. +
  1581. + if(src_is_ref) {
  1582. + copy.source.u.ref = src;
  1583. + copy.flags = GNTCOPY_source_gref;
  1584. + } else copy.source.u.gmfn = src;
  1585. +
  1586. + if(dst_is_ref) {
  1587. + copy.dest.u.ref = dst;
  1588. + copy.flags |= GNTCOPY_dest_gref;
  1589. + } else copy.dest.u.gmfn = dst;
  1590. +
  1591. + copy.source.domid = sdom;
  1592. + copy.source.offset = soff;
  1593. + copy.dest.domid = ddom;
  1594. + copy.dest.offset = doff;
  1595. + copy.len = length;
  1596. +
  1597. + res = HYPERCALL_grant_table_op(GNTTABOP_copy, &copy, 1);
  1598. + return (res < 0) ? res : copy.status;
  1599. +}
  1600. diff --git a/rts/xen/hypercalls.c b/rts/xen/hypercalls.c
  1601. new file mode 100644
  1602. index 0000000..bbb0fd5
  1603. --- /dev/null
  1604. +++ b/rts/xen/hypercalls.c
  1605. @@ -0,0 +1,113 @@
  1606. +#define __XEN__
  1607. +#include <hypercalls.h>
  1608. +#include <xen/xen.h>
  1609. +
  1610. +#ifdef __i386__
  1611. +#define HC_RET "eax"
  1612. +#define HC_ARG1 "ebx"
  1613. +#define HC_ARG2 "ecx"
  1614. +#define HC_ARG3 "edx"
  1615. +#define HC_ARG4 "esi"
  1616. +#define HC_ARG5 "edi"
  1617. +#endif
  1618. +
  1619. +#ifdef __x86_64__
  1620. +#define HC_RET "rax"
  1621. +#define HC_ARG1 "rdi"
  1622. +#define HC_ARG2 "rsi"
  1623. +#define HC_ARG3 "rdx"
  1624. +#define HC_ARG4 "r10"
  1625. +#define HC_ARG5 "r8"
  1626. +#endif
  1627. +
  1628. +extern struct { char _entry[32]; } hypercall_page[];
  1629. +
  1630. +#define hypercall(x, a1, a2, a3, a4, a5) \
  1631. + ({ \
  1632. + register unsigned long __res asm(HC_RET); \
  1633. + register unsigned long __arg1 asm(HC_ARG1) = __arg1; \
  1634. + register unsigned long __arg2 asm(HC_ARG2) = __arg2; \
  1635. + register unsigned long __arg3 asm(HC_ARG3) = __arg3; \
  1636. + register unsigned long __arg4 asm(HC_ARG4) = __arg4; \
  1637. + register unsigned long __arg5 asm(HC_ARG5) = __arg5; \
  1638. + __arg1 = (unsigned long)(a1); \
  1639. + __arg2 = (unsigned long)(a2); \
  1640. + __arg3 = (unsigned long)(a3); \
  1641. + __arg4 = (unsigned long)(a4); \
  1642. + __arg5 = (unsigned long)(a5); \
  1643. + asm volatile ("call hypercall_page+%c[offset]" \
  1644. + : "=r"(__res), "+r"(__arg1), "+r"(__arg2), "+r"(__arg3), \
  1645. + "+r"(__arg4), "+r"(__arg5) \
  1646. + : [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))\
  1647. + : "memory"); \
  1648. + __res; \
  1649. + })
  1650. +
  1651. +long HYPERCALL_mmu_update(const struct mmu_update reqs[],
  1652. + unsigned count, unsigned *done_out,
  1653. + unsigned dom)
  1654. +{
  1655. + return hypercall(mmu_update, (uintptr_t)reqs, count,
  1656. + (uintptr_t)done_out, dom, 0);
  1657. +}
  1658. +
  1659. +long HYPERCALL_memory_op(unsigned int cmd, void *arg)
  1660. +{
  1661. + return hypercall(memory_op, cmd, (uintptr_t)arg, 0, 0, 0);
  1662. +}
  1663. +
  1664. +long HYPERCALL_console_io(int cmd, int count, char *buffer)
  1665. +{
  1666. + return hypercall(console_io, cmd, count,(uintptr_t)buffer,0,0);
  1667. +}
  1668. +
  1669. +long HYPERCALL_vcpu_op(int cmd, int vcpuid, void *extra)
  1670. +{
  1671. + return hypercall(vcpu_op, cmd, vcpuid, (uintptr_t)extra, 0, 0);
  1672. +}
  1673. +
  1674. +long HYPERCALL_mmuext_op(struct mmuext_op *op, unsigned int count,
  1675. + unsigned int *pdone, unsigned int foreigndom)
  1676. +{
  1677. + return hypercall(mmuext_op, (uintptr_t)op, count,
  1678. + (uintptr_t)pdone, foreigndom, 0);
  1679. +}
  1680. +
  1681. +long HYPERCALL_sched_op(int cmd, void *arg)
  1682. +{
  1683. + return hypercall(sched_op, cmd, (uintptr_t)arg, 0, 0, 0);
  1684. +}
  1685. +
  1686. +long HYPERCALL_domctl(xen_domctl_t *op)
  1687. +{
  1688. + return hypercall(domctl, (uintptr_t)op, 0, 0, 0, 0);
  1689. +}
  1690. +
  1691. +long HYPERCALL_grant_table_op(int cmd, void *args, unsigned int count)
  1692. +{
  1693. + return hypercall(grant_table_op, cmd, args, count, 0, 0);
  1694. +}
  1695. +
  1696. +long HYPERCALL_set_trap_table(const struct trap_info traps[])
  1697. +{
  1698. + return hypercall(set_trap_table, traps, 0, 0, 0, 0);
  1699. +}
  1700. +
  1701. +long HYPERCALL_set_callbacks(void *event, void *fail)
  1702. +{
  1703. +#ifdef __x86_64__
  1704. + return hypercall(set_callbacks, event, fail, 0, 0, 0);
  1705. +#else
  1706. + return hypercall(set_callbacks,FLAT_KERNEL_CS,event,FLAT_KERNEL_CS,fail,0);
  1707. +#endif
  1708. +}
  1709. +
  1710. +long HYPERCALL_event_channel_op(int cmd, void *arg)
  1711. +{
  1712. + return hypercall(event_channel_op, cmd, arg, 0, 0, 0);
  1713. +}
  1714. +
  1715. +long HYPERCALL_set_timer_op(uint64_t until)
  1716. +{
  1717. + return hypercall(set_timer_op, until, 0, 0, 0, 0);
  1718. +}
  1719. diff --git a/rts/xen/include/grants.h b/rts/xen/include/grants.h
  1720. new file mode 100644
  1721. index 0000000..582a2bd
  1722. --- /dev/null
  1723. +++ b/rts/xen/include/grants.h
  1724. @@ -0,0 +1,26 @@
  1725. +#ifndef RTS_XEN_GRANTS_H
  1726. +#define RTS_XEN_GRANTS_H
  1727. +
  1728. +#ifndef __XEN__
  1729. +#define __XEN__
  1730. +#endif
  1731. +
  1732. +#include <xen/xen.h>
  1733. +#include <xen/grant_table.h>
  1734. +
  1735. +void init_grants(void);
  1736. +
  1737. +long alloc_grant(domid_t, void *, uint16_t, int, grant_ref_t *);
  1738. +long end_grant(grant_ref_t);
  1739. +
  1740. +long map_grants(domid_t,int,grant_ref_t*,size_t,void**,uint32_t*,uint64_t*);
  1741. +long unmap_grants(grant_handle_t *, size_t);
  1742. +
  1743. +long prepare_transfer(domid_t);
  1744. +long transfer_frame(domid_t, grant_ref_t, void*);
  1745. +long complete_transfer(grant_ref_t, int);
  1746. +long copy_frame(unsigned long src, int src_is_ref, domid_t sdom, uint16_t soff,
  1747. + unsigned long dst, int dst_is_ref, domid_t ddom, uint16_t doff,
  1748. + uint16_t length);
  1749. +
  1750. +#endif
  1751. diff --git a/rts/xen/include/hypercalls.h b/rts/xen/include/hypercalls.h
  1752. new file mode 100644
  1753. index 0000000..9127ba9
  1754. --- /dev/null
  1755. +++ b/rts/xen/include/hypercalls.h
  1756. @@ -0,0 +1,63 @@
  1757. +#ifndef RTS_XEN_HYPERCALLS_H
  1758. +#define RTS_XEN_HYPERCALLS_H
  1759. +
  1760. +#include <assert.h>
  1761. +#include <stdint.h>
  1762. +#include <sys/types.h>
  1763. +#include <xen/xen.h>
  1764. +#include <xen/platform.h>
  1765. +#include <xen/tmem.h>
  1766. +#include <xen/event_channel.h>
  1767. +#include <xen/xsm/flask_op.h>
  1768. +
  1769. +typedef struct xen_domctl xen_domctl_t;
  1770. +typedef struct xen_sysctl xen_sysctl_t;
  1771. +
  1772. +long HYPERCALL_set_trap_table(const struct trap_info traps[]);
  1773. +long HYPERCALL_mmu_update(const struct mmu_update reqs[],
  1774. + unsigned count, unsigned *done_out,
  1775. + unsigned foreigndom);
  1776. +long HYPERCALL_set_gdt(const xen_pfn_t frames[], unsigned int entries);
  1777. +long HYPERCALL_stack_switch(unsigned long ss, unsigned long esp);
  1778. +long HYPERCALL_set_callbacks(void *event_addr, void *fail_addr);
  1779. +long HYPERCALL_fpu_taskswitch(int set);
  1780. +long HYPERCALL_platform_op(const struct xen_platform_op*);
  1781. +long HYPERCALL_set_debugreg(int regno, unsigned long val);
  1782. +unsigned long HYPERCALL_get_debugreg(int regno);
  1783. +long HYPERCALL_update_descriptor(uint64_t ma, uint64_t desc);
  1784. +long HYPERCALL_memory_op(unsigned int cmd, void *arg);
  1785. +long HYPERCALL_multicall(multicall_entry_t *entries, int nr_calls);
  1786. +long HYPERCALL_update_va_mapping(unsigned long va, uint64_t val,
  1787. + unsigned long fl);
  1788. +long HYPERCALL_set_timer_op(uint64_t timeout);
  1789. +long HYPERCALL_xen_version(int cmd, void *buffer);
  1790. +long HYPERCALL_console_io(int cmd, int count, char *buffer);
  1791. +long HYPERCALL_grant_table_op(int cmd, void *args, unsigned int count);
  1792. +long HYPERCALL_vm_assist(unsigned int cmd, unsigned int type);
  1793. +long HYPERCALL_update_va_mapping_otherdomain(unsigned long va, uint64_t val,
  1794. + unsigned long fl, domid_t domid);
  1795. +long HYPERCALL_iret(void);
  1796. +long HYPERCALL_vcpu_op(int cmd, int vcpuid, void *extra);
  1797. +#ifdef __x86_64__
  1798. +long HYPERCALL_set_segment_base(unsigned int which, unsigned long base);
  1799. +#endif
  1800. +long HYPERCALL_mmuext_op(struct mmuext_op *op, unsigned int count,
  1801. + unsigned int *pdone, unsigned int foreigndom);
  1802. +#ifdef XEN_FLASK_INTERFACE_VERSION
  1803. +long HYPERCALL_xsm_op(xen_flask_op_t *op);
  1804. +#else
  1805. +long HYPERCALL_xsm_op(flask_op_t *op);
  1806. +#endif
  1807. +long HYPERCALL_nmi_op(int cmd, void *arg);
  1808. +long HYPERCALL_sched_op(int cmd, void *arg);
  1809. +long HYPERCALL_callback_op(int cmd, void *arg);
  1810. +long HYPERCALL_xenoprof_op(int op, void *arg);
  1811. +long HYPERCALL_event_channel_op(int cmd, void *arg);
  1812. +long HYPERCALL_physdev_op(int cmd, void *arg);
  1813. +long HYPERCALL_hvm_op(int op, void *arg);
  1814. +long HYPERCALL_sysctl(xen_sysctl_t *op);
  1815. +long HYPERCALL_domctl(xen_domctl_t *op);
  1816. +long HYPERCALL_kexec_op(unsigned long op, int arg1, void *arg);
  1817. +long HYPERCALL_tmem_op(tmem_op_t *ops);
  1818. +
  1819. +#endif
  1820. diff --git a/rts/xen/include/iomanager.h b/rts/xen/include/iomanager.h
  1821. new file mode 100644
  1822. index 0000000..c0b3886
  1823. --- /dev/null
  1824. +++ b/rts/xen/include/iomanager.h
  1825. @@ -0,0 +1,9 @@
  1826. +#ifndef RTS_XEN_IOMANAGER_H
  1827. +#define RTS_XEN_IOMANAGER_H
  1828. +
  1829. +#include "Rts.h"
  1830. +
  1831. +StgWord waitForWaiter(StgStablePtr *out);
  1832. +void registerWaiter(HsInt, StgStablePtr);
  1833. +
  1834. +#endif
  1835. diff --git a/rts/xen/include/locks.h b/rts/xen/include/locks.h
  1836. new file mode 100644
  1837. index 0000000..56d581e
  1838. --- /dev/null
  1839. +++ b/rts/xen/include/locks.h
  1840. @@ -0,0 +1,31 @@
  1841. +#ifndef RTS_XEN_LOCKS_H
  1842. +#define RTS_XEN_LOCKS_H
  1843. +
  1844. +#include <stdint.h>
  1845. +
  1846. +typedef uint32_t halvm_mutex_t;
  1847. +typedef struct _vcpu_thread *halvm_vcpu_t;
  1848. +
  1849. +struct condlock {
  1850. + halvm_mutex_t lock;
  1851. + struct _vcpu_thread *waiter;
  1852. + uint32_t state;
  1853. +};
  1854. +
  1855. +#define CONDLOCK_EMPTY 1
  1856. +#define CONDLOCK_WAITING 2
  1857. +#define CONDLOCK_SIGNALED 3
  1858. +
  1859. +typedef struct condlock halvm_condlock_t;
  1860. +typedef uintptr_t halvm_vcpukey_t;
  1861. +
  1862. +int halvm_acquire_lock(halvm_mutex_t *mutex);
  1863. +int halvm_try_acquire_lock(halvm_mutex_t *mutex);
  1864. +int halvm_release_lock(halvm_mutex_t *mutex);
  1865. +
  1866. +#ifndef THREADED_RTS
  1867. +void initMutex(halvm_mutex_t *);
  1868. +void closeMutex(halvm_mutex_t *);
  1869. +#endif
  1870. +
  1871. +#endif
  1872. diff --git a/rts/xen/include/memory.h b/rts/xen/include/memory.h
  1873. new file mode 100644
  1874. index 0000000..3b7d2db
  1875. --- /dev/null
  1876. +++ b/rts/xen/include/memory.h
  1877. @@ -0,0 +1,70 @@
  1878. +#ifndef RTS_XEN_MEMORY_H
  1879. +#define RTS_XEN_MEMORY_H
  1880. +
  1881. +#ifndef __XEN__
  1882. +#define __XEN__
  1883. +#endif
  1884. +
  1885. +#include <stdint.h>
  1886. +#include <sys/types.h>
  1887. +#include <xen/xen.h>
  1888. +
  1889. +// start the haskell heap at 64M
  1890. +#define HASKELL_HEAP_START ((char *)0x4000000)
  1891. +
  1892. +#define PAGE_SHIFT 12
  1893. +#define PAGE_SIZE (1 << PAGE_SHIFT)
  1894. +#define VCPU_STACK_SIZE (256 * PAGE_SIZE)
  1895. +#define IRQ_STACK_SIZE (8 * PAGE_SIZE)
  1896. +
  1897. +
  1898. +#ifdef CONFIG_X86_32
  1899. +#error "Pure 32-bit mode is no longer supported!"
  1900. +#endif
  1901. +
  1902. +#ifdef CONFIG_X86_PAE
  1903. +typedef uint32_t mfn_t;
  1904. +typedef uint32_t pfn_t;
  1905. +typedef uint64_t maddr_t;
  1906. +#define PFN_SET_BIT (1 << 31)
  1907. +#define CPU_LOCAL_MEM_START 0x4000
  1908. +#define CPU_LOCAL_MEM_END (512 * 4096)
  1909. +#define IN_HYPERVISOR_SPACE(x) ((uintptr_t)(x) >= HYPERVISOR_VIRT_START)
  1910. +#define MEMORY_TYPES_DECLARED
  1911. +#endif
  1912. +
  1913. +#ifdef CONFIG_X86_64
  1914. +typedef uint64_t mfn_t;
  1915. +typedef uint64_t pfn_t;
  1916. +typedef uint64_t maddr_t;
  1917. +#define PFN_SET_BIT (1UL << 63)
  1918. +#define CPU_LOCAL_MEM_START 0x4000
  1919. +#define CPU_LOCAL_MEM_END (512 * 4096)
  1920. +#define IN_HYPERVISOR_SPACE(x) (((uintptr_t)(x) >= HYPERVISOR_VIRT_START) &&\
  1921. + ((uintptr_t)(x) < HYPERVISOR_VIRT_END))
  1922. +#define MEMORY_TYPES_DECLARED
  1923. +#endif
  1924. +
  1925. +#ifndef MEMORY_TYPES_DECLARED
  1926. +#error "Need to be compiled with CONFIG_X86_32, 64, or PAE."
  1927. +#endif
  1928. +
  1929. +extern mfn_t *p2m_map;
  1930. +extern unsigned long cur_pages;
  1931. +extern unsigned long max_pages;
  1932. +
  1933. +void set_pframe_used(pfn_t);
  1934. +void set_pframe_unused(pfn_t);
  1935. +mfn_t get_free_frame(void);
  1936. +unsigned long used_frames(void);
  1937. +
  1938. +unsigned long initialize_memory(start_info_t *, void *);
  1939. +void *claim_shared_space(size_t);
  1940. +void *map_frames(mfn_t *, size_t);
  1941. +long pin_frame(int, mfn_t, domid_t);
  1942. +
  1943. +void system_wmb(void);
  1944. +void system_rmb(void);
  1945. +void system_mb(void);
  1946. +
  1947. +#endif
  1948. diff --git a/rts/xen/include/signals.h b/rts/xen/include/signals.h
  1949. new file mode 100644
  1950. index 0000000..c705af2
  1951. --- /dev/null
  1952. +++ b/rts/xen/include/signals.h
  1953. @@ -0,0 +1,36 @@
  1954. +#ifndef RTS_XEN_SIGNALS_H
  1955. +#define RTS_XEN_SIGNALS_H
  1956. +
  1957. +#ifndef __XEN__
  1958. +#define __XEN__
  1959. +#endif
  1960. +
  1961. +#include <stdint.h>
  1962. +#include <xen/xen.h>
  1963. +#include <Rts.h>
  1964. +
  1965. +void init_signals(struct shared_info *);
  1966. +
  1967. +long bind_virq(uint32_t, uint32_t);
  1968. +long bind_pirq(uint32_t, int);
  1969. +long bind_ipi(uint32_t);
  1970. +void set_c_handler(uint32_t, void (*)(int));
  1971. +void clear_c_handler(uint32_t);
  1972. +void set_haskell_handler(uint32_t, StgStablePtr);
  1973. +StgStablePtr clear_haskell_handler(uint32_t);
  1974. +long channel_send(uint32_t);
  1975. +long channel_alloc(uint32_t, uint32_t);
  1976. +long channel_bind(uint32_t, uint32_t);
  1977. +long channel_close(uint32_t);
  1978. +
  1979. +void mask_channel(uint32_t);
  1980. +void unmask_channel(uint32_t);
  1981. +
  1982. +void do_hypervisor_callback(void *);
  1983. +
  1984. +rtsBool anyUserHandlers(void);
  1985. +int signals_pending(void);
  1986. +int allow_signals(int);
  1987. +StgStablePtr dequeueSignalHandler(void);
  1988. +
  1989. +#endif
  1990. diff --git a/rts/xen/include/smp.h b/rts/xen/include/smp.h
  1991. new file mode 100644
  1992. index 0000000..9467d11
  1993. --- /dev/null
  1994. +++ b/rts/xen/include/smp.h
  1995. @@ -0,0 +1,66 @@
  1996. +#ifndef RTS_XEN_SMP_H
  1997. +#define RTS_XEN_SMP_H
  1998. +
  1999. +#ifndef __XEN__
  2000. +#define __XEN__
  2001. +#endif
  2002. +
  2003. +#include <stdint.h>
  2004. +#include <xen/xen.h>
  2005. +#include <xen/event_channel.h>
  2006. +#include "locks.h"
  2007. +
  2008. +#ifdef THREADED_RTS
  2009. +#define MUNUSED
  2010. +#else
  2011. +#define MUNUSED __attribute__((unused))
  2012. +#endif
  2013. +
  2014. +#ifdef THREADED_RTS
  2015. +typedef struct _vcpu_thread vcpu_thread_t;
  2016. +
  2017. +struct _vcpu_local_info {
  2018. + uint32_t num;
  2019. + evtchn_port_t ipi_port;
  2020. + vcpu_thread_t *cur_thread;
  2021. + unsigned long local_evt_bits[sizeof(unsigned long) * 8];
  2022. + struct vcpu_info info;
  2023. +} __attribute__((aligned(512)));
  2024. +
  2025. +typedef struct _vcpu_local_info vcpu_local_info_t;
  2026. +
  2027. +struct _per_vcpu_data {
  2028. + vcpu_local_info_t *cpuinfo;
  2029. + void *irqstack;
  2030. +} __attribute__((aligned(16)));
  2031. +
  2032. +typedef struct _per_vcpu_data per_vcpu_data_t;
  2033. +
  2034. +static inline vcpu_local_info_t *cpu_info(void)
  2035. +{
  2036. + vcpu_local_info_t *out;
  2037. + asm("mov %%fs:0, %0" : "=r"(out));
  2038. + return out;
  2039. +}
  2040. +
  2041. +#define vcpu_num() (cpu_info()->num)
  2042. +#define vcpu_ipi_port() (cpu_info()->ipi_port)
  2043. +#define vcpu_cur_thread() (cpu_info()->cur_thread)
  2044. +#define vcpu_evt_bits(x) (cpu_info()->local_evt_bits[x])
  2045. +#define vcpu_info() (cpu_info()->info)
  2046. +
  2047. +void init_smp_system(uint32_t);
  2048. +void unlockThread(vcpu_thread_t *);
  2049. +void lockCurrentThread(halvm_mutex_t*);
  2050. +void pokeSleepThread(void);
  2051. +#else
  2052. +extern struct shared_info *HYPERVISOR_shared_info;
  2053. +
  2054. +#define vcpu_num() (0)
  2055. +#define vcpu_info() (HYPERVISOR_shared_info->vcpu_info[0])
  2056. +#define vcpu_evt_bits(x) (0)
  2057. +#endif
  2058. +
  2059. +void sleepUntilWaiter(unsigned long);
  2060. +
  2061. +#endif
  2062. diff --git a/rts/xen/include/time_rts.h b/rts/xen/include/time_rts.h
  2063. new file mode 100644
  2064. index 0000000..3709470
  2065. --- /dev/null
  2066. +++ b/rts/xen/include/time_rts.h
  2067. @@ -0,0 +1,15 @@
  2068. +#ifndef RTS_XEN_TIME_H
  2069. +#define RTS_XEN_TIME_H
  2070. +
  2071. +#ifndef __XEN__
  2072. +#define __XEN__
  2073. +#endif
  2074. +
  2075. +#include <xen/xen.h>
  2076. +#include "Rts.h"
  2077. +
  2078. +void init_time(struct shared_info *);
  2079. +StgWord getDelayTarget(HsInt /* microseconds */);
  2080. +uint64_t monotonic_clock(void);
  2081. +
  2082. +#endif
  2083. diff --git a/rts/xen/include/vmm.h b/rts/xen/include/vmm.h
  2084. new file mode 100644
  2085. index 0000000..5404fc3
  2086. --- /dev/null
  2087. +++ b/rts/xen/include/vmm.h
  2088. @@ -0,0 +1,77 @@
  2089. +#ifndef RTS_XEN_VMM_H
  2090. +#define RTS_XEN_VMM_H
  2091. +
  2092. +#ifndef __XEN__
  2093. +#define __XEN__
  2094. +#endif
  2095. +
  2096. +#include <stdint.h>
  2097. +#include <sys/types.h>
  2098. +#include <xen/xen.h>
  2099. +
  2100. +#define PG_PRESENT (1 << 0)
  2101. +#define PG_READWRITE (1 << 1)
  2102. +#define PG_USER (1 << 2)
  2103. +#define PG_WRITETHROUGH (1 << 3)
  2104. +#define PG_CACHEDISABLE (1 << 4)
  2105. +#define PG_ACCESSED (1 << 5)
  2106. +#define PG_DIRTY (1 << 6)
  2107. +#define PG_SIZE (1 << 7)
  2108. +#define PG_GLOBAL (1 << 8)
  2109. +#define PG_CLAIMED (1 << 9)
  2110. +#define PG_UNUSED1 (1 << 10)
  2111. +#define PG_UNUSED2 (1 << 11)
  2112. +
  2113. +#define STANDARD_PERMS (PG_PRESENT | PG_USER | PG_CLAIMED)
  2114. +#define STANDARD_RW_PERMS (STANDARD_PERMS | PG_READWRITE)
  2115. +
  2116. +#ifdef CONFIG_X86_PAE
  2117. +typedef uint64_t pte_t;
  2118. +
  2119. +#define NUM_PT_ENTRIES 512
  2120. +#define MADDR_MASK 0x0000000FFFFFF000ULL
  2121. +#define PG_EXECUTABLE 0xFFFFFFFFFFFFFFFFULL
  2122. +#define NUM_PT_LEVELS 3
  2123. +
  2124. +#define BUILD_ADDR(b,c,d) ((void*)((((uintptr_t)(b)) << 30) | \
  2125. + (((uintptr_t)(c)) << 21) | \
  2126. + (((uintptr_t)(d)) << 12)))
  2127. +#define CANONICALIZE(x) (x)
  2128. +#define DECANONICALIZE(x) (x)
  2129. +#endif
  2130. +
  2131. +#ifdef CONFIG_X86_64
  2132. +typedef uint64_t pte_t;
  2133. +
  2134. +#define NUM_PT_ENTRIES 512
  2135. +#define MADDR_MASK 0x000FFFFFFFFFF000ULL
  2136. +#define PG_EXECUTABLE 0x7FFFFFFFFFFFFFFFULL
  2137. +#define NUM_PT_LEVELS 4
  2138. +
  2139. +#define BUILD_ADDR(a,b,c,d) ((void*)((((uintptr_t)(a)) << 39) | \
  2140. + (((uintptr_t)(b)) << 30) | \
  2141. + (((uintptr_t)(c)) << 21) | \
  2142. + (((uintptr_t)(d)) << 12)))
  2143. +#define CANONICALIZE(x) (void*)((((uintptr_t)(x)) & (1UL << 49)) \
  2144. + ? ((uintptr_t)x | 0xffff000000000000) \
  2145. + : ((uintptr_t)x & 0xFFFFFFFFFFFF))
  2146. +#define DECANONICALIZE(x) ((void*)((uintptr_t)(x) & 0xFFFFFFFFFFFF))
  2147. +#endif
  2148. +
  2149. +#define INDEX_MASK ((NUM_PT_ENTRIES) - 1)
  2150. +
  2151. +#define VADDR_L1_IDX(x) ((((uintptr_t)(x)) >> 12) & INDEX_MASK)
  2152. +#define VADDR_L2_IDX(x) ((((uintptr_t)(x)) >> 21) & INDEX_MASK)
  2153. +#define VADDR_L3_IDX(x) ((((uintptr_t)(x)) >> 30) & INDEX_MASK)
  2154. +#define VADDR_L4_IDX(x) ((((uintptr_t)(x)) >> 39) & INDEX_MASK)
  2155. +
  2156. +#define ENTRY_PRESENT(x) ((x) & PG_PRESENT)
  2157. +#define ENTRY_CLAIMED(x) ((x) & PG_CLAIMED)
  2158. +#define ENTRY_MADDR(x) ((pte_t)(x) & MADDR_MASK)
  2159. +
  2160. +void *initialize_vmm(start_info_t *, void *);
  2161. +pte_t get_pt_entry(void *addr);
  2162. +void set_pt_entry(void *addr, pte_t entry);
  2163. +void *machine_to_virtual(uint64_t maddr);
  2164. +
  2165. +#endif
  2166. diff --git a/rts/xen/iomanager.c b/rts/xen/iomanager.c
  2167. new file mode 100644
  2168. index 0000000..8a19611
  2169. --- /dev/null
  2170. +++ b/rts/xen/iomanager.c
  2171. @@ -0,0 +1,110 @@
  2172. +#include "Rts.h"
  2173. +#include "Prelude.h"
  2174. +#include <assert.h>
  2175. +#include "iomanager.h"
  2176. +#include "time_rts.h"
  2177. +#include "signals.h"
  2178. +#include "Task.h"
  2179. +#include "Schedule.h"
  2180. +#include "smp.h"
  2181. +
  2182. +void setIOManagerControlFd(int fd)
  2183. +{
  2184. + printf("ERROR: Someone called setIOManagerControlFd(%d)\n", fd);
  2185. +}
  2186. +
  2187. +void setIOManagerWakeupFd(int fd)
  2188. +{
  2189. + printf("ERROR: Someone called setIOManagerWakeupFd(%d)\n", fd);
  2190. +}
  2191. +
  2192. +void ioManagerWakeup(void)
  2193. +{
  2194. + /* nothin'! */
  2195. +}
  2196. +
  2197. +#ifdef THREADED_RTS
  2198. +typedef struct waiter {
  2199. + struct waiter *next;
  2200. + StgWord target;
  2201. + StgStablePtr action;
  2202. +} waiter_t;
  2203. +
  2204. +static halvm_mutex_t waiters_lock;
  2205. +static waiter_t *waiters = NULL;
  2206. +#endif
  2207. +
  2208. +void registerWaiter(HsInt usecs MUNUSED, StgStablePtr action MUNUSED)
  2209. +{
  2210. +#ifdef THREADED_RTS
  2211. + waiter_t *newWaiter = malloc(sizeof(waiter_t));
  2212. + waiter_t *cur, *prev;
  2213. +
  2214. + newWaiter->target = getDelayTarget(usecs);
  2215. + newWaiter->action = action;
  2216. +
  2217. + halvm_acquire_lock(&waiters_lock);
  2218. + for(cur = waiters, prev = NULL; cur; prev = cur, cur = cur->next)
  2219. + if(cur->target > newWaiter->target) {
  2220. + newWaiter->next = cur;
  2221. + if(prev) prev->next = newWaiter; else waiters = newWaiter;
  2222. + halvm_release_lock(&waiters_lock);
  2223. + return;
  2224. + }
  2225. +
  2226. + newWaiter->next = NULL;
  2227. + if(prev) prev->next = newWaiter; else waiters = newWaiter;
  2228. + halvm_release_lock(&waiters_lock);
  2229. + pokeSleepThread();
  2230. +#endif
  2231. +}
  2232. +
  2233. +StgWord waitForWaiter(StgStablePtr *out MUNUSED)
  2234. +{
  2235. +#ifdef THREADED_RTS
  2236. + StgStablePtr signal = dequeueSignalHandler();
  2237. + unsigned long target;
  2238. +
  2239. + if(signal) {
  2240. + *out = signal;
  2241. + return 0;
  2242. + }
  2243. +
  2244. + halvm_acquire_lock(&waiters_lock);
  2245. + if(waiters && waiters->target <= getDelayTarget(0)) {
  2246. + waiter_t *dead = waiters;
  2247. +
  2248. + *out = waiters->action;
  2249. + waiters = waiters->next;
  2250. + halvm_release_lock(&waiters_lock);
  2251. + free(dead);
  2252. +
  2253. + return 0;
  2254. + }
  2255. + target = waiters ? waiters->target : getDelayTarget(6000000);
  2256. + halvm_release_lock(&waiters_lock);
  2257. +
  2258. + return target;
  2259. +#else
  2260. + return NULL;
  2261. +#endif
  2262. +}
  2263. +
  2264. +#ifdef THREADED_RTS
  2265. +void ioManagerDie(void)
  2266. +{
  2267. + if(waiters) {
  2268. + printf("WARNING: IO Manager is dying with people waiting to run.\n");
  2269. + }
  2270. +}
  2271. +
  2272. +void ioManagerStart(void)
  2273. +{
  2274. + Capability *cap;
  2275. +
  2276. + initMutex(&waiters_lock);
  2277. + cap = rts_lock();
  2278. + rts_evalIO(&cap, &base_GHCziConcziIO_ensureIOManagerIsRunning_closure, NULL);
  2279. + rts_unlock(cap);
  2280. +}
  2281. +#endif
  2282. diff --git a/rts/xen/locks.c b/rts/xen/locks.c
  2283. new file mode 100644
  2284. index 0000000..f750858
  2285. --- /dev/null
  2286. +++ b/rts/xen/locks.c
  2287. @@ -0,0 +1,139 @@
  2288. +#include <errno.h>
  2289. +#include "locks.h"
  2290. +#include "smp.h"
  2291. +#include "signals.h"
  2292. +#include "Rts.h"
  2293. +#include "sm/GC.h"
  2294. +#include "RtsSignals.h"
  2295. +#include "Task.h"
  2296. +#include <runtime_reqs.h>
  2297. +#include <assert.h>
  2298. +
  2299. +#define LOCK_FREE 0
  2300. +#define LOCK_TAKEN 1
  2301. +#define LOCK_CLOSED 0xbadbadFF
  2302. +
  2303. +int halvm_acquire_lock(halvm_mutex_t *mutex)
  2304. +{
  2305. + unsigned long count = 1;
  2306. +
  2307. + while(1) {
  2308. + switch(__sync_val_compare_and_swap(mutex, LOCK_FREE, LOCK_TAKEN)) {
  2309. + case LOCK_FREE:
  2310. + return 0;
  2311. + case LOCK_TAKEN:
  2312. + break;
  2313. + case LOCK_CLOSED:
  2314. + return EINVAL;
  2315. + default:
  2316. + printf("ERROR: Lock in weird state!\n");
  2317. + return EINVAL;
  2318. + }
  2319. +
  2320. + if(!(count && 0xFFF)) {
  2321. + runtime_block(0);
  2322. + }
  2323. + }
  2324. +}
  2325. +
  2326. +int halvm_try_acquire_lock(halvm_mutex_t *mutex)
  2327. +{
  2328. + switch(__sync_val_compare_and_swap(mutex, LOCK_FREE, LOCK_TAKEN)) {
  2329. + case LOCK_FREE:
  2330. + return 0;
  2331. + case LOCK_TAKEN:
  2332. + return EBUSY;
  2333. + case LOCK_CLOSED:
  2334. + return EINVAL;
  2335. + default:
  2336. + printf("ERROR: Lock in weird state (2)\n");
  2337. + return EINVAL;
  2338. + }
  2339. +}
  2340. +
  2341. +int halvm_release_lock(halvm_mutex_t *mutex)
  2342. +{
  2343. + switch(__sync_val_compare_and_swap(mutex, LOCK_TAKEN, LOCK_FREE)) {
  2344. + case LOCK_FREE:
  2345. + return EINVAL;
  2346. + case LOCK_TAKEN:
  2347. + return 0;
  2348. + case LOCK_CLOSED:
  2349. + return EINVAL;
  2350. + default:
  2351. + printf("ERROR: Lock in weird state (3)\n");
  2352. + return EINVAL;
  2353. + }
  2354. +}
  2355. +
  2356. +/* ************************************************************************* */
  2357. +
  2358. +void initMutex(halvm_mutex_t *mut)
  2359. +{
  2360. + *mut = LOCK_FREE;
  2361. +}
  2362. +
  2363. +void closeMutex(halvm_mutex_t *mut)
  2364. +{
  2365. + *mut = LOCK_CLOSED;
  2366. +}
  2367. +
  2368. +/* ************************************************************************* */
  2369. +
  2370. +/* ************************************************************************* */
  2371. +
  2372. +#ifdef THREADED_RTS
  2373. +/* the GHC RTS doesn't use the full power of conditional locks. instead, */
  2374. +/* it uses them as a handy way to go to sleep or get woken up when a task */
  2375. +/* runs out of things to do, while ensuring that a particular lock is held */
  2376. +/* when it wakes up. This means, for example, that there's always a maximum */
  2377. +/* of one person waiting on the lock, which in turn means we can greatly */
  2378. +/* simplify our implementation. */
  2379. +void initCondition(halvm_condlock_t *cond)
  2380. +{
  2381. + initMutex( &(cond->lock) );
  2382. + cond->waiter = 0;
  2383. + cond->state = CONDLOCK_EMPTY;
  2384. +}
  2385. +
  2386. +void closeCondition(halvm_condlock_t *cond)
  2387. +{
  2388. + closeMutex( &(cond->lock) );
  2389. +}
  2390. +
  2391. +
  2392. +rtsBool broadcastCondition(halvm_condlock_t *cond __attribute__((unused)))
  2393. +{
  2394. + return rtsTrue;
  2395. +}
  2396. +
  2397. +rtsBool signalCondition(halvm_condlock_t *cond)
  2398. +{
  2399. + halvm_acquire_lock( &(cond->lock) );
  2400. + if(cond->state == CONDLOCK_WAITING) {
  2401. + cond->state = CONDLOCK_SIGNALED;
  2402. + unlockThread(cond->waiter);
  2403. + cond->waiter = NULL;
  2404. + }
  2405. + halvm_release_lock( &(cond->lock) );
  2406. + return rtsTrue;
  2407. +}
  2408. +
  2409. +rtsBool waitCondition(halvm_condlock_t *cond, Mutex *mut)
  2410. +{
  2411. + halvm_acquire_lock( &(cond->lock) );
  2412. + halvm_release_lock( mut );
  2413. + assert(cond->state != CONDLOCK_WAITING);
  2414. + assert(cond->state != CONDLOCK_SIGNALED);
  2415. + cond->waiter = vcpu_cur_thread();
  2416. + cond->state = CONDLOCK_WAITING;
  2417. + lockCurrentThread( &(cond->lock) );
  2418. + assert(cond->state == CONDLOCK_SIGNALED);
  2419. + cond->state = CONDLOCK_EMPTY;
  2420. + halvm_release_lock( &(cond->lock) );
  2421. + halvm_acquire_lock(mut);
  2422. + return rtsTrue;
  2423. +}
  2424. +
  2425. +#endif
  2426. +
  2427. diff --git a/rts/xen/memory.c b/rts/xen/memory.c
  2428. new file mode 100644
  2429. index 0000000..5a6ec93
  2430. --- /dev/null
  2431. +++ b/rts/xen/memory.c
  2432. @@ -0,0 +1,548 @@
  2433. +#define __XEN__
  2434. +#include "Rts.h"
  2435. +#include "RtsUtils.h"
  2436. +#include "sm/OSMem.h"
  2437. +#include <runtime_reqs.h>
  2438. +#include <xen/xen.h>
  2439. +#include <xen/memory.h>
  2440. +#include "vmm.h"
  2441. +#include "memory.h"
  2442. +#include <assert.h>
  2443. +#include "hypercalls.h"
  2444. +#include <sys/mman.h>
  2445. +#include "locks.h"
  2446. +#include <errno.h>
  2447. +#include <string.h>
  2448. +
  2449. +#define PAGE_ALIGN(t1,t2,x) (t1)(((t2)x + (PAGE_SIZE-1)) & (~(PAGE_SIZE-1)))
  2450. +#define PAGE_ALIGNED(a) (0 == ((uintptr_t)a & (PAGE_SIZE - 1)))
  2451. +
  2452. +extern int _text;
  2453. +extern char _mem_start[];
  2454. +unsigned long cur_pages = 0;
  2455. +unsigned long max_pages = 0;
  2456. +
  2457. +
  2458. +/** Stats *********************************************************************/
  2459. +
  2460. +struct {
  2461. + int num_pg_allocs;
  2462. + int num_pg_frees;
  2463. + int num_mb_allocs;
  2464. + int num_mb_frees;
  2465. +} stats;
  2466. +
  2467. +static void dump_stats(void) {
  2468. + printf("GC Stats:\n");
  2469. + printf("\tnum_pg_allocs: %d\n", stats.num_pg_allocs);
  2470. + printf("\tnum_pg_frees: %d\n", stats.num_pg_frees);
  2471. + printf("\tnum_mb_allocs: %d\n", stats.num_mb_allocs);
  2472. + printf("\tnum_mb_frees: %d\n", stats.num_mb_frees);
  2473. +
  2474. + printf("\tmalloc heap: %dkb\n",
  2475. + (stats.num_pg_allocs - (stats.num_mb_allocs * 256)) * 4);
  2476. + printf("\tmblocks: %dkb\n", stats.num_mb_allocs * 256 * 4);
  2477. +
  2478. + return;
  2479. +}
  2480. +
  2481. +/******************************************************************************/
  2482. +
  2483. +mfn_t *p2m_map = NULL;
  2484. +
  2485. +void set_pframe_used(pfn_t pfn)
  2486. +{
  2487. + assert(pfn < cur_pages);
  2488. + assert(p2m_map);
  2489. + assert(p2m_map[pfn]);
  2490. + p2m_map[pfn] = p2m_map[pfn] | PFN_SET_BIT;
  2491. +}
  2492. +
  2493. +void set_pframe_unused(pfn_t pfn)
  2494. +{
  2495. + assert(pfn < cur_pages);
  2496. + assert(p2m_map);
  2497. + assert(p2m_map[pfn]);
  2498. + p2m_map[pfn] = p2m_map[pfn] & (~PFN_SET_BIT);
  2499. +}
  2500. +
  2501. +mfn_t get_free_frame()
  2502. +{
  2503. + unsigned long i;
  2504. +
  2505. + assert(p2m_map);
  2506. + for(i = 0; i < cur_pages; i++)
  2507. + if(!(p2m_map[i] & PFN_SET_BIT)) {
  2508. + mfn_t retval = p2m_map[i];
  2509. + p2m_map[i] = p2m_map[i] | PFN_SET_BIT;
  2510. + return retval;
  2511. + }
  2512. +
  2513. + return 0;
  2514. +}
  2515. +
  2516. +unsigned long used_frames(void)
  2517. +{
  2518. + unsigned long i, retval;
  2519. +
  2520. + for(i = 0, retval = 0; i < cur_pages; i++)
  2521. + if(p2m_map[i] & PFN_SET_BIT)
  2522. + retval += 1;
  2523. +
  2524. + return retval;
  2525. +}
  2526. +
  2527. +/******************************************************************************/
  2528. +
  2529. +static halvm_mutex_t memory_search_lock;
  2530. +
  2531. +unsigned long initialize_memory(start_info_t *start_info, void *init_sp)
  2532. +{
  2533. + domid_t self = DOMID_SELF;
  2534. + void *free_space_start, *init_alloc_end, *cur;
  2535. + uint32_t i, used_frames;
  2536. +
  2537. + /* gather some basic information about ourselves */
  2538. + p2m_map = (mfn_t*)start_info->mfn_list;
  2539. + max_pages = HYPERCALL_memory_op(XENMEM_maximum_reservation, &self);
  2540. + cur_pages = HYPERCALL_memory_op(XENMEM_current_reservation, &self);
  2541. +
  2542. + printf("init_sp: 0x%p\n", init_sp);
  2543. + printf("self: 0x%p\n", &self);
  2544. +
  2545. + /* sanity checks */
  2546. + assert(p2m_map);
  2547. + assert((long)cur_pages > 0);
  2548. + assert((long)max_pages > 0);
  2549. +
  2550. + /* basic setup */
  2551. + init_alloc_end = (void*)(((uintptr_t)init_sp + 0x3FFFFF) & (~0x3FFFFF));
  2552. + if( ((uintptr_t)init_alloc_end - (uintptr_t)init_sp) < (512 * 1024) ) {
  2553. + /* Xen guarantees at least 4MB alignment and 512kB padding after */
  2554. + /* the stack. So the above does the alignment, and this if does */
  2555. + /* the edge case. */
  2556. + init_alloc_end = (void*)((uintptr_t)init_alloc_end + (4 * 1024 * 1024));
  2557. + }
  2558. + used_frames = ((uintptr_t)init_alloc_end - (uintptr_t)&_text) >> PAGE_SHIFT;
  2559. + for(i = 0; i < used_frames; i++)
  2560. + set_pframe_used(i);
  2561. +
  2562. + free_space_start = initialize_vmm(start_info, init_sp);
  2563. + free_space_start = PAGE_ALIGN(void*,uintptr_t,free_space_start);
  2564. + i = ((uintptr_t)free_space_start - (uintptr_t)&_text) >> PAGE_SHIFT;
  2565. + for(cur = free_space_start;
  2566. + i < used_frames;
  2567. + i++, cur = (void*)((uintptr_t)cur + PAGE_SIZE)) {
  2568. + set_pframe_unused(i);
  2569. + set_pt_entry(cur, 0);
  2570. + }
  2571. +
  2572. + /* Finally, initialize the lock */
  2573. + initMutex(&memory_search_lock);
  2574. +
  2575. + return max_pages;
  2576. +}
  2577. +
  2578. +/******************************************************************************/
  2579. +
  2580. +static inline void *advance_page(void *p)
  2581. +{
  2582. + return CANONICALIZE((void*)((uintptr_t)DECANONICALIZE(p) + PAGE_SIZE));
  2583. +}
  2584. +
  2585. +/*
  2586. + * INVARIANTS:
  2587. + * * start is already aligned WRT align
  2588. + * * align is a multiple of PAGE_SIZE
  2589. + */
  2590. +static void *run_search_loop(void *start, size_t length, size_t align)
  2591. +{
  2592. + char *cur = start, *block_start = start, *retval = NULL;
  2593. + size_t needed_space = length;
  2594. +
  2595. + /* printf("searching from: 0x%x\n", start); */
  2596. +
  2597. + assert(NULL != start);
  2598. + while(needed_space > 0) {
  2599. + pte_t ent = get_pt_entry(cur);
  2600. +
  2601. + if(ENTRY_PRESENT(ent) || ENTRY_CLAIMED(ent)) {
  2602. + /* nevermind, we can't use anything we've found up until now */
  2603. + needed_space = length;
  2604. + retval = NULL;
  2605. +
  2606. + /* increment by the target address by the alignemnt required */
  2607. + block_start += align;
  2608. + cur = block_start;
  2609. +
  2610. + continue;
  2611. + }
  2612. +
  2613. + /* we can start or extend the current run */
  2614. + if(!retval) retval = cur;
  2615. + needed_space = needed_space - PAGE_SIZE;
  2616. +
  2617. + if(needed_space > 0) {
  2618. + cur = advance_page(cur);
  2619. +
  2620. + /* check for wraparound, which is bad */
  2621. + if( cur < retval ) {
  2622. + needed_space = length;
  2623. + retval = NULL;
  2624. + }
  2625. +
  2626. + /* if we're back where we started from, give up */
  2627. + if( cur == start )
  2628. + return NULL;
  2629. + }
  2630. + }
  2631. +
  2632. + /* printf("found: 0x%x\n", retval); */
  2633. +
  2634. + return retval;
  2635. +}
  2636. +
  2637. +static inline void *find_new_addr(void *start_in, size_t length)
  2638. +{
  2639. + static void *glob_search_hint = (void*)_mem_start;
  2640. + void *p = PAGE_ALIGN(void*,uintptr_t,start_in);
  2641. +
  2642. + /* and if they didn't give us any info (or it's junk, see above), */
  2643. + /* let's use a reasonable hint about where to start our search. */
  2644. + if(!p) p = glob_search_hint;
  2645. + p = run_search_loop(p, length, PAGE_SIZE);
  2646. + glob_search_hint = PAGE_ALIGN(void*,uintptr_t,((uintptr_t)p + length));
  2647. + return p;
  2648. +}
  2649. +
  2650. +static void *internal_alloc(void *, size_t, int);
  2651. +
  2652. +void *runtime_alloc(void *dest_in, size_t length_in, int prot)
  2653. +{
  2654. + size_t length = PAGE_ALIGN(size_t, size_t, length_in);
  2655. + void * dest = NULL;
  2656. +
  2657. + assert(dest = find_new_addr(dest_in, length));
  2658. +
  2659. + return internal_alloc(dest, length, prot);
  2660. +}
  2661. +
  2662. +/* Always allocate with a destination address already found, an amount that is
  2663. + * already page aligned.
  2664. + */
  2665. +static void *internal_alloc(void *dest, size_t length, int prot)
  2666. +{
  2667. + void *cur, *end;
  2668. +
  2669. + assert(PAGE_ALIGNED(dest));
  2670. + assert(PAGE_ALIGNED(length));
  2671. +
  2672. + halvm_acquire_lock(&memory_search_lock);
  2673. +
  2674. + cur = dest;
  2675. + end = (void*)((uintptr_t)dest + length);
  2676. + while( (uintptr_t)cur < (uintptr_t)end ) {
  2677. + pte_t entry = ((pte_t)get_free_frame()) << PAGE_SHIFT;
  2678. +
  2679. + if(!entry) {
  2680. + /* ACK! We're out of memory */
  2681. + cur = dest;
  2682. + end = cur;
  2683. +
  2684. + /* Free anything we've allocated for this request */
  2685. + while( (uintptr_t)cur < (uintptr_t)end ) {
  2686. + pte_t entry = get_pt_entry(cur);
  2687. + set_pframe_unused(entry >> PAGE_SHIFT);
  2688. + set_pt_entry(cur, 0);
  2689. + }
  2690. +
  2691. + /* and return failure */
  2692. + halvm_release_lock(&memory_search_lock);
  2693. + return NULL;
  2694. + } else {
  2695. + entry = entry | PG_PRESENT | PG_USER;
  2696. + if(prot & PROT_WRITE)
  2697. + entry = entry | PG_READWRITE;
  2698. + set_pt_entry(cur, entry);
  2699. + }
  2700. +
  2701. + ++stats.num_pg_allocs;
  2702. + cur = advance_page(cur);
  2703. + }
  2704. +
  2705. + /* done! */
  2706. + halvm_release_lock(&memory_search_lock);
  2707. + memset(dest, 0, length);
  2708. + return dest;
  2709. +}
  2710. +
  2711. +void *map_frames(mfn_t *frames, size_t num_frames)
  2712. +{
  2713. + void *dest;
  2714. + size_t i;
  2715. +
  2716. + halvm_acquire_lock(&memory_search_lock);
  2717. + assert(dest = find_new_addr(NULL, num_frames * PAGE_SIZE));
  2718. + for(i = 0; i < num_frames; i++)
  2719. + set_pt_entry((void*)((uintptr_t)dest + (i * PAGE_SIZE)),
  2720. + ((pte_t)frames[i] << PAGE_SHIFT) | STANDARD_RW_PERMS);
  2721. + halvm_release_lock(&memory_search_lock);
  2722. + return dest;
  2723. +}
  2724. +
  2725. +long pin_frame(int level, mfn_t mfn, domid_t dom)
  2726. +{
  2727. + mmuext_op_t op;
  2728. +
  2729. + switch(level) {
  2730. + case 1: op.cmd = MMUEXT_PIN_L1_TABLE; break;
  2731. + case 2: op.cmd = MMUEXT_PIN_L2_TABLE; break;
  2732. + case 3: op.cmd = MMUEXT_PIN_L3_TABLE; break;
  2733. + case 4: op.cmd = MMUEXT_PIN_L4_TABLE; break;
  2734. + default:
  2735. + return -EINVAL;
  2736. + }
  2737. + op.arg1.mfn = mfn;
  2738. +
  2739. + return HYPERCALL_mmuext_op(&op, 1, NULL, dom);
  2740. +}
  2741. +
  2742. +void *runtime_realloc(void *start, int can_move, size_t oldlen, size_t newlen)
  2743. +{
  2744. + void *retval, *oldcur, *oldend, *newcur, *newend;
  2745. + pte_t page_flags, ent;
  2746. +
  2747. + if(!start)
  2748. + return NULL;
  2749. +
  2750. + /* special case, when we're shrinking */
  2751. + if(newlen < oldlen) {
  2752. + runtime_free((void*)((uintptr_t)start + newlen), oldlen - newlen);
  2753. + return start;
  2754. + }
  2755. +
  2756. + /* weird case, when things are equal */
  2757. + if(newlen == oldlen)
  2758. + return start;
  2759. +
  2760. + /* get the flags that this entry uses */
  2761. + page_flags = get_pt_entry(start);
  2762. + page_flags = page_flags & (PAGE_SIZE-1);
  2763. + if( !ENTRY_PRESENT(page_flags) && !ENTRY_CLAIMED(page_flags) )
  2764. + return NULL;
  2765. +
  2766. + /* find where to put the new stuff */
  2767. + halvm_acquire_lock(&memory_search_lock);
  2768. + oldend = (void*)((uintptr_t)start + oldlen);
  2769. + newend = (void*)((uintptr_t)start + newlen);
  2770. + while(oldend < newend) {
  2771. + ent = get_pt_entry(oldend);
  2772. + if( ENTRY_CLAIMED(ent) || ENTRY_PRESENT(ent) )
  2773. + break;
  2774. + oldend = (void*)((uintptr_t)oldend + PAGE_SIZE);
  2775. + }
  2776. +
  2777. + if(oldend >= newend) {
  2778. + /* in this case, we have sufficient room to map the new stuff at the end */
  2779. + oldend = (void*)((uintptr_t)start + oldlen);
  2780. + while(oldend < newend)
  2781. + set_pt_entry(oldend, (get_free_frame() << PAGE_SHIFT) | page_flags);
  2782. + return start;
  2783. + }
  2784. +
  2785. + /* there isn't room at the end. can we move the pointer? */
  2786. + if(!can_move) {
  2787. + printf("WARNING: Can't realloc without moving, and !can_move\n");
  2788. + halvm_release_lock(&memory_search_lock);
  2789. + return NULL;
  2790. + }
  2791. +
  2792. + /* we can, so we need to find a place to put it */
  2793. + retval = find_new_addr(start, newlen);
  2794. + if(!retval) {
  2795. + halvm_release_lock(&memory_search_lock);
  2796. + printf("WARNING: No room for mremap()!\n");
  2797. + return NULL;
  2798. + }
  2799. +
  2800. + /* shift the pages over */
  2801. + oldcur = start; oldend = (void*)((uintptr_t)oldcur + oldlen);
  2802. + newcur = retval; newend = (void*)((uintptr_t)newcur + newlen);
  2803. + while(newcur < newend) {
  2804. + if(oldcur < oldend) {
  2805. + ent = get_pt_entry(oldcur);
  2806. + set_pt_entry(oldcur, 0);
  2807. + set_pt_entry(newcur, ENTRY_MADDR(ent) | page_flags);
  2808. + } else {
  2809. + ent = get_free_frame();
  2810. + if(!ent) {
  2811. + halvm_release_lock(&memory_search_lock);
  2812. + printf("WARNING: Ran out of free frames in mremap()\n");
  2813. + return NULL;
  2814. + }
  2815. + set_pt_entry(newcur, (ent << PAGE_SHIFT) | page_flags);
  2816. + }
  2817. + oldcur = (void*)((uintptr_t)oldcur + PAGE_SIZE);
  2818. + newcur = (void*)((uintptr_t)newcur + PAGE_SIZE);
  2819. + }
  2820. + halvm_release_lock(&memory_search_lock);
  2821. +
  2822. + return retval;
  2823. +}
  2824. +
  2825. +void *claim_shared_space(size_t amt)
  2826. +{
  2827. + void *retval;
  2828. + size_t i;
  2829. +
  2830. + halvm_acquire_lock(&memory_search_lock);
  2831. + amt = (amt + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
  2832. + retval = find_new_addr(NULL, amt);
  2833. + for(i = 0; i < (amt / PAGE_SIZE); i++)
  2834. + set_pt_entry((void*)((uintptr_t)retval + (i * PAGE_SIZE)), PG_CLAIMED);
  2835. + halvm_release_lock(&memory_search_lock);
  2836. + return retval;
  2837. +}
  2838. +
  2839. +void runtime_free(void *start, size_t length)
  2840. +{
  2841. + void *end = (void*)((uintptr_t)start + length);
  2842. +
  2843. + halvm_acquire_lock(&memory_search_lock);
  2844. + while(start < end) {
  2845. + pte_t pte = get_pt_entry(start);
  2846. +
  2847. + if(ENTRY_PRESENT(pte)) {
  2848. + mfn_t mfn = pte >> PAGE_SHIFT;
  2849. + pfn_t pfn = machine_to_phys_mapping[mfn];
  2850. + if(pfn) set_pframe_unused(pfn);
  2851. + }
  2852. + set_pt_entry(start, 0);
  2853. + start = (void*)((uintptr_t)start + PAGE_SIZE);
  2854. +
  2855. + ++stats.num_pg_frees;
  2856. + }
  2857. + halvm_release_lock(&memory_search_lock);
  2858. +}
  2859. +
  2860. +int runtime_memprotect(void *addr, size_t length, int prot)
  2861. +{
  2862. + printf("runtime_memprotect(%p, %d, %d)\n", addr, length, prot);
  2863. + return 0; // FIXME
  2864. +}
  2865. +
  2866. +int runtime_pagesize()
  2867. +{
  2868. + return PAGE_SIZE;
  2869. +}
  2870. +
  2871. +/******************************************************************************/
  2872. +
  2873. +W_ getPageFaults(void);
  2874. +
  2875. +W_ getPageSize(void)
  2876. +{
  2877. + return runtime_pagesize();
  2878. +}
  2879. +
  2880. +W_ getPageFaults(void)
  2881. +{
  2882. + return 0;
  2883. +}
  2884. +
  2885. +static char * next_request = HASKELL_HEAP_START;
  2886. +
  2887. +void *osGetMBlocks(nat n)
  2888. +{
  2889. + char * allocp = NULL;
  2890. + int len = n * MBLOCK_SIZE;
  2891. + char * addr = run_search_loop(next_request, len, MBLOCK_SIZE);
  2892. +
  2893. + allocp = internal_alloc(addr, len, PROT_READWRITE);
  2894. + if(NULL == allocp) {
  2895. + printf("WARNING: Out of memory. The GHC RTS is about to go nuts.\n");
  2896. + dump_stats();
  2897. + return NULL;
  2898. + }
  2899. +
  2900. + next_request = allocp + len;
  2901. +
  2902. + stats.num_mb_allocs += n;
  2903. +
  2904. + /* printf("osGetMBlocks: %d -> 0x%x\n", n, allocp); */
  2905. +
  2906. + return allocp;
  2907. +}
  2908. +
  2909. +void osFreeAllMBlocks(void)
  2910. +{
  2911. + /* ignore this */
  2912. +}
  2913. +
  2914. +void osMemInit(void)
  2915. +{
  2916. + /* ignore this */
  2917. +}
  2918. +
  2919. +void osFreeMBlocks(char *addr, nat n)
  2920. +{
  2921. + /* printf("osFreeMBlocks: 0x%x + %d\n", addr, n); */
  2922. + runtime_free(addr, n * MBLOCK_SIZE);
  2923. +
  2924. + /* next time, start allocation from this block */
  2925. + next_request = addr;
  2926. +
  2927. + stats.num_mb_frees += n;
  2928. +}
  2929. +
  2930. +void osReleaseFreeMemory(void)
  2931. +{
  2932. + /* ignore this */
  2933. +}
  2934. +
  2935. +void setExecutable(void *p, W_ len, rtsBool exec)
  2936. +{
  2937. + void *end = (void*)((uintptr_t)p + len);
  2938. +
  2939. + printf("setExecutable(%p, %d, %d)\n", p, len, exec);
  2940. + while((uintptr_t)p < (uintptr_t)end) {
  2941. + pte_t entry = get_pt_entry(p);
  2942. +
  2943. + if(entry & PG_PRESENT)
  2944. + set_pt_entry(p, entry & PG_EXECUTABLE);
  2945. + p = (void*)((uintptr_t)p + 4096);
  2946. + }
  2947. +}
  2948. +
  2949. +StgWord64 getPhysicalMemorySize(void)
  2950. +{
  2951. + return (max_pages * PAGE_SIZE);
  2952. +}
  2953. +
  2954. +void system_wmb()
  2955. +{
  2956. +#ifdef __x86_64__
  2957. + asm volatile ("sfence" : : : "memory");
  2958. +#else
  2959. + asm volatile ("" : : : "memory");
  2960. +#endif
  2961. +}
  2962. +
  2963. +void system_rmb()
  2964. +{
  2965. +#ifdef __x86_64__
  2966. + asm volatile ("lfence" : : : "memory");
  2967. +#else
  2968. + asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory");
  2969. +#endif
  2970. +}
  2971. +
  2972. +void system_mb()
  2973. +{
  2974. +#ifdef __x86_64__
  2975. + asm volatile ("mfence" : : : "memory");
  2976. +#else
  2977. + asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory");
  2978. +#endif
  2979. +}
  2980. +
  2981. diff --git a/rts/xen/profiling.c b/rts/xen/profiling.c
  2982. new file mode 100644
  2983. index 0000000..fecd50d
  2984. --- /dev/null
  2985. +++ b/rts/xen/profiling.c
  2986. @@ -0,0 +1,519 @@
  2987. +#ifdef PROFILING
  2988. +#include <runtime_reqs.h>
  2989. +#include <errno.h>
  2990. +#include <stdio.h>
  2991. +#include <stdint.h>
  2992. +#include <string.h>
  2993. +#include <sys/mman.h>
  2994. +#include <assert.h>
  2995. +#define XEN_HAVE_PV_GUEST_ENTRY 1
  2996. +#include <xen/xen.h>
  2997. +#include <xen/io/xenbus.h>
  2998. +#include <xen/io/xs_wire.h>
  2999. +#include <xen/io/blkif.h>
  3000. +#include <signals.h>
  3001. +#include <grants.h>
  3002. +#include <memory.h>
  3003. +#include <vmm.h>
  3004. +
  3005. +#ifdef __x86_64__
  3006. +#define wmb() asm volatile ("sfence" : : : "memory")
  3007. +#define rmb() asm volatile ("lfence" : : : "memory")
  3008. +#define mb() asm volatile ("mfence" : : : "memory")
  3009. +#else
  3010. +#define wmb() asm volatile ("" : : : "memory")
  3011. +#define rmb() asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory")
  3012. +#define mb() asm volatile ("lock; addl $0, 0(%%esp)" : : : "memory")
  3013. +#endif
  3014. +
  3015. +struct FILE {
  3016. + size_t fsize;
  3017. + size_t cur_block_num;
  3018. + size_t cur_block_off;
  3019. + grant_ref_t ring_grant, block_grant;
  3020. + uint32_t chan;
  3021. + char *block;
  3022. + blkif_vdev_t disk_handle;
  3023. + blkif_front_ring_t ring;
  3024. +};
  3025. +
  3026. +struct xenStorePaths {
  3027. + char *feDir;
  3028. + char *beDir;
  3029. +};
  3030. +typedef struct xenStorePaths XenStorePaths;
  3031. +
  3032. +extern struct start_info *system_start_info;
  3033. +static struct xenstore_domain_interface *xsint = NULL;
  3034. +
  3035. +static int push_out_block(FILE *p, int closed);
  3036. +static int write_block(FILE *p, blkif_sector_t, size_t);
  3037. +static XenStorePaths *find_xs_paths(char *, char *, uint32_t);
  3038. +
  3039. +static char *xenstore_getkey(char *);
  3040. +static long xenstore_setkey(char *, char *, size_t);
  3041. +static uint32_t xenstore_write(uint32_t, uint32_t, void *);
  3042. +static uint32_t xenstore_read(uint32_t, uint32_t *, void **);
  3043. +
  3044. +#define min(a,b) ((a) < (b) ? (a) : (b))
  3045. +
  3046. +static void handler(int x __attribute__((unused))) { }
  3047. +
  3048. +FILE *profile_fopen(const char *fname, const char *mode)
  3049. +{
  3050. + char *key = NULL, *val = NULL, *rsp = NULL, *domStr = NULL, *diskname = NULL;
  3051. + uint32_t req, rsptype, rsplen, domId;
  3052. + XenStorePaths *xsp = NULL;
  3053. + uint64_t store_mptr;
  3054. + FILE *retval = NULL;
  3055. + int vallen;
  3056. + long res;
  3057. +
  3058. + if(strncmp(mode, "w", 1) != 0)
  3059. + goto fail;
  3060. +
  3061. + if(strncmp(fname, "HaLVM.prof", 11) == 0)
  3062. + diskname = "xvdp1";
  3063. + if(strncmp(fname, "HaLVM.hp", 9) == 0)
  3064. + diskname = "xvdp2";
  3065. + if(!diskname)
  3066. + goto fail;
  3067. +
  3068. + store_mptr = (uint64_t)system_start_info->store_mfn << 12;
  3069. + unmask_channel(system_start_info->store_evtchn);
  3070. + xsint = (struct xenstore_domain_interface*)machine_to_virtual(store_mptr);
  3071. + if(!xsint) {
  3072. + printf("PROFILING ERROR: Could not map XenStore page.\n");
  3073. + goto fail;
  3074. + }
  3075. +
  3076. + /* Try to run "ls devices/vbd" */
  3077. + req = xenstore_write(XS_DIRECTORY, strlen("device/vbd") + 1, "device/vbd");
  3078. + rsplen = xenstore_read(req, &rsptype, (void**)&rsp);
  3079. + if(rsptype == XS_ERROR) {
  3080. + printf("PROFILING: XenStore read error. Did you forget to add a disk?\n");
  3081. + goto fail;
  3082. + }
  3083. + if(rsptype != XS_DIRECTORY) {
  3084. + printf("PROFILING: XenStore has gone weird. Giving up.\n");
  3085. + goto fail;
  3086. + }
  3087. +
  3088. + /* Find the XenStore paths associated with the disk we want */
  3089. + xsp = find_xs_paths(diskname, rsp, rsplen);
  3090. + if(!xsp) {
  3091. + printf("PROFILING: Couldn't find file to open.\n");
  3092. + goto fail;
  3093. + }
  3094. +
  3095. + /* Pull out the other's domId */
  3096. + key = malloc(256);
  3097. + snprintf(key, 256, "%s/backend-id", xsp->feDir);
  3098. + domStr = xenstore_getkey(key);
  3099. + domId = atoi(domStr);
  3100. +
  3101. + /* allocate the return structure and buffers */
  3102. + retval = malloc(sizeof(FILE));
  3103. + if(!retval)
  3104. + goto fail;
  3105. + memset(retval, 0, sizeof(FILE));
  3106. + retval->cur_block_num = 1;
  3107. + retval->block = runtime_alloc(NULL, 4096, PROT_READ|PROT_WRITE);
  3108. + if(!retval->block)
  3109. + goto fail;
  3110. + assert( (((uintptr_t)retval->block) & 4095) == 0 );
  3111. + retval->ring.sring = runtime_alloc(NULL, 4096, PROT_READ|PROT_WRITE);
  3112. + if(!retval->ring.sring)
  3113. + goto fail;
  3114. + assert( (((uintptr_t)retval->ring.sring) & 4095) == 0 );
  3115. + SHARED_RING_INIT(retval->ring.sring);
  3116. + FRONT_RING_INIT(&(retval->ring), retval->ring.sring, 4096);
  3117. +
  3118. + /* get the device handle */
  3119. + snprintf(key, 256, "%s/virtual-device", xsp->feDir);
  3120. + val = xenstore_getkey(key);
  3121. + retval->disk_handle = atoi(val);
  3122. +
  3123. + /* allocate the grant references and event channel */
  3124. + res = alloc_grant(domId, retval->ring.sring, 4096, 0, &retval->ring_grant);
  3125. + if(res) {
  3126. + printf("PROFILING: Failed to allocate ring grant reference: %d\n", res);
  3127. + goto fail;
  3128. + }
  3129. + res = alloc_grant(domId, retval->block, 4096, 0, &retval->block_grant);
  3130. + if(res) {
  3131. + printf("PROFILING: Failed to allocate block grant reference: %d\n", res);
  3132. + goto fail;
  3133. + }
  3134. + res = channel_alloc(DOMID_SELF, domId);
  3135. + if(res < 0) {
  3136. + printf("PROFILING: Failed to allocate grant reference: %d\n", res);
  3137. + goto fail;
  3138. + }
  3139. + retval->chan = (uint32_t)res;
  3140. + set_c_handler(retval->chan, handler);
  3141. +
  3142. + /* write them into our tree */
  3143. + val = malloc(256);
  3144. + /* */ snprintf(key, 256, "%s/ring-ref", xsp->feDir);
  3145. + vallen = snprintf(val, 256, "%d", retval->ring_grant);
  3146. + if(!xenstore_setkey(key, val, vallen)) goto fail;
  3147. + /* */ snprintf(key, 256, "%s/event-channel", xsp->feDir);
  3148. + vallen = snprintf(val, 256, "%d", retval->chan);
  3149. + if(!xenstore_setkey(key, val, vallen)) goto fail;
  3150. + /* */ snprintf(key, 256, "%s/state", xsp->feDir);
  3151. + vallen = snprintf(val, 256, "%d", XenbusStateInitialised);
  3152. + if(!xenstore_setkey(key, val, vallen)) goto fail;
  3153. +
  3154. + /* wait for the other side to sync up */
  3155. + do {
  3156. + char *state;
  3157. +
  3158. + runtime_block(1);
  3159. + snprintf(key, 256, "%s/state", xsp->beDir);
  3160. + state = xenstore_getkey(key);
  3161. + res = atoi(state);
  3162. + free(state);
  3163. + } while(res != XenbusStateConnected);
  3164. +
  3165. + /* write out that we're good */
  3166. + /* */ snprintf(key, 256, "%s/state", xsp->feDir);
  3167. + vallen = snprintf(val, 256, "%d", XenbusStateConnected);
  3168. + if(!xenstore_setkey(key, val, vallen)) goto fail;
  3169. +
  3170. + return retval;
  3171. +
  3172. +fail:
  3173. + if(key) free(key);
  3174. + if(val) free(val);
  3175. + if(rsp) free(rsp);
  3176. + if(xsp) {
  3177. + free(xsp->feDir);
  3178. + free(xsp->beDir);
  3179. + free(xsp);
  3180. + }
  3181. + if(domStr) free(domStr);
  3182. + if(retval) {
  3183. + if(retval->block_grant) end_grant(retval->block_grant);
  3184. + if(retval->ring_grant) end_grant(retval->ring_grant);
  3185. + if(retval->block) runtime_free(retval->block, 4096);
  3186. + if(retval->ring.sring) runtime_free(retval->ring.sring, 4096);
  3187. + if(retval->chan) channel_close(retval->chan);
  3188. + free(retval);
  3189. + }
  3190. + errno = -EACCES;
  3191. + return NULL;
  3192. +}
  3193. +
  3194. +void profile_write(FILE *p, void *buf, int amt)
  3195. +{
  3196. + while(p->cur_block_off + amt > 4096) {
  3197. + int amt1 = 4096 - p->cur_block_off;
  3198. + memcpy(p->block + p->cur_block_off, buf, amt1);
  3199. + p->fsize += amt1;
  3200. + p->cur_block_off = 4096;
  3201. + push_out_block(p, 0);
  3202. +
  3203. + buf = (void*)((uintptr_t)buf + amt1);
  3204. + amt = amt - amt1;
  3205. + }
  3206. +
  3207. + memcpy(p->block + p->cur_block_off, buf, amt);
  3208. + p->fsize += amt;
  3209. + p->cur_block_off += amt;
  3210. +
  3211. + if(p->cur_block_off == 4096)
  3212. + push_out_block(p, 0);
  3213. +}
  3214. +
  3215. +void profile_flush(FILE *p)
  3216. +{
  3217. + if(p->cur_block_off) {
  3218. + void *copy = malloc(p->cur_block_off);
  3219. + size_t copy_size = p->cur_block_off;
  3220. + size_t skip_amt, i;
  3221. +
  3222. + memcpy(copy, p->block, p->cur_block_off);
  3223. + write_block(p, p->cur_block_num, p->cur_block_off);
  3224. + for(i = 0; i < 512 / sizeof(size_t); i += 2) {
  3225. + ((size_t*)p->block)[i+0] = p->fsize ^ i;
  3226. + ((size_t*)p->block)[i+1] = 0 ^ i;
  3227. + }
  3228. + write_block(p, 0, 512);
  3229. + skip_amt = (copy_size / 512) * 512;
  3230. + p->cur_block_num += copy_size / 512;
  3231. + p->cur_block_off = copy_size % 512;
  3232. + memcpy(p->block, (void*)((uintptr_t)copy + skip_amt), p->cur_block_off);
  3233. + free(copy);
  3234. + }
  3235. +}
  3236. +
  3237. +void profile_fclose(FILE *p)
  3238. +{
  3239. + push_out_block(p, 1);
  3240. +}
  3241. +
  3242. +/******************************************************************************
  3243. + ******************************************************************************/
  3244. +
  3245. +/* WARNING WARNING WARNING: This overwrites the data in FILE->block */
  3246. +static int push_out_block(FILE *p, int closed)
  3247. +{
  3248. + size_t i;
  3249. + int res;
  3250. +
  3251. + assert( (p->cur_block_off % 512 == 0) || closed );
  3252. + /* write out the block, if there's any data */
  3253. + if(p->cur_block_off) {
  3254. + res = write_block(p, p->cur_block_num, p->cur_block_off);
  3255. + if(!res) return 0;
  3256. + }
  3257. + /* write out the new header */
  3258. + for(i = 0; i < 512 / sizeof(size_t); i += 2) {
  3259. + ((size_t*)p->block)[i+0] = p->fsize ^ i;
  3260. + ((size_t*)p->block)[i+1] = closed ^ i;
  3261. + }
  3262. + res = write_block(p, 0, 512);
  3263. + if(!res) return 0;
  3264. + /* reinitialize the state */
  3265. + memset(p->block, 0, 4096);
  3266. + p->cur_block_num += p->cur_block_off / 512;
  3267. + p->cur_block_off = 0;
  3268. +
  3269. + return 1;
  3270. +}
  3271. +
  3272. +static int write_block(FILE *p, blkif_sector_t sector, size_t amt)
  3273. +{
  3274. + static uint64_t next_reqid = 1;
  3275. + blkif_response_t *rsp;
  3276. + blkif_request_t *req;
  3277. + int notify, work_to_do;
  3278. + uint64_t reqid;
  3279. + RING_IDX i;
  3280. +
  3281. + /* wait until we can write something */
  3282. + while(RING_FULL(&p->ring)) runtime_block(1);
  3283. +
  3284. + /* write out the request */
  3285. + i = p->ring.req_prod_pvt++;
  3286. + req = RING_GET_REQUEST(&p->ring, i);
  3287. + memset(req, 0, sizeof(blkif_request_t));
  3288. + req->operation = BLKIF_OP_WRITE;
  3289. + req->nr_segments = 1;
  3290. + req->handle = p->disk_handle;
  3291. + req->id = reqid = next_reqid++;
  3292. + req->sector_number = sector;
  3293. + req->seg[0].gref = p->block_grant;
  3294. + req->seg[0].first_sect = 0;
  3295. + req->seg[0].last_sect = (amt - 1) / 512;
  3296. + wmb();
  3297. + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&p->ring, notify);
  3298. + if(notify) channel_send(p->chan);
  3299. +
  3300. + /* wait for it to be satisfied */
  3301. + do {
  3302. + while(!RING_HAS_UNCONSUMED_RESPONSES(&p->ring))
  3303. + runtime_block(1);
  3304. + i = p->ring.rsp_cons++;
  3305. + rsp = RING_GET_RESPONSE(&p->ring, i);
  3306. + } while(rsp->id != reqid);
  3307. +
  3308. + /* was it successful? */
  3309. + if(rsp->status != BLKIF_RSP_OKAY) {
  3310. + printf("PROFILING: Block write failed!\n");
  3311. + return 0;
  3312. + }
  3313. +
  3314. + /* we do writes one at a time, synchronously, so work_to_do should always
  3315. + be false */
  3316. + RING_FINAL_CHECK_FOR_RESPONSES(&p->ring, work_to_do);
  3317. + assert(!work_to_do);
  3318. +
  3319. + return 1;
  3320. +}
  3321. +
  3322. +static XenStorePaths *find_xs_paths(char *fname, char *dir, uint32_t dirlen)
  3323. +{
  3324. + uint32_t i;
  3325. + char *cur;
  3326. +
  3327. + /* parse the responses, trying to find one with the name 'HaLVM.prof' */
  3328. + for(i = dirlen, cur = dir; i > 0; ) {
  3329. + char *key = malloc(256), *backend, *dev;
  3330. +
  3331. + /* get the backend key */
  3332. + snprintf(key, 256, "device/vbd/%s/backend", cur);
  3333. + backend = xenstore_getkey(key);
  3334. + if(!backend) continue;
  3335. +
  3336. + /* get the device name */
  3337. + snprintf(key, 256, "%s/dev", backend);
  3338. + dev = xenstore_getkey(key);
  3339. + if(!dev) continue;
  3340. +
  3341. + /* is this what we're looking for */
  3342. + if(strncmp(fname, dev, strlen(fname)) == 0) {
  3343. + XenStorePaths *out = malloc(sizeof(XenStorePaths));
  3344. +
  3345. + out->feDir = malloc(256);
  3346. + snprintf(out->feDir, 256, "device/vbd/%s", cur);
  3347. + out->beDir = backend;
  3348. +
  3349. + free(key);
  3350. + free(dev);
  3351. +
  3352. + return out;
  3353. + }
  3354. +
  3355. + /* advance to the next word */
  3356. + while( (i > 0) && (cur[0] != 0) ) { i -= 1; cur += 1; }
  3357. + if(i > 0) { i -= 1; cur += 1; }
  3358. + }
  3359. +
  3360. + return NULL;
  3361. +}
  3362. +
  3363. +/******************************************************************************
  3364. + ******************************************************************************/
  3365. +
  3366. +static char *xenstore_getkey(char *key)
  3367. +{
  3368. + uint32_t req_id, type, len;
  3369. + char *res, *buffer;
  3370. +
  3371. + req_id = xenstore_write(XS_READ, strlen(key) + 1, key);
  3372. + len = xenstore_read(req_id, &type, (void**)&buffer);
  3373. + if(type == XS_ERROR) {
  3374. + printf("PROFILING: Error reading key |%s|: %s\n", key, buffer);
  3375. + free(buffer);
  3376. + return NULL;
  3377. + }
  3378. + if(type != XS_READ) {
  3379. + printf("PROFILING: Error reading key |%s|: %d\n", key, type);
  3380. + free(buffer);
  3381. + return NULL;
  3382. + }
  3383. +
  3384. + /* the Xenstore doesn't send back 0-terminated values on reads, so
  3385. + make our result zero terminated */
  3386. + res = malloc(len + 1);
  3387. + memcpy(res, buffer, len);
  3388. + res[len] = 0;
  3389. + free(buffer);
  3390. +
  3391. + return res;
  3392. +}
  3393. +
  3394. +static long xenstore_setkey(char *key, char *val, size_t val_len)
  3395. +{
  3396. + uint32_t req_id, key_len, res, type;
  3397. + char *outbuf, *resbuf;
  3398. +
  3399. + /* convert our inputs into KEY0VAL */
  3400. + key_len = strlen(key);
  3401. + outbuf = malloc(key_len + 1 + val_len);
  3402. + memcpy(outbuf, key, key_len);
  3403. + memcpy(outbuf + key_len + 1, val, val_len);
  3404. + outbuf[key_len] = 0;
  3405. +
  3406. + req_id = xenstore_write(XS_WRITE, key_len + 1 + val_len, outbuf);
  3407. + res = xenstore_read(req_id, &type, (void**)&resbuf);
  3408. + if(type == XS_ERROR) {
  3409. + printf("PROFILING: Error writing key |%s|: %s\n", key, resbuf);
  3410. + res = 0;
  3411. + } else if(type != XS_WRITE) {
  3412. + printf("PROFILING: Error writing key |%s|: %d\n", key, type);
  3413. + res = 0;
  3414. + } else res = 1;
  3415. +
  3416. + free(outbuf);
  3417. + free(resbuf);
  3418. +
  3419. + return res;
  3420. +}
  3421. +
  3422. +static uint32_t xenstore_write(uint32_t type, uint32_t len, void *inbuf)
  3423. +{
  3424. + static uint32_t req_id = 1;
  3425. + struct xsd_sockmsg m;
  3426. + void *buffer, *cur;
  3427. + uint32_t prod;
  3428. +
  3429. + /* build out the header and adjust the final length */
  3430. + m.type = type;
  3431. + m.req_id = req_id++;
  3432. + m.tx_id = 0;
  3433. + m.len = len;
  3434. + len += sizeof(struct xsd_sockmsg);
  3435. +
  3436. + /* wait until we can send out the data all at once */
  3437. + while( (XENSTORE_RING_SIZE - (xsint->req_prod - xsint->req_cons)) < len )
  3438. + runtime_block(1);
  3439. + assert( (xsint->req_prod + len - xsint->req_cons) < XENSTORE_RING_SIZE);
  3440. +
  3441. + /* Combine the data into one block */
  3442. + cur = buffer = malloc(len);
  3443. + memcpy(buffer, &m, sizeof(struct xsd_sockmsg));
  3444. + memcpy((void*)((uintptr_t)buffer + sizeof(struct xsd_sockmsg)), inbuf, m.len);
  3445. +
  3446. + /* dump it out to the ring */
  3447. + prod = xsint->req_prod;
  3448. + while(len != 0) {
  3449. + uint32_t nextbit = min(len, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
  3450. + memcpy(xsint->req + MASK_XENSTORE_IDX(prod), cur, nextbit);
  3451. + prod += nextbit;
  3452. + cur = (void*)((uintptr_t)cur + nextbit);
  3453. + len -= nextbit;
  3454. + }
  3455. +
  3456. + /* notify the other size */
  3457. + wmb();
  3458. + xsint->req_prod = prod;
  3459. + channel_send(system_start_info->store_evtchn);
  3460. +
  3461. + /* free our buffer and return the request id */
  3462. + free(buffer);
  3463. + return m.req_id;
  3464. +}
  3465. +
  3466. +static uint32_t xenstore_read(uint32_t req_id, uint32_t *rtype, void **buffer)
  3467. +{
  3468. + struct xsd_sockmsg m;
  3469. + char *mbuf;
  3470. + uint32_t cons, i;
  3471. +
  3472. + *buffer = NULL; /* safety */
  3473. + *rtype = 0xDEADBEEF;
  3474. +again:
  3475. + /* wait until there's some data available */
  3476. + while( (xsint->rsp_prod - xsint->rsp_cons) < sizeof(struct xsd_sockmsg) )
  3477. + runtime_block(1);
  3478. +
  3479. + /* copy off the header */
  3480. + cons = xsint->rsp_cons;
  3481. + for(i = 0; i < sizeof(struct xsd_sockmsg); i++)
  3482. + ((char*)(&m))[i] = xsint->rsp[MASK_XENSTORE_IDX(cons++)];
  3483. +
  3484. + /* is this the item we were looking for? */
  3485. + if(m.req_id != req_id) {
  3486. + /* no ... so ignore this message and restart */
  3487. + cons += m.len;
  3488. + xsint->rsp_cons = cons;
  3489. + goto again;
  3490. + }
  3491. +
  3492. + /* it is! allocate and copy off the result */
  3493. + mbuf = malloc(m.len);
  3494. + while( (xsint->rsp_prod - cons) < m.len )
  3495. + runtime_block(1);
  3496. + for(i = 0; i < m.len; i++)
  3497. + mbuf[i] = xsint->rsp[MASK_XENSTORE_IDX(cons++)];
  3498. +
  3499. + /* update the other size and return the buffer and length */
  3500. + xsint->rsp_cons = cons;
  3501. + *buffer = mbuf;
  3502. + *rtype = m.type;
  3503. + return m.len;
  3504. +}
  3505. +#endif
  3506. diff --git a/rts/xen/signals.c b/rts/xen/signals.c
  3507. new file mode 100644
  3508. index 0000000..1088e0d
  3509. --- /dev/null
  3510. +++ b/rts/xen/signals.c
  3511. @@ -0,0 +1,502 @@
  3512. +#define __XEN__
  3513. +#include "Rts.h"
  3514. +#include "Schedule.h"
  3515. +#include "RtsSignals.h"
  3516. +#include "RtsUtils.h"
  3517. +#include "Task.h"
  3518. +#include "signals.h"
  3519. +#include <runtime_reqs.h>
  3520. +#include <string.h>
  3521. +#include <sys/mman.h>
  3522. +#include <xen/xen.h>
  3523. +#include <xen/event_channel.h>
  3524. +#include <xen/sched.h>
  3525. +#include <xen/vcpu.h>
  3526. +#include "hypercalls.h"
  3527. +#include <assert.h>
  3528. +#include "locks.h"
  3529. +#include "memory.h"
  3530. +#include "smp.h"
  3531. +#include "time_rts.h"
  3532. +
  3533. +#ifndef THREADED_RTS
  3534. +#include "AwaitEvent.h"
  3535. +#endif
  3536. +
  3537. +static void force_hypervisor_callback(void);
  3538. +
  3539. +#define sync_swap __sync_lock_test_and_set
  3540. +
  3541. +
  3542. +/* ************************************************************************ */
  3543. +
  3544. +#define MAX_EVTCHANS ((sizeof(long) * 8) * (sizeof(long) * 8))
  3545. +#define MAX_PENDING_HANDLERS MAX_EVTCHANS
  3546. +
  3547. +typedef struct signal_handler {
  3548. + void (*c_handler)(int);
  3549. + StgStablePtr haskell_handler;
  3550. +} signal_handler_t;
  3551. +
  3552. +static signal_handler_t *signal_handlers;
  3553. +static struct shared_info *shared_info;
  3554. +static unsigned long *ipi_mask;
  3555. +
  3556. +#if defined(__x86_64__) && !defined(THREADED_RTS)
  3557. +static struct pda
  3558. +{
  3559. + int irqcount; /* offset 0 (used in x86_64.S) */
  3560. + char *irqstackptr; /* 8 */
  3561. +} cpu0_pda;
  3562. +#endif
  3563. +
  3564. +void init_signals(struct shared_info *sinfo)
  3565. +{
  3566. + shared_info = sinfo;
  3567. + signal_handlers = calloc(MAX_EVTCHANS, sizeof(signal_handler_t));
  3568. + memset(shared_info->evtchn_mask, 0xFF, sizeof(shared_info->evtchn_mask));
  3569. + ipi_mask = calloc(sizeof(unsigned long) * 8, sizeof(unsigned long));
  3570. + memset(ipi_mask, 0, sizeof(unsigned long) * 8 * sizeof(unsigned long));
  3571. +}
  3572. +
  3573. +long bind_virq(uint32_t virq, uint32_t vcpu)
  3574. +{
  3575. + evtchn_bind_virq_t arg = { .virq = virq, .vcpu = vcpu, .port = 0 };
  3576. + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_virq, &arg);
  3577. + return (res >= 0) ? arg.port : res;
  3578. +}
  3579. +
  3580. +long bind_pirq(uint32_t pirq, int will_share)
  3581. +{
  3582. + evtchn_bind_pirq_t arg = { .pirq = pirq,
  3583. + .flags = will_share ? BIND_PIRQ__WILL_SHARE : 0,
  3584. + .port = 0 };
  3585. + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_pirq, &arg);
  3586. + return (res >= 0) ? arg.port : res;
  3587. +}
  3588. +
  3589. +long bind_ipi(uint32_t vcpu)
  3590. +{
  3591. + evtchn_bind_ipi_t arg = { .vcpu = vcpu, .port = 0 };
  3592. + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_ipi, &arg);
  3593. + unsigned long bit;
  3594. + int offset;
  3595. +
  3596. + if(res < 0)
  3597. + return res;
  3598. +
  3599. + offset = arg.port / (sizeof(unsigned long) * 8);
  3600. + bit = 1 << (arg.port % (sizeof(unsigned long) * 8));
  3601. + __sync_fetch_and_or( &(ipi_mask[offset]), bit);
  3602. +
  3603. + return arg.port;
  3604. +}
  3605. +
  3606. +void set_c_handler(uint32_t chan, void (handler)(int))
  3607. +{
  3608. + assert(chan < MAX_EVTCHANS);
  3609. + (void)sync_swap(&(signal_handlers[chan].c_handler), handler);
  3610. + unmask_channel(chan);
  3611. +}
  3612. +
  3613. +void clear_c_handler(uint32_t chan)
  3614. +{
  3615. + assert(chan < MAX_EVTCHANS);
  3616. + mask_channel(chan);
  3617. + (void)sync_swap(&(signal_handlers[chan].c_handler), NULL);
  3618. +}
  3619. +
  3620. +void set_haskell_handler(uint32_t chan, StgStablePtr handler)
  3621. +{
  3622. + assert(chan < MAX_EVTCHANS);
  3623. + (void)sync_swap(&(signal_handlers[chan].haskell_handler), handler);
  3624. + unmask_channel(chan);
  3625. +}
  3626. +
  3627. +StgStablePtr clear_haskell_handler(uint32_t chan)
  3628. +{
  3629. + assert(chan < MAX_EVTCHANS);
  3630. + mask_channel(chan);
  3631. + return sync_swap(&(signal_handlers[chan].haskell_handler), NULL);
  3632. +}
  3633. +
  3634. +void mask_channel(uint32_t chan)
  3635. +{
  3636. + asm volatile("lock btsl %1, %0"
  3637. + : "=m"(shared_info->evtchn_mask)
  3638. + : "r"(chan) : "memory");
  3639. +}
  3640. +
  3641. +void unmask_channel(uint32_t chan)
  3642. +{
  3643. + int was_set = 0;
  3644. +
  3645. + asm volatile("lock btrl %1, %0"
  3646. + : "=m"(shared_info->evtchn_mask)
  3647. + : "r"(chan) : "memory");
  3648. + /* it appears that masking off a channel simply forbids the interrupt */
  3649. + /* from being sent to us, not from the event being set pending. so */
  3650. + /* running this clears out any undelivered events before we unmask an */
  3651. + /* event. */
  3652. + asm volatile("btl %2,%1 ; sbbl %0,%0"
  3653. + : "=r"(was_set), "=m"(shared_info->evtchn_pending)
  3654. + : "r"(chan));
  3655. + if(was_set) {
  3656. + asm volatile("lock btsl %k2, %1 ; sbbl %0, %0"
  3657. + : "=r"(was_set), "=m"(vcpu_info().evtchn_pending_sel)
  3658. + : "r"(chan / (sizeof(unsigned long) * 8)) : "memory");
  3659. + if(!was_set) {
  3660. + vcpu_info().evtchn_upcall_pending = 1;
  3661. + if(!vcpu_info().evtchn_upcall_mask) force_hypervisor_callback();
  3662. + }
  3663. + }
  3664. +}
  3665. +
  3666. +static inline void clear_channel(uint32_t chan)
  3667. +{
  3668. + asm volatile("lock btrl %1, %0"
  3669. + : "=m"(shared_info->evtchn_pending)
  3670. + : "r"(chan) : "memory");
  3671. +}
  3672. +
  3673. +long channel_send(uint32_t chan)
  3674. +{
  3675. + return HYPERCALL_event_channel_op(EVTCHNOP_send, &chan);
  3676. +}
  3677. +
  3678. +long channel_alloc(uint32_t local, uint32_t remote)
  3679. +{
  3680. + evtchn_alloc_unbound_t arg = { .dom = local, .remote_dom = remote, .port = 0};
  3681. + long res = HYPERCALL_event_channel_op(EVTCHNOP_alloc_unbound, &arg);
  3682. + return res ? res : arg.port;
  3683. +}
  3684. +
  3685. +long channel_bind(uint32_t rdom, uint32_t rport)
  3686. +{
  3687. + evtchn_bind_interdomain_t arg = { .remote_dom = rdom, .remote_port = rport };
  3688. + long res = HYPERCALL_event_channel_op(EVTCHNOP_bind_interdomain, &arg);
  3689. + return res ? res : arg.local_port;
  3690. +}
  3691. +
  3692. +long channel_close(uint32_t chan)
  3693. +{
  3694. + return HYPERCALL_event_channel_op(EVTCHNOP_close, &chan);
  3695. +}
  3696. +
  3697. +/* ************************************************************************ */
  3698. +
  3699. +void initDefaultHandlers(void)
  3700. +{
  3701. + /* nothing! */
  3702. +}
  3703. +
  3704. +void resetDefaultHandlers(void)
  3705. +{
  3706. + /* nothing! */
  3707. +}
  3708. +
  3709. +/* ************************************************************************ */
  3710. +
  3711. +static StgStablePtr *pending_handler_queue = NULL;
  3712. +static unsigned int pending_handler_head = 0;
  3713. +static unsigned int pending_handler_tail = 0;
  3714. +#ifdef THREADED_RTS
  3715. +static halvm_mutex_t pending_handler_lock;
  3716. +#define PENDING_HANDLERS_LOCK() halvm_acquire_lock(&pending_handler_lock);
  3717. +#define PENDING_HANDLERS_UNLOCK() halvm_release_lock(&pending_handler_lock);
  3718. +
  3719. +#else
  3720. +#define PENDING_HANDLERS_LOCK() ;
  3721. +#define PENDING_HANDLERS_UNLOCK() ;
  3722. +#endif
  3723. +
  3724. +void initUserSignals(void)
  3725. +{
  3726. + pending_handler_queue = calloc(MAX_PENDING_HANDLERS, sizeof(StgStablePtr));
  3727. + pending_handler_head = pending_handler_tail = 0;
  3728. +#ifdef THREADED_RTS
  3729. + initMutex(&pending_handler_lock);
  3730. +#endif
  3731. +}
  3732. +
  3733. +int signals_pending(void)
  3734. +{
  3735. + int res, orig_allowed;
  3736. +
  3737. + force_hypervisor_callback();
  3738. + orig_allowed = allow_signals(0);
  3739. + PENDING_HANDLERS_LOCK();
  3740. + res = pending_handler_head != pending_handler_tail;
  3741. + PENDING_HANDLERS_UNLOCK();
  3742. + allow_signals(orig_allowed);
  3743. + return res;
  3744. +}
  3745. +
  3746. +static void enqueueSignalHandler(StgStablePtr handler)
  3747. +{
  3748. + PENDING_HANDLERS_LOCK();
  3749. + pending_handler_queue[pending_handler_tail] = handler;
  3750. + pending_handler_tail = (pending_handler_tail + 1) % MAX_PENDING_HANDLERS;
  3751. + assert(pending_handler_tail != pending_handler_head);
  3752. + PENDING_HANDLERS_UNLOCK();
  3753. +}
  3754. +
  3755. +StgStablePtr dequeueSignalHandler(void)
  3756. +{
  3757. + StgStablePtr retval;
  3758. + int orig_allowed;
  3759. +
  3760. + orig_allowed = allow_signals(0);
  3761. + PENDING_HANDLERS_LOCK();
  3762. + if(pending_handler_head == pending_handler_tail) {
  3763. + retval = NULL;
  3764. + } else {
  3765. + retval = pending_handler_queue[pending_handler_head];
  3766. + pending_handler_head = (pending_handler_head + 1) % MAX_PENDING_HANDLERS;
  3767. + }
  3768. + PENDING_HANDLERS_UNLOCK();
  3769. + allow_signals(orig_allowed);
  3770. +
  3771. + return retval;
  3772. +}
  3773. +
  3774. +#include "vmm.h"
  3775. +
  3776. +int allow_signals(int allow)
  3777. +{
  3778. + int orig_val;
  3779. +
  3780. +#if defined(__x86_64__) && !defined(THREADED_RTS)
  3781. + static int initialized = 0;
  3782. + if(!initialized) {
  3783. + asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
  3784. + asm volatile("wrmsr" : : "c"(0xc0000100), /* MSR_FS_BASE */
  3785. + "a"((uintptr_t)&cpu0_pda & 0xFFFFFFFF),
  3786. + "d"((uintptr_t)&cpu0_pda >> 32));
  3787. + cpu0_pda.irqcount = -1;
  3788. + cpu0_pda.irqstackptr = runtime_alloc(NULL, IRQ_STACK_SIZE, PROT_READWRITE);
  3789. + initialized = 1;
  3790. + }
  3791. +#endif
  3792. + orig_val = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask,!!!allow);
  3793. + asm volatile("" : : : "memory");
  3794. + if(allow && vcpu_info().evtchn_upcall_pending)
  3795. + force_hypervisor_callback();
  3796. +
  3797. + return orig_val;
  3798. +}
  3799. +
  3800. +#ifndef THREADED_RTS
  3801. +void awaitUserSignals(void)
  3802. +{
  3803. + force_hypervisor_callback();
  3804. + while(!signals_pending() && sched_state == SCHED_RUNNING)
  3805. + runtime_block(10 * 60 * 1000); // 10 minutes
  3806. +}
  3807. +#endif
  3808. +
  3809. +rtsBool anyUserHandlers(void)
  3810. +{
  3811. + int i;
  3812. +
  3813. + for(i = 0; i < (int)MAX_EVTCHANS; i++)
  3814. + if(signal_handlers[i].haskell_handler) {
  3815. + return rtsTrue;
  3816. + }
  3817. +
  3818. + return rtsFalse;
  3819. +}
  3820. +
  3821. +void blockUserSignals(void)
  3822. +{
  3823. + /* nothing to do */
  3824. +}
  3825. +
  3826. +void unblockUserSignals(void)
  3827. +{
  3828. + /* nothing to do */
  3829. +}
  3830. +
  3831. +void markSignalHandlers(evac_fn evac __attribute__((unused)),
  3832. + void *user __attribute__((unused)))
  3833. +{
  3834. + /* nothing -- stable pointers should prevent GC */
  3835. +}
  3836. +
  3837. +void freeSignalHandlers(void)
  3838. +{
  3839. + /* nothing */
  3840. +}
  3841. +
  3842. +/* ************************************************************************ */
  3843. +
  3844. +#ifndef THREADED_RTS
  3845. +void startSignalHandlers(Capability *cap)
  3846. +{
  3847. + StgStablePtr next;
  3848. +
  3849. + while( (next = dequeueSignalHandler()) ) {
  3850. + StgClosure *h = (StgClosure*)deRefStablePtr(next);
  3851. + scheduleThread(cap, createIOThread(cap,RtsFlags.GcFlags.initialStkSize,h));
  3852. + }
  3853. +}
  3854. +
  3855. +static rtsBool wakeUpSleepingThreads(StgWord now)
  3856. +{
  3857. + rtsBool retval = rtsFalse;
  3858. +
  3859. + /* wake up anyone that's sleeping */
  3860. + while((sleeping_queue != END_TSO_QUEUE) &&
  3861. + (sleeping_queue->block_info.target <= now))
  3862. + {
  3863. + StgTSO *tso = sleeping_queue;
  3864. + retval = rtsTrue;
  3865. + sleeping_queue = tso->_link;
  3866. + tso->why_blocked = NotBlocked;
  3867. + tso->_link = END_TSO_QUEUE;
  3868. + pushOnRunQueue(&MainCapability, tso);
  3869. + }
  3870. +
  3871. + return retval;
  3872. +}
  3873. +
  3874. +void awaitEvent(rtsBool wait)
  3875. +{
  3876. + do {
  3877. + StgWord now = getDelayTarget(0);
  3878. +
  3879. + if(wakeUpSleepingThreads(now))
  3880. + return;
  3881. +
  3882. + if(signals_pending()) {
  3883. + startSignalHandlers(&MainCapability);
  3884. + return;
  3885. + }
  3886. +
  3887. + /* if we're supposed to wait, try blocking for awhile */
  3888. + if(wait) {
  3889. + lnat block_time = ~0;
  3890. +
  3891. + if(sleeping_queue != END_TSO_QUEUE) {
  3892. + StgWord target = sleeping_queue->block_info.target; /* in us */
  3893. +
  3894. + assert(target > now);
  3895. + block_time = (target - now) / 1000; /* us -> ms */
  3896. + }
  3897. + runtime_block(block_time);
  3898. + }
  3899. +
  3900. + if(sched_state >= SCHED_INTERRUPTING)
  3901. + return;
  3902. +
  3903. + wakeUpSleepingThreads(getDelayTarget(0));
  3904. + } while(wait && (sched_state == SCHED_RUNNING)
  3905. + && emptyRunQueue(&MainCapability));
  3906. +}
  3907. +#endif
  3908. +
  3909. +#define one_day (1 * 24 * 60 * 60 * 1000)
  3910. +
  3911. +void runtime_block(unsigned long milliseconds)
  3912. +{
  3913. + int orig_allowed;
  3914. +
  3915. + if(!signals_pending()) {
  3916. + orig_allowed = allow_signals(0);
  3917. + force_hypervisor_callback();
  3918. +
  3919. + if(!signals_pending()) {
  3920. + uint64_t now, until;
  3921. + int result;
  3922. +
  3923. + milliseconds = (milliseconds > one_day) ? one_day : milliseconds;
  3924. + now = monotonic_clock();
  3925. + until = now + (milliseconds * 1000000UL);
  3926. + if(monotonic_clock() < until) {
  3927. + vcpu_set_singleshot_timer_t t = { .timeout_abs_ns = until, .flags = VCPU_SSHOTTMR_future };
  3928. + result = HYPERCALL_vcpu_op(VCPUOP_set_singleshot_timer,vcpu_num(),&t);
  3929. + if (result >= 0) {
  3930. + assert(HYPERCALL_sched_op(SCHEDOP_block, 0) >= 0);
  3931. + force_hypervisor_callback();
  3932. + now = monotonic_clock();
  3933. + }
  3934. + }
  3935. + }
  3936. +
  3937. + allow_signals(orig_allowed);
  3938. + }
  3939. +}
  3940. +
  3941. +int stg_sig_install(int sig, int spi, void *mask __attribute__((unused)))
  3942. +{
  3943. + assert(sig == 2);
  3944. + return spi;
  3945. +}
  3946. +
  3947. +/* ************************************************************************ */
  3948. +
  3949. +static void force_hypervisor_callback(void)
  3950. +{
  3951. + uint8_t save;
  3952. +
  3953. + while(vcpu_info().evtchn_upcall_pending) {
  3954. + save = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask, 1);
  3955. + do_hypervisor_callback(NULL);
  3956. + save = __sync_lock_test_and_set(&vcpu_info().evtchn_upcall_mask, save);
  3957. + }
  3958. +}
  3959. +
  3960. +void do_hypervisor_callback(void *u __attribute__((unused)))
  3961. +{
  3962. + unsigned long lev1, lev2;
  3963. +
  3964. + while( sync_swap(&vcpu_info().evtchn_upcall_pending, 0) ) {
  3965. + while( (lev1 = sync_swap(&vcpu_info().evtchn_pending_sel, 0)) ) {
  3966. + while(lev1) {
  3967. + unsigned long idx = __builtin_ffsl(lev1), ipi_filter;
  3968. + unsigned long *pending;
  3969. +
  3970. + assert(idx);
  3971. + idx = idx - 1; /* ffsl returns offset + 1 */
  3972. + lev1 = lev1 & ~(1UL << idx);
  3973. + /* ipi_mask[idx] contains 1s for all IPI channels, so xor the
  3974. + current VCPU's event channel bits to get "all but the current"
  3975. + set. */
  3976. + ipi_filter = ipi_mask[idx] ^ vcpu_evt_bits(idx);
  3977. + pending = &(shared_info->evtchn_pending[idx]);
  3978. + /* we then want lev2 to set the pending bits to include everything
  3979. + in lev2 except for items in ipi_filter, because we'll handle
  3980. + all non-IPIs and IPIs directed at us */
  3981. + while( (lev2 = __sync_fetch_and_and(pending, ipi_filter))) {
  3982. + /* this is the value that existed before the and, above, so it
  3983. + includes all the events. so mask off the IPIs we don't care
  3984. + about. */
  3985. + lev2 = lev2 & ~ipi_filter;
  3986. + /* there exists the chance that this leaves nothing, which
  3987. + can get is in an awkward loop. so we need to explicitly
  3988. + break to get out of here. */
  3989. + if(!lev2) break;
  3990. + /* and now we can process as normal. */
  3991. + while(lev2) {
  3992. + unsigned long idx2 = __builtin_ffsl(lev2), chn;
  3993. +
  3994. + assert(idx2);
  3995. + idx2 = idx2 - 1;
  3996. + chn = (idx * sizeof(unsigned long) * 8) + idx2;
  3997. + lev2 = lev2 & ~(1UL << idx2);
  3998. +
  3999. + if(signal_handlers[chn].c_handler) {
  4000. + signal_handlers[chn].c_handler(chn);
  4001. + }
  4002. +
  4003. + if(signal_handlers[chn].haskell_handler) {
  4004. + enqueueSignalHandler(signal_handlers[chn].haskell_handler);
  4005. + }
  4006. + }
  4007. + }
  4008. + }
  4009. + }
  4010. + }
  4011. +}
  4012. +
  4013. +
  4014. diff --git a/rts/xen/smp.c b/rts/xen/smp.c
  4015. new file mode 100644
  4016. index 0000000..6cc55d1
  4017. --- /dev/null
  4018. +++ b/rts/xen/smp.c
  4019. @@ -0,0 +1,613 @@
  4020. +#define __XEN__
  4021. +#include <assert.h>
  4022. +#include <errno.h>
  4023. +#include <runtime_reqs.h>
  4024. +#include <sys/mman.h>
  4025. +#include <stdint.h>
  4026. +#include <string.h>
  4027. +#include <xen/xen.h>
  4028. +#include <xen/vcpu.h>
  4029. +
  4030. +#include "Rts.h"
  4031. +#include "RtsUtils.h"
  4032. +#include "rts/OSThreads.h"
  4033. +
  4034. +#include "hypercalls.h"
  4035. +#include "locks.h"
  4036. +#include "memory.h"
  4037. +#include "signals.h"
  4038. +#include "smp.h"
  4039. +#include "time_rts.h"
  4040. +#include "vmm.h"
  4041. +
  4042. +#define INIT_KEYTAB_SIZE 1024
  4043. +
  4044. +#ifdef THREADED_RTS
  4045. +enum thread_state {
  4046. + threadRunning,
  4047. + threadReadyToRun,
  4048. + threadBlocked,
  4049. + threadSleeping,
  4050. + threadCreated,
  4051. + threadDead
  4052. +};
  4053. +
  4054. +struct _vcpu_thread {
  4055. + struct _vcpu_thread *prev;
  4056. + struct _vcpu_thread *next;
  4057. + enum thread_state state;
  4058. + void **localKeys;
  4059. + uintptr_t numKeys;
  4060. + /* savedStack: valid iff state in [threadBlocked,threadSleeping] */
  4061. + void *savedStack;
  4062. + /* wakeTarget: valid iff state in [threadSleeping] */
  4063. + unsigned long wakeTarget;
  4064. + /* startProc/param: validd iff state in [threadCreated] */
  4065. + OSThreadProc *startProc;
  4066. + void *param;
  4067. +};
  4068. +
  4069. +struct _desc {
  4070. + uint16_t limit_low;
  4071. + uint16_t base_low;
  4072. + uint8_t base_mid;
  4073. + uint8_t type : 4;
  4074. + uint8_t s : 1;
  4075. + uint8_t dpl : 2;
  4076. + uint8_t p : 1;
  4077. + uint8_t limit_high : 4;
  4078. + uint8_t avl : 1;
  4079. + uint8_t l : 1;
  4080. + uint8_t db : 1;
  4081. + uint8_t g : 1;
  4082. + uint8_t base_high;
  4083. +} __attribute__((packed));
  4084. +typedef struct _desc desc_t;
  4085. +
  4086. +#define vcpu_selector(x) (((x) << 3) | (1 << 2))
  4087. +
  4088. +static halvm_mutex_t thread_lists_lock;
  4089. +static vcpu_thread_t *run_queue_start; /* threads waiting to run */
  4090. +static vcpu_thread_t *run_queue_end; /* threads waiting to run */
  4091. +static vcpu_thread_t *sleeping_queue;
  4092. +static evtchn_port_t *waiting_vcpus;
  4093. +static uint32_t num_vcpus;
  4094. +
  4095. +static halvm_mutex_t key_table_lock;
  4096. +static uint32_t key_table_size;
  4097. +static uint8_t *used_keys;
  4098. +
  4099. +static void startSubordinateVCPU(void);
  4100. +static void subordinateQuit(void);
  4101. +static void runNextTask(void);
  4102. +extern void hypervisor_callback(void);
  4103. +extern void failsafe_callback(void);
  4104. +
  4105. +void saveContextAndGo(vcpu_thread_t *);
  4106. +void restoreContext(vcpu_thread_t *);
  4107. +
  4108. +void init_smp_system(uint32_t ncpus)
  4109. +{
  4110. + per_vcpu_data_t *percpudata;
  4111. + vcpu_thread_t *initialThread;
  4112. + vcpu_local_info_t *infos;
  4113. + mmuext_op_t setldt;
  4114. + desc_t *ldt;
  4115. + uint32_t i;
  4116. +
  4117. + assert(ncpus < 8192); /* max LDT entries */
  4118. + num_vcpus = ncpus;
  4119. +
  4120. + initMutex(&thread_lists_lock);
  4121. + run_queue_start = NULL;
  4122. + run_queue_end = NULL;
  4123. + sleeping_queue = NULL;
  4124. + waiting_vcpus = calloc(ncpus, sizeof(evtchn_port_t));
  4125. + /* we use runtime_alloc here because it gives us back page-aligned addrs */
  4126. + percpudata = runtime_alloc(NULL,ncpus*sizeof(per_vcpu_data_t),PROT_READWRITE);
  4127. + infos = runtime_alloc(NULL, ncpus*sizeof(vcpu_local_info_t), PROT_READWRITE);
  4128. + ldt = runtime_alloc(NULL, ncpus * sizeof(desc_t), PROT_READWRITE);
  4129. + memset(percpudata, 0, ncpus * sizeof(per_vcpu_data_t));
  4130. + memset(infos, 0, ncpus * sizeof(vcpu_local_info_t));
  4131. + memset(ldt, 0, ncpus * sizeof(desc_t));
  4132. +
  4133. + initMutex(&key_table_lock);
  4134. + key_table_size = INIT_KEYTAB_SIZE;
  4135. + used_keys = calloc(key_table_size, sizeof(uint8_t));
  4136. +
  4137. + initialThread = malloc(sizeof(vcpu_thread_t));
  4138. + initialThread->next = initialThread->prev = NULL;
  4139. + initialThread->state = threadRunning;
  4140. +
  4141. + for(i = 0; i < ncpus; i++) {
  4142. + uintptr_t cpuptr = (uintptr_t)(&percpudata[i]);
  4143. + vcpu_register_vcpu_info_t inforeg;
  4144. + unsigned long offset, modulus;
  4145. + evtchn_port_t ipi_port;
  4146. +
  4147. + percpudata[i].cpuinfo = &infos[i];
  4148. + percpudata[i].irqstack = runtime_alloc(NULL,IRQ_STACK_SIZE,PROT_READWRITE);
  4149. +
  4150. + ipi_port = bind_ipi(i);
  4151. + offset = ipi_port / (sizeof(unsigned long) * 8);
  4152. + modulus = ipi_port % (sizeof(unsigned long) * 8);
  4153. +
  4154. + infos[i].num = i;
  4155. + infos[i].cur_thread = initialThread;
  4156. + infos[i].ipi_port = ipi_port;
  4157. + infos[i].local_evt_bits[offset] = 1 << modulus;
  4158. +
  4159. + inforeg.mfn = (uint64_t)get_pt_entry(&(infos[i].info)) >> PAGE_SHIFT;
  4160. + inforeg.offset = (uintptr_t)&(infos[i].info) & (PAGE_SIZE-1);
  4161. + assert(HYPERCALL_vcpu_op(VCPUOP_register_vcpu_info, i, &inforeg) >= 0);
  4162. +
  4163. + ldt[i].limit_low = sizeof(per_vcpu_data_t);
  4164. + ldt[i].type = 2; /* Data, Read/Write */
  4165. + ldt[i].s = 1; /* code or, in this case, data segment */
  4166. + ldt[i].p = 1; /* present */
  4167. + ldt[i].base_low = cpuptr & 0xFFFF; /* low 16 */
  4168. + ldt[i].base_mid = (cpuptr >> 16) & 0xFF;
  4169. + ldt[i].base_high = (cpuptr >> 24) & 0xFF;
  4170. + }
  4171. +
  4172. + /* the LDT cannot be read/write, so adjust its entries in the page tables */
  4173. + for(i = 0; i < ((ncpus * sizeof(desc_t)) + (PAGE_SIZE-1)) / PAGE_SIZE; i++) {
  4174. + void *addr = (void*)((uintptr_t)ldt + (i * PAGE_SIZE));
  4175. + set_pt_entry(addr, get_pt_entry(addr) & ~PG_READWRITE);
  4176. + }
  4177. +
  4178. + /* set the LDT in place and load VCPU#0's FS entry */
  4179. + setldt.cmd = MMUEXT_SET_LDT;
  4180. + setldt.arg1.linear_addr = (unsigned long)ldt;
  4181. + setldt.arg2.nr_ents = ncpus;
  4182. + assert(HYPERCALL_mmuext_op(&setldt, 1, NULL, DOMID_SELF) >= 0);
  4183. + asm("movl %0, %%fs" : : "r"(vcpu_selector(0)));
  4184. + assert(cpu_info() == &infos[0]);
  4185. +
  4186. + for(i = 1; i < ncpus; i++) {
  4187. + vcpu_guest_context_t *context = malloc(sizeof(vcpu_guest_context_t));
  4188. + unsigned long creg;
  4189. + void **stack;
  4190. +
  4191. + stack = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
  4192. + memset(context, 0, sizeof(vcpu_guest_context_t));
  4193. + memset(stack, 0, VCPU_STACK_SIZE);
  4194. + context->flags = VGCF_i387_valid;
  4195. + context->flags |= VGCF_in_kernel;
  4196. + context->flags |= VGCF_failsafe_disables_events;
  4197. +#ifdef __x86_64__
  4198. + context->flags |= VGCF_syscall_disables_events;
  4199. +#endif
  4200. + /* set up the user registers */
  4201. + context->user_regs.eip = (unsigned long)&startSubordinateVCPU;
  4202. + context->user_regs.cs = FLAT_KERNEL_CS;
  4203. + context->user_regs.ss = FLAT_KERNEL_SS;
  4204. + context->user_regs.ds = FLAT_KERNEL_DS;
  4205. + context->user_regs.es = FLAT_KERNEL_DS;
  4206. + context->user_regs.fs = vcpu_selector(i);
  4207. + context->user_regs.gs = FLAT_KERNEL_DS;
  4208. + stack = (void**)((uintptr_t)stack + VCPU_STACK_SIZE);
  4209. + stack[-1] = subordinateQuit; /* works as a return point */
  4210. + context->user_regs.esp = (unsigned long)&(stack[-1]);
  4211. + /* set the control registers */
  4212. + asm("mov %%cr0, %0" : "=r"(creg)); context->ctrlreg[0] = creg;
  4213. + asm("mov %%cr2, %0" : "=r"(creg)); context->ctrlreg[2] = creg;
  4214. + asm("mov %%cr3, %0" : "=r"(creg)); context->ctrlreg[3] = creg;
  4215. + asm("mov %%cr4, %0" : "=r"(creg)); context->ctrlreg[4] = creg;
  4216. + /* set the LDT */
  4217. + context->ldt_base = (unsigned long)ldt;
  4218. + context->ldt_ents = ncpus;
  4219. + /* set the callback pointers */
  4220. +#ifdef __i386__
  4221. + context->event_callback_cs = FLAT_KERNEL_CS;
  4222. + context->event_callback_eip = (unsigned long)&hypervisor_callback;
  4223. + context->failsafe_callback_cs = FLAT_KERNEL_CS;
  4224. + context->failsafe_callback_eip = (unsigned long)&failsafe_callback;
  4225. +#else
  4226. + context->event_callback_eip = (unsigned long)&hypervisor_callback;
  4227. + context->failsafe_callback_eip = (unsigned long)&failsafe_callback;
  4228. +#endif
  4229. + assert( HYPERCALL_vcpu_op(VCPUOP_initialise, i, context) >= 0);
  4230. + free(context);
  4231. + assert( HYPERCALL_vcpu_op(VCPUOP_up, i, context) >= 0);
  4232. + }
  4233. +}
  4234. +
  4235. +#define VCPU_LOCAL_STARTU ((uintptr_t)VCPU_LOCAL_START)
  4236. +
  4237. +static void startSubordinateVCPU()
  4238. +{
  4239. + runNextTask();
  4240. +}
  4241. +
  4242. +static void subordinateQuit()
  4243. +{
  4244. + while(1) (void)HYPERCALL_vcpu_op(VCPUOP_down, vcpu_num(), 0);
  4245. +}
  4246. +
  4247. +static unsigned long get_sleep_time(void)
  4248. +{
  4249. + unsigned long target = 24 * 60 * 60 * 1000;
  4250. + unsigned long now = getDelayTarget(0);
  4251. + vcpu_thread_t *thr;
  4252. +
  4253. + halvm_acquire_lock(&thread_lists_lock);
  4254. + for(thr = sleeping_queue; thr; thr = thr->next) {
  4255. + unsigned long candidate = (thr->wakeTarget - now) / 1000;
  4256. + if(thr->wakeTarget < now) target = 0;
  4257. + if(candidate < target) target = candidate;
  4258. + }
  4259. + halvm_release_lock(&thread_lists_lock);
  4260. +
  4261. + return target;
  4262. +}
  4263. +
  4264. +static void runNextTask()
  4265. +{
  4266. + void *p;
  4267. +
  4268. + while(1) {
  4269. + halvm_acquire_lock(&thread_lists_lock);
  4270. + if(run_queue_start) {
  4271. + vcpu_thread_t *next_task = run_queue_start;
  4272. +
  4273. + /* adjust the head and tail pointers */
  4274. + run_queue_start = next_task->next;
  4275. + next_task->prev = next_task->next = NULL;
  4276. + if(run_queue_start)
  4277. + run_queue_start->prev = NULL;
  4278. + else
  4279. + run_queue_end = NULL;
  4280. + /* we're either going to jump somewhere else or die at this point,
  4281. + so be nice and release the lock */
  4282. + halvm_release_lock(&thread_lists_lock);
  4283. +
  4284. + switch(next_task->state) {
  4285. + case threadRunning:
  4286. + printf("ERROR: Running thread on run queue.\n");
  4287. + assert(0);
  4288. + case threadReadyToRun:
  4289. + next_task->state = threadRunning;
  4290. + vcpu_cur_thread() = next_task;
  4291. + restoreContext(next_task);
  4292. + assert(0); /* should not get here */
  4293. + case threadBlocked:
  4294. + printf("ERROR: Blocked thread on run queue.\n");
  4295. + assert(0);
  4296. + case threadSleeping:
  4297. + printf("ERROR: Sleeping thread on run queue.\n");
  4298. + assert(0);
  4299. + case threadCreated:
  4300. + vcpu_cur_thread() = next_task;
  4301. + p = runtime_alloc(NULL, VCPU_STACK_SIZE, PROT_READWRITE);
  4302. +#ifdef __x86_64__
  4303. + asm("mov %0, %%rsp" : : "r"((uintptr_t)p + VCPU_STACK_SIZE));
  4304. +#else
  4305. + asm("mov %0, %%esp" : : "r"((uintptr_t)p + VCPU_STACK_SIZE));
  4306. +#endif
  4307. + /* I'm not sure enough of the disposition of local variables to */
  4308. + /* really trust using them after the stack swap */
  4309. + vcpu_cur_thread()->state = threadRunning;
  4310. + vcpu_cur_thread()->startProc(
  4311. + vcpu_cur_thread()->param);
  4312. + shutdownThread(); /* if we get back here, we should just die */
  4313. + case threadDead:
  4314. + printf("ERROR: Dead thread on run queue.\n");
  4315. + assert(0);
  4316. + default:
  4317. + printf("ERROR: Unacceptable task state on sleeping queue: %d\n",
  4318. + next_task->state);
  4319. + assert(0);
  4320. + }
  4321. + }
  4322. +
  4323. + /* block signals before we release the lock, to avoid a signalling race */
  4324. + allow_signals(0);
  4325. + waiting_vcpus[vcpu_num()] = vcpu_ipi_port();
  4326. + __sync_synchronize();
  4327. + halvm_release_lock(&thread_lists_lock);
  4328. + runtime_block(get_sleep_time()); /* will turn signals back on */
  4329. + pokeSleepThread();
  4330. + }
  4331. +}
  4332. +
  4333. +void newThreadLocalKey(halvm_vcpukey_t *key)
  4334. +{
  4335. + uint32_t i;
  4336. +
  4337. + halvm_acquire_lock(&key_table_lock);
  4338. + for(i = 0; i < key_table_size; i++)
  4339. + if(!used_keys[i]) {
  4340. + used_keys[i] = 1;
  4341. + *key = i;
  4342. + halvm_release_lock(&key_table_lock);
  4343. + return;
  4344. + }
  4345. +
  4346. + /* need to resize */
  4347. + used_keys = realloc(used_keys, (key_table_size * 2) * sizeof(uint8_t));
  4348. + for(i = key_table_size; i < (key_table_size * 2); i++)
  4349. + used_keys[i] = 0;
  4350. + *key = key_table_size;
  4351. + used_keys[key_table_size] = 1;
  4352. + key_table_size = key_table_size * 2;
  4353. + halvm_release_lock(&key_table_lock);
  4354. +}
  4355. +
  4356. +void *getThreadLocalVar(halvm_vcpukey_t *key)
  4357. +{
  4358. + vcpu_thread_t *me = vcpu_cur_thread();
  4359. + uintptr_t index = *key, i;
  4360. +
  4361. + assert(me);
  4362. + assert(me->state == threadRunning);
  4363. +
  4364. + if(me->numKeys > index) {
  4365. + return me->localKeys[index];
  4366. + }
  4367. +
  4368. + me->localKeys = realloc(me->localKeys, (index+1) * sizeof(void*));
  4369. + for(i = me->numKeys; i <= index; i++)
  4370. + me->localKeys[i] = NULL;
  4371. + me->numKeys = index + 1;
  4372. +
  4373. + return NULL;
  4374. +}
  4375. +
  4376. +void setThreadLocalVar(halvm_vcpukey_t *key, void *value)
  4377. +{
  4378. + vcpu_thread_t *me = vcpu_cur_thread();
  4379. + uintptr_t index = *key, i;
  4380. +
  4381. + assert(me);
  4382. + assert(me->state == threadRunning);
  4383. +
  4384. + if(me->numKeys > index) {
  4385. + me->localKeys[index] = value;
  4386. + return;
  4387. + }
  4388. +
  4389. + me->localKeys =
  4390. + realloc(me->localKeys, (index+1) * sizeof(void*));
  4391. + for(i = me->numKeys; i < index; i++)
  4392. + me->localKeys[i] = NULL;
  4393. + me->numKeys = index + 1;
  4394. + me->localKeys[index] = value;
  4395. +}
  4396. +
  4397. +void freeThreadLocalKey(halvm_vcpukey_t *key)
  4398. +{
  4399. + /* this is a bit incorrect, as free/get will still get the old value,
  4400. + but I don't think it matters in the current GHC usage */
  4401. + halvm_acquire_lock(&key_table_lock);
  4402. + used_keys[*key] = 0;
  4403. + halvm_release_lock(&key_table_lock);
  4404. +}
  4405. +
  4406. +nat getNumberOfProcessors(void)
  4407. +{
  4408. + return num_vcpus;
  4409. +}
  4410. +
  4411. +int forkOS_createThread(HsStablePtr entry __attribute__((unused)))
  4412. +{
  4413. + printf("ERROR: forkOS_createThread called.\n");
  4414. + return 0;
  4415. +}
  4416. +
  4417. +int createOSThread(OSThreadId *pid, OSThreadProc *startProc, void *param)
  4418. +{
  4419. + vcpu_thread_t *newt = malloc(sizeof(vcpu_thread_t));
  4420. + uint32_t i;
  4421. +
  4422. + if(!newt)
  4423. + return EAGAIN;
  4424. +
  4425. + memset(newt, 0, sizeof(vcpu_thread_t));
  4426. + newt->state = threadCreated;
  4427. + newt->numKeys = key_table_size;
  4428. + newt->localKeys = calloc(newt->numKeys, sizeof(void*));
  4429. + newt->startProc = startProc;
  4430. + newt->param = param;
  4431. + newt->next = newt->prev = NULL;
  4432. +
  4433. + halvm_acquire_lock(&thread_lists_lock);
  4434. + if(run_queue_start) {
  4435. + assert(run_queue_end);
  4436. + run_queue_end->next = newt;
  4437. + newt->prev = run_queue_end;
  4438. + run_queue_end = newt;
  4439. + } else {
  4440. + assert(!run_queue_end);
  4441. + run_queue_start = run_queue_end = newt;
  4442. + }
  4443. + halvm_release_lock(&thread_lists_lock);
  4444. +
  4445. + for(i = 0; i < num_vcpus; i++) {
  4446. + evtchn_port_t sleeping = __sync_lock_test_and_set(&(waiting_vcpus[i]), 0);
  4447. + if(sleeping) {
  4448. + channel_send(sleeping);
  4449. + break;
  4450. + }
  4451. + }
  4452. +
  4453. + *pid = newt;
  4454. + return 0;
  4455. +}
  4456. +
  4457. +OSThreadId osThreadId(void)
  4458. +{
  4459. + return vcpu_cur_thread();
  4460. +}
  4461. +
  4462. +void interruptOSThread(OSThreadId id __attribute__((unused)))
  4463. +{
  4464. + printf("ERROR: interruptOSThread called.\n");
  4465. +}
  4466. +
  4467. +void shutdownThread(void)
  4468. +{
  4469. + assert(vcpu_cur_thread());
  4470. + assert(vcpu_cur_thread()->state == threadRunning);
  4471. + assert(!vcpu_cur_thread()->next);
  4472. + assert(!vcpu_cur_thread()->prev);
  4473. + vcpu_cur_thread()->state = threadDead;
  4474. + /* this leaks memory in order to make osThreadIsAlive work ... bad plan? */
  4475. + runNextTask();
  4476. + __builtin_unreachable();
  4477. +}
  4478. +
  4479. +void __attribute__((noinline,noclone)) saveContextAndGo(vcpu_thread_t *thr)
  4480. +{
  4481. +#ifdef __x86_64__
  4482. + asm volatile ("push %%rbx ;"
  4483. + "push %%rbp ;"
  4484. + "push %%r12 ;"
  4485. + "push %%r13 ;"
  4486. + "push %%r14 ;"
  4487. + "push %%r15 ;"
  4488. + "movq %%rsp, %0 ;"
  4489. + "jmp runNextTask"
  4490. + : "=m"(thr->savedStack) : : "memory");
  4491. +#else
  4492. + asm volatile ("push %%ebx ;"
  4493. + "push %%ebp ;"
  4494. + "mov %%esp, %0 ;"
  4495. + "jmp runNextTask"
  4496. + : "=m"(thr->savedStack) : : "memory");
  4497. +#endif
  4498. +}
  4499. +
  4500. +void __attribute__((noinline)) restoreContext(vcpu_thread_t *thr)
  4501. +{
  4502. +#ifdef __x86_64__
  4503. + asm volatile ("mov %0, %%rsp ; "
  4504. + "pop %%r15 ; "
  4505. + "pop %%r14 ; "
  4506. + "pop %%r13 ; "
  4507. + "pop %%r12 ; "
  4508. + "pop %%rbp ;"
  4509. + "pop %%rbx ;"
  4510. + : : "m"(thr->savedStack) : "memory");
  4511. +#else
  4512. + asm volatile ("mov %0, %%esp ; "
  4513. + "pop %%ebp ;"
  4514. + "pop %%ebx ;"
  4515. + : : "m"(thr->savedStack) : "memory");
  4516. +#endif
  4517. +}
  4518. +
  4519. +void yieldThread(void)
  4520. +{
  4521. + vcpu_thread_t *me = vcpu_cur_thread();
  4522. +
  4523. + halvm_acquire_lock(&thread_lists_lock);
  4524. + if(run_queue_end) {
  4525. + me->prev = run_queue_end;
  4526. + me->next = NULL;
  4527. + run_queue_end->next = me;
  4528. + run_queue_end = me;
  4529. + } else {
  4530. + run_queue_start = run_queue_end = me;
  4531. + }
  4532. + halvm_release_lock(&thread_lists_lock);
  4533. + me->state = threadReadyToRun;
  4534. + vcpu_cur_thread() = NULL;
  4535. + saveContextAndGo(me);
  4536. +}
  4537. +
  4538. +void unlockThread(vcpu_thread_t *thr)
  4539. +{
  4540. + halvm_acquire_lock(&thread_lists_lock);
  4541. + if(run_queue_end) {
  4542. + run_queue_end->next = thr;
  4543. + thr->prev = run_queue_end;
  4544. + thr->next = NULL;
  4545. + run_queue_end = thr;
  4546. + } else {
  4547. + run_queue_start = run_queue_end = thr;
  4548. + thr->next = thr->prev = NULL;
  4549. + }
  4550. + thr->state = threadReadyToRun;
  4551. + halvm_release_lock(&thread_lists_lock);
  4552. +}
  4553. +
  4554. +void lockCurrentThread(halvm_mutex_t *lock)
  4555. +{
  4556. + vcpu_thread_t *me = vcpu_cur_thread();
  4557. +
  4558. + vcpu_cur_thread() = NULL;
  4559. + me->prev = me->next = NULL;
  4560. + me->state = threadBlocked;
  4561. + halvm_release_lock(lock);
  4562. + saveContextAndGo(me);
  4563. + halvm_acquire_lock(lock);
  4564. +}
  4565. +
  4566. +void sleepUntilWaiter(unsigned long target_us)
  4567. +{
  4568. + vcpu_thread_t *me = vcpu_cur_thread();
  4569. +
  4570. + vcpu_cur_thread() = NULL;
  4571. + me->prev = NULL;
  4572. + me->state = threadSleeping;
  4573. + me->wakeTarget = target_us;
  4574. +
  4575. + halvm_acquire_lock(&thread_lists_lock);
  4576. + me->next = sleeping_queue;
  4577. + if(sleeping_queue)
  4578. + sleeping_queue->prev = me;
  4579. + sleeping_queue = me;
  4580. + halvm_release_lock(&thread_lists_lock);
  4581. +
  4582. + saveContextAndGo(me);
  4583. +}
  4584. +
  4585. +void pokeSleepThread(void)
  4586. +{
  4587. + halvm_acquire_lock(&thread_lists_lock);
  4588. + while(sleeping_queue) {
  4589. + vcpu_thread_t *cur = sleeping_queue;
  4590. +
  4591. + assert(cur->state == threadSleeping);
  4592. + cur->state = threadReadyToRun;
  4593. + sleeping_queue = sleeping_queue->next;
  4594. + if(run_queue_end) {
  4595. + cur->prev = run_queue_end;
  4596. + cur->next = NULL;
  4597. + run_queue_end->next = cur;
  4598. + run_queue_end = cur;
  4599. + } else {
  4600. + run_queue_start = run_queue_end = cur;
  4601. + cur->next = cur->prev = NULL;
  4602. + }
  4603. + }
  4604. + halvm_release_lock(&thread_lists_lock);
  4605. +}
  4606. +
  4607. +rtsBool osThreadIsAlive(OSThreadId id)
  4608. +{
  4609. + return (id->state != threadDead);
  4610. +}
  4611. +
  4612. +void setThreadAffinity(nat n, nat m)
  4613. +{
  4614. + printf("setThreadAffinity(%d, %d)\n", n, m); // FIXME
  4615. +}
  4616. +#else
  4617. +int forkOS_createThread(HsStablePtr entry __attribute__((unused)))
  4618. +{
  4619. + printf("ERROR: forkOS_createThread called.\n");
  4620. + return 0;
  4621. +}
  4622. +
  4623. +nat getNumberOfProcessors(void)
  4624. +{
  4625. + return 1;
  4626. +}
  4627. +
  4628. +void sleepUntilWaiter(unsigned long target_us __attribute__((unused)))
  4629. +{
  4630. +}
  4631. +
  4632. +#endif
  4633. diff --git a/rts/xen/time.c b/rts/xen/time.c
  4634. new file mode 100644
  4635. index 0000000..4a1db29
  4636. --- /dev/null
  4637. +++ b/rts/xen/time.c
  4638. @@ -0,0 +1,217 @@
  4639. +#define __XEN__
  4640. +#include <stdint.h>
  4641. +#include "Rts.h"
  4642. +#include "Ticker.h"
  4643. +#include "GetTime.h"
  4644. +#include <stdlib.h>
  4645. +#include <string.h>
  4646. +#include <time.h>
  4647. +#include <runtime_reqs.h>
  4648. +#include "time_rts.h"
  4649. +#include <signals.h>
  4650. +#include <xen/xen.h>
  4651. +#include <xen/vcpu.h>
  4652. +#include <assert.h>
  4653. +#include "hypercalls.h"
  4654. +#include "memory.h"
  4655. +#include "smp.h"
  4656. +#include <errno.h>
  4657. +
  4658. +#ifdef __x86_64
  4659. +# define rmb() asm volatile("lfence" : : : "memory")
  4660. +#else
  4661. +# define rmb() asm volatile("lock; addl $0, 0(%%esp)" : : : "memory")
  4662. +#endif
  4663. +
  4664. +/* ************************************************************************* */
  4665. +
  4666. +static uint64_t start_time = 0;
  4667. +static uint32_t timer_echan = 0;
  4668. +static struct shared_info *shared_info = NULL;
  4669. +
  4670. +void init_time(struct shared_info *sinfo)
  4671. +{
  4672. + long res = bind_virq(VIRQ_TIMER, 0);
  4673. + assert(res >= 0);
  4674. + timer_echan = res;
  4675. + shared_info = sinfo;
  4676. + start_time = monotonic_clock();
  4677. +}
  4678. +
  4679. +static inline uint64_t rdtscll(void)
  4680. +{
  4681. + uint32_t highbits, lowbits;
  4682. + uint64_t retval;
  4683. +
  4684. + asm volatile("rdtsc" : "=a"(lowbits), "=d"(highbits));
  4685. + retval = (((uint64_t)highbits) << 32) | ((uint64_t)lowbits);
  4686. + return retval;
  4687. +}
  4688. +
  4689. +uint64_t monotonic_clock(void)
  4690. +{
  4691. + struct vcpu_time_info *time = &vcpu_info().time;
  4692. + uint32_t start_version, end_version;
  4693. + uint64_t now, delta, retval = 0;
  4694. +
  4695. + do {
  4696. + /* if the low bit in the version is set, an update is in progress */
  4697. + do { start_version = time->version; } while (start_version & 0x1);
  4698. + __sync_synchronize();
  4699. + /* pull in the base system time */
  4700. + retval = time->system_time;
  4701. + /* now we figure out the difference between now and when that was written */
  4702. + now = rdtscll();
  4703. + delta = now - time->tsc_timestamp;
  4704. + if(time->tsc_shift < 0)
  4705. + delta >>= -time->tsc_shift;
  4706. + else
  4707. + delta <<= time->tsc_shift;
  4708. + retval += (delta * time->tsc_to_system_mul) >> 32;
  4709. + __sync_synchronize();
  4710. + /* get our end version */
  4711. + end_version = time->version;
  4712. + __sync_synchronize();
  4713. + /* if the two values are different, we my have an inconsistent time */
  4714. + } while(start_version != end_version);
  4715. +
  4716. + return retval;
  4717. +}
  4718. +
  4719. +/* ************************************************************************* */
  4720. +
  4721. +time_t runtime_time()
  4722. +{
  4723. + uint32_t start_version, end_version;
  4724. + time_t retval;
  4725. +
  4726. + do {
  4727. + /* if the low bit in the version is set, an update is in progress */
  4728. + do { start_version = vcpu_info().time.version; }
  4729. + while (start_version & 0x1);
  4730. + rmb();
  4731. + retval = shared_info->wc_sec;
  4732. + retval += shared_info->wc_nsec / 1000000000ULL; /* ns -> s */
  4733. + rmb();
  4734. + end_version = vcpu_info().time.version;
  4735. + rmb();
  4736. + } while(start_version != end_version);
  4737. +
  4738. + return retval;
  4739. +}
  4740. +
  4741. +int runtime_gettimeofday(struct timeval *tv)
  4742. +{
  4743. + uint32_t start_version, end_version;
  4744. + uint64_t offset = monotonic_clock();
  4745. +
  4746. + if(!tv) return EFAULT;
  4747. +
  4748. + do {
  4749. + /* if the low bit in the version is set, an update is in progress */
  4750. + do { start_version = vcpu_info().time.version; }
  4751. + while (start_version & 0x1);
  4752. + rmb();
  4753. + tv->tv_sec = shared_info->wc_sec + (offset / 1000000000ULL);
  4754. + tv->tv_usec = (shared_info->wc_nsec + (offset % 1000000000ULL)) / 1000ULL;
  4755. + rmb();
  4756. + end_version = vcpu_info().time.version;
  4757. + rmb();
  4758. + } while(start_version != end_version);
  4759. +
  4760. + return 0;
  4761. +}
  4762. +
  4763. +int runtime_rusage(int who __attribute__((unused)), struct rusage *usage)
  4764. +{
  4765. + uint64_t now = monotonic_clock();
  4766. + uint64_t diff = now - start_time;
  4767. +
  4768. + assert(now >= start_time);
  4769. + memset(usage, 0, sizeof(struct rusage));
  4770. + usage->ru_utime.tv_sec = diff / 1000000000;
  4771. + usage->ru_utime.tv_usec = (diff % 1000000000) / 1000;
  4772. + usage->ru_maxrss = max_pages * 4096;
  4773. + usage->ru_ixrss = cur_pages * 4096;
  4774. + usage->ru_idrss = cur_pages * 4096;
  4775. + usage->ru_isrss = VCPU_STACK_SIZE;
  4776. +
  4777. + return 0;
  4778. +}
  4779. +
  4780. +void getProcessTimes(Time *user, Time *elapsed)
  4781. +{
  4782. + uint64_t now = monotonic_clock();
  4783. + if(user) *user = NSToTime(now);
  4784. + if(elapsed) *elapsed = NSToTime(now);
  4785. +}
  4786. +
  4787. +/* ************************************************************************* */
  4788. +
  4789. +void initializeTimer()
  4790. +{
  4791. + /* nothing for the HaLVM */
  4792. +}
  4793. +
  4794. +Time getProcessElapsedTime()
  4795. +{
  4796. + return NSToTime(monotonic_clock());
  4797. +}
  4798. +
  4799. +Time getProcessCPUTime()
  4800. +{
  4801. + return NSToTime(monotonic_clock());
  4802. +}
  4803. +
  4804. +Time getThreadCPUTime()
  4805. +{
  4806. + return NSToTime(monotonic_clock());
  4807. +}
  4808. +
  4809. +StgWord64 getMonotonicNSec()
  4810. +{
  4811. + return NSToTime(monotonic_clock());
  4812. +}
  4813. +
  4814. +/* ************************************************************************* */
  4815. +
  4816. +StgWord getDelayTarget(HsInt us /* microseconds */)
  4817. +{
  4818. + Time now = (Time)((uint64_t)monotonic_clock() / (uint64_t)1000); /* ns->us */
  4819. +
  4820. + if( (now + us) < now ) {
  4821. + printf("Exceptional case in getDelayTarget.\n");
  4822. + return 0;
  4823. + }
  4824. +
  4825. + return now + us;
  4826. +}
  4827. +
  4828. +/* ************************************************************************* */
  4829. +
  4830. +static uint64_t timer_interval = 0;
  4831. +
  4832. +void initTicker(Time interval, TickProc handle_tick)
  4833. +{
  4834. + /* the interval is given in units of TIME_RESOLUTION, which is essentially */
  4835. + /* provided as a hertz value. I could probably assume that it'll remain at */
  4836. + /* nanoseconds, but this is a bit more reasonable ... */
  4837. + timer_interval = (interval * TIME_RESOLUTION) / 1000000000;
  4838. + set_c_handler(timer_echan, handle_tick);
  4839. +}
  4840. +
  4841. +void startTicker(void)
  4842. +{
  4843. + HYPERCALL_vcpu_op(VCPUOP_set_periodic_timer, vcpu_num(), &timer_interval);
  4844. +}
  4845. +
  4846. +void stopTicker(void)
  4847. +{
  4848. + HYPERCALL_vcpu_op(VCPUOP_stop_periodic_timer, vcpu_num(), &timer_interval);
  4849. +}
  4850. +
  4851. +void exitTicker(rtsBool wait __attribute__((unused)))
  4852. +{
  4853. + timer_interval = 0;
  4854. + clear_c_handler(timer_echan);
  4855. +}
  4856. diff --git a/rts/xen/vmm_32p.c b/rts/xen/vmm_32p.c
  4857. new file mode 100644
  4858. index 0000000..e7b289a
  4859. --- /dev/null
  4860. +++ b/rts/xen/vmm_32p.c
  4861. @@ -0,0 +1,182 @@
  4862. +#ifdef CONFIG_X86_PAE
  4863. +#include "vmm.h"
  4864. +#include "memory.h"
  4865. +#include <stdio.h>
  4866. +#include <stdlib.h>
  4867. +#include <assert.h>
  4868. +#include <string.h>
  4869. +#include "hypercalls.h"
  4870. +#include "locks.h"
  4871. +#include "smp.h"
  4872. +
  4873. +static halvm_mutex_t vmm_lock;
  4874. +// Information regarding the handy temporary space we use
  4875. +static pte_t *temp_table;
  4876. +static maddr_t temp_table_pt_entry;
  4877. +static maddr_t l3_phys_base;
  4878. +// The start of where we've been mapped
  4879. +extern int _text;
  4880. +
  4881. +static inline int mmu_update(uint64_t ptr, uint64_t val)
  4882. +{
  4883. + mmu_update_t update;
  4884. + update.ptr = ptr;
  4885. + update.val = val;
  4886. + return HYPERCALL_mmu_update(&update, 1, NULL, DOMID_SELF) >= 0;
  4887. +}
  4888. +
  4889. +static void temporarily_map(maddr_t maddr, maddr_t flags)
  4890. +{
  4891. + mmuext_op_t flush;
  4892. + int res;
  4893. +
  4894. + flush.cmd = MMUEXT_INVLPG_LOCAL;
  4895. + flush.arg1.linear_addr = (unsigned long)temp_table;
  4896. + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
  4897. +
  4898. + res = mmu_update(temp_table_pt_entry,
  4899. + ENTRY_MADDR(maddr)|PG_PRESENT|PG_USER|flags);
  4900. + if(res <= 0) {
  4901. + assert(*(void**)(0));
  4902. + }
  4903. +}
  4904. +
  4905. +void *initialize_vmm(start_info_t *sinfo, void *init_sp)
  4906. +{
  4907. + uintptr_t l3vb_off = (uintptr_t)sinfo->pt_base - (uintptr_t)&_text;
  4908. + uintptr_t l3vb_poff = l3vb_off >> PAGE_SHIFT;
  4909. + pte_t *l3_virt_base = (pte_t*)sinfo->pt_base;
  4910. + pte_t *table, entry;
  4911. + mfn_t mfn;
  4912. + pfn_t pfn;
  4913. +
  4914. + l3_phys_base = ((pte_t)(p2m_map[l3vb_poff] & 0x7FFFFFFF)) << PAGE_SHIFT;
  4915. + // Figure out where the temporary table's page table entry is.
  4916. + temp_table = init_sp;
  4917. + entry = l3_virt_base[VADDR_L3_IDX(temp_table)];
  4918. + mfn = entry >> PAGE_SHIFT;
  4919. + pfn = machine_to_phys_mapping[mfn];
  4920. + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L2 table
  4921. + entry = table[VADDR_L2_IDX(temp_table)];
  4922. + temp_table_pt_entry = ENTRY_MADDR(entry) + (8 * VADDR_L1_IDX(temp_table));
  4923. + initMutex(&vmm_lock);
  4924. + return (void*)((uintptr_t)init_sp + PAGE_SIZE);
  4925. +}
  4926. +
  4927. +static pte_t create_table_entry(maddr_t table_base, int idx, int level)
  4928. +{
  4929. + mfn_t mfn = get_free_frame();
  4930. + mmuext_op_t extreq;
  4931. + pte_t retval;
  4932. +
  4933. + assert(mfn);
  4934. +
  4935. + /* clear the new page table */
  4936. + temporarily_map((maddr_t)mfn << PAGE_SHIFT, PG_READWRITE);
  4937. + memset(temp_table, 0, PAGE_SIZE);
  4938. +
  4939. + /* unmap it; we can't have any writable links mapped */
  4940. + assert(mmu_update(temp_table_pt_entry, 0));
  4941. +
  4942. + /* pin it */
  4943. + extreq.cmd = level;
  4944. + extreq.arg1.mfn = mfn;
  4945. + assert(HYPERCALL_mmuext_op(&extreq, 1, NULL, DOMID_SELF) >= 0);
  4946. +
  4947. + /* write in the value */
  4948. + retval = (((pte_t)mfn) << PAGE_SHIFT) | PG_USER | PG_PRESENT | PG_READWRITE;
  4949. + assert(mmu_update(table_base + (sizeof(pte_t) * idx), retval));
  4950. +
  4951. + return retval;
  4952. +}
  4953. +
  4954. +pte_t get_pt_entry(void *addr)
  4955. +{
  4956. + pte_t entry;
  4957. +
  4958. + halvm_acquire_lock(&vmm_lock);
  4959. + temporarily_map(l3_phys_base, 0);
  4960. + entry = temp_table[VADDR_L3_IDX(addr)];
  4961. + if(ENTRY_PRESENT(entry)) {
  4962. + temporarily_map(ENTRY_MADDR(entry), 0);
  4963. + entry = temp_table[VADDR_L2_IDX(addr)];
  4964. + if(ENTRY_PRESENT(entry)) {
  4965. + temporarily_map(ENTRY_MADDR(entry), 0);
  4966. + entry = temp_table[VADDR_L1_IDX(addr)];
  4967. + halvm_release_lock(&vmm_lock);
  4968. + return entry;
  4969. + }
  4970. + }
  4971. +
  4972. + halvm_release_lock(&vmm_lock);
  4973. + return 0;
  4974. +}
  4975. +
  4976. +void set_pt_entry(void *addr, pte_t val)
  4977. +{
  4978. + pte_t l3ent, l2ent;
  4979. +
  4980. + halvm_acquire_lock(&vmm_lock);
  4981. + temporarily_map(l3_phys_base, 0);
  4982. + l3ent = temp_table[VADDR_L3_IDX(addr)];
  4983. + if(!ENTRY_PRESENT(l3ent)) {
  4984. + l3ent = create_table_entry(l3_phys_base, VADDR_L3_IDX(addr),
  4985. + MMUEXT_PIN_L2_TABLE);
  4986. + }
  4987. +
  4988. + temporarily_map(ENTRY_MADDR(l3ent), 0);
  4989. + l2ent = temp_table[VADDR_L2_IDX(addr)];
  4990. + if(!ENTRY_PRESENT(l2ent)) {
  4991. + l2ent = create_table_entry(ENTRY_MADDR(l3ent), VADDR_L2_IDX(addr),
  4992. + MMUEXT_PIN_L1_TABLE);
  4993. + }
  4994. + assert(mmu_update(ENTRY_MADDR(l2ent)+(VADDR_L1_IDX(addr)*sizeof(pte_t)),val));
  4995. + halvm_release_lock(&vmm_lock);
  4996. +
  4997. + /* if(ENTRY_PRESENT(val)) { */
  4998. + mmuext_op_t flush;
  4999. + flush.cmd = MMUEXT_INVLPG_ALL;
  5000. + flush.arg1.linear_addr = (unsigned long)addr;
  5001. + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
  5002. + /* } */
  5003. +}
  5004. +
  5005. +void *machine_to_virtual(uint64_t maddr)
  5006. +{
  5007. + pte_t l3_entry, l2_entry;
  5008. + int i, j, k;
  5009. +
  5010. + for(i = 0; i < 512; i++) {
  5011. + if(i == VADDR_L3_IDX(HYPERVISOR_VIRT_START))
  5012. + break;
  5013. +
  5014. + temporarily_map(l3_phys_base, 0);
  5015. + l3_entry = temp_table[i];
  5016. + if(ENTRY_PRESENT(l3_entry)) {
  5017. + pte_t l2_table_base = ENTRY_MADDR(l3_entry);
  5018. +
  5019. + for(j = 0; j < 512; j++) {
  5020. + temporarily_map(l2_table_base, 0);
  5021. + l2_entry = temp_table[j];
  5022. +
  5023. + if(ENTRY_PRESENT(l2_entry)) {
  5024. + pte_t l1_table_base = ENTRY_MADDR(l2_entry);
  5025. +
  5026. + temporarily_map(l1_table_base, 0);
  5027. + for(k = 0; k < 512; k++) {
  5028. + if(ENTRY_PRESENT(temp_table[k])) {
  5029. + if(ENTRY_MADDR(maddr) == ENTRY_MADDR(temp_table[k])) {
  5030. + void *base = BUILD_ADDR(i, j, k);
  5031. + uintptr_t offset = maddr & (PAGE_SIZE-1);
  5032. + return (void*)((uintptr_t)base + offset);
  5033. + }
  5034. + }
  5035. + }
  5036. + }
  5037. + }
  5038. + }
  5039. + }
  5040. +
  5041. + return NULL;
  5042. +}
  5043. +#endif
  5044. diff --git a/rts/xen/vmm_64.c b/rts/xen/vmm_64.c
  5045. new file mode 100644
  5046. index 0000000..50a503a
  5047. --- /dev/null
  5048. +++ b/rts/xen/vmm_64.c
  5049. @@ -0,0 +1,212 @@
  5050. +#ifdef CONFIG_X86_64
  5051. +#include "vmm.h"
  5052. +#include "memory.h"
  5053. +#include <stdio.h>
  5054. +#include <stdlib.h>
  5055. +#include <assert.h>
  5056. +#include <string.h>
  5057. +#include "hypercalls.h"
  5058. +#include "locks.h"
  5059. +#include "smp.h"
  5060. +
  5061. +#include "Rts.h"
  5062. +#include "RtsUtils.h"
  5063. +#include "rts/OSThreads.h"
  5064. +
  5065. +static halvm_mutex_t vmm_lock;
  5066. +// Information regarding the handy temporary space we use
  5067. +static pte_t *temp_table;
  5068. +static maddr_t temp_table_pt_entry;
  5069. +static maddr_t l4_phys_base;
  5070. +// The start of where we've been mapped
  5071. +extern int _text;
  5072. +
  5073. +static inline int mmu_update(uint64_t ptr, uint64_t val)
  5074. +{
  5075. + mmu_update_t update;
  5076. + update.ptr = ptr;
  5077. + update.val = val;
  5078. + return HYPERCALL_mmu_update(&update, 1, NULL, DOMID_SELF) >= 0;
  5079. +}
  5080. +
  5081. +static void temporarily_map(maddr_t maddr, maddr_t flags)
  5082. +{
  5083. + mmuext_op_t flush;
  5084. + int res;
  5085. +
  5086. + flush.cmd = MMUEXT_INVLPG_LOCAL;
  5087. + flush.arg1.linear_addr = (unsigned long)temp_table;
  5088. + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
  5089. +
  5090. + res = mmu_update(temp_table_pt_entry,
  5091. + ENTRY_MADDR(maddr)|PG_PRESENT|PG_USER|flags);
  5092. + if(res <= 0) {
  5093. + assert(*(void**)(0));
  5094. + }
  5095. +
  5096. +}
  5097. +
  5098. +void *initialize_vmm(start_info_t *sinfo, void *init_sp)
  5099. +{
  5100. + uintptr_t l4vb_off = (uintptr_t)sinfo->pt_base - (uintptr_t)&_text;
  5101. + uintptr_t l4vb_poff = l4vb_off >> PAGE_SHIFT;
  5102. + pte_t *l4_virt_base = (pte_t*)sinfo->pt_base;
  5103. + pte_t *table, entry;
  5104. + mfn_t mfn;
  5105. + pfn_t pfn;
  5106. +
  5107. + l4_phys_base = p2m_map[l4vb_poff] << PAGE_SHIFT;
  5108. + // Figure out where the temporary table's page table entry is.
  5109. + temp_table = init_sp;
  5110. + entry = l4_virt_base[VADDR_L4_IDX(temp_table)];
  5111. + mfn = entry >> PAGE_SHIFT;
  5112. + pfn = machine_to_phys_mapping[mfn];
  5113. + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L3
  5114. + entry = table[VADDR_L3_IDX(temp_table)];
  5115. + mfn = entry >> PAGE_SHIFT;
  5116. + pfn = machine_to_phys_mapping[mfn];
  5117. + table = (pte_t*)((uintptr_t)&_text + (pfn << PAGE_SHIFT)); // L2
  5118. + entry = table[VADDR_L2_IDX(temp_table)];
  5119. + temp_table_pt_entry = ENTRY_MADDR(entry) + (8 * VADDR_L1_IDX(temp_table));
  5120. + initMutex(&vmm_lock);
  5121. + return (void*)((uintptr_t)init_sp + PAGE_SIZE);
  5122. +}
  5123. +
  5124. +static pte_t create_table_entry(maddr_t table_base, int idx, int level)
  5125. +{
  5126. + mfn_t mfn = get_free_frame();
  5127. + mmuext_op_t extreq;
  5128. + pte_t retval;
  5129. +
  5130. + assert(mfn);
  5131. +
  5132. + /* clear the new page table */
  5133. + temporarily_map(mfn << PAGE_SHIFT, PG_READWRITE);
  5134. + memset(temp_table, 0, PAGE_SIZE);
  5135. +
  5136. + /* unmap it; we can't have any writable links mapped */
  5137. + assert(mmu_update(temp_table_pt_entry, 0));
  5138. +
  5139. + /* pin it */
  5140. + extreq.cmd = level;
  5141. + extreq.arg1.mfn = mfn;
  5142. + assert(HYPERCALL_mmuext_op(&extreq, 1, NULL, DOMID_SELF) >= 0);
  5143. +
  5144. + /* write in the value */
  5145. + retval = (mfn << PAGE_SHIFT) | PG_USER | PG_PRESENT | PG_READWRITE;
  5146. + assert(mmu_update(table_base + (sizeof(pte_t) * idx), retval));
  5147. +
  5148. + return retval;
  5149. +}
  5150. +
  5151. +pte_t get_pt_entry(void *addr)
  5152. +{
  5153. + pte_t entry;
  5154. +
  5155. + halvm_acquire_lock(&vmm_lock);
  5156. + temporarily_map(l4_phys_base, 0);
  5157. + entry = temp_table[VADDR_L4_IDX(addr)];
  5158. + if(ENTRY_PRESENT(entry)) {
  5159. + temporarily_map(ENTRY_MADDR(entry), 0);
  5160. + entry = temp_table[VADDR_L3_IDX(addr)];
  5161. + if(ENTRY_PRESENT(entry)) {
  5162. + temporarily_map(ENTRY_MADDR(entry), 0);
  5163. + entry = temp_table[VADDR_L2_IDX(addr)];
  5164. + if(ENTRY_PRESENT(entry)) {
  5165. + pte_t retval;
  5166. +
  5167. + temporarily_map(ENTRY_MADDR(entry), 0);
  5168. + retval = temp_table[VADDR_L1_IDX(addr)];
  5169. + halvm_release_lock(&vmm_lock);
  5170. + return retval;
  5171. + }
  5172. + }
  5173. + }
  5174. +
  5175. + halvm_release_lock(&vmm_lock);
  5176. + return 0;
  5177. +}
  5178. +
  5179. +void set_pt_entry(void *addr, pte_t val)
  5180. +{
  5181. + pte_t l4ent, l3ent, l2ent;
  5182. +
  5183. + halvm_acquire_lock(&vmm_lock);
  5184. + temporarily_map(l4_phys_base, 0);
  5185. + l4ent = temp_table[VADDR_L4_IDX(addr)];
  5186. + if(!ENTRY_PRESENT(l4ent)) {
  5187. + l4ent = create_table_entry(l4_phys_base, VADDR_L4_IDX(addr),
  5188. + MMUEXT_PIN_L3_TABLE);
  5189. + }
  5190. +
  5191. + temporarily_map(ENTRY_MADDR(l4ent), 0);
  5192. + l3ent = temp_table[VADDR_L3_IDX(addr)];
  5193. + if(!ENTRY_PRESENT(l3ent)) {
  5194. + l3ent = create_table_entry(ENTRY_MADDR(l4ent), VADDR_L3_IDX(addr),
  5195. + MMUEXT_PIN_L2_TABLE);
  5196. + }
  5197. +
  5198. + temporarily_map(ENTRY_MADDR(l3ent), 0);
  5199. + l2ent = temp_table[VADDR_L2_IDX(addr)];
  5200. + if(!ENTRY_PRESENT(l2ent)) {
  5201. + l2ent = create_table_entry(ENTRY_MADDR(l3ent), VADDR_L2_IDX(addr),
  5202. + MMUEXT_PIN_L1_TABLE);
  5203. + }
  5204. + assert(mmu_update(ENTRY_MADDR(l2ent)+(VADDR_L1_IDX(addr)*sizeof(pte_t)),val));
  5205. + halvm_release_lock(&vmm_lock);
  5206. +
  5207. + /* if(ENTRY_PRESENT(val)) { */
  5208. + mmuext_op_t flush;
  5209. + flush.cmd = MMUEXT_INVLPG_ALL;
  5210. + flush.arg1.linear_addr = (unsigned long)addr;
  5211. + assert(HYPERCALL_mmuext_op(&flush, 1, NULL, DOMID_SELF) >= 0);
  5212. + /* } */
  5213. +}
  5214. +
  5215. +void *machine_to_virtual(uint64_t maddr)
  5216. +{
  5217. + pte_t l4_entry, l3_entry, l2_entry;
  5218. + int i, j, k, l;
  5219. +
  5220. + for(i = 0; i < 512; i++) {
  5221. + if(i == VADDR_L4_IDX(HYPERVISOR_VIRT_START))
  5222. + i = VADDR_L4_IDX(HYPERVISOR_VIRT_END);
  5223. +
  5224. + temporarily_map(l4_phys_base, 0);
  5225. + l4_entry = temp_table[i];
  5226. + if(ENTRY_PRESENT(l4_entry)) {
  5227. + pte_t l3_table_base = ENTRY_MADDR(l4_entry);
  5228. +
  5229. + for(j = 0; j < 512; j++) {
  5230. + temporarily_map(l3_table_base, 0);
  5231. + l3_entry = temp_table[j];
  5232. +
  5233. + if(ENTRY_PRESENT(l3_entry)) {
  5234. + pte_t l2_table_base = ENTRY_MADDR(l3_entry);
  5235. +
  5236. + for(k = 0; k < 512; k++) {
  5237. + temporarily_map(l2_table_base, 0);
  5238. + l2_entry = temp_table[k];
  5239. +
  5240. + if(ENTRY_PRESENT(l2_entry)) {
  5241. + pte_t l1_table_base = ENTRY_MADDR(l2_entry);
  5242. +
  5243. + temporarily_map(l1_table_base, 0);
  5244. + for(l = 0; l < 512; l++) {
  5245. + if(ENTRY_PRESENT(temp_table[l]))
  5246. + if(ENTRY_MADDR(maddr) == ENTRY_MADDR(temp_table[l])) {
  5247. + void *base = BUILD_ADDR(i, j, k, l);
  5248. + uintptr_t offset = maddr & (PAGE_SIZE-1);
  5249. + return (void*)((uintptr_t)base + offset);
  5250. + }
  5251. + }
  5252. + }
  5253. + }
  5254. + }
  5255. + }
  5256. + }
  5257. + }
  5258. +
  5259. + return NULL;
  5260. +}
  5261. +#endif
  5262. diff --git a/rules/build-package-way.mk b/rules/build-package-way.mk
  5263. index 294e432..413de9d 100644
  5264. --- a/rules/build-package-way.mk
  5265. +++ b/rules/build-package-way.mk
  5266. @@ -94,7 +94,7 @@ $$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS) $$(ALL_RTS_LIBS) $$($1_$2_$3_DEPS_LIBS)
  5267. endif
  5268. else
  5269. # Build the ordinary .a library
  5270. -$$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS)
  5271. +$$($1_$2_$3_LIB) : $$($1_$2_$3_ALL_OBJS) $$($1_$2_$3_DEPS_LIBS)
  5272. $$(call removeFiles,$$@ $$@.contents)
  5273. ifeq "$$($1_$2_SplitObjs)" "YES"
  5274. $$(FIND) $$(patsubst %.$$($3_osuf),%_$$($3_osuf)_split,$$($1_$2_$3_HS_OBJS)) -name '*.$$($3_osuf)' -print >> $$@.contents
  5275. diff --git a/rules/build-package.mk b/rules/build-package.mk
  5276. index 34997cc..d6f81a4 100644
  5277. --- a/rules/build-package.mk
  5278. +++ b/rules/build-package.mk
  5279. @@ -28,7 +28,14 @@
  5280. # libraries/base_dist_CC_OPTS = -Iinclude ...
  5281. # libraries/base_dist_LD_OPTS = -package ghc-prim-0.1.0.0
  5282.  
  5283. +
  5284. +# Stage1Only => ("compiler" => stage == 0) \/ (stage == 0 \/ stage == 1)
  5285. +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)
  5286. +
  5287. define build-package
  5288. +
  5289. +ifeq "$$(call build-package-cond,$1,$3)" "YES"
  5290. +
  5291. $(call trace, build-package($1,$2,$3))
  5292. $(call profStart, build-package($1,$2,$3))
  5293. # $1 = dir
  5294. @@ -52,6 +59,9 @@ ifneq "$$($1_$2_NOT_NEEDED)" "YES"
  5295. $$(eval $$(call build-package-helper,$1,$2,$3))
  5296. endif
  5297. $(call profEnd, build-package($1,$2,$3))
  5298. +
  5299. +endif
  5300. +
  5301. endef
  5302.  
  5303.  
  5304. diff --git a/rules/build-prog.mk b/rules/build-prog.mk
  5305. index 399369e..82c854d 100644
  5306. --- a/rules/build-prog.mk
  5307. +++ b/rules/build-prog.mk
  5308. @@ -19,7 +19,15 @@
  5309. #
  5310. # $(eval $(call build-prog,utils/genapply,dist-install,1))
  5311.  
  5312. +str-equal = $(if $(findstring $1,$2),YES)
  5313. +cond-neg = $(if $(call str-equal,$1,YES),,YES)
  5314. +
  5315. +build-cond = $(if $(call str-equal,$(Stage1Only),YES),$(if $(call str-equal,$1,0),YES,NO),YES)
  5316. +
  5317. define build-prog
  5318. +
  5319. +ifeq "$$(call build-cond,$3)" "YES"
  5320. +
  5321. $(call trace, build-prog($1,$2,$3))
  5322. $(call profStart, build-prog($1,$2,$3))
  5323. # $1 = dir
  5324. @@ -48,6 +56,9 @@ ifneq "$$($1_$2_NOT_NEEDED)" "YES"
  5325. $$(eval $$(call build-prog-helper,$1,$2,$3))
  5326. endif
  5327. $(call profEnd, build-prog($1,$2,$3))
  5328. +
  5329. +endif
  5330. +
  5331. endef
  5332.  
  5333.  
  5334. diff --git a/sync-all b/sync-all
  5335. index 4b4b7a3..c9ffd92 100755
  5336. --- a/sync-all
  5337. +++ b/sync-all
  5338. @@ -881,7 +881,7 @@ sub main {
  5339. }
  5340.  
  5341. # check for ghc repositories in cwd
  5342. - my $checked_out_found = 1 if (-d ".git" && -d "compiler");
  5343. + my $checked_out_found = 1 if (-e ".git" && -d "compiler");
  5344. my $bare_found = 1 if (-d "ghc.git");
  5345.  
  5346. if ($bare_flag && ! $bare_found && ! $defaultrepo) {
  5347. diff --git a/utils/runghc/ghc.mk b/utils/runghc/ghc.mk
  5348. index 31bf089..c5f4c21 100644
  5349. --- a/utils/runghc/ghc.mk
  5350. +++ b/utils/runghc/ghc.mk
  5351. @@ -34,10 +34,14 @@ ifeq "$(Windows_Host)" "YES"
  5352. install_runhaskell: install_bins
  5353. "$(CP)" $(DESTDIR)$(bindir)/runghc$(exeext1) $(DESTDIR)$(bindir)/runhaskell$(exeext1)
  5354. else
  5355. +ifeq "$(TargetOS_CPP)" "HaLVM"
  5356. +install_runhaskell:
  5357. +
  5358. +else
  5359. install_runhaskell:
  5360. $(call removeFiles,"$(DESTDIR)$(bindir)/runhaskell")
  5361. $(LN_S) runghc "$(DESTDIR)$(bindir)/runhaskell"
  5362. $(call removeFiles,"$(DESTDIR)$(bindir)/runghc")
  5363. $(LN_S) runghc-$(ProjectVersion) "$(DESTDIR)$(bindir)/runghc"
  5364. endif
  5365. -
  5366. +endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement