2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
10 #include <arch/thread.h>
14 #include <arch/user_debugger.h>
26 #include <util/AutoLock.h>
27 #include <util/Random.h>
28 #include <vm/vm_types.h>
29 #include <vm/VMAddressSpace.h>
31 #include "paging/X86PagingStructures.h"
32 #include "paging/X86VMTranslationMap.h"
33 #include "x86_signals.h"
36 //#define TRACE_ARCH_THREAD
37 #ifdef TRACE_ARCH_THREAD
38 # define TRACE(x) dprintf x
44 #ifdef SYSCALL_TRACING
46 namespace SyscallTracing
{
48 class RestartSyscall
: public AbstractTraceEntry
{
55 virtual void AddDump(TraceOutput
& out
)
57 out
.Print("syscall restart");
63 # define TSYSCALL(x) new(std::nothrow) SyscallTracing::x
67 #endif // SYSCALL_TRACING
73 static struct arch_thread sInitialState
_ALIGNED(16);
74 // the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it
78 set_fs_register(uint32 segment
)
80 asm("movl %0,%%fs" :: "r" (segment
));
85 x86_restart_syscall(struct iframe
* frame
)
87 Thread
* thread
= thread_get_current_thread();
89 atomic_and(&thread
->flags
, ~THREAD_FLAGS_RESTART_SYSCALL
);
90 atomic_or(&thread
->flags
, THREAD_FLAGS_SYSCALL_RESTARTED
);
92 frame
->ax
= frame
->orig_eax
;
93 frame
->dx
= frame
->orig_edx
;
95 // undoes the "int $99"/"sysenter"/"syscall" instruction
96 // (so that it'll be executed again)
98 TSYSCALL(RestartSyscall());
103 x86_set_tls_context(Thread
*thread
)
105 segment_descriptor
* gdt
= get_gdt(smp_get_current_cpu());
106 set_segment_descriptor_base(&gdt
[USER_TLS_SEGMENT
],
107 thread
->user_local_storage
);
108 set_fs_register((USER_TLS_SEGMENT
<< 3) | DPL_USER
);
113 arch_randomize_stack_pointer(addr_t value
)
115 STATIC_ASSERT(MAX_RANDOM_VALUE
>= B_PAGE_SIZE
- 1);
116 value
-= random_value() & (B_PAGE_SIZE
- 1);
117 return (value
& ~addr_t(0xf)) - 4;
118 // This means, result % 16 == 12, which is what esp should adhere to
119 // when a function is entered for the stack to be considered aligned to
125 get_signal_stack(Thread
* thread
, struct iframe
* frame
, struct sigaction
* action
,
128 // use the alternate signal stack if we should and can
129 if (thread
->signal_stack_enabled
130 && (action
->sa_flags
& SA_ONSTACK
) != 0
131 && (frame
->user_sp
< thread
->signal_stack_base
132 || frame
->user_sp
>= thread
->signal_stack_base
133 + thread
->signal_stack_size
)) {
134 addr_t stackTop
= thread
->signal_stack_base
+ thread
->signal_stack_size
;
135 return (uint8
*)arch_randomize_stack_pointer(stackTop
- spaceNeeded
);
138 return (uint8
*)((frame
->user_sp
- spaceNeeded
) & ~addr_t(0xf)) - 4;
139 // align stack pointer (cf. arch_randomize_stack_pointer())
147 arch_thread_init(struct kernel_args
*args
)
149 // save one global valid FPU state; it will be copied in the arch dependent
150 // part of each new thread
152 asm volatile ("clts; fninit; fnclex;");
154 x86_fxsave(sInitialState
.fpu_state
);
156 x86_fnsave(sInitialState
.fpu_state
);
163 arch_thread_init_thread_struct(Thread
*thread
)
165 // set up an initial state (stack & fpu)
166 memcpy(&thread
->arch_info
, &sInitialState
, sizeof(struct arch_thread
));
171 /*! Prepares the given thread's kernel stack for executing its entry function.
173 \param thread The thread.
174 \param stack The usable bottom of the thread's kernel stack.
175 \param stackTop The usable top of the thread's kernel stack.
176 \param function The entry function the thread shall execute.
177 \param data Pointer to be passed to the entry function.
180 arch_thread_init_kthread_stack(Thread
* thread
, void* _stack
, void* _stackTop
,
181 void (*function
)(void*), const void* data
)
183 addr_t
* stackTop
= (addr_t
*)_stackTop
;
185 TRACE(("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
186 "%p\n", stackTop
, function
, data
));
188 // push the function argument, a pointer to the data
189 *--stackTop
= (addr_t
)data
;
191 // push a dummy return address for the function
194 // push the function address -- that's the return address used after the
196 *--stackTop
= (addr_t
)function
;
198 // simulate pushad as done by x86_context_switch()
199 for (int i
= 0; i
< 8; i
++)
202 // save the stack position
203 thread
->arch_info
.current_stack
.esp
= stackTop
;
204 thread
->arch_info
.current_stack
.ss
= (addr_t
*)KERNEL_DATA_SELECTOR
;
209 arch_thread_dump_info(void *info
)
211 struct arch_thread
*at
= (struct arch_thread
*)info
;
213 kprintf("\tesp: %p\n", at
->current_stack
.esp
);
214 kprintf("\tss: %p\n", at
->current_stack
.ss
);
215 kprintf("\tfpu_state at %p\n", at
->fpu_state
);
219 /*! Sets up initial thread context and enters user space
222 arch_thread_enter_userspace(Thread
* thread
, addr_t entry
, void* args1
,
225 addr_t stackTop
= thread
->user_stack_base
+ thread
->user_stack_size
;
228 TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
229 "ustack_top 0x%lx\n", entry
, args1
, args2
, stackTop
));
231 stackTop
= arch_randomize_stack_pointer(stackTop
- sizeof(args
));
233 // Copy the address of the stub that calls exit_thread() when the thread
234 // entry function returns to the top of the stack to act as the return
235 // address. The stub is inside commpage.
236 addr_t commPageAddress
= (addr_t
)thread
->team
->commpage_address
;
237 args
[0] = ((addr_t
*)commPageAddress
)[COMMPAGE_ENTRY_X86_THREAD_EXIT
]
239 args
[1] = (uint32
)args1
;
240 args
[2] = (uint32
)args2
;
242 if (user_memcpy((void *)stackTop
, args
, sizeof(args
)) < B_OK
)
243 return B_BAD_ADDRESS
;
245 // prepare the user iframe
247 frame
.type
= IFRAME_TYPE_SYSCALL
;
248 frame
.gs
= USER_DATA_SELECTOR
;
249 // frame.fs not used, we call x86_set_tls_context() on context switch
250 frame
.es
= USER_DATA_SELECTOR
;
251 frame
.ds
= USER_DATA_SELECTOR
;
253 frame
.cs
= USER_CODE_SELECTOR
;
254 frame
.flags
= X86_EFLAGS_RESERVED1
| X86_EFLAGS_INTERRUPT
255 | (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT
);
256 frame
.user_sp
= stackTop
;
257 frame
.user_ss
= USER_DATA_SELECTOR
;
259 // return to userland
260 x86_initial_return_to_userland(thread
, &frame
);
267 /*! Sets up the user iframe for invoking a signal handler.
269 The function fills in the remaining fields of the given \a signalFrameData,
270 copies it to the thread's userland stack (the one on which the signal shall
271 be handled), and sets up the user iframe so that when returning to userland
272 a wrapper function is executed that calls the user-defined signal handler.
273 When the signal handler returns, the wrapper function shall call the
274 "restore signal frame" syscall with the (possibly modified) signal frame
277 The following fields of the \a signalFrameData structure still need to be
279 - \c context.uc_stack: The stack currently used by the thread.
280 - \c context.uc_mcontext: The current userland state of the registers.
281 - \c syscall_restart_return_value: Architecture specific use. On x86 the
282 value of eax and edx which are overwritten by the syscall return value.
284 Furthermore the function needs to set \c thread->user_signal_context to the
285 userland pointer to the \c ucontext_t on the user stack.
287 \param thread The current thread.
288 \param action The signal action specified for the signal to be handled.
289 \param signalFrameData A partially initialized structure of all the data
290 that need to be copied to userland.
291 \return \c B_OK on success, another error code, if something goes wrong.
294 arch_setup_signal_frame(Thread
* thread
, struct sigaction
* action
,
295 struct signal_frame_data
* signalFrameData
)
297 struct iframe
*frame
= x86_get_current_iframe();
298 if (!IFRAME_IS_USER(frame
)) {
299 panic("arch_setup_signal_frame(): No user iframe!");
303 // In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
304 // had the same signal number.
305 if ((action
->sa_flags
& SA_BEOS_COMPATIBLE_HANDLER
) != 0
306 && signalFrameData
->info
.si_signo
== SIGBUS
) {
307 signalFrameData
->info
.si_signo
= SIGSEGV
;
310 // store the register state in signalFrameData->context.uc_mcontext
311 signalFrameData
->context
.uc_mcontext
.eip
= frame
->ip
;
312 signalFrameData
->context
.uc_mcontext
.eflags
= frame
->flags
;
313 signalFrameData
->context
.uc_mcontext
.eax
= frame
->ax
;
314 signalFrameData
->context
.uc_mcontext
.ecx
= frame
->cx
;
315 signalFrameData
->context
.uc_mcontext
.edx
= frame
->dx
;
316 signalFrameData
->context
.uc_mcontext
.ebp
= frame
->bp
;
317 signalFrameData
->context
.uc_mcontext
.esp
= frame
->user_sp
;
318 signalFrameData
->context
.uc_mcontext
.edi
= frame
->di
;
319 signalFrameData
->context
.uc_mcontext
.esi
= frame
->si
;
320 signalFrameData
->context
.uc_mcontext
.ebx
= frame
->bx
;
321 x86_fnsave((void *)(&signalFrameData
->context
.uc_mcontext
.xregs
));
323 // Fill in signalFrameData->context.uc_stack
324 signal_get_user_stack(frame
->user_sp
, &signalFrameData
->context
.uc_stack
);
326 // store orig_eax/orig_edx in syscall_restart_return_value
327 signalFrameData
->syscall_restart_return_value
328 = (uint64
)frame
->orig_edx
<< 32 | frame
->orig_eax
;
330 // get the stack to use -- that's either the current one or a special signal
332 uint32 stackFrame
[2];
333 uint8
* userStack
= get_signal_stack(thread
, frame
, action
,
334 sizeof(*signalFrameData
) + sizeof(stackFrame
));
336 // copy the signal frame data onto the stack
337 signal_frame_data
* userSignalFrameData
338 = (signal_frame_data
*)(userStack
+ sizeof(stackFrame
));
339 if (user_memcpy(userSignalFrameData
, signalFrameData
,
340 sizeof(*signalFrameData
)) != B_OK
) {
341 return B_BAD_ADDRESS
;
344 // prepare the user stack frame for a function call to the signal handler
346 stackFrame
[0] = frame
->ip
;
347 stackFrame
[1] = (addr_t
)userSignalFrameData
;
348 // parameter: pointer to signal frame data
350 if (user_memcpy(userStack
, stackFrame
, sizeof(stackFrame
)) != B_OK
)
351 return B_BAD_ADDRESS
;
353 // Update Thread::user_signal_context, now that everything seems to have
355 thread
->user_signal_context
= &userSignalFrameData
->context
;
357 // Adjust the iframe's esp and eip, so that the thread will continue with
358 // the prepared stack, executing the signal handler wrapper function.
359 frame
->user_sp
= (addr_t
)userStack
;
360 frame
->ip
= x86_get_user_signal_handler_wrapper(
361 (action
->sa_flags
& SA_BEOS_COMPATIBLE_HANDLER
) != 0,
362 thread
->team
->commpage_address
);
369 arch_restore_signal_frame(struct signal_frame_data
* signalFrameData
)
371 struct iframe
* frame
= x86_get_current_iframe();
373 TRACE(("### arch_restore_signal_frame: entry\n"));
375 frame
->orig_eax
= (uint32
)signalFrameData
->syscall_restart_return_value
;
377 = (uint32
)(signalFrameData
->syscall_restart_return_value
>> 32);
379 frame
->ip
= signalFrameData
->context
.uc_mcontext
.eip
;
380 frame
->flags
= (frame
->flags
& ~(uint32
)X86_EFLAGS_USER_FLAGS
)
381 | (signalFrameData
->context
.uc_mcontext
.eflags
& X86_EFLAGS_USER_FLAGS
);
382 frame
->ax
= signalFrameData
->context
.uc_mcontext
.eax
;
383 frame
->cx
= signalFrameData
->context
.uc_mcontext
.ecx
;
384 frame
->dx
= signalFrameData
->context
.uc_mcontext
.edx
;
385 frame
->bp
= signalFrameData
->context
.uc_mcontext
.ebp
;
386 frame
->user_sp
= signalFrameData
->context
.uc_mcontext
.esp
;
387 frame
->di
= signalFrameData
->context
.uc_mcontext
.edi
;
388 frame
->si
= signalFrameData
->context
.uc_mcontext
.esi
;
389 frame
->bx
= signalFrameData
->context
.uc_mcontext
.ebx
;
391 x86_frstor((void*)(&signalFrameData
->context
.uc_mcontext
.xregs
));
393 TRACE(("### arch_restore_signal_frame: exit\n"));
395 return (int64
)frame
->ax
| ((int64
)frame
->dx
<< 32);
400 arch_syscall_64_bit_return_value(void)
402 Thread
* thread
= thread_get_current_thread();
403 atomic_or(&thread
->flags
, THREAD_FLAGS_64_BIT_SYSCALL_RETURN
);