-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fuchsia] Implement PageAllocator APIs using VMOs instead of mmap().
Memory is implicitly allocated/deallocated in response to mmap() and munmap() calls when working with MAP_ANONYMOUS mmaps. Fuchsia's Zircon kernel separates reservation of address space through Virtual Memory Address Ranges (VMARs) from allocation of pages through Virtual Memory Objects (VMOs). This implementation creates and maps a new VMO for each call to SystemAllocPagesInternal(). Each of these VMOs has is named based on the PageTag of the subsystem (e.g. V8, Blink) making the allocation, making it easier to identify which subsystems are consuming memory. DecommitSystemPagesInternal() will be implemented once Fuchsia provides the vmar_op_range(DECOMMIT) API. Bug: 927411 Change-Id: Ie7966f9dcf487e308326e940ca3941c0f87487f4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1859677 Reviewed-by: Chris Palmer <palmer@chromium.org> Reviewed-by: Wez <wez@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Commit-Queue: Wez <wez@chromium.org> Cr-Commit-Position: refs/heads/master@{#711960}
- Loading branch information
Wez
authored and
Commit Bot
committed
Nov 2, 2019
1 parent
c416e43
commit 7fcb6fe
Showing
4 changed files
with
199 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
// Copyright 2019 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// | ||
// This file implements memory allocation primitives for PageAllocator using | ||
// Fuchsia's VMOs (Virtual Memory Objects). VMO API is documented in | ||
// https://fuchsia.dev/fuchsia-src/zircon/objects/vm_object . A VMO is a kernel | ||
// object that corresponds to a set of memory pages. VMO pages may be mapped | ||
// to an address space. The code below creates VMOs for each memory allocations | ||
// and maps them to the default address space of the current process. | ||
|
||
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_FUCHSIA_H_ | ||
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_FUCHSIA_H_ | ||
|
||
#include <lib/zx/vmar.h> | ||
#include <lib/zx/vmo.h> | ||
|
||
#include "base/allocator/partition_allocator/page_allocator.h" | ||
#include "base/fuchsia/fuchsia_logging.h" | ||
#include "base/logging.h" | ||
|
||
namespace base { | ||
|
||
namespace { | ||
|
||
// Returns VMO name for a PageTag. | ||
const char* PageTagToName(PageTag tag) { | ||
switch (tag) { | ||
case PageTag::kBlinkGC: | ||
return "cr_blink_gc"; | ||
case PageTag::kPartitionAlloc: | ||
return "cr_partition_alloc"; | ||
case PageTag::kChromium: | ||
return "cr_chromium"; | ||
case PageTag::kV8: | ||
return "cr_v8"; | ||
default: | ||
DCHECK(false); | ||
return ""; | ||
} | ||
} | ||
|
||
zx_vm_option_t PageAccessibilityToZxVmOptions( | ||
PageAccessibilityConfiguration accessibility) { | ||
switch (accessibility) { | ||
case PageRead: | ||
return ZX_VM_PERM_READ; | ||
case PageReadWrite: | ||
return ZX_VM_PERM_READ | ZX_VM_PERM_WRITE; | ||
case PageReadExecute: | ||
return ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE; | ||
case PageReadWriteExecute: | ||
return ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE; | ||
default: | ||
NOTREACHED(); | ||
FALLTHROUGH; | ||
case PageInaccessible: | ||
return 0; | ||
} | ||
} | ||
|
||
} // namespace | ||
|
||
// zx_vmar_map() will fail if the VMO cannot be mapped at |vmar_offset|, i.e. | ||
// |hint| is not advisory. | ||
constexpr bool kHintIsAdvisory = false; | ||
|
||
std::atomic<int32_t> s_allocPageErrorCode{0}; | ||
|
||
void* SystemAllocPagesInternal(void* hint, | ||
size_t length, | ||
PageAccessibilityConfiguration accessibility, | ||
PageTag page_tag, | ||
bool commit) { | ||
zx::vmo vmo; | ||
zx_status_t status = zx::vmo::create(length, 0, &vmo); | ||
if (status != ZX_OK) { | ||
ZX_DLOG(INFO, status) << "zx_vmo_create"; | ||
return nullptr; | ||
} | ||
|
||
const char* vmo_name = PageTagToName(page_tag); | ||
status = vmo.set_property(ZX_PROP_NAME, vmo_name, strlen(vmo_name)); | ||
|
||
// VMO names are used only for debugging, so failure to set a name is not | ||
// fatal. | ||
ZX_DCHECK(status == ZX_OK, status); | ||
|
||
if (page_tag == PageTag::kV8) { | ||
// V8 uses JIT. Call zx_vmo_replace_as_executable() to allow code execution | ||
// in the new VMO. | ||
status = vmo.replace_as_executable(zx::handle(), &vmo); | ||
if (status != ZX_OK) { | ||
ZX_DLOG(INFO, status) << "zx_vmo_replace_as_executable"; | ||
return nullptr; | ||
} | ||
} | ||
|
||
zx_vm_option_t options = PageAccessibilityToZxVmOptions(accessibility); | ||
|
||
uint64_t vmar_offset = 0; | ||
if (hint) { | ||
vmar_offset = reinterpret_cast<uint64_t>(hint); | ||
options |= ZX_VM_SPECIFIC; | ||
} | ||
|
||
uint64_t address; | ||
status = | ||
zx::vmar::root_self()->map(vmar_offset, vmo, | ||
/*vmo_offset=*/0, length, options, &address); | ||
if (status != ZX_OK) { | ||
ZX_DLOG(INFO, status) << "zx_vmar_map"; | ||
return nullptr; | ||
} | ||
|
||
return reinterpret_cast<void*>(address); | ||
} | ||
|
||
void* TrimMappingInternal(void* base, | ||
size_t base_length, | ||
size_t trim_length, | ||
PageAccessibilityConfiguration accessibility, | ||
bool commit, | ||
size_t pre_slack, | ||
size_t post_slack) { | ||
DCHECK_EQ(base_length, trim_length + pre_slack + post_slack); | ||
|
||
uint64_t base_address = reinterpret_cast<uint64_t>(base); | ||
|
||
// Unmap head if necessary. | ||
if (pre_slack) { | ||
zx_status_t status = zx::vmar::root_self()->unmap(base_address, pre_slack); | ||
ZX_CHECK(status == ZX_OK, status); | ||
} | ||
|
||
// Unmap tail if necessary. | ||
if (post_slack) { | ||
zx_status_t status = zx::vmar::root_self()->unmap( | ||
base_address + pre_slack + trim_length, post_slack); | ||
ZX_CHECK(status == ZX_OK, status); | ||
} | ||
|
||
return reinterpret_cast<void*>(base_address + pre_slack); | ||
} | ||
|
||
bool TrySetSystemPagesAccessInternal( | ||
void* address, | ||
size_t length, | ||
PageAccessibilityConfiguration accessibility) { | ||
zx_status_t status = zx::vmar::root_self()->protect( | ||
reinterpret_cast<uint64_t>(address), length, | ||
PageAccessibilityToZxVmOptions(accessibility)); | ||
return status == ZX_OK; | ||
} | ||
|
||
void SetSystemPagesAccessInternal( | ||
void* address, | ||
size_t length, | ||
PageAccessibilityConfiguration accessibility) { | ||
zx_status_t status = zx::vmar::root_self()->protect( | ||
reinterpret_cast<uint64_t>(address), length, | ||
PageAccessibilityToZxVmOptions(accessibility)); | ||
ZX_CHECK(status == ZX_OK, status); | ||
} | ||
|
||
void FreePagesInternal(void* address, size_t length) { | ||
uint64_t address_int = reinterpret_cast<uint64_t>(address); | ||
zx_status_t status = zx::vmar::root_self()->unmap(address_int, length); | ||
ZX_CHECK(status == ZX_OK, status); | ||
} | ||
|
||
void DecommitSystemPagesInternal(void* address, size_t length) { | ||
DiscardSystemPages(address, length); | ||
SetSystemPagesAccessInternal(address, length, PageInaccessible); | ||
} | ||
|
||
bool RecommitSystemPagesInternal(void* address, | ||
size_t length, | ||
PageAccessibilityConfiguration accessibility) { | ||
SetSystemPagesAccessInternal(address, length, accessibility); | ||
return true; | ||
} | ||
|
||
void DiscardSystemPagesInternal(void* address, size_t length) { | ||
NOTIMPLEMENTED_LOG_ONCE(); | ||
} | ||
|
||
} // namespace base | ||
|
||
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_FUCHSIA_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters