Use kernel cacheflush for large sizes on MIPS.
This is a workaround to a deserializer bug. The bug was exposed
with a recent optimization to use user-mode cache-flushing on
MIPS. To reduce risk, we're doing a workaround in mips-specific
code so that other arch's cannot be affected.
The deserializer does this FlushICache:
CPU::FlushICache(last_object_address_, Page::kPageSize);
However, that region includes OS guard-pages with no access
privilege. The MIPS kernel cacheflush routines work OK in this
case, but the Bionic cacheflush recently enabled user-mode flushing
using the synci instruction, which causes a segfault on MIPS when
the guard pages are reached.
(change I48fd6f2b0cbe80c3cd90f453ced97a2f154f7ad3)
The workaround just reverts to the kernel flush when the size
is Page::kPageSize or bigger.
A better fix would be to alter the deserializer so that only the
executable pages are flushed:
CPU::FlushICache(last_object_address_,
isolate_->memory_allocator()->CodePageAreaSize());
However, that changes common code for all supported architectures.
There is no evidence that this bug affects the other arch's, so we
are doing a MIPS-specific workaround.
(cherry-pick from AOSP)
bug: 8851838
Change-Id: I30b62eb579feab1453d3ae85a5fb9b408f91756b
Signed-off-by: Paul Lind <paul.lind@imgtec.com>
diff --git a/src/mips/cpu-mips.cc b/src/mips/cpu-mips.cc
index 93ebeda..b820000 100644
--- a/src/mips/cpu-mips.cc
+++ b/src/mips/cpu-mips.cc
@@ -65,10 +65,23 @@
#if !defined (USE_SIMULATOR)
#if defined(ANDROID)
- // Bionic cacheflush can typically run in userland, avoiding kernel call.
- char *end = reinterpret_cast<char *>(start) + size;
- cacheflush(
- reinterpret_cast<intptr_t>(start), reinterpret_cast<intptr_t>(end), 0);
+ // Workaround for a deserializer bug. Bionic usermode cacheflush
+ // fails in deserializer for a size of Page::kPageSize (1MB),
+ // because that region contains protected pages. Switch to kernel
+ // cacheflush in this case.
+ if (size >= static_cast<size_t>(Page::kPageSize)) {
+ int res;
+ // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
+ res = syscall(__NR_cacheflush, start, size, ICACHE);
+ if (res) {
+ V8_Fatal(__FILE__, __LINE__, "Failed to flush the instruction cache");
+ }
+ } else {
+ // Bionic cacheflush can typically run in userland, avoiding kernel call.
+ char *end = reinterpret_cast<char *>(start) + size;
+ cacheflush(
+ reinterpret_cast<intptr_t>(start), reinterpret_cast<intptr_t>(end), 0);
+ }
#else // ANDROID
int res;
// See http://www.linux-mips.org/wiki/Cacheflush_Syscall.