From 8c7c06b5cdac575f2288290cbad8c757ca078635 Mon Sep 17 00:00:00 2001 From: Paul Lind Date: Mon, 6 May 2013 16:09:29 -0700 Subject: 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 --- src/mips/cpu-mips.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/mips/cpu-mips.cc b/src/mips/cpu-mips.cc index 93ebeda8..b8200007 100644 --- a/src/mips/cpu-mips.cc +++ b/src/mips/cpu-mips.cc @@ -65,10 +65,23 @@ void CPU::FlushICache(void* start, size_t size) { #if !defined (USE_SIMULATOR) #if defined(ANDROID) - // Bionic cacheflush can typically run in userland, avoiding kernel call. - char *end = reinterpret_cast(start) + size; - cacheflush( - reinterpret_cast(start), reinterpret_cast(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(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(start) + size; + cacheflush( + reinterpret_cast(start), reinterpret_cast(end), 0); + } #else // ANDROID int res; // See http://www.linux-mips.org/wiki/Cacheflush_Syscall. -- cgit v1.2.3