Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "mem_map.h"
     18 
     19 #include <windows.h>
     20 
     21 #include "android-base/logging.h"
     22 #include "android-base/stringprintf.h"
     23 #include "android-base/mapped_file.h"
     24 #ifdef PROT_READ
     25 #undef PROT_READ
     26 #endif
     27 #ifdef PROT_WRITE
     28 #undef PROT_WRITE
     29 #endif
     30 #include "mman.h"
     31 
     32 namespace art {
     33 
     34 using android::base::MappedFile;
     35 using android::base::StringPrintf;
     36 
     37 static off_t allocation_granularity;
     38 
     39 void MemMap::TargetMMapInit() {
     40   SYSTEM_INFO si;
     41   GetSystemInfo(&si);
     42   allocation_granularity = si.dwAllocationGranularity;
     43 }
     44 
     45 void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
     46   UNUSED(start);
     47   size_t padding = fd_off % allocation_granularity;
     48   off_t file_offset = fd_off - padding;
     49   off_t map_length = len + padding;
     50 
     51   // Only read and write permissions are supported.
     52   if ((prot != PROT_READ) && (prot != (PROT_READ | PROT_WRITE))) {
     53     PLOG(ERROR) << "Protection or flag error was not supported.";
     54     errno = EINVAL;
     55     return MAP_FAILED;
     56   }
     57   // Fixed is not currently supported either.
     58   // TODO(sehr): add MAP_FIXED support.
     59   if ((flags & MAP_FIXED) != 0) {
     60     PLOG(ERROR) << "MAP_FIXED not supported.";
     61     errno = EINVAL;
     62     return MAP_FAILED;
     63   }
     64 
     65   // Compute the Windows access flags for the two APIs from the PROTs and MAPs.
     66   DWORD map_access = 0;
     67   DWORD view_access = 0;
     68   if ((prot & PROT_WRITE) != 0) {
     69     map_access = PAGE_READWRITE;
     70     if (((flags & MAP_SHARED) != 0) && ((flags & MAP_PRIVATE) == 0)) {
     71       view_access = FILE_MAP_ALL_ACCESS;
     72     } else if (((flags & MAP_SHARED) == 0) && ((flags & MAP_PRIVATE) != 0)) {
     73       view_access = FILE_MAP_COPY | FILE_MAP_READ;
     74     } else {
     75       PLOG(ERROR) << "MAP_PRIVATE and MAP_SHARED inconsistently set.";
     76       errno = EINVAL;
     77       return MAP_FAILED;
     78     }
     79   } else {
     80     map_access = PAGE_READONLY;
     81     view_access = FILE_MAP_READ;
     82   }
     83 
     84   // MapViewOfFile does not like to see a size greater than the file size of the
     85   // underlying file object, unless the underlying file object is writable.  If
     86   // the mapped region would go beyond the end of the underlying file, use zero,
     87   // as this indicates the physical size.
     88   HANDLE file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
     89   LARGE_INTEGER file_length;
     90   if (!::GetFileSizeEx(file_handle, &file_length)) {
     91     PLOG(ERROR) << "Couldn't get file size.";
     92     errno = EINVAL;
     93     return MAP_FAILED;
     94   }
     95   if (((map_access & PAGE_READONLY) != 0) &&
     96       file_offset + map_length > file_length.QuadPart) {
     97     map_length = 0;
     98   }
     99 
    100   // Create a file mapping object that will be used to access the file.
    101   HANDLE handle = ::CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)),
    102                                       nullptr,
    103                                       map_access,
    104                                       0,
    105                                       0,
    106                                       nullptr);
    107   if (handle == nullptr) {
    108     DWORD error = ::GetLastError();
    109     PLOG(ERROR) << StringPrintf("Couldn't create file mapping %lx.", error);
    110     errno = EINVAL;
    111     return MAP_FAILED;
    112   }
    113 
    114   // Map the file into the process address space.
    115   DWORD offset_low = static_cast<DWORD>(file_offset & 0xffffffffU);
    116 #ifdef _WIN64
    117   DWORD offset_high = static_cast<DWORD>(file_offset >> 32);
    118 #else
    119   DWORD offset_high = static_cast<DWORD>(0);
    120 #endif
    121   void* view_address = MapViewOfFile(handle, view_access, offset_high, offset_low, map_length);
    122   if (view_address == nullptr) {
    123     DWORD error = ::GetLastError();
    124     PLOG(ERROR) << StringPrintf("Couldn't create file view %lx.", error);
    125     ::CloseHandle(handle);
    126     errno = EINVAL;
    127     return MAP_FAILED;
    128   }
    129 
    130   return view_address;
    131 }
    132 
    133 int MemMap::TargetMUnmap(void* start, size_t len) {
    134   // TODO(sehr): implement unmap.
    135   UNUSED(start);
    136   UNUSED(len);
    137   return 0;
    138 }
    139 
    140 }  // namespace art
    141