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