5#include <fidl/fuchsia.kernel/cpp/fidl.h>
6#include <lib/component/incoming/cpp/protocol.h>
7#include <lib/zx/resource.h>
8#include <lib/zx/thread.h>
9#include <lib/zx/vmar.h>
10#include <lib/zx/vmo.h>
25static zx_handle_t g_vmex_resource = ZX_HANDLE_INVALID;
27static void* g_root_vmar_base =
nullptr;
31void SetVmexResource() {
32 DCHECK_EQ(g_vmex_resource, ZX_HANDLE_INVALID);
34 auto vmex_resource_client =
35 component::Connect<fuchsia_kernel::VmexResource>();
36 if (vmex_resource_client.is_error()) {
40 fidl::SyncClient sync_vmex_resource_client(
41 std::move(vmex_resource_client.value()));
42 auto result = sync_vmex_resource_client->Get();
47 g_vmex_resource =
result->resource().release();
56 return ZX_VM_PERM_READ;
58 return ZX_VM_PERM_READ | ZX_VM_PERM_WRITE;
60 return ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE;
62 return ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE;
69zx_vm_option_t GetAlignmentOptionFromAlignment(
size_t alignment) {
73 ZX_VM_ALIGN_1KB == (10 << ZX_VM_ALIGN_BASE),
74 "Fuchsia's ZX_VM_ALIGN_1KB constant doesn't match expected value");
76 ZX_VM_ALIGN_4GB == (32 << ZX_VM_ALIGN_BASE),
77 "Fuchsia's ZX_VM_ALIGN_4GB constant doesn't match expected value");
78 zx_vm_option_t alignment_log2 = 0;
79 for (
int shift = 10; shift <= 32; shift++) {
80 if (alignment == (
size_t{1} << shift)) {
81 alignment_log2 = shift;
85 return alignment_log2 << ZX_VM_ALIGN_BASE;
88enum class PlacementMode {
97void* MapVmo(
const zx::vmar& vmar,
void* vmar_base,
size_t page_size,
98 void* address,
const zx::vmo& vmo, uint64_t
offset,
99 PlacementMode placement,
size_t size,
size_t alignment,
102 DCHECK_EQ(0,
reinterpret_cast<uintptr_t
>(address) % page_size);
103 DCHECK_IMPLIES(placement != PlacementMode::kAnywhere, address !=
nullptr);
107 size_t vmar_offset = 0;
108 if (placement == PlacementMode::kAnywhere) {
109 zx_vm_option_t alignment_option =
110 GetAlignmentOptionFromAlignment(alignment);
111 if (alignment_option == 0) {
116 options |= alignment_option;
118 CHECK_EQ(
reinterpret_cast<intptr_t
>(address) % alignment, 0);
120 uintptr_t target_addr =
reinterpret_cast<uintptr_t
>(address);
121 uintptr_t
base =
reinterpret_cast<uintptr_t
>(vmar_base);
123 vmar_offset = target_addr -
base;
124 options |= ZX_VM_SPECIFIC;
128 zx_status_t status = vmar.map(options, vmar_offset, vmo, 0, size, &
result);
130 if (status == ZX_OK) {
132 return reinterpret_cast<void*
>(
result);
135 if (placement != PlacementMode::kUseHint) {
144 return MapVmo(vmar, vmar_base, page_size,
nullptr, vmo,
offset,
145 PlacementMode::kAnywhere, size, alignment, access);
148void* CreateAndMapVmo(
const zx::vmar& vmar,
void* vmar_base,
size_t page_size,
149 void* address, PlacementMode placement,
size_t size,
152 if (zx::vmo::create(size, 0, &vmo) != ZX_OK) {
155 static const char kVirtualMemoryName[] =
"v8-virtualmem";
156 vmo.set_property(ZX_PROP_NAME, kVirtualMemoryName,
157 strlen(kVirtualMemoryName));
163 zx::unowned_resource vmex(g_vmex_resource);
164 if (vmo.replace_as_executable(*vmex, &vmo) != ZX_OK) {
168 return MapVmo(vmar, vmar_base, page_size, address, vmo, 0, placement, size,
172bool UnmapVmo(
const zx::vmar& vmar,
size_t page_size,
void* address,
174 DCHECK_EQ(0,
reinterpret_cast<uintptr_t
>(address) % page_size);
176 return vmar.unmap(
reinterpret_cast<uintptr_t
>(address), size) == ZX_OK;
179bool SetPermissionsInternal(
const zx::vmar& vmar,
size_t page_size,
180 void* address,
size_t size,
182 DCHECK_EQ(0,
reinterpret_cast<uintptr_t
>(address) % page_size);
186 vmar.protect(prot,
reinterpret_cast<uintptr_t
>(address), size);
194 return status == ZX_OK;
197bool DiscardSystemPagesInternal(
const zx::vmar& vmar,
size_t page_size,
198 void* address,
size_t size) {
199 DCHECK_EQ(0,
reinterpret_cast<uintptr_t
>(address) % page_size);
201 uint64_t address_int =
reinterpret_cast<uint64_t
>(address);
202 return vmar.op_range(ZX_VMO_OP_DECOMMIT, address_int, size,
nullptr, 0) ==
206zx_status_t CreateAddressSpaceReservationInternal(
207 const zx::vmar& vmar,
void* vmar_base,
size_t page_size,
void* address,
208 PlacementMode placement,
size_t size,
size_t alignment,
210 zx_vaddr_t* child_addr) {
213 DCHECK_EQ(0,
reinterpret_cast<uintptr_t
>(address) % alignment);
214 DCHECK_IMPLIES(placement != PlacementMode::kAnywhere, address !=
nullptr);
217 zx_vm_option_t options = ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE |
218 ZX_VM_CAN_MAP_EXECUTE | ZX_VM_CAN_MAP_SPECIFIC;
220 zx_vm_option_t alignment_option = GetAlignmentOptionFromAlignment(alignment);
222 options |= alignment_option;
224 size_t vmar_offset = 0;
225 if (placement != PlacementMode::kAnywhere) {
227 uintptr_t target_addr =
reinterpret_cast<uintptr_t
>(address);
228 uintptr_t
base =
reinterpret_cast<uintptr_t
>(vmar_base);
230 vmar_offset = target_addr -
base;
231 options |= ZX_VM_SPECIFIC;
235 vmar.allocate(options, vmar_offset, size, child, child_addr);
236 if (status != ZX_OK && placement == PlacementMode::kUseHint) {
240 options &= ~(ZX_VM_SPECIFIC);
241 status = vmar.allocate(options, 0, size, child, child_addr);
250 return new PosixDefaultTimezoneCache();
259 zx_status_t status = zx::vmar::root_self()->get_info(
260 ZX_INFO_VMAR, &info,
sizeof(info),
nullptr,
nullptr);
262 g_root_vmar_base =
reinterpret_cast<void*
>(info.base);
268void*
OS::Allocate(
void* address,
size_t size,
size_t alignment,
269 MemoryPermission access) {
270 PlacementMode placement =
271 address !=
nullptr ? PlacementMode::kUseHint : PlacementMode::kAnywhere;
272 return CreateAndMapVmo(*zx::vmar::root_self(), g_root_vmar_base,
278void OS::Free(
void* address,
size_t size) {
286 PlacementMode placement =
287 address !=
nullptr ? PlacementMode::kUseHint : PlacementMode::kAnywhere;
288 zx::unowned_vmo vmo(VMOFromSharedMemoryHandle(handle));
304 return SetPermissionsInternal(*zx::vmar::root_self(),
CommitPageSize(),
305 address, size, access);
319 return DiscardSystemPagesInternal(*zx::vmar::root_self(),
CommitPageSize(),
333bool OS::SealPages(
void* address,
size_t size) {
return false; }
340 void* hint,
size_t size,
size_t alignment,
344 zx_vaddr_t child_addr;
345 PlacementMode placement =
346 hint !=
nullptr ? PlacementMode::kUseHint : PlacementMode::kAnywhere;
347 zx_status_t status = CreateAddressSpaceReservationInternal(
349 placement, size, alignment, max_permission, &child, &child_addr);
350 if (status != ZX_OK)
return {};
358 zx::vmar vmar(reservation.vmar_);
365 if (zx::vmo::create(size, 0, &vmo) != ZX_OK) {
368 return SharedMemoryHandleFromVMO(vmo.release());
374 zx_handle_t vmo = VMOFromSharedMemoryHandle(handle);
375 zx_handle_close(vmo);
390 const auto kNanosPerMicrosecond = 1000ULL;
391 const auto kMicrosPerSecond = 1000000ULL;
393 zx_info_thread_stats_t info = {};
394 if (zx::thread::self()->get_info(ZX_INFO_THREAD_STATS, &info,
sizeof(info),
395 nullptr,
nullptr) != ZX_OK) {
400 const uint64_t micros_since_thread_started =
401 (info.total_runtime + kNanosPerMicrosecond - 1ULL) / kNanosPerMicrosecond;
403 *secs =
static_cast<uint32_t
>(micros_since_thread_started / kMicrosPerSecond);
405 static_cast<uint32_t
>(micros_since_thread_started % kMicrosPerSecond);
417std::optional<AddressSpaceReservation>
423 zx_vaddr_t child_addr;
424 zx_status_t status = CreateAddressSpaceReservationInternal(
427 &child, &child_addr);
428 if (status != ZX_OK)
return {};
429 DCHECK_EQ(
reinterpret_cast<void*
>(child_addr), address);
443 void* allocation = CreateAndMapVmo(
446 DCHECK(!allocation || allocation == address);
447 return allocation !=
nullptr;
461 zx::unowned_vmo vmo(VMOFromSharedMemoryHandle(handle));
463 address, *vmo,
offset, PlacementMode::kFixed, size,
477 address, size, access);
487 return DiscardSystemPagesInternal(*zx::unowned_vmar(vmar_),
V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool Allocate(void *address, size_t size, OS::MemoryPermission access)
bool Contains(void *region_addr, size_t region_size) const
V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, OS::MemoryPermission access)
AddressSpaceReservation(void *base, size_t size)
V8_WARN_UNUSED_RESULT bool Free(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, OS::MemoryPermission access)
V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
V8_WARN_UNUSED_RESULT bool FreeShared(void *address, size_t size)
V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateSubReservation(void *address, size_t size, OS::MemoryPermission max_permission)
V8_WARN_UNUSED_RESULT bool AllocateShared(void *address, size_t size, OS::MemoryPermission access, PlatformSharedMemoryHandle handle, uint64_t offset)
static V8_WARN_UNUSED_RESULT bool FreeSubReservation(AddressSpaceReservation reservation)
static V8_WARN_UNUSED_RESULT void * AllocateShared(size_t size, MemoryPermission access)
static V8_WARN_UNUSED_RESULT bool SealPages(void *address, size_t size)
static void SignalCodeMovingGC()
static bool HasLazyCommits()
static V8_WARN_UNUSED_RESULT bool CanReserveAddressSpace()
static V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
static size_t AllocatePageSize()
static void SetDataReadOnly(void *address, size_t size)
static void FreeAddressSpaceReservation(AddressSpaceReservation reservation)
static PlatformSharedMemoryHandle CreateSharedMemoryHandleForTesting(size_t size)
static void FreeShared(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, MemoryPermission access)
static void Initialize(AbortMode abort_mode, const char *const gc_fake_mmap)
static V8_WARN_UNUSED_RESULT bool DecommitPages(void *address, size_t size)
static size_t CommitPageSize()
static void Release(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, MemoryPermission access)
static std::vector< SharedLibraryAddress > GetSharedLibraryAddresses()
static int GetUserTime(uint32_t *secs, uint32_t *usecs)
static V8_WARN_UNUSED_RESULT void * Allocate(void *address, size_t size, size_t alignment, MemoryPermission access)
static void DestroySharedMemoryHandle(PlatformSharedMemoryHandle handle)
static TimezoneCache * CreateTimezoneCache()
static V8_WARN_UNUSED_RESULT std::optional< AddressSpaceReservation > CreateAddressSpaceReservation(void *hint, size_t size, size_t alignment, MemoryPermission max_permission)
friend class AddressSpaceReservation
static void Free(void *address, size_t size)
static std::optional< MemoryRange > GetFirstFreeMemoryRangeWithin(Address boundary_start, Address boundary_end, size_t minimum_size, size_t alignment)
static void AdjustSchedulingParams()
Handle< SharedFunctionInfo > info
ZoneVector< RpoNumber > & result
int GetProtectionFromMemoryPermission(OS::MemoryPermission access)
void PosixInitializeCommon(AbortMode abort_mode, const char *const gc_fake_mmap)
static constexpr PlatformSharedMemoryHandle kInvalidSharedMemoryHandle
intptr_t PlatformSharedMemoryHandle
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define CHECK_NE(lhs, rhs)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)