Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
virtual_memory.c
1/* Copyright (c) 2020 tevador <tevador@gmail.com> */
2/* See LICENSE for licensing information */
3
4#include "virtual_memory.h"
5
6#ifdef HASHX_WIN
7#include <windows.h>
8#else
9#ifdef __APPLE__
10#include <mach/vm_statistics.h>
11#endif
12#include <sys/types.h>
13#include <sys/mman.h>
14#ifndef MAP_ANONYMOUS
15#define MAP_ANONYMOUS MAP_ANON
16#endif
17#define PAGE_READONLY PROT_READ
18#define PAGE_READWRITE (PROT_READ | PROT_WRITE)
19#define PAGE_EXECUTE_READ (PROT_READ | PROT_EXEC)
20#define PAGE_EXECUTE_READWRITE (PROT_READ | PROT_WRITE | PROT_EXEC)
21#if defined(__NetBSD__) && defined(PROT_MPROTECT)
22#define PAGE_MMAP_PROT (PAGE_READWRITE | PROT_MPROTECT(PROT_EXEC))
23#else
24#define PAGE_MMAP_PROT PAGE_READWRITE
25#endif
26#endif
27
28void* hashx_vm_alloc(size_t bytes) {
29 void* mem;
30#ifdef HASHX_WIN
31 mem = VirtualAlloc(NULL, bytes, MEM_COMMIT, PAGE_READWRITE);
32#else
33 mem = mmap(NULL, bytes, PAGE_MMAP_PROT, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
34 if (mem == MAP_FAILED)
35 return NULL;
36#endif
37 return mem;
38}
39
40static inline bool page_protect(void* ptr, size_t bytes, int rules) {
41#ifdef HASHX_WIN
42 DWORD oldp;
43 if (!VirtualProtect(ptr, bytes, (DWORD)rules, &oldp)) {
44 return false;
45 }
46#else
47 if (mprotect(ptr, bytes, rules) != 0)
48 return false;
49#endif
50 return true;
51}
52
53bool hashx_vm_rw(void* ptr, size_t bytes) {
54 return page_protect(ptr, bytes, PAGE_READWRITE);
55}
56
57bool hashx_vm_rx(void* ptr, size_t bytes) {
58 return page_protect(ptr, bytes, PAGE_EXECUTE_READ);
59}
60
61#ifdef EQUIX_SUPPORT_HUGEPAGES
62
63#ifdef HASHX_WIN
64
65static bool set_privilege(const char* pszPrivilege, BOOL bEnable) {
66 HANDLE hToken;
67 TOKEN_PRIVILEGES tp;
68 BOOL status;
69 DWORD error;
70
71 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
72 | TOKEN_QUERY, &hToken))
73 return false;
74
75 if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid))
76 return false;
77
78 tp.PrivilegeCount = 1;
79
80 if (bEnable)
81 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
82 else
83 tp.Privileges[0].Attributes = 0;
84
85 status = AdjustTokenPrivileges(hToken, FALSE, &tp, 0,
86 (PTOKEN_PRIVILEGES)NULL, 0);
87 error = GetLastError();
88
89 CloseHandle(hToken);
90
91 return status && (error == ERROR_SUCCESS);
92}
93#endif /* HASHX_WIN */
94
95void* hashx_vm_alloc_huge(size_t bytes) {
96 void* mem;
97#ifdef HASHX_WIN
98 if (!set_privilege("SeLockMemoryPrivilege", 1)) {
99 /* Failed, but try the VirtualAlloc anyway */
100 }
101 SIZE_T page_min = GetLargePageMinimum();
102 if (page_min > 0) {
103 mem = VirtualAlloc(NULL, ALIGN_SIZE(bytes, page_min), MEM_COMMIT
104 | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
105 }
106 else {
107 mem = NULL;
108 }
109#else
110#ifdef __APPLE__
111 mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS,
112 VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
113#elif defined(__FreeBSD__)
114 mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS
115 | MAP_ALIGNED_SUPER, -1, 0);
116#elif defined(__OpenBSD__) || defined(__NetBSD__)
117 (void)bytes;
118 mem = MAP_FAILED; // OpenBSD and NetBSD do not support huge pages
119#else
120 mem = mmap(NULL, bytes, PAGE_READWRITE, MAP_PRIVATE | MAP_ANONYMOUS
121 | MAP_HUGETLB | MAP_POPULATE, -1, 0);
122#endif
123 if (mem == MAP_FAILED) {
124 mem = NULL;
125 }
126#endif
127 return mem;
128}
129#endif /* EQUIX_SUPPORT_HUGEPAGES */
130
131void hashx_vm_free(void* ptr, size_t bytes) {
132 if (!ptr) {
133 return;
134 }
135#ifdef HASHX_WIN
136 (void)bytes;
137 VirtualFree(ptr, 0, MEM_RELEASE);
138#else
139 munmap(ptr, bytes);
140#endif
141}