opl_olympus_asm.s revision 2dd3029adb4864ebca3dd9cd6dad5fc4d38abff6
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Assembly code support for the Olympus-C module
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if !defined(lint)
#include "assym.h"
#endif /* lint */
#include <sys/asm_linkage.h>
#include <vm/hat_sfmmu.h>
#include <sys/machparam.h>
#include <sys/machcpuvar.h>
#include <sys/machthread.h>
#include <sys/machtrap.h>
#include <sys/privregs.h>
#include <sys/asm_linkage.h>
#include <sys/opl_olympus_regs.h>
#include <sys/opl_module.h>
#ifdef TRAPTRACE
#include <sys/traptrace.h>
#endif /* TRAPTRACE */
/*
* Macro that flushes the entire Ecache.
*
* arg1 = ecache size
* arg2 = ecache linesize
* arg3 = ecache flush address - Not used for olympus-C
*/
/*
* SPARC64-VI MMU and Cache operations.
*/
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
/*
* flush page from the tlb
*
* %o0 = vaddr
* %o1 = sfmmup
*/
#ifdef DEBUG
#endif /* DEBUG */
/*
* disable ints
*/
/*
* Then, blow out the tlb
* Interrupts are disabled to prevent the primary ctx register
* from changing underneath us.
*/
/*
* For Kernel demaps use primary. type = page implicitly
*/
1:
/*
* User demap. We need to set the primary context properly.
* Secondary context cannot be used for SPARC64-VI IMMU.
* %o0 = vaddr
* %o1 = sfmmup
* %o3 = FLUSH_ADDR
*/
#endif /* lint */
#if defined(lint)
void
vtag_flushall(void)
{}
#else /* lint */
/*
* flush the tlb
*/
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
/*
* x-trap to flush page from tlb and tsb
*
* %g1 = vaddr, zero-extended on 32-bit kernel
* %g2 = sfmmup
*
* assumes TSBE_TAG = 0
*/
/* We need to demap in the kernel context */
1:
/* We need to demap in a user context */
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
/*
* x-trap to flush pgcnt MMU_PAGESIZE pages from tlb
*
* %g1 = vaddr, zero-extended on 32-bit kernel
* %g2 = <sfmmup58|pgcnt6>
*
* NOTE: this handler relies on the fact that no
* interrupts or traps can occur during the loop
* issuing the TLB_DEMAP operations. It is assumed
* that interrupts are disabled and this code is
* fetching from the kernel locked text address.
*
* assumes TSBE_TAG = 0
*/
/* We need to demap in the kernel context */
4:
1:
/*
* We need to demap in a user context
*
* g2 = sfmmup
* g3 = pgcnt
*/
3:
#endif /* lint */
#if defined(lint)
/*ARGSUSED*/
void
{}
#else /* lint */
/*
* x-trap to flush tlb
*/
#endif /* lint */
/*
* VAC (virtual address conflict) does not apply to OPL.
* VAC resolution is managed by the Olympus processor hardware.
* As a result, all OPL VAC flushing routines are no-ops.
*/
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
#endif /* lint */
#if defined(lint)
int
idsr_busy(void)
{
return (0);
}
#else /* lint */
/*
* Determine whether or not the IDSR is busy.
* Entry: no arguments
* Returns: 1 if busy, 0 otherwise
*/
1:
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
/* ARGSUSED */
void
{}
#else /* lint */
.asciz "ASI_INTR_DISPATCH_STATUS error: busy"
.align 4
/*
* Setup interrupt dispatch data registers
* Entry:
* %o0 - function or inumber to call
* %o1, %o2 - arguments (2 uint64_t's)
*/
.seg "text"
#ifdef DEBUG
!
!
#endif /* DEBUG */
!
!
1:
!
!
!
!
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{ return; }
#else /* lint */
/*
*/
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{}
#else /* lint */
/*
* flush_instr_mem:
* Flush 1 page of the I-$ starting at vaddr
* %o0 vaddr
* %o1 bytes to be flushed
*
* SPARC64-VI maintains consistency of the on-chip Instruction Cache with
* the stores from all processors so that a FLUSH instruction is only needed
* to ensure pipeline is consistent. This means a single flush is sufficient at
* the end of a sequence of stores that updates the instruction stream to
* ensure correct operation.
*/
#endif /* lint */
/*
* flush_ecache:
* %o0 - 64 bit physical address
* %o1 - ecache size
* %o2 - ecache linesize
*/
#if defined(lint)
/*ARGSUSED*/
void
{}
#else /* !lint */
/*
* Flush the entire Ecache.
*/
#endif /* lint */
#if defined(lint)
/*ARGSUSED*/
void
int icache_lsize)
{
}
#else /* lint */
/*
* I/D cache flushing is not needed for OPL processors
*/
#endif /* lint */
#ifdef TRAPTRACE
/*
* Simplified trap trace macro for OPL. Adapted from us3.
*/
#endif /* TRAPTRACE */
/*
* Macros facilitating error handling.
*/
/*
* Save alternative global registers reg1, reg2, reg3
* to scratchpad registers 1, 2, 3 respectively.
*/
/*
* Restore alternative global registers reg1, reg2, reg3
* from scratchpad registers 1, 2, 3 respectively.
*/
/*
* Logs value `val' into the member `offset' of a structure
* at physical address `pa'
*/
#define FLUSH_ALL_TLB(tmp1) \
/*
* Extracts the Physaddr to Logging Buffer field of the OPL_SCRATCHPAD_ERRLOG
* scratch register by zeroing all other fields. Result is in pa.
*/
/*
* Advance the per-cpu error log buffer pointer to the next
* ERRLOG_SZ entry, making sure that it will modulo (wraparound)
* ERRLOG_BUFSIZ boundary. The args logpa, bufmask, tmp are
* unused input registers for this macro.
*
* Algorithm:
* 1. logpa = contents of errorlog scratchpad register
* 2. bufmask = ERRLOG_BUFSIZ - 1
* 3. tmp = logpa & ~(bufmask) (tmp is now logbase)
* 4. logpa += ERRLOG_SZ
* 5. logpa = logpa & bufmask (get new offset to logbase)
* 4. logpa = tmp | logpa
* 7. write logpa back into errorlog scratchpad register
*
* new logpa = (logpa & ~bufmask) | ((logpa + ERRLOG_SZ) & bufmask)
*
*/
/* Log error status registers into the log buffer */
/*
* Scrub the STICK_COMPARE register to clear error by updating
* it to a reasonable value for interrupt generation.
* Ensure that we observe the CPU_ENABLE flag so that we
* don't accidentally enable TICK interrupt in STICK_COMPARE
* i.e. no clock interrupt will be generated if CPU_ENABLE flag
* is off.
*/
/*
* Reset registers that may be corrupted by IAUG_CRE error.
* To update interrupt handling related registers force the
* clock interrupt.
*/
#define CLEAR_FPREGS(tmp) \
#define CLEAR_GLOBALS() \
/*
* We do not clear the alternative globals here because they
* are scratch registers, i.e. there is no code that reads from
* them without write to them firstly. In other words every
* read always follows write that makes extra write to the
* alternative globals unnecessary.
*/
CLEAR_GLOBALS() ;\
CLEAR_GLOBALS() ;\
nop ;\
CLEAR_GLOBALS() ;\
/*
* Reset all window related registers
*/
#define RESET_WINREG(tmp) \
nop ;\
/*
* %pstate, %pc, %npc are propagated to %tstate, %tpc, %tnpc,
* and we reset these regiseter here.
*/
#define RESET_CUR_TSTATE(tmp) \
/*
* In case of urgent errors some MMU registers may be
* corrupted, so we set here some reasonable values for
* them. Note that resetting MMU registers also reset the context
* info, we will need to reset the window registers to prevent
* Note that the TLBs must be flushed before programming the context
* registers.
*/
#if !defined(lint)
FLUSH_ALL_TLB(tmp1) ;\
#define RESET_TSB_TAGPTR(tmp) \
#endif /* lint */
/*
* In case of errors in the MMU_TSB_PREFETCH registers we have to
* reset them. We can use "0" as the reset value, this way we set
* the "V" bit of the registers to 0, which will disable the prefetch
* so the values of the other fields are irrelevant.
*/
#if !defined(lint)
#define RESET_TSB_PREFETCH(tmp) \
#endif /* lint */
/*
* In case of errors in the MMU_SHARED_CONTEXT register we have to
* reset its value. We can use "0" as the reset value, it will put
* 0 in the IV field disabling the shared context support, and
* making values of all the other fields of the register irrelevant.
*/
#if !defined(lint)
#define RESET_SHARED_CTXT(tmp) \
#endif /* lint */
/*
* RESET_TO_PRIV()
*
* In many cases, we need to force the thread into privilege mode because
* privilege mode is only thing in which the system continue to work
* due to undeterminable user mode information that come from register
* corruption.
*
* - opl_uger_ctxt
* If the error is secondary TSB related register parity, we have no idea
* what value is supposed to be for it.
*
* The below three cases %tstate is not accessible until it is overwritten
* with some value, so we have no clue if the thread was running on user mode
* or not
* - opl_uger_pstate
* If the error is %pstate parity, it propagates to %tstate.
* - opl_uger_tstate
* No need to say the reason
* - opl_uger_r
* If the error is %ccr or %asi parity, it propagates to %tstate
*
* For the above four cases, user mode info may not be available for
* sys_trap() and user_trap() to work consistently. So we have to force
* the thread into privilege mode.
*
* Forcing the thread to privilege mode requires forcing
* regular %g7 to be CPU_THREAD. Because if it was running on user mode,
* %g7 will be set in user_trap(). Also since the %sp may be in
* an inconsistent state, we need to do a stack reset and switch to
* something we know i.e. current thread's kernel stack.
* We also reset the window registers and MMU registers just to
* make sure.
*
* To set regular %g7, we need to clear PSTATE_AG bit and need to
* use one local register. Note that we are panicking and will never
* unwind back so it is ok to clobber a local.
*
* If the thread was running in user mode, the %tpc value itself might be
* within the range of OBP addresses. %tpc must be forced to be zero to prevent
* sys_trap() from going to prom_trap()
*
*/
#if defined(lint)
void
ce_err(void)
{}
#else /* lint */
/*
* We normally don't expect CE traps since we disable the
* 0x63 trap reporting at the start of day. There is a
* small window before we disable them, so let check for
* it. Otherwise, panic.
*/
.align 128
1:
/*
* We did disabled the 0x63 trap reporting.
* This shouldn't happen - panic.
*/
#endif /* lint */
#if defined(lint)
void
ce_err_tl1(void)
{}
#else /* lint */
/*
* We don't use trap for CE detection.
*/
#endif /* lint */
#if defined(lint)
void
async_err(void)
{}
#else /* lint */
/*
* For OPL, we patch in the right handler at start of day.
* is patched, panic.
*/
#endif /* lint */
#if defined(lint)
void
opl_sync_trap(void)
{}
#else /* lint */
.seg ".data"
.align 16
.word 0
.align 16
/*
* Common synchronous error trap handler (tt=0xA, 0x32)
* All TL=0 and TL>0 0xA and 0x32 traps vector to this handler.
* The error handling can be best summarized as follows:
* 0. Do TRAPTRACE if enabled.
* 1. Save globals %g1, %g2 & %g3 onto the scratchpad regs.
* 2. The SFSR register is read and verified as valid by checking
* SFSR.FV bit being set. If the SFSR.FV is not set, the
* error cases cannot be decoded/determined and the SFPAR
* register that contain the physical faultaddr is also
* cases. Assuming the SFSR.FV is valid:
* - BERR(bus error)/TO(timeout)/UE case
* If any of these error cases are detected, read the SFPAR
* to get the faultaddress. Generate ereport.
* - TLB Parity case (only recoverable case)
* For DAE, read SFAR for the faultaddress. For IAE,
* use %tpc for faultaddress (SFAR is not valid in IAE)
* Flush all the tlbs.
* Subtract one from the recoverable error count stored in
* the error log scratch register. If the threshold limit
* is reached (zero) - generate ereport. Else
* restore globals and retry (no ereport is generated).
* - TLB Multiple hits
* For DAE, read SFAR for the faultaddress. For IAE,
* use %tpc for faultaddress (SFAR is not valid in IAE).
* Flush all tlbs and generate ereport.
* 3. TL=0 and TL>0 considerations
* - Since both TL=0 & TL>1 traps are made to vector into
* the same handler, the underlying assumption/design here is
* that any nested error condition (if happens) occurs only
* in the handler and the system is assumed to eventually
* Red-mode. With this philosophy in mind, the recoverable
* TLB Parity error case never check the TL level before it
* retry. Note that this is ok for the TL>1 case (assuming we
* don't have a nested error) since we always save the globals
* %g1, %g2 & %g3 whenever we enter this trap handler.
* - Additional TL=0 vs TL>1 handling includes:
* - For UE error occuring under TL>1, special handling
* is added to prevent the unlikely chance of a cpu-lockup
* when a UE was originally detected in user stack and
* the spill trap handler taken from sys_trap() so happened
* to reference the same UE location. Under the above
* condition (TL>1 and UE error), paranoid code is added
* to reset window regs so that spill traps can't happen
* during the unwind back to TL=0 handling.
* Note that we can do that because we are not returning
* back.
* 4. Ereport generation.
* - Ereport generation is performed when we unwind to the TL=0
* handling code via sys_trap(). on_trap()/lofault protection
* will apply there.
*
*/
#ifdef TRAPTRACE
#endif /* TRAPTRACE */
0:
7:
1:
/*
* This is the TLB parity error case and it is the
* only retryable error case.
* Only %g1, %g2 and %g3 are allowed
*/
8:
2:
/*
* non-retryable error handling
* now we can use other registers since
* we will not be returning back
*/
/*
* Special case for UE on user stack.
* There is a possibility that the same error may come back here
* by touching the same UE in spill trap handler taken from
* sys_trap(). It ends up with an infinite loop causing a cpu lockup.
* Conditions for this handling this case are:
* - SFSR_FV is valid and SFSR_UE is set
* - we are at TL > 1
* If the above conditions are true, we force %cansave to be a
* big number to prevent spill trap in sys_trap(). Note that
* we will not be returning back.
*/
4:
3:
6:
#endif /* lint */
#if defined(lint)
void
opl_uger_trap(void)
{}
#else /* lint */
/*
* Common Urgent error trap handler (tt=0x40)
* All TL=0 and TL>0 0x40 traps vector to this handler.
* The error handling can be best summarized as follows:
* 1. Read the Urgent error status register (UGERSR)
* Faultaddress is N/A here and it is not collected.
* 2. Check to see if we have a multiple errors case
* If so, we enable WEAK_ED (weak error detection) bit
* to prevent any potential error storms and branch directly
* error cases when we get a multiple error situation)
* 3. Now look for the recoverable error cases which include
* IUG_DTLB, IUG_ITLB or COREERR errors. If any of the
* recoverable errors are detected, do the following:
* - Flush all tlbs.
* - Verify that we came from TL=0, if not, generate
* ereport. Note that the reason we don't recover
* at TL>0 is because the AGs might be corrupted or
* the scratchpad regs like we did for opl_sync_trap().
* - Check the INSTEND[5:4] bits in the UGERSR. If the
* value is 0x3 (11b), this error is not recoverable.
* Generate ereport.
* - Subtract one from the recoverable error count stored in
* the error log scratch register. If the threshold limit
* is reached (zero) - generate ereport.
* - If the count is within the limit, update the count
* in the error log register (subtract one). Log the error
* info in the log buffer. Capture traptrace if enabled.
* Retry (no ereport generated)
* 4. The rest of the error cases are unrecoverable and will
* be handled according (flushing regs, etc as required).
* For details on these error cases (UGER_CRE, UGER_CTXT, etc..)
* Ereport will be generated for these errors.
* 5. Ereport generation.
* - Ereport generation for urgent error trap always
* result in a panic when we unwind to the TL=0 handling
* code via sys_trap(). on_trap()/lofault protection do
* not apply there.
*/
/*
* Fall thru to handle recoverable case
* Need to do the following additional checks to determine
* if this is indeed recoverable.
* 1. Error trap came from TL=0 and
* 2. INSTEND[5:4] bits in UGERSR is not 0x3
* 3. Recoverable error count limit not reached
*
*/
#ifdef TRAPTRACE
#endif /* TRAPTRACE */
/*
* Process the rest of the unrecoverable error cases
* All error cases below ultimately branch to either
* opl_uger_panic or opl_uger_panic1.
* opl_uger_panic1 is the same as opl_uger_panic except
* for the additional execution of the RESET_TO_PRIV()
* macro that does a heavy handed reset. Read the
* comments for RESET_TO_PRIV() macro for more info.
*/
1:
1:
/*
* IUG_TSBP error may corrupt MMU registers
* Reset them here.
*/
/*
* Set up the argument for sys_trap.
* %g2 = arg #1 already set above
*/
#endif /* lint */
#if defined(lint)
void
opl_ta3_trap(void)
{}
void
opl_cleanw_subr(void)
{}
#else /* lint */
/*
* OPL ta3 support (note please, that win_reg
* area size for each cpu is 2^7 bytes)
*/
/*
* The purpose of this function is to make sure that the restore
* instruction after the flushw does not cause a fill trap. The sun4u
* fill trap handler can not handle a tlb fault of an unmapped stack
* except at the restore instruction at user_rtt. On OPL systems the
* stack can get unmapped between the flushw and restore instructions
* since multiple strands share the tlb.
*/
#endif /* lint */
#if defined(lint)
void
opl_serr_instr(void)
{}
#else /* lint */
/*
* The actual trap handler for tt=0x0a, and tt=0x32
*/
.align 32
#endif /* lint */
#if defined(lint)
void
opl_ugerr_instr(void)
{}
#else /* lint */
/*
* The actual trap handler for tt=0x40
*/
.align 32
#endif /* lint */
#if defined(lint)
void
opl_ta3_instr(void)
{}
#else /* lint */
/*
* The actual trap handler for tt=0x103 (flushw)
*/
.align 32
#endif /* lint */
#if defined(lint)
void
opl_ta4_instr(void)
{}
#else /* lint */
/*
* The patch for the .clean_windows code
*/
#endif /* lint */
#if defined(lint)
/*
* Get timestamp (stick).
*/
/* ARGSUSED */
void
{
}
#else /* lint */
#endif /* lint */
#if defined(lint)
/*
* Set STICK adjusted by skew.
*/
/* ARGSUSED */
void
{
}
#else /* lint */
.align 16
1: nop
#endif /* lint */
#if defined(lint)
/*
* Debugger-specific stick retrieval
*/
/*ARGSUSED*/
int
{
return (0);
}
#else /* lint */
#endif /* lint */
#if defined(lint)
/*ARGSUSED*/
int
{ return (0); }
#else
1:
/*
* We're about to write a block full or either total garbage
* (not kernel data, don't worry) or user floating-point data
* (so it only _looks_ like garbage).
*/
1:
0:
1:
/*
* If tryagain is set (%i2) we tail-call dtrace_blksuword32_err()
* which deals with watchpoints. Otherwise, just return -1.
*/
1:
#endif /* lint */
#if defined(lint)
/*ARGSUSED*/
void
ras_cntr_reset(void *arg)
{
}
#else
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
{
}
#else /* lint */
/*
* Initialize the error log scratchpad register
*/
/*
* Disable all restrainable error traps
*/
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
opl_mpg_enable(void)
{
}
#else /* lint */
/*
* Enable MMU translating multiple page sizes for
* sITLB and sDTLB.
*/
#endif /* lint */
#if defined(lint)
/*
* This function is called for each (enabled) CPU. We use it to
* initialize error handling related registers.
*/
/*ARGSUSED*/
void
cpu_feature_init(void)
{}
#else /* lint */
!
!
!
!
#endif /* lint */
#if defined(lint)
void
cpu_cleartickpnt(void)
{}
#else /* lint */
/*
* Clear the NPT (non-privileged trap) bit in the %tick/%stick
* registers. In an effort to make the change in the
* all interrupts while we're changing the registers. We also
* ensure that the read and write instructions are in the same
* line in the instruction cache.
*/
2:
/* clearing NPT bit */
1:
4:
/* clearing NPT bit */
3:
#endif /* lint */
#if defined(lint)
void
cpu_halt_cpu(void)
{}
void
cpu_smt_pause(void)
{}
#else /* lint */
/*
* Halt the current strand with the suspend instruction.
* instruction mnemonic, use byte code for now.
*/
.word 0x81b01040
/*
* Pause the current strand with the sleep instruction.
* instruction mnemonic, use byte code for now.
*/
.word 0x81b01060
#endif /* lint */