X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=sboot%2Fmagpie_1_1%2Fsboot%2Fathos%2Fsrc%2Fxtos%2Fmemerror-vector.S;fp=sboot%2Fmagpie_1_1%2Fsboot%2Fathos%2Fsrc%2Fxtos%2Fmemerror-vector.S;h=04f7c0d2dca54b9d893399614be69ba2d6830f39;hb=ff66305a044be28464fa0969ea2d605bb268d478;hp=0000000000000000000000000000000000000000;hpb=60b496560eec004ded92ae4dad43b3d102c6658d;p=open-ath9k-htc-firmware.git diff --git a/sboot/magpie_1_1/sboot/athos/src/xtos/memerror-vector.S b/sboot/magpie_1_1/sboot/athos/src/xtos/memerror-vector.S new file mode 100755 index 0000000..04f7c0d --- /dev/null +++ b/sboot/magpie_1_1/sboot/athos/src/xtos/memerror-vector.S @@ -0,0 +1,482 @@ +/* memerror-vector.S -- Memory Error Exception Vector and Handler */ + +/* $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/memerror-vector.S#3 $ */ + +/* + * Copyright (c) 2006-2010 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +//#include +#include +#include + +#if XCHAL_HAVE_MEM_ECC_PARITY +# if defined(__SPLIT__vector) + + // Place this code in the memory error exception vector: + .begin literal_prefix .MemoryExceptionVector + .section .MemoryExceptionVector.text, "ax" + + .global _MemErrorVector + .align 4 +_MemErrorVector: +# if 0 /* XCHAL_HAVE_DEBUG */ + // Memory errors raise PS.INTLEVEL above DEBUGLEVEL, so + // break instructions have no effect within them (debug + // exceptions are masked). So leave commented out for now. + break 1, 5 // unhandled memory error exception +# endif + wsr a0, MESAVE + movi a0, _MemErrorHandler + jx a0 + + .size _MemErrorVector, . - _MemErrorVector + .text + .end literal_prefix + + +# elif defined(__SPLIT__handler) + +/* + * Some rules and assumptions: + * + * Anything that can interrupt this handler (e.g. NMI): + * - must not lock or unlock cache lines + */ + + +#define ICACHE_WAYWIDTH (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) /* LICT's "iis" */ +#define DCACHE_WAYWIDTH (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) /* LDCT's "dis" */ +/* NOTE: Memory ECC/parity is not supported on XLMI or on local ROMs: */ +#define HAVE_LOCAL_RAM (XCHAL_NUM_DATARAM || XCHAL_NUM_INSTRAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/) + + + //.lcomm _MemErrorSave, 8 + .comm _MemErrorSave, 8, 4 + + .text + .align 4 + .global _MemErrorHandler +_MemErrorHandler: + rsr a0, MESR + bbsi.l a0, MESR_DME_SHIFT, .L_fatal_dme +# if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0 + bbsi.l a0, MESR_MEMTYPE_SHIFT+1, .L_cache // branch if error on a cache +# endif + // Error in a local memory. +# if HAVE_LOCAL_RAM + bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_uncorrectable_local + // Correctable error in a local memory (IRAM or DRAM). + // (MEVADDR has all 32 bits, so XSR preserves a register:) + xsr a2, MEVADDR + // Note: MEVADDR is always 4-byte aligned, + // so we can just do L32I/S32I to correct the error. + // However, that's not atomic, and NMI can store in between; + // that's usually a problem for D rather than I, avoid the + // issue using S32C1I if configured (else NMI must not write DataRAM!?!): +# if (XCHAL_HAVE_S32C1I && (XCHAL_NUM_DATARAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/)) + bbci.l a0, MESR_MEMTYPE_SHIFT, .L_instram // branch if error on InstRAM + // Unfortunately we need 3 registers to do S32C1I (data,addr,SCOMPARE1) so + // we need to save to _MemErrorSave: + movi a0, _MemErrorSave + s32i a4, a0, 0 // save a4 + l32i a4, a2, 0 // load data (re-correct) + rsr a0, SCOMPARE1 // save SCOMPARE1 + wsr a4, SCOMPARE1 + s32c1i a4, a2, 0 // store if still contains same value (else other store corrected error) + movi a4, _MemErrorSave + wsr a0, SCOMPARE1 // restore SCOMPARE1 + l32i a4, a4, 0 // restore a4 + j 2f +.L_instram: +# endif + l32i a0, a2, 0 // load data (re-correct) + s32i a0, a2, 0 // store data to correct ECC bits +2: xsr a2, MEVADDR +# endif /* HAVE_LOCAL_RAM */ +.L_done: + rsr a0, MESAVE + rfme + + + // Weak reference: if unresolved, links okay but with zero value: + .weak _xtos_merr_hook_fatal_dme +.L_fatal_dme: + // Fatal (unrecoverable) error, double memory exception + movi a0, _xtos_merr_hook_fatal_dme +1: beqz a0, 1b // fatal double memory error, no hook, so infinite loop + jx a0 // jump to user hook, if present + + +# if HAVE_LOCAL_RAM + // Weak reference: if unresolved, links okay but with zero value: + .weak _xtos_merr_hook_uncorrectable_local +.L_uncorrectable_local: + // Fatal (unrecoverable) error in IRAM or DRAM: parity or uncorrectable ECC error + movi a0, _xtos_merr_hook_uncorrectable_local +1: beqz a0, 1b // fatal memory error, no hook provided, so infinite loop + jx a0 // jump to user hook, if present +# endif + + +# if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0 +.L_cache: + // Error in one of the caches. +# endif + +# if XCHAL_ICACHE_SIZE > 0 +# if XCHAL_DCACHE_SIZE > 0 + bbsi.l a0, MESR_MEMTYPE_SHIFT, .L_dcache // branch if data cache error +# endif + // Error in the instruction cache. + bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_icache_noncorr // branch if uncorrectable + // Correctable error in the instruction cache. + xsr a2, MEVADDR + // TODO FIXME: remove these 5 lines if waynum is in MEVADDR!? by using III if tag and IHI otherwise!?!?!?: +# if XCHAL_ICACHE_WAYS > 1 + extui a0, a0, MESR_WAYNUM_SHIFT, 2 + slli a0, a0, ICACHE_WAYWIDTH + slli a2, a2, 32 - ICACHE_WAYWIDTH + srli a2, a2, 32 - ICACHE_WAYWIDTH + or a2, a2, a0 +# endif + iii a2, 0 // invalidate line (whole set!) if not locked +# if XCHAL_ICACHE_LINE_LOCKABLE + // III has no effect if the line is locked; for that case, need to do more: + lict a0, a2 + bbci.l a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_done // branch if unlocked + // Correctable error in a locked instruction cache line. + // Fix both tag and one word, quicker than figuring out whether error is in tag or data: + sict a0, a2 // fix tag + licw a0, a2 + sicw a0, a2 // fix data word +# endif +.L_icache_done: + xsr a2, MEVADDR + j .L_done + +.L_icache_noncorr: + // Non-correctable error in the instruction cache. + bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_icache_tag_noncorr // branch if tag error + // Non-correctable error in the instruction cache data. + // Just invalidate the line if we can. +# if XCHAL_ICACHE_LINE_LOCKABLE + // If locked, need a different fix sequence. + xsr a2, MEVADDR + +# if XCHAL_ICACHE_WAYS > 1 + // This sequence is shorter, but does not retain original MEVADDR so + // prevents subsequent use of instructions requiring a virtual address + // (such as LICW, IPFL, etc): +// extui a0, a0, MESR_WAYNUM_SHIFT, 2 +// slli a0, a0, ICACHE_WAYWIDTH +// slli a2, a2, 32 - ICACHE_WAYWIDTH +// srli a2, a2, 32 - ICACHE_WAYWIDTH +// or a2, a2, a0 + + extui a0, a0, MESR_WAYNUM_SHIFT, 2 // id of way with mem error + slli a0, a0, ICACHE_WAYWIDTH + xor a0, a2, a0 // xor corresponding bits of addr + extui a0, a0, ICACHE_WAYWIDTH, 2 // take 2 xor'ed way bits + or a2, a2, a0 // save them at bottom of addr + slli a0, a0, ICACHE_WAYWIDTH + xor a2, a2, a0 // and change 2 way bits of addr +# endif + lict a0, a2 + bbsi.l a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_locked_uncor // branch if locked + // Cache line is not locked, just invalidate: +# if XCHAL_ICACHE_WAYS > 1 + iii a2, 0 +# else + ihi a2, 0 +# endif + j .L_icache_done + + // NOTE: we don't use the LICW/SICW sequence below unless the line is locked, + // otherwise the i-cache line might get replaced between LICW and SICW + // (if we're not extremely careful), which would be disastrous. + // Also, for locked lines, LICW/SICW is much safer than IHU/IHI/IPFL + // because it doesn't leave a window where the line is unlocked; + // however, if the error is non-correctable, we have no choice. + +.L_icache_locked_uncor: + // If locked and uncorrectable however, the only recourse is relocking. + // So we need to recover the virtual address so we can do IPFL. + // Note: can't use MEPC instead of MEVADDR, because (a) it might not + // point to the correct cache line, and (b) it might be completely wrong + // in the case where the mem error happened e.g. during an LICW or IPFL. +# if XCHAL_ICACHE_WAYS > 1 + // Recover virtual address in a2: + extui a0, a2, 0, 2 // get saved xor'ed bits at bottom + slli a0, a0, ICACHE_WAYWIDTH // line them up + xor a2, a2, a0 // restore original MEVADDR +# endif + ihu a2, 0 // unlock line + ihi a2, 0 // invalidate line + ipfl a2, 0 // refetch-and-lock the line + j .L_icache_done +# else /* LOCKABLE */ + rsr a0, MEVADDR + ihi a0, 0 // invalidate that cache line + j .L_done +# endif /* LOCKABLE */ + +.L_icache_tag_noncorr: + // Non-correctable error in the instruction cache tag. + // Just invalidate the tag or the entire set. +# if XCHAL_ICACHE_LINE_LOCKABLE + // Note: can't use either IIU or III, as these don't write the entire tag, + // so they'll get the exception again. So, have to use SICT. +# if XCHAL_ICACHE_WAYS > 1 + // TODO FIXME: avoid this 8-line alternative if waynum is in MEVADDR!?: + xsr a2, MEVADDR + extui a0, a0, MESR_WAYNUM_SHIFT, 2 + slli a0, a0, ICACHE_WAYWIDTH + slli a2, a2, 32 - ICACHE_WAYWIDTH + srli a2, a2, 32 - ICACHE_WAYWIDTH + or a2, a2, a0 + iiu a2, 0 // unlock line ==> also invalidates! (I-side only) + xsr a2, MEVADDR +# else + rsr a0, MEVADDR + iiu a0, 0 // unlock line ==> also invalidates! (I-side only) +# endif + // If line was locked, can't recover lock state, need external info to recover. + // User can provide an assembler hook routine _xtos_merr_hook_icache_relock + // to relock the icache at the index in a2: + // - any number of lines might still be locked at that index, + // including all of them + // - no stack is provided, a0 must be used as starting point to + // load a save area and saved registers as necessary + // - unless routine just does ret (i.e. does not modify any + // register, only possible if it does nothing), it needs to + // return by restoring all registers it modified, ending with: + // rsr a0, MESAVE + // rfme + // CAVEAT EMPTOR: this hook mechanism is subject to change. + .weak _xtos_merr_hook_icache_relock // if unresolved, links with zero value + movi a0, _xtos_merr_hook_icache_relock +1: beqz a0, 1b // if no hook to recover lock state on icache tag mem error, loop forever + callx0 a0 // invoke user hook to relock i-cache (index in MEVADDR) +# else + rsr a0, MEVADDR + iii a0, 0 // invalidate entire set +# endif + j .L_done +# endif /* have ICACHE */ + + +# if XCHAL_DCACHE_SIZE > 0 +# if XCHAL_ICACHE_SIZE > 0 +.L_dcache: +# endif + // Error in the data cache. +# if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE + bbsi.l a0, MESR_ERRTYPE_SHIFT, .L_dcache_noncorr // branch if uncorrectable + // Uncorrectable error on a writeback dcache might be unrecoverable: +# endif + bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag // branch if tag error + // Error in the data cache data (correctable, or non-correctable in writethru+unlockable cache). + // MEVADDR always a real vaddr here; might point to cache-isolate mode area though. +# if XCHAL_DCACHE_LINE_LOCKABLE + // Correctable error on lockable dcache data. + // If locked, need to refetch the line (or load/store its contents, which is less safe): + xsr a2, MEVADDR +# if XCHAL_DCACHE_WAYS > 1 + // Need some extra computation to get the correct dcache way's tag: + movi a0, _MemErrorSave + s32i a4, a0, 0 // save a4 + s32i a5, a0, 4 // save a5 + rsr a4, MESR + extui a4, a4, MESR_WAYNUM_SHIFT, 2 + slli a4, a4, DCACHE_WAYWIDTH + slli a5, a2, 32 - DCACHE_WAYWIDTH + srli a5, a5, 32 - DCACHE_WAYWIDTH + add a4, a4, a5 + mov a5, a0 + ldct a0, a4 + l32i a4, a5, 0 // restore a4 + l32i a5, a5, 4 // restore a5 +# else + ldct a0, a2 +# endif + // FIXME: if castout, a2 is a physical address! doesn't work with any address translation. +# if 0 /* translation */ + movi a4, _xtos_vmap_vaddr // FIXME: do we need two variables for full MMU? +1: beqz a4, 1b // if no vaddr to use, loop forever (FIXME: caxlt: could assume V==P) + rdtlb1 a5, a4 // save current contents + ... clear lower bits of a4 ... + xx = some function of a2 + wdtlb xx, a4 + a2 = virtual address, i.e. some function of a2 and a4 ... + ... do the sequence below ... + ... + wdtlb a5, a4 // restore TLB entry +# endif + // NOTE: the following sequence leaves the line temporarily unlocked, if locked. + // We assume NMI handlers don't lock lines or rely on their being locked. + // We could have used "l32i a0,a2,0; s32i a0,a2,0" but that's not atomic on the data. + dhu a2, 0 // unlock the cache line, if locked + dhwbi a2, 0 // writeback and invalidate cache line + bbci.l a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f + dpfl a2, 0 // re-prefetch-and-lock the cache line +1: xsr a2, MEVADDR +# else /* LOCKABLE */ + // Error in unlockable data cache data (correctable, or non-correctable in writethru cache). + rsr a0, MEVADDR + // USELESS NOTE: if writethru dcache and NMI handlers don't store to this, we could use DHI instead: + // FIXME: if castout, a0 is a physical address! doesn't work with any address translation. + dhwbi a0, 0 // writeback (if correctable) and invalidate that cache line +# endif /* LOCKABLE */ + j .L_done + +.L_dcache_tag: + // Error in data cache tag (correctable, or non-correctable in writethru+unlockable cache). + // MEVADDR only contains cache index here (not waynum), don't expect a vaddr (the ISA + // says upper bits are undefined; actual hw does put a vaddr, but in future might not). + // Whether or not correctable, just invalidate the particular way's line: + xsr a2, MEVADDR + // NOTE: could remove these 5 lines if hw were designed with waynum in MEVADDR (but is not): +# if XCHAL_DCACHE_WAYS > 1 + extui a0, a0, MESR_WAYNUM_SHIFT, 2 + slli a0, a0, DCACHE_WAYWIDTH + slli a2, a2, 32 - DCACHE_WAYWIDTH + srli a2, a2, 32 - DCACHE_WAYWIDTH + or a2, a2, a0 +# endif +# if XCHAL_DCACHE_LINE_LOCKABLE + ldct a0, a2 // invalidate and unlock that cache tag + bbci.l a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f // branch if not locked + sdct a0, a2 // if locked, this safely writes whole tag +# endif +1: diwbi a2, 0 // writeback (if correctable) and invalidate the line + xsr a2, MEVADDR + j .L_done + + + +# if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE +.L_dcache_noncorr: + // Uncorrectable error on a (writeback and/or lockable) data cache. +# if XCHAL_DCACHE_IS_WRITEBACK + // On tag errors we don't know whether the line is dirty, so this is unrecoverable: + bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_uncorrectable_dtag // branch if tag error + // Castouts are by definition dirty, uncorrectable errors on these are unrecoverable: + bbsi.l a0, MESR_ACCTYPE_SHIFT, .L_uncorrectable_dirty // branch if castout + // Note: could still be an error on dirty dcache data, also unrecoverable. +# else + bbsi.l a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag_noncorr // branch if tag error +# endif + // Uncorrectable error in dcache data. + // May be dirty or locked, so get tag to find out. + xsr a2, MEVADDR +# if XCHAL_DCACHE_WAYS > 1 + extui a0, a0, MESR_WAYNUM_SHIFT, 2 // id of way with mem error + slli a0, a0, DCACHE_WAYWIDTH + xor a0, a2, a0 // xor corresponding bits of addr + extui a0, a0, DCACHE_WAYWIDTH, 2 // take 2 xor'ed way bits + or a2, a2, a0 // save them at bottom of addr + slli a0, a0, DCACHE_WAYWIDTH + xor a2, a2, a0 // and change 2 way bits of addr +# endif + ldct a0, a2 // get dcache tag +# if XCHAL_DCACHE_IS_WRITEBACK + bbsi.l a0, XCHAL_DCACHE_TAG_D_SHIFT, .L_uncorrectable_dirty_2 // branch if dirty +# endif + // Data cache line is clean. +# if XCHAL_DCACHE_LINE_LOCKABLE + bbsi.l a0, XCHAL_DCACHE_TAG_L_SHIFT, .L_dcache_nc_locked +# endif + // Data cache line is clean and unlocked. Just invalidate it. + // FIXME: any stores to this line by an NMI handler will be lost. + // On the other hand, if we use DHWBI, any stores by an NMI handler + // that don't happen to fix the error result in an unrecoverable castout. + // +# if XCHAL_ICACHE_WAYS > 1 + // Recover virtual address in a2: + extui a0, a2, 0, 2 // get saved xor'ed bits at bottom + slli a0, a0, ICACHE_WAYWIDTH // line them up + xor a2, a2, a0 // restore original MEVADDR +# endif + dhi a2, 0 // invalidate that data cache line + xsr a2, MEVADDR + j .L_done + +# if XCHAL_DCACHE_LINE_LOCKABLE +.L_dcache_nc_locked: +# if XCHAL_ICACHE_WAYS > 1 + // Recover virtual address in a2: + extui a0, a2, 0, 2 // get saved xor'ed bits at bottom + slli a0, a0, ICACHE_WAYWIDTH // line them up + xor a2, a2, a0 // restore original MEVADDR +# endif + // Unlock, invalidate, and relock it: + dhu a2, 0 // unlock that data cache line + dhi a2, 0 // invalidate that data cache line + dpfl a2, 0 // prefetch-and-lock the line again + xsr a2, MEVADDR + j .L_done +# endif + +# if XCHAL_DCACHE_IS_WRITEBACK + // Weak reference: if unresolved, links okay but with zero value: + .weak _xtos_merr_hook_uncor_dtag +.L_uncorrectable_dtag: + // Fatal (unrecoverable) error in dcache tag (maybe dirty): parity or uncorrectable ECC error + movi a0, _xtos_merr_hook_uncor_dtag +1: beqz a0, 1b // fatal non-corr dcache tag, no hook, so infinite loop + jx a0 // jump to user hook, if present + + // Weak reference: if unresolved, links okay but with zero value: + .weak _xtos_merr_hook_uncor_dirty +.L_uncorrectable_dirty_2: + xsr a2, MEVADDR +.L_uncorrectable_dirty: + // Fatal (unrecoverable) error, parity or non-correctable ECC error on dirty cache data + movi a0, _xtos_merr_hook_uncor_dirty +1: beqz a0, 1b // fatal non-corr dirty cache line, no hook, so infinite loop + jx a0 // jump to user hook, if present +# else +.L_dcache_tag_noncorr: + // Uncorrectable error on a lockable writethru data cache tag. + // We have to invalidate the line, but that way we lose the lock bit. + // Provide a hook to relock if necessary (using knowledge outside this module + // about what needs to be locked). See _xtos_merr_hook_icache_relock for details. + // CAVEAT EMPTOR: this hook mechanism is subject to change. + .weak _xtos_merr_hook_dcache_relock // if unresolved, links with zero value + movi a0, _xtos_merr_hook_dcache_relock +1: beqz a0, 1b // if no hook to recover lock state on dcache tag mem error, loop forever + callx0 a0 // invoke user hook to relock d-cache (index in MEVADDR) + j .L_done +# endif + +# endif /* DCACHE IS WRITEBACK || LINE_LOCKABLE */ + +# endif /* have DCACHE */ + + .size _MemErrorHandler, . - _MemErrorHandler + + + +# endif /* splitting */ +#endif /* XCHAL_HAVE_MEM_ECC_PARITY */ +