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