| /* |
| * 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 <windows.h> |
| // This include needs to be here due to the coding conventions. Unfortunately |
| // it drags in the definition of the ERROR macro. Similarly to base/utils.cc, |
| // undefine the macro here. See also, the comment at android-base/logging.h. |
| #ifdef ERROR |
| #undef ERROR |
| #endif |
| |
| #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::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<HANDLE>(_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<HANDLE>(_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<DWORD>(file_offset & 0xffffffffU); |
| #ifdef _WIN64 |
| DWORD offset_high = static_cast<DWORD>(file_offset >> 32); |
| #else |
| DWORD offset_high = static_cast<DWORD>(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 |