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:
Alex Smith
2012-07-09 16:43:01 +01:00
parent 85d4a8bc4e
commit b5c9d24abc
24 changed files with 923 additions and 691 deletions
+11 -11
View File
@@ -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;
+9 -9
View File
@@ -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;
+15 -8
View File
@@ -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);
+1 -1
View File
@@ -10,7 +10,7 @@
struct arch_debug_registers {
uint32 ebp;
addr_t bp;
};
+12 -7
View File
@@ -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;
};
+3 -3
View File
@@ -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):
+33 -33
View File
@@ -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;
}
}
+5 -5
View File
@@ -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
+396
View File
@@ -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);
}
+53 -3
View File
@@ -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
+4 -4
View File
@@ -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)
+11 -109
View File
@@ -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 };
+196
View File
@@ -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;
}
+3 -1
View File
@@ -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
+1 -7
View File
@@ -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
+38 -38
View File
@@ -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
};
+2 -1
View File
@@ -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;
}
+55 -416
View File
@@ -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");
+12 -9
View File
@@ -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
}