/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include "assym.h" /* * This file implements the following ddi common access * functions: * * ddi_get{8,16,32,64} * ddi_put{8,16,32,64} * * and the underlying "trivial" implementations * * i_ddi_{get,put}{8,16,32,64} * * which assume that there is no need to check the access handle - * byte swapping will be done by the mmu and the address is always * accessible via ld/st instructions. */ /* * The functionality of each of the ddi_get/put routines is performed by * the respective indirect function defined in the access handle. Use of * the access handle functions provides compatibility across platforms for * drivers. * * By default, the indirect access handle functions are initialized to the * i_ddi_get/put routines to perform memory mapped IO. If memory mapped IO * is not possible or desired, the access handle must be intialized to another * valid routine to perform the sepcified IO operation. * * The alignment and placement of the following functions have been optimized * such that the implementation specific versions, i_ddi*, fall within the * same cache-line of the generic versions, ddi_*. This insures that an * I-cache hit will occur thus minimizing the performance impact of using the * access handle. */ .align 32 ENTRY(ddi_get8) ALTENTRY(ddi_io_get8) ALTENTRY(ddi_mem_get8) ldn [%o0 + AHI_GET8], %g1 /* hdl->ahi_get8 access hndl */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_get8) SET_SIZE(ddi_io_get8) SET_SIZE(ddi_mem_get8) .align 16 ENTRY(i_ddi_get8) retl ldub [%o1], %o0 SET_SIZE(i_ddi_get8) .align 32 ENTRY(ddi_get16) ALTENTRY(ddi_io_get16) ALTENTRY(ddi_mem_get16) ldn [%o0 + AHI_GET16], %g1 /* hdl->ahi_get16 access hndl */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_get16) SET_SIZE(ddi_io_get16) SET_SIZE(ddi_mem_get16) .align 16 ENTRY(i_ddi_get16) ALTENTRY(i_ddi_swap_get16) retl lduh [%o1], %o0 SET_SIZE(i_ddi_get16) SET_SIZE(i_ddi_swap_get16) .align 32 ENTRY(ddi_get32) ALTENTRY(ddi_io_get32) ALTENTRY(ddi_mem_get32) ldn [%o0 + AHI_GET32], %g1 /* hdl->ahi_get32 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_get32) SET_SIZE(ddi_io_get32) SET_SIZE(ddi_mem_get32) .align 16 ENTRY(i_ddi_get32) ALTENTRY(i_ddi_swap_get32) retl ld [%o1], %o0 SET_SIZE(i_ddi_get32) SET_SIZE(i_ddi_swap_get32) .align 32 ENTRY(ddi_get64) ALTENTRY(ddi_io_get64) ALTENTRY(ddi_mem_get64) ldn [%o0 + AHI_GET64], %g1 /* hdl->ahi_get64 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_get64) SET_SIZE(ddi_io_get64) SET_SIZE(ddi_mem_get64) .align 16 ENTRY(i_ddi_get64) ALTENTRY(i_ddi_swap_get64) retl ldx [%o1], %o0 SET_SIZE(i_ddi_get64) SET_SIZE(i_ddi_swap_get64) .align 32 ENTRY(ddi_put8) ALTENTRY(ddi_io_put8) ALTENTRY(ddi_mem_put8) ldn [%o0 + AHI_PUT8], %g1 /* hdl->ahi_put8 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_put8) SET_SIZE(ddi_io_put8) SET_SIZE(ddi_mem_put8) .align 16 ENTRY(i_ddi_put8) retl stub %o2, [%o1] SET_SIZE(i_ddi_put8) .align 32 ENTRY(ddi_put16) ALTENTRY(ddi_io_put16) ALTENTRY(ddi_mem_put16) ldn [%o0 + AHI_PUT16], %g1 /* hdl->ahi_put16 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_put16) SET_SIZE(ddi_io_put16) SET_SIZE(ddi_mem_put16) .align 16 ENTRY(i_ddi_put16) ALTENTRY(i_ddi_swap_put16) retl stuh %o2, [%o1] SET_SIZE(i_ddi_put16) SET_SIZE(i_ddi_swap_put16) .align 32 ENTRY(ddi_put32) ALTENTRY(ddi_io_put32) ALTENTRY(ddi_mem_put32) ldn [%o0 + AHI_PUT32], %g1 /* hdl->ahi_put16 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_put32) SET_SIZE(ddi_io_put32) SET_SIZE(ddi_mem_put32) .align 16 ENTRY(i_ddi_put32) ALTENTRY(i_ddi_swap_put32) retl st %o2, [%o1] SET_SIZE(i_ddi_put32) SET_SIZE(i_ddi_swap_put32) .align 32 ENTRY(ddi_put64) ALTENTRY(ddi_io_put64) ALTENTRY(ddi_mem_put64) ldn [%o0 + AHI_PUT64], %g1 /* hdl->ahi_put64 access handle */ jmpl %g1, %g0 /* jump to access handle routine */ nop SET_SIZE(ddi_put64) SET_SIZE(ddi_io_put64) SET_SIZE(ddi_mem_put64) .align 16 ENTRY(i_ddi_put64) ALTENTRY(i_ddi_swap_put64) retl stx %o2, [%o1] SET_SIZE(i_ddi_put64) SET_SIZE(i_ddi_swap_put64) /* * The ddi_io_rep_get/put routines don't take a flag argument like the "plain" * and mem versions do. This flag is used to determine whether or not the * device address or port should be automatically incremented. For IO space, * the device port is never incremented and as such, the flag is always set * to DDI_DEV_NO_AUTOINCR. * * This define processes the repetitive get functionality. Automatic * incrementing of the device address is determined by the flag field * %o4. If this is set for AUTOINCR, %o4 is updated with 1 for the * subsequent increment in 2:. * * If this flag is not set for AUTOINCR, %o4 is update with a value of 0 thus * making the increment operation a non-operation. */ #define DDI_REP_GET(n,s) \ cmp DDI_DEV_NO_AUTOINCR, %o4; \ mov %g0, %o4; \ brz,pn %o3, 1f; \ movnz %xcc, n, %o4; \ 2: \ dec %o3; \ ld##s [%o2], %g4; \ add %o2, %o4, %o2; \ st##s %g4, [%o1]; \ brnz,pt %o3, 2b; \ add %o1, n, %o1; \ 1: .align 32 ENTRY(ddi_rep_get8) ALTENTRY(ddi_mem_rep_get8) ldn [%o0 + AHI_REP_GET8], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_get8) SET_SIZE(ddi_mem_rep_get8) .align 16 ENTRY(i_ddi_rep_get8) DDI_REP_GET(1,ub) retl nop SET_SIZE(i_ddi_rep_get8) .align 32 ENTRY(ddi_rep_get16) ALTENTRY(ddi_mem_rep_get16) ldn [%o0 + AHI_REP_GET16], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_get16) SET_SIZE(ddi_mem_rep_get16) .align 16 ENTRY(i_ddi_rep_get16) ALTENTRY(i_ddi_swap_rep_get16) DDI_REP_GET(2,uh) retl nop SET_SIZE(i_ddi_rep_get16) SET_SIZE(i_ddi_swap_rep_get16) .align 32 ENTRY(ddi_rep_get32) ALTENTRY(ddi_mem_rep_get32) ldn [%o0 + AHI_REP_GET32], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_get32) SET_SIZE(ddi_mem_rep_get32) .align 16 ENTRY(i_ddi_rep_get32) ALTENTRY(i_ddi_swap_rep_get32) DDI_REP_GET(4,/**/) retl nop SET_SIZE(i_ddi_rep_get32) SET_SIZE(i_ddi_swap_rep_get32) .align 32 ENTRY(ddi_rep_get64) ALTENTRY(ddi_mem_rep_get64) ldn [%o0 + AHI_REP_GET64], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_get64) SET_SIZE(ddi_mem_rep_get64) .align 16 ENTRY(i_ddi_rep_get64) ALTENTRY(i_ddi_swap_rep_get64) DDI_REP_GET(8,x) retl nop SET_SIZE(i_ddi_rep_get64) SET_SIZE(i_ddi_swap_rep_get64) /* * This define processes the repetitive put functionality. Automatic * incrementing of the device address is determined by the flag field * %o4. If this is set for AUTOINCR, %o4 is updated with 1 for the * subsequent increment in 2:. * * If this flag is not set for AUTOINCR, %o4 is update with a value of 0 thus * making the increment operation a non-operation. */ #define DDI_REP_PUT(n,s) \ cmp DDI_DEV_NO_AUTOINCR, %o4; \ mov %g0, %o4; \ brz,pn %o3, 1f; \ movnz %xcc, n, %o4; \ 2: \ dec %o3; \ ld##s [%o1], %g4; \ add %o1, n, %o1; \ st##s %g4, [%o2]; \ brnz,pt %o3, 2b; \ add %o2, %o4, %o2; \ 1: .align 32 ENTRY(ddi_rep_put8) ALTENTRY(ddi_mem_rep_put8) ldn [%o0 + AHI_REP_PUT8], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_put8) SET_SIZE(ddi_mem_rep_put8) .align 16 ENTRY(i_ddi_rep_put8) DDI_REP_PUT(1,ub) retl nop SET_SIZE(i_ddi_rep_put8) .align 32 ENTRY(ddi_rep_put16) ALTENTRY(ddi_mem_rep_put16) ldn [%o0 + AHI_REP_PUT16], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_put16) SET_SIZE(ddi_mem_rep_put16) .align 16 ENTRY(i_ddi_rep_put16) ALTENTRY(i_ddi_swap_rep_put16) DDI_REP_PUT(2,uh) retl nop SET_SIZE(i_ddi_rep_put16) SET_SIZE(i_ddi_swap_rep_put16) .align 32 ENTRY(ddi_rep_put32) ALTENTRY(ddi_mem_rep_put32) ldn [%o0 + AHI_REP_PUT32], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_put32) SET_SIZE(ddi_mem_rep_put32) .align 16 ENTRY(i_ddi_rep_put32) ALTENTRY(i_ddi_swap_rep_put32) DDI_REP_PUT(4,/**/) retl nop SET_SIZE(i_ddi_rep_put32) SET_SIZE(i_ddi_swap_rep_put32) .align 32 ENTRY(ddi_rep_put64) ALTENTRY(ddi_mem_rep_put64) ldn [%o0 + AHI_REP_PUT64], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_rep_put64) SET_SIZE(ddi_mem_rep_put64) .align 16 ENTRY(i_ddi_rep_put64) ALTENTRY(i_ddi_swap_rep_put64) DDI_REP_PUT(8,x) retl nop SET_SIZE(i_ddi_rep_put64) SET_SIZE(i_ddi_swap_rep_put64) .align 16 ENTRY(ddi_io_rep_get8) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_GET8], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_get8) .align 16 ENTRY(ddi_io_rep_get16) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_GET16], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_get16) .align 16 ENTRY(ddi_io_rep_get32) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_GET32], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_get32) .align 16 ENTRY(ddi_io_rep_get64) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_GET64], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_get64) .align 64 ENTRY(ddi_check_acc_handle) save %sp, -SA(WINDOWSIZE), %sp ! get a new window ldn [%i0 + AHI_FAULT_CHECK], %g1 jmpl %g1, %o7 mov %i0, %o0 brnz,a,pn %o0, 0f ! if (return_value != 0) mov -1, %o0 ! return (DDI_FAILURE) 0: ! else return (DDI_SUCCESS) sra %o0, 0, %i0 ret restore SET_SIZE(ddi_check_acc_handle) .align 16 ENTRY(i_ddi_acc_fault_check) retl ld [%o0 + AHI_FAULT], %o0 SET_SIZE(i_ddi_acc_fault_check) .align 16 ENTRY(ddi_io_rep_put8) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_PUT8], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_put8) .align 16 ENTRY(ddi_io_rep_put16) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_PUT16], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_put16) .align 16 ENTRY(ddi_io_rep_put32) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_PUT32], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_put32) .align 16 ENTRY(ddi_io_rep_put64) set DDI_DEV_NO_AUTOINCR, %o4 /* Set flag to DDI_DEV_NO_AUTOINCR */ ldn [%o0 + AHI_REP_PUT64], %g1 jmpl %g1, %g0 nop SET_SIZE(ddi_io_rep_put64) ENTRY(do_peek) rdpr %pstate, %o3 ! check ints andcc %o3, PSTATE_IE, %g0 bz,a done or %g0, 1, %o0 ! Return failure if ints are disabled wrpr %o3, PSTATE_IE, %pstate cmp %o0, 8 ! 64-bit? bne,a .peek_int cmp %o0, 4 ! 32-bit? ldx [%o1], %g1 ba .peekdone stx %g1, [%o2] .peek_int: bne,a .peek_half cmp %o0, 2 ! 16-bit? lduw [%o1], %g1 ba .peekdone stuw %g1, [%o2] .peek_half: bne,a .peek_byte ldub [%o1], %g1 ! 8-bit! lduh [%o1], %g1 ba .peekdone stuh %g1, [%o2] .peek_byte: stub %g1, [%o2] .peekdone: membar #Sync ! Make sure the loads take rdpr %pstate, %o3 ! check&enable ints andcc %o3, PSTATE_IE, %g0 bnz 1f nop wrpr %o3, PSTATE_IE, %pstate 1: mov %g0, %o0 done: retl nop SET_SIZE(do_peek) ENTRY(do_poke) cmp %o0, 8 ! 64 bit? bne,a .poke_int cmp %o0, 4 ! 32-bit? ldx [%o2], %g1 ba .pokedone stx %g1, [%o1] .poke_int: bne,a .poke_half cmp %o0, 2 ! 16-bit? lduw [%o2], %g1 ba .pokedone stuw %g1, [%o1] .poke_half: bne,a .poke_byte ldub [%o2], %g1 ! 8-bit! lduh [%o2], %g1 ba .pokedone stuh %g1, [%o1] .poke_byte: stub %g1, [%o1] .pokedone: membar #Sync retl mov %g0, %o0 SET_SIZE(do_poke) /* * The peek_fault() and poke_fault() routines below are used as on_trap() * trampoline routines. i_ddi_peek and i_ddi_poke execute do_peek and do_poke * under on_trap protection (see ), but modify ot_trampoline to * refer to the corresponding routine below. If a trap occurs, the trap code * will bounce back to the trampoline code, which will effectively cause * do_peek or do_poke to return DDI_FAILURE, instead of longjmp'ing back to * on_trap. In the case of a peek, we may also need to re-enable interrupts. */ .seg ".data" .peek_panic: .asciz "peek_fault: missing or invalid on_trap_data" .poke_panic: .asciz "poke_fault: missing or invalid on_trap_data" ENTRY(peek_fault) ldn [THREAD_REG + T_ONTRAP], %o0 ! %o0 = on_trap_data pointer brz,pn %o0, .peekfail ! if (%o0 == NULL) panic nop lduh [%o0 + OT_PROT], %o1 ! %o1 = %o0->ot_prot andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS)) bz,pn %icc, .peekfail ! panic rdpr %pstate, %o3 andcc %o3, PSTATE_IE, %g0 ! enable interrupts bnz 1f nop wrpr %o3, PSTATE_IE, %pstate 1: retl sub %g0, 1, %o0 ! return (DDI_FAILURE); .peekfail: set .peek_panic, %o0 ! Load panic message call panic ! Panic if bad t_ontrap data nop SET_SIZE(peek_fault) ENTRY(poke_fault) ldn [THREAD_REG + T_ONTRAP], %o0 ! %o0 = on_trap_data pointer brz,pn %o0, .pokefail ! if (%o0 == NULL) panic nop lduh [%o0 + OT_PROT], %o1 ! %o1 = %o0->ot_prot andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS)) bz,pn %icc, .pokefail ! panic nop retl sub %g0, 1, %o0 ! return (DDI_FAILURE); .pokefail: set .poke_panic, %o0 ! Load panic message call panic ! Panic if bad t_ontrap data nop SET_SIZE(poke_fault) /* * IO Fault Services * * Support for protected IO accesses is implemented in the following * functions. A driver may request one of three protection mechanisms * that enable the system to survive an access errors. The protection * mechansim is set-up during ddi_regs_map_setup time and may be one of: * * DDI_DEFAULT_ACC - no error protection requested. We will * use the standard ddi_get/ddi_put operations * defined above. * * DDI_FLAGERR - Driver requests that errors encountered will * be flagged by the system. The driver is * responsible for checking the error status * of the access with a call to ddi_acc_err_get() * upon return of ddi_get or ddi_put. To prevent * an access from causing a system we use internal * on_trap semantics. * * The system, depending upon the error, * may or may not panic. * * DDI_CAUTIOUS_ACC - Driver expects that the access may cause * an error to occur. The system will return * an error status but will not generate an ereport. * The system will also ensure synchronous and * exclusive access to the IO space accessed by * the caller. * * To prevent an access from causing a system panic, * we use on_trap semantics to catch the error and * set error status. * * If a read access error is detected and DDI_CAUTIOUS_ACC or * DDI_FLAGERR_ACC protection was requested, we will trampoline to the * error handler, i_ddi_trampoline. i_ddi_trampoline will: * - check for proper protection semantics * - set the error status of the access handle to DDI_FM_NONFATAL * - re-enable interrupts if neccessary * - longjmp back to the initiating access function. * If a write access error is detected, an interrupt is typically * generated and claimed by a bus nexus responsible for the write * transaction. The nexus error handler is expected to set the * error status and the IO initiating driver is expected to check * for a failed transaction via ddi_fm_acc_err_get(). * */ .seg ".data" .acc_panic: .asciz "DDI access: missing or invalid on_trap_data" ENTRY(i_ddi_caut_trampoline) ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap lduh [%o5 + OT_PROT], %o1 ! %o1 = %o0->ot_prot andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS)) bz,pn %icc, .cautaccfail ! panic rdpr %pstate, %o3 andcc %o3, PSTATE_IE, %g0 ! enable interrupts bnz 1f nop wrpr %o3, PSTATE_IE, %pstate 1: ldn [%o5 + OT_HANDLE], %o0 ! %o0 = ot_handle brz,pn %o0, .cautaccfail ! if (ot_handle == NULL) panic nop ldn [%o0 + AHI_ERR], %o4 ! %o4 = hp->ahi_err membar #Sync stx %g0, [%o4 + ERR_ENA] ! ahi_err->err_ena = 0 mov -2, %o0 st %o0, [%o4 + ERR_STATUS] ! ahi_err->err_status = NONFATAL b longjmp ! longjmp back add %o5, OT_JMPBUF, %o0 ! %o0 = &ot_jmpbuf .cautaccfail: set .acc_panic, %o0 ! Load panic message call panic ! Panic if bad t_ontrap data nop SET_SIZE(i_ddi_caut_trampoline) /* * DDI on_trap set-up functions, i_ddi_ontrap() and i_ddinotrap() are used * to protect * ddi_get accesses for DDI_CAUT_ACC. i_ddi_ontrap() sets * the jumpbuf (setjmp) that will return back to the access routine from * i_ddi_trampoline(). DDI_NOPROTECT() clears the ontrap set-up. */ ENTRY(i_ddi_ontrap) ldn [%o0 + AHI_ERR], %o4 ldn [%o4 + ERR_ONTRAP], %o4 ! %o4 = hp->ahi_err->err_ontrap ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap stn %o5, [%o4 + OT_PREV] ! ot_prev = t_ontrap membar #Sync ! force error barrier stn %o4, [THREAD_REG + T_ONTRAP] ! t_ontrap = err_ontrap b setjmp add %o4, OT_JMPBUF, %o0 SET_SIZE(i_ddi_ontrap) ENTRY(i_ddi_notrap) membar #Sync ! force error barrier ldn [%o0 + AHI_ERR], %o4 ldn [%o4 + ERR_ONTRAP], %o4 ! %o4 = hp->ahi_err->err_ontrap ldn [%o4 + OT_PREV], %o4 retl stn %o4, [THREAD_REG + T_ONTRAP] ! restore curthread->t_ontrap SET_SIZE(i_ddi_notrap) /* * Internal on_trap set-up macros. DDI_PROTECT() and DDI_NOPROTECT() are used * to protect * ddi_get accesses for DDI_FLAGERR_ACC. DDI_NOPROTECT() sets * the jumpbuf that will return back to the access routine from * i_ddi_protect_trampoline(). DDI_NOPROTECT() clears the ontrap set-up. */ ENTRY(i_ddi_prot_trampoline) ldn [THREAD_REG + T_ONTRAP], %o5 ! %o5 = curthread->t_ontrap lduh [%o5 + OT_PROT], %o1 ! %o1 = %o0->ot_prot andcc %o1, OT_DATA_ACCESS, %g0 ! if (!(%o1 & OT_DATA_ACCESS)) bz,pn %icc, .protaccfail ! panic rdpr %pstate, %o3 andcc %o3, PSTATE_IE, %g0 ! enable interrupts bnz 1f nop wrpr %o3, PSTATE_IE, %pstate 1: ldn [%o5 + OT_HANDLE], %o0 ! %o0 = ot_handle brz,pn %o0, .protaccfail ! if (ot_handle == NULL) panic nop ldn [%o0 + AHI_ERR], %o4 ! %o4 = hp->ahi_err stn %g0, [%o4 + ERR_ENA] ! ahi_err->err_ena = 0 mov -2, %o0 st %o0, [%o4 + ERR_STATUS] ! ahi_err->err_status = NONFATAL ldn [%o5 + OT_PREV], %o0 ! restore ontrap membar #Sync ! force error barrier stn %o0, [THREAD_REG + T_ONTRAP]; b longjmp ! longjmp back add %o5, OT_JMPBUF, %o0 ! %o0 = &ot_jmpbuf .protaccfail: set .acc_panic, %o0 ! Load panic message call panic ! Panic if bad t_ontrap data nop SET_SIZE(i_ddi_prot_trampoline) #define DDI_PROTECT() \ ldn [%o0 + AHI_ERR], %o4; \ ldn [%o4 + ERR_ONTRAP], %o4; \ ldn [THREAD_REG + T_ONTRAP], %o5; \ stn %o5, [%o4 + OT_PREV]; \ membar #Sync; \ stn %o4, [THREAD_REG + T_ONTRAP]; \ add %o4, OT_JMPBUF, %o0; \ stn %o7, [%o0 + L_PC]; \ stn %sp, [%o0 + L_SP]; \ clr %o0; #define DDI_NOPROTECT() \ ldn [THREAD_REG + T_ONTRAP], %o4; \ ldn [%o4 + OT_PREV], %o5; \ membar #Sync; \ stn %o5, [THREAD_REG + T_ONTRAP]; /* * DDI_FLAGERR_ACC specific get/put routines. */ .align 16 ENTRY(i_ddi_prot_get8) DDI_PROTECT() ! set ontrap protection ldub [%o1], %o2 ! do the io access DDI_NOPROTECT() ! remove protection & ret retl mov %o2, %o0 ! set return value SET_SIZE(i_ddi_prot_get8) .align 16 ENTRY(i_ddi_prot_get16) DDI_PROTECT() ! set ontrap protection lduh [%o1], %o2 ! do the io access DDI_NOPROTECT() ! remove protection & ret retl mov %o2, %o0 ! set return value SET_SIZE(i_ddi_prot_get16) .align 16 ENTRY(i_ddi_prot_get32) DDI_PROTECT() ! set ontrap protection ld [%o1], %o2 ! do the io access DDI_NOPROTECT() ! remove protection & ret retl mov %o2, %o0 ! set return value SET_SIZE(i_ddi_prot_get32) .align 16 ENTRY(i_ddi_prot_get64) DDI_PROTECT() ! set ontrap protection ldx [%o1], %o2 ! do the io access DDI_NOPROTECT() ! remove protection & ret retl mov %o2, %o0 ! set return value SET_SIZE(i_ddi_prot_get64) .align 16 ENTRY(i_ddi_prot_put8) stub %o2, [%o1] ! do the io access retl membar #Sync; SET_SIZE(i_ddi_prot_put8) .align 16 ENTRY(i_ddi_prot_put16) stuh %o2, [%o1] ! do the io access retl membar #Sync; SET_SIZE(i_ddi_prot_put16) .align 16 ENTRY(i_ddi_prot_put32) st %o2, [%o1] ! do the io access retl membar #Sync; SET_SIZE(i_ddi_prot_put32) .align 16 ENTRY(i_ddi_prot_put64) stx %o2, [%o1] ! do the io access retl membar #Sync; SET_SIZE(i_ddi_prot_put64) .align 16 ENTRY(i_ddi_prot_rep_get8) DDI_PROTECT() ! set ontrap protection tst %o0 ! check access error bnz,a 1f nop DDI_REP_GET(1,ub) 1: DDI_NOPROTECT() ! remove protection & ret retl nop SET_SIZE(i_ddi_prot_rep_get8) .align 16 ENTRY(i_ddi_prot_rep_get16) DDI_PROTECT() ! set ontrap protection tst %o0 ! check access error bnz,a 1f nop DDI_REP_GET(2,uh) 1: DDI_NOPROTECT() ! remove protection & ret retl nop SET_SIZE(i_ddi_prot_rep_get16) .align 16 ENTRY(i_ddi_prot_rep_get32) DDI_PROTECT() ! set ontrap protection tst %o0 ! check access error bnz,a 1f nop DDI_REP_GET(4,/**/) 1: DDI_NOPROTECT() ! remove protection & ret retl nop SET_SIZE(i_ddi_prot_rep_get32) .align 16 ENTRY(i_ddi_prot_rep_get64) DDI_PROTECT() ! set ontrap protection tst %o0 ! check access error bnz,a 1f nop DDI_REP_GET(8,x) 1: DDI_NOPROTECT() ! remove protection & ret retl nop SET_SIZE(i_ddi_prot_rep_get64) .align 16 ENTRY(i_ddi_prot_rep_put8) DDI_REP_PUT(1,ub) retl membar #Sync; SET_SIZE(i_ddi_prot_rep_put8) .align 16 ENTRY(i_ddi_prot_rep_put16) DDI_REP_PUT(2,uh) retl membar #Sync; SET_SIZE(i_ddi_prot_rep_put16) .align 16 ENTRY(i_ddi_prot_rep_put32) DDI_REP_PUT(4,/**/) retl membar #Sync; SET_SIZE(i_ddi_prot_rep_put32) .align 16 ENTRY(i_ddi_prot_rep_put64) DDI_REP_PUT(8,x) retl membar #Sync; SET_SIZE(i_ddi_prot_rep_put64) /* * Common DDI_CAUTIOUS_ACC routine called from cautious access routines * in ddi_impl.c */ ENTRY(i_ddi_caut_get) rdpr %pstate, %o3 ! check ints andcc %o3, PSTATE_IE, %g0 bz,a cautdone nop wrpr %o3, PSTATE_IE, %pstate cmp %o0, 8 ! 64-bit? bne,a .get_int cmp %o0, 4 ! 32-bit? ldx [%o1], %g1 ba .getdone stx %g1, [%o2] .get_int: bne,a .get_half cmp %o0, 2 ! 16-bit? lduw [%o1], %g1 ba .getdone stuw %g1, [%o2] .get_half: bne,a .get_byte ldub [%o1], %g1 ! 8-bit! lduh [%o1], %g1 ba .getdone stuh %g1, [%o2] .get_byte: stub %g1, [%o2] .getdone: rdpr %pstate, %o3 ! check&enable ints andcc %o3, PSTATE_IE, %g0 bnz,a cautdone nop wrpr %o3, PSTATE_IE, %pstate cautdone: retl nop SET_SIZE(i_ddi_caut_get)