You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.3 KiB
141 lines
4.3 KiB
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "mem_map.h"
|
|
|
|
#include <windows.h>
|
|
|
|
#include "android-base/logging.h"
|
|
#include "android-base/stringprintf.h"
|
|
#include "android-base/mapped_file.h"
|
|
#ifdef PROT_READ
|
|
#undef PROT_READ
|
|
#endif
|
|
#ifdef PROT_WRITE
|
|
#undef PROT_WRITE
|
|
#endif
|
|
#include "mman.h"
|
|
|
|
namespace art {
|
|
|
|
using android::base::MappedFile;
|
|
using android::base::StringPrintf;
|
|
|
|
static off_t allocation_granularity;
|
|
|
|
void MemMap::TargetMMapInit() {
|
|
SYSTEM_INFO si;
|
|
GetSystemInfo(&si);
|
|
allocation_granularity = si.dwAllocationGranularity;
|
|
}
|
|
|
|
void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
|
|
UNUSED(start);
|
|
size_t padding = fd_off % allocation_granularity;
|
|
off_t file_offset = fd_off - padding;
|
|
off_t map_length = len + padding;
|
|
|
|
// Only read and write permissions are supported.
|
|
if ((prot != PROT_READ) && (prot != (PROT_READ | PROT_WRITE))) {
|
|
PLOG(ERROR) << "Protection or flag error was not supported.";
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
// Fixed is not currently supported either.
|
|
// TODO(sehr): add MAP_FIXED support.
|
|
if ((flags & MAP_FIXED) != 0) {
|
|
PLOG(ERROR) << "MAP_FIXED not supported.";
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
// Compute the Windows access flags for the two APIs from the PROTs and MAPs.
|
|
DWORD map_access = 0;
|
|
DWORD view_access = 0;
|
|
if ((prot & PROT_WRITE) != 0) {
|
|
map_access = PAGE_READWRITE;
|
|
if (((flags & MAP_SHARED) != 0) && ((flags & MAP_PRIVATE) == 0)) {
|
|
view_access = FILE_MAP_ALL_ACCESS;
|
|
} else if (((flags & MAP_SHARED) == 0) && ((flags & MAP_PRIVATE) != 0)) {
|
|
view_access = FILE_MAP_COPY | FILE_MAP_READ;
|
|
} else {
|
|
PLOG(ERROR) << "MAP_PRIVATE and MAP_SHARED inconsistently set.";
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
} else {
|
|
map_access = PAGE_READONLY;
|
|
view_access = FILE_MAP_READ;
|
|
}
|
|
|
|
// MapViewOfFile does not like to see a size greater than the file size of the
|
|
// underlying file object, unless the underlying file object is writable. If
|
|
// the mapped region would go beyond the end of the underlying file, use zero,
|
|
// as this indicates the physical size.
|
|
HANDLE file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
|
LARGE_INTEGER file_length;
|
|
if (!::GetFileSizeEx(file_handle, &file_length)) {
|
|
PLOG(ERROR) << "Couldn't get file size.";
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
if (((map_access & PAGE_READONLY) != 0) &&
|
|
file_offset + map_length > file_length.QuadPart) {
|
|
map_length = 0;
|
|
}
|
|
|
|
// Create a file mapping object that will be used to access the file.
|
|
HANDLE handle = ::CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)),
|
|
nullptr,
|
|
map_access,
|
|
0,
|
|
0,
|
|
nullptr);
|
|
if (handle == nullptr) {
|
|
DWORD error = ::GetLastError();
|
|
PLOG(ERROR) << StringPrintf("Couldn't create file mapping %lx.", error);
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
// Map the file into the process address space.
|
|
DWORD offset_low = static_cast<DWORD>(file_offset & 0xffffffffU);
|
|
#ifdef _WIN64
|
|
DWORD offset_high = static_cast<DWORD>(file_offset >> 32);
|
|
#else
|
|
DWORD offset_high = static_cast<DWORD>(0);
|
|
#endif
|
|
void* view_address = MapViewOfFile(handle, view_access, offset_high, offset_low, map_length);
|
|
if (view_address == nullptr) {
|
|
DWORD error = ::GetLastError();
|
|
PLOG(ERROR) << StringPrintf("Couldn't create file view %lx.", error);
|
|
::CloseHandle(handle);
|
|
errno = EINVAL;
|
|
return MAP_FAILED;
|
|
}
|
|
|
|
return view_address;
|
|
}
|
|
|
|
int MemMap::TargetMUnmap(void* start, size_t len) {
|
|
// TODO(sehr): implement unmap.
|
|
UNUSED(start);
|
|
UNUSED(len);
|
|
return 0;
|
|
}
|
|
|
|
} // namespace art
|