Index: head/sys/sparc64/sparc64/machdep.c =================================================================== --- head/sys/sparc64/sparc64/machdep.c (revision 112913) +++ head/sys/sparc64/sparc64/machdep.c (revision 112914) @@ -1,712 +1,705 @@ /*- * Copyright (c) 2001 Jake Burkholder. * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * from: FreeBSD: src/sys/i386/i386/machdep.c,v 1.477 2001/08/27 * $FreeBSD$ */ #include "opt_compat.h" #include "opt_ddb.h" #include "opt_msgbuf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef int ofw_vec_t(void *); struct tlb_entry *kernel_tlbs; int kernel_tlb_slots; int cold = 1; long Maxmem; char pcpu0[PCPU_PAGES * PAGE_SIZE]; char uarea0[UAREA_PAGES * PAGE_SIZE]; struct trapframe frame0; vm_offset_t kstack0; vm_offset_t kstack0_phys; struct kva_md_info kmi; u_long ofw_vec; u_long ofw_tba; static struct timecounter tick_tc; char sparc64_model[32]; static timecounter_get_t tick_get_timecount; void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec); void sparc64_shutdown_final(void *dummy, int howto); static void cpu_startup(void *); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); CTASSERT((1 << INT_SHIFT) == sizeof(int)); CTASSERT((1 << PTR_SHIFT) == sizeof(char *)); CTASSERT(sizeof(struct reg) == 256); CTASSERT(sizeof(struct fpreg) == 272); CTASSERT(sizeof(struct __mcontext) == 512); CTASSERT(sizeof(struct pcpu) <= ((PCPU_PAGES * PAGE_SIZE) / 2)); static void cpu_startup(void *arg) { tick_tc.tc_get_timecount = tick_get_timecount; tick_tc.tc_poll_pps = NULL; tick_tc.tc_counter_mask = ~0u; tick_tc.tc_frequency = tick_freq; tick_tc.tc_name = "tick"; tc_init(&tick_tc); cpu_identify(rdpr(ver), tick_freq, PCPU_GET(cpuid)); printf("Model: %s\n", sparc64_model); vm_ksubmap_init(&kmi); bufinit(); vm_pager_bufferinit(); EVENTHANDLER_REGISTER(shutdown_final, sparc64_shutdown_final, NULL, SHUTDOWN_PRI_LAST); } void cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) { struct intr_request *ir; int i; pcpu->pc_irtail = &pcpu->pc_irhead; for (i = 0; i < IR_FREE; i++) { ir = &pcpu->pc_irpool[i]; ir->ir_next = pcpu->pc_irfree; pcpu->pc_irfree = ir; } } unsigned tick_get_timecount(struct timecounter *tc) { return ((unsigned)rd(tick)); } void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) { phandle_t child; phandle_t root; struct pcpu *pc; vm_offset_t end; caddr_t kmdp; u_int clock; char *env; char type[8]; end = 0; kmdp = NULL; /* * Find out what kind of cpu we have first, for anything that changes * behaviour. */ cpu_impl = VER_IMPL(rdpr(ver)); /* * Initialize openfirmware (needed for console). */ OF_init(vec); /* * Parse metadata if present and fetch parameters. Must be before the * console is inited so cninit gets the right value of boothowto. */ if (mdp != NULL) { preload_metadata = mdp; kmdp = preload_search_by_type("elf kernel"); if (kmdp != NULL) { boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); kernel_tlb_slots = MD_FETCH(kmdp, MODINFOMD_DTLB_SLOTS, int); kernel_tlbs = (void *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_DTLB); } } /* * Initialize the console before printing anything. */ cninit(); /* * Panic is there is no metadata. Most likely the kernel was booted * directly, instead of through loader(8). */ if (mdp == NULL || kmdp == NULL) { printf("sparc64_init: no loader metadata.\n" "This probably means you are not using loader(8).\n"); panic("sparc64_init"); } /* * Sanity check the kernel end, which is important. */ if (end == 0) { printf("sparc64_init: warning, kernel end not specified.\n" "Attempting to continue anyway.\n"); end = (vm_offset_t)_end; } root = OF_peer(0); for (child = OF_child(root); child != 0; child = OF_peer(child)) { OF_getprop(child, "device_type", type, sizeof(type)); if (strcmp(type, "cpu") == 0) break; } if (child == 0) panic("cpu_startup: no cpu\n"); OF_getprop(child, "#dtlb-entries", &tlb_dtlb_entries, sizeof(tlb_dtlb_entries)); OF_getprop(child, "#itlb-entries", &tlb_itlb_entries, sizeof(tlb_itlb_entries)); cache_init(child); #ifdef DDB kdb_init(); #endif #ifdef SMP mp_tramp = mp_tramp_alloc(); #endif /* * Initialize virtual memory and calculate physmem. */ pmap_bootstrap(end); /* * Initialize tunables. */ init_param1(); init_param2(physmem); env = getenv("kernelname"); if (env != NULL) { strlcpy(kernelname, env, sizeof(kernelname)); freeenv(env); } /* * Disable tick for now. */ tick_stop(); /* * Initialize the interrupt tables. */ intr_init1(); /* * Initialize proc0 stuff (p_contested needs to be done early). */ proc_linkup(&proc0, &ksegrp0, &kse0, &thread0); proc0.p_md.md_sigtramp = NULL; proc0.p_md.md_utrap = NULL; proc0.p_uarea = (struct user *)uarea0; proc0.p_stats = &proc0.p_uarea->u_stats; thread0.td_kstack = kstack0; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; frame0.tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_PRIV; thread0.td_frame = &frame0; /* * Prime our per-cpu data page for use. Note, we are using it for our * stack, so don't pass the real size (PAGE_SIZE) to pcpu_init or * it'll zero it out from under us. */ pc = (struct pcpu *)(pcpu0 + (PCPU_PAGES * PAGE_SIZE)) - 1; pcpu_init(pc, 0, sizeof(struct pcpu)); pc->pc_curthread = &thread0; pc->pc_curpcb = thread0.td_pcb; pc->pc_mid = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); pc->pc_addr = (vm_offset_t)pcpu0; pc->pc_node = child; pc->pc_tlb_ctx = TLB_CTX_USER_MIN; pc->pc_tlb_ctx_min = TLB_CTX_USER_MIN; pc->pc_tlb_ctx_max = TLB_CTX_USER_MAX; /* * Initialize global registers. */ cpu_setregs(pc); /* * Initialize the message buffer (after setting trap table). */ msgbufinit(msgbufp, MSGBUF_SIZE); mutex_init(); intr_init2(); OF_getprop(PCPU_GET(node), "clock-frequency", &clock, sizeof(clock)); tick_init(clock); OF_getprop(root, "name", sparc64_model, sizeof(sparc64_model) - 1); } void set_openfirm_callback(ofw_vec_t *vec) { ofw_tba = rdpr(tba); ofw_vec = (u_long)vec; } void sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct trapframe *tf; struct sigframe *sfp; struct sigacts *psp; struct sigframe sf; struct thread *td; struct frame *fp; struct proc *p; int oonstack; u_long sp; oonstack = 0; td = curthread; p = td->td_proc; psp = p->p_sigacts; tf = td->td_frame; sp = tf->tf_sp + SPOFF; oonstack = sigonstack(sp); CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, catcher, sig); /* Make sure we have a signal trampoline to return to. */ if (p->p_md.md_sigtramp == NULL) { /* * No signal tramoline... kill the process. */ CTR0(KTR_SIG, "sendsig: no sigtramp"); printf("sendsig: %s is too old, rebuild it\n", p->p_comm); sigexit(td, sig); /* NOTREACHED */ } /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; bcopy(tf, &sf.sf_uc.uc_mcontext, sizeof(*tf)); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct sigframe)); } else sfp = (struct sigframe *)sp - 1; PROC_UNLOCK(p); fp = (struct frame *)sfp - 1; /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ tf->tf_out[0] = sig; tf->tf_out[1] = (register_t)&sfp->sf_si; tf->tf_out[2] = (register_t)&sfp->sf_uc; tf->tf_out[4] = (register_t)catcher; /* Fill siginfo structure. */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void *)tf->tf_sfar; /* Copy the sigframe out to the user's stack. */ if (rwindow_save(td) != 0 || copyout(&sf, sfp, sizeof(*sfp)) != 0 || suword(&fp->fr_in[6], tf->tf_out[6]) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ CTR2(KTR_SIG, "sendsig: sigexit td=%p sfp=%p", td, sfp); PROC_LOCK(p); sigexit(td, SIGILL); /* NOTREACHED */ } tf->tf_tpc = (u_long)p->p_md.md_sigtramp; tf->tf_tnpc = tf->tf_tpc + 4; tf->tf_sp = (u_long)fp - SPOFF; CTR3(KTR_SIG, "sendsig: return td=%p pc=%#lx sp=%#lx", td, tf->tf_tpc, tf->tf_sp); PROC_LOCK(p); } #ifndef _SYS_SYSPROTO_H_ struct sigreturn_args { ucontext_t *ucp; }; #endif /* * MPSAFE */ int sigreturn(struct thread *td, struct sigreturn_args *uap) { struct trapframe *tf; struct proc *p; mcontext_t *mc; ucontext_t uc; p = td->td_proc; if (rwindow_save(td)) { PROC_LOCK(p); sigexit(td, SIGILL); } CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp); if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) { CTR1(KTR_SIG, "sigreturn: efault td=%p", td); return (EFAULT); } mc = &uc.uc_mcontext; tf = td->td_frame; if (!TSTATE_SECURE(mc->mc_tstate)) return (EINVAL); mc->mc_wstate = tf->tf_wstate; bcopy(mc, tf, sizeof(*tf)); PROC_LOCK(p); td->td_sigmask = uc.uc_sigmask; SIG_CANTMASK(td->td_sigmask); signotify(td); PROC_UNLOCK(p); CTR4(KTR_SIG, "sigreturn: return td=%p pc=%#lx sp=%#lx tstate=%#lx", td, tf->tf_tpc, tf->tf_sp, tf->tf_tstate); return (EJUSTRETURN); } #ifdef COMPAT_FREEBSD4 int freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap) { return sigreturn(td, (struct sigreturn_args *)uap); } #endif int get_mcontext(struct thread *td, mcontext_t *mcp) { return (ENOSYS); } int set_mcontext(struct thread *td, const mcontext_t *mcp) { return (ENOSYS); } /* * Exit the kernel and execute a firmware call that will not return, as * specified by the arguments. */ void cpu_shutdown(void *args) { #ifdef SMP cpu_mp_shutdown(); #endif openfirmware_exit(args); } /* * Duplicate OF_exit() with a different firmware call function that restores * the trap table, otherwise a RED state exception is triggered in at least * some firmware versions. */ void cpu_halt(void) { static struct { cell_t name; cell_t nargs; cell_t nreturns; } args = { (cell_t)"exit", 0, 0 }; cpu_shutdown(&args); } void sparc64_shutdown_final(void *dummy, int howto) { static struct { cell_t name; cell_t nargs; cell_t nreturns; } args = { (cell_t)"SUNW,power-off", 0, 0 }; /* Turn the power off? */ if ((howto & RB_POWEROFF) != 0) cpu_shutdown(&args); /* In case of halt, return to the firmware */ if ((howto & RB_HALT) != 0) cpu_halt(); } int ptrace_set_pc(struct thread *td, u_long addr) { td->td_frame->tf_tpc = addr; td->td_frame->tf_tnpc = addr + 4; return (0); } int ptrace_single_step(struct thread *td) { /* TODO; */ return (0); } void exec_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) { struct trapframe *tf; struct md_utrap *ut; struct pcb *pcb; struct proc *p; u_long sp; /* XXX no cpu_exec */ p = td->td_proc; p->p_md.md_sigtramp = NULL; if ((ut = p->p_md.md_utrap) != NULL) { ut->ut_refcnt--; if (ut->ut_refcnt == 0) free(ut, M_SUBPROC); p->p_md.md_utrap = NULL; } pcb = td->td_pcb; tf = td->td_frame; sp = rounddown(stack, 16); bzero(pcb, sizeof(*pcb)); bzero(tf, sizeof(*tf)); tf->tf_out[0] = stack; tf->tf_out[3] = p->p_sysent->sv_psstrings; tf->tf_out[6] = sp - SPOFF - sizeof(struct frame); tf->tf_tnpc = entry + 4; tf->tf_tpc = entry; tf->tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_MM_TSO; td->td_retval[0] = tf->tf_out[0]; td->td_retval[1] = tf->tf_out[1]; } void Debugger(const char *msg) { printf("Debugger(\"%s\")\n", msg); critical_enter(); breakpoint(); critical_exit(); } int fill_regs(struct thread *td, struct reg *regs) { bcopy(td->td_frame, regs, sizeof(*regs)); return (0); } int set_regs(struct thread *td, struct reg *regs) { if (!TSTATE_SECURE(regs->r_tstate)) return (EINVAL); bcopy(regs, td->td_frame, sizeof(*regs)); return (0); } int fill_dbregs(struct thread *td, struct dbreg *dbregs) { return (ENOSYS); } int set_dbregs(struct thread *td, struct dbreg *dbregs) { return (ENOSYS); } int fill_fpregs(struct thread *td, struct fpreg *fpregs) { struct trapframe *tf; struct pcb *pcb; pcb = td->td_pcb; tf = td->td_frame; bcopy(pcb->pcb_fpstate.fp_fb, fpregs->fr_regs, sizeof(pcb->pcb_fpstate.fp_fb)); fpregs->fr_fsr = tf->tf_fsr; fpregs->fr_gsr = tf->tf_gsr; return (0); } int set_fpregs(struct thread *td, struct fpreg *fpregs) { struct trapframe *tf; struct pcb *pcb; pcb = td->td_pcb; tf = td->td_frame; bcopy(fpregs->fr_regs, pcb->pcb_fpstate.fp_fb, sizeof(fpregs->fr_regs)); tf->tf_fsr = fpregs->fr_fsr; tf->tf_gsr = fpregs->fr_gsr; return (0); } - -intptr_t -casuptr(intptr_t *p, intptr_t old, intptr_t new) -{ - return (-1); -} - Index: head/sys/sparc64/sparc64/support.S =================================================================== --- head/sys/sparc64/sparc64/support.S (revision 112913) +++ head/sys/sparc64/sparc64/support.S (revision 112914) @@ -1,633 +1,656 @@ /*- * Copyright (c) 2001 Jake Burkholder. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include "assym.s" .register %g2, #ignore .register %g3, #ignore .register %g6, #ignore #define E /* empty */ /* * Generate load and store instructions for the corresponding width and asi * (or not). Note that we want to evaluate the macro args before * concatenating, so that E really turns into nothing. */ #define _LD(w, a) ld ## w ## a #define _ST(w, a) st ## w ## a #define LD(w, a) _LD(w, a) #define ST(w, a) _ST(w, a) /* * Common code for copy routines. * * We use large macros to generate functions for each of the copy routines. * This allows the load and store instructions to be generated for the right * operation, asi or not. It is possible to write an asi independent function * but this would require 2 expensive wrs in the main loop to switch %asi. * It would also screw up profiling (if we ever get it), but may save some I$. * We assume that either one of dasi and sasi is empty, or that they are both * the same (empty or non-empty). It is up to the caller to set %asi. */ /* * ASI independent implementation of copystr(9). * Used to implement copyinstr() and copystr(). * * Return value is in %g1. */ #define _COPYSTR(src, dst, len, done, sa, sasi, da, dasi) \ brz len, 4f ; \ mov src, %g2 ; \ 1: deccc 1, len ; \ bl,a,pn %xcc, 3f ; \ nop ; \ LD(ub, sa) [src] sasi, %g1 ; \ ST(b, da) %g1, [dst] dasi ; \ brz,pn %g1, 3f ; \ inc src ; \ b %xcc, 1b ; \ inc dst ; \ 2: mov ENAMETOOLONG, %g1 ; \ 3: sub src, %g2, %g2 ; \ brnz,a done, 4f ; \ stx %g2, [done] ; \ 4: /* * ASI independent implementation of memset(3). * Used to implement bzero(), memset() and aszero(). * * If the pattern is non-zero, duplicate it to fill 64 bits. * Store bytes until dst is 8-byte aligned, then store 8 bytes. * It has yet to be determined how much unrolling is beneficial. * Could also read and compare before writing to minimize snoop traffic. * * XXX bzero() should be implemented as * #define bzero(dst, len) (void)memset((dst), 0, (len)) * if at all. */ #define _MEMSET(dst, pat, len, da, dasi) \ brlez,pn len, 5f ; \ and pat, 0xff, pat ; \ brz,pt pat, 1f ; \ sllx pat, 8, %g1 ; \ or pat, %g1, pat ; \ sllx pat, 16, %g1 ; \ or pat, %g1, pat ; \ sllx pat, 32, %g1 ; \ or pat, %g1, pat ; \ _ALIGN_TEXT ; \ 1: deccc 1, len ; \ bl,pn %xcc, 5f ; \ btst 7, dst ; \ bz,a,pt %xcc, 2f ; \ inc 1, len ; \ ST(b, da) pat, [dst] dasi ; \ b %xcc, 1b ; \ inc dst ; \ _ALIGN_TEXT ; \ 2: deccc 32, len ; \ bl,a,pn %xcc, 3f ; \ inc 32, len ; \ ST(x, da) pat, [dst] dasi ; \ ST(x, da) pat, [dst + 8] dasi ; \ ST(x, da) pat, [dst + 16] dasi ; \ ST(x, da) pat, [dst + 24] dasi ; \ b %xcc, 2b ; \ inc 32, dst ; \ _ALIGN_TEXT ; \ 3: deccc 8, len ; \ bl,a,pn %xcc, 4f ; \ inc 8, len ; \ ST(x, da) pat, [dst] dasi ; \ b %xcc, 3b ; \ inc 8, dst ; \ _ALIGN_TEXT ; \ 4: deccc 1, len ; \ bl,a,pn %xcc, 5f ; \ nop ; \ ST(b, da) pat, [dst] dasi ; \ b %xcc, 4b ; \ inc 1, dst ; \ 5: /* * ASI independent implementation of memcpy(3). * Used to implement bcopy(), copyin(), copyout(), memcpy(), ascopy(), * ascopyfrom() and ascopyto(). * * Transfer bytes until dst is 8-byte aligned. If src is then also 8 byte * aligned, transfer 8 bytes, otherwise finish with bytes. The unaligned * case could be optimized, but it is expected that this is the uncommon * case and of questionable value. The code to do so is also rather large * and ugly. It has yet to be determined how much unrolling is beneficial. * * XXX bcopy() must also check for overlap. This is stupid. * XXX bcopy() should be implemented as * #define bcopy(src, dst, len) (void)memcpy((dst), (src), (len)) * if at all. */ #define _MEMCPY(dst, src, len, da, dasi, sa, sasi) \ 1: deccc 1, len ; \ bl,pn %xcc, 6f ; \ btst 7, dst ; \ bz,a,pt %xcc, 2f ; \ inc 1, len ; \ LD(ub, sa) [src] sasi, %g1 ; \ ST(b, da) %g1, [dst] dasi ; \ inc 1, src ; \ b %xcc, 1b ; \ inc 1, dst ; \ _ALIGN_TEXT ; \ 2: btst 7, src ; \ bz,a,pt %xcc, 3f ; \ nop ; \ b,a %xcc, 5f ; \ _ALIGN_TEXT ; \ 3: deccc 32, len ; \ bl,a,pn %xcc, 4f ; \ inc 32, len ; \ LD(x, sa) [src] sasi, %g1 ; \ LD(x, sa) [src + 8] sasi, %g2 ; \ LD(x, sa) [src + 16] sasi, %g3 ; \ LD(x, sa) [src + 24] sasi, %g4 ; \ ST(x, da) %g1, [dst] dasi ; \ ST(x, da) %g2, [dst + 8] dasi ; \ ST(x, da) %g3, [dst + 16] dasi ; \ ST(x, da) %g4, [dst + 24] dasi ; \ inc 32, src ; \ b %xcc, 3b ; \ inc 32, dst ; \ _ALIGN_TEXT ; \ 4: deccc 8, len ; \ bl,a,pn %xcc, 5f ; \ inc 8, len ; \ LD(x, sa) [src] sasi, %g1 ; \ ST(x, da) %g1, [dst] dasi ; \ inc 8, src ; \ b %xcc, 4b ; \ inc 8, dst ; \ _ALIGN_TEXT ; \ 5: deccc 1, len ; \ bl,a,pn %xcc, 6f ; \ nop ; \ LD(ub, sa) [src] sasi, %g1 ; \ ST(b, da) %g1, [dst] dasi ; \ inc src ; \ b %xcc, 5b ; \ inc dst ; \ 6: /* * void ascopy(u_long asi, vm_offset_t src, vm_offset_t dst, size_t len) */ ENTRY(ascopy) wr %o0, 0, %asi _MEMCPY(%o2, %o1, %o3, a, %asi, a, %asi) retl nop END(ascopy) /* * void ascopyfrom(u_long sasi, vm_offset_t src, caddr_t dst, size_t len) */ ENTRY(ascopyfrom) wr %o0, 0, %asi _MEMCPY(%o2, %o1, %o3, E, E, a, %asi) retl nop END(ascopyfrom) /* * void ascopyto(caddr_t src, u_long dasi, vm_offset_t dst, size_t len) */ ENTRY(ascopyto) wr %o1, 0, %asi _MEMCPY(%o2, %o0, %o3, a, %asi, E, E) retl nop END(ascopyto) /* * void aszero(u_long asi, vm_offset_t pa, size_t len) */ ENTRY(aszero) wr %o0, 0, %asi _MEMSET(%o1, %g0, %o2, a, %asi) retl nop END(aszero) /* * int bcmp(const void *b1, const void *b2, size_t len) */ ENTRY(bcmp) brz,pn %o2, 2f clr %o3 1: ldub [%o0 + %o3], %o4 ldub [%o1 + %o3], %o5 cmp %o4, %o5 bne,pn %xcc, 2f inc %o3 deccc %o2 bne,pt %xcc, 1b nop 2: retl mov %o2, %o0 END(bcmp) /* * void bcopy(const void *src, void *dst, size_t len) */ ENTRY(bcopy) ENTRY(ovbcopy) /* * Check for overlap, and copy backwards if so. */ sub %o1, %o0, %g1 cmp %g1, %o2 bgeu,a,pt %xcc, 3f nop /* * Copy backwards. */ add %o0, %o2, %o0 add %o1, %o2, %o1 1: deccc 1, %o2 bl,a,pn %xcc, 2f nop dec 1, %o0 ldub [%o0], %g1 dec 1, %o1 b %xcc, 1b stb %g1, [%o1] 2: retl nop /* * Do the fast version. */ 3: _MEMCPY(%o1, %o0, %o2, E, E, E, E) retl nop END(bcopy) /* * void bzero(void *b, size_t len) */ ENTRY(bzero) _MEMSET(%o0, %g0, %o1, E, E) retl nop END(bzero) /* * int copystr(const void *src, void *dst, size_t len, size_t *done) */ ENTRY(copystr) _COPYSTR(%o0, %o1, %o2, %o3, E, E, E, E) retl mov %g1, %o0 END(copystr) /* * void *memcpy(void *dst, const void *src, size_t len) */ ENTRY(memcpy) mov %o0, %o3 _MEMCPY(%o3, %o1, %o2, E, E, E, E) retl nop END(memcpy) /* * void *memset(void *b, int c, size_t len) */ ENTRY(memset) mov %o0, %o3 _MEMSET(%o3, %o1, %o2, E, E) retl nop END(memset) .globl copy_nofault_begin copy_nofault_begin: nop /* * int copyin(const void *uaddr, void *kaddr, size_t len) */ ENTRY(copyin) wr %g0, ASI_AIUP, %asi _MEMCPY(%o1, %o0, %o2, E, E, a, %asi) retl clr %o0 END(copyin) /* * int copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) */ ENTRY(copyinstr) wr %g0, ASI_AIUP, %asi _COPYSTR(%o0, %o1, %o2, %o3, a, %asi, E, E) retl mov %g1, %o0 END(copyinstr) /* * int copyout(const void *kaddr, void *uaddr, size_t len) */ ENTRY(copyout) wr %g0, ASI_AIUP, %asi _MEMCPY(%o1, %o0, %o2, a, %asi, E, E) retl clr %o0 END(copyout) .globl copy_nofault_end copy_nofault_end: nop ENTRY(copy_fault) retl mov EFAULT, %o0 END(copy_fault) .globl fs_nofault_begin fs_nofault_begin: nop /* * Chatty aliases for fetch, store functions. */ .globl fubyte, fusword, fuword, subyte, susword, suword .set fubyte, fuword8 .set fusword, fuword16 .set fuword, fuword64 .set subyte, suword8 .set susword, suword16 .set suword, suword64 + .globl casuptr, fuptr, suptr + .set casuptr, casuword64 + .set fuptr, fuword64 + .set suptr, suword64 + +/* + * int32_t casuword32(volatile int32_t *p, int32_t e, int32_t s) + */ +ENTRY(casuword32) + casa [%o0] ASI_AIUP, %o1, %o2 + retl + mov %o2, %o0 +END(casuword32) + +/* + * int64_t casuword64(volatile int64_t *p, int64_t e, int64_t s) + */ +ENTRY(casuword64) + casxa [%o0] ASI_AIUP, %o1, %o2 + retl + mov %o2, %o0 +END(casuword64) + /* * int fuword8(const void *base) */ ENTRY(fuword8) retl lduba [%o0] ASI_AIUP, %o0 END(fuword8) /* * int fuword16(const void *base) */ ENTRY(fuword16) retl lduha [%o0] ASI_AIUP, %o0 END(fuword16) /* * int32_t fuword32(const void *base) */ ENTRY(fuword32) retl lduwa [%o0] ASI_AIUP, %o0 END(fuword32) /* * int64_t fuword64(const void *base) */ ENTRY(fuword64) retl ldxa [%o0] ASI_AIUP, %o0 END(fuword64) /* * int suword8(const void *base, int word) */ ENTRY(suword8) stba %o1, [%o0] ASI_AIUP retl clr %o0 END(suword8) /* * int suword16(const void *base, int word) */ ENTRY(suword16) stha %o1, [%o0] ASI_AIUP retl clr %o0 END(suword16) /* * int suword32(const void *base, int32_t word) */ ENTRY(suword32) stwa %o1, [%o0] ASI_AIUP retl clr %o0 END(suword32) /* * int suword64(const void *base, int64_t word) */ ENTRY(suword64) stxa %o1, [%o0] ASI_AIUP retl clr %o0 END(suword64) .globl fs_nofault_intr_begin fs_nofault_intr_begin: nop /* * int fuswintr(const void *base) */ ENTRY(fuswintr) retl lduha [%o0] ASI_AIUP, %o0 END(fuswintr) /* * int suswintr(const void *base, int word) */ ENTRY(suswintr) stha %o1, [%o0] ASI_AIUP retl clr %o0 END(suswintr) .globl fs_nofault_intr_end fs_nofault_intr_end: nop .globl fs_nofault_end fs_nofault_end: nop ENTRY(fs_fault) retl mov -1, %o0 END(fsfault) ENTRY(longjmp) set 1, %g3 movrz %o1, %o1, %g3 mov %o0, %g1 ldx [%g1 + _JB_FP], %g2 1: cmp %fp, %g2 bl,a,pt %xcc, 1b restore bne,pn %xcc, 2f ldx [%g1 + _JB_SP], %o2 cmp %o2, %sp blt,pn %xcc, 2f movge %xcc, %o2, %sp ldx [%g1 + _JB_PC], %o7 retl mov %g3, %o0 2: PANIC("longjmp botch", %l1) END(longjmp) ENTRY(setjmp) stx %sp, [%o0 + _JB_SP] stx %o7, [%o0 + _JB_PC] stx %fp, [%o0 + _JB_FP] retl clr %o0 END(setjmp) /* * void openfirmware(cell_t args[]) */ ENTRY(openfirmware) save %sp, -CCFSZ, %sp SET(ofw_vec, %l7, %l6) ldx [%l6], %l6 rdpr %pil, %l7 wrpr %g0, PIL_TICK, %pil call %l6 mov %i0, %o0 wrpr %l7, 0, %pil ret restore %o0, %g0, %o0 END(openfirmware) /* * void ofw_exit(cell_t args[]) */ ENTRY(openfirmware_exit) save %sp, -CCFSZ, %sp flushw wrpr %g0, PIL_TICK, %pil SET(ofw_tba, %l7, %l5) ldx [%l5], %l5 wrpr %l5, 0, %tba ! restore the ofw trap table SET(ofw_vec, %l7, %l6) ldx [%l6], %l6 SET(kstack0 + KSTACK_PAGES * PAGE_SIZE - PCB_SIZEOF, %l7, %l0) sub %l0, SPOFF, %fp ! setup a stack in a locked page sub %l0, SPOFF + CCFSZ, %sp mov AA_DMMU_PCXR, %l3 ! set context 0 stxa %g0, [%l3] ASI_DMMU membar #Sync wrpr %g0, 0, %tl ! force trap level 0 call %l6 mov %i0, %o0 ! never to return END(openfirmware_exit) #ifdef GPROF ENTRY(user) nop ENTRY(btrap) nop ENTRY(etrap) nop ENTRY(bintr) nop ENTRY(eintr) nop /* * XXX including sys/gmon.h in genassym.c is not possible due to uintfptr_t * badness. */ #define GM_STATE 0x0 #define GMON_PROF_OFF 3 #define GMON_PROF_HIRES 4 .globl _mcount .set _mcount, __cyg_profile_func_enter ENTRY(__cyg_profile_func_enter) SET(_gmonparam, %o3, %o2) lduw [%o2 + GM_STATE], %o3 cmp %o3, GMON_PROF_OFF be,a,pn %icc, 1f nop SET(mcount, %o3, %o2) jmpl %o2, %g0 nop 1: retl nop END(__cyg_profile_func_enter) #ifdef GUPROF ENTRY(__cyg_profile_func_exit) SET(_gmonparam, %o3, %o2) lduw [%o2 + GM_STATE], %o3 cmp %o3, GMON_PROF_HIRES be,a,pn %icc, 1f nop SET(mexitcount, %o3, %o2) jmpl %o2, %g0 nop 1: retl nop END(__cyg_profile_func_exit) #endif /* GUPROF */ #endif /* GPROF */