diff --git a/headers/private/kernel/arch/ppc/arch_cpu.h b/headers/private/kernel/arch/ppc/arch_cpu.h index 17865443ed..15bbe330f7 100644 --- a/headers/private/kernel/arch/ppc/arch_cpu.h +++ b/headers/private/kernel/arch/ppc/arch_cpu.h @@ -13,6 +13,7 @@ #define PAGE_SIZE 4096 struct iframe { + uint32 vector; uint32 srr0; uint32 srr1; uint32 dar; diff --git a/headers/private/kernel/arch/ppc/arch_thread.h b/headers/private/kernel/arch/ppc/arch_thread.h index 96805569db..b9e1cbdacb 100644 --- a/headers/private/kernel/arch/ppc/arch_thread.h +++ b/headers/private/kernel/arch/ppc/arch_thread.h @@ -1,8 +1,44 @@ /* -** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ + * Copyright 2003-2006, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler + * Ingo Weinhold + */ #ifndef _KERNEL_ARCH_PPC_THREAD_H #define _KERNEL_ARCH_PPC_THREAD_H +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame); +void ppc_pop_iframe(struct iframe_stack *stack); +struct iframe *ppc_get_user_iframe(void); + + +extern inline struct thread * +arch_thread_get_current_thread(void) +{ + struct thread *t; + asm volatile("mfsprg2 %0" : "=r"(t)); + return t; +} + + +extern inline void +arch_thread_set_current_thread(struct thread *t) +{ + asm volatile("mtsprg2 %0" : : "r"(t)); +} + + +#ifdef __cplusplus +} +#endif + + #endif /* _KERNEL_ARCH_PPC_THREAD_H */ diff --git a/headers/private/kernel/arch/ppc/arch_thread_types.h b/headers/private/kernel/arch/ppc/arch_thread_types.h index 96fb0bda74..17c3aa851b 100644 --- a/headers/private/kernel/arch/ppc/arch_thread_types.h +++ b/headers/private/kernel/arch/ppc/arch_thread_types.h @@ -5,17 +5,34 @@ #ifndef KERNEL_ARCH_PPC_THREAD_TYPES_H #define KERNEL_ARCH_PPC_THREAD_TYPES_H +#define IFRAME_TRACE_DEPTH 4 + +struct iframe_stack { + struct iframe *frames[IFRAME_TRACE_DEPTH]; + int32 index; +}; + // architecture specific thread info struct arch_thread { - void *sp; // stack pointer + void *sp; // stack pointer + void *interrupt_stack; + + // used to track interrupts on this thread + struct iframe_stack iframes; }; struct arch_team { - // nothing here + // 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; }; struct arch_fork_arg { - // nothing here yet + // 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; }; #endif /* KERNEL_ARCH_PPC_THREAD_TYPES_H */ diff --git a/src/system/kernel/arch/ppc/arch_cpu.cpp b/src/system/kernel/arch/ppc/arch_cpu.cpp index 2adf2fb165..29ea49a677 100644 --- a/src/system/kernel/arch/ppc/arch_cpu.cpp +++ b/src/system/kernel/arch/ppc/arch_cpu.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -17,6 +18,10 @@ status_t arch_cpu_preboot_init(kernel_args *args) { + // The current thread must be NULL for all CPUs till we have threads. + // Some boot code relies on this. + arch_thread_set_current_thread(NULL); + return B_OK; } diff --git a/src/system/kernel/arch/ppc/arch_debug.cpp b/src/system/kernel/arch/ppc/arch_debug.cpp index 8f81866b28..02e50193d2 100644 --- a/src/system/kernel/arch/ppc/arch_debug.cpp +++ b/src/system/kernel/arch/ppc/arch_debug.cpp @@ -1,15 +1,260 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2003-2005, Axel D�fler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. */ -#include -#include #include +#include +#include +#include +#include +#include -// ToDo: put stack trace and disassembly routines here +struct stack_frame { + struct stack_frame *previous; + addr_t return_address; +}; + +#define NUM_PREVIOUS_LOCATIONS 32 + +extern struct iframe_stack gBootFrameStack; + + +static bool +already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer) +{ + int32 last = *_last; + int32 num = *_num; + int32 i; + + for (i = 0; i < num; i++) { + if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) + % NUM_PREVIOUS_LOCATIONS] == framePointer) { + return true; + } + } + + *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; + visited[last] = framePointer; + + if (num < NUM_PREVIOUS_LOCATIONS) + *_num = num + 1; + + return false; +} + + +static inline stack_frame * +get_current_stack_frame() +{ + stack_frame *frame; + asm volatile("mr %0, %%r1" : "=r"(frame)); + return frame; +} + + +static status_t +get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip) +{ + struct thread *thread = thread_get_current_thread(); + + // set fault handler, so that we can safely access user stacks + if (thread) + thread->fault_handler = (addr_t)&&error; + + *ip = ((struct stack_frame *)framePointer)->return_address; + *next = (addr_t)((struct stack_frame *)framePointer)->previous; + + if (thread) + thread->fault_handler = NULL; + return B_OK; + +error: + thread->fault_handler = NULL; + return B_BAD_ADDRESS; +} + + +static void +print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer, + addr_t nextFramePointer) +{ + addr_t diff = nextFramePointer - framePointer; + + // kernel space/user space switch + if (diff & 0x80000000) + diff = 0; + + // lookup symbol + const char *symbol, *image; + addr_t baseAddress; + bool exactMatch; + status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol, + &image, &exactMatch); + if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) { + // try to locate the image in the images loaded into user space + status = image_debug_lookup_user_symbol_address(thread->team, ip, + &baseAddress, &symbol, &image, &exactMatch); + } + if (status == B_OK) { + if (symbol != NULL) { + kprintf("%08lx (+%4ld) %08lx <%s>:%s + 0x%04lx%s\n", framePointer, + diff, ip, image, symbol, ip - baseAddress, + (exactMatch ? "" : " (nearest)")); + } else { + kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n", + framePointer, diff, ip, image, (void *)baseAddress, + ip - baseAddress); + } + } else + kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip); +} + + +static int +stack_trace(int argc, char **argv) +{ + uint32 previousLocations[NUM_PREVIOUS_LOCATIONS]; + struct iframe_stack *frameStack; + struct thread *thread; + addr_t framePointer; + int32 i, num = 0, last = 0; + + if (argc < 2) { + thread = thread_get_current_thread(); + framePointer = (addr_t)get_current_stack_frame(); + } else { +// TODO: Add support for stack traces of other threads. +/* thread_id id = strtoul(argv[1], NULL, 0); + thread = thread_get_thread_struct_locked(id); + if (thread == NULL) { + kprintf("could not find thread %ld\n", id); + return 0; + } + + // read %ebp from the thread's stack stored by a pushad + ebp = thread->arch_info.current_stack.esp[2]; + + if (id != thread_get_current_thread_id()) { + // switch to the page directory of the new thread to be + // able to follow the stack trace into userland + addr_t newPageDirectory = (addr_t)x86_next_page_directory( + thread_get_current_thread(), thread); + + if (newPageDirectory != 0) { + read_cr3(oldPageDirectory); + write_cr3(newPageDirectory); + } + } +*/ +kprintf("Stack traces of other threads not supported yet!\n"); +return 0; + } + + // We don't have a thread pointer early in the boot process + if (thread != NULL) + frameStack = &thread->arch_info.iframes; + else + frameStack = &gBootFrameStack; + + for (i = 0; i < frameStack->index; i++) { + kprintf("iframe %p (end = %p)\n", + frameStack->frames[i], frameStack->frames[i] + 1); + } + + if (thread != NULL) { + kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id, + thread->name); + + kprintf(" kernel stack: %p to %p\n", + (void *)thread->kernel_stack_base, + (void *)(thread->kernel_stack_base + KERNEL_STACK_SIZE)); + if (thread->user_stack_base != 0) { + kprintf(" user stack: %p to %p\n", + (void *)thread->user_stack_base, + (void *)(thread->user_stack_base + thread->user_stack_size)); + } + } + + kprintf("frame caller :function + offset\n"); + + for (;;) { + // see if the frame pointer matches the iframe + struct iframe *frame = NULL; + for (i = 0; i < frameStack->index; i++) { + if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) { + // it's an iframe + frame = frameStack->frames[i]; + break; + } + } + + if (frame) { + kprintf("iframe at %p\n", frame); + kprintf(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n", + frame->r0, frame->r1, frame->r2, frame->r3); + kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n", + frame->r4, frame->r5, frame->r6, frame->r7); + kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n", + frame->r8, frame->r9, frame->r10, frame->r11); + kprintf(" r12 0x%08lx r13 0x%08lx r14 0x%08lx r15 0x%08lx\n", + frame->r12, frame->r13, frame->r14, frame->r15); + kprintf(" r16 0x%08lx r17 0x%08lx r18 0x%08lx r19 0x%08lx\n", + frame->r16, frame->r17, frame->r18, frame->r19); + kprintf(" r20 0x%08lx r21 0x%08lx r22 0x%08lx r23 0x%08lx\n", + frame->r20, frame->r21, frame->r22, frame->r23); + kprintf(" r24 0x%08lx r25 0x%08lx r26 0x%08lx r27 0x%08lx\n", + frame->r24, frame->r25, frame->r26, frame->r27); + kprintf(" r28 0x%08lx r29 0x%08lx r30 0x%08lx r31 0x%08lx\n", + frame->r28, frame->r29, frame->r30, frame->r31); + kprintf(" srr0 0x%08lx srr1 0x%08lx", frame->srr0, frame->srr1); +// TODO: Look up the bit in srr1! +// if ((frame->error_code & 0x4) != 0) { +// // from user space +// kprintf("user esp 0x%lx", frame->user_esp); +// } + kprintf("\n"); + kprintf(" vector: 0x%lx\n", frame->vector); + + print_stack_frame(thread, frame->srr0, framePointer, frame->r1); + framePointer = frame->r1; + } else { + addr_t ip, nextFramePointer; + + if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) { + kprintf("%08lx -- read fault\n", framePointer); + break; + } + + if (ip == 0 || framePointer == 0) + break; + + print_stack_frame(thread, ip, framePointer, nextFramePointer); + framePointer = nextFramePointer; + } + + if (already_visited(previousLocations, &last, &num, framePointer)) { + kprintf("circular stack frame: %p!\n", (void *)framePointer); + break; + } + if (framePointer == 0) + break; + } + +/* if (oldPageDirectory != 0) { + // switch back to the previous page directory to no cause any troubles + write_cr3(oldPageDirectory); + } +*/ + + return 0; +} + + + +// #pragma mark - void @@ -21,7 +266,7 @@ arch_debug_save_registers(int *regs) void * arch_debug_get_caller(void) { - // TODO: imeplement me + // TODO: implement me return (void *)&arch_debug_get_caller; } @@ -29,7 +274,11 @@ arch_debug_get_caller(void) status_t arch_debug_init(kernel_args *args) { - return B_OK; + add_debugger_command("where", &stack_trace, "Same as \"sc\""); + add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); + add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); + + return B_NO_ERROR; } diff --git a/src/system/kernel/arch/ppc/arch_exceptions.S b/src/system/kernel/arch/ppc/arch_exceptions.S index f4bf327469..c73770db2b 100644 --- a/src/system/kernel/arch/ppc/arch_exceptions.S +++ b/src/system/kernel/arch/ppc/arch_exceptions.S @@ -288,6 +288,8 @@ __save_regs: mfspr %r0, %srr0 stwu %r0, -4(%r1) /* push SRR0 */ + stwu %r3, -4(%r1) /* exception vector offset */ + blr @@ -295,7 +297,7 @@ __save_regs: * r1: iframe pointer */ __restore_regs_and_rfi: - lwz %r0, 0(%r1) /* SRR0 */ + lwzu %r0, 4(%r1) /* SRR0 (skip vector offset) */ mtspr %srr0, %r0 lwzu %r0, 4(%r1) /* SRR1 */ mtspr %srr1, %r0 diff --git a/src/system/kernel/arch/ppc/arch_int.cpp b/src/system/kernel/arch/ppc/arch_int.cpp index ad14367fc9..54ab9b23c6 100644 --- a/src/system/kernel/arch/ppc/arch_int.cpp +++ b/src/system/kernel/arch/ppc/arch_int.cpp @@ -36,6 +36,11 @@ extern"C" void ppc_exception_tail(void); static ppc_cpu_exception_context sCPUExceptionContexts[SMP_MAX_CPUS]; +// An iframe stack used in the early boot process when we don't have +// threads yet. +struct iframe_stack gBootFrameStack; + + void arch_int_enable_io_interrupt(int irq) { @@ -72,20 +77,24 @@ print_iframe(struct iframe *frame) } -extern "C" void exception_tail_test(); -void -exception_tail_test() -{ -} - extern "C" void ppc_exception_entry(int vector, struct iframe *iframe); void ppc_exception_entry(int vector, struct iframe *iframe) { int ret = B_HANDLED_INTERRUPT; - if (vector != 0x900) - dprintf("ppc_exception_entry: time %Ld vector 0x%x, iframe %p\n", system_time(), vector, iframe); + if (vector != 0x900) { + dprintf("ppc_exception_entry: time %lld vector 0x%x, iframe %p, " + "srr0: %p\n", system_time(), vector, iframe, (void*)iframe->srr0); + } + + struct thread *thread = thread_get_current_thread(); + + // push iframe + if (thread) + ppc_push_iframe(&thread->arch_info.iframes, iframe); + else + ppc_push_iframe(&gBootFrameStack, iframe); switch (vector) { case 0x100: // system reset @@ -170,6 +179,12 @@ ppc_exception_entry(int vector, struct iframe *iframe) RELEASE_THREAD_LOCK(); restore_interrupts(state); } + + // pop iframe + if (thread) + ppc_pop_iframe(&thread->arch_info.iframes); + else + ppc_pop_iframe(&gBootFrameStack); } diff --git a/src/system/kernel/arch/ppc/arch_thread.c b/src/system/kernel/arch/ppc/arch_thread.c index 4d62145c35..8354cf10bf 100644 --- a/src/system/kernel/arch/ppc/arch_thread.c +++ b/src/system/kernel/arch/ppc/arch_thread.c @@ -1,11 +1,16 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2003-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * + * Authors: + * Axel Dörfler + * Ingo Weinhold + * * Copyright 2001, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. */ +#include #include #include @@ -16,6 +21,40 @@ #include +void +ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame) +{ + ASSERT(stack->index < IFRAME_TRACE_DEPTH); + stack->frames[stack->index++] = frame; +} + + +void +ppc_pop_iframe(struct iframe_stack *stack) +{ + ASSERT(stack->index > 0); + stack->index--; +} + + +/** Returns the current iframe structure of the running thread. + * This function must only be called in a context where it's actually + * sure that such iframe exists; ie. from syscalls, but usually not + * from standard kernel threads. + */ +static struct iframe * +ppc_get_current_iframe(void) +{ + struct thread *thread = thread_get_current_thread(); + + ASSERT(thread->arch_info.iframes.index >= 0); + return thread->arch_info.iframes.frames[thread->arch_info.iframes.index - 1]; +} + + +// #pragma mark - + + status_t arch_thread_init(struct kernel_args *args) { @@ -61,23 +100,6 @@ arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void ( } -// ToDo: we are single proc for now -static struct thread *current_thread = NULL; - -struct thread * -arch_thread_get_current_thread(void) -{ - return current_thread; -} - - -void -arch_thread_set_current_thread(struct thread *t) -{ - current_thread = t; -} - - void arch_thread_init_tls(struct thread *thread) { diff --git a/src/system/kernel/arch/ppc/arch_vm.cpp b/src/system/kernel/arch/ppc/arch_vm.cpp index e7664a45a7..14f48cc7ac 100644 --- a/src/system/kernel/arch/ppc/arch_vm.cpp +++ b/src/system/kernel/arch/ppc/arch_vm.cpp @@ -6,6 +6,7 @@ * Distributed under the terms of the NewOS License. */ +#include #include #include @@ -14,6 +15,14 @@ #include +//#define TRACE_ARCH_VM +#ifdef TRACE_ARCH_VM +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + status_t arch_vm_init(kernel_args *args) { @@ -93,8 +102,34 @@ arch_vm_init_post_area(kernel_args *args) status_t arch_vm_init_end(kernel_args *args) { - // throw away anything in the kernel_args.pgtable[] that's not yet mapped - //vm_free_unused_boot_loader_range(KERNEL_BASE, 0x400000 * args->arch_args.num_pgtables); + TRACE(("arch_vm_init_end(): %lu virtual ranges to keep:\n", + args->arch_args.num_virtual_ranges_to_keep)); + + for (int i = 0; i < (int)args->arch_args.num_virtual_ranges_to_keep; i++) { + addr_range &range = args->arch_args.virtual_ranges_to_keep[i]; + + TRACE((" start: %p, size: 0x%lx\n", (void*)range.start, range.size)); + + // skip ranges outside the kernel address space + if (!IS_KERNEL_ADDRESS(range.start)) { + TRACE((" no kernel address, skipping...\n")); + continue; + } + + void *address = (void*)range.start; + area_id area = create_area("boot loader reserved area", &address, + B_EXACT_ADDRESS, range.size, B_ALREADY_WIRED, + B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + if (area < 0) { + panic("arch_vm_init_end(): Failed to create area for boot loader " + "reserved area: %p - %p\n", (void*)range.start, + (void*)(range.start + range.size)); + } + } + + // Throw away any address space mappings we've inherited from the boot + // loader and have not yet turned into an area. + vm_free_unused_boot_loader_range(0, 0xffffffff - B_PAGE_SIZE + 1); return B_OK; } diff --git a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp index 351305435b..729aef0484 100644 --- a/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp +++ b/src/system/kernel/arch/ppc/arch_vm_translation_map.cpp @@ -323,7 +323,7 @@ unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) start = ROUNDOWN(start, B_PAGE_SIZE); end = ROUNDUP(end, B_PAGE_SIZE); - dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end); +// dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end); while (start < end) { if (remove_page_table_entry(map, start))