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