Implemented threading for x86_64.
* Thread creation and switching is working fine, however threads do not yet get interrupted because I've not implemented hardware interrupt handling yet (I'll do that next). * I've made some changes to struct iframe: I've removed the e/r prefixes from the member names for both 32/64, so now they're just named ip, ax, bp, etc. This makes it easier to write code that works with both 32/64 without having to deal with different iframe member names.
This commit is contained in:
@@ -15,25 +15,25 @@ struct iframe {
|
||||
uint32 fs;
|
||||
uint32 es;
|
||||
uint32 ds;
|
||||
uint32 edi;
|
||||
uint32 esi;
|
||||
uint32 ebp;
|
||||
uint32 esp;
|
||||
uint32 ebx;
|
||||
uint32 edx;
|
||||
uint32 ecx;
|
||||
uint32 eax;
|
||||
uint32 di;
|
||||
uint32 si;
|
||||
uint32 bp;
|
||||
uint32 sp;
|
||||
uint32 bx;
|
||||
uint32 dx;
|
||||
uint32 cx;
|
||||
uint32 ax;
|
||||
uint32 orig_eax;
|
||||
uint32 orig_edx;
|
||||
uint32 vector;
|
||||
uint32 error_code;
|
||||
uint32 eip;
|
||||
uint32 ip;
|
||||
uint32 cs;
|
||||
uint32 flags;
|
||||
|
||||
// user_esp and user_ss are only present when the iframe is a userland
|
||||
// user_sp and user_ss are only present when the iframe is a userland
|
||||
// iframe (IFRAME_IS_USER()). A kernel iframe is shorter.
|
||||
uint32 user_esp;
|
||||
uint32 user_sp;
|
||||
uint32 user_ss;
|
||||
};
|
||||
|
||||
|
||||
@@ -76,9 +76,9 @@ struct gdt_idt_descr {
|
||||
|
||||
struct tss {
|
||||
uint32 _reserved1;
|
||||
uint64 rsp0;
|
||||
uint64 rsp1;
|
||||
uint64 rsp2;
|
||||
uint64 sp0;
|
||||
uint64 sp1;
|
||||
uint64 sp2;
|
||||
uint64 _reserved2;
|
||||
uint64 ist1;
|
||||
uint64 ist2;
|
||||
|
||||
@@ -16,21 +16,21 @@ struct iframe {
|
||||
uint64 r10;
|
||||
uint64 r9;
|
||||
uint64 r8;
|
||||
uint64 rbp;
|
||||
uint64 rsi;
|
||||
uint64 rdi;
|
||||
uint64 rdx;
|
||||
uint64 rcx;
|
||||
uint64 rbx;
|
||||
uint64 rax;
|
||||
uint64 bp;
|
||||
uint64 si;
|
||||
uint64 di;
|
||||
uint64 dx;
|
||||
uint64 cx;
|
||||
uint64 bx;
|
||||
uint64 ax;
|
||||
uint64 vector;
|
||||
uint64 error_code;
|
||||
uint64 rip;
|
||||
uint64 ip;
|
||||
uint64 cs;
|
||||
uint64 flags;
|
||||
|
||||
// Only present when the iframe is a userland iframe (IFRAME_IS_USER()).
|
||||
uint64 user_rsp;
|
||||
uint64 user_sp;
|
||||
uint64 user_ss;
|
||||
} _PACKED;
|
||||
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
#endif // !_ASSEMBLER
|
||||
|
||||
|
||||
#undef PAUSE
|
||||
#define PAUSE() asm volatile ("pause;")
|
||||
|
||||
|
||||
// MSR registers (possibly Intel specific)
|
||||
#define IA32_MSR_TSC 0x10
|
||||
#define IA32_MSR_APIC_BASE 0x1b
|
||||
@@ -40,6 +36,14 @@
|
||||
#define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200
|
||||
#define IA32_MSR_MTRR_PHYSICAL_MASK_0 0x201
|
||||
|
||||
// x86_64 MSRs.
|
||||
#define IA32_MSR_STAR 0xc0000081
|
||||
#define IA32_MSR_LSTAR 0xc0000082
|
||||
#define IA32_MSR_FMASK 0xc0000084
|
||||
#define IA32_MSR_FS_BASE 0xc0000100
|
||||
#define IA32_MSR_GS_BASE 0xc0000101
|
||||
#define IA32_MSR_KERNEL_GS_BASE 0xc0000102
|
||||
|
||||
// K8 MSR registers
|
||||
#define K8_MSR_IPM 0xc0010055
|
||||
|
||||
@@ -268,6 +272,9 @@ typedef struct arch_cpu_info {
|
||||
} arch_cpu_info;
|
||||
|
||||
|
||||
#undef PAUSE
|
||||
#define PAUSE() asm volatile ("pause;")
|
||||
|
||||
#define nop() __asm__ ("nop"::)
|
||||
|
||||
#define x86_read_cr0() ({ \
|
||||
@@ -379,11 +386,13 @@ void x86_context_switch(struct arch_thread* oldState,
|
||||
struct arch_thread* newState);
|
||||
void x86_userspace_thread_exit(void);
|
||||
void x86_end_userspace_thread_exit(void);
|
||||
void x86_swap_pgdir(uint32 newPageDir);
|
||||
void x86_swap_pgdir(addr_t newPageDir);
|
||||
void x86_set_tss_and_kstack(addr_t kstack);
|
||||
void x86_fxsave(void* fpuState);
|
||||
void x86_fxrstor(const void* fpuState);
|
||||
void x86_noop_swap(void* oldFpuState, const void* newFpuState);
|
||||
void x86_fxsave_swap(void* oldFpuState, const void* newFpuState);
|
||||
addr_t x86_read_ebp();
|
||||
addr_t x86_get_stack_frame();
|
||||
uint64 x86_read_msr(uint32 registerNumber);
|
||||
void x86_write_msr(uint32 registerNumber, uint64 value);
|
||||
void* x86_get_idt(int32 cpu);
|
||||
@@ -401,10 +410,8 @@ void x86_page_fault_exception_double_fault(struct iframe* frame);
|
||||
|
||||
#ifndef __x86_64__
|
||||
|
||||
void x86_set_tss_and_kstack(addr_t kstack);
|
||||
void x86_fnsave(void* fpuState);
|
||||
void x86_frstor(const void* fpuState);
|
||||
void x86_noop_swap(void* oldFpuState, const void* newFpuState);
|
||||
void x86_fnsave_swap(void* oldFpuState, const void* newFpuState);
|
||||
void x86_set_task_gate(int32 cpu, int32 n, int32 segment);
|
||||
int32 x86_double_fault_get_cpu(void);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
struct arch_debug_registers {
|
||||
uint32 ebp;
|
||||
addr_t bp;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -16,35 +16,40 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct sigaction;
|
||||
|
||||
|
||||
struct iframe* x86_get_user_iframe(void);
|
||||
struct iframe* x86_get_current_iframe(void);
|
||||
struct iframe* x86_get_thread_user_iframe(Thread* thread);
|
||||
|
||||
uint32 x86_next_page_directory(Thread* from, Thread* to);
|
||||
phys_addr_t x86_next_page_directory(Thread* from, Thread* to);
|
||||
void x86_initial_return_to_userland(Thread* thread, struct iframe* iframe);
|
||||
uint8* x86_get_signal_stack(Thread* thread, struct iframe* frame,
|
||||
struct sigaction* action);
|
||||
|
||||
void x86_restart_syscall(struct iframe* frame);
|
||||
|
||||
void x86_set_tls_context(Thread* thread);
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
// TODO
|
||||
|
||||
extern Thread* gCurrentThread;
|
||||
|
||||
static inline Thread*
|
||||
arch_thread_get_current_thread(void)
|
||||
{
|
||||
return gCurrentThread;
|
||||
addr_t addr;
|
||||
__asm__("mov %%gs:0, %0" : "=r"(addr));
|
||||
return (Thread*)addr;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
arch_thread_set_current_thread(Thread* t)
|
||||
{
|
||||
gCurrentThread = t;
|
||||
// Point GS segment base at thread architecture data.
|
||||
t->arch_info.thread = t;
|
||||
x86_write_msr(IA32_MSR_GS_BASE, (addr_t)&t->arch_info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,27 +12,42 @@
|
||||
#include <arch_cpu.h>
|
||||
|
||||
|
||||
namespace BKernel {
|
||||
struct Thread;
|
||||
}
|
||||
|
||||
|
||||
#define _ALIGNED(bytes) __attribute__((aligned(bytes)))
|
||||
// move this to somewhere else, maybe BeBuild.h?
|
||||
|
||||
|
||||
#ifndef __x86_64__
|
||||
struct farcall {
|
||||
uint32* esp;
|
||||
uint32* ss;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// architecture specific thread info
|
||||
struct arch_thread {
|
||||
#ifdef __x86_64__
|
||||
uint64* rsp;
|
||||
// Back pointer to the containing Thread structure. The GS segment base is
|
||||
// pointed here, used to get the current thread.
|
||||
BKernel::Thread* thread;
|
||||
|
||||
// RSP for kernel entry used by SYSCALL, and temporary scratch space.
|
||||
uint64* syscall_rsp;
|
||||
uint64* user_rsp;
|
||||
|
||||
uint64* current_stack;
|
||||
#else
|
||||
struct farcall current_stack;
|
||||
struct farcall interrupt_stack;
|
||||
struct farcall current_stack;
|
||||
struct farcall interrupt_stack;
|
||||
#endif
|
||||
|
||||
// 512 byte floating point save point - this must be 16 byte aligned
|
||||
uint8 fpu_state[512] _ALIGNED(16);
|
||||
uint8 fpu_state[512] _ALIGNED(16);
|
||||
} _ALIGNED(16);
|
||||
|
||||
|
||||
@@ -40,7 +55,7 @@ struct arch_team {
|
||||
// gcc treats empty structures as zero-length in C, but as if they contain
|
||||
// a char in C++. So we have to put a dummy in to be able to use the struct
|
||||
// from both in a consistent way.
|
||||
char dummy;
|
||||
char dummy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -71,11 +71,11 @@ FUNCTION(x86_fxsave_swap):
|
||||
ret
|
||||
FUNCTION_END(x86_fxsave_swap)
|
||||
|
||||
/* uint32 x86_read_ebp(); */
|
||||
FUNCTION(x86_read_ebp):
|
||||
/* uint32 x86_get_stack_frame(); */
|
||||
FUNCTION(x86_get_stack_frame):
|
||||
movl %ebp, %eax
|
||||
ret
|
||||
FUNCTION_END(x86_read_ebp)
|
||||
FUNCTION_END(x86_get_stack_frame)
|
||||
|
||||
/* uint64 x86_read_msr(uint32 register); */
|
||||
FUNCTION(x86_read_msr):
|
||||
|
||||
@@ -161,7 +161,7 @@ invalid_exception(struct iframe* frame)
|
||||
char name[32];
|
||||
panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %ld!\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->eip, thread ? thread->id : -1);
|
||||
frame->ip, thread ? thread->id : -1);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,14 +194,14 @@ unexpected_exception(struct iframe* frame)
|
||||
type = B_DIVIDE_ERROR;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTDIV;
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
case 4: // Overflow Exception (#OF)
|
||||
type = B_OVERFLOW_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTOVF;
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
case 5: // BOUND Range Exceeded Exception (#BR)
|
||||
@@ -214,14 +214,14 @@ unexpected_exception(struct iframe* frame)
|
||||
type = B_INVALID_OPCODE_EXCEPTION;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_ILLOPC;
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
case 13: // General Protection Exception (#GP)
|
||||
type = B_GENERAL_PROTECTION_FAULT;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_PRVOPC; // or ILL_PRVREG
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
case 16: // x87 FPU Floating-Point Error (#MF)
|
||||
@@ -230,7 +230,7 @@ unexpected_exception(struct iframe* frame)
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the FPU status
|
||||
// register!
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
case 17: // Alignment Check Exception (#AC)
|
||||
@@ -247,7 +247,7 @@ unexpected_exception(struct iframe* frame)
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the MXCSR register!
|
||||
signalAddress = frame->eip;
|
||||
signalAddress = frame->ip;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -300,15 +300,15 @@ x86_double_fault_exception(struct iframe* frame)
|
||||
frame->ds = tss->ds;
|
||||
frame->fs = tss->fs;
|
||||
frame->gs = tss->gs;
|
||||
frame->eip = tss->eip;
|
||||
frame->ebp = tss->ebp;
|
||||
frame->esp = tss->esp;
|
||||
frame->eax = tss->eax;
|
||||
frame->ebx = tss->ebx;
|
||||
frame->ecx = tss->ecx;
|
||||
frame->edx = tss->edx;
|
||||
frame->esi = tss->esi;
|
||||
frame->edi = tss->edi;
|
||||
frame->ip = tss->eip;
|
||||
frame->bp = tss->ebp;
|
||||
frame->sp = tss->esp;
|
||||
frame->ax = tss->eax;
|
||||
frame->bx = tss->ebx;
|
||||
frame->cx = tss->ecx;
|
||||
frame->dx = tss->edx;
|
||||
frame->si = tss->esi;
|
||||
frame->di = tss->edi;
|
||||
frame->flags = tss->eflags;
|
||||
|
||||
// Use a special handler for page faults which avoids the triple fault
|
||||
@@ -328,10 +328,10 @@ x86_page_fault_exception_double_fault(struct iframe* frame)
|
||||
cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
|
||||
addr_t faultHandler = cpu.fault_handler;
|
||||
if (faultHandler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
debug_set_page_fault_info(cr2, frame->ip,
|
||||
(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = faultHandler;
|
||||
frame->ebp = cpu.fault_handler_stack_pointer;
|
||||
frame->ip = faultHandler;
|
||||
frame->bp = cpu.fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ x86_page_fault_exception_double_fault(struct iframe* frame)
|
||||
// print the info we've got and enter an infinite loop.
|
||||
kprintf("Page fault in double fault debugger without fault handler! "
|
||||
"Touching address %p from eip %p. Entering infinite loop...\n",
|
||||
(void*)cr2, (void*)frame->eip);
|
||||
(void*)cr2, (void*)frame->ip);
|
||||
|
||||
while (true);
|
||||
}
|
||||
@@ -359,28 +359,28 @@ page_fault_exception(struct iframe* frame)
|
||||
if (thread != NULL) {
|
||||
cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
|
||||
if (cpu->fault_handler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
debug_set_page_fault_info(cr2, frame->ip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = cpu->fault_handler;
|
||||
frame->ebp = cpu->fault_handler_stack_pointer;
|
||||
frame->ip = cpu->fault_handler;
|
||||
frame->bp = cpu->fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->fault_handler != 0) {
|
||||
kprintf("ERROR: thread::fault_handler used in kernel "
|
||||
"debugger!\n");
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
debug_set_page_fault_info(cr2, frame->ip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = thread->fault_handler;
|
||||
frame->ip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, not really
|
||||
panic("page fault in debugger without fault handler! Touching "
|
||||
"address %p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
"address %p from eip %p\n", (void *)cr2, (void *)frame->ip);
|
||||
return;
|
||||
} else if ((frame->flags & 0x200) == 0) {
|
||||
// interrupts disabled
|
||||
@@ -390,8 +390,8 @@ page_fault_exception(struct iframe* frame)
|
||||
// disabled, which in most cases is a bug. We should add some thread
|
||||
// flag allowing to explicitly indicate that this handling is desired.
|
||||
if (thread && thread->fault_handler != 0) {
|
||||
if (frame->eip != thread->fault_handler) {
|
||||
frame->eip = thread->fault_handler;
|
||||
if (frame->ip != thread->fault_handler) {
|
||||
frame->ip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -399,30 +399,30 @@ page_fault_exception(struct iframe* frame)
|
||||
// certain infinite loop.
|
||||
panic("page fault, interrupts disabled, fault handler loop. "
|
||||
"Touching address %p from eip %p\n", (void*)cr2,
|
||||
(void*)frame->eip);
|
||||
(void*)frame->ip);
|
||||
}
|
||||
|
||||
// If we are not running the kernel startup the page fault was not
|
||||
// allowed to happen and we must panic.
|
||||
panic("page fault, but interrupts were disabled. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->ip);
|
||||
return;
|
||||
} else if (thread != NULL && thread->page_faults_allowed < 1) {
|
||||
panic("page fault not allowed at this place. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->ip);
|
||||
return;
|
||||
}
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
vm_page_fault(cr2, frame->eip,
|
||||
vm_page_fault(cr2, frame->ip,
|
||||
(frame->error_code & 0x2) != 0, // write access
|
||||
(frame->error_code & 0x4) != 0, // userland
|
||||
&newip);
|
||||
if (newip != 0) {
|
||||
// the page fault handler wants us to modify the iframe to set the
|
||||
// IP the cpu will return to to be this ip
|
||||
frame->eip = newip;
|
||||
frame->ip = newip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
subl $80, %esp; \
|
||||
\
|
||||
/* get the address of the syscall parameters */ \
|
||||
movl IFRAME_user_esp(%ebp), %esi; \
|
||||
movl IFRAME_user_sp(%ebp), %esi; \
|
||||
addl $4, %esi; \
|
||||
cmp $KERNEL_BASE, %esi; /* must not be a kernel address */ \
|
||||
jae bad_syscall_params; \
|
||||
@@ -673,8 +673,8 @@ STATIC_FUNCTION(handle_syscall):
|
||||
|
||||
// overwrite the values of %eax and %edx on the stack (the syscall return
|
||||
// value)
|
||||
movl %edx, IFRAME_edx(%ebp)
|
||||
movl %eax, IFRAME_eax(%ebp)
|
||||
movl %edx, IFRAME_dx(%ebp)
|
||||
movl %eax, IFRAME_ax(%ebp)
|
||||
|
||||
TRACE_POST_SYSCALL()
|
||||
|
||||
@@ -725,8 +725,8 @@ FUNCTION_END(handle_syscall)
|
||||
jz 1f
|
||||
pushl -8(%ebp) // syscall start time
|
||||
pushl -12(%ebp)
|
||||
movl IFRAME_edx(%ebp), %edx // syscall return value
|
||||
movl IFRAME_eax(%ebp), %eax
|
||||
movl IFRAME_dx(%ebp), %edx // syscall return value
|
||||
movl IFRAME_ax(%ebp), %eax
|
||||
push %edx
|
||||
push %eax
|
||||
lea 16(%esp), %eax // syscall parameters
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <arch/thread.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <arch/user_debugger.h>
|
||||
#include <arch_cpu.h>
|
||||
#include <cpu.h>
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <ksignal.h>
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <tls.h>
|
||||
#include <tracing.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <vm/vm_types.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
|
||||
#include "paging/X86PagingStructures.h"
|
||||
#include "paging/X86VMTranslationMap.h"
|
||||
#include "x86_signals.h"
|
||||
|
||||
|
||||
//#define TRACE_ARCH_THREAD
|
||||
#ifdef TRACE_ARCH_THREAD
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SYSCALL_TRACING
|
||||
|
||||
namespace SyscallTracing {
|
||||
|
||||
class RestartSyscall : public AbstractTraceEntry {
|
||||
public:
|
||||
RestartSyscall()
|
||||
{
|
||||
Initialized();
|
||||
}
|
||||
|
||||
virtual void AddDump(TraceOutput& out)
|
||||
{
|
||||
out.Print("syscall restart");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
# define TSYSCALL(x) new(std::nothrow) SyscallTracing::x
|
||||
|
||||
#else
|
||||
# define TSYSCALL(x)
|
||||
#endif // SYSCALL_TRACING
|
||||
|
||||
|
||||
// from arch_cpu.cpp
|
||||
extern bool gHasSSE;
|
||||
|
||||
static struct arch_thread sInitialState _ALIGNED(16);
|
||||
// the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it
|
||||
|
||||
|
||||
static inline void
|
||||
set_fs_register(uint32 segment)
|
||||
{
|
||||
asm("movl %0,%%fs" :: "r" (segment));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_restart_syscall(struct iframe* frame)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
|
||||
atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
|
||||
atomic_or(&thread->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
|
||||
|
||||
frame->ax = frame->orig_eax;
|
||||
frame->dx = frame->orig_edx;
|
||||
frame->ip -= 2;
|
||||
// undoes the "int $99"/"sysenter"/"syscall" instruction
|
||||
// (so that it'll be executed again)
|
||||
|
||||
TSYSCALL(RestartSyscall());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_set_tls_context(Thread *thread)
|
||||
{
|
||||
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
|
||||
|
||||
set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
|
||||
set_fs_register((entry << 3) | DPL_USER);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init(struct kernel_args *args)
|
||||
{
|
||||
// save one global valid FPU state; it will be copied in the arch dependent
|
||||
// part of each new thread
|
||||
|
||||
asm volatile ("clts; fninit; fnclex;");
|
||||
if (gHasSSE)
|
||||
x86_fxsave(sInitialState.fpu_state);
|
||||
else
|
||||
x86_fnsave(sInitialState.fpu_state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init_thread_struct(Thread *thread)
|
||||
{
|
||||
// set up an initial state (stack & fpu)
|
||||
memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Prepares the given thread's kernel stack for executing its entry function.
|
||||
|
||||
\param thread The thread.
|
||||
\param stack The usable bottom of the thread's kernel stack.
|
||||
\param stackTop The usable top of the thread's kernel stack.
|
||||
\param function The entry function the thread shall execute.
|
||||
\param data Pointer to be passed to the entry function.
|
||||
*/
|
||||
void
|
||||
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
|
||||
void (*function)(void*), const void* data)
|
||||
{
|
||||
addr_t* stackTop = (addr_t*)_stackTop;
|
||||
|
||||
TRACE(("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
|
||||
"%p\n", stackTop, function, data));
|
||||
|
||||
// push the function argument, a pointer to the data
|
||||
*--stackTop = (addr_t)data;
|
||||
|
||||
// push a dummy return address for the function
|
||||
*--stackTop = 0;
|
||||
|
||||
// push the function address -- that's the return address used after the
|
||||
// context switch
|
||||
*--stackTop = (addr_t)function;
|
||||
|
||||
// simulate pushad as done by x86_context_switch()
|
||||
for (int i = 0; i < 8; i++)
|
||||
*--stackTop = 0;
|
||||
|
||||
// save the stack position
|
||||
thread->arch_info.current_stack.esp = stackTop;
|
||||
thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SEG;
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the user-space TLS local storage pointer in
|
||||
the thread structure, and the reserved TLS slots.
|
||||
|
||||
Is called from _create_user_thread_kentry().
|
||||
*/
|
||||
status_t
|
||||
arch_thread_init_tls(Thread *thread)
|
||||
{
|
||||
uint32 tls[TLS_USER_THREAD_SLOT + 1];
|
||||
|
||||
thread->user_local_storage = thread->user_stack_base
|
||||
+ thread->user_stack_size;
|
||||
|
||||
// initialize default TLS fields
|
||||
memset(tls, 0, sizeof(tls));
|
||||
tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
|
||||
tls[TLS_THREAD_ID_SLOT] = thread->id;
|
||||
tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread;
|
||||
|
||||
return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_dump_info(void *info)
|
||||
{
|
||||
struct arch_thread *at = (struct arch_thread *)info;
|
||||
|
||||
kprintf("\tesp: %p\n", at->current_stack.esp);
|
||||
kprintf("\tss: %p\n", at->current_stack.ss);
|
||||
kprintf("\tfpu_state at %p\n", at->fpu_state);
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up initial thread context and enters user space
|
||||
*/
|
||||
status_t
|
||||
arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
|
||||
void* args2)
|
||||
{
|
||||
addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
|
||||
uint32 codeSize = (addr_t)x86_end_userspace_thread_exit
|
||||
- (addr_t)x86_userspace_thread_exit;
|
||||
uint32 args[3];
|
||||
|
||||
TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
|
||||
"ustack_top 0x%lx\n", entry, args1, args2, stackTop));
|
||||
|
||||
// copy the little stub that calls exit_thread() when the thread entry
|
||||
// function returns, as well as the arguments of the entry function
|
||||
stackTop -= codeSize;
|
||||
|
||||
if (user_memcpy((void *)stackTop, (const void *)&x86_userspace_thread_exit, codeSize) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
args[0] = stackTop;
|
||||
args[1] = (uint32)args1;
|
||||
args[2] = (uint32)args2;
|
||||
stackTop -= sizeof(args);
|
||||
|
||||
if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// prepare the user iframe
|
||||
iframe frame = {};
|
||||
frame.type = IFRAME_TYPE_SYSCALL;
|
||||
frame.gs = USER_DATA_SEG;
|
||||
// frame.fs not used, we call x86_set_tls_context() on context switch
|
||||
frame.es = USER_DATA_SEG;
|
||||
frame.ds = USER_DATA_SEG;
|
||||
frame.ip = entry;
|
||||
frame.cs = USER_CODE_SEG;
|
||||
frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
|
||||
| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
|
||||
frame.user_sp = stackTop;
|
||||
frame.user_ss = USER_DATA_SEG;
|
||||
|
||||
// return to userland
|
||||
x86_initial_return_to_userland(thread, &frame);
|
||||
|
||||
return B_OK;
|
||||
// never gets here
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up the user iframe for invoking a signal handler.
|
||||
|
||||
The function fills in the remaining fields of the given \a signalFrameData,
|
||||
copies it to the thread's userland stack (the one on which the signal shall
|
||||
be handled), and sets up the user iframe so that when returning to userland
|
||||
a wrapper function is executed that calls the user-defined signal handler.
|
||||
When the signal handler returns, the wrapper function shall call the
|
||||
"restore signal frame" syscall with the (possibly modified) signal frame
|
||||
data.
|
||||
|
||||
The following fields of the \a signalFrameData structure still need to be
|
||||
filled in:
|
||||
- \c context.uc_stack: The stack currently used by the thread.
|
||||
- \c context.uc_mcontext: The current userland state of the registers.
|
||||
- \c syscall_restart_return_value: Architecture specific use. On x86 the
|
||||
value of eax and edx which are overwritten by the syscall return value.
|
||||
|
||||
Furthermore the function needs to set \c thread->user_signal_context to the
|
||||
userland pointer to the \c ucontext_t on the user stack.
|
||||
|
||||
\param thread The current thread.
|
||||
\param action The signal action specified for the signal to be handled.
|
||||
\param signalFrameData A partially initialized structure of all the data
|
||||
that need to be copied to userland.
|
||||
\return \c B_OK on success, another error code, if something goes wrong.
|
||||
*/
|
||||
status_t
|
||||
arch_setup_signal_frame(Thread* thread, struct sigaction* action,
|
||||
struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
struct iframe *frame = x86_get_current_iframe();
|
||||
if (!IFRAME_IS_USER(frame)) {
|
||||
panic("arch_setup_signal_frame(): No user iframe!");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
|
||||
// had the same signal number.
|
||||
if ((action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0
|
||||
&& signalFrameData->info.si_signo == SIGBUS) {
|
||||
signalFrameData->info.si_signo = SIGSEGV;
|
||||
}
|
||||
|
||||
// store the register state in signalFrameData->context.uc_mcontext
|
||||
signalFrameData->context.uc_mcontext.eip = frame->ip;
|
||||
signalFrameData->context.uc_mcontext.eflags = frame->flags;
|
||||
signalFrameData->context.uc_mcontext.eax = frame->ax;
|
||||
signalFrameData->context.uc_mcontext.ecx = frame->cx;
|
||||
signalFrameData->context.uc_mcontext.edx = frame->dx;
|
||||
signalFrameData->context.uc_mcontext.ebp = frame->bp;
|
||||
signalFrameData->context.uc_mcontext.esp = frame->user_sp;
|
||||
signalFrameData->context.uc_mcontext.edi = frame->di;
|
||||
signalFrameData->context.uc_mcontext.esi = frame->si;
|
||||
signalFrameData->context.uc_mcontext.ebx = frame->bx;
|
||||
x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
// fill in signalFrameData->context.uc_stack
|
||||
signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
|
||||
|
||||
// store orig_eax/orig_edx in syscall_restart_return_value
|
||||
signalFrameData->syscall_restart_return_value
|
||||
= (uint64)frame->orig_edx << 32 | frame->orig_eax;
|
||||
|
||||
// get the stack to use -- that's either the current one or a special signal
|
||||
// stack
|
||||
uint8* userStack = x86_get_signal_stack(thread, frame, action);
|
||||
|
||||
// copy the signal frame data onto the stack
|
||||
userStack -= sizeof(*signalFrameData);
|
||||
signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
|
||||
if (user_memcpy(userSignalFrameData, signalFrameData,
|
||||
sizeof(*signalFrameData)) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
// prepare the user stack frame for a function call to the signal handler
|
||||
// wrapper function
|
||||
uint32 stackFrame[2] = {
|
||||
frame->ip, // return address
|
||||
(addr_t)userSignalFrameData, // parameter: pointer to signal frame data
|
||||
};
|
||||
|
||||
userStack -= sizeof(stackFrame);
|
||||
if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// Update Thread::user_signal_context, now that everything seems to have
|
||||
// gone fine.
|
||||
thread->user_signal_context = &userSignalFrameData->context;
|
||||
|
||||
// Adjust the iframe's esp and eip, so that the thread will continue with
|
||||
// the prepared stack, executing the signal handler wrapper function.
|
||||
frame->user_sp = (addr_t)userStack;
|
||||
frame->ip = x86_get_user_signal_handler_wrapper(
|
||||
(action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
struct iframe* frame = x86_get_current_iframe();
|
||||
|
||||
TRACE(("### arch_restore_signal_frame: entry\n"));
|
||||
|
||||
frame->orig_eax = (uint32)signalFrameData->syscall_restart_return_value;
|
||||
frame->orig_edx
|
||||
= (uint32)(signalFrameData->syscall_restart_return_value >> 32);
|
||||
|
||||
frame->ip = signalFrameData->context.uc_mcontext.eip;
|
||||
frame->flags = (frame->flags & ~(uint32)X86_EFLAGS_USER_FLAGS)
|
||||
| (signalFrameData->context.uc_mcontext.eflags & X86_EFLAGS_USER_FLAGS);
|
||||
frame->ax = signalFrameData->context.uc_mcontext.eax;
|
||||
frame->cx = signalFrameData->context.uc_mcontext.ecx;
|
||||
frame->dx = signalFrameData->context.uc_mcontext.edx;
|
||||
frame->bp = signalFrameData->context.uc_mcontext.ebp;
|
||||
frame->user_sp = signalFrameData->context.uc_mcontext.esp;
|
||||
frame->di = signalFrameData->context.uc_mcontext.edi;
|
||||
frame->si = signalFrameData->context.uc_mcontext.esi;
|
||||
frame->bx = signalFrameData->context.uc_mcontext.ebx;
|
||||
|
||||
x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
TRACE(("### arch_restore_signal_frame: exit\n"));
|
||||
|
||||
return (int64)frame->ax | ((int64)frame->dx << 32);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_syscall_64_bit_return_value(void)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <asm_defs.h>
|
||||
|
||||
#include "asm_offsets.h"
|
||||
|
||||
|
||||
.text
|
||||
|
||||
@@ -24,6 +26,13 @@ FUNCTION(x86_fxrstor):
|
||||
FUNCTION_END(x86_fxrstor)
|
||||
|
||||
|
||||
/* void x86_noop_swap(void *oldFpuState, const void *newFpuState); */
|
||||
FUNCTION(x86_noop_swap):
|
||||
nop
|
||||
ret
|
||||
FUNCTION_END(x86_noop_swap)
|
||||
|
||||
|
||||
/* void x86_fxsave_swap(void* oldFpuState, const void* newFpuState); */
|
||||
FUNCTION(x86_fxsave_swap):
|
||||
fxsave (%rdi)
|
||||
@@ -32,11 +41,11 @@ FUNCTION(x86_fxsave_swap):
|
||||
FUNCTION_END(x86_fxsave_swap)
|
||||
|
||||
|
||||
/* addr_t x86_read_ebp(); */
|
||||
FUNCTION(x86_read_ebp):
|
||||
/* addr_t x86_get_stack_frame(); */
|
||||
FUNCTION(x86_get_stack_frame):
|
||||
mov %rbp, %rax
|
||||
ret
|
||||
FUNCTION_END(x86_read_ebp)
|
||||
FUNCTION_END(x86_get_stack_frame)
|
||||
|
||||
|
||||
/* uint64 x86_read_msr(uint32 register); */
|
||||
@@ -61,6 +70,47 @@ FUNCTION(x86_write_msr):
|
||||
FUNCTION_END(x86_write_msr)
|
||||
|
||||
|
||||
/* void x86_64_thread_entry(); */
|
||||
FUNCTION(x86_64_thread_entry):
|
||||
movq %r15, %rdi
|
||||
jmp *%r14
|
||||
FUNCTION_END(x86_64_thread_entry)
|
||||
|
||||
|
||||
/* void x86_context_switch(struct arch_thread* oldState,
|
||||
struct arch_thread* newState); */
|
||||
FUNCTION(x86_context_switch):
|
||||
// Just need to save callee-save registers: RBP, RBX, R12-15.
|
||||
push %r15
|
||||
push %r14
|
||||
push %r13
|
||||
push %r12
|
||||
push %rbp
|
||||
push %rbx
|
||||
|
||||
// Swap the stack pointers.
|
||||
movq %rsp, ARCH_THREAD_current_stack(%rdi)
|
||||
movq ARCH_THREAD_current_stack(%rsi), %rsp
|
||||
|
||||
// Restore callee-save registers.
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
pop %r12
|
||||
pop %r13
|
||||
pop %r14
|
||||
pop %r15
|
||||
|
||||
ret
|
||||
FUNCTION_END(x86_context_switch)
|
||||
|
||||
|
||||
/* void x86_swap_pgdir(uint64 newPageDir); */
|
||||
FUNCTION(x86_swap_pgdir):
|
||||
movq %rdi, %cr3
|
||||
ret
|
||||
FUNCTION_END(x86_swap_pgdir)
|
||||
|
||||
|
||||
null_idt_descr:
|
||||
.word 0
|
||||
.quad 0
|
||||
|
||||
@@ -72,7 +72,7 @@ invalid_exception(iframe* frame)
|
||||
char name[32];
|
||||
panic("unhandled trap %#lx (%s) at ip %#lx\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->rip);
|
||||
frame->ip);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ fatal_exception(iframe* frame)
|
||||
char name[32];
|
||||
panic("fatal exception %#lx (%s) at ip %#lx, error code %#lx\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->rip, frame->error_code);
|
||||
frame->ip, frame->error_code);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ unexpected_exception(iframe* frame)
|
||||
char name[32];
|
||||
panic("fatal exception %#lx (%s) at ip %#lx, error code %#lx\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->rip, frame->error_code);
|
||||
frame->ip, frame->error_code);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ page_fault_exception(iframe* frame)
|
||||
addr_t cr2 = x86_read_cr2();
|
||||
|
||||
panic("page fault exception at ip %#lx on %#lx, error code %#lx\n",
|
||||
frame->rip, cr2, frame->error_code);
|
||||
frame->ip, cr2, frame->error_code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ SYMBOL(isr_array):
|
||||
.Lintr = .Lintr+1
|
||||
.endr
|
||||
|
||||
|
||||
// Common interrupt handling code.
|
||||
FUNCTION(int_bottom):
|
||||
// If coming from user-mode, need to load the kernel GS segment base.
|
||||
@@ -141,3 +142,21 @@ FUNCTION(int_bottom):
|
||||
jz 2f
|
||||
swapgs
|
||||
2: iretq
|
||||
FUNCTION_END(int_bottom)
|
||||
|
||||
|
||||
/*! \fn void x86_return_to_userland(iframe* frame)
|
||||
\brief Returns to the userland environment given by \a frame.
|
||||
|
||||
Before returning to userland all potentially necessary kernel exit work is
|
||||
done.
|
||||
|
||||
\a frame must point to a location somewhere on the caller's stack (e.g. a
|
||||
local variable).
|
||||
The function must be called with interrupts disabled.
|
||||
|
||||
\param frame The iframe defining the userland environment.
|
||||
*/
|
||||
FUNCTION(x86_return_to_userland):
|
||||
ud2a
|
||||
FUNCTION_END(x86_return_to_userland)
|
||||
|
||||
@@ -37,10 +37,6 @@
|
||||
#include <arch/elf.h>
|
||||
|
||||
|
||||
// temporary
|
||||
Thread* gCurrentThread = NULL;
|
||||
|
||||
|
||||
status_t
|
||||
arch_commpage_init(void)
|
||||
{
|
||||
@@ -106,23 +102,23 @@ print_iframe(struct iframe* frame)
|
||||
bool isUser = IFRAME_IS_USER(frame);
|
||||
|
||||
kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
|
||||
isUser ? (uint64*)(frame + 1) : &frame->user_rsp);
|
||||
isUser ? (uint64*)(frame + 1) : &frame->user_sp);
|
||||
|
||||
kprintf(" rax 0x%-16lx rbx 0x%-16lx rcx 0x%lx\n", frame->rax,
|
||||
frame->rbx, frame->rcx);
|
||||
kprintf(" rdx 0x%-16lx rsi 0x%-16lx rdi 0x%lx\n", frame->rdx,
|
||||
frame->rsi, frame->rdi);
|
||||
kprintf(" rbp 0x%-16lx r8 0x%-16lx r9 0x%lx\n", frame->rbp,
|
||||
kprintf(" rax 0x%-16lx rbx 0x%-16lx rcx 0x%lx\n", frame->ax,
|
||||
frame->bx, frame->cx);
|
||||
kprintf(" rdx 0x%-16lx rsi 0x%-16lx rdi 0x%lx\n", frame->dx,
|
||||
frame->si, frame->di);
|
||||
kprintf(" rbp 0x%-16lx r8 0x%-16lx r9 0x%lx\n", frame->bp,
|
||||
frame->r8, frame->r9);
|
||||
kprintf(" r10 0x%-16lx r11 0x%-16lx r12 0x%lx\n", frame->r10,
|
||||
frame->r11, frame->r12);
|
||||
kprintf(" r13 0x%-16lx r14 0x%-16lx r15 0x%lx\n", frame->r13,
|
||||
frame->r14, frame->r15);
|
||||
kprintf(" rip 0x%-16lx rflags 0x%-16lx", frame->rip, frame->flags);
|
||||
kprintf(" rip 0x%-16lx rflags 0x%-16lx", frame->ip, frame->flags);
|
||||
|
||||
if (isUser) {
|
||||
// from user space
|
||||
kprintf("user rsp 0x%lx", frame->user_rsp);
|
||||
kprintf("user rsp 0x%lx", frame->user_sp);
|
||||
}
|
||||
kprintf("\n");
|
||||
kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector,
|
||||
@@ -186,7 +182,7 @@ print_stack_frame(addr_t rip, addr_t rbp, addr_t nextRbp, int32 callIndex)
|
||||
void
|
||||
arch_debug_stack_trace(void)
|
||||
{
|
||||
addr_t rbp = x86_read_ebp();
|
||||
addr_t rbp = x86_get_stack_frame();
|
||||
|
||||
kprintf("frame caller <image>:function"
|
||||
" + offset\n");
|
||||
@@ -198,9 +194,9 @@ arch_debug_stack_trace(void)
|
||||
if (is_iframe(rbp)) {
|
||||
struct iframe* frame = (struct iframe*)rbp;
|
||||
print_iframe(frame);
|
||||
print_stack_frame(frame->rip, rbp, frame->rbp, callIndex);
|
||||
print_stack_frame(frame->ip, rbp, frame->bp, callIndex);
|
||||
|
||||
rbp = frame->rbp;
|
||||
rbp = frame->bp;
|
||||
} else {
|
||||
stack_frame* frame = (stack_frame*)rbp;
|
||||
if (frame->return_address == 0)
|
||||
@@ -374,100 +370,6 @@ arch_system_info_init(struct kernel_args *args)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init(struct kernel_args *args)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_team_init_team_struct(Team *p, bool kernel)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init_thread_struct(Thread *thread)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
|
||||
void (*function)(void*), const void* data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init_tls(Thread *thread)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_context_switch(Thread *from, Thread *to)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_dump_info(void *info)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
|
||||
void* args2)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
arch_on_signal_stack(Thread *thread)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_setup_signal_frame(Thread* thread, struct sigaction* action,
|
||||
struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_store_fork_frame(struct arch_fork_arg *arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_restore_fork_frame(struct arch_fork_arg* arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// The software breakpoint instruction (int3).
|
||||
const uint8 kX86SoftwareBreakpoint[1] = { 0xcc };
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
|
||||
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <arch/thread.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_cpu.h>
|
||||
#include <cpu.h>
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <ksignal.h>
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <tls.h>
|
||||
#include <vm/vm_types.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
|
||||
#include "paging/X86PagingStructures.h"
|
||||
#include "paging/X86VMTranslationMap.h"
|
||||
|
||||
|
||||
//#define TRACE_ARCH_THREAD
|
||||
#ifdef TRACE_ARCH_THREAD
|
||||
# define TRACE(x...) dprintf(x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" void x86_64_thread_entry();
|
||||
|
||||
// Initial thread saved state.
|
||||
static arch_thread sInitialState;
|
||||
|
||||
|
||||
void
|
||||
x86_set_tls_context(Thread* thread)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init(kernel_args* args)
|
||||
{
|
||||
// Save one global valid FPU state; it will be copied in the arch dependent
|
||||
// part of each new thread.
|
||||
asm volatile ("clts; fninit; fnclex;");
|
||||
x86_fxsave(sInitialState.fpu_state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init_thread_struct(Thread* thread)
|
||||
{
|
||||
// Copy the initial saved FPU state to the new thread.
|
||||
memcpy(&thread->arch_info, &sInitialState, sizeof(arch_thread));
|
||||
|
||||
// Initialise the current thread pointer.
|
||||
thread->arch_info.thread = thread;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Prepares the given thread's kernel stack for executing its entry function.
|
||||
|
||||
\param thread The thread.
|
||||
\param stack The usable bottom of the thread's kernel stack.
|
||||
\param stackTop The usable top of the thread's kernel stack.
|
||||
\param function The entry function the thread shall execute.
|
||||
\param data Pointer to be passed to the entry function.
|
||||
*/
|
||||
void
|
||||
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
|
||||
void (*function)(void*), const void* data)
|
||||
{
|
||||
addr_t* stackTop = (addr_t*)_stackTop;
|
||||
|
||||
TRACE("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
|
||||
"%p\n", _stackTop, function, data);
|
||||
|
||||
// x86_64 uses registers for argument passing, first argument in RDI,
|
||||
// however we don't save RDI on every context switch (there is no need
|
||||
// for us to: it is not callee-save, and only contains the first argument
|
||||
// to x86_context_switch). However, this presents a problem since we
|
||||
// cannot store the argument for the entry function here. Therefore, we
|
||||
// save the function address in R14 and the argument in R15 (which are
|
||||
// restored), and then set up the stack to initially call a wrapper
|
||||
// function which passes the argument correctly.
|
||||
|
||||
*--stackTop = 0; // Dummy return address.
|
||||
*--stackTop = (addr_t)x86_64_thread_entry; // Wrapper function.
|
||||
*--stackTop = (addr_t)data; // R15: argument.
|
||||
*--stackTop = (addr_t)function; // R14: entry function.
|
||||
*--stackTop = 0; // R13.
|
||||
*--stackTop = 0; // R12.
|
||||
*--stackTop = 0; // RBP.
|
||||
*--stackTop = 0; // RBX.
|
||||
|
||||
// Save the stack position.
|
||||
thread->arch_info.current_stack = stackTop;
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the user-space TLS local storage pointer in
|
||||
the thread structure, and the reserved TLS slots.
|
||||
|
||||
Is called from _create_user_thread_kentry().
|
||||
*/
|
||||
status_t
|
||||
arch_thread_init_tls(Thread* thread)
|
||||
{
|
||||
dprintf("arch_thread_init_tls: TODO\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_dump_info(void* info)
|
||||
{
|
||||
arch_thread* thread = (arch_thread*)info;
|
||||
|
||||
kprintf("\trsp: %p\n", thread->current_stack);
|
||||
kprintf("\tsyscall_rsp: %p\n", thread->syscall_rsp);
|
||||
kprintf("\tuser_rsp: %p\n", thread->user_rsp);
|
||||
kprintf("\tfpu_state at %p\n", thread->fpu_state);
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up initial thread context and enters user space
|
||||
*/
|
||||
status_t
|
||||
arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
|
||||
void* args2)
|
||||
{
|
||||
panic("arch_thread_enter_userspace: TODO\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up the user iframe for invoking a signal handler.
|
||||
|
||||
The function fills in the remaining fields of the given \a signalFrameData,
|
||||
copies it to the thread's userland stack (the one on which the signal shall
|
||||
be handled), and sets up the user iframe so that when returning to userland
|
||||
a wrapper function is executed that calls the user-defined signal handler.
|
||||
When the signal handler returns, the wrapper function shall call the
|
||||
"restore signal frame" syscall with the (possibly modified) signal frame
|
||||
data.
|
||||
|
||||
The following fields of the \a signalFrameData structure still need to be
|
||||
filled in:
|
||||
- \c context.uc_stack: The stack currently used by the thread.
|
||||
- \c context.uc_mcontext: The current userland state of the registers.
|
||||
- \c syscall_restart_return_value: Architecture specific use. On x86 the
|
||||
value of eax and edx which are overwritten by the syscall return value.
|
||||
|
||||
Furthermore the function needs to set \c thread->user_signal_context to the
|
||||
userland pointer to the \c ucontext_t on the user stack.
|
||||
|
||||
\param thread The current thread.
|
||||
\param action The signal action specified for the signal to be handled.
|
||||
\param signalFrameData A partially initialized structure of all the data
|
||||
that need to be copied to userland.
|
||||
\return \c B_OK on success, another error code, if something goes wrong.
|
||||
*/
|
||||
status_t
|
||||
arch_setup_signal_frame(Thread* thread, struct sigaction* action,
|
||||
struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
panic("arch_setup_signal_frame: TODO\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
panic("arch_restore_signal_frame: TODO\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -24,6 +24,7 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
int.cpp
|
||||
interrupts.S
|
||||
stubs.cpp
|
||||
thread.cpp
|
||||
|
||||
# paging
|
||||
x86_physical_page_mapper_mapped.cpp
|
||||
@@ -43,12 +44,12 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
cpuid.S
|
||||
int.cpp
|
||||
interrupts.S
|
||||
thread.cpp
|
||||
|
||||
arch_commpage.cpp
|
||||
arch_debug.cpp
|
||||
arch_real_time_clock.cpp
|
||||
arch_smp.cpp
|
||||
arch_thread.cpp
|
||||
arch_system_info.cpp
|
||||
arch_user_debugger.cpp
|
||||
apm.cpp
|
||||
@@ -83,6 +84,7 @@ local archGenericSources =
|
||||
arch_elf.cpp
|
||||
arch_int.cpp
|
||||
arch_platform.cpp
|
||||
arch_thread.cpp
|
||||
arch_timer.cpp
|
||||
arch_vm.cpp
|
||||
arch_vm_translation_map.cpp
|
||||
|
||||
@@ -91,10 +91,8 @@ extern "C" void x86_reboot(void);
|
||||
// from arch.S
|
||||
|
||||
void (*gCpuIdleFunc)(void);
|
||||
#ifndef __x86_64__
|
||||
void (*gX86SwapFPUFunc)(void* oldState, const void* newState) = x86_noop_swap;
|
||||
bool gHasSSE = false;
|
||||
#endif
|
||||
|
||||
static uint32 sCpuRendezvous;
|
||||
static uint32 sCpuRendezvous2;
|
||||
@@ -343,10 +341,8 @@ x86_init_fpu(void)
|
||||
x86_write_cr4(x86_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION);
|
||||
x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
|
||||
|
||||
#ifndef __x86_64__
|
||||
gX86SwapFPUFunc = x86_fxsave_swap;
|
||||
gHasSSE = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -708,7 +704,7 @@ x86_get_double_fault_stack(int32 cpu, size_t* _size)
|
||||
int32
|
||||
x86_double_fault_get_cpu(void)
|
||||
{
|
||||
uint32 stack = x86_read_ebp();
|
||||
uint32 stack = x86_get_stack_frame();
|
||||
return (stack - (uint32)sDoubleFaultStacks) / kDoubleFaultStackSize;
|
||||
}
|
||||
#endif
|
||||
@@ -973,13 +969,11 @@ arch_cpu_init_post_modules(kernel_args* args)
|
||||
}
|
||||
|
||||
|
||||
#ifndef __x86_64__
|
||||
void
|
||||
x86_set_tss_and_kstack(addr_t kstack)
|
||||
{
|
||||
get_cpu_struct()->arch.tss.sp0 = kstack;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
|
||||
@@ -363,16 +363,16 @@ print_iframe(struct iframe *frame)
|
||||
{
|
||||
bool isUser = IFRAME_IS_USER(frame);
|
||||
kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
|
||||
isUser ? (uint32*)(frame + 1) : &frame->user_esp);
|
||||
isUser ? (uint32*)(frame + 1) : &frame->user_sp);
|
||||
|
||||
kprintf(" eax 0x%-9lx ebx 0x%-9lx ecx 0x%-9lx edx 0x%lx\n",
|
||||
frame->eax, frame->ebx, frame->ecx, frame->edx);
|
||||
frame->ax, frame->bx, frame->cx, frame->dx);
|
||||
kprintf(" esi 0x%-9lx edi 0x%-9lx ebp 0x%-9lx esp 0x%lx\n",
|
||||
frame->esi, frame->edi, frame->ebp, frame->esp);
|
||||
kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->eip, frame->flags);
|
||||
frame->si, frame->di, frame->bp, frame->sp);
|
||||
kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->ip, frame->flags);
|
||||
if (isUser) {
|
||||
// from user space
|
||||
kprintf("user esp 0x%lx", frame->user_esp);
|
||||
kprintf("user esp 0x%lx", frame->user_sp);
|
||||
}
|
||||
kprintf("\n");
|
||||
kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector,
|
||||
@@ -413,7 +413,7 @@ setup_for_thread(char *arg, Thread **_thread, uint32 *_ebp,
|
||||
thread->cpu->cpu_num);
|
||||
if (registers == NULL)
|
||||
return false;
|
||||
*_ebp = registers->ebp;
|
||||
*_ebp = registers->bp;
|
||||
} else {
|
||||
// read %ebp from the thread's stack stored by a pushad
|
||||
*_ebp = thread->arch_info.current_stack.esp[2];
|
||||
@@ -495,7 +495,7 @@ get_previous_iframe(Thread* thread, struct iframe* frame)
|
||||
if (frame == NULL)
|
||||
return NULL;
|
||||
|
||||
return find_previous_iframe(thread, frame->ebp);
|
||||
return find_previous_iframe(thread, frame->bp);
|
||||
}
|
||||
|
||||
|
||||
@@ -532,28 +532,28 @@ find_debug_variable(const char* variableName, bool& settable)
|
||||
return &frame->cs;
|
||||
} else if (strcmp(variableName, "edi") == 0) {
|
||||
settable = true;
|
||||
return &frame->edi;
|
||||
return &frame->di;
|
||||
} else if (strcmp(variableName, "esi") == 0) {
|
||||
settable = true;
|
||||
return &frame->esi;
|
||||
return &frame->si;
|
||||
} else if (strcmp(variableName, "ebp") == 0) {
|
||||
settable = true;
|
||||
return &frame->ebp;
|
||||
return &frame->bp;
|
||||
} else if (strcmp(variableName, "esp") == 0) {
|
||||
settable = true;
|
||||
return &frame->esp;
|
||||
return &frame->sp;
|
||||
} else if (strcmp(variableName, "ebx") == 0) {
|
||||
settable = true;
|
||||
return &frame->ebx;
|
||||
return &frame->bx;
|
||||
} else if (strcmp(variableName, "edx") == 0) {
|
||||
settable = true;
|
||||
return &frame->edx;
|
||||
return &frame->dx;
|
||||
} else if (strcmp(variableName, "ecx") == 0) {
|
||||
settable = true;
|
||||
return &frame->ecx;
|
||||
return &frame->cx;
|
||||
} else if (strcmp(variableName, "eax") == 0) {
|
||||
settable = true;
|
||||
return &frame->eax;
|
||||
return &frame->ax;
|
||||
} else if (strcmp(variableName, "orig_eax") == 0) {
|
||||
settable = true;
|
||||
return &frame->orig_eax;
|
||||
@@ -562,7 +562,7 @@ find_debug_variable(const char* variableName, bool& settable)
|
||||
return &frame->orig_edx;
|
||||
} else if (strcmp(variableName, "eip") == 0) {
|
||||
settable = true;
|
||||
return &frame->eip;
|
||||
return &frame->ip;
|
||||
} else if (strcmp(variableName, "eflags") == 0) {
|
||||
settable = true;
|
||||
return &frame->flags;
|
||||
@@ -571,7 +571,7 @@ find_debug_variable(const char* variableName, bool& settable)
|
||||
if (IFRAME_IS_USER(frame)) {
|
||||
if (strcmp(variableName, "user_esp") == 0) {
|
||||
settable = true;
|
||||
return &frame->user_esp;
|
||||
return &frame->user_sp;
|
||||
} else if (strcmp(variableName, "user_ss") == 0) {
|
||||
return &frame->user_ss;
|
||||
}
|
||||
@@ -606,7 +606,7 @@ stack_trace(int argc, char **argv)
|
||||
uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
|
||||
Thread *thread = NULL;
|
||||
uint32 oldPageDirectory = 0;
|
||||
uint32 ebp = x86_read_ebp();
|
||||
uint32 ebp = x86_get_stack_frame();
|
||||
int32 num = 0, last = 0;
|
||||
|
||||
if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL,
|
||||
@@ -641,10 +641,10 @@ stack_trace(int argc, char **argv)
|
||||
struct iframe *frame = (struct iframe *)ebp;
|
||||
|
||||
print_iframe(frame);
|
||||
print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex,
|
||||
print_stack_frame(thread, frame->ip, ebp, frame->bp, callIndex,
|
||||
demangle);
|
||||
|
||||
ebp = frame->ebp;
|
||||
ebp = frame->bp;
|
||||
} else {
|
||||
addr_t eip, nextEbp;
|
||||
|
||||
@@ -760,7 +760,7 @@ show_call(int argc, char **argv)
|
||||
|
||||
Thread *thread = NULL;
|
||||
uint32 oldPageDirectory = 0;
|
||||
addr_t ebp = x86_read_ebp();
|
||||
addr_t ebp = x86_get_stack_frame();
|
||||
int32 argCount = 0;
|
||||
|
||||
if (argc >= 2 && argv[argc - 1][0] == '-') {
|
||||
@@ -804,9 +804,9 @@ show_call(int argc, char **argv)
|
||||
struct iframe *frame = (struct iframe *)ebp;
|
||||
|
||||
if (index == callIndex)
|
||||
print_call(thread, frame->eip, ebp, frame->ebp, argCount);
|
||||
print_call(thread, frame->ip, ebp, frame->bp, argCount);
|
||||
|
||||
ebp = frame->ebp;
|
||||
ebp = frame->bp;
|
||||
} else {
|
||||
addr_t eip, nextEbp;
|
||||
|
||||
@@ -871,7 +871,7 @@ dump_iframes(int argc, char **argv)
|
||||
|
||||
DebuggedThreadSetter threadSetter(thread);
|
||||
|
||||
struct iframe* frame = find_previous_iframe(thread, x86_read_ebp());
|
||||
struct iframe* frame = find_previous_iframe(thread, x86_get_stack_frame());
|
||||
while (frame != NULL) {
|
||||
print_iframe(frame);
|
||||
frame = get_previous_iframe(thread, frame);
|
||||
@@ -965,8 +965,8 @@ void
|
||||
arch_debug_save_registers(struct arch_debug_registers* registers)
|
||||
{
|
||||
// get the caller's frame pointer
|
||||
stack_frame* frame = (stack_frame*)x86_read_ebp();
|
||||
registers->ebp = (addr_t)frame->previous;
|
||||
stack_frame* frame = (stack_frame*)x86_get_stack_frame();
|
||||
registers->bp = (addr_t)frame->previous;
|
||||
}
|
||||
|
||||
|
||||
@@ -985,7 +985,7 @@ arch_debug_contains_call(Thread *thread, const char *symbol,
|
||||
|
||||
addr_t ebp;
|
||||
if (thread == thread_get_current_thread())
|
||||
ebp = x86_read_ebp();
|
||||
ebp = x86_get_stack_frame();
|
||||
else {
|
||||
if (thread->state == B_THREAD_RUNNING) {
|
||||
// The thread is currently running on another CPU.
|
||||
@@ -995,7 +995,7 @@ arch_debug_contains_call(Thread *thread, const char *symbol,
|
||||
thread->cpu->cpu_num);
|
||||
if (registers == NULL)
|
||||
return false;
|
||||
ebp = registers->ebp;
|
||||
ebp = registers->bp;
|
||||
} else {
|
||||
// thread not running
|
||||
ebp = thread->arch_info.current_stack.esp[2];
|
||||
@@ -1009,10 +1009,10 @@ arch_debug_contains_call(Thread *thread, const char *symbol,
|
||||
if (is_iframe(thread, ebp)) {
|
||||
struct iframe *frame = (struct iframe *)ebp;
|
||||
|
||||
if (is_calling(thread, frame->eip, symbol, start, end))
|
||||
if (is_calling(thread, frame->ip, symbol, start, end))
|
||||
return true;
|
||||
|
||||
ebp = frame->ebp;
|
||||
ebp = frame->bp;
|
||||
} else {
|
||||
addr_t eip, nextEbp;
|
||||
|
||||
@@ -1037,7 +1037,7 @@ arch_debug_contains_call(Thread *thread, const char *symbol,
|
||||
void *
|
||||
arch_debug_get_caller(void)
|
||||
{
|
||||
struct stack_frame *frame = (struct stack_frame *)x86_read_ebp();
|
||||
struct stack_frame *frame = (struct stack_frame *)x86_get_stack_frame();
|
||||
return (void *)frame->previous->return_address;
|
||||
}
|
||||
|
||||
@@ -1064,7 +1064,7 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
|
||||
|
||||
Thread* thread = thread_get_current_thread();
|
||||
int32 count = 0;
|
||||
addr_t ebp = x86_read_ebp();
|
||||
addr_t ebp = x86_get_stack_frame();
|
||||
bool onKernelStack = true;
|
||||
|
||||
while (ebp != 0 && count < maxCount) {
|
||||
@@ -1078,8 +1078,8 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
|
||||
|
||||
if (onKernelStack && is_iframe(thread, ebp)) {
|
||||
struct iframe *frame = (struct iframe*)ebp;
|
||||
eip = frame->eip;
|
||||
nextEbp = frame->ebp;
|
||||
eip = frame->ip;
|
||||
nextEbp = frame->bp;
|
||||
|
||||
if (skipIframes > 0) {
|
||||
if (--skipIframes == 0)
|
||||
@@ -1119,7 +1119,7 @@ arch_debug_get_interrupt_pc(bool* _isSyscall)
|
||||
if (_isSyscall != NULL)
|
||||
*_isSyscall = frame->vector == 99;
|
||||
|
||||
return (void*)(addr_t)frame->eip;
|
||||
return (void*)(addr_t)frame->ip;
|
||||
}
|
||||
|
||||
|
||||
@@ -1199,9 +1199,9 @@ arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||
// gdb wants the register dump in *big endian* format.
|
||||
static const int32 kRegisterCount = 14;
|
||||
uint32 registers[kRegisterCount] = {
|
||||
frame->eax, frame->ebx, frame->ecx, frame->edx,
|
||||
frame->esp, frame->ebp, frame->esi, frame->edi,
|
||||
frame->eip, frame->flags,
|
||||
frame->ax, frame->bx, frame->cx, frame->dx,
|
||||
frame->sp, frame->bp, frame->si, frame->di,
|
||||
frame->ip, frame->flags,
|
||||
frame->cs, frame->ds, frame->ds, frame->es
|
||||
// assume ss == ds
|
||||
};
|
||||
|
||||
@@ -89,6 +89,7 @@ hardware_interrupt(struct iframe* frame)
|
||||
callback(data);
|
||||
}
|
||||
#else
|
||||
return;
|
||||
panic("implement me");
|
||||
#endif
|
||||
}
|
||||
@@ -159,7 +160,7 @@ arch_int_init_io(kernel_args* args)
|
||||
ioapic_init(args);
|
||||
msi_init();
|
||||
#else
|
||||
panic("implement me");
|
||||
//panic("implement me");
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -11,96 +11,36 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <arch/user_debugger.h>
|
||||
#include <arch_cpu.h>
|
||||
#include <cpu.h>
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <ksignal.h>
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <tls.h>
|
||||
#include <tracing.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <vm/vm_types.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
|
||||
#include "paging/X86PagingStructures.h"
|
||||
#include "paging/X86VMTranslationMap.h"
|
||||
#include "x86_signals.h"
|
||||
#include "x86_syscalls.h"
|
||||
|
||||
|
||||
//#define TRACE_ARCH_THREAD
|
||||
#ifdef TRACE_ARCH_THREAD
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SYSCALL_TRACING
|
||||
|
||||
namespace SyscallTracing {
|
||||
|
||||
class RestartSyscall : public AbstractTraceEntry {
|
||||
public:
|
||||
RestartSyscall()
|
||||
{
|
||||
Initialized();
|
||||
}
|
||||
|
||||
virtual void AddDump(TraceOutput& out)
|
||||
{
|
||||
out.Print("syscall restart");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
# define TSYSCALL(x) new(std::nothrow) SyscallTracing::x
|
||||
|
||||
#else
|
||||
# define TSYSCALL(x)
|
||||
#endif // SYSCALL_TRACING
|
||||
|
||||
|
||||
// from arch_interrupts.S
|
||||
extern "C" void x86_return_to_userland(iframe* frame);
|
||||
|
||||
// from arch_cpu.c
|
||||
// from arch_cpu.cpp
|
||||
extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
|
||||
extern bool gHasSSE;
|
||||
|
||||
static struct arch_thread sInitialState _ALIGNED(16);
|
||||
// the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init(struct kernel_args *args)
|
||||
{
|
||||
// save one global valid FPU state; it will be copied in the arch dependent
|
||||
// part of each new thread
|
||||
|
||||
asm volatile ("clts; fninit; fnclex;");
|
||||
if (gHasSSE)
|
||||
x86_fxsave(sInitialState.fpu_state);
|
||||
else
|
||||
x86_fnsave(sInitialState.fpu_state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static struct iframe *
|
||||
find_previous_iframe(Thread *thread, addr_t frame)
|
||||
static struct iframe*
|
||||
find_previous_iframe(Thread* thread, addr_t frame)
|
||||
{
|
||||
// iterate backwards through the stack frames, until we hit an iframe
|
||||
while (frame >= thread->kernel_stack_base
|
||||
&& frame < thread->kernel_stack_top) {
|
||||
addr_t previousFrame = *(addr_t*)frame;
|
||||
if ((previousFrame & ~IFRAME_TYPE_MASK) == 0) {
|
||||
if ((previousFrame & ~(addr_t)IFRAME_TYPE_MASK) == 0) {
|
||||
if (previousFrame == 0)
|
||||
return NULL;
|
||||
return (struct iframe*)frame;
|
||||
@@ -119,7 +59,7 @@ get_previous_iframe(struct iframe* frame)
|
||||
if (frame == NULL)
|
||||
return NULL;
|
||||
|
||||
return find_previous_iframe(thread_get_current_thread(), frame->ebp);
|
||||
return find_previous_iframe(thread_get_current_thread(), frame->bp);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,39 +72,8 @@ get_previous_iframe(struct iframe* frame)
|
||||
static struct iframe*
|
||||
get_current_iframe(void)
|
||||
{
|
||||
return find_previous_iframe(thread_get_current_thread(), x86_read_ebp());
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
set_fs_register(uint32 segment)
|
||||
{
|
||||
asm("movl %0,%%fs" :: "r" (segment));
|
||||
}
|
||||
|
||||
|
||||
/*! Returns to the userland environment given by \a frame for a thread not
|
||||
having been userland before.
|
||||
|
||||
Before returning to userland all potentially necessary kernel exit work is
|
||||
done.
|
||||
|
||||
\param thread The current thread.
|
||||
\param frame The iframe defining the userland environment. Must point to a
|
||||
location somewhere on the caller's stack (e.g. a local variable).
|
||||
*/
|
||||
static void
|
||||
initial_return_to_userland(Thread* thread, iframe* frame)
|
||||
{
|
||||
// disable interrupts and set up CPU specifics for this thread
|
||||
disable_interrupts();
|
||||
|
||||
x86_set_tss_and_kstack(thread->kernel_stack_top);
|
||||
x86_set_tls_context(thread);
|
||||
x86_set_syscall_stack(thread->kernel_stack_top);
|
||||
|
||||
// return to userland
|
||||
x86_return_to_userland(frame);
|
||||
return find_previous_iframe(thread_get_current_thread(),
|
||||
x86_get_stack_frame());
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +84,7 @@ initial_return_to_userland(Thread* thread, iframe* frame)
|
||||
\return The iframe, or \c NULL, if there is no such iframe (e.g. when
|
||||
the thread is a kernel thread).
|
||||
*/
|
||||
struct iframe *
|
||||
struct iframe*
|
||||
x86_get_user_iframe(void)
|
||||
{
|
||||
struct iframe* frame = get_current_iframe();
|
||||
@@ -193,17 +102,21 @@ x86_get_user_iframe(void)
|
||||
/*! \brief Like x86_get_user_iframe(), just for the given thread.
|
||||
The thread must not be running and the threads spinlock must be held.
|
||||
*/
|
||||
struct iframe *
|
||||
struct iframe*
|
||||
x86_get_thread_user_iframe(Thread *thread)
|
||||
{
|
||||
if (thread->state == B_THREAD_RUNNING)
|
||||
return NULL;
|
||||
|
||||
// read %ebp from the thread's stack stored by a pushad
|
||||
addr_t ebp = thread->arch_info.current_stack.esp[2];
|
||||
// Read frame pointer from the thread's stack.
|
||||
#ifdef __x86_64__
|
||||
addr_t bp = thread->arch_info.current_stack[1];
|
||||
#else
|
||||
addr_t bp = thread->arch_info.current_stack.esp[2];
|
||||
#endif
|
||||
|
||||
// find the user iframe
|
||||
struct iframe *frame = find_previous_iframe(thread, ebp);
|
||||
struct iframe* frame = find_previous_iframe(thread, bp);
|
||||
|
||||
while (frame != NULL) {
|
||||
if (IFRAME_IS_USER(frame))
|
||||
@@ -215,14 +128,14 @@ x86_get_thread_user_iframe(Thread *thread)
|
||||
}
|
||||
|
||||
|
||||
struct iframe *
|
||||
struct iframe*
|
||||
x86_get_current_iframe(void)
|
||||
{
|
||||
return get_current_iframe();
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
phys_addr_t
|
||||
x86_next_page_directory(Thread *from, Thread *to)
|
||||
{
|
||||
VMAddressSpace* toAddressSpace = to->team->address_space;
|
||||
@@ -239,47 +152,45 @@ x86_next_page_directory(Thread *from, Thread *to)
|
||||
}
|
||||
|
||||
|
||||
/*! Returns to the userland environment given by \a frame for a thread not
|
||||
having been userland before.
|
||||
|
||||
Before returning to userland all potentially necessary kernel exit work is
|
||||
done.
|
||||
|
||||
\param thread The current thread.
|
||||
\param frame The iframe defining the userland environment. Must point to a
|
||||
location somewhere on the caller's stack (e.g. a local variable).
|
||||
*/
|
||||
void
|
||||
x86_restart_syscall(struct iframe* frame)
|
||||
x86_initial_return_to_userland(Thread* thread, iframe* frame)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
// disable interrupts and set up CPU specifics for this thread
|
||||
disable_interrupts();
|
||||
|
||||
atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
|
||||
atomic_or(&thread->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
|
||||
x86_set_tss_and_kstack(thread->kernel_stack_top);
|
||||
x86_set_tls_context(thread);
|
||||
x86_set_syscall_stack(thread->kernel_stack_top);
|
||||
|
||||
frame->eax = frame->orig_eax;
|
||||
frame->edx = frame->orig_edx;
|
||||
frame->eip -= 2;
|
||||
// undoes the "int $99"/"sysenter"/"syscall" instruction
|
||||
// (so that it'll be executed again)
|
||||
|
||||
TSYSCALL(RestartSyscall());
|
||||
// return to userland
|
||||
x86_return_to_userland(frame);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_set_tls_context(Thread *thread)
|
||||
{
|
||||
int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT;
|
||||
|
||||
set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage);
|
||||
set_fs_register((entry << 3) | DPL_USER);
|
||||
}
|
||||
|
||||
|
||||
static uint8*
|
||||
get_signal_stack(Thread* thread, struct iframe* frame, struct sigaction* action)
|
||||
uint8*
|
||||
x86_get_signal_stack(Thread* thread, struct iframe* frame,
|
||||
struct sigaction* action)
|
||||
{
|
||||
// use the alternate signal stack if we should and can
|
||||
if (thread->signal_stack_enabled
|
||||
&& (action->sa_flags & SA_ONSTACK) != 0
|
||||
&& (frame->user_esp < thread->signal_stack_base
|
||||
|| frame->user_esp >= thread->signal_stack_base
|
||||
&& (frame->user_sp < thread->signal_stack_base
|
||||
|| frame->user_sp >= thread->signal_stack_base
|
||||
+ thread->signal_stack_size)) {
|
||||
return (uint8*)(thread->signal_stack_base + thread->signal_stack_size);
|
||||
}
|
||||
|
||||
return (uint8*)frame->user_esp;
|
||||
return (uint8*)frame->user_sp;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,84 +198,14 @@ get_signal_stack(Thread* thread, struct iframe* frame, struct sigaction* action)
|
||||
|
||||
|
||||
status_t
|
||||
arch_team_init_team_struct(Team *p, bool kernel)
|
||||
arch_team_init_team_struct(Team* p, bool kernel)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_thread_init_thread_struct(Thread *thread)
|
||||
{
|
||||
// set up an initial state (stack & fpu)
|
||||
memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Prepares the given thread's kernel stack for executing its entry function.
|
||||
|
||||
\param thread The thread.
|
||||
\param stack The usable bottom of the thread's kernel stack.
|
||||
\param stackTop The usable top of the thread's kernel stack.
|
||||
\param function The entry function the thread shall execute.
|
||||
\param data Pointer to be passed to the entry function.
|
||||
*/
|
||||
void
|
||||
arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
|
||||
void (*function)(void*), const void* data)
|
||||
{
|
||||
addr_t* stackTop = (addr_t*)_stackTop;
|
||||
|
||||
TRACE(("arch_thread_init_kthread_stack: stack top %p, function %, data: "
|
||||
"%p\n", stackTop, function, data));
|
||||
|
||||
// push the function argument, a pointer to the data
|
||||
*--stackTop = (addr_t)data;
|
||||
|
||||
// push a dummy return address for the function
|
||||
*--stackTop = 0;
|
||||
|
||||
// push the function address -- that's the return address used after the
|
||||
// context switch
|
||||
*--stackTop = (addr_t)function;
|
||||
|
||||
// simulate pushad as done by x86_context_switch()
|
||||
for (int i = 0; i < 8; i++)
|
||||
*--stackTop = 0;
|
||||
|
||||
// save the stack position
|
||||
thread->arch_info.current_stack.esp = stackTop;
|
||||
thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SEG;
|
||||
}
|
||||
|
||||
|
||||
/** Initializes the user-space TLS local storage pointer in
|
||||
* the thread structure, and the reserved TLS slots.
|
||||
*
|
||||
* Is called from _create_user_thread_kentry().
|
||||
*/
|
||||
|
||||
status_t
|
||||
arch_thread_init_tls(Thread *thread)
|
||||
{
|
||||
uint32 tls[TLS_USER_THREAD_SLOT + 1];
|
||||
|
||||
thread->user_local_storage = thread->user_stack_base
|
||||
+ thread->user_stack_size;
|
||||
|
||||
// initialize default TLS fields
|
||||
memset(tls, 0, sizeof(tls));
|
||||
tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage;
|
||||
tls[TLS_THREAD_ID_SLOT] = thread->id;
|
||||
tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread;
|
||||
|
||||
return user_memcpy((void *)thread->user_local_storage, tls, sizeof(tls));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_context_switch(Thread *from, Thread *to)
|
||||
arch_thread_context_switch(Thread* from, Thread* to)
|
||||
{
|
||||
x86_set_tss_and_kstack(to->kernel_stack_top);
|
||||
x86_set_syscall_stack(to->kernel_stack_top);
|
||||
@@ -395,7 +236,7 @@ arch_thread_context_switch(Thread *from, Thread *to)
|
||||
cpuData->arch.active_paging_structures = toPagingStructures;
|
||||
|
||||
// set the page directory, if it changes
|
||||
uint32 newPageDirectory = toPagingStructures->pgdir_phys;
|
||||
addr_t newPageDirectory = toPagingStructures->pgdir_phys;
|
||||
if (newPageDirectory != activePagingStructures->pgdir_phys)
|
||||
x86_swap_pgdir(newPageDirectory);
|
||||
|
||||
@@ -408,225 +249,31 @@ arch_thread_context_switch(Thread *from, Thread *to)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_thread_dump_info(void *info)
|
||||
{
|
||||
struct arch_thread *at = (struct arch_thread *)info;
|
||||
|
||||
kprintf("\tesp: %p\n", at->current_stack.esp);
|
||||
kprintf("\tss: %p\n", at->current_stack.ss);
|
||||
kprintf("\tfpu_state at %p\n", at->fpu_state);
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up initial thread context and enters user space
|
||||
*/
|
||||
status_t
|
||||
arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
|
||||
void* args2)
|
||||
{
|
||||
addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
|
||||
uint32 codeSize = (addr_t)x86_end_userspace_thread_exit
|
||||
- (addr_t)x86_userspace_thread_exit;
|
||||
uint32 args[3];
|
||||
|
||||
TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
|
||||
"ustack_top 0x%lx\n", entry, args1, args2, stackTop));
|
||||
|
||||
// copy the little stub that calls exit_thread() when the thread entry
|
||||
// function returns, as well as the arguments of the entry function
|
||||
stackTop -= codeSize;
|
||||
|
||||
if (user_memcpy((void *)stackTop, (const void *)&x86_userspace_thread_exit, codeSize) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
args[0] = stackTop;
|
||||
args[1] = (uint32)args1;
|
||||
args[2] = (uint32)args2;
|
||||
stackTop -= sizeof(args);
|
||||
|
||||
if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// prepare the user iframe
|
||||
iframe frame = {};
|
||||
frame.type = IFRAME_TYPE_SYSCALL;
|
||||
frame.gs = USER_DATA_SEG;
|
||||
// frame.fs not used, we call x86_set_tls_context() on context switch
|
||||
frame.es = USER_DATA_SEG;
|
||||
frame.ds = USER_DATA_SEG;
|
||||
frame.eip = entry;
|
||||
frame.cs = USER_CODE_SEG;
|
||||
frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
|
||||
| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
|
||||
frame.user_esp = stackTop;
|
||||
frame.user_ss = USER_DATA_SEG;
|
||||
|
||||
// return to userland
|
||||
initial_return_to_userland(thread, &frame);
|
||||
|
||||
return B_OK;
|
||||
// never gets here
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
arch_on_signal_stack(Thread *thread)
|
||||
{
|
||||
struct iframe *frame = get_current_iframe();
|
||||
struct iframe* frame = get_current_iframe();
|
||||
|
||||
return frame->user_esp >= thread->signal_stack_base
|
||||
&& frame->user_esp < thread->signal_stack_base
|
||||
return frame->user_sp >= thread->signal_stack_base
|
||||
&& frame->user_sp < thread->signal_stack_base
|
||||
+ thread->signal_stack_size;
|
||||
}
|
||||
|
||||
|
||||
/*! Sets up the user iframe for invoking a signal handler.
|
||||
|
||||
The function fills in the remaining fields of the given \a signalFrameData,
|
||||
copies it to the thread's userland stack (the one on which the signal shall
|
||||
be handled), and sets up the user iframe so that when returning to userland
|
||||
a wrapper function is executed that calls the user-defined signal handler.
|
||||
When the signal handler returns, the wrapper function shall call the
|
||||
"restore signal frame" syscall with the (possibly modified) signal frame
|
||||
data.
|
||||
|
||||
The following fields of the \a signalFrameData structure still need to be
|
||||
filled in:
|
||||
- \c context.uc_stack: The stack currently used by the thread.
|
||||
- \c context.uc_mcontext: The current userland state of the registers.
|
||||
- \c syscall_restart_return_value: Architecture specific use. On x86 the
|
||||
value of eax and edx which are overwritten by the syscall return value.
|
||||
|
||||
Furthermore the function needs to set \c thread->user_signal_context to the
|
||||
userland pointer to the \c ucontext_t on the user stack.
|
||||
|
||||
\param thread The current thread.
|
||||
\param action The signal action specified for the signal to be handled.
|
||||
\param signalFrameData A partially initialized structure of all the data
|
||||
that need to be copied to userland.
|
||||
\return \c B_OK on success, another error code, if something goes wrong.
|
||||
/*! Saves everything needed to restore the frame in the child fork in the
|
||||
arch_fork_arg structure to be passed to arch_restore_fork_frame().
|
||||
Also makes sure to return the right value.
|
||||
*/
|
||||
status_t
|
||||
arch_setup_signal_frame(Thread* thread, struct sigaction* action,
|
||||
struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
struct iframe *frame = get_current_iframe();
|
||||
if (!IFRAME_IS_USER(frame)) {
|
||||
panic("arch_setup_signal_frame(): No user iframe!");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
|
||||
// had the same signal number.
|
||||
if ((action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0
|
||||
&& signalFrameData->info.si_signo == SIGBUS) {
|
||||
signalFrameData->info.si_signo = SIGSEGV;
|
||||
}
|
||||
|
||||
// store the register state in signalFrameData->context.uc_mcontext
|
||||
signalFrameData->context.uc_mcontext.eip = frame->eip;
|
||||
signalFrameData->context.uc_mcontext.eflags = frame->flags;
|
||||
signalFrameData->context.uc_mcontext.eax = frame->eax;
|
||||
signalFrameData->context.uc_mcontext.ecx = frame->ecx;
|
||||
signalFrameData->context.uc_mcontext.edx = frame->edx;
|
||||
signalFrameData->context.uc_mcontext.ebp = frame->ebp;
|
||||
signalFrameData->context.uc_mcontext.esp = frame->user_esp;
|
||||
signalFrameData->context.uc_mcontext.edi = frame->edi;
|
||||
signalFrameData->context.uc_mcontext.esi = frame->esi;
|
||||
signalFrameData->context.uc_mcontext.ebx = frame->ebx;
|
||||
x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
// fill in signalFrameData->context.uc_stack
|
||||
signal_get_user_stack(frame->user_esp, &signalFrameData->context.uc_stack);
|
||||
|
||||
// store orig_eax/orig_edx in syscall_restart_return_value
|
||||
signalFrameData->syscall_restart_return_value
|
||||
= (uint64)frame->orig_edx << 32 | frame->orig_eax;
|
||||
|
||||
// get the stack to use -- that's either the current one or a special signal
|
||||
// stack
|
||||
uint8* userStack = get_signal_stack(thread, frame, action);
|
||||
|
||||
// copy the signal frame data onto the stack
|
||||
userStack -= sizeof(*signalFrameData);
|
||||
signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
|
||||
if (user_memcpy(userSignalFrameData, signalFrameData,
|
||||
sizeof(*signalFrameData)) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
// prepare the user stack frame for a function call to the signal handler
|
||||
// wrapper function
|
||||
uint32 stackFrame[2] = {
|
||||
frame->eip, // return address
|
||||
(addr_t)userSignalFrameData, // parameter: pointer to signal frame data
|
||||
};
|
||||
|
||||
userStack -= sizeof(stackFrame);
|
||||
if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// Update Thread::user_signal_context, now that everything seems to have
|
||||
// gone fine.
|
||||
thread->user_signal_context = &userSignalFrameData->context;
|
||||
|
||||
// Adjust the iframe's esp and eip, so that the thread will continue with
|
||||
// the prepared stack, executing the signal handler wrapper function.
|
||||
frame->user_esp = (addr_t)userStack;
|
||||
frame->eip = x86_get_user_signal_handler_wrapper(
|
||||
(action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
|
||||
{
|
||||
struct iframe* frame = get_current_iframe();
|
||||
|
||||
TRACE(("### arch_restore_signal_frame: entry\n"));
|
||||
|
||||
frame->orig_eax = (uint32)signalFrameData->syscall_restart_return_value;
|
||||
frame->orig_edx
|
||||
= (uint32)(signalFrameData->syscall_restart_return_value >> 32);
|
||||
|
||||
frame->eip = signalFrameData->context.uc_mcontext.eip;
|
||||
frame->flags = (frame->flags & ~(uint32)X86_EFLAGS_USER_FLAGS)
|
||||
| (signalFrameData->context.uc_mcontext.eflags & X86_EFLAGS_USER_FLAGS);
|
||||
frame->eax = signalFrameData->context.uc_mcontext.eax;
|
||||
frame->ecx = signalFrameData->context.uc_mcontext.ecx;
|
||||
frame->edx = signalFrameData->context.uc_mcontext.edx;
|
||||
frame->ebp = signalFrameData->context.uc_mcontext.ebp;
|
||||
frame->user_esp = signalFrameData->context.uc_mcontext.esp;
|
||||
frame->edi = signalFrameData->context.uc_mcontext.edi;
|
||||
frame->esi = signalFrameData->context.uc_mcontext.esi;
|
||||
frame->ebx = signalFrameData->context.uc_mcontext.ebx;
|
||||
|
||||
x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
TRACE(("### arch_restore_signal_frame: exit\n"));
|
||||
|
||||
return (int64)frame->eax | ((int64)frame->edx << 32);
|
||||
}
|
||||
|
||||
|
||||
/** Saves everything needed to restore the frame in the child fork in the
|
||||
* arch_fork_arg structure to be passed to arch_restore_fork_frame().
|
||||
* Also makes sure to return the right value.
|
||||
*/
|
||||
|
||||
void
|
||||
arch_store_fork_frame(struct arch_fork_arg *arg)
|
||||
arch_store_fork_frame(struct arch_fork_arg* arg)
|
||||
{
|
||||
struct iframe *frame = get_current_iframe();
|
||||
struct iframe* frame = x86_get_current_iframe();
|
||||
|
||||
// we need to copy the threads current iframe
|
||||
arg->iframe = *frame;
|
||||
|
||||
// we also want fork() to return 0 for the child
|
||||
arg->iframe.eax = 0;
|
||||
arg->iframe.ax = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -644,13 +291,5 @@ arch_store_fork_frame(struct arch_fork_arg *arg)
|
||||
void
|
||||
arch_restore_fork_frame(struct arch_fork_arg* arg)
|
||||
{
|
||||
initial_return_to_userland(thread_get_current_thread(), &arg->iframe);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_syscall_64_bit_return_value(void)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
|
||||
x86_initial_return_to_userland(thread_get_current_thread(), &arg->iframe);
|
||||
}
|
||||
|
||||
@@ -75,20 +75,20 @@ get_iframe_registers(struct iframe *frame, debug_cpu_state *cpuState)
|
||||
cpuState->fs = frame->fs;
|
||||
cpuState->es = frame->es;
|
||||
cpuState->ds = frame->ds;
|
||||
cpuState->edi = frame->edi;
|
||||
cpuState->esi = frame->esi;
|
||||
cpuState->ebp = frame->ebp;
|
||||
cpuState->esp = frame->esp;
|
||||
cpuState->ebx = frame->ebx;
|
||||
cpuState->edi = frame->di;
|
||||
cpuState->esi = frame->si;
|
||||
cpuState->ebp = frame->bp;
|
||||
cpuState->esp = frame->sp;
|
||||
cpuState->ebx = frame->bx;
|
||||
cpuState->edx = frame->orig_edx;
|
||||
cpuState->ecx = frame->ecx;
|
||||
cpuState->ecx = frame->cx;
|
||||
cpuState->eax = frame->orig_eax;
|
||||
cpuState->vector = frame->vector;
|
||||
cpuState->error_code = frame->error_code;
|
||||
cpuState->eip = frame->eip;
|
||||
cpuState->eip = frame->ip;
|
||||
cpuState->cs = frame->cs;
|
||||
cpuState->eflags = frame->flags;
|
||||
cpuState->user_esp = frame->user_esp;
|
||||
cpuState->user_esp = frame->user_sp;
|
||||
cpuState->user_ss = frame->user_ss;
|
||||
}
|
||||
|
||||
@@ -606,21 +606,21 @@ arch_set_debug_cpu_state(const debug_cpu_state *cpuState)
|
||||
// frame->fs = cpuState->fs;
|
||||
// frame->es = cpuState->es;
|
||||
// frame->ds = cpuState->ds;
|
||||
frame->edi = cpuState->edi;
|
||||
frame->esi = cpuState->esi;
|
||||
frame->ebp = cpuState->ebp;
|
||||
frame->di = cpuState->edi;
|
||||
frame->si = cpuState->esi;
|
||||
frame->bp = cpuState->ebp;
|
||||
// frame->esp = cpuState->esp;
|
||||
frame->ebx = cpuState->ebx;
|
||||
frame->edx = cpuState->edx;
|
||||
frame->ecx = cpuState->ecx;
|
||||
frame->eax = cpuState->eax;
|
||||
frame->bx = cpuState->ebx;
|
||||
frame->dx = cpuState->edx;
|
||||
frame->cx = cpuState->ecx;
|
||||
frame->ax = cpuState->eax;
|
||||
// frame->vector = cpuState->vector;
|
||||
// frame->error_code = cpuState->error_code;
|
||||
frame->eip = cpuState->eip;
|
||||
frame->ip = cpuState->eip;
|
||||
// frame->cs = cpuState->cs;
|
||||
frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS)
|
||||
| (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS);
|
||||
frame->user_esp = cpuState->user_esp;
|
||||
frame->user_sp = cpuState->user_esp;
|
||||
// frame->user_ss = cpuState->user_ss;
|
||||
}
|
||||
}
|
||||
@@ -977,7 +977,7 @@ x86_handle_breakpoint_exception(struct iframe *frame)
|
||||
TRACE(("x86_handle_breakpoint_exception()\n"));
|
||||
|
||||
// reset eip to the int3 instruction
|
||||
frame->eip--;
|
||||
frame->ip--;
|
||||
|
||||
if (!IFRAME_IS_USER(frame)) {
|
||||
panic("breakpoint exception in kernel mode");
|
||||
|
||||
@@ -45,20 +45,23 @@ dummy()
|
||||
DEFINE_OFFSET_MACRO(THREAD, Thread, fault_handler);
|
||||
|
||||
#ifdef __x86_64__
|
||||
// struct iframe
|
||||
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, vector);
|
||||
#else
|
||||
// struct arch_thread
|
||||
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, syscall_rsp);
|
||||
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, user_rsp);
|
||||
DEFINE_OFFSET_MACRO(ARCH_THREAD, arch_thread, current_stack);
|
||||
#endif
|
||||
|
||||
// struct iframe
|
||||
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, cs);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, eax);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, edx);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, orig_eax);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, ax);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, dx);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, vector);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, eip);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, ip);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, flags);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, user_esp);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, user_sp);
|
||||
#ifdef __INTEL__
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, orig_eax);
|
||||
|
||||
// struct vm86_iframe
|
||||
DEFINE_SIZEOF_MACRO(VM86_IFRAME, vm86_iframe);
|
||||
|
||||
@@ -18,8 +18,11 @@ void x86_initialize_commpage_syscall();
|
||||
static inline void
|
||||
x86_set_syscall_stack(addr_t stackTop)
|
||||
{
|
||||
// TODO: x86_64
|
||||
#ifndef __x86_64__
|
||||
if (gX86SetSyscallStack != NULL)
|
||||
gX86SetSyscallStack(stackTop);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user