From f8e89e479d60f73be4d003f2fc7283192e32d42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 17 Oct 2003 13:57:28 +0000 Subject: [PATCH] Adoption of Travis' PPC code. Changed to our VM structures and slightly different arch-specific CPU functions. Fixed some bugs. Not tested. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5069 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/core/arch/ppc/Jamfile | 6 +- src/kernel/core/arch/ppc/arch_asm.S | 217 +++++++- src/kernel/core/arch/ppc/arch_cpu.c | 165 +++--- src/kernel/core/arch/ppc/arch_dbg_console.c | 288 +++++++++- src/kernel/core/arch/ppc/arch_debug.c | 2 +- src/kernel/core/arch/ppc/arch_elf.c | 97 +++- src/kernel/core/arch/ppc/arch_exceptions.S | 387 +++++++++++++ src/kernel/core/arch/ppc/arch_int.c | 162 +++++- src/kernel/core/arch/ppc/arch_mmu.cpp | 6 +- src/kernel/core/arch/ppc/arch_thread.c | 48 +- src/kernel/core/arch/ppc/arch_timer.c | 26 +- src/kernel/core/arch/ppc/arch_vm.cpp | 107 ++++ .../core/arch/ppc/arch_vm_translation_map.cpp | 516 ++++++++++++++++++ 13 files changed, 1891 insertions(+), 136 deletions(-) create mode 100644 src/kernel/core/arch/ppc/arch_exceptions.S create mode 100644 src/kernel/core/arch/ppc/arch_vm.cpp create mode 100644 src/kernel/core/arch/ppc/arch_vm_translation_map.cpp diff --git a/src/kernel/core/arch/ppc/Jamfile b/src/kernel/core/arch/ppc/Jamfile index 7b2fad597a..82c7743aaa 100644 --- a/src/kernel/core/arch/ppc/Jamfile +++ b/src/kernel/core/arch/ppc/Jamfile @@ -7,16 +7,16 @@ KernelStaticLibrary libppc : <$(SOURCE_GRIST)>arch_dbg_console.c <$(SOURCE_GRIST)>arch_debug.c <$(SOURCE_GRIST)>arch_elf.c + <$(SOURCE_GRIST)>arch_exceptions.S <$(SOURCE_GRIST)>arch_faults.c <$(SOURCE_GRIST)>arch_int.c <$(SOURCE_GRIST)>arch_mmu.cpp <$(SOURCE_GRIST)>arch_smp.c <$(SOURCE_GRIST)>arch_thread.c <$(SOURCE_GRIST)>arch_timer.c - <$(SOURCE_GRIST)>arch_vm.c - <$(SOURCE_GRIST)>arch_vm_translation_map.c + <$(SOURCE_GRIST)>arch_vm.cpp + <$(SOURCE_GRIST)>arch_vm_translation_map.cpp <$(SOURCE_GRIST)>arch_asm.S -# <$(SOURCE_GRIST)>arch_interrupts.S : -fno-pic -Wno-unused ; diff --git a/src/kernel/core/arch/ppc/arch_asm.S b/src/kernel/core/arch/ppc/arch_asm.S index ddf7a06567..3715e8f9e8 100755 --- a/src/kernel/core/arch/ppc/arch_asm.S +++ b/src/kernel/core/arch/ppc/arch_asm.S @@ -1,22 +1,215 @@ /* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Copyright 2003, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ -#define FUNC(name) .align 4 ; .globl ##name ; ##name: +#define FUNCTION(x) .global x; .type x,@function; x .text -.globl reboot -reboot: -.globl arch_int_restore_interrupts -arch_int_restore_interrupts: +// ToDo: fixme +FUNCTION(reboot): + b . -.globl arch_int_enable_interrupts -arch_int_enable_interrupts: -.globl arch_int_disable_interrupts -arch_int_disable_interrupts: +/* void arch_int_enable_interrupts(void) */ +FUNCTION(arch_int_enable_interrupts): + mfmsr %r3 // load msr -.global dbg_save_registers -dbg_save_registers: +/* + li %r4, 1 + insrwi %r3, %r4, 1, 16 // set the EE bit +*/ + + li %r4, 0 + ori %r4, %r4, (1 << 15) // create a mask for EE bit of MSR + or %r3, %r3, %r4 // set the EE bit + + mtmsr %r3 // put it back into the msr + blr + +/* void arch_int_disable_interrupts(void) */ +FUNCTION(arch_int_disable_interrupts): + mfmsr %r3 // load msr + +/* + li %r4, 0 + rlwinm %r3, %r4, 15, 16, 16 // mask the EE bit +*/ + + li %r4, 0 + ori %r4, %r4, (1 << 15) // create a mask for EE bit of MSR + andc %r3, %r3, %r4 // mask the EE bit + + mtmsr %r3 // put it back into the msr + blr + +/* bool arch_int_are_interrupts_enabled(void) */ +FUNCTION(arch_int_are_interrupts_enabled): + mfmsr %r3 // load msr + extrwi %r3, %r3, 1, 16 // mask out the EE bit + blr + +// ToDo: fixme +FUNCTION(dbg_save_registers): + blr + +/* long long get_time_base(void) */ +FUNCTION(get_time_base): +1: + mftbu %r3 // get the upper time base register + mftb %r4 // get the lower time base register + mftbu %r5 // get the upper again + cmpw %r5, %r3 // see if it changed while we were reading the lower + bne- 1b // if so, repeat + blr + +/* void getibats(int bats[8]); */ +FUNCTION(getibats): + mfibatu %r0,0 + stw %r0,0(%r3) + mfibatl %r0,0 + stwu %r0,4(%r3) + mfibatu %r0,1 + stwu %r0,4(%r3) + mfibatl %r0,1 + stwu %r0,4(%r3) + mfibatu %r0,2 + stwu %r0,4(%r3) + mfibatl %r0,2 + stwu %r0,4(%r3) + mfibatu %r0,3 + stwu %r0,4(%r3) + mfibatl %r0,3 + stwu %r0,4(%r3) + blr + +// void setibats(int bats[8]); +FUNCTION(setibats): + lwz %r0,0(%r3) + mtibatu 0,%r0 + isync + lwzu %r0,4(%r3) + mtibatl 0,%r0 + isync + lwzu %r0,4(%r3) + mtibatu 1,%r0 + isync + lwzu %r0,4(%r3) + mtibatl 1,%r0 + isync + lwzu %r0,4(%r3) + mtibatu 2,%r0 + isync + lwzu %r0,4(%r3) + mtibatl 2,%r0 + isync + lwzu %r0,4(%r3) + mtibatu 3,%r0 + isync + lwzu %r0,4(%r3) + mtibatl 3,%r0 + isync + + blr + +// void getdbats(int bats[8]); +FUNCTION(getdbats): + mfdbatu %r0,0 + stw %r0,0(%r3) + mfdbatl %r0,0 + stwu %r0,4(%r3) + mfdbatu %r0,1 + stwu %r0,4(%r3) + mfdbatl %r0,1 + stwu %r0,4(%r3) + mfdbatu %r0,2 + stwu %r0,4(%r3) + mfdbatl %r0,2 + stwu %r0,4(%r3) + mfdbatu %r0,3 + stwu %r0,4(%r3) + mfdbatl %r0,3 + stwu %r0,4(%r3) + blr + +// void setdbats(int bats[8]); +FUNCTION(setdbats): + lwz %r0,0(%r3) + mtdbatu 0,%r0 + lwzu %r0,4(%r3) + mtdbatl 0,%r0 + lwzu %r0,4(%r3) + mtdbatu 1,%r0 + lwzu %r0,4(%r3) + mtdbatl 1,%r0 + lwzu %r0,4(%r3) + mtdbatu 2,%r0 + lwzu %r0,4(%r3) + mtdbatl 2,%r0 + lwzu %r0,4(%r3) + mtdbatu 3,%r0 + lwzu %r0,4(%r3) + mtdbatl 3,%r0 + sync + + blr + +// unsigned int gethid0(); +FUNCTION(gethid0): + mfspr %r3, 1008 + blr + +// void sethid0(unsigned int val); +FUNCTION(sethid0): + mtspr 1008, %r3 + blr + +// unsigned int getl2cr(); +FUNCTION(getl2cr): + mfspr %r3, 1017 + blr + +// void setl2cr(unsigned int val); +FUNCTION(setl2cr): + mtspr 1017, %r3 + blr + +// void ppc_context_switch(addr_t *old_sp, addr_t new_sp); +FUNCTION(ppc_context_switch): + + // regs to push on the stack: r13-r31, cr, r2, lr +#define SAVE_FRAME_SIZE (((31 - 13 + 1) + 1 + 1 + 1) * 4) + + // push the old regs we need to save on the stack + addi %sp, %sp, -SAVE_FRAME_SIZE + stmw %r13, 12(%sp) + stw %r2, 8(%sp) + mfcr %r0 + stw %r0, 4(%sp) + mflr %r0 + stw %r0, 0(%sp) + + // save the old stack pointer + stw %sp, 0(%r3) + + // restore the new stack pointer + mr %sp, %r4 + + // restore the new regs + lwz %r0, 0(%sp) + mtlr %r0 + lwz %r0, 4(%sp) + mtcr %r0 + lwz %r2, 8(%sp) + lmw %r13, 12(%sp) + addi %sp, %sp, SAVE_FRAME_SIZE + + blr + +// void arch_thread_switch_kstack_and_call(addr_t new_kstack, void (*func)(void *), void *arg) +FUNCTION(arch_thread_switch_kstack_and_call): + mr %sp, %r3 // set the new stack pointer + mtctr %r4 // move the target function into CTR + mr %r3, %r5 // move the arg to this func to the new arg + bctr diff --git a/src/kernel/core/arch/ppc/arch_cpu.c b/src/kernel/core/arch/ppc/arch_cpu.c index 44415a8b8e..c483a44195 100755 --- a/src/kernel/core/arch/ppc/arch_cpu.c +++ b/src/kernel/core/arch/ppc/arch_cpu.c @@ -1,136 +1,186 @@ /* -** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. +** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include +#include -int +int arch_cpu_preboot_init(kernel_args *ka) { return 0; } -int +int arch_cpu_init(kernel_args *ka) { - //setup_system_time(ka->arch_args.system_time_cv_factor); - return 0; } -int +int arch_cpu_init2(kernel_args *ka) { return 0; } +#define CACHELINE 32 -void -arch_cpu_invalidate_TLB_range(addr start, addr end) +void +arch_cpu_sync_icache(void *address, size_t len) { - int num_pages = end/PAGE_SIZE - start/PAGE_SIZE; - while (num_pages-- >= 0) { - //invalidate_TLB(start); + int l, off; + char *p; + + off = (unsigned int)address & (CACHELINE - 1); + len += off; + + l = len; + p = (char *)address - off; + do { + asm volatile ("dcbst 0,%0" :: "r"(p)); + p += CACHELINE; + } while((l -= CACHELINE) > 0); + asm volatile ("sync"); + p = (char *)address - off; + do { + asm volatile ("icbi 0,%0" :: "r"(p)); + p += CACHELINE; + } while((len -= CACHELINE) > 0); + asm volatile ("sync"); + asm volatile ("isync"); +} + + +void +arch_cpu_invalidate_TLB_range(addr_t start, addr_t end) +{ + asm volatile("sync"); + while(start < end) { + asm volatile("tlbie %0" :: "r" (start)); + asm volatile("eieio"); + asm volatile("sync"); start += PAGE_SIZE; } + asm volatile("tlbsync"); + asm volatile("sync"); } -void -arch_cpu_invalidate_TLB_list(addr pages[], int num_pages) +void +arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) { int i; - for (i = 0; i < num_pages; i++) { - //invalidate_TLB(pages[i]); + + asm volatile("sync"); + for(i = 0; i < num_pages; i++) { + asm volatile("tlbie %0" :: "r" (pages[i])); + asm volatile("eieio"); + asm volatile("sync"); } + asm volatile("tlbsync"); + asm volatile("sync"); } -void +void arch_cpu_global_TLB_invalidate(void) { + unsigned long i; + + asm volatile("sync"); + for(i=0; i< 0x40000; i += 0x1000) { + asm volatile("tlbie %0" :: "r" (i)); + asm volatile("eieio"); + asm volatile("sync"); + } + asm volatile("tlbsync"); + asm volatile("sync"); +} + + +// ToDo: doesn't belong here! +#include + +long long +system_time(void) +{ + bigtime_t time_base = get_time_base(); + + return (time_base * 1000000) / ((66*1000*1000) / 4); + // ToDo: remove hard coded } int -arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *faultHandler) +arch_cpu_user_memcpy(void *to, const void *from, size_t size, addr *fault_handler) { char *tmp = (char *)to; char *s = (char *)from; - *faultHandler = (addr)&&error; + *fault_handler = (addr)&&error; while (size--) *tmp++ = *s++; - *faultHandler = 0; + *fault_handler = 0; return 0; error: - *faultHandler = 0; + *fault_handler = 0; return B_BAD_ADDRESS; } int -arch_cpu_user_strcpy(char *to, const char *from, addr *faultHandler) +arch_cpu_user_strcpy(char *to, const char *from, addr *fault_handler) { - *faultHandler = (addr)&&error; + *fault_handler = (addr)&&error; while ((*to++ = *from++) != '\0') ; - *faultHandler = 0; + *fault_handler = 0; return 0; error: - *faultHandler = 0; + *fault_handler = 0; return B_BAD_ADDRESS; } int -arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr *faultHandler) +arch_cpu_user_strncpy(char *to, const char *from, size_t size, addr *fault_handler) { - *faultHandler = (addr)&&error; + *fault_handler = (addr)&&error; while(size-- && (*to++ = *from++) != '\0') ; - *faultHandler = 0; + *fault_handler = 0; return 0; error: - *faultHandler = 0; + *fault_handler = 0; return B_BAD_ADDRESS; } -/*! \brief Copies at most (\a size - 1) characters from the string in \a from to - the string in \a to, NULL-terminating the result. - \param to Pointer to the destination C-string. - \param from Pointer to the source C-string. - \param size Size in bytes of the string buffer pointed to by \a to. - - \return strlen(\a from). -*/ +/** \brief Copies at most (\a size - 1) characters from the string in \a from to + * the string in \a to, NULL-terminating the result. + * + * \param to Pointer to the destination C-string. + * \param from Pointer to the source C-string. + * \param size Size in bytes of the string buffer pointed to by \a to. + * + * \return strlen(\a from). + */ + int arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr *faultHandler) { @@ -158,21 +208,22 @@ error: return B_BAD_ADDRESS; } + int -arch_cpu_user_memset(void *s, char c, size_t count, addr *faultHandler) +arch_cpu_user_memset(void *s, char c, size_t count, addr *fault_handler) { char *xs = (char *)s; - *faultHandler = (addr)&&error; + *fault_handler = (addr)&&error; while (count--) *xs++ = c; - *faultHandler = 0; + *fault_handler = 0; return 0; error: - *faultHandler = 0; + *fault_handler = 0; return B_BAD_ADDRESS; } @@ -180,14 +231,6 @@ error: void arch_cpu_idle(void) { - switch (smp_get_num_cpus()) { - case 0: - panic("You need at least 1 CPU to run OpenBeOS\n"); - case 1: - //hlt(); - break; - default: - break; - } } + diff --git a/src/kernel/core/arch/ppc/arch_dbg_console.c b/src/kernel/core/arch/ppc/arch_dbg_console.c index ae64fd0ed8..b51fbc23d4 100755 --- a/src/kernel/core/arch/ppc/arch_dbg_console.c +++ b/src/kernel/core/arch/ppc/arch_dbg_console.c @@ -1,44 +1,286 @@ -/* +/* ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ #include -#include - +#include +#include #include +#include -int + +#define FRAMEBUFFER_DBG_CONSOLE 1 + +#if FRAMEBUFFER_DBG_CONSOLE +unsigned char FONT[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */ +0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */ +0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */ +0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */ +0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */ +0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */ +0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */ +0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */ +0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */ +0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */ +0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */ +0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */ +0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */ +0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */ +0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /* '4' */ +0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */ +0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */ +0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */ +0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */ +0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */ +0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */ +0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */ +0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */ +0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */ +0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */ +0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */ +0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */ +0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */ +0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */ +0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */ +0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */ +0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */ +0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */ +0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */ +0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */ +0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */ +0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */ +0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */ +0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */ +0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */ +0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */ +0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */ +0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */ +0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */ +0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */ +0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */ +0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */ +0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */ +0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */ +0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */ +0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */ +0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */ +0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */ +0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */ +0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */ +0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */ +0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */ +0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */ +0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */ +0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */ +0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */ +0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */ +0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */ +0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */ +0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */ +0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */ +}; + +static unsigned char *framebuffer; +static unsigned int draw_color; +static unsigned int back_color; +static int char_x,char_y; +static int screen_size_x, screen_size_y; +static int screen_depth; +static int num_cols, num_rows; + +#define CHAR_WIDTH 6 +#define CHAR_HEIGHT 12 + + +static void +draw_char(unsigned char c, int x, int y) +{ + int i,j; + unsigned char *base = &framebuffer[y*screen_size_x + x]; + unsigned char line; + + for(i=0; i> 1; + } + base += screen_size_x; + } +} + +#define SCROLL 0 + + +static void +arch_dbg_putchar(char c) +{ + if(c == '\n') { + char_x = 0; + char_y++; +#if !SCROLL + memset(framebuffer + ((char_y < num_rows) ? char_y : 0) * CHAR_HEIGHT * screen_size_x, back_color, screen_size_x*CHAR_HEIGHT); +#endif + } else { + draw_char(c, char_x * CHAR_WIDTH, char_y * CHAR_HEIGHT); + char_x++; + } + if(char_x >= num_cols) { + char_x = 0; + char_y++; + } + if(char_y >= num_rows) { +#if SCROLL + // scroll up + memcpy(framebuffer, framebuffer + screen_size_x*CHAR_HEIGHT, screen_size_x * screen_size_y - screen_size_x*CHAR_HEIGHT); + memset(framebuffer + (screen_size_y-CHAR_HEIGHT)*screen_size_x, back_color, screen_size_x*CHAR_HEIGHT); + char_y--; +#else + // wrap around + char_y = 0; +#endif + } +} +#endif + + +int arch_dbg_con_init(kernel_args *ka) { +#if FRAMEBUFFER_DBG_CONSOLE + framebuffer = (unsigned char *)ka->fb.mapping.start; + screen_size_x = ka->fb.x_size; + screen_size_y = ka->fb.y_size; + + back_color = 0x0; + draw_color = 0xff; + char_x = 0; + char_y = ka->cons_line; + screen_depth = ka->fb.bit_depth; + + num_cols = screen_size_x / CHAR_WIDTH; + num_rows = screen_size_y / CHAR_HEIGHT; + +#endif + + return B_NO_ERROR; +} + + +int +arch_dbg_con_init2(kernel_args *ka) +{ +#if 0 +#if FRAMEBUFFER_DBG_CONSOLE + region_id fb_region; + void *new_framebuffer; + + /* remap the framebuffer into kernel space and remove the BAT entry mapping it currently */ + fb_region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "framebuffer", &new_framebuffer, + REGION_ADDR_ANY_ADDRESS, ka->fb.phys_addr.size, LOCK_RW|LOCK_KERNEL, ka->fb.phys_addr.start); + if(fb_region < 0) + panic("arch_dbg_con_init2: unable to remap framebuffer into kernel space\n"); + dprintf("framebuffer now at %p, phys addr 0x%x\n", new_framebuffer, ka->fb.phys_addr.start); + + dprintf("compare %d\n", memcmp(framebuffer, new_framebuffer, ka->fb.phys_addr.size)); + +#endif +#endif + return B_NO_ERROR; +} + +char arch_dbg_con_read() +{ + for(;;); return 0; } - -char -arch_dbg_con_read() -{ - return 0; -} - - -static void -_arch_dbg_con_putch(const char c) -{ -} - - -char -arch_dbg_con_putch(const char c) +char arch_dbg_con_putch(const char c) { return c; } - -void -arch_dbg_con_puts(const char *s) +void arch_dbg_con_puts(const char *str) { + while(*str) { + arch_dbg_putchar(*str); + str++; + } +} + +ssize_t arch_dbg_con_write(const void *buf, ssize_t len) +{ + ssize_t i; + + for(i = 0; i < len; i++) + arch_dbg_putchar(((char *)buf)[i]); + + return 0; } diff --git a/src/kernel/core/arch/ppc/arch_debug.c b/src/kernel/core/arch/ppc/arch_debug.c index 1433778b47..470981ed2d 100755 --- a/src/kernel/core/arch/ppc/arch_debug.c +++ b/src/kernel/core/arch/ppc/arch_debug.c @@ -9,7 +9,7 @@ #include -// ToDo: will put stack trace and disassembly routines here +// ToDo: put stack trace and disassembly routines here void diff --git a/src/kernel/core/arch/ppc/arch_elf.c b/src/kernel/core/arch/ppc/arch_elf.c index 73e9865106..fb9d3d6c5b 100644 --- a/src/kernel/core/arch/ppc/arch_elf.c +++ b/src/kernel/core/arch/ppc/arch_elf.c @@ -1,6 +1,6 @@ /* -** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. +** Copyright 2002, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. */ @@ -9,28 +9,97 @@ #include #include -#define ELF_TRACE 0 -#if ELF_TRACE -# define TRACE(x) dprintf x -#else -# define TRACE(x) ; -#endif + +#define CHATTY 0 -int +int arch_elf_relocate_rel(struct elf_image_info *image, const char *sym_prepend, struct elf_image_info *resolve_image, struct Elf32_Rel *rel, int rel_len) { - dprintf("arch_elf_relocate_rel: not supported on PPC\n"); - return B_ERROR; + // there are no rel entries in PPC elf + return B_NO_ERROR; } -int +int arch_elf_relocate_rela(struct elf_image_info *image, const char *sym_prepend, struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len) { - dprintf("arch_elf_relocate_rela: not supported on PPC\n"); - return B_ERROR; + int i; + struct Elf32_Sym *sym; + int vlErr; + addr_t S = 0; + addr_t final_val; + +#define P ((addr_t)(image->regions[0].delta + rel[i].r_offset)) +#define A ((addr_t)rel[i].r_addend) +#define B (image->regions[0].delta) + + for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) { +#if CHATTY + dprintf("looking at rel type %d, offset 0x%x, sym 0x%x, addend 0x%x\n", + ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend); +#endif + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_PPC_ADDR32: + case R_PPC_ADDR24: + case R_PPC_ADDR16: + case R_PPC_ADDR16_LO: + case R_PPC_ADDR16_HI: + case R_PPC_ADDR16_HA: + case R_PPC_REL24: + sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info)); + + vlErr = elf_resolve_symbol(image, sym, resolve_image, sym_prepend, &S); + if (vlErr<0) + return vlErr; + break; + } + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_PPC_NONE: + continue; + + case R_PPC_ADDR32: + final_val = S + A; + break; + + case R_PPC_ADDR16: + *(Elf32_Half*)P = S; + continue; + + case R_PPC_ADDR16_LO: + *(Elf32_Half*)P = S & 0xffff; + continue; + + case R_PPC_ADDR16_HI: + *(Elf32_Half*)P = (S >> 16) & 0xffff; + continue; + + case R_PPC_ADDR16_HA: + *(Elf32_Half*)P = ((S >> 16) + ((S & 0x8000) ? 1 : 0)) & 0xFFFF; + continue; + + case R_PPC_REL24: + final_val = (*(Elf32_Word *)P & 0xff000003) | ((S + A - P) & 0x3fffffc); + break; + + case R_PPC_RELATIVE: + final_val = B + A; + break; + + default: + dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)); + return B_ERROR; + } +#if CHATTY + dprintf("going to put 0x%x at 0x%x\n", final_val, P); +#endif + *(addr_t *)P = final_val; + } + + return B_NO_ERROR; + } diff --git a/src/kernel/core/arch/ppc/arch_exceptions.S b/src/kernel/core/arch/ppc/arch_exceptions.S new file mode 100644 index 0000000000..eed4eff708 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_exceptions.S @@ -0,0 +1,387 @@ +/* +** Copyright 2003, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#define FUNCTION(x) .global x; .type x,@function; x +#define LOCAL_FUNCTION(x) .type x,@function; x + +/* +** General exception handling pseudocode: +** save %r0 into sprg0 +** save %r2 into sprg1 +** save %r1 into sprg2 +** save cr into %r2 (will mess up cr in the conditional check below) +** load saved msr into %r0 +** see if was in kernel mode +** if not, +** load kernel stack from EAR into %r1 +** restore cr from %r2 +** set up in BAT 0 (instruction and data) a identity mapping of 0x0 +** load old msr +** merge old msr mmu bits with current msr +** load new msr (should turn the mmu on) +** save lr into sprg3 +** set up and branch to the next instruction (moving the program counter into kernel space) +** remove the BAT mapping +** set up stack frame and push everything +*/ + +#define VEC_ENTRY() \ + mtsprg0 %r0 ; /* save %r0 */ \ + mtsprg1 %r2 ; /* save %r2 */ \ + mtsprg2 %r1 ; /* save the old stack */ \ + mfcr %r2 ; /* save cr */ \ +\ + mfsrr1 %r0 ; /* load saved msr */ \ + andi. %r0, %r0, (1 << 14) ; /* see if it was in kernel mode */ \ + beq- 0f ; /* yep */ \ +\ + /* load the kernel stack */ \ + mfear %r1 ; /* load the kernel stack pointer from the EAR reg */ \ +0: \ + mtcrf 0xff, %r2 ; /* restore the CR, it was messed up in the previous compare */ \ +\ + /* we are going to turn on the mmu, lets have a BAT entry in place to keep us identity mapped */ \ + li %r0, 0x2 ; /* BATU_VS */ \ + mtibatu 0, %r0 ; /* load the upper word of the instruction BAT */ \ + mtdbatu 0, %r0 ; /* load the upper word of the data BAT */ \ + li %r0, 0x10|0x2 ; /* BATL_MC | BATL_PP_RW */ \ + mtibatl 0, %r0 ; /* load the lower word of the instruction BAT */ \ + mtdbatl 0, %r0 ; /* load the lower word of the data BAT */ \ + isync ; \ + sync ; \ +\ + /* turn the mmu back on */ \ + mfsrr1 %r0 ; /* load saved msr */ \ + rlwinm %r0, %r0, 28, 30, 31 ; /* extract mmu bits */ \ + mfmsr %r2 ; /* load the current msr */ \ + rlwimi %r2, %r0, 4, 26, 27 ; /* merge the mmu bits with the current msr */ \ + mtmsr %r2 ; /* load the new msr (turning the mmu back on */ \ + isync ; \ +\ + mflr %r0 ; /* load the lr */ \ + mtsprg 3, %r0 ; /* save it */ \ + lis %r0, 1f@h ; /* load the address of a label in a few instructions */ \ + ori %r0, %r0, 1f@l ; /* we will jump to it to get the program counter into the kernel region */ \ + mtlr %r0 ; /* get ready to jump to this label */ \ + blr ; /* branch to the next instruction (with the mmu on) */ \ +1: \ + /* turn the BAT back off */ \ + li %r2, 0 ; \ + mtibatu 0, %r2 ; \ + mtdbatu 0, %r2 ; \ + mtibatl 0, %r2 ; \ + mtdbatl 0, %r2 ; \ + isync ; \ + sync ; \ +\ + bl __save_regs ; /* dump an iframe on the stack */ + +.global __irqvec_start +__irqvec_start: + .long 0 + +/* called by the tail end of the VEC_ENTRY macro +** register expectations: +** %r1 - stack +** sprg0 - old %r0 +** sprg1 - old %r2 +** sprg2 - old stack (%r1) +** sprg3 - old lr +** all other regs should have been unmodified by the exception handler, +** and ready to be saved +*/ +FUNCTION(__save_regs): + mfsprg %r0, 0 + stwu %r0, -4(%r1) /* push %r0 */ + mfsprg %r0, 2 + stwu %r0, -4(%r1) /* push old %r1 (stack) */ + mfsprg %r0, 1 + stwu %r0, -4(%r1) /* push %r2 */ + stwu %r3, -4(%r1) /* push %r3-%r31 */ + stwu %r4, -4(%r1) /* push %r3-%r31 */ + stwu %r5, -4(%r1) /* push %r3-%r31 */ + stwu %r6, -4(%r1) /* push %r3-%r31 */ + stwu %r7, -4(%r1) /* push %r3-%r31 */ + stwu %r8, -4(%r1) /* push %r3-%r31 */ + stwu %r9, -4(%r1) /* push %r3-%r31 */ + stwu %r10, -4(%r1) /* push %r3-%r31 */ + stwu %r11, -4(%r1) /* push %r3-%r31 */ + stwu %r12, -4(%r1) /* push %r3-%r31 */ + + /* strictly speaking, we dont need to save %r13-%r31, but I will for now */ + stwu %r13, -4(%r1) /* push %r3-%r31 */ + stwu %r14, -4(%r1) /* push %r3-%r31 */ + stwu %r15, -4(%r1) /* push %r3-%r31 */ + stwu %r16, -4(%r1) /* push %r3-%r31 */ + stwu %r17, -4(%r1) /* push %r3-%r31 */ + stwu %r18, -4(%r1) /* push %r3-%r31 */ + stwu %r19, -4(%r1) /* push %r3-%r31 */ + stwu %r20, -4(%r1) /* push %r3-%r31 */ + stwu %r21, -4(%r1) /* push %r3-%r31 */ + stwu %r22, -4(%r1) /* push %r3-%r31 */ + stwu %r23, -4(%r1) /* push %r3-%r31 */ + stwu %r24, -4(%r1) /* push %r3-%r31 */ + stwu %r25, -4(%r1) /* push %r3-%r31 */ + stwu %r26, -4(%r1) /* push %r3-%r31 */ + stwu %r27, -4(%r1) /* push %r3-%r31 */ + stwu %r28, -4(%r1) /* push %r3-%r31 */ + stwu %r29, -4(%r1) /* push %r3-%r31 */ + stwu %r30, -4(%r1) /* push %r3-%r31 */ + stwu %r31, -4(%r1) /* push %r3-%r31 */ + + /* save some of the other regs */ + mfctr %r0 + stwu %r0, -4(%r1) /* push CTR */ + mfxer %r0 + stwu %r0, -4(%r1) /* push XER */ + mfcr %r0 + stwu %r0, -4(%r1) /* push CR */ + mfsprg %r0, 3 + stwu %r0, -4(%r1) /* push LR */ + mfspr %r0, %dsisr + stwu %r0, -4(%r1) /* push DSISR */ + mfspr %r0, %dar + stwu %r0, -4(%r1) /* push DAR */ + mfspr %r0, %srr1 + stwu %r0, -4(%r1) /* push SRR1 */ + mfspr %r0, %srr0 + stwu %r0, -4(%r1) /* push SRR0 */ + + addi %r1, %r1, -8 /* adjust the stack pointer to leave some padding on it for C */ + + /* get outta here */ + blr + +/* not enough space for __restore_regs_and_rfi here, see below */ + +.skip 0x100 - (. - __irqvec_start) +FUNCTION(system_reset_exception): + VEC_ENTRY(); + li %r3, 0x100 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x200 - (. - __irqvec_start) +FUNCTION(machine_check_exception): + VEC_ENTRY(); + li %r3, 0x200 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x300 - (. - __irqvec_start) +FUNCTION(DSI_exception): + VEC_ENTRY(); + li %r3, 0x300 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x400 - (. - __irqvec_start) +FUNCTION(ISI_exception): + VEC_ENTRY(); + li %r3, 0x400 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x500 - (. - __irqvec_start) +FUNCTION(external_interrupt_exception): + VEC_ENTRY(); + li %r3, 0x500 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x600 - (. - __irqvec_start) +FUNCTION(alignment_exception): + VEC_ENTRY(); + li %r3, 0x600 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x700 - (. - __irqvec_start) +FUNCTION(program_exception): + VEC_ENTRY(); + li %r3, 0x700 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x800 - (. - __irqvec_start) +FUNCTION(FP_unavailable_exception): + VEC_ENTRY(); + li %r3, 0x800 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x900 - (. - __irqvec_start) +FUNCTION(decrementer_exception): + VEC_ENTRY(); + li %r3, 0x900 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +/* called at the tail end of each of the exceptions +** placed here because of the space between these two +** exception handlers. +*/ +FUNCTION(__restore_regs_and_rfi): + addi %r1, %r1, 8 /* adjust the stack pointer to get it back to the base of the iframe */ + + lwz %r0, 0(%r1) /* SRR0 */ + mtspr %srr0, %r0 + lwzu %r0, 4(%r1) /* SRR1 */ + mtspr %srr1, %r0 + lwzu %r0, 4(%r1) /* DAR */ + mtspr %dar, %r0 + lwzu %r0, 4(%r1) /* DSISR */ + mtspr %dsisr, %r0 + lwzu %r0, 4(%r1) /* LR */ + mtlr %r0 + lwzu %r0, 4(%r1) /* CR */ + mtcr %r0 + lwzu %r0, 4(%r1) /* XER */ + mtxer %r0 + lwzu %r0, 4(%r1) /* CTR */ + mtctr %r0 + + /* strictly speaking, we dont really need to have saved these regs */ + lwzu %r31, 4(%r1) + lwzu %r30, 4(%r1) + lwzu %r29, 4(%r1) + lwzu %r28, 4(%r1) + lwzu %r27, 4(%r1) + lwzu %r26, 4(%r1) + lwzu %r25, 4(%r1) + lwzu %r24, 4(%r1) + lwzu %r23, 4(%r1) + lwzu %r22, 4(%r1) + lwzu %r21, 4(%r1) + lwzu %r20, 4(%r1) + lwzu %r19, 4(%r1) + lwzu %r18, 4(%r1) + lwzu %r17, 4(%r1) + lwzu %r16, 4(%r1) + lwzu %r15, 4(%r1) + lwzu %r14, 4(%r1) + lwzu %r13, 4(%r1) + + lwzu %r12, 4(%r1) + lwzu %r11, 4(%r1) + lwzu %r10, 4(%r1) + lwzu %r9, 4(%r1) + lwzu %r8, 4(%r1) + lwzu %r7, 4(%r1) + lwzu %r6, 4(%r1) + lwzu %r5, 4(%r1) + lwzu %r4, 4(%r1) + lwzu %r3, 4(%r1) + lwzu %r2, 4(%r1) + lwz %r0, 8(%r1) + lwz %r1, 4(%r1) + + /* get out of here */ + rfi + +.skip 0xc00 - (. - __irqvec_start) +FUNCTION(system_call_exception): + VEC_ENTRY(); + li %r3, 0xc00 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0xd00 - (. - __irqvec_start) +FUNCTION(trace_exception): + VEC_ENTRY(); + li %r3, 0xd00 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0xe00 - (. - __irqvec_start) +FUNCTION(FP_assist_exception): + VEC_ENTRY(); + li %r3, 0xe00 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0xf00 - (. - __irqvec_start) +FUNCTION(perf_monitor_exception): + /* XXX deal with this, normal VEC_ENTRY code is too big to fit here */ + rfi + +.skip 0xf20 - (. - __irqvec_start) +FUNCTION(altivec_unavailable_exception): + VEC_ENTRY(); + li %r3, 0xf20 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1000 - (. - __irqvec_start) +FUNCTION(ITLB_miss_exception): + VEC_ENTRY(); + li %r3, 0x1000 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1100 - (. - __irqvec_start) +FUNCTION(DTLB_miss_on_load_exception): + VEC_ENTRY(); + li %r3, 0x1100 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1200 - (. - __irqvec_start) +FUNCTION(DTLB_miss_on_store_exception): + VEC_ENTRY(); + li %r3, 0x1200 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1300 - (. - __irqvec_start) +FUNCTION(instruction_address_breakpoint_exception): + VEC_ENTRY(); + li %r3, 0x1300 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1400 - (. - __irqvec_start) +FUNCTION(system_management_exception): + VEC_ENTRY(); + li %r3, 0x1400 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1600 - (. - __irqvec_start) +FUNCTION(altivec_assist_exception): + VEC_ENTRY(); + li %r3, 0x1600 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.skip 0x1700 - (. - __irqvec_start) +FUNCTION(thermal_management_exception): + VEC_ENTRY(); + li %r3, 0x1700 + addi %r4, %r1, 8 + bl ppc_exception_entry + bl __restore_regs_and_rfi + +.global __irqvec_end +__irqvec_end: + diff --git a/src/kernel/core/arch/ppc/arch_int.c b/src/kernel/core/arch/ppc/arch_int.c index bc74d33c6a..4920538817 100755 --- a/src/kernel/core/arch/ppc/arch_int.c +++ b/src/kernel/core/arch/ppc/arch_int.c @@ -4,41 +4,179 @@ */ -#include +#include + #include +#include +#include +#include +#include + +#include + +// defined in arch_exceptions.S +extern int __irqvec_start; +extern int __irqvec_end; -bool -arch_int_is_interrupts_enabled(void) -{ - return true; -} - - -void +void arch_int_enable_io_interrupt(int irq) { return; } -void +void arch_int_disable_io_interrupt(int irq) { return; } -int +static void +print_iframe(struct iframe *frame) +{ + dprintf("iframe at %p:\n", frame); + dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r0, frame->r1, frame->r2, frame->r3); + dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r4, frame->r5, frame->r6, frame->r7); + dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r8, frame->r9, frame->r10, frame->r11); + dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r12, frame->r13, frame->r14, frame->r15); + dprintf("r16-r19: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r16, frame->r17, frame->r18, frame->r19); + dprintf("r20-r23: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r20, frame->r21, frame->r22, frame->r23); + dprintf("r24-r27: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r24, frame->r25, frame->r26, frame->r27); + dprintf("r28-r31: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r28, frame->r29, frame->r30, frame->r31); + dprintf(" ctr 0x%08lx xer 0x%08lx\n", frame->ctr, frame->xer); + dprintf(" cr 0x%08lx lr 0x%08lx\n", frame->cr, frame->lr); + dprintf(" dsisr 0x%08lx dar 0x%08lx\n", frame->dsisr, frame->dar); + dprintf(" srr1 0x%08lx srr0 0x%08lx\n", frame->srr1, frame->srr0); +} + + +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); + + switch (vector) { + case 0x100: // system reset + panic("system reset exception\n"); + break; + case 0x200: // machine check + panic("machine check exception\n"); + break; + case 0x300: // DSI + case 0x400: // ISI + { + addr_t newip; + + ret = vm_page_fault(iframe->dar, iframe->srr0, + iframe->dsisr & (1 << 25), // store or load + iframe->srr1 & (1 << 14), // was the system in user or supervisor + &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 + iframe->srr0 = newip; + } + break; + } + case 0x500: // external interrupt + panic("external interrrupt exception: unimplemented\n"); + break; + case 0x600: // alignment exception + panic("alignment exception: unimplemented\n"); + break; + case 0x700: // program exception + panic("program exception: unimplemented\n"); + break; + case 0x800: // FP unavailable exception + panic("FP unavailable exception: unimplemented\n"); + break; + case 0x900: // decrementer exception + ret = timer_interrupt(); + break; + case 0xc00: // system call + panic("system call exception: unimplemented\n"); + break; + case 0xd00: // trace exception + panic("trace exception: unimplemented\n"); + break; + case 0xe00: // FP assist exception + panic("FP assist exception: unimplemented\n"); + break; + case 0xf00: // performance monitor exception + panic("performance monitor exception: unimplemented\n"); + break; + case 0xf20: // alitivec unavailable exception + panic("alitivec unavailable exception: unimplemented\n"); + break; + case 0x1000: + case 0x1100: + case 0x1200: + panic("TLB miss exception: unimplemented\n"); + break; + case 0x1300: // instruction address exception + panic("instruction address exception: unimplemented\n"); + break; + case 0x1400: // system management exception + panic("system management exception: unimplemented\n"); + break; + case 0x1600: // altivec assist exception + panic("altivec assist exception: unimplemented\n"); + break; + case 0x1700: // thermal management exception + panic("thermal management exception: unimplemented\n"); + break; + default: + dprintf("unhandled exception type 0x%x\n", vector); + print_iframe(iframe); + panic("unhandled exception type\n"); + } + + if (ret == B_INVOKE_SCHEDULER) { + int state = disable_interrupts(); + GRAB_THREAD_LOCK(); + scheduler_reschedule(); + RELEASE_THREAD_LOCK(); + restore_interrupts(state); + } +} + + +int arch_int_init(kernel_args *ka) { return 0; } -int +int arch_int_init2(kernel_args *ka) { + region_id exception_region; + void *ex_handlers; + + // create a region to map the irq vector code into (physical addres 0x0) + ex_handlers = (void *)ka->arch_args.exception_handlers.start; + exception_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "exception_handlers", + &ex_handlers, REGION_ADDR_EXACT_ADDRESS, + ka->arch_args.exception_handlers.size, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + if (exception_region < 0) + panic("arch_int_init2: could not create exception handler region\n"); + + dprintf("exception handlers at %p\n", ex_handlers); + + // copy the handlers into this area + memcpy(ex_handlers, &__irqvec_start, ka->arch_args.exception_handlers.size); + arch_cpu_sync_icache(0, 0x3000); + + // make sure the IP bit isn't set (putting the exceptions at 0x0) + set_msr(get_msr() & ~MSR_IP); + return 0; } diff --git a/src/kernel/core/arch/ppc/arch_mmu.cpp b/src/kernel/core/arch/ppc/arch_mmu.cpp index 9ebac3704b..f89e908837 100644 --- a/src/kernel/core/arch/ppc/arch_mmu.cpp +++ b/src/kernel/core/arch/ppc/arch_mmu.cpp @@ -30,17 +30,17 @@ page_table_entry::SecondaryHash(uint32 primaryHash) void -ppc_get_page_table(void **_pageTable, size_t *_size) +ppc_get_page_table(page_table_entry_group **_pageTable, size_t *_size) { uint32 sdr1 = get_sdr1(); - *_pageTable = (void *)(sdr1 & 0xffff0000); + *_pageTable = (page_table_entry_group *)(sdr1 & 0xffff0000); *_size = ((sdr1 & 0x1ff) + 1) << 16; } void -ppc_set_page_table(void *pageTable, size_t size) +ppc_set_page_table(page_table_entry_group *pageTable, size_t size) { set_sdr1(((uint32)pageTable & 0xffff0000) | (((size >> 16) - 1 ) & 0x1ff)); } diff --git a/src/kernel/core/arch/ppc/arch_thread.c b/src/kernel/core/arch/ppc/arch_thread.c index 717bbb01c5..08398fa9f5 100755 --- a/src/kernel/core/arch/ppc/arch_thread.c +++ b/src/kernel/core/arch/ppc/arch_thread.c @@ -8,6 +8,8 @@ #include #include +#include + int arch_team_init_team_struct(struct team *team, bool kernel) @@ -19,6 +21,9 @@ arch_team_init_team_struct(struct team *team, bool kernel) int arch_thread_init_thread_struct(struct thread *t) { + // set up an initial state (stack & fpu) + memset(&t->arch_info, 0, sizeof(t->arch_info)); + return 0; } @@ -26,20 +31,38 @@ arch_thread_init_thread_struct(struct thread *t) int arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) { + addr_t *kstack = (addr_t *)t->kernel_stack_base; + size_t kstack_size = KSTACK_SIZE; + addr_t *kstack_top = kstack + kstack_size / sizeof(addr_t) - 2 * 4; + + // r13-r31, cr, r2 + kstack_top -= (31 - 13 + 1) + 1 + 1; + + // set the saved lr address to be the start_func + kstack_top--; + *kstack_top = (addr_t)start_func; + + // save this stack position + t->arch_info.sp = (void *)kstack_top; + return 0; } +// ToDo: we are single proc for now +static struct thread *current_thread = NULL; + struct thread * arch_thread_get_current_thread(void) { - return NULL; + return current_thread; } -void -arch_thread_set_current_thread(struct thread *thread) +void +arch_thread_set_current_thread(struct thread *t) { + current_thread = t; } @@ -58,18 +81,37 @@ arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*fun void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) { + // set the new kernel stack in the EAR register. + // this is used in the exception handler code to decide what kernel stack to + // switch to if the exception had happened when the processor was in user mode + asm("mtear %0" :: "g"(t_to->kernel_stack_base + KSTACK_SIZE - 8)); + + // switch the asids if we need to + if (t_to->team->_aspace_id >= 0) { + // the target thread has is user space + if (t_from->team->_aspace_id != t_to->team->_aspace_id) { + // switching to a new address space + ppc_translation_map_change_asid(&t_to->team->aspace->translation_map); + } + } + + ppc_context_switch(&t_from->arch_info.sp, t_to->arch_info.sp); } void arch_thread_dump_info(void *info) { + struct arch_thread *at = (struct arch_thread *)info; + + dprintf("\tsp: %p\n", at->sp); } void arch_thread_enter_uspace(struct thread *thread, addr entry, void *arg1, void *arg2) { + panic("arch_thread_enter_uspace(): not yet implemented\n"); } diff --git a/src/kernel/core/arch/ppc/arch_timer.c b/src/kernel/core/arch/ppc/arch_timer.c index 2a4a44d14e..ce18fc4aad 100755 --- a/src/kernel/core/arch/ppc/arch_timer.c +++ b/src/kernel/core/arch/ppc/arch_timer.c @@ -1,4 +1,4 @@ -/* +/* ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ @@ -6,23 +6,41 @@ #include #include +#include + +#include #include -void +static bigtime_t sTickRate; + + +void arch_timer_set_hardware_timer(bigtime_t timeout) { + bigtime_t new_val_64; + + if(timeout < 1000) + timeout = 1000; + + new_val_64 = (timeout * sTickRate) / 1000000; + + asm("mtdec %0" :: "r"((uint32)new_val_64)); } -void +void arch_timer_clear_hardware_timer() { + asm("mtdec %0" :: "r"(0x7fffffff)); } -int +int arch_init_timer(kernel_args *ka) { + sTickRate = (66*1000*1000) / 4; // ToDo: fix + return 0; } + diff --git a/src/kernel/core/arch/ppc/arch_vm.cpp b/src/kernel/core/arch/ppc/arch_vm.cpp new file mode 100644 index 0000000000..cc1a93262b --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_vm.cpp @@ -0,0 +1,107 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + + +#include +#include + +#include +#include + + +int +arch_vm_init(kernel_args *ka) +{ + return 0; +} + + +int +arch_vm_init2(kernel_args *ka) +{ +// int bats[8]; +// int i; + +#if 0 + // print out any bat mappings + getibats(bats); + dprintf("ibats:\n"); + for(i = 0; i < 4; i++) + dprintf("0x%x 0x%x\n", bats[i*2], bats[i*2+1]); + getdbats(bats); + dprintf("dbats:\n"); + for(i = 0; i < 4; i++) + dprintf("0x%x 0x%x\n", bats[i*2], bats[i*2+1]); +#endif + +#if 1 + // turn off the first 2 BAT mappings (3 & 4 are used by the lower level code) + block_address_translation bat; + bat.Clear(); + + set_ibat0(&bat); + set_ibat1(&bat); + set_dbat0(&bat); + set_dbat1(&bat); +/* getibats(bats); + memset(bats, 0, 2 * 2); + setibats(bats); + getdbats(bats); + memset(bats, 0, 2 * 2); + setdbats(bats); +*/ +#endif +#if 0 + // just clear the first BAT mapping (0 - 256MB) + dprintf("msr 0x%x\n", getmsr()); + { + unsigned int reg; + asm("mr %0,1" : "=r"(reg)); + dprintf("sp 0x%x\n", reg); + } + dprintf("ka %p\n", ka); + + getibats(bats); + dprintf("ibats:\n"); + for(i = 0; i < 4; i++) + dprintf("0x%x 0x%x\n", bats[i*2], bats[i*2+1]); + bats[0] = bats[1] = 0; + setibats(bats); + getdbats(bats); + dprintf("dbats:\n"); + for(i = 0; i < 4; i++) + dprintf("0x%x 0x%x\n", bats[i*2], bats[i*2+1]); + bats[0] = bats[1] = 0; + setdbats(bats); +#endif + return 0; +} + + +int +arch_vm_init_existing_maps(kernel_args *ka) +{ + void *temp = (void *)ka->fb.mapping.start; + + // create a region for the framebuffer + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "framebuffer", &temp, REGION_ADDR_EXACT_ADDRESS, + ka->fb.mapping.size, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + + return B_NO_ERROR; +} + + +int +arch_vm_init_endvm(kernel_args *ka) +{ + return B_NO_ERROR; +} + + +void +arch_vm_aspace_swap(vm_address_space *aspace) +{ +} + diff --git a/src/kernel/core/arch/ppc/arch_vm_translation_map.cpp b/src/kernel/core/arch/ppc/arch_vm_translation_map.cpp new file mode 100644 index 0000000000..80b73491c5 --- /dev/null +++ b/src/kernel/core/arch/ppc/arch_vm_translation_map.cpp @@ -0,0 +1,516 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct page_table_entry_group *sPageTable; +static size_t sPageTableSize; +static uint32 sPageTableHashMask; +static area_id sPageTableRegion; + + +// 512 MB of iospace +#define IOSPACE_SIZE (512*1024*1024) +// put it 512 MB into kernel space +#define IOSPACE_BASE (KERNEL_BASE + IOSPACE_SIZE) + +#define MAX_ASIDS (PAGE_SIZE * 8) +static uint32 asid_bitmap[MAX_ASIDS / (sizeof(uint32) * 8)]; +spinlock asid_bitmap_lock; +#define ASID_SHIFT 4 +#define VADDR_TO_ASID(map, vaddr) \ + (((map)->arch_data->asid_base << ASID_SHIFT) + ((vaddr) / 0x10000000)) + +// vm_translation object stuff +typedef struct vm_translation_map_arch_info_struct { + int asid_base; // shift left by ASID_SHIFT to get the base asid to use +} vm_translation_map_arch_info; + + +static int +lock_tmap(vm_translation_map *map) +{ + recursive_lock_lock(&map->lock); + return 0; +} + + +static int +unlock_tmap(vm_translation_map *map) +{ + recursive_lock_unlock(&map->lock); + return 0; +} + + +static void +destroy_tmap(vm_translation_map *map) +{ + if (map->map_count > 0) { + panic("vm_translation_map.destroy_tmap: map %p has positive map count %d\n", map, map->map_count); + } + + // mark the asid not in use + atomic_and((vint32 *)&asid_bitmap[map->arch_data->asid_base / 32], + ~(1 << (map->arch_data->asid_base % 32))); + + free(map->arch_data); + recursive_lock_destroy(&map->lock); +} + + +static void +fill_page_table_entry(page_table_entry *entry, uint32 virtualSegmentID, + addr_t virtualAddress, addr_t physicalAddress, uint8 protection, + bool secondaryHash) +{ + // lower 32 bit - set at once + entry->physical_page_number = physicalAddress / B_PAGE_SIZE; + entry->_reserved0 = 0; + entry->referenced = false; + entry->changed = false; + entry->write_through = false; + entry->caching_inhibited = false; + entry->memory_coherent = false; + entry->guarded = false; + entry->_reserved1 = 0; + entry->page_protection = protection & 0x3; + eieio(); + // we need to make sure that the lower 32 bit were + // already written when the entry becomes valid + + // upper 32 bit + entry->virtual_segment_id = virtualSegmentID; + entry->secondary_hash = secondaryHash; + entry->abbr_page_index = (virtualAddress >> 22) & 0x3f; + entry->valid = true; + + // ToDo: this is probably a bit too much sledge hammer + arch_cpu_global_TLB_invalidate(); +} + + +static int +map_tmap(vm_translation_map *map, addr_t virtualAddress, addr_t physicalAddress, unsigned int attributes) +{ + // lookup the vsid based off the va + uint32 virtualSegmentID = VADDR_TO_ASID(map, virtualAddress); + + if (attributes & LOCK_KERNEL) + attributes = 0; // all kernel mappings are R/W to supervisor code + else + attributes = (attributes & LOCK_RW) ? PTE_READ_WRITE : PTE_READ_ONLY; + + //dprintf("vm_translation_map.map_tmap: vsid %d, pa 0x%lx, va 0x%lx\n", vsid, pa, va); + + // Search for a free page table slot using the primary hash value + + uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress); + page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask]; + + for (int i = 0; i < 8; i++) { + page_table_entry *entry = &group->entry[i]; + + if (entry->valid) + continue; + + fill_page_table_entry(entry, virtualSegmentID, virtualAddress, physicalAddress, + attributes, false); + map->map_count++; + return B_OK; + } + + // Didn't found one, try the secondary hash value + + hash = page_table_entry::SecondaryHash(hash); + group = &sPageTable[hash & sPageTableHashMask]; + + for (int i = 0; i < 8; i++) { + page_table_entry *entry = &group->entry[i]; + + if (entry->valid) + continue; + + fill_page_table_entry(entry, virtualSegmentID, virtualAddress, physicalAddress, + attributes, false); + map->map_count++; + return B_OK; + } + + panic("vm_translation_map.map_tmap: hash table full\n"); + return B_ERROR; +} + + +static page_table_entry * +lookup_pagetable_entry(vm_translation_map *map, addr_t virtualAddress) +{ + // lookup the vsid based off the va + uint32 virtualSegmentID = VADDR_TO_ASID(map, virtualAddress); + +// dprintf("vm_translation_map.lookup_pagetable_entry: vsid %d, va 0x%lx\n", vsid, va); + + + // Search for the page table entry using the primary hash value + + uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress); + page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask]; + + for (int i = 0; i < 8; i++) { + page_table_entry *entry = &group->entry[i]; + + if (entry->virtual_segment_id == virtualSegmentID + && entry->secondary_hash == false + && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f)) + return entry; + } + + // Didn't found it, try the secondary hash value + + hash = page_table_entry::SecondaryHash(hash); + group = &sPageTable[hash & sPageTableHashMask]; + + for (int i = 0; i < 8; i++) { + page_table_entry *entry = &group->entry[i]; + + if (entry->virtual_segment_id == virtualSegmentID + && entry->secondary_hash == true + && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f)) + return entry; + } + + return NULL; +} + + +static int +unmap_tmap(vm_translation_map *map, addr_t start, addr_t end) +{ + page_table_entry *entry; + + start = ROUNDOWN(start, PAGE_SIZE); + end = ROUNDUP(end, PAGE_SIZE); + + dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end); + + while (start < end) { + entry = lookup_pagetable_entry(map, start); + if (entry) { + // unmap this page + entry->valid = 0; + arch_cpu_global_TLB_invalidate(); + map->map_count--; + } + + start += B_PAGE_SIZE; + } + + return 0; +} + + +static int +query_tmap(vm_translation_map *map, addr_t va, addr_t *out_physical, unsigned int *out_flags) +{ + page_table_entry *entry; + + // default the flags to not present + *out_flags = 0; + *out_physical = 0; + + entry = lookup_pagetable_entry(map, va); + if (entry == NULL) + return B_NO_ERROR; + + *out_flags |= (entry->page_protection == PTE_READ_ONLY) ? LOCK_RO : LOCK_RW; + if (va >= KERNEL_BASE) + *out_flags |= LOCK_KERNEL; // XXX is this enough? + *out_flags |= entry->changed ? PAGE_MODIFIED : 0; + *out_flags |= entry->referenced ? PAGE_ACCESSED : 0; + *out_flags |= entry->valid ? PAGE_PRESENT : 0; + + *out_physical = entry->physical_page_number * B_PAGE_SIZE; + + return B_OK; +} + + +static addr_t +get_mapped_size_tmap(vm_translation_map *map) +{ + return map->map_count; +} + + +static int +protect_tmap(vm_translation_map *map, addr_t base, addr_t top, unsigned int attributes) +{ + // XXX finish + return -1; +} + + +static int +clear_flags_tmap(vm_translation_map *map, addr_t virtualAddress, unsigned int flags) +{ + page_table_entry *entry = lookup_pagetable_entry(map, virtualAddress); + if (entry == NULL) + return B_NO_ERROR; + + if (flags & PAGE_MODIFIED) + entry->changed = false; + if (flags & PAGE_ACCESSED) + entry->referenced = false; + + arch_cpu_global_TLB_invalidate(); + + return B_OK; +} + + +static void +flush_tmap(vm_translation_map *map) +{ + arch_cpu_global_TLB_invalidate(); +} + + +static int +get_physical_page_tmap(addr_t pa, addr_t *va, int flags) +{ + pa = ROUNDOWN(pa, PAGE_SIZE); + + if(pa > IOSPACE_SIZE) + panic("get_physical_page_tmap: asked for pa 0x%lx, cannot provide\n", pa); + + *va = (IOSPACE_BASE + pa); + return 0; +} + + +static int +put_physical_page_tmap(addr_t va) +{ + if (va < IOSPACE_BASE || va >= IOSPACE_BASE + IOSPACE_SIZE) + panic("put_physical_page_tmap: va 0x%lx out of iospace region\n", va); + + return 0; +} + + +static vm_translation_map_ops tmap_ops = { + destroy_tmap, + lock_tmap, + unlock_tmap, + map_tmap, + unmap_tmap, + query_tmap, + get_mapped_size_tmap, + protect_tmap, + clear_flags_tmap, + flush_tmap, + get_physical_page_tmap, + put_physical_page_tmap +}; + + +int +vm_translation_map_create(vm_translation_map *new_map, bool kernel) +{ + // initialize the new object + new_map->ops = &tmap_ops; + new_map->map_count = 0; + if (recursive_lock_init(&new_map->lock, "map lock") < B_OK) + return B_NO_MEMORY; + + new_map->arch_data = (vm_translation_map_arch_info *)malloc(sizeof(vm_translation_map_arch_info)); + if (new_map->arch_data == NULL) + return B_NO_MEMORY; + + cpu_status state = disable_interrupts(); + acquire_spinlock(&asid_bitmap_lock); + + // allocate a ASID base for this one + if (kernel) { + new_map->arch_data->asid_base = 0; // set up by the bootloader + asid_bitmap[0] |= 0x1; + } else { + int i = 0; + + while (i < MAX_ASIDS) { + if (asid_bitmap[i / 32] == 0xffffffff) { + i += 32; + continue; + } + if ((asid_bitmap[i / 32] & (1 << (i % 32))) == 0) { + // we found it + asid_bitmap[i / 32] |= 1 << (i % 32); + break; + } + i++; + } + if (i >= MAX_ASIDS) + panic("vm_translation_map_create: out of ASIDS\n"); + new_map->arch_data->asid_base = i; + } + + release_spinlock(&asid_bitmap_lock); + restore_interrupts(state); + + return 0; +} + + +int +vm_translation_map_module_init(kernel_args *args) +{ + sPageTable = (page_table_entry_group *)args->arch_args.page_table.start; + sPageTableSize = args->arch_args.page_table.size; + sPageTableHashMask = (sPageTableSize >> 6) - 1; + + return B_OK; +} + + +void +vm_translation_map_module_init_post_sem(kernel_args *ka) +{ +} + + +int +vm_translation_map_module_init2(kernel_args *ka) +{ + // create a region to cover the page table + sPageTableRegion = vm_create_anonymous_region(vm_get_kernel_aspace_id(), + "page_table", (void **)&sPageTable, REGION_ADDR_EXACT_ADDRESS, + sPageTableSize, REGION_WIRING_WIRED_ALREADY, LOCK_KERNEL | LOCK_RW); + + // ToDo: for now just map 0 - 512MB of physical memory to the iospace region + block_address_translation bat; + + bat.Clear(); + bat.SetVirtualAddress((void *)IOSPACE_BASE); + bat.page_index = IOSPACE_BASE; + bat.length = BAT_LENGTH_256MB; + bat.kernel_valid = true; + bat.SetPhysicalAddress(NULL); + bat.memory_coherent = true; + bat.protection = BAT_READ_WRITE; + + set_ibat2(&bat); + set_dbat2(&bat); + isync(); + + bat.SetVirtualAddress((void *)(IOSPACE_BASE + 256 * 1024 * 1024)); + bat.SetPhysicalAddress((void *)(256 * 1024 * 1024)); + + set_ibat3(&bat); + set_dbat3(&bat); + isync(); +/* + int ibats[8], dbats[8]; + + getibats(ibats); + getdbats(dbats); + + // use bat 2 & 3 to do this + ibats[4] = dbats[4] = IOSPACE_BASE | BATU_LEN_256M | BATU_VS; + ibats[5] = dbats[5] = 0x0 | BATL_MC | BATL_PP_RW; + ibats[6] = dbats[6] = (IOSPACE_BASE + 256*1024*1024) | BATU_LEN_256M | BATU_VS; + ibats[7] = dbats[7] = (256*1024*1024) | BATL_MC | BATL_PP_RW; + + setibats(ibats); + setdbats(dbats); +*/ + + // create a region to cover the iospace + void *temp = (void *)IOSPACE_BASE; + vm_create_null_region(vm_get_kernel_aspace_id(), "iospace", &temp, + REGION_ADDR_EXACT_ADDRESS, IOSPACE_SIZE); + + return 0; +} + + +/** Directly maps a page without having knowledge of any kernel structures. + * Used only during VM setup. + * It currently ignores the "attributes" parameter and sets all pages + * read/write. + */ + +int +vm_translation_map_quick_map(kernel_args *ka, addr_t virtualAddress, addr_t physicalAddress, uint8 attributes, addr_t (*get_free_page)(kernel_args *)) +{ + uint32 virtualSegmentID = get_sr((void *)virtualAddress) & 0xffffff; + + uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, (uint32)virtualAddress); + page_table_entry_group *group = &sPageTable[hash & sPageTableHashMask]; + + for (int32 i = 0; i < 8; i++) { + // 8 entries in a group + if (group->entry[i].valid) + continue; + + fill_page_table_entry(&group->entry[i], virtualSegmentID, virtualAddress, physicalAddress, PTE_READ_WRITE, false); + return B_OK; + } + + hash = page_table_entry::SecondaryHash(hash); + group = &sPageTable[hash & sPageTableHashMask]; + + for (int32 i = 0; i < 8; i++) { + if (group->entry[i].valid) + continue; + + fill_page_table_entry(&group->entry[i], virtualSegmentID, virtualAddress, physicalAddress, PTE_READ_WRITE, true); + return B_OK; + } + + return B_ERROR; +} + + +// XXX currently assumes this translation map is active + +int +vm_translation_map_quick_query(addr_t va, addr_t *out_physical) +{ + //PANIC_UNIMPLEMENTED(); + panic("vm_translation_map_quick_query(): not yet implemented\n"); + return 0; +} + + +void +ppc_translation_map_change_asid(vm_translation_map *map) +{ +// this code depends on the kernel being at 0x80000000, fix if we change that +#if KERNEL_BASE != 0x80000000 +#error fix me +#endif + int asid_base = map->arch_data->asid_base; + + asm("mtsr 0,%0" :: "g"(asid_base)); + asm("mtsr 1,%0" :: "g"(asid_base+1)); + asm("mtsr 2,%0" :: "g"(asid_base+2)); + asm("mtsr 3,%0" :: "g"(asid_base+3)); + asm("mtsr 4,%0" :: "g"(asid_base+4)); + asm("mtsr 5,%0" :: "g"(asid_base+5)); + asm("mtsr 6,%0" :: "g"(asid_base+6)); + asm("mtsr 7,%0" :: "g"(asid_base+7)); +} +