0.9.8.42:
[sbcl.git] / src / runtime / win32-os.c
1 /*
2  * the Win32 incarnation of OS-dependent routines.  See also
3  * $(sbcl_arch)-win32-os.c
4  *
5  * This file (along with os.h) exports an OS-independent interface to
6  * the operating system VM facilities. Surprise surprise, this
7  * interface looks a lot like the Mach interface (but simpler in some
8  * places). For some operating systems, a subset of these functions
9  * will have to be emulated.
10  */
11
12 /*
13  * This software is part of the SBCL system. See the README file for
14  * more information.
15  *
16  * This software is derived from the CMU CL system, which was
17  * written at Carnegie Mellon University and released into the
18  * public domain. The software is in the public domain and is
19  * provided with absolutely no warranty. See the COPYING and CREDITS
20  * files for more information.
21  */
22
23 /*
24  * This file was copied from the Linux version of the same, and
25  * likely still has some linuxisms in it have haven't been elimiated
26  * yet.
27  */
28
29 #include <stdio.h>
30 #include <sys/param.h>
31 #include <sys/file.h>
32 #include "sbcl.h"
33 #include "./signal.h"
34 #include "os.h"
35 #include "arch.h"
36 #include "globals.h"
37 #include "sbcl.h"
38 #include "interrupt.h"
39 #include "interr.h"
40 #include "lispregs.h"
41 #include "monitor.h"
42 #include "alloc.h"
43 #include "genesis/primitive-objects.h"
44
45 #include <sys/types.h>
46 #include <signal.h>
47 #include <sys/time.h>
48 #include <sys/stat.h>
49 #include <unistd.h>
50
51 #include <excpt.h>
52
53 #include "validate.h"
54 #include "thread.h"
55 size_t os_vm_page_size;
56
57
58 #include "gc.h"
59 #include "gencgc-internal.h"
60
61 #if 0
62 int linux_sparc_siginfo_bug = 0;
63 int linux_supports_futex=0;
64 #endif
65
66 /* The exception handling function looks like this: */
67 EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *,
68                                        struct lisp_exception_frame *,
69                                        CONTEXT *,
70                                        void *);
71
72 void *base_seh_frame;
73
74 static void *get_seh_frame(void)
75 {
76     void* retval;
77     asm volatile ("movl %%fs:0,%0": "=r" (retval));
78     return retval;
79 }
80
81 static void set_seh_frame(void *frame)
82 {
83     asm volatile ("movl %0,%%fs:0": : "r" (frame));
84 }
85
86 static struct lisp_exception_frame *find_our_seh_frame(void)
87 {
88     struct lisp_exception_frame *frame = get_seh_frame();
89
90     while (frame->handler != handle_exception)
91         frame = frame->next_frame;
92
93     return frame;
94 }
95
96 #if 0
97 inline static void *get_stack_frame(void)
98 {
99     void* retval;
100     asm volatile ("movl %%ebp,%0": "=r" (retval));
101     return retval;
102 }
103 #endif
104
105 void os_init(char *argv[], char *envp[])
106 {
107     SYSTEM_INFO system_info;
108
109     GetSystemInfo(&system_info);
110     os_vm_page_size = system_info.dwPageSize;
111
112     base_seh_frame = get_seh_frame();
113 }
114
115
116 /*
117  * So we have three fun scenarios here.
118  *
119  * First, we could be being called to reserve the memory areas
120  * during initialization (prior to loading the core file).
121  *
122  * Second, we could be being called by the GC to commit a page
123  * that has just been decommitted (for easy zero-fill).
124  *
125  * Third, we could be being called by create_thread_struct()
126  * in order to create the sundry and various stacks.
127  *
128  * The third case is easy to pick out because it passes an
129  * addr of 0.
130  *
131  * The second case is easy to pick out because it will be for
132  * a range of memory that is MEM_RESERVE rather than MEM_FREE.
133  *
134  * The second case is also an easy implement, because we leave
135  * the memory as reserved (since we do lazy commits).
136  */
137
138 os_vm_address_t
139 os_validate(os_vm_address_t addr, os_vm_size_t len)
140 {
141     MEMORY_BASIC_INFORMATION mem_info;
142
143     if (!addr) {
144         /* the simple case first */
145         os_vm_address_t real_addr;
146         if (!(real_addr = VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) {
147             perror("VirtualAlloc");
148             return 0;
149         }
150
151         return real_addr;
152     }
153
154     if (!VirtualQuery(addr, &mem_info, sizeof mem_info)) {
155         perror("VirtualQuery");
156         return 0;
157     }
158
159     if ((mem_info.State == MEM_RESERVE) && (mem_info.RegionSize >=len)) return addr;
160
161     if (mem_info.State == MEM_RESERVE) {
162         fprintf(stderr, "validation of reserved space too short.\n");
163         fflush(stderr);
164     }
165
166     if (!VirtualAlloc(addr, len, (mem_info.State == MEM_RESERVE)? MEM_COMMIT: MEM_RESERVE, PAGE_EXECUTE_READWRITE)) {
167         perror("VirtualAlloc");
168         return 0;
169     }
170
171     return addr;
172 }
173
174 /*
175  * For os_invalidate(), we merely decommit the memory rather than
176  * freeing the address space. This loses when freeing per-thread
177  * data and related memory since it leaks address space. It's not
178  * too lossy, however, since the two scenarios I'm aware of are
179  * fd-stream buffers, which are pooled rather than torched, and
180  * thread information, which I hope to pool (since windows creates
181  * threads at its own whim, and we probably want to be able to
182  * have them callback without funky magic on the part of the user,
183  * and full-on thread allocation is fairly heavyweight). Someone
184  * will probably shoot me down on this with some pithy comment on
185  * the use of (setf symbol-value) on a special variable. I'm happy
186  * for them.
187  */
188
189 void
190 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
191 {
192     if (!VirtualFree(addr, len, MEM_DECOMMIT)) {
193         perror("VirtualFree");
194     }
195 }
196
197 /*
198  * os_map() is called to map a chunk of the core file into memory.
199  *
200  * Unfortunately, Windows semantics completely screws this up, so
201  * we just add backing store from the swapfile to where the chunk
202  * goes and read it up like a normal file. We could consider using
203  * a lazy read (demand page) setup, but that would mean keeping an
204  * open file pointer for the core indefinately (and be one more
205  * thing to maintain).
206  */
207
208 os_vm_address_t
209 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
210 {
211     os_vm_size_t count;
212
213     fprintf(stderr, "os_map: %d, 0x%x, %p, 0x%x.\n", fd, offset, addr, len);
214     fflush(stderr);
215
216     if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) {
217         perror("VirtualAlloc");
218         lose("os_map: VirtualAlloc failure");
219     }
220
221     if (lseek(fd, offset, SEEK_SET) == -1) {
222         lose("os_map: Seek failure.");
223     }
224
225     count = read(fd, addr, len);
226     if (count != len) {
227         fprintf(stderr, "expected 0x%x, read 0x%x.\n", len, count);
228         lose("os_map: Failed to read enough bytes.");
229     }
230
231     return addr;
232 }
233
234 static DWORD os_protect_modes[8] = {
235     PAGE_NOACCESS,
236     PAGE_READONLY,
237     PAGE_READWRITE,
238     PAGE_READWRITE,
239     PAGE_EXECUTE,
240     PAGE_EXECUTE_READ,
241     PAGE_EXECUTE_READWRITE,
242     PAGE_EXECUTE_READWRITE,
243 };
244
245 void
246 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
247 {
248     DWORD old_prot;
249
250     if (!VirtualProtect(address, length, os_protect_modes[prot], &old_prot)) {
251         fprintf(stderr, "VirtualProtect failed, code 0x%lx.\n", GetLastError());
252         fflush(stderr);
253     }
254 }
255
256 /* FIXME: Now that FOO_END, rather than FOO_SIZE, is the fundamental
257  * description of a space, we could probably punt this and just do
258  * (FOO_START <= x && x < FOO_END) everywhere it's called. */
259 static boolean
260 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
261 {
262     char* beg = (char*)((long)sbeg);
263     char* end = (char*)((long)sbeg) + slen;
264     char* adr = (char*)a;
265     return (adr >= beg && adr < end);
266 }
267
268 boolean
269 is_valid_lisp_addr(os_vm_address_t addr)
270 {
271     struct thread *th;
272     if(in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) ||
273        in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE) ||
274        in_range_p(addr, DYNAMIC_SPACE_START  , DYNAMIC_SPACE_SIZE))
275         return 1;
276     for_each_thread(th) {
277         if(((os_vm_address_t)th->control_stack_start <= addr) && (addr < (os_vm_address_t)th->control_stack_end))
278             return 1;
279         if(in_range_p(addr, (unsigned long)th->binding_stack_start, BINDING_STACK_SIZE))
280             return 1;
281     }
282     return 0;
283 }
284
285 /*
286  * any OS-dependent special low-level handling for signals
287  */
288
289 /* A tiny bit of interrupt.c state we want our paws on. */
290 extern boolean internal_errors_enabled;
291
292 /*
293  * FIXME: There is a potential problem with foreign code here.
294  * If we are running foreign code instead of lisp code and an
295  * exception occurs we arrange a call into Lisp. If the
296  * foreign code has installed an exception handler, we run the
297  * very great risk of throwing through their exception handler
298  * without asking it to unwind. This is more a problem with
299  * non-sigtrap (EXCEPTION_BREAKPOINT) exceptions, as they could
300  * reasonably be expected to happen in foreign code. We need to
301  * figure out the exception handler unwind semantics and adhere
302  * to them (probably by abusing the Lisp unwind-protect system)
303  * if we are going to handle this scenario correctly.
304  *
305  * A good explanation of the exception handling semantics is
306  * http://win32assembly.online.fr/Exceptionhandling.html .
307  * We will also need to handle this ourselves when foreign
308  * code tries to unwind -us-.
309  *
310  * When unwinding through foreign code we should unwind the
311  * Lisp stack to the entry from foreign code, then unwind the
312  * foreign code stack to the entry from Lisp, then resume
313  * unwinding in Lisp.
314  */
315
316 EXCEPTION_DISPOSITION sigtrap_emulator(CONTEXT *context,
317                                        struct lisp_exception_frame *exception_frame)
318 {
319     if (*((char *)context->Eip + 1) == trap_ContextRestore) {
320         /*
321          * This is the cleanup for what is immediately below, and
322          * for the generic exception handling further below. We
323          * have to memcpy() the original context (emulated sigtrap
324          * or normal exception) over our context and resume it.
325          */
326         memcpy(context, &exception_frame->context, sizeof(CONTEXT));
327         return ExceptionContinueExecution;
328
329     } else { /* Not a trap_ContextRestore, must be a sigtrap. */
330         /* sigtrap_trampoline is defined in x86-assem.S. */
331         extern void sigtrap_trampoline;
332
333         /*
334          * Unlike some other operating systems, Win32 leaves EIP
335          * pointing to the breakpoint instruction.
336          */
337         context->Eip++;
338
339         /*
340          * We're not on an alternate stack like we would be in some
341          * other operating systems, and we don't want to risk leaking
342          * any important resources if we throw out of the sigtrap
343          * handler, so we need to copy off our context to a "safe"
344          * place and then monkey with the return EIP to point to a
345          * trampoline which calls another function which copies the
346          * context out to a really-safe place and then calls the real
347          * sigtrap handler. When the real sigtrap handler returns, the
348          * trampoline then contains another breakpoint with a code of
349          * trap_ContextRestore (see above). Essentially the same
350          * mechanism is used by the generic exception path. There is
351          * a small window of opportunity between us copying the
352          * context to the "safe" place and the sigtrap wrapper copying
353          * it to the really-safe place (allocated in its stack frame)
354          * during which the context can be smashed. The only scenario
355          * I can come up with for this, however, involves a stack
356          * overflow occuring at just the wrong time (which makes one
357          * wonder how stack overflow exceptions even happen, given
358          * that we don't switch stacks for exception processing...)
359          */
360         memcpy(&exception_frame->context, context, sizeof(CONTEXT));
361         context->Eax = context->Eip;
362         context->Eip = (unsigned long)&sigtrap_trampoline;
363
364         /* and return */
365         return ExceptionContinueExecution;
366     }
367 }
368
369 void sigtrap_wrapper(void)
370 {
371     /*
372      * This is the wrapper around the sigtrap handler called from
373      * the trampoline returned to from the function above.
374      *
375      * There actually is a point to some of the commented-out code
376      * in this function, although it really belongs to the callback
377      * wrappers. Once it is installed there, it can probably be
378      * removed from here.
379      */
380
381     extern void sigtrap_handler(int signal, siginfo_t *info, void *context);
382
383 /*     volatile struct { */
384 /*      void *handler[2]; */
385     CONTEXT context;
386 /*     } handler; */
387
388     struct lisp_exception_frame *frame = find_our_seh_frame();
389
390 /*     wos_install_interrupt_handlers(handler); */
391 /*     handler.handler[0] = get_seh_frame(); */
392 /*     handler.handler[1] = &handle_exception; */
393 /*     set_seh_frame(&handler); */
394
395     memcpy(&context, &frame->context, sizeof(CONTEXT));
396     sigtrap_handler(0, NULL, &context);
397     memcpy(&frame->context, &context, sizeof(CONTEXT));
398
399 /*     set_seh_frame(handler.handler[0]); */
400 }
401
402 EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *exception_record,
403                                        struct lisp_exception_frame *exception_frame,
404                                        CONTEXT *context,
405                                        void *dc) /* FIXME: What's dc again? */
406 {
407
408     /* For EXCEPTION_ACCESS_VIOLATION only. */
409     void *fault_address = (void *)exception_record->ExceptionInformation[1];
410
411     if (exception_record->ExceptionCode == EXCEPTION_BREAKPOINT) {
412         /* Pick off sigtrap case first. */
413         return sigtrap_emulator(context, exception_frame);
414
415     } else if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
416                is_valid_lisp_addr(fault_address)) {
417         /* Pick off GC-related memory fault next. */
418         MEMORY_BASIC_INFORMATION mem_info;
419
420         if (!VirtualQuery(fault_address, &mem_info, sizeof mem_info)) {
421             fprintf(stderr, "VirtualQuery: 0x%lx.\n", GetLastError());
422             lose("handle_exception: VirtualQuery failure");
423         }
424
425         if (mem_info.State == MEM_RESERVE) {
426             /* First use new page, lets get some memory for it. */
427             if (!VirtualAlloc(mem_info.BaseAddress, os_vm_page_size,
428                               MEM_COMMIT, PAGE_EXECUTE_READWRITE)) {
429                 fprintf(stderr, "VirtualAlloc: 0x%lx.\n", GetLastError());
430                 lose("handle_exception: VirtualAlloc failure");
431
432             } else {
433                 /*
434                  * Now, if the page is supposedly write-protected and this
435                  * is a write, tell the gc that it's been hit.
436                  *
437                  * FIXME: Are we supposed to fall-through to the Lisp
438                  * exception handler if the gc doesn't take the wp violation?
439                  */
440                 if (exception_record->ExceptionInformation[0]) {
441                     int index = find_page_index(fault_address);
442                     if ((index != -1) && (page_table[index].write_protected)) {
443                         gencgc_handle_wp_violation(fault_address);
444                     }
445                 }
446                 return ExceptionContinueExecution;
447             }
448
449         } else if (gencgc_handle_wp_violation(fault_address)) {
450             /* gc accepts the wp violation, so resume where we left off. */
451             return ExceptionContinueExecution;
452         }
453
454         /* All else failed, drop through to the lisp-side exception handler. */
455     }
456
457     /*
458      * If we fall through to here then we need to either forward
459      * the exception to the lisp-side exception handler if it's
460      * set up, or drop to LDB.
461      */
462
463     if (internal_errors_enabled) {
464         /* exception_trampoline is defined in x86-assem.S. */
465         extern void exception_trampoline;
466
467         /*
468          * We're making the somewhat arbitrary decision that
469          * having internal errors enabled means that lisp has
470          * sufficient marbles to be able to handle exceptions.
471          *
472          * Exceptions aren't supposed to happen during cold
473          * init or reinit anyway.
474          */
475
476         /*
477          * We use the same mechanism as the sigtrap emulator above
478          * with just a couple changes. We obviously use a different
479          * trampoline and wrapper function, we kill out any live
480          * floating point exceptions, and we save off the exception
481          * record as well as the context.
482          */
483
484         /* Save off context and exception information */
485         memcpy(&exception_frame->context, context, sizeof(CONTEXT));
486         memcpy(&exception_frame->exception, exception_record, sizeof(EXCEPTION_RECORD));
487
488         /* Set up to activate trampoline when we return */
489         context->Eax = context->Eip;
490         context->Eip = (unsigned long)&exception_trampoline;
491
492         /* Make sure a floating-point trap doesn't kill us */
493         context->FloatSave.StatusWord &= ~0x3f;
494
495         /* And return */
496         return ExceptionContinueExecution;
497     }
498
499     fprintf(stderr, "Exception Code: 0x%lx.\n", exception_record->ExceptionCode);
500     fprintf(stderr, "Faulting IP: 0x%lx.\n", (DWORD)exception_record->ExceptionAddress);
501     if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
502         MEMORY_BASIC_INFORMATION mem_info;
503
504         if (VirtualQuery(fault_address, &mem_info, sizeof mem_info)) {
505             fprintf(stderr, "page status: 0x%lx.\n", mem_info.State);
506         }
507
508         fprintf(stderr, "Was writing: %ld, where: 0x%lx.\n",
509                 exception_record->ExceptionInformation[0],
510                 (DWORD)fault_address);
511     }
512
513     fflush(stderr);
514
515     fake_foreign_function_call(context);
516     monitor_or_something();
517
518     return ExceptionContinueSearch;
519 }
520
521 void handle_win32_exception_wrapper(void)
522 {
523     struct lisp_exception_frame *frame = find_our_seh_frame();
524     CONTEXT context;
525     EXCEPTION_RECORD exception_record;
526     lispobj context_sap;
527     lispobj exception_record_sap;
528
529     memcpy(&context, &frame->context, sizeof(CONTEXT));
530     memcpy(&exception_record, &frame->exception, sizeof(EXCEPTION_RECORD));
531
532     fake_foreign_function_call(&context);
533
534     /* Allocate the SAP objects while the "interrupts" are still
535      * disabled. */
536     context_sap = alloc_sap(&context);
537     exception_record_sap = alloc_sap(&exception_record);
538
539     funcall2(SymbolFunction(HANDLE_WIN32_EXCEPTION), context_sap,
540              exception_record_sap);
541
542     undo_fake_foreign_function_call(&context);
543
544     memcpy(&frame->context, &context, sizeof(CONTEXT));
545 }
546
547 void
548 wos_install_interrupt_handlers(struct lisp_exception_frame *handler)
549 {
550     handler->next_frame = get_seh_frame();
551     handler->handler = &handle_exception;
552     set_seh_frame(handler);
553 }
554
555 void bcopy(const void *src, void *dest, size_t n)
556 {
557     MoveMemory(dest, src, n);
558 }
559
560 /*
561  * The stubs below are replacements for the windows versions,
562  * which can -fail- when used in our memory spaces because they
563  * validate the memory spaces they are passed in a way that
564  * denies our exception handler a chance to run.
565  */
566
567 void *memmove(void *dest, const void *src, size_t n)
568 {
569     if (dest < src) {
570         int i;
571         for (i = 0; i < n; i++) *(((char *)dest)+i) = *(((char *)src)+i);
572     } else {
573         while (n--) *(((char *)dest)+n) = *(((char *)src)+n);
574     }
575     return dest;
576 }
577
578 void *memcpy(void *dest, const void *src, size_t n)
579 {
580     while (n--) *(((char *)dest)+n) = *(((char *)src)+n);
581     return dest;
582 }
583
584 char *dirname(char *path)
585 {
586     static char buf[PATH_MAX + 1];
587     size_t pathlen = strlen(path);
588     int i;
589
590     if (pathlen >= sizeof(buf)) {
591         lose("Pathname too long in dirname.\n");
592         return NULL;
593     }
594
595     strcpy(buf, path);
596     for (i = pathlen; i >= 0; --i) {
597         if (buf[i] == '/' || buf[i] == '\\') {
598             buf[i] = '\0';
599             break;
600         }
601     }
602
603     return buf;
604 }
605
606 /* This is a manually-maintained version of ldso_stubs.S. */
607
608 void scratch(void)
609 {
610     strerror(42);
611     asin(0);
612     acos(0);
613     sinh(0);
614     cosh(0);
615     hypot(0, 0);
616     write(0, 0, 0);
617     close(0);
618     rename(0,0);
619     getcwd(0,0);
620     dup(0);
621     LoadLibrary(0);
622     GetProcAddress(0, 0);
623     FreeLibrary(0);
624     mkdir(0);
625     isatty(0);
626     access(0,0);
627     GetLastError();
628     FormatMessageA(0, 0, 0, 0, 0, 0, 0);
629     _get_osfhandle(0);
630     ReadFile(0, 0, 0, 0, 0);
631     WriteFile(0, 0, 0, 0, 0);
632     PeekNamedPipe(0, 0, 0, 0, 0, 0);
633     FlushConsoleInputBuffer(0);
634     PeekConsoleInput(0, 0, 0, 0);
635     Sleep(0);
636 }
637
638 /* EOF */