Path: blob/master/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp
40971 views
/*1* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "gc/shared/gcLogPrecious.hpp"25#include "gc/z/zErrno.hpp"26#include "gc/z/zGlobals.hpp"27#include "gc/z/zLargePages.inline.hpp"28#include "gc/z/zPhysicalMemory.inline.hpp"29#include "gc/z/zPhysicalMemoryBacking_bsd.hpp"30#include "logging/log.hpp"31#include "runtime/globals.hpp"32#include "runtime/os.hpp"33#include "utilities/align.hpp"34#include "utilities/debug.hpp"3536#include <mach/mach.h>37#include <mach/mach_vm.h>38#include <sys/mman.h>39#include <sys/types.h>4041// The backing is represented by a reserved virtual address space, in which42// we commit and uncommit physical memory. Multi-mapping the different heap43// views is done by simply remapping the backing memory using mach_vm_remap().4445static int vm_flags_superpage() {46if (!ZLargePages::is_explicit()) {47return 0;48}4950const int page_size_in_megabytes = ZGranuleSize >> 20;51return page_size_in_megabytes << VM_FLAGS_SUPERPAGE_SHIFT;52}5354static ZErrno mremap(uintptr_t from_addr, uintptr_t to_addr, size_t size) {55mach_vm_address_t remap_addr = to_addr;56vm_prot_t remap_cur_prot;57vm_prot_t remap_max_prot;5859// Remap memory to an additional location60const kern_return_t res = mach_vm_remap(mach_task_self(),61&remap_addr,62size,630 /* mask */,64VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | vm_flags_superpage(),65mach_task_self(),66from_addr,67FALSE /* copy */,68&remap_cur_prot,69&remap_max_prot,70VM_INHERIT_COPY);7172return (res == KERN_SUCCESS) ? ZErrno(0) : ZErrno(EINVAL);73}7475ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) :76_base(0),77_initialized(false) {7879// Reserve address space for backing memory80_base = (uintptr_t)os::reserve_memory(max_capacity);81if (_base == 0) {82// Failed83log_error_pd(gc)("Failed to reserve address space for backing memory");84return;85}8687// Successfully initialized88_initialized = true;89}9091bool ZPhysicalMemoryBacking::is_initialized() const {92return _initialized;93}9495void ZPhysicalMemoryBacking::warn_commit_limits(size_t max_capacity) const {96// Does nothing97}9899bool ZPhysicalMemoryBacking::commit_inner(size_t offset, size_t length) const {100assert(is_aligned(offset, os::vm_page_size()), "Invalid offset");101assert(is_aligned(length, os::vm_page_size()), "Invalid length");102103log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",104offset / M, (offset + length) / M, length / M);105106const uintptr_t addr = _base + offset;107const void* const res = mmap((void*)addr, length, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);108if (res == MAP_FAILED) {109ZErrno err;110log_error(gc)("Failed to commit memory (%s)", err.to_string());111return false;112}113114// Success115return true;116}117118size_t ZPhysicalMemoryBacking::commit(size_t offset, size_t length) const {119// Try to commit the whole region120if (commit_inner(offset, length)) {121// Success122return length;123}124125// Failed, try to commit as much as possible126size_t start = offset;127size_t end = offset + length;128129for (;;) {130length = align_down((end - start) / 2, ZGranuleSize);131if (length == 0) {132// Done, don't commit more133return start - offset;134}135136if (commit_inner(start, length)) {137// Success, try commit more138start += length;139} else {140// Failed, try commit less141end -= length;142}143}144}145146size_t ZPhysicalMemoryBacking::uncommit(size_t offset, size_t length) const {147assert(is_aligned(offset, os::vm_page_size()), "Invalid offset");148assert(is_aligned(length, os::vm_page_size()), "Invalid length");149150log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",151offset / M, (offset + length) / M, length / M);152153const uintptr_t start = _base + offset;154const void* const res = mmap((void*)start, length, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);155if (res == MAP_FAILED) {156ZErrno err;157log_error(gc)("Failed to uncommit memory (%s)", err.to_string());158return 0;159}160161return length;162}163164void ZPhysicalMemoryBacking::map(uintptr_t addr, size_t size, uintptr_t offset) const {165const ZErrno err = mremap(_base + offset, addr, size);166if (err) {167fatal("Failed to remap memory (%s)", err.to_string());168}169}170171void ZPhysicalMemoryBacking::unmap(uintptr_t addr, size_t size) const {172// Note that we must keep the address space reservation intact and just detach173// the backing memory. For this reason we map a new anonymous, non-accessible174// and non-reserved page over the mapping instead of actually unmapping.175const void* const res = mmap((void*)addr, size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);176if (res == MAP_FAILED) {177ZErrno err;178fatal("Failed to map memory (%s)", err.to_string());179}180}181182183