0.8.18.14:
[sbcl.git] / src / runtime / x86-64-linux-os.c
1 /*
2  * The x86 Linux incarnation of arch-dependent OS-dependent routines.
3  * See also "linux-os.c".
4  */
5
6 /*
7  * This software is part of the SBCL system. See the README file for
8  * more information.
9  *
10  * This software is derived from the CMU CL system, which was
11  * written at Carnegie Mellon University and released into the
12  * public domain. The software is in the public domain and is
13  * provided with absolutely no warranty. See the COPYING and CREDITS
14  * files for more information.
15  */
16
17 #include <stdio.h>
18 #include <stddef.h>
19 #include <sys/param.h>
20 #include <sys/file.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #define __USE_GNU
26 #include <sys/ucontext.h>
27 #undef __USE_GNU
28
29
30 #include "./signal.h"
31 #include "os.h"
32 #include "arch.h"
33 #include "globals.h"
34 #include "interrupt.h"
35 #include "interr.h"
36 #include "lispregs.h"
37 #include "sbcl.h"
38 #include <sys/socket.h>
39 #include <sys/utsname.h>
40
41 #include <sys/types.h>
42 #include <signal.h>
43 /* #include <sys/sysinfo.h> */
44 #include <sys/time.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <asm/ldt.h>
48 #include <linux/unistd.h>
49 #include <sys/mman.h>
50 #include <linux/version.h>
51 #include "thread.h"             /* dynamic_values_bytes */
52
53 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
54 #define user_desc  modify_ldt_ldt_s 
55 #endif
56
57 _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount );
58
59 #include "validate.h"
60 size_t os_vm_page_size;
61
62 u32 local_ldt_copy[LDT_ENTRIES*LDT_ENTRY_SIZE/sizeof(u32)];
63
64 /* This is never actually called, but it's great for calling from gdb when
65  * users have thread-related problems that maintainers can't duplicate */
66
67 void debug_get_ldt()
68
69     int n=modify_ldt (0, local_ldt_copy, sizeof local_ldt_copy);
70     printf("%d bytes in ldt: print/x local_ldt_copy\n", n);
71 }
72
73 lispobj modify_ldt_lock;        /* protect all calls to modify_ldt */
74
75 int arch_os_thread_init(struct thread *thread) {
76     stack_t sigstack;
77 #ifdef LISP_FEATURE_SB_THREAD
78     /* this must be called from a function that has an exclusive lock
79      * on all_threads
80      */
81     struct user_desc ldt_entry = {
82         1, 0, 0, /* index, address, length filled in later */
83         1, MODIFY_LDT_CONTENTS_DATA, 0, 0, 0, 1
84     }; 
85     int n;
86     get_spinlock(&modify_ldt_lock,thread);
87     n=modify_ldt(0,local_ldt_copy,sizeof local_ldt_copy);
88     /* get next free ldt entry */
89
90     if(n) {
91         u32 *p;
92         for(n=0,p=local_ldt_copy;*p;p+=LDT_ENTRY_SIZE/sizeof(u32))
93             n++;
94     }
95     ldt_entry.entry_number=n;
96     ldt_entry.base_addr=(unsigned long) thread;
97     ldt_entry.limit=dynamic_values_bytes;
98     ldt_entry.limit_in_pages=0;
99     if (modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) {
100         modify_ldt_lock=0;
101         /* modify_ldt call failed: something magical is not happening */
102         return -1;
103     }
104     __asm__ __volatile__ ("movw %w0, %%fs" : : "q" 
105                           ((n << 3) /* selector number */
106                            + (1 << 2) /* TI set = LDT */
107                            + 3)); /* privilege level */
108     thread->tls_cookie=n;
109     modify_ldt_lock=0;
110
111     if(n<0) return 0;
112 #endif
113 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
114     /* Signal handlers are run on the control stack, so if it is exhausted
115      * we had better use an alternate stack for whatever signal tells us
116      * we've exhausted it */
117     sigstack.ss_sp=((void *) thread)+dynamic_values_bytes;
118     sigstack.ss_flags=0;
119     sigstack.ss_size = 32*SIGSTKSZ;
120     sigaltstack(&sigstack,0);
121 #endif
122     return 1;
123 }
124
125 struct thread *debug_get_fs() {
126     register u32 fs;
127     __asm__ __volatile__ ("movl %%fs,%0" : "=r" (fs)  : );
128     return fs;
129 }
130
131 /* free any arch/os-specific resources used by thread, which is now
132  * defunct.  Not called on live threads
133  */
134
135 int arch_os_thread_cleanup(struct thread *thread) {
136     struct user_desc ldt_entry = {
137         0, 0, 0, 
138         0, MODIFY_LDT_CONTENTS_DATA, 0, 0, 0, 0
139     }; 
140
141     ldt_entry.entry_number=thread->tls_cookie;
142     get_spinlock(&modify_ldt_lock,thread);
143     if (modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) {
144         modify_ldt_lock=0;
145         /* modify_ldt call failed: something magical is not happening */
146         return 0;
147     }
148     modify_ldt_lock=0;
149     return 1;
150 }
151
152
153 os_context_register_t *
154 os_context_register_addr(os_context_t *context, int offset)
155 {
156 #define RCASE(name) case reg_ ## name: return &context->uc_mcontext.gregs[REG_ ## name];
157     switch(offset) {
158         RCASE(RAX)
159         RCASE(RCX)
160         RCASE(RDX)
161         RCASE(RBX)
162         RCASE(RSP)
163         RCASE(RBP)
164         RCASE(RSI)
165         RCASE(RDI)
166         RCASE(R8)
167         RCASE(R9)
168         RCASE(R10)
169         RCASE(R11)
170         RCASE(R12)
171         RCASE(R13)
172         RCASE(R14)
173         RCASE(R15)
174       default: 
175         if(offset<NGREG) 
176             return &context->uc_mcontext.gregs[offset/2+4];
177         else return 0;
178     }
179     return &context->uc_mcontext.gregs[offset];
180 }
181
182 os_context_register_t *
183 os_context_pc_addr(os_context_t *context)
184 {
185     return &context->uc_mcontext.gregs[REG_RIP]; /*  REG_EIP */
186 }
187
188 os_context_register_t *
189 os_context_sp_addr(os_context_t *context)
190 {                               
191     return &context->uc_mcontext.gregs[REG_RSP];
192 }
193
194 os_context_register_t *
195 os_context_fp_addr(os_context_t *context)
196 {
197     return &context->uc_mcontext.gregs[REG_RBP];
198 }
199
200 unsigned long
201 os_context_fp_control(os_context_t *context)
202 {
203 #if 0
204     return ((((context->uc_mcontext.fpregs->cw) & 0xffff) ^ 0x3f) |
205             (((context->uc_mcontext.fpregs->sw) & 0xffff) << 16));
206 #else
207     return 0;
208 #endif
209 }
210
211 sigset_t *
212 os_context_sigmask_addr(os_context_t *context)
213 {
214     return &context->uc_sigmask;
215 }
216
217 void
218 os_restore_fp_control(os_context_t *context)
219 {
220 #if 0
221     asm ("fldcw %0" : : "m" (context->uc_mcontext.fpregs->cw));
222 #endif
223 }
224
225 void
226 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
227 {
228 }
229