added 4 changesets to branch 'refs/remotes/xyzzy-github/x86_64' old head: ee7aba5117fea8aa4d292fb9c105dc483c67a2e2 new head: b5c9d24abcc3599375153ed310b495ea944d46a0 ---------------------------------------------------------------------------- 5e9bb17: Renamed remaining i386_* functions to x86_* for consistency. 8c5e747: Don't need to shift the factor in system_time(), just store the already shifted value. 85d4a8b: Fixed compilation of C code using ELF headers. b5c9d24: 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. [ Alex Smith <alex@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 30 files changed, 958 insertions(+), 727 deletions(-) headers/private/kernel/arch/x86/32/iframe.h | 22 +- headers/private/kernel/arch/x86/64/descriptors.h | 6 +- headers/private/kernel/arch/x86/64/iframe.h | 18 +- headers/private/kernel/arch/x86/arch_cpu.h | 23 +- headers/private/kernel/arch/x86/arch_debug.h | 2 +- headers/private/kernel/arch/x86/arch_thread.h | 25 +- .../private/kernel/arch/x86/arch_thread_types.h | 25 +- headers/private/kernel/arch/x86/smp_priv.h | 1 - headers/private/system/elf_common.h | 2 +- src/system/kernel/arch/x86/32/arch.S | 6 +- src/system/kernel/arch/x86/32/int.cpp | 66 +-- src/system/kernel/arch/x86/32/interrupts.S | 14 +- src/system/kernel/arch/x86/32/thread.cpp | 396 +++++++++++++ src/system/kernel/arch/x86/64/arch.S | 56 +- src/system/kernel/arch/x86/64/int.cpp | 8 +- src/system/kernel/arch/x86/64/interrupts.S | 19 + src/system/kernel/arch/x86/64/stubs.cpp | 120 +--- src/system/kernel/arch/x86/64/thread.cpp | 196 +++++++ src/system/kernel/arch/x86/Jamfile | 4 +- src/system/kernel/arch/x86/arch_cpu.cpp | 13 +- src/system/kernel/arch/x86/arch_debug.cpp | 78 +-- src/system/kernel/arch/x86/arch_int.cpp | 3 +- src/system/kernel/arch/x86/arch_smp.cpp | 12 +- src/system/kernel/arch/x86/arch_thread.cpp | 480 ++-------------- src/system/kernel/arch/x86/arch_user_debugger.cpp | 56 +- src/system/kernel/arch/x86/asm_offsets.cpp | 21 +- src/system/kernel/arch/x86/vm86.cpp | 2 +- src/system/kernel/arch/x86/x86_syscalls.h | 3 + src/system/kernel/vm/vm.cpp | 2 +- .../libroot/os/arch/x86_64/system_time_asm.S | 6 +- ############################################################################ Commit: 5e9bb17da7b9cdd76ff9072486fab90688cf8c36 Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Mon Jul 9 11:14:18 2012 UTC Renamed remaining i386_* functions to x86_* for consistency. ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 204c901..17a3d41 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -401,7 +401,7 @@ void x86_page_fault_exception_double_fault(struct iframe* frame); #ifndef __x86_64__ -void i386_set_tss_and_kstack(addr_t kstack); +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); diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h index 7efd8b1..4a08809 100644 --- a/headers/private/kernel/arch/x86/arch_thread.h +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -17,9 +17,9 @@ extern "C" { #endif -struct iframe* i386_get_user_iframe(void); -struct iframe* i386_get_current_iframe(void); -struct iframe* i386_get_thread_user_iframe(Thread* thread); +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); diff --git a/headers/private/kernel/arch/x86/smp_priv.h b/headers/private/kernel/arch/x86/smp_priv.h index f5e6f45..17b0351 100644 --- a/headers/private/kernel/arch/x86/smp_priv.h +++ b/headers/private/kernel/arch/x86/smp_priv.h @@ -7,7 +7,6 @@ #include <SupportDefs.h> -int i386_smp_interrupt(int vector); void arch_smp_ack_interrupt(void); status_t arch_smp_set_apic_timer(bigtime_t relativeTimeout); status_t arch_smp_clear_apic_timer(void); diff --git a/src/system/kernel/arch/x86/32/interrupts.S b/src/system/kernel/arch/x86/32/interrupts.S index aa4dfe1..014fa33 100644 --- a/src/system/kernel/arch/x86/32/interrupts.S +++ b/src/system/kernel/arch/x86/32/interrupts.S @@ -884,7 +884,7 @@ FUNCTION(x86_vm86_enter): pushl THREAD_kernel_stack_top(%edi) movl %esp, THREAD_kernel_stack_top(%edi) pushl %esp - call i386_set_tss_and_kstack + call x86_set_tss_and_kstack // go to vm86 mode cli @@ -916,7 +916,7 @@ FUNCTION(x86_vm86_return): movl %dr3, %edi movl %eax, THREAD_kernel_stack_top(%edi) pushl %eax - call i386_set_tss_and_kstack + call x86_set_tss_and_kstack addl $4, %esp // restore registers diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 2edd3c3..2c61241 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -974,7 +974,7 @@ arch_cpu_init_post_modules(kernel_args* args) #ifndef __x86_64__ void -i386_set_tss_and_kstack(addr_t kstack) +x86_set_tss_and_kstack(addr_t kstack) { get_cpu_struct()->arch.tss.sp0 = kstack; } diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index e8b9092..beedfa3 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -503,7 +503,7 @@ static struct iframe* get_current_iframe(Thread* thread) { if (thread == thread_get_current_thread()) - return i386_get_current_iframe(); + return x86_get_current_iframe(); addr_t ebp = thread->arch_info.current_stack.esp[2]; // NOTE: This doesn't work, if the thread is running (on another CPU). diff --git a/src/system/kernel/arch/x86/arch_smp.cpp b/src/system/kernel/arch/x86/arch_smp.cpp index 0720ae0..a63051b 100644 --- a/src/system/kernel/arch/x86/arch_smp.cpp +++ b/src/system/kernel/arch/x86/arch_smp.cpp @@ -39,7 +39,7 @@ static uint32 sAPICVersions[B_MAX_CPU_COUNT]; static int32 -i386_ici_interrupt(void *data) +x86_ici_interrupt(void *data) { // genuine inter-cpu interrupt int cpu = smp_get_current_cpu(); @@ -49,7 +49,7 @@ i386_ici_interrupt(void *data) static int32 -i386_spurious_interrupt(void *data) +x86_spurious_interrupt(void *data) { // spurious interrupt TRACE(("spurious interrupt on cpu %ld\n", smp_get_current_cpu())); @@ -62,7 +62,7 @@ i386_spurious_interrupt(void *data) static int32 -i386_smp_error_interrupt(void *data) +x86_smp_error_interrupt(void *data) { // smp error interrupt TRACE(("smp error interrupt on cpu %ld\n", smp_get_current_cpu())); @@ -91,9 +91,9 @@ arch_smp_init(kernel_args *args) if (args->num_cpus > 1) { // I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted reserve_io_interrupt_vectors(3, 0xfd - ARCH_INTERRUPT_BASE); - install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR); - install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); - install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &x86_ici_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &x86_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); + install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &x86_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); } return B_OK; diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index ce482ba..da8e47d 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -67,7 +67,6 @@ class RestartSyscall : public AbstractTraceEntry { // from arch_interrupts.S -extern "C" void i386_stack_init(struct farcall *interrupt_stack_offset); extern "C" void x86_return_to_userland(iframe* frame); // from arch_cpu.c @@ -160,7 +159,7 @@ initial_return_to_userland(Thread* thread, iframe* frame) // disable interrupts and set up CPU specifics for this thread disable_interrupts(); - i386_set_tss_and_kstack(thread->kernel_stack_top); + x86_set_tss_and_kstack(thread->kernel_stack_top); x86_set_tls_context(thread); x86_set_syscall_stack(thread->kernel_stack_top); @@ -177,7 +176,7 @@ initial_return_to_userland(Thread* thread, iframe* frame) the thread is a kernel thread). */ struct iframe * -i386_get_user_iframe(void) +x86_get_user_iframe(void) { struct iframe* frame = get_current_iframe(); @@ -191,11 +190,11 @@ i386_get_user_iframe(void) } -/*! \brief Like i386_get_user_iframe(), just for the given thread. +/*! \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 * -i386_get_thread_user_iframe(Thread *thread) +x86_get_thread_user_iframe(Thread *thread) { if (thread->state == B_THREAD_RUNNING) return NULL; @@ -217,7 +216,7 @@ i386_get_thread_user_iframe(Thread *thread) struct iframe * -i386_get_current_iframe(void) +x86_get_current_iframe(void) { return get_current_iframe(); } @@ -367,7 +366,7 @@ arch_thread_init_tls(Thread *thread) void arch_thread_context_switch(Thread *from, Thread *to) { - i386_set_tss_and_kstack(to->kernel_stack_top); + x86_set_tss_and_kstack(to->kernel_stack_top); x86_set_syscall_stack(to->kernel_stack_top); // set TLS GDT entry to the current thread - since this action is diff --git a/src/system/kernel/arch/x86/arch_user_debugger.cpp b/src/system/kernel/arch/x86/arch_user_debugger.cpp index 42aaf6f..99e2b83 100644 --- a/src/system/kernel/arch/x86/arch_user_debugger.cpp +++ b/src/system/kernel/arch/x86/arch_user_debugger.cpp @@ -516,7 +516,7 @@ debugger_single_step(int argc, char** argv) // TODO: Since we need an iframe, this doesn't work when KDL wasn't entered // via an exception. - struct iframe* frame = i386_get_current_iframe(); + struct iframe* frame = x86_get_current_iframe(); if (frame == NULL) { kprintf("Failed to get the current iframe!\n"); return 0; @@ -568,7 +568,7 @@ arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) void arch_update_thread_single_step() { - if (struct iframe* frame = i386_get_user_iframe()) { + if (struct iframe* frame = x86_get_user_iframe()) { Thread* thread = thread_get_current_thread(); // set/clear TF in EFLAGS depending on whether single stepping is @@ -584,7 +584,7 @@ arch_update_thread_single_step() void arch_set_debug_cpu_state(const debug_cpu_state *cpuState) { - if (struct iframe *frame = i386_get_user_iframe()) { + if (struct iframe *frame = x86_get_user_iframe()) { // For the floating point state to be correct the calling function must // not use these registers (not even indirectly). if (gHasSSE) { @@ -629,7 +629,7 @@ arch_set_debug_cpu_state(const debug_cpu_state *cpuState) void arch_get_debug_cpu_state(debug_cpu_state *cpuState) { - if (struct iframe *frame = i386_get_user_iframe()) { + if (struct iframe *frame = x86_get_user_iframe()) { // For the floating point state to be correct the calling function must // not use these registers (not even indirectly). if (gHasSSE) { @@ -852,7 +852,7 @@ x86_handle_debug_exception(struct iframe *frame) asm("movl %%dr7, %0" : "=r"(dr7)); } - TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); + TRACE(("x86_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); // check, which exception condition applies if (dr6 & X86_DR6_BREAKPOINT_MASK) { @@ -885,7 +885,7 @@ x86_handle_debug_exception(struct iframe *frame) // Occurs only, if GD in DR7 is set (which we don't do) and someone // tries to write to the debug registers. if (IFRAME_IS_USER(frame)) { - dprintf("i386_handle_debug_exception(): ignoring spurious general " + dprintf("x86_handle_debug_exception(): ignoring spurious general " "detect exception\n"); enable_interrupts(); @@ -908,7 +908,7 @@ x86_handle_debug_exception(struct iframe *frame) // kernel entry or whether this is genuine kernel single-stepping. bool inKernel = true; if (thread->team != team_get_kernel_team() - && i386_get_user_iframe() == NULL) { + && x86_get_user_iframe() == NULL) { // TODO: This is not yet fully correct, since a newly created // thread that hasn't entered userland yet also has this // property. @@ -948,7 +948,7 @@ x86_handle_debug_exception(struct iframe *frame) // task switch // Occurs only, if T in EFLAGS is set (which we don't do). if (IFRAME_IS_USER(frame)) { - dprintf("i386_handle_debug_exception(): ignoring spurious task switch " + dprintf("x86_handle_debug_exception(): ignoring spurious task switch " "exception\n"); enable_interrupts(); @@ -956,7 +956,7 @@ x86_handle_debug_exception(struct iframe *frame) panic("spurious task switch exception in kernel mode"); } else { if (IFRAME_IS_USER(frame)) { - TRACE(("i386_handle_debug_exception(): ignoring spurious debug " + TRACE(("x86_handle_debug_exception(): ignoring spurious debug " "exception (no condition recognized)\n")); enable_interrupts(); @@ -974,7 +974,7 @@ x86_handle_debug_exception(struct iframe *frame) void x86_handle_breakpoint_exception(struct iframe *frame) { - TRACE(("i386_handle_breakpoint_exception()\n")); + TRACE(("x86_handle_breakpoint_exception()\n")); // reset eip to the int3 instruction frame->eip--; diff --git a/src/system/kernel/arch/x86/vm86.cpp b/src/system/kernel/arch/x86/vm86.cpp index ebfce51..948b701 100644 --- a/src/system/kernel/arch/x86/vm86.cpp +++ b/src/system/kernel/arch/x86/vm86.cpp @@ -512,7 +512,7 @@ emulate(struct vm86_state *state) static bool vm86_fault_callback(addr_t address, addr_t faultAddress, bool isWrite) { - struct iframe *frame = i386_get_user_iframe(); + struct iframe *frame = x86_get_user_iframe(); TRACE("Unhandled fault at %#" B_PRIxADDR " touching %#" B_PRIxADDR "while %s\n", faultAddress, address, isWrite ? "writing" : "reading"); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 21518a2..b4f00fb 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -4088,7 +4088,7 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser, #endif } frame; # ifdef __INTEL__ - struct iframe* iframe = i386_get_user_iframe(); + struct iframe* iframe = x86_get_user_iframe(); if (iframe == NULL) panic("iframe is NULL!"); ############################################################################ Commit: 8c5e74719039c7275a5a80b236b830b7b4ba1be7 Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Mon Jul 9 11:25:49 2012 UTC Don't need to shift the factor in system_time(), just store the already shifted value. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 2c61241..41713b3 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -824,7 +824,8 @@ arch_cpu_init(kernel_args* args) // The x86_64 system_time() implementation uses 64-bit multiplication and // therefore shifting is not necessary for low frequencies (it's also not // too likely that there'll be any x86_64 CPUs clocked under 1GHz). - __x86_setup_system_time(conversionFactor, conversionFactorNsecs); + __x86_setup_system_time((uint64)conversionFactor << 32, + conversionFactorNsecs); #else if (conversionFactorNsecs >> 32 != 0) { // the TSC frequency is < 1 GHz, which forces us to shift the factor diff --git a/src/system/libroot/os/arch/x86_64/system_time_asm.S b/src/system/libroot/os/arch/x86_64/system_time_asm.S index 135b54a..641c86d 100644 --- a/src/system/libroot/os/arch/x86_64/system_time_asm.S +++ b/src/system/libroot/os/arch/x86_64/system_time_asm.S @@ -29,9 +29,9 @@ FUNCTION_END(__x86_setup_system_time) /* int64 system_time(); */ FUNCTION(system_time): // (rdtsc * cv_factor) >> 32. + // Factor is pre-shifted left by 32 bits. movq cv_factor, %rcx - shl $32, %rcx // Load 64-bit TSC into %eax (low), %edx (high). rdtsc @@ -43,7 +43,7 @@ FUNCTION(system_time): // Multiply by conversion factor, result in %rax (low), %rdx (high). mulq %rcx - // Conversion factor preshifted by 32, whole result in high. + // Due to pre-shifting of the factor the whole result in high. movq %rdx, %rax ret FUNCTION_END(system_time) @@ -53,7 +53,7 @@ FUNCTION_END(system_time) FUNCTION(system_time_nsecs): // Same algorithm as system_time(), but with a different factor. // (rdtsc * cv_factor_nsecs) >> 32. - // Cannot pre-shift the factor here, otherwise we may lose the upper + // Factor has not been pre-shifted here, otherwise we may lose the upper // 32 bits. movq cv_factor_nsecs, %rcx ############################################################################ Commit: 85d4a8bc4e248b992efcde8af001f156cd2c47a9 Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Mon Jul 9 13:35:01 2012 UTC Fixed compilation of C code using ELF headers. ---------------------------------------------------------------------------- diff --git a/headers/private/system/elf_common.h b/headers/private/system/elf_common.h index edfd744..31eb0c0 100644 --- a/headers/private/system/elf_common.h +++ b/headers/private/system/elf_common.h @@ -272,7 +272,7 @@ #endif #define DEFINE_ELF_TYPE(type, name) \ struct _ELF_TYPE(type); \ - typedef _ELF_TYPE(type) name + typedef struct _ELF_TYPE(type) name DEFINE_ELF_TYPE(Ehdr, elf_ehdr); DEFINE_ELF_TYPE(Phdr, elf_phdr); ############################################################################ Commit: b5c9d24abcc3599375153ed310b495ea944d46a0 Author: Alex Smith <alex@xxxxxxxxxxxxxxxx> Date: Mon Jul 9 15:43:01 2012 UTC 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. ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/arch/x86/32/iframe.h b/headers/private/kernel/arch/x86/32/iframe.h index 6da6c1f..1aa51ed 100644 --- a/headers/private/kernel/arch/x86/32/iframe.h +++ b/headers/private/kernel/arch/x86/32/iframe.h @@ -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; }; diff --git a/headers/private/kernel/arch/x86/64/descriptors.h b/headers/private/kernel/arch/x86/64/descriptors.h index 8e70cba..3f05196 100644 --- a/headers/private/kernel/arch/x86/64/descriptors.h +++ b/headers/private/kernel/arch/x86/64/descriptors.h @@ -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; diff --git a/headers/private/kernel/arch/x86/64/iframe.h b/headers/private/kernel/arch/x86/64/iframe.h index a0ca48f..cd257ef 100644 --- a/headers/private/kernel/arch/x86/64/iframe.h +++ b/headers/private/kernel/arch/x86/64/iframe.h @@ -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; diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 17a3d41..32f0129 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -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); diff --git a/headers/private/kernel/arch/x86/arch_debug.h b/headers/private/kernel/arch/x86/arch_debug.h index 789ecc74..eb2028f 100644 --- a/headers/private/kernel/arch/x86/arch_debug.h +++ b/headers/private/kernel/arch/x86/arch_debug.h @@ -10,7 +10,7 @@ struct arch_debug_registers { - uint32 ebp; + addr_t bp; }; diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h index 4a08809..850cfc9 100644 --- a/headers/private/kernel/arch/x86/arch_thread.h +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -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); } diff --git a/headers/private/kernel/arch/x86/arch_thread_types.h b/headers/private/kernel/arch/x86/arch_thread_types.h index 900046f..209543e 100644 --- a/headers/private/kernel/arch/x86/arch_thread_types.h +++ b/headers/private/kernel/arch/x86/arch_thread_types.h @@ -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; }; diff --git a/src/system/kernel/arch/x86/32/arch.S b/src/system/kernel/arch/x86/32/arch.S index e966580..97eb069 100644 --- a/src/system/kernel/arch/x86/32/arch.S +++ b/src/system/kernel/arch/x86/32/arch.S @@ -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): diff --git a/src/system/kernel/arch/x86/32/int.cpp b/src/system/kernel/arch/x86/32/int.cpp index d35e3f0..acfc117 100644 --- a/src/system/kernel/arch/x86/32/int.cpp +++ b/src/system/kernel/arch/x86/32/int.cpp @@ -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; } } diff --git a/src/system/kernel/arch/x86/32/interrupts.S b/src/system/kernel/arch/x86/32/interrupts.S index 014fa33..ea3cd5e 100644 --- a/src/system/kernel/arch/x86/32/interrupts.S +++ b/src/system/kernel/arch/x86/32/interrupts.S @@ -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 diff --git a/src/system/kernel/arch/x86/32/thread.cpp b/src/system/kernel/arch/x86/32/thread.cpp new file mode 100644 index 0000000..4df1685 --- /dev/null +++ b/src/system/kernel/arch/x86/32/thread.cpp @@ -0,0 +1,396 @@ +/* + * Copyright 2002-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * 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); +} diff --git a/src/system/kernel/arch/x86/64/arch.S b/src/system/kernel/arch/x86/64/arch.S index eb51f75..4fe6573 100644 --- a/src/system/kernel/arch/x86/64/arch.S +++ b/src/system/kernel/arch/x86/64/arch.S @@ -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 diff --git a/src/system/kernel/arch/x86/64/int.cpp b/src/system/kernel/arch/x86/64/int.cpp index bbc5850..6117171 100644 --- a/src/system/kernel/arch/x86/64/int.cpp +++ b/src/system/kernel/arch/x86/64/int.cpp @@ -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); } diff --git a/src/system/kernel/arch/x86/64/interrupts.S b/src/system/kernel/arch/x86/64/interrupts.S index d5f8fca..7987ed2 100644 --- a/src/system/kernel/arch/x86/64/interrupts.S +++ b/src/system/kernel/arch/x86/64/interrupts.S @@ -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) diff --git a/src/system/kernel/arch/x86/64/stubs.cpp b/src/system/kernel/arch/x86/64/stubs.cpp index 5f85b9a..2651c32 100644 --- a/src/system/kernel/arch/x86/64/stubs.cpp +++ b/src/system/kernel/arch/x86/64/stubs.cpp @@ -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 }; diff --git a/src/system/kernel/arch/x86/64/thread.cpp b/src/system/kernel/arch/x86/64/thread.cpp new file mode 100644 index 0000000..b4e9d8a --- /dev/null +++ b/src/system/kernel/arch/x86/64/thread.cpp @@ -0,0 +1,196 @@ +/* + * Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxxx + * Copyright 2002-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * 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; +} diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index ad27ff1..0fac1a0 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -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 diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 41713b3..3640773 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.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 diff --git a/src/system/kernel/arch/x86/arch_debug.cpp b/src/system/kernel/arch/x86/arch_debug.cpp index beedfa3..c8e494c 100644 --- a/src/system/kernel/arch/x86/arch_debug.cpp +++ b/src/system/kernel/arch/x86/arch_debug.cpp @@ -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 }; diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 9bec1d7..3fdee86 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -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; } diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index da8e47d..d0a1769 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -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) } -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->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()); -} +/*! 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_set_tls_context(Thread *thread) +x86_initial_return_to_userland(Thread* thread, iframe* frame) { - int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; + // 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); - set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage); - set_fs_register((entry << 3) | DPL_USER); + // return to userland + x86_return_to_userland(frame); } -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. [ *** diff truncated: 446 lines dropped *** ]