/* * Copyright (C) 2018 The Android Open Source Project * * 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 "mem_map.h" #include #include "android-base/logging.h" #include "android-base/stringprintf.h" #include "android-base/mapped_file.h" #ifdef PROT_READ #undef PROT_READ #endif #ifdef PROT_WRITE #undef PROT_WRITE #endif #include "mman.h" namespace art { using android::base::MappedFile; using android::base::StringPrintf; static off_t allocation_granularity; void MemMap::TargetMMapInit() { SYSTEM_INFO si; GetSystemInfo(&si); allocation_granularity = si.dwAllocationGranularity; } void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) { UNUSED(start); size_t padding = fd_off % allocation_granularity; off_t file_offset = fd_off - padding; off_t map_length = len + padding; // Only read and write permissions are supported. if ((prot != PROT_READ) && (prot != (PROT_READ | PROT_WRITE))) { PLOG(ERROR) << "Protection or flag error was not supported."; errno = EINVAL; return MAP_FAILED; } // Fixed is not currently supported either. // TODO(sehr): add MAP_FIXED support. if ((flags & MAP_FIXED) != 0) { PLOG(ERROR) << "MAP_FIXED not supported."; errno = EINVAL; return MAP_FAILED; } // Compute the Windows access flags for the two APIs from the PROTs and MAPs. DWORD map_access = 0; DWORD view_access = 0; if ((prot & PROT_WRITE) != 0) { map_access = PAGE_READWRITE; if (((flags & MAP_SHARED) != 0) && ((flags & MAP_PRIVATE) == 0)) { view_access = FILE_MAP_ALL_ACCESS; } else if (((flags & MAP_SHARED) == 0) && ((flags & MAP_PRIVATE) != 0)) { view_access = FILE_MAP_COPY | FILE_MAP_READ; } else { PLOG(ERROR) << "MAP_PRIVATE and MAP_SHARED inconsistently set."; errno = EINVAL; return MAP_FAILED; } } else { map_access = PAGE_READONLY; view_access = FILE_MAP_READ; } // MapViewOfFile does not like to see a size greater than the file size of the // underlying file object, unless the underlying file object is writable. If // the mapped region would go beyond the end of the underlying file, use zero, // as this indicates the physical size. HANDLE file_handle = reinterpret_cast(_get_osfhandle(fd)); LARGE_INTEGER file_length; if (!::GetFileSizeEx(file_handle, &file_length)) { PLOG(ERROR) << "Couldn't get file size."; errno = EINVAL; return MAP_FAILED; } if (((map_access & PAGE_READONLY) != 0) && file_offset + map_length > file_length.QuadPart) { map_length = 0; } // Create a file mapping object that will be used to access the file. HANDLE handle = ::CreateFileMapping(reinterpret_cast(_get_osfhandle(fd)), nullptr, map_access, 0, 0, nullptr); if (handle == nullptr) { DWORD error = ::GetLastError(); PLOG(ERROR) << StringPrintf("Couldn't create file mapping %lx.", error); errno = EINVAL; return MAP_FAILED; } // Map the file into the process address space. DWORD offset_low = static_cast(file_offset & 0xffffffffU); #ifdef _WIN64 DWORD offset_high = static_cast(file_offset >> 32); #else DWORD offset_high = static_cast(0); #endif void* view_address = MapViewOfFile(handle, view_access, offset_high, offset_low, map_length); if (view_address == nullptr) { DWORD error = ::GetLastError(); PLOG(ERROR) << StringPrintf("Couldn't create file view %lx.", error); ::CloseHandle(handle); errno = EINVAL; return MAP_FAILED; } return view_address; } int MemMap::TargetMUnmap(void* start, size_t len) { // TODO(sehr): implement unmap. UNUSED(start); UNUSED(len); return 0; } } // namespace art