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 // This include needs to be here due to the coding conventions.  Unfortunately
21 // it drags in the definition of the ERROR macro. Similarly to base/utils.cc,
22 // undefine the macro here. See also, the comment at android-base/logging.h.
23 #ifdef ERROR
24 #undef ERROR
25 #endif
26 
27 #include "android-base/logging.h"
28 #include "android-base/stringprintf.h"
29 #include "android-base/mapped_file.h"
30 #ifdef PROT_READ
31 #undef PROT_READ
32 #endif
33 #ifdef PROT_WRITE
34 #undef PROT_WRITE
35 #endif
36 #include "mman.h"
37 
38 namespace art {
39 
40 using android::base::StringPrintf;
41 
42 static off_t allocation_granularity;
43 
TargetMMapInit()44 void MemMap::TargetMMapInit() {
45   SYSTEM_INFO si;
46   GetSystemInfo(&si);
47   allocation_granularity = si.dwAllocationGranularity;
48 }
49 
TargetMMap(void * start,size_t len,int prot,int flags,int fd,off_t fd_off)50 void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
51   UNUSED(start);
52   size_t padding = fd_off % allocation_granularity;
53   off_t file_offset = fd_off - padding;
54   off_t map_length = len + padding;
55 
56   // Only read and write permissions are supported.
57   if ((prot != PROT_READ) && (prot != (PROT_READ | PROT_WRITE))) {
58     PLOG(ERROR) << "Protection or flag error was not supported.";
59     errno = EINVAL;
60     return MAP_FAILED;
61   }
62   // Fixed is not currently supported either.
63   // TODO(sehr): add MAP_FIXED support.
64   if ((flags & MAP_FIXED) != 0) {
65     PLOG(ERROR) << "MAP_FIXED not supported.";
66     errno = EINVAL;
67     return MAP_FAILED;
68   }
69 
70   // Compute the Windows access flags for the two APIs from the PROTs and MAPs.
71   DWORD map_access = 0;
72   DWORD view_access = 0;
73   if ((prot & PROT_WRITE) != 0) {
74     map_access = PAGE_READWRITE;
75     if (((flags & MAP_SHARED) != 0) && ((flags & MAP_PRIVATE) == 0)) {
76       view_access = FILE_MAP_ALL_ACCESS;
77     } else if (((flags & MAP_SHARED) == 0) && ((flags & MAP_PRIVATE) != 0)) {
78       view_access = FILE_MAP_COPY | FILE_MAP_READ;
79     } else {
80       PLOG(ERROR) << "MAP_PRIVATE and MAP_SHARED inconsistently set.";
81       errno = EINVAL;
82       return MAP_FAILED;
83     }
84   } else {
85     map_access = PAGE_READONLY;
86     view_access = FILE_MAP_READ;
87   }
88 
89   // MapViewOfFile does not like to see a size greater than the file size of the
90   // underlying file object, unless the underlying file object is writable.  If
91   // the mapped region would go beyond the end of the underlying file, use zero,
92   // as this indicates the physical size.
93   HANDLE file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
94   LARGE_INTEGER file_length;
95   if (!::GetFileSizeEx(file_handle, &file_length)) {
96     PLOG(ERROR) << "Couldn't get file size.";
97     errno = EINVAL;
98     return MAP_FAILED;
99   }
100   if (((map_access & PAGE_READONLY) != 0) &&
101       file_offset + map_length > file_length.QuadPart) {
102     map_length = 0;
103   }
104 
105   // Create a file mapping object that will be used to access the file.
106   HANDLE handle = ::CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)),
107                                       nullptr,
108                                       map_access,
109                                       0,
110                                       0,
111                                       nullptr);
112   if (handle == nullptr) {
113     DWORD error = ::GetLastError();
114     PLOG(ERROR) << StringPrintf("Couldn't create file mapping %lx.", error);
115     errno = EINVAL;
116     return MAP_FAILED;
117   }
118 
119   // Map the file into the process address space.
120   DWORD offset_low = static_cast<DWORD>(file_offset & 0xffffffffU);
121 #ifdef _WIN64
122   DWORD offset_high = static_cast<DWORD>(file_offset >> 32);
123 #else
124   DWORD offset_high = static_cast<DWORD>(0);
125 #endif
126   void* view_address = MapViewOfFile(handle, view_access, offset_high, offset_low, map_length);
127   if (view_address == nullptr) {
128     DWORD error = ::GetLastError();
129     PLOG(ERROR) << StringPrintf("Couldn't create file view %lx.", error);
130     ::CloseHandle(handle);
131     errno = EINVAL;
132     return MAP_FAILED;
133   }
134 
135   return view_address;
136 }
137 
TargetMUnmap(void * start,size_t len)138 int MemMap::TargetMUnmap(void* start, size_t len) {
139   // TODO(sehr): implement unmap.
140   UNUSED(start);
141   UNUSED(len);
142   return 0;
143 }
144 
145 }  // namespace art
146