diff options
Diffstat (limited to 'sys/arch/mvme88k/m88k/locore.S')
-rw-r--r-- | sys/arch/mvme88k/m88k/locore.S | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/sys/arch/mvme88k/m88k/locore.S b/sys/arch/mvme88k/m88k/locore.S new file mode 100644 index 00000000000..e0c2ad9c862 --- /dev/null +++ b/sys/arch/mvme88k/m88k/locore.S @@ -0,0 +1,496 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * Copyright (c) 1991 OMRON Corporation + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* $RCSfile: locore.S,v $ -- asm boot routines + * + ********************************************************************** + *****************************************************************RCS**/ + +#ifndef ASSEMBLER /* predefined by ascpp, at least */ +#define ASSEMBLER +#endif + +#include "machine/locore.h" +#include "machine/m88100.h" +#include "machine/trap.h" +#include "machine/asm.h" +#include "machine/board.h" /* lots of stuff (OBIO_PIO*, SYSV_BASE, etc)*/ +#include "machine/vmparam.h" /* INTSTACK_SIZE */ +#include "assym.s" + +/***********************************************************************/ + +/* + * Arrange for the include file version number to appear directly in + * the namelist. + */ +global _INCLUDE_VERSION +def _INCLUDE_VERSION, INCLUDE_VERSION +#ifndef NBPG +#define NBPG 4096 +#endif /* NBPG */ + +#ifndef UADDR +#define UADDR 0xFFEE0000 /* address of u */ +#endif /* UADDR */ +#ifndef USIZE +#define USIZE (UPAGES * NBPG) +#endif /* USIZE */ +/* + * The memory looks like: + * 0x00000 - 0x01000 : trap vectors + * 0x01000 - 0x10000 : first 64k used by BUG + * 0x10000 == start : Boot loader jumps here. (for now, this can + * handle only NMAGIC - screwy linker) + * + ***********************************************************************/ + text + +LABEL(_kernelstart) +LABEL(_start) +LABEL(start) + br _start_text +#if 0 + .align 4096 ; VBR points to page aligned list + _LABEL(vector_list) /* references memory BELOW this line */ + #include "machine/exception_vectors.h" + word END_OF_VECTOR_LIST + + _LABEL(_msgsw) + word 0 /* Bits here turn on/off debugging somewhere. */ +#endif +/* + * Do a dump. Called by auto-restart. + */ + + global _dumpsys +LABEL(_doadump) + bsr _dumpsys + bsr _doboot + /*NOTREACHED*/ + +/**************************************************************************/ +LABEL(_start_text) /* This is the *real* start upon poweron or reset */ + /* + * Args passed by boot loader + * r2 howto + * r3 first_addr (first available address) + * r4 ((Clun << 8) | Dlun & FF) -> bootdev + * r5 esym + * r6 miniroot + */ + or.u r13, r0, hi16(_boothowto) + st r2, r13, lo16(_boothowto) + or.u r13, r0, hi16(_first_addr) + st r3, r13, lo16(_first_addr) +#if 0 + or.u r13, r0, hi16(_bootdev) + st r4, r13, lo16(_bootdev) +#endif + or.u r13, r0, hi16(_esym) + st r5, r13, lo16(_esym) + or.u r13, r0, hi16(_miniroot) + st r6, r13, lo16(_miniroot) + + /* + * CPU Initialization + * + * Every CPU starts from here.. + * (well, from 'start' above, which just jumps here). + * + * I use r11 and r22 here 'cause they're easy to not + * get mixed up -- r10, for example, looks too similar + * to r0 when not being careful.... + * + * Ensure that the PSR is as we like: + * supervisor mode + * big-endian byte ordering + * concurrent operation allowed + * carry bit clear (I don't think we really care about this) + * FPU enabled + * misaligned access raises an exception + * interrupts disabled + * shadow registers frozen + * + * The manual says not to disable interrupts and freeze shadowing + * at the same time because interupts are not actually disabled + * until after the next instruction. Well, if an interrupt + * occurs now, we're in deep anyway, so I'm going to do + * the two together. + * + * Upon a reset (or poweron, I guess), the PSR indicates: + * supervisor mode + * interrupts, shadowing, FPU, missaligned exception: all disabled + * + * We'll just construct our own turning on what we want. + * + * jfriedl@omron.co.jp + */ + stcr r0, SSBR /* clear this for later */ + + /* XXX We can use SR0-SR3 for any purpose */ + set r11, r0, 1<PSR_SUPERVISOR_MODE_BIT> + set r11, r11, 1<PSR_INTERRUPT_DISABLE_BIT> + stcr r11, PSR + /* shadowing, FPU, misalgined access exception: all enabled now.*/ +#if 0 + or.u r11, r0, hi16(_vector_list) + or r11, r11, lo16(_vector_list) + stcr r11, VBR +#endif /* 0 */ + stcr r0, VBR + +/************************************************************************/ + +#if defined(RAW_PRINTF) && RAW_PRINTF + bsr replace_mayput_with_rawputchar +#endif + + /* + * switch to interrupt stack + */ + or.u r31, r0, hi16(_intstack_end) + or r31, r31, lo16(_intstack_end) + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + + /* + * Want to make the call: + * vector_init(VBR, vector_list) + */ + or.u r3, r0, hi16(_vector_list) + or r3, r3, lo16(_vector_list) + bsr.n _vector_init + ldcr r2, VBR + +#if 0 + /* clear BSS. Boot loader might have already done this... */ + or.u r2, r0, hi16(_edata) + or r2, r2, lo16(_edata) + or.u r4, r0, hi16(_end) + or r4, r4, lo16(_end) + bsr.n _bzero /* bzero(edata, end-edata) */ + subu r3, r4, r2 +#endif + + /* still on int stack */ + bsr.n _m187_bootstrap + subu r31, r31, 40 + addu r31, r31, 40 + + /* switch to proc0 uarea */ + + or.u r10, r0, hi16(UADDR) + or r31, r10,lo16(UADDR) + addu r31, r31, USIZE + + /* make the call: main() */ + bsr.n _main + subu r31, r31, 40 + addu r31, r31, 40 + br _return_from_main + +/*****************************************************************************/ + + data + .align 4096 ; VBR points to page aligned list + global _vector_list +_vector_list: ; references memory BELOW this line + #include "machine/exception_vectors.h" + word END_OF_VECTOR_LIST + + global _msgsw +_msgsw: + word 0 ;Bits here turn on/off debugging somewhere. + .align 4096 + global _intstack + global _intstack_end +_intstack: + space 4 * NBPG /* 16K */ +_intstack_end: + +/* + * When a process exits and its u. area goes away, we set curpcb to point + * to this `u.', leaving us with something to use for an interrupt stack, + * and letting all the register save code have a pcb_uw to examine. + * This is also carefully arranged (to come just before u0, so that + * process 0's kernel stack can quietly overrun into it during bootup, if + * we feel like doing that). + * Should be page aligned. + */ + global _idle_u +_idle_u: + space UPAGES * NBPG + +/* + * Process 0's u. + * + * This must be page aligned + */ + global _u0 + align 4096 +_u0: space UPAGES * NBPG +estack0: + +/* + * UPAGES get mapped to kstack + */ + + global _kstack +_kstack: + word UADDR + +#ifdef DDB + global _esym +_esym: + word 0 +#endif /* DDB */ + + global _proc0paddr /* move to C code */ +_proc0paddr: + word _u0 /* KVA of proc0 uarea */ + +/* + * _curpcb points to the current pcb (and hence u. area). + * Initially this is the special one. + */ +/* + * pcb is composed of kernel state + user state + * I may have to change curpcb to u0 + PCB_USER based on what + * other parts expect XXX + */ + global _curpcb /* move to C code */ +_curpcb: word _u0 /* curpcb = &u0 */ + +/* + * Trampoline code. Gets copied to the top of + * user stack in exec. + */ + global _sigcode +_sigcode: + /* r31 points to sigframe */ + ld r2, r31, 0 /* signo */ + ld r3, r31, 4 /* code */ + ld r4, r31, 8 /* sigcontext* */ + or r5, r0, 0 /* addr = 0 for now */ + ld r6, r31, 12 /* handler */ + jsr.n r6 + addu r31, r31, 40 + subu r31, r31, 40 + ld r2, r31, 8 /* sigcontext* */ + or r9, r0, SYS_sigreturn + tb0 0, r0, 128 /* syscall trap, calling sigreturn */ + or r0, r0, 0 + or r0, r0, 0 + /* sigreturn will not return unless it fails */ + or r9, r0, SYS_exit + tb0 0, r0, 128 /* syscall trap, exit */ + or r0, r0, 0 + or r0, r0, 0 + global _esigcode +_esigcode: + +#if 0 +/* + * thread_bootstrap: + * + * Bootstrap a new thread using the thread state that has been + * placed on the stack. Our fp has been set up for us, we only need + * to fix up a few things in the saved frame, then get into + * usermode. + */ +ENTRY(thread_bootstrap) + /* + * Here r31 should point to the place on our stack which + * contains a pointer to our exception frame. + */ +#if DDB + ENTRY_ASM +#endif + br return_from_exception_handler + +/* + * save_context + */ +ENTRY(save_context) + subu r31,r31,40 /* allocate stack for r1 and args */ + st r1,r31,36 /* save return address */ + bsr _spl /* get the current interrupt mask */ + ld r1,r31,36 /* recover return address */ + addu r31,r31,40 /* put stack pointer back */ + ldcr r10,SR0 /* r10 <- current_thread() */ + ld r10,r10,THREAD_PCB /* r10 <- pcb */ +#if (PCB_KERNEL!=0) + addu r10, r10, PCB_KERNEL /* point to kernel save region */ +#endif + st r1,r10,0 /* do setjmp */ /* save return address */ + st r14,r10,4 + st r15,r10,2*4 + st r16,r10,3*4 + st r17,r10,4*4 + st r18,r10,5*4 + st r19,r10,6*4 + st r20,r10,7*4 + st r21,r10,8*4 + st r22,r10,9*4 + st r23,r10,10*4 + st r24,r10,11*4 + st r25,r10,12*4 + /* In principle, registers 26-29 are never manipulated in the + kernel. Maybe we can skip saving them? */ + st r26,r10,13*4 + st r27,r10,14*4 + st r28,r10,15*4 + st r29,r10,16*4 + st r30,r10,17*4 /* save frame pointer */ + st r31,r10,18*4 /* save stack pointer */ + st r2,r10,19*4 /* save interrupt mask */ + /* we need to switch to the interrupt stack here */ + or.u r31, r0, hi16(_intstack) + or r31, r31, lo16(_intstack) + addu r31, r31, INTSTACK_SIZE /* end of stack */ + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + jmp.n r1 + or r2,r0,r0 +#endif /* 0 */ + +/* ------------------------------------------------------------------------ */ +/* + * unsigned measure_pause(volatile int *flag) + * + * Count cycles executed until *flag becomes nonzero. + * Return the number of cycles counted. + */ +ENTRY(measure_pause) + /* R2 is pointer to flag */ + def GRANULAIRTY, 10000 + + or r3, r0, 1 /* r3 is my counter, this is the first */ + + measure_pause_outer_loop: + or r4, r0, GRANULAIRTY + + measure_pause_inner_loop: + /* + * Execute a tight loop of a known number of cycles. + * This assumes, of course, that the instruction cache is on. + * This loop takes two cycles per iteration. + */ + bcnd.n ne0, r4, measure_pause_inner_loop + subu r4, r4, 1 + + + /* + * Now add the number of cycles done above (plus the overhead + * of the outer loop) to the total count. + * Also, check the *flag and exit the outer loop if it's non-zero. + * + * The overhead is really unknown because it's not known how + * the memory system will tread the access to *flag, so we just + * take a guess. + */ + ld r4, r2, r0 /* get the flag */ + addu r3, r3, (GRANULAIRTY * 2 + 10) /* account for the cost */ + bcnd eq0, r4, measure_pause_outer_loop /* continue or exit the loop*/ + + jmp.n r1 + or r2, r3, r0 /* pass count back */ + +/* + * void delay_in_microseconds(int count) + * + * The processor loops (busy waits) for the given number of microseconds: + * Thus, delay_in_microseconds(1000000) will delay for one second. + * + * REGISTER USAGE: + * IN r1 - return address + * IN r2 - (signed int) number of microseconds + * r3 - (float) number of microseconds + * r4/5 - (double) number of cycles per microsecond + * r6 - (float) number of cycles to delay + * r7 - (signed) number of cycles to delay + */ +ENTRY(delay_in_microseconds) +ENTRY(delay) + flt.ss r3, r2 /* convert microseconds from signed int to float */ + or.u r4, r0, hi16(_cycles_per_microsecond) + ld.d r4, r4, lo16(_cycles_per_microsecond) + fmul.ssd r6, r3, r4 /* convert microseconds to cycles */ + int.ss r7, r6 /* convert cycles from float to signed int */ + subu r7, r7, 25 /* subtract for overhead of above instruction */ + + /* now loop for the given number of cycles */ + pause_loop: + bcnd.n gt0, r7, pause_loop + subu r7, r7, 2 /* two cycles per iteration */ + + jmp r1 /* return */ + +#if 0 +/* + * void switch_to_shutdown_context(thread_t thread, + * void (*routine)(processor_t), + * processor_t processor) + * + * saves the kernel context of the thread, + * switches to the interrupt stack, + * continues the thread (with thread_dispatch), + * then runs routine on the interrupt stack. + * + */ + +ENTRY(switch_to_shutdown_context) +/* call save_context to save the thread state */ + subu r31, r31, 40 + or r25, r3, r0 /* save arguments */ + or r24, r4, r0 + bsr.n _save_context + st r1, r31, 36 + addu r31, r31, 40 + ldcr r10, SR0 /* r10 <- current_thread() */ + st r31, r10, THREAD_KERNEL_STACK /* save stack pointer */ + st r0, r10, THREAD_SWAP_FUNC /* null continuation */ + ldcr r11, SR1 + mak r11, r11, FLAG_CPU_FIELD_WIDTH<0> /* r1 = cpu # */ + or r12, r12, lo16(_interrupt_stack) + ld r31, r12 [r11] + addu r31, r31, INTSTACK_SIZE /* end of stack */ + clr r31, r31, 3<0> /* round down to 8-byte boundary */ + /* save the thread; switched to the interrupt stack; now call thread + dispatch to get rid of this thread */ + or r2, r10, r0 + bsr.n _thread_dispatch + subu r31, r31, 40 + /* call the continuation routine */ + jsr.n r25 + or r2, r24, r0 + /* panic if here */ + or.u r2, r0, hi16(1f) + bsr.n _panic + or r2, r2, lo16(1f) +1: + string "switch_to_shutdown_context" +#endif /* 0 */ |