* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/platform/map.h"
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "ecmascript/platform/os.h"
namespace panda::ecmascript {
#if defined(PANDA_TARGET_ARM64) && defined(PANDA_TARGET_OHOS)
static long Syscall(unsigned long n, unsigned long a, unsigned long b, unsigned long c, unsigned long d,
unsigned long e, unsigned long f)
{
register unsigned long x8 asm("x8") = n;
register unsigned long x0 asm("x0") = a;
register unsigned long x1 asm("x1") = b;
register unsigned long x2 asm("x2") = c;
register unsigned long x3 asm("x3") = d;
register unsigned long x4 asm("x4") = e;
register unsigned long x5 asm("x5") = f;
asm volatile("svc 0" : "=r"(x0) : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) : "memory", "cc");
return x0;
}
#endif
static inline void *InlineMmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
#if defined(PANDA_TARGET_ARM64) && defined(PANDA_TARGET_OHOS)
long res = Syscall(SYS_mmap, (unsigned long)addr, len, prot, flags, fd, offset);
if (res < 0) {
errno = (int)res;
return MAP_FAILED;
} else {
return (void *)res;
}
#else
return mmap(addr, len, prot, flags, fd, offset);
#endif
}
static inline int InlineMunmap(void *addr, size_t len)
{
#if defined(PANDA_TARGET_ARM64) && defined(PANDA_TARGET_OHOS)
long res = Syscall(SYS_munmap, (unsigned long)addr, len, 0, 0, 0, 0);
if (res < 0) {
errno = (int)res;
}
return (int)res;
#else
return munmap(addr, len);
#endif
}
MemMap PageMap(size_t size, int prot, size_t alignment, void *addr, int flags, bool jitfort)
{
ASSERT(size == AlignUp(size, PageSize()));
ASSERT(alignment == AlignUp(alignment, PageSize()));
size_t allocSize = size + alignment;
int newFlags = static_cast<int>(MAP_PRIVATE | MAP_ANONYMOUS | static_cast<unsigned int>(flags));
void *result =
jitfort ? InlineMmap(addr, allocSize, prot, newFlags, -1, 0) : mmap(addr, allocSize, prot, newFlags, -1, 0);
if (reinterpret_cast<intptr_t>(result) == -1) {
LOG_ECMA(FATAL) << "mmap failed with error code:" << strerror(errno);
}
if (alignment != 0) {
auto alignResult = AlignUp(reinterpret_cast<uintptr_t>(result), alignment);
size_t leftSize = alignResult - reinterpret_cast<uintptr_t>(result);
size_t rightSize = alignment - leftSize;
void *alignEndResult = reinterpret_cast<void *>(alignResult + size);
jitfort ? InlineMunmap(result, leftSize) : munmap(result, leftSize);
jitfort ? InlineMunmap(alignEndResult, rightSize) : munmap(alignEndResult, rightSize);
result = reinterpret_cast<void *>(alignResult);
}
return MemMap(result, size);
}
void PageUnmap(MemMap it, bool jitfort)
{
if (jitfort) {
InlineMunmap(it.GetMem(), it.GetSize());
} else {
munmap(it.GetMem(), it.GetSize());
}
}
MemMap MachineCodePageMap(size_t size, int prot, size_t alignment)
{
MemMap memMap = PageMap(size, prot, alignment);
PageTag(memMap.GetMem(), memMap.GetSize(), PageTagType::MACHINE_CODE);
return memMap;
}
void MachineCodePageUnmap(MemMap it)
{
PageClearTag(it.GetMem(), it.GetSize());
if (!PageProtect(it.GetMem(), it.GetSize(), PAGE_PROT_NONE)) {
return;
}
PageUnmap(it);
}
void PageRelease(void *mem, size_t size)
{
madvise(mem, size, MADV_DONTNEED);
}
void PagePreRead(void *mem, size_t size)
{
madvise(mem, size, MADV_WILLNEED);
}
void PageTag(void *mem, size_t size, PageTagType type, [[maybe_unused]] const std::string &spaceName,
[[maybe_unused]] const uint32_t threadId)
{
#if defined(CROSS_PLATFORM)
const char *tag = GetPageTagString(type);
PrctlSetVMA(mem, size, tag);
#else
const std::string &tag = GetPageTagString(type, spaceName, threadId);
PrctlSetVMA(mem, size, tag.c_str());
#endif
}
void PageClearTag(void *mem, size_t size)
{
PrctlSetVMA(mem, size, nullptr);
}
bool PageProtect(void *mem, size_t size, int prot)
{
int ret = mprotect(mem, size, prot);
if (ret != 0) {
LOG_ECMA(ERROR) << "PageProtect mem = " << mem << ", size = " << size <<
", change to " << prot << " failed, ret = " << ret << ", error code is " << errno;
return false;
}
return true;
}
size_t PageSize()
{
return getpagesize();
}
}