1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/FlushICache.h"
9 #ifdef JS_CODEGEN_ARM64
10 # include "jit/arm64/vixl/MozCachingDecoder.h"
11 # include "jit/arm64/vixl/Simulator-vixl.h"
14 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
17 # include <linux/version.h>
18 # define LINUX_HAS_MEMBARRIER (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
20 # define LINUX_HAS_MEMBARRIER 0
23 # if LINUX_HAS_MEMBARRIER || defined(__android__)
26 # if LINUX_HAS_MEMBARRIER
27 # include <linux/membarrier.h>
28 # include <sys/syscall.h>
29 # include <sys/utsname.h>
31 # elif defined(__android__)
32 # include <sys/syscall.h>
35 # error "Missing platform-specific declarations for membarrier syscall!"
36 # endif // __linux__ / ANDROID
38 static int membarrier(int cmd
, int flags
) {
39 return syscall(__NR_membarrier
, cmd
, flags
);
42 // These definitions come from the Linux kernel source, for kernels before 4.16
43 // which didn't have access to these membarrier commands.
44 # ifndef MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
45 # define MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE (1 << 5)
48 # ifndef MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
49 # define MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE (1 << 6)
51 # endif // LINUX_HAS_MEMBARRIER || defined(__android__)
54 using namespace js::jit
;
59 bool CanFlushExecutionContextForAllThreads() {
60 # if (LINUX_HAS_MEMBARRIER || defined(__android__))
61 // On linux, check the kernel supports membarrier(2), that is, it's a kernel
62 // above Linux 4.16 included.
64 // Note: this code has been extracted (August 2020) from
65 // https://android.googlesource.com/platform/art/+/58520dfba31d6eeef75f5babff15e09aa28e5db8/libartbase/base/membarrier.cc#50
66 static constexpr int kRequiredMajor
= 4;
67 static constexpr int kRequiredMinor
= 16;
69 static bool computed
= false;
70 static bool kernelHasMembarrier
= false;
73 return kernelHasMembarrier
;
78 kernelHasMembarrier
= uname(&uts
) == 0 && strcmp(uts
.sysname
, "Linux") == 0 &&
79 sscanf(uts
.release
, "%d.%d", &major
, &minor
) == 2 &&
80 major
>= kRequiredMajor
&&
81 (major
!= kRequiredMajor
|| minor
>= kRequiredMinor
);
83 // As a test bed, try to run the syscall with the command registering the
84 // intent to use the actual membarrier we'll want to carry out later.
86 // IMPORTANT: This is required or else running the membarrier later won't
87 // actually interrupt the threads in this process.
88 if (kernelHasMembarrier
&&
89 membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE
, 0) != 0) {
90 kernelHasMembarrier
= false;
94 return kernelHasMembarrier
;
96 // On other platforms, we assume that the syscall for flushing the icache
97 // will flush the execution context for other cores.
102 void FlushExecutionContextForAllThreads() {
103 // Callers must check that this operation is available.
104 MOZ_RELEASE_ASSERT(CanFlushExecutionContextForAllThreads());
106 # if defined(JS_SIMULATOR_ARM64) && defined(JS_CACHE_SIMULATOR_ARM64)
107 // Emulate what the real hardware would do by emitting a membarrier that'll
108 // interrupt and flush the execution context of all threads.
109 using js::jit::SimulatorProcess
;
110 js::jit::AutoLockSimulatorCache alsc
;
111 SimulatorProcess::membarrier();
112 # elif (LINUX_HAS_MEMBARRIER || defined(__android__))
113 // The caller has checked this can be performed, which will have registered
114 // this process to receive the membarrier. See above.
116 // membarrier will trigger an inter-processor-interrupt on any active threads
117 // of this process. This is an execution context synchronization event
118 // equivalent to running an `isb` instruction.
119 if (membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
, 0) != 0) {
120 // Better safe than sorry.
121 MOZ_CRASH("membarrier can't be executed");
124 // On other platforms, we assume that the syscall for flushing the icache
125 // will flush the execution context for other cores.