]> gitweb.factorcode.org Git - factor.git/blob - vm/os-windows.cpp
vm: allocate an extra canary page before callstack
[factor.git] / vm / os-windows.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 HMODULE hFactorDll;
7
8 void factor_vm::init_ffi()
9 {
10         hFactorDll = GetModuleHandle(FACTOR_DLL);
11         if(!hFactorDll)
12                 fatal_error("GetModuleHandle() failed", 0);
13 }
14
15 void factor_vm::ffi_dlopen(dll *dll)
16 {
17         dll->handle = LoadLibraryEx((WCHAR *)alien_offset(dll->path), NULL, 0);
18 }
19
20 void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
21 {
22         return (void *)GetProcAddress(dll ? (HMODULE)dll->handle : hFactorDll, symbol);
23 }
24
25 void *factor_vm::ffi_dlsym_raw(dll *dll, symbol_char *symbol)
26 {
27         return ffi_dlsym(dll, symbol);
28 }
29
30 void factor_vm::ffi_dlclose(dll *dll)
31 {
32         FreeLibrary((HMODULE)dll->handle);
33         dll->handle = NULL;
34 }
35
36 BOOL factor_vm::windows_stat(vm_char *path)
37 {
38         BY_HANDLE_FILE_INFORMATION bhfi;
39         HANDLE h = CreateFileW(path,
40                         GENERIC_READ,
41                         FILE_SHARE_READ,
42                         NULL,
43                         OPEN_EXISTING,
44                         FILE_FLAG_BACKUP_SEMANTICS,
45                         NULL);
46
47         if(h == INVALID_HANDLE_VALUE)
48         {
49                 // FindFirstFile is the only call that can stat c:\pagefile.sys
50                 WIN32_FIND_DATA st;
51                 HANDLE h;
52
53                 if(INVALID_HANDLE_VALUE == (h = FindFirstFile(path, &st)))
54                         return false;
55                 FindClose(h);
56                 return true;
57         }
58         BOOL ret = GetFileInformationByHandle(h, &bhfi);
59         CloseHandle(h);
60         return ret;
61 }
62
63 void factor_vm::windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length)
64 {
65         wcsncpy(temp_path, full_path, length - 1);
66         size_t full_path_len = wcslen(full_path);
67         if (full_path_len < length - 1)
68                 wcsncat(temp_path, L".image", length - full_path_len - 1);
69         temp_path[length - 1] = 0;
70 }
71
72 /* You must free() this yourself. */
73 const vm_char *factor_vm::default_image_path()
74 {
75         vm_char full_path[MAX_UNICODE_PATH];
76         vm_char *ptr;
77         vm_char temp_path[MAX_UNICODE_PATH];
78
79         if(!GetModuleFileName(NULL, full_path, MAX_UNICODE_PATH))
80                 fatal_error("GetModuleFileName() failed", 0);
81
82         if((ptr = wcsrchr(full_path, '.')))
83                 *ptr = 0;
84
85         wcsncpy(temp_path, full_path, MAX_UNICODE_PATH - 1);
86         size_t full_path_len = wcslen(full_path);
87         if (full_path_len < MAX_UNICODE_PATH - 1)
88                 wcsncat(temp_path, L".image", MAX_UNICODE_PATH - full_path_len - 1);
89         temp_path[MAX_UNICODE_PATH - 1] = 0;
90
91         return safe_strdup(temp_path);
92 }
93
94 /* You must free() this yourself. */
95 const vm_char *factor_vm::vm_executable_path()
96 {
97         vm_char full_path[MAX_UNICODE_PATH];
98         if(!GetModuleFileName(NULL, full_path, MAX_UNICODE_PATH))
99                 fatal_error("GetModuleFileName() failed", 0);
100         return safe_strdup(full_path);
101 }
102
103 void factor_vm::primitive_existsp()
104 {
105         vm_char *path = untag_check<byte_array>(ctx->pop())->data<vm_char>();
106         ctx->push(tag_boolean(windows_stat(path)));
107 }
108
109 segment::segment(cell size_, bool executable_p, bool canary_page_p)
110 {
111         size = size_;
112
113         char *mem;
114         DWORD ignore;
115
116         cell pagesize = getpagesize();
117         cell startsize = canary_page_p ? 2*pagesize : pagesize;
118         if((mem = (char *)VirtualAlloc(NULL, startsize + size + pagesize,
119                 MEM_COMMIT, executable_p ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE)) == 0)
120                 out_of_memory();
121
122         if (!VirtualProtect(mem, startsize, PAGE_NOACCESS, &ignore))
123                 fatal_error("Cannot allocate low guard page", (cell)mem);
124
125         if (!VirtualProtect(mem + size + startsize,
126                 pagesize, PAGE_NOACCESS, &ignore))
127                 fatal_error("Cannot allocate high guard page", (cell)mem);
128
129         start = (cell)mem + startsize;
130         end = start + size;
131 }
132
133 segment::~segment()
134 {
135         SYSTEM_INFO si;
136         GetSystemInfo(&si);
137         if(!VirtualFree((void*)(start - si.dwPageSize), 0, MEM_RELEASE))
138                 fatal_error("Segment deallocation failed",0);
139 }
140
141 long getpagesize()
142 {
143         static long g_pagesize = 0;
144         if(!g_pagesize)
145         {
146                 SYSTEM_INFO system_info;
147                 GetSystemInfo (&system_info);
148                 g_pagesize = system_info.dwPageSize;
149         }
150         return g_pagesize;
151 }
152
153 void code_heap::guard_safepoint()
154 {
155         DWORD ignore;
156         if (!VirtualProtect(safepoint_page, getpagesize(), PAGE_NOACCESS, &ignore))
157                 fatal_error("Cannot protect safepoint guard page", (cell)safepoint_page);
158 }
159
160 void code_heap::unguard_safepoint()
161 {
162         DWORD ignore;
163         if (!VirtualProtect(safepoint_page, getpagesize(), PAGE_READWRITE, &ignore))
164                 fatal_error("Cannot unprotect safepoint guard page", (cell)safepoint_page);
165 }
166
167 void factor_vm::move_file(const vm_char *path1, const vm_char *path2)
168 {
169         if(MoveFileEx((path1),(path2),MOVEFILE_REPLACE_EXISTING) == false)
170                 general_error(ERROR_IO,tag_fixnum(GetLastError()),false_object);
171 }
172
173 void factor_vm::init_signals() {}
174
175 THREADHANDLE start_thread(void *(*start_routine)(void *), void *args)
176 {
177         return (void *)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0);
178 }
179
180 u64 nano_count()
181 {
182         static double scale_factor;
183
184         static u32 hi = 0;
185         static u32 lo = 0;
186
187         LARGE_INTEGER count;
188         BOOL ret = QueryPerformanceCounter(&count);
189         if(ret == 0)
190                 fatal_error("QueryPerformanceCounter", 0);
191
192         if(scale_factor == 0.0)
193         {
194                 LARGE_INTEGER frequency;
195                 BOOL ret = QueryPerformanceFrequency(&frequency);
196                 if(ret == 0)
197                         fatal_error("QueryPerformanceFrequency", 0);
198                 scale_factor = (1000000000.0 / frequency.QuadPart);
199         }
200
201 #ifdef FACTOR_64
202         hi = count.HighPart;
203 #else
204         /* On VirtualBox, QueryPerformanceCounter does not increment
205         the high part every time the low part overflows.  Workaround. */
206         if(lo > count.LowPart)
207                 hi++;
208 #endif
209         lo = count.LowPart;
210
211         return (u64)((((u64)hi << 32) | (u64)lo) * scale_factor);
212 }
213
214 void sleep_nanos(u64 nsec)
215 {
216         Sleep((DWORD)(nsec/1000000));
217 }
218
219 LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
220 {
221         c->ESP = (cell)fix_callstack_top((stack_frame *)c->ESP);
222         ctx->callstack_top = (stack_frame *)c->ESP;
223
224         switch (e->ExceptionCode)
225         {
226         case EXCEPTION_ACCESS_VIOLATION:
227                 signal_fault_addr = e->ExceptionInformation[1];
228                 c->EIP = (cell)factor::memory_signal_handler_impl;
229                 break;
230
231         case STATUS_FLOAT_DENORMAL_OPERAND:
232         case STATUS_FLOAT_DIVIDE_BY_ZERO:
233         case STATUS_FLOAT_INEXACT_RESULT:
234         case STATUS_FLOAT_INVALID_OPERATION:
235         case STATUS_FLOAT_OVERFLOW:
236         case STATUS_FLOAT_STACK_CHECK:
237         case STATUS_FLOAT_UNDERFLOW:
238         case STATUS_FLOAT_MULTIPLE_FAULTS:
239         case STATUS_FLOAT_MULTIPLE_TRAPS:
240 #ifdef FACTOR_64
241                 signal_fpu_status = fpu_status(MXCSR(c));
242 #else
243                 signal_fpu_status = fpu_status(X87SW(c) | MXCSR(c));
244
245                 /* This seems to have no effect */
246                 X87SW(c) = 0;
247 #endif
248                 MXCSR(c) &= 0xffffffc0;
249                 c->EIP = (cell)factor::fp_signal_handler_impl;
250                 break;
251         default:
252                 signal_number = e->ExceptionCode;
253                 c->EIP = (cell)factor::synchronous_signal_handler_impl;
254                 break;
255         }
256
257         return 0;
258 }
259
260 VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
261 {
262         return current_vm()->exception_handler(e,frame,c,dispatch);
263 }
264
265 BOOL factor_vm::ctrl_handler(DWORD dwCtrlType)
266 {
267         switch (dwCtrlType) {
268         case CTRL_C_EVENT:
269         case CTRL_BREAK_EVENT:
270                 enqueue_safepoint_signal((cell)-1);
271                 return TRUE;
272         default:
273                 return FALSE;
274         }
275 }
276
277 VM_C_API BOOL ctrl_handler(DWORD dwCtrlType)
278 {
279         factor_vm *vm = current_vm_p();
280         if (vm != NULL)
281                 return vm->ctrl_handler(dwCtrlType);
282         else
283                 return FALSE;
284 }
285
286 void factor_vm::open_console()
287 {
288         SetConsoleCtrlHandler(factor::ctrl_handler, TRUE);
289 }
290
291 }