/*1* arch/sh/kernel/cpu/sh5/entry.S2*3* Copyright (C) 2000, 2001 Paolo Alberelli4* Copyright (C) 2004 - 2008 Paul Mundt5* Copyright (C) 2003, 2004 Richard Curnow6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/11#include <linux/errno.h>12#include <linux/init.h>13#include <linux/sys.h>14#include <cpu/registers.h>15#include <asm/processor.h>16#include <asm/unistd.h>17#include <asm/thread_info.h>18#include <asm/asm-offsets.h>1920/*21* SR fields.22*/23#define SR_ASID_MASK 0x00ff000024#define SR_FD_MASK 0x0000800025#define SR_SS 0x0800000026#define SR_BL 0x1000000027#define SR_MD 0x400000002829/*30* Event code.31*/32#define EVENT_INTERRUPT 033#define EVENT_FAULT_TLB 134#define EVENT_FAULT_NOT_TLB 235#define EVENT_DEBUG 33637/* EXPEVT values */38#define RESET_CAUSE 0x2039#define DEBUGSS_CAUSE 0x9804041/*42* Frame layout. Quad index.43*/44#define FRAME_T(x) FRAME_TBASE+(x*8)45#define FRAME_R(x) FRAME_RBASE+(x*8)46#define FRAME_S(x) FRAME_SBASE+(x*8)47#define FSPC 048#define FSSR 149#define FSYSCALL_ID 25051/* Arrange the save frame to be a multiple of 32 bytes long */52#define FRAME_SBASE 053#define FRAME_RBASE (FRAME_SBASE+(3*8)) /* SYSCALL_ID - SSR - SPC */54#define FRAME_TBASE (FRAME_RBASE+(63*8)) /* r0 - r62 */55#define FRAME_PBASE (FRAME_TBASE+(8*8)) /* tr0 -tr7 */56#define FRAME_SIZE (FRAME_PBASE+(2*8)) /* pad0-pad1 */5758#define FP_FRAME_SIZE FP_FRAME_BASE+(33*8) /* dr0 - dr31 + fpscr */59#define FP_FRAME_BASE 06061#define SAVED_R2 0*862#define SAVED_R3 1*863#define SAVED_R4 2*864#define SAVED_R5 3*865#define SAVED_R18 4*866#define SAVED_R6 5*867#define SAVED_TR0 6*86869/* These are the registers saved in the TLB path that aren't saved in the first70level of the normal one. */71#define TLB_SAVED_R25 7*872#define TLB_SAVED_TR1 8*873#define TLB_SAVED_TR2 9*874#define TLB_SAVED_TR3 10*875#define TLB_SAVED_TR4 11*876/* Save R0/R1 : PT-migrating compiler currently dishounours -ffixed-r0 and -ffixed-r1 causing77breakage otherwise. */78#define TLB_SAVED_R0 12*879#define TLB_SAVED_R1 13*88081#define CLI() \82getcon SR, r6; \83ori r6, 0xf0, r6; \84putcon r6, SR;8586#define STI() \87getcon SR, r6; \88andi r6, ~0xf0, r6; \89putcon r6, SR;9091#ifdef CONFIG_PREEMPT92# define preempt_stop() CLI()93#else94# define preempt_stop()95# define resume_kernel restore_all96#endif9798.section .data, "aw"99100#define FAST_TLBMISS_STACK_CACHELINES 4101#define FAST_TLBMISS_STACK_QUADWORDS (4*FAST_TLBMISS_STACK_CACHELINES)102103/* Register back-up area for all exceptions */104.balign 32105/* Allow for 16 quadwords to be pushed by fast tlbmiss handling106* register saves etc. */107.fill FAST_TLBMISS_STACK_QUADWORDS, 8, 0x0108/* This is 32 byte aligned by construction */109/* Register back-up area for all exceptions */110reg_save_area:111.quad 0112.quad 0113.quad 0114.quad 0115116.quad 0117.quad 0118.quad 0119.quad 0120121.quad 0122.quad 0123.quad 0124.quad 0125126.quad 0127.quad 0128129/* Save area for RESVEC exceptions. We cannot use reg_save_area because of130* reentrancy. Note this area may be accessed via physical address.131* Align so this fits a whole single cache line, for ease of purging.132*/133.balign 32,0,32134resvec_save_area:135.quad 0136.quad 0137.quad 0138.quad 0139.quad 0140.balign 32,0,32141142/* Jump table of 3rd level handlers */143trap_jtable:144.long do_exception_error /* 0x000 */145.long do_exception_error /* 0x020 */146#ifdef CONFIG_MMU147.long tlb_miss_load /* 0x040 */148.long tlb_miss_store /* 0x060 */149#else150.long do_exception_error151.long do_exception_error152#endif153! ARTIFICIAL pseudo-EXPEVT setting154.long do_debug_interrupt /* 0x080 */155#ifdef CONFIG_MMU156.long tlb_miss_load /* 0x0A0 */157.long tlb_miss_store /* 0x0C0 */158#else159.long do_exception_error160.long do_exception_error161#endif162.long do_address_error_load /* 0x0E0 */163.long do_address_error_store /* 0x100 */164#ifdef CONFIG_SH_FPU165.long do_fpu_error /* 0x120 */166#else167.long do_exception_error /* 0x120 */168#endif169.long do_exception_error /* 0x140 */170.long system_call /* 0x160 */171.long do_reserved_inst /* 0x180 */172.long do_illegal_slot_inst /* 0x1A0 */173.long do_exception_error /* 0x1C0 - NMI */174.long do_exception_error /* 0x1E0 */175.rept 15176.long do_IRQ /* 0x200 - 0x3C0 */177.endr178.long do_exception_error /* 0x3E0 */179.rept 32180.long do_IRQ /* 0x400 - 0x7E0 */181.endr182.long fpu_error_or_IRQA /* 0x800 */183.long fpu_error_or_IRQB /* 0x820 */184.long do_IRQ /* 0x840 */185.long do_IRQ /* 0x860 */186.rept 6187.long do_exception_error /* 0x880 - 0x920 */188.endr189.long breakpoint_trap_handler /* 0x940 */190.long do_exception_error /* 0x960 */191.long do_single_step /* 0x980 */192193.rept 3194.long do_exception_error /* 0x9A0 - 0x9E0 */195.endr196.long do_IRQ /* 0xA00 */197.long do_IRQ /* 0xA20 */198#ifdef CONFIG_MMU199.long itlb_miss_or_IRQ /* 0xA40 */200#else201.long do_IRQ202#endif203.long do_IRQ /* 0xA60 */204.long do_IRQ /* 0xA80 */205#ifdef CONFIG_MMU206.long itlb_miss_or_IRQ /* 0xAA0 */207#else208.long do_IRQ209#endif210.long do_exception_error /* 0xAC0 */211.long do_address_error_exec /* 0xAE0 */212.rept 8213.long do_exception_error /* 0xB00 - 0xBE0 */214.endr215.rept 18216.long do_IRQ /* 0xC00 - 0xE20 */217.endr218219.section .text64, "ax"220221/*222* --- Exception/Interrupt/Event Handling Section223*/224225/*226* VBR and RESVEC blocks.227*228* First level handler for VBR-based exceptions.229*230* To avoid waste of space, align to the maximum text block size.231* This is assumed to be at most 128 bytes or 32 instructions.232* DO NOT EXCEED 32 instructions on the first level handlers !233*234* Also note that RESVEC is contained within the VBR block235* where the room left (1KB - TEXT_SIZE) allows placing236* the RESVEC block (at most 512B + TEXT_SIZE).237*238* So first (and only) level handler for RESVEC-based exceptions.239*240* Where the fault/interrupt is handled (not_a_tlb_miss, tlb_miss241* and interrupt) we are a lot tight with register space until242* saving onto the stack frame, which is done in handle_exception().243*244*/245246#define TEXT_SIZE 128247#define BLOCK_SIZE 1664 /* Dynamic check, 13*128 */248249.balign TEXT_SIZE250LVBR_block:251.space 256, 0 /* Power-on class handler, */252/* not required here */253not_a_tlb_miss:254synco /* TAKum03020 (but probably a good idea anyway.) */255/* Save original stack pointer into KCR1 */256putcon SP, KCR1257258/* Save other original registers into reg_save_area */259movi reg_save_area, SP260st.q SP, SAVED_R2, r2261st.q SP, SAVED_R3, r3262st.q SP, SAVED_R4, r4263st.q SP, SAVED_R5, r5264st.q SP, SAVED_R6, r6265st.q SP, SAVED_R18, r18266gettr tr0, r3267st.q SP, SAVED_TR0, r3268269/* Set args for Non-debug, Not a TLB miss class handler */270getcon EXPEVT, r2271movi ret_from_exception, r3272ori r3, 1, r3273movi EVENT_FAULT_NOT_TLB, r4274or SP, ZERO, r5275getcon KCR1, SP276pta handle_exception, tr0277blink tr0, ZERO278279.balign 256280! VBR+0x200281nop282.balign 256283! VBR+0x300284nop285.balign 256286/*287* Instead of the natural .balign 1024 place RESVEC here288* respecting the final 1KB alignment.289*/290.balign TEXT_SIZE291/*292* Instead of '.space 1024-TEXT_SIZE' place the RESVEC293* block making sure the final alignment is correct.294*/295#ifdef CONFIG_MMU296tlb_miss:297synco /* TAKum03020 (but probably a good idea anyway.) */298putcon SP, KCR1299movi reg_save_area, SP300/* SP is guaranteed 32-byte aligned. */301st.q SP, TLB_SAVED_R0 , r0302st.q SP, TLB_SAVED_R1 , r1303st.q SP, SAVED_R2 , r2304st.q SP, SAVED_R3 , r3305st.q SP, SAVED_R4 , r4306st.q SP, SAVED_R5 , r5307st.q SP, SAVED_R6 , r6308st.q SP, SAVED_R18, r18309310/* Save R25 for safety; as/ld may want to use it to achieve the call to311* the code in mm/tlbmiss.c */312st.q SP, TLB_SAVED_R25, r25313gettr tr0, r2314gettr tr1, r3315gettr tr2, r4316gettr tr3, r5317gettr tr4, r18318st.q SP, SAVED_TR0 , r2319st.q SP, TLB_SAVED_TR1 , r3320st.q SP, TLB_SAVED_TR2 , r4321st.q SP, TLB_SAVED_TR3 , r5322st.q SP, TLB_SAVED_TR4 , r18323324pt do_fast_page_fault, tr0325getcon SSR, r2326getcon EXPEVT, r3327getcon TEA, r4328shlri r2, 30, r2329andi r2, 1, r2 /* r2 = SSR.MD */330blink tr0, LINK331332pt fixup_to_invoke_general_handler, tr1333334/* If the fast path handler fixed the fault, just drop through quickly335to the restore code right away to return to the excepting context.336*/337beqi/u r2, 0, tr1338339fast_tlb_miss_restore:340ld.q SP, SAVED_TR0, r2341ld.q SP, TLB_SAVED_TR1, r3342ld.q SP, TLB_SAVED_TR2, r4343344ld.q SP, TLB_SAVED_TR3, r5345ld.q SP, TLB_SAVED_TR4, r18346347ptabs r2, tr0348ptabs r3, tr1349ptabs r4, tr2350ptabs r5, tr3351ptabs r18, tr4352353ld.q SP, TLB_SAVED_R0, r0354ld.q SP, TLB_SAVED_R1, r1355ld.q SP, SAVED_R2, r2356ld.q SP, SAVED_R3, r3357ld.q SP, SAVED_R4, r4358ld.q SP, SAVED_R5, r5359ld.q SP, SAVED_R6, r6360ld.q SP, SAVED_R18, r18361ld.q SP, TLB_SAVED_R25, r25362363getcon KCR1, SP364rte365nop /* for safety, in case the code is run on sh5-101 cut1.x */366367fixup_to_invoke_general_handler:368369/* OK, new method. Restore stuff that's not expected to get saved into370the 'first-level' reg save area, then just fall through to setting371up the registers and calling the second-level handler. */372373/* 2nd level expects r2,3,4,5,6,18,tr0 to be saved. So we must restore374r25,tr1-4 and save r6 to get into the right state. */375376ld.q SP, TLB_SAVED_TR1, r3377ld.q SP, TLB_SAVED_TR2, r4378ld.q SP, TLB_SAVED_TR3, r5379ld.q SP, TLB_SAVED_TR4, r18380ld.q SP, TLB_SAVED_R25, r25381382ld.q SP, TLB_SAVED_R0, r0383ld.q SP, TLB_SAVED_R1, r1384385ptabs/u r3, tr1386ptabs/u r4, tr2387ptabs/u r5, tr3388ptabs/u r18, tr4389390/* Set args for Non-debug, TLB miss class handler */391getcon EXPEVT, r2392movi ret_from_exception, r3393ori r3, 1, r3394movi EVENT_FAULT_TLB, r4395or SP, ZERO, r5396getcon KCR1, SP397pta handle_exception, tr0398blink tr0, ZERO399#else /* CONFIG_MMU */400.balign 256401#endif402403/* NB TAKE GREAT CARE HERE TO ENSURE THAT THE INTERRUPT CODE404DOES END UP AT VBR+0x600 */405nop406nop407nop408nop409nop410nop411412.balign 256413/* VBR + 0x600 */414415interrupt:416synco /* TAKum03020 (but probably a good idea anyway.) */417/* Save original stack pointer into KCR1 */418putcon SP, KCR1419420/* Save other original registers into reg_save_area */421movi reg_save_area, SP422st.q SP, SAVED_R2, r2423st.q SP, SAVED_R3, r3424st.q SP, SAVED_R4, r4425st.q SP, SAVED_R5, r5426st.q SP, SAVED_R6, r6427st.q SP, SAVED_R18, r18428gettr tr0, r3429st.q SP, SAVED_TR0, r3430431/* Set args for interrupt class handler */432getcon INTEVT, r2433movi ret_from_irq, r3434ori r3, 1, r3435movi EVENT_INTERRUPT, r4436or SP, ZERO, r5437getcon KCR1, SP438pta handle_exception, tr0439blink tr0, ZERO440.balign TEXT_SIZE /* let's waste the bare minimum */441442LVBR_block_end: /* Marker. Used for total checking */443444.balign 256445LRESVEC_block:446/* Panic handler. Called with MMU off. Possible causes/actions:447* - Reset: Jump to program start.448* - Single Step: Turn off Single Step & return.449* - Others: Call panic handler, passing PC as arg.450* (this may need to be extended...)451*/452reset_or_panic:453synco /* TAKum03020 (but probably a good idea anyway.) */454putcon SP, DCR455/* First save r0-1 and tr0, as we need to use these */456movi resvec_save_area-CONFIG_PAGE_OFFSET, SP457st.q SP, 0, r0458st.q SP, 8, r1459gettr tr0, r0460st.q SP, 32, r0461462/* Check cause */463getcon EXPEVT, r0464movi RESET_CAUSE, r1465sub r1, r0, r1 /* r1=0 if reset */466movi _stext-CONFIG_PAGE_OFFSET, r0467ori r0, 1, r0468ptabs r0, tr0469beqi r1, 0, tr0 /* Jump to start address if reset */470471getcon EXPEVT, r0472movi DEBUGSS_CAUSE, r1473sub r1, r0, r1 /* r1=0 if single step */474pta single_step_panic, tr0475beqi r1, 0, tr0 /* jump if single step */476477/* Now jump to where we save the registers. */478movi panic_stash_regs-CONFIG_PAGE_OFFSET, r1479ptabs r1, tr0480blink tr0, r63481482single_step_panic:483/* We are in a handler with Single Step set. We need to resume the484* handler, by turning on MMU & turning off Single Step. */485getcon SSR, r0486movi SR_MMU, r1487or r0, r1, r0488movi ~SR_SS, r1489and r0, r1, r0490putcon r0, SSR491/* Restore EXPEVT, as the rte won't do this */492getcon PEXPEVT, r0493putcon r0, EXPEVT494/* Restore regs */495ld.q SP, 32, r0496ptabs r0, tr0497ld.q SP, 0, r0498ld.q SP, 8, r1499getcon DCR, SP500synco501rte502503504.balign 256505debug_exception:506synco /* TAKum03020 (but probably a good idea anyway.) */507/*508* Single step/software_break_point first level handler.509* Called with MMU off, so the first thing we do is enable it510* by doing an rte with appropriate SSR.511*/512putcon SP, DCR513/* Save SSR & SPC, together with R0 & R1, as we need to use 2 regs. */514movi resvec_save_area-CONFIG_PAGE_OFFSET, SP515516/* With the MMU off, we are bypassing the cache, so purge any517* data that will be made stale by the following stores.518*/519ocbp SP, 0520synco521522st.q SP, 0, r0523st.q SP, 8, r1524getcon SPC, r0525st.q SP, 16, r0526getcon SSR, r0527st.q SP, 24, r0528529/* Enable MMU, block exceptions, set priv mode, disable single step */530movi SR_MMU | SR_BL | SR_MD, r1531or r0, r1, r0532movi ~SR_SS, r1533and r0, r1, r0534putcon r0, SSR535/* Force control to debug_exception_2 when rte is executed */536movi debug_exeception_2, r0537ori r0, 1, r0 /* force SHmedia, just in case */538putcon r0, SPC539getcon DCR, SP540synco541rte542debug_exeception_2:543/* Restore saved regs */544putcon SP, KCR1545movi resvec_save_area, SP546ld.q SP, 24, r0547putcon r0, SSR548ld.q SP, 16, r0549putcon r0, SPC550ld.q SP, 0, r0551ld.q SP, 8, r1552553/* Save other original registers into reg_save_area */554movi reg_save_area, SP555st.q SP, SAVED_R2, r2556st.q SP, SAVED_R3, r3557st.q SP, SAVED_R4, r4558st.q SP, SAVED_R5, r5559st.q SP, SAVED_R6, r6560st.q SP, SAVED_R18, r18561gettr tr0, r3562st.q SP, SAVED_TR0, r3563564/* Set args for debug class handler */565getcon EXPEVT, r2566movi ret_from_exception, r3567ori r3, 1, r3568movi EVENT_DEBUG, r4569or SP, ZERO, r5570getcon KCR1, SP571pta handle_exception, tr0572blink tr0, ZERO573574.balign 256575debug_interrupt:576/* !!! WE COME HERE IN REAL MODE !!! */577/* Hook-up debug interrupt to allow various debugging options to be578* hooked into its handler. */579/* Save original stack pointer into KCR1 */580synco581putcon SP, KCR1582movi resvec_save_area-CONFIG_PAGE_OFFSET, SP583ocbp SP, 0584ocbp SP, 32585synco586587/* Save other original registers into reg_save_area thru real addresses */588st.q SP, SAVED_R2, r2589st.q SP, SAVED_R3, r3590st.q SP, SAVED_R4, r4591st.q SP, SAVED_R5, r5592st.q SP, SAVED_R6, r6593st.q SP, SAVED_R18, r18594gettr tr0, r3595st.q SP, SAVED_TR0, r3596597/* move (spc,ssr)->(pspc,pssr). The rte will shift598them back again, so that they look like the originals599as far as the real handler code is concerned. */600getcon spc, r6601putcon r6, pspc602getcon ssr, r6603putcon r6, pssr604605! construct useful SR for handle_exception606movi 3, r6607shlli r6, 30, r6608getcon sr, r18609or r18, r6, r6610putcon r6, ssr611612! SSR is now the current SR with the MD and MMU bits set613! i.e. the rte will switch back to priv mode and put614! the mmu back on615616! construct spc617movi handle_exception, r18618ori r18, 1, r18 ! for safety (do we need this?)619putcon r18, spc620621/* Set args for Non-debug, Not a TLB miss class handler */622623! EXPEVT==0x80 is unused, so 'steal' this value to put the624! debug interrupt handler in the vectoring table625movi 0x80, r2626movi ret_from_exception, r3627ori r3, 1, r3628movi EVENT_FAULT_NOT_TLB, r4629630or SP, ZERO, r5631movi CONFIG_PAGE_OFFSET, r6632add r6, r5, r5633getcon KCR1, SP634635synco ! for safety636rte ! -> handle_exception, switch back to priv mode again637638LRESVEC_block_end: /* Marker. Unused. */639640.balign TEXT_SIZE641642/*643* Second level handler for VBR-based exceptions. Pre-handler.644* In common to all stack-frame sensitive handlers.645*646* Inputs:647* (KCR0) Current [current task union]648* (KCR1) Original SP649* (r2) INTEVT/EXPEVT650* (r3) appropriate return address651* (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault, 3=debug)652* (r5) Pointer to reg_save_area653* (SP) Original SP654*655* Available registers:656* (r6)657* (r18)658* (tr0)659*660*/661handle_exception:662/* Common 2nd level handler. */663664/* First thing we need an appropriate stack pointer */665getcon SSR, r6666shlri r6, 30, r6667andi r6, 1, r6668pta stack_ok, tr0669bne r6, ZERO, tr0 /* Original stack pointer is fine */670671/* Set stack pointer for user fault */672getcon KCR0, SP673movi THREAD_SIZE, r6 /* Point to the end */674add SP, r6, SP675676stack_ok:677678/* DEBUG : check for underflow/overflow of the kernel stack */679pta no_underflow, tr0680getcon KCR0, r6681movi 1024, r18682add r6, r18, r6683bge SP, r6, tr0 ! ? below 1k from bottom of stack : danger zone684685/* Just panic to cause a crash. */686bad_sp:687ld.b r63, 0, r6688nop689690no_underflow:691pta bad_sp, tr0692getcon kcr0, r6693movi THREAD_SIZE, r18694add r18, r6, r6695bgt SP, r6, tr0 ! sp above the stack696697/* Make some room for the BASIC frame. */698movi -(FRAME_SIZE), r6699add SP, r6, SP700701/* Could do this with no stalling if we had another spare register, but the702code below will be OK. */703ld.q r5, SAVED_R2, r6704ld.q r5, SAVED_R3, r18705st.q SP, FRAME_R(2), r6706ld.q r5, SAVED_R4, r6707st.q SP, FRAME_R(3), r18708ld.q r5, SAVED_R5, r18709st.q SP, FRAME_R(4), r6710ld.q r5, SAVED_R6, r6711st.q SP, FRAME_R(5), r18712ld.q r5, SAVED_R18, r18713st.q SP, FRAME_R(6), r6714ld.q r5, SAVED_TR0, r6715st.q SP, FRAME_R(18), r18716st.q SP, FRAME_T(0), r6717718/* Keep old SP around */719getcon KCR1, r6720721/* Save the rest of the general purpose registers */722st.q SP, FRAME_R(0), r0723st.q SP, FRAME_R(1), r1724st.q SP, FRAME_R(7), r7725st.q SP, FRAME_R(8), r8726st.q SP, FRAME_R(9), r9727st.q SP, FRAME_R(10), r10728st.q SP, FRAME_R(11), r11729st.q SP, FRAME_R(12), r12730st.q SP, FRAME_R(13), r13731st.q SP, FRAME_R(14), r14732733/* SP is somewhere else */734st.q SP, FRAME_R(15), r6735736st.q SP, FRAME_R(16), r16737st.q SP, FRAME_R(17), r17738/* r18 is saved earlier. */739st.q SP, FRAME_R(19), r19740st.q SP, FRAME_R(20), r20741st.q SP, FRAME_R(21), r21742st.q SP, FRAME_R(22), r22743st.q SP, FRAME_R(23), r23744st.q SP, FRAME_R(24), r24745st.q SP, FRAME_R(25), r25746st.q SP, FRAME_R(26), r26747st.q SP, FRAME_R(27), r27748st.q SP, FRAME_R(28), r28749st.q SP, FRAME_R(29), r29750st.q SP, FRAME_R(30), r30751st.q SP, FRAME_R(31), r31752st.q SP, FRAME_R(32), r32753st.q SP, FRAME_R(33), r33754st.q SP, FRAME_R(34), r34755st.q SP, FRAME_R(35), r35756st.q SP, FRAME_R(36), r36757st.q SP, FRAME_R(37), r37758st.q SP, FRAME_R(38), r38759st.q SP, FRAME_R(39), r39760st.q SP, FRAME_R(40), r40761st.q SP, FRAME_R(41), r41762st.q SP, FRAME_R(42), r42763st.q SP, FRAME_R(43), r43764st.q SP, FRAME_R(44), r44765st.q SP, FRAME_R(45), r45766st.q SP, FRAME_R(46), r46767st.q SP, FRAME_R(47), r47768st.q SP, FRAME_R(48), r48769st.q SP, FRAME_R(49), r49770st.q SP, FRAME_R(50), r50771st.q SP, FRAME_R(51), r51772st.q SP, FRAME_R(52), r52773st.q SP, FRAME_R(53), r53774st.q SP, FRAME_R(54), r54775st.q SP, FRAME_R(55), r55776st.q SP, FRAME_R(56), r56777st.q SP, FRAME_R(57), r57778st.q SP, FRAME_R(58), r58779st.q SP, FRAME_R(59), r59780st.q SP, FRAME_R(60), r60781st.q SP, FRAME_R(61), r61782st.q SP, FRAME_R(62), r62783784/*785* Save the S* registers.786*/787getcon SSR, r61788st.q SP, FRAME_S(FSSR), r61789getcon SPC, r62790st.q SP, FRAME_S(FSPC), r62791movi -1, r62 /* Reset syscall_nr */792st.q SP, FRAME_S(FSYSCALL_ID), r62793794/* Save the rest of the target registers */795gettr tr1, r6796st.q SP, FRAME_T(1), r6797gettr tr2, r6798st.q SP, FRAME_T(2), r6799gettr tr3, r6800st.q SP, FRAME_T(3), r6801gettr tr4, r6802st.q SP, FRAME_T(4), r6803gettr tr5, r6804st.q SP, FRAME_T(5), r6805gettr tr6, r6806st.q SP, FRAME_T(6), r6807gettr tr7, r6808st.q SP, FRAME_T(7), r6809810! setup FP so that unwinder can wind back through nested kernel mode811! exceptions812add SP, ZERO, r14813814/* For syscall and debug race condition, get TRA now */815getcon TRA, r5816817/* We are in a safe position to turn SR.BL off, but set IMASK=0xf818* Also set FD, to catch FPU usage in the kernel.819*820* [email protected] 29/07/2002821*822* On all SH5-101 revisions it is unsafe to raise the IMASK and at the823* same time change BL from 1->0, as any pending interrupt of a level824* higher than he previous value of IMASK will leak through and be825* taken unexpectedly.826*827* To avoid this we raise the IMASK and then issue another PUTCON to828* enable interrupts.829*/830getcon SR, r6831movi SR_IMASK | SR_FD, r7832or r6, r7, r6833putcon r6, SR834movi SR_UNBLOCK_EXC, r7835and r6, r7, r6836putcon r6, SR837838839/* Now call the appropriate 3rd level handler */840or r3, ZERO, LINK841movi trap_jtable, r3842shlri r2, 3, r2843ldx.l r2, r3, r3844shlri r2, 2, r2845ptabs r3, tr0846or SP, ZERO, r3847blink tr0, ZERO848849/*850* Second level handler for VBR-based exceptions. Post-handlers.851*852* Post-handlers for interrupts (ret_from_irq), exceptions853* (ret_from_exception) and common reentrance doors (restore_all854* to get back to the original context, ret_from_syscall loop to855* check kernel exiting).856*857* ret_with_reschedule and work_notifysig are an inner lables of858* the ret_from_syscall loop.859*860* In common to all stack-frame sensitive handlers.861*862* Inputs:863* (SP) struct pt_regs *, original register's frame pointer (basic)864*865*/866.global ret_from_irq867ret_from_irq:868ld.q SP, FRAME_S(FSSR), r6869shlri r6, 30, r6870andi r6, 1, r6871pta resume_kernel, tr0872bne r6, ZERO, tr0 /* no further checks */873STI()874pta ret_with_reschedule, tr0875blink tr0, ZERO /* Do not check softirqs */876877.global ret_from_exception878ret_from_exception:879preempt_stop()880881ld.q SP, FRAME_S(FSSR), r6882shlri r6, 30, r6883andi r6, 1, r6884pta resume_kernel, tr0885bne r6, ZERO, tr0 /* no further checks */886887/* Check softirqs */888889#ifdef CONFIG_PREEMPT890pta ret_from_syscall, tr0891blink tr0, ZERO892893resume_kernel:894CLI()895896pta restore_all, tr0897898getcon KCR0, r6899ld.l r6, TI_PRE_COUNT, r7900beq/u r7, ZERO, tr0901902need_resched:903ld.l r6, TI_FLAGS, r7904movi (1 << TIF_NEED_RESCHED), r8905and r8, r7, r8906bne r8, ZERO, tr0907908getcon SR, r7909andi r7, 0xf0, r7910bne r7, ZERO, tr0911912movi preempt_schedule_irq, r7913ori r7, 1, r7914ptabs r7, tr1915blink tr1, LINK916917pta need_resched, tr1918blink tr1, ZERO919#endif920921.global ret_from_syscall922ret_from_syscall:923924ret_with_reschedule:925getcon KCR0, r6 ! r6 contains current_thread_info926ld.l r6, TI_FLAGS, r7 ! r7 contains current_thread_info->flags927928movi _TIF_NEED_RESCHED, r8929and r8, r7, r8930pta work_resched, tr0931bne r8, ZERO, tr0932933pta restore_all, tr1934935movi _TIF_SIGPENDING, r8936and r8, r7, r8937pta work_notifysig, tr0938bne r8, ZERO, tr0939940blink tr1, ZERO941942work_resched:943pta ret_from_syscall, tr0944gettr tr0, LINK945movi schedule, r6946ptabs r6, tr0947blink tr0, ZERO /* Call schedule(), return on top */948949work_notifysig:950gettr tr1, LINK951952movi do_notify_resume, r6953ptabs r6, tr0954or SP, ZERO, r2955or r7, ZERO, r3956blink tr0, LINK /* Call do_notify_resume(regs, current_thread_info->flags), return here */957958restore_all:959/* Do prefetches */960961ld.q SP, FRAME_T(0), r6962ld.q SP, FRAME_T(1), r7963ld.q SP, FRAME_T(2), r8964ld.q SP, FRAME_T(3), r9965ptabs r6, tr0966ptabs r7, tr1967ptabs r8, tr2968ptabs r9, tr3969ld.q SP, FRAME_T(4), r6970ld.q SP, FRAME_T(5), r7971ld.q SP, FRAME_T(6), r8972ld.q SP, FRAME_T(7), r9973ptabs r6, tr4974ptabs r7, tr5975ptabs r8, tr6976ptabs r9, tr7977978ld.q SP, FRAME_R(0), r0979ld.q SP, FRAME_R(1), r1980ld.q SP, FRAME_R(2), r2981ld.q SP, FRAME_R(3), r3982ld.q SP, FRAME_R(4), r4983ld.q SP, FRAME_R(5), r5984ld.q SP, FRAME_R(6), r6985ld.q SP, FRAME_R(7), r7986ld.q SP, FRAME_R(8), r8987ld.q SP, FRAME_R(9), r9988ld.q SP, FRAME_R(10), r10989ld.q SP, FRAME_R(11), r11990ld.q SP, FRAME_R(12), r12991ld.q SP, FRAME_R(13), r13992ld.q SP, FRAME_R(14), r14993994ld.q SP, FRAME_R(16), r16995ld.q SP, FRAME_R(17), r17996ld.q SP, FRAME_R(18), r18997ld.q SP, FRAME_R(19), r19998ld.q SP, FRAME_R(20), r20999ld.q SP, FRAME_R(21), r211000ld.q SP, FRAME_R(22), r221001ld.q SP, FRAME_R(23), r231002ld.q SP, FRAME_R(24), r241003ld.q SP, FRAME_R(25), r251004ld.q SP, FRAME_R(26), r261005ld.q SP, FRAME_R(27), r271006ld.q SP, FRAME_R(28), r281007ld.q SP, FRAME_R(29), r291008ld.q SP, FRAME_R(30), r301009ld.q SP, FRAME_R(31), r311010ld.q SP, FRAME_R(32), r321011ld.q SP, FRAME_R(33), r331012ld.q SP, FRAME_R(34), r341013ld.q SP, FRAME_R(35), r351014ld.q SP, FRAME_R(36), r361015ld.q SP, FRAME_R(37), r371016ld.q SP, FRAME_R(38), r381017ld.q SP, FRAME_R(39), r391018ld.q SP, FRAME_R(40), r401019ld.q SP, FRAME_R(41), r411020ld.q SP, FRAME_R(42), r421021ld.q SP, FRAME_R(43), r431022ld.q SP, FRAME_R(44), r441023ld.q SP, FRAME_R(45), r451024ld.q SP, FRAME_R(46), r461025ld.q SP, FRAME_R(47), r471026ld.q SP, FRAME_R(48), r481027ld.q SP, FRAME_R(49), r491028ld.q SP, FRAME_R(50), r501029ld.q SP, FRAME_R(51), r511030ld.q SP, FRAME_R(52), r521031ld.q SP, FRAME_R(53), r531032ld.q SP, FRAME_R(54), r541033ld.q SP, FRAME_R(55), r551034ld.q SP, FRAME_R(56), r561035ld.q SP, FRAME_R(57), r571036ld.q SP, FRAME_R(58), r5810371038getcon SR, r591039movi SR_BLOCK_EXC, r601040or r59, r60, r591041putcon r59, SR /* SR.BL = 1, keep nesting out */1042ld.q SP, FRAME_S(FSSR), r611043ld.q SP, FRAME_S(FSPC), r621044movi SR_ASID_MASK, r601045and r59, r60, r591046andc r61, r60, r61 /* Clear out older ASID */1047or r59, r61, r61 /* Retain current ASID */1048putcon r61, SSR1049putcon r62, SPC10501051/* Ignore FSYSCALL_ID */10521053ld.q SP, FRAME_R(59), r591054ld.q SP, FRAME_R(60), r601055ld.q SP, FRAME_R(61), r611056ld.q SP, FRAME_R(62), r6210571058/* Last touch */1059ld.q SP, FRAME_R(15), SP1060rte1061nop10621063/*1064* Third level handlers for VBR-based exceptions. Adapting args to1065* and/or deflecting to fourth level handlers.1066*1067* Fourth level handlers interface.1068* Most are C-coded handlers directly pointed by the trap_jtable.1069* (Third = Fourth level)1070* Inputs:1071* (r2) fault/interrupt code, entry number (e.g. NMI = 14,1072* IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...)1073* (r3) struct pt_regs *, original register's frame pointer1074* (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault)1075* (r5) TRA control register (for syscall/debug benefit only)1076* (LINK) return address1077* (SP) = r31078*1079* Kernel TLB fault handlers will get a slightly different interface.1080* (r2) struct pt_regs *, original register's frame pointer1081* (r3) writeaccess, whether it's a store fault as opposed to load fault1082* (r4) execaccess, whether it's a ITLB fault as opposed to DTLB fault1083* (r5) Effective Address of fault1084* (LINK) return address1085* (SP) = r21086*1087* fpu_error_or_IRQ? is a helper to deflect to the right cause.1088*1089*/1090#ifdef CONFIG_MMU1091tlb_miss_load:1092or SP, ZERO, r21093or ZERO, ZERO, r3 /* Read */1094or ZERO, ZERO, r4 /* Data */1095getcon TEA, r51096pta call_do_page_fault, tr01097beq ZERO, ZERO, tr010981099tlb_miss_store:1100or SP, ZERO, r21101movi 1, r3 /* Write */1102or ZERO, ZERO, r4 /* Data */1103getcon TEA, r51104pta call_do_page_fault, tr01105beq ZERO, ZERO, tr011061107itlb_miss_or_IRQ:1108pta its_IRQ, tr01109beqi/u r4, EVENT_INTERRUPT, tr01110or SP, ZERO, r21111or ZERO, ZERO, r3 /* Read */1112movi 1, r4 /* Text */1113getcon TEA, r51114/* Fall through */11151116call_do_page_fault:1117movi do_page_fault, r61118ptabs r6, tr01119blink tr0, ZERO1120#endif /* CONFIG_MMU */11211122fpu_error_or_IRQA:1123pta its_IRQ, tr01124beqi/l r4, EVENT_INTERRUPT, tr01125#ifdef CONFIG_SH_FPU1126movi fpu_state_restore_trap_handler, r61127#else1128movi do_exception_error, r61129#endif1130ptabs r6, tr01131blink tr0, ZERO11321133fpu_error_or_IRQB:1134pta its_IRQ, tr01135beqi/l r4, EVENT_INTERRUPT, tr01136#ifdef CONFIG_SH_FPU1137movi fpu_state_restore_trap_handler, r61138#else1139movi do_exception_error, r61140#endif1141ptabs r6, tr01142blink tr0, ZERO11431144its_IRQ:1145movi do_IRQ, r61146ptabs r6, tr01147blink tr0, ZERO11481149/*1150* system_call/unknown_trap third level handler:1151*1152* Inputs:1153* (r2) fault/interrupt code, entry number (TRAP = 11)1154* (r3) struct pt_regs *, original register's frame pointer1155* (r4) Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault)1156* (r5) TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr)1157* (SP) = r31158* (LINK) return address: ret_from_exception1159* (*r3) Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7)1160*1161* Outputs:1162* (*r3) Syscall reply (Saved r2)1163* (LINK) In case of syscall only it can be scrapped.1164* Common second level post handler will be ret_from_syscall.1165* Common (non-trace) exit point to that is syscall_ret (saving1166* result to r2). Common bad exit point is syscall_bad (returning1167* ENOSYS then saved to r2).1168*1169*/11701171unknown_trap:1172/* Unknown Trap or User Trace */1173movi do_unknown_trapa, r61174ptabs r6, tr01175ld.q r3, FRAME_R(9), r2 /* r2 = #arg << 16 | syscall # */1176andi r2, 0x1ff, r2 /* r2 = syscall # */1177blink tr0, LINK11781179pta syscall_ret, tr01180blink tr0, ZERO11811182/* New syscall implementation*/1183system_call:1184pta unknown_trap, tr01185or r5, ZERO, r4 /* TRA (=r5) -> r4 */1186shlri r4, 20, r41187bnei r4, 1, tr0 /* unknown_trap if not 0x1yzzzz */11881189/* It's a system call */1190st.q r3, FRAME_S(FSYSCALL_ID), r5 /* ID (0x1yzzzz) -> stack */1191andi r5, 0x1ff, r5 /* syscall # -> r5 */11921193STI()11941195pta syscall_allowed, tr01196movi NR_syscalls - 1, r4 /* Last valid */1197bgeu/l r4, r5, tr011981199syscall_bad:1200/* Return ENOSYS ! */1201movi -(ENOSYS), r2 /* Fall-through */12021203.global syscall_ret1204syscall_ret:1205st.q SP, FRAME_R(9), r2 /* Expecting SP back to BASIC frame */1206ld.q SP, FRAME_S(FSPC), r21207addi r2, 4, r2 /* Move PC, being pre-execution event */1208st.q SP, FRAME_S(FSPC), r21209pta ret_from_syscall, tr01210blink tr0, ZERO121112121213/* A different return path for ret_from_fork, because we now need1214* to call schedule_tail with the later kernels. Because prev is1215* loaded into r2 by switch_to() means we can just call it straight away1216*/12171218.global ret_from_fork1219ret_from_fork:12201221movi schedule_tail,r51222ori r5, 1, r51223ptabs r5, tr01224blink tr0, LINK12251226ld.q SP, FRAME_S(FSPC), r21227addi r2, 4, r2 /* Move PC, being pre-execution event */1228st.q SP, FRAME_S(FSPC), r21229pta ret_from_syscall, tr01230blink tr0, ZERO12311232syscall_allowed:1233/* Use LINK to deflect the exit point, default is syscall_ret */1234pta syscall_ret, tr01235gettr tr0, LINK1236pta syscall_notrace, tr012371238getcon KCR0, r21239ld.l r2, TI_FLAGS, r41240movi _TIF_WORK_SYSCALL_MASK, r61241and r6, r4, r61242beq/l r6, ZERO, tr012431244/* Trace it by calling syscall_trace before and after */1245movi do_syscall_trace_enter, r41246or SP, ZERO, r21247ptabs r4, tr01248blink tr0, LINK12491250/* Save the retval */1251st.q SP, FRAME_R(2), r212521253/* Reload syscall number as r5 is trashed by do_syscall_trace_enter */1254ld.q SP, FRAME_S(FSYSCALL_ID), r51255andi r5, 0x1ff, r512561257pta syscall_ret_trace, tr01258gettr tr0, LINK12591260syscall_notrace:1261/* Now point to the appropriate 4th level syscall handler */1262movi sys_call_table, r41263shlli r5, 2, r51264ldx.l r4, r5, r51265ptabs r5, tr012661267/* Prepare original args */1268ld.q SP, FRAME_R(2), r21269ld.q SP, FRAME_R(3), r31270ld.q SP, FRAME_R(4), r41271ld.q SP, FRAME_R(5), r51272ld.q SP, FRAME_R(6), r61273ld.q SP, FRAME_R(7), r712741275/* And now the trick for those syscalls requiring regs * ! */1276or SP, ZERO, r812771278/* Call it */1279blink tr0, ZERO /* LINK is already properly set */12801281syscall_ret_trace:1282/* We get back here only if under trace */1283st.q SP, FRAME_R(9), r2 /* Save return value */12841285movi do_syscall_trace_leave, LINK1286or SP, ZERO, r21287ptabs LINK, tr01288blink tr0, LINK12891290/* This needs to be done after any syscall tracing */1291ld.q SP, FRAME_S(FSPC), r21292addi r2, 4, r2 /* Move PC, being pre-execution event */1293st.q SP, FRAME_S(FSPC), r212941295pta ret_from_syscall, tr01296blink tr0, ZERO /* Resume normal return sequence */12971298/*1299* --- Switch to running under a particular ASID and return the previous ASID value1300* --- The caller is assumed to have done a cli before calling this.1301*1302* Input r2 : new ASID1303* Output r2 : old ASID1304*/13051306.global switch_and_save_asid1307switch_and_save_asid:1308getcon sr, r01309movi 255, r41310shlli r4, 16, r4 /* r4 = mask to select ASID */1311and r0, r4, r3 /* r3 = shifted old ASID */1312andi r2, 255, r2 /* mask down new ASID */1313shlli r2, 16, r2 /* align new ASID against SR.ASID */1314andc r0, r4, r0 /* efface old ASID from SR */1315or r0, r2, r0 /* insert the new ASID */1316putcon r0, ssr1317movi 1f, r01318putcon r0, spc1319rte1320nop13211:1322ptabs LINK, tr01323shlri r3, 16, r2 /* r2 = old ASID */1324blink tr0, r6313251326.global route_to_panic_handler1327route_to_panic_handler:1328/* Switch to real mode, goto panic_handler, don't return. Useful for1329last-chance debugging, e.g. if no output wants to go to the console.1330*/13311332movi panic_handler - CONFIG_PAGE_OFFSET, r11333ptabs r1, tr01334pta 1f, tr11335gettr tr1, r01336putcon r0, spc1337getcon sr, r01338movi 1, r11339shlli r1, 31, r11340andc r0, r1, r01341putcon r0, ssr1342rte1343nop13441: /* Now in real mode */1345blink tr0, r631346nop13471348.global peek_real_address_q1349peek_real_address_q:1350/* Two args:1351r2 : real mode address to peek1352r2(out) : result quadword13531354This is provided as a cheapskate way of manipulating device1355registers for debugging (to avoid the need to ioremap the debug1356module, and to avoid the need to ioremap the watchpoint1357controller in a way that identity maps sufficient bits to avoid the1358SH5-101 cut2 silicon defect).13591360This code is not performance critical1361*/13621363add.l r2, r63, r2 /* sign extend address */1364getcon sr, r0 /* r0 = saved original SR */1365movi 1, r11366shlli r1, 28, r11367or r0, r1, r1 /* r0 with block bit set */1368putcon r1, sr /* now in critical section */1369movi 1, r361370shlli r36, 31, r361371andc r1, r36, r1 /* turn sr.mmu off in real mode section */13721373putcon r1, ssr1374movi .peek0 - CONFIG_PAGE_OFFSET, r36 /* real mode target address */1375movi 1f, r37 /* virtual mode return addr */1376putcon r36, spc13771378synco1379rte1380nop13811382.peek0: /* come here in real mode, don't touch caches!!1383still in critical section (sr.bl==1) */1384putcon r0, ssr1385putcon r37, spc1386/* Here's the actual peek. If the address is bad, all bets are now off1387* what will happen (handlers invoked in real-mode = bad news) */1388ld.q r2, 0, r21389synco1390rte /* Back to virtual mode */1391nop139213931:1394ptabs LINK, tr01395blink tr0, r6313961397.global poke_real_address_q1398poke_real_address_q:1399/* Two args:1400r2 : real mode address to poke1401r3 : quadword value to write.14021403This is provided as a cheapskate way of manipulating device1404registers for debugging (to avoid the need to ioremap the debug1405module, and to avoid the need to ioremap the watchpoint1406controller in a way that identity maps sufficient bits to avoid the1407SH5-101 cut2 silicon defect).14081409This code is not performance critical1410*/14111412add.l r2, r63, r2 /* sign extend address */1413getcon sr, r0 /* r0 = saved original SR */1414movi 1, r11415shlli r1, 28, r11416or r0, r1, r1 /* r0 with block bit set */1417putcon r1, sr /* now in critical section */1418movi 1, r361419shlli r36, 31, r361420andc r1, r36, r1 /* turn sr.mmu off in real mode section */14211422putcon r1, ssr1423movi .poke0-CONFIG_PAGE_OFFSET, r36 /* real mode target address */1424movi 1f, r37 /* virtual mode return addr */1425putcon r36, spc14261427synco1428rte1429nop14301431.poke0: /* come here in real mode, don't touch caches!!1432still in critical section (sr.bl==1) */1433putcon r0, ssr1434putcon r37, spc1435/* Here's the actual poke. If the address is bad, all bets are now off1436* what will happen (handlers invoked in real-mode = bad news) */1437st.q r2, 0, r31438synco1439rte /* Back to virtual mode */1440nop144114421:1443ptabs LINK, tr01444blink tr0, r6314451446#ifdef CONFIG_MMU1447/*1448* --- User Access Handling Section1449*/14501451/*1452* User Access support. It all moved to non inlined Assembler1453* functions in here.1454*1455* __kernel_size_t __copy_user(void *__to, const void *__from,1456* __kernel_size_t __n)1457*1458* Inputs:1459* (r2) target address1460* (r3) source address1461* (r4) size in bytes1462*1463* Ouputs:1464* (*r2) target data1465* (r2) non-copied bytes1466*1467* If a fault occurs on the user pointer, bail out early and return the1468* number of bytes not copied in r2.1469* Strategy : for large blocks, call a real memcpy function which can1470* move >1 byte at a time using unaligned ld/st instructions, and can1471* manipulate the cache using prefetch + alloco to improve the speed1472* further. If a fault occurs in that function, just revert to the1473* byte-by-byte approach used for small blocks; this is rare so the1474* performance hit for that case does not matter.1475*1476* For small blocks it's not worth the overhead of setting up and calling1477* the memcpy routine; do the copy a byte at a time.1478*1479*/1480.global __copy_user1481__copy_user:1482pta __copy_user_byte_by_byte, tr11483movi 16, r0 ! this value is a best guess, should tune it by benchmarking1484bge/u r0, r4, tr11485pta copy_user_memcpy, tr01486addi SP, -32, SP1487/* Save arguments in case we have to fix-up unhandled page fault */1488st.q SP, 0, r21489st.q SP, 8, r31490st.q SP, 16, r41491st.q SP, 24, r35 ! r35 is callee-save1492/* Save LINK in a register to reduce RTS time later (otherwise1493ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */1494ori LINK, 0, r351495blink tr0, LINK14961497/* Copy completed normally if we get back here */1498ptabs r35, tr01499ld.q SP, 24, r351500/* don't restore r2-r4, pointless */1501/* set result=r2 to zero as the copy must have succeeded. */1502or r63, r63, r21503addi SP, 32, SP1504blink tr0, r63 ! RTS15051506.global __copy_user_fixup1507__copy_user_fixup:1508/* Restore stack frame */1509ori r35, 0, LINK1510ld.q SP, 24, r351511ld.q SP, 16, r41512ld.q SP, 8, r31513ld.q SP, 0, r21514addi SP, 32, SP1515/* Fall through to original code, in the 'same' state we entered with */15161517/* The slow byte-by-byte method is used if the fast copy traps due to a bad1518user address. In that rare case, the speed drop can be tolerated. */1519__copy_user_byte_by_byte:1520pta ___copy_user_exit, tr11521pta ___copy_user1, tr01522beq/u r4, r63, tr1 /* early exit for zero length copy */1523sub r2, r3, r01524addi r0, -1, r015251526___copy_user1:1527ld.b r3, 0, r5 /* Fault address 1 */15281529/* Could rewrite this to use just 1 add, but the second comes 'free'1530due to load latency */1531addi r3, 1, r31532addi r4, -1, r4 /* No real fixup required */1533___copy_user2:1534stx.b r3, r0, r5 /* Fault address 2 */1535bne r4, ZERO, tr015361537___copy_user_exit:1538or r4, ZERO, r21539ptabs LINK, tr01540blink tr0, ZERO15411542/*1543* __kernel_size_t __clear_user(void *addr, __kernel_size_t size)1544*1545* Inputs:1546* (r2) target address1547* (r3) size in bytes1548*1549* Ouputs:1550* (*r2) zero-ed target data1551* (r2) non-zero-ed bytes1552*/1553.global __clear_user1554__clear_user:1555pta ___clear_user_exit, tr11556pta ___clear_user1, tr01557beq/u r3, r63, tr115581559___clear_user1:1560st.b r2, 0, ZERO /* Fault address */1561addi r2, 1, r21562addi r3, -1, r3 /* No real fixup required */1563bne r3, ZERO, tr015641565___clear_user_exit:1566or r3, ZERO, r21567ptabs LINK, tr01568blink tr0, ZERO15691570#endif /* CONFIG_MMU */15711572/*1573* int __strncpy_from_user(unsigned long __dest, unsigned long __src,1574* int __count)1575*1576* Inputs:1577* (r2) target address1578* (r3) source address1579* (r4) maximum size in bytes1580*1581* Ouputs:1582* (*r2) copied data1583* (r2) -EFAULT (in case of faulting)1584* copied data (otherwise)1585*/1586.global __strncpy_from_user1587__strncpy_from_user:1588pta ___strncpy_from_user1, tr01589pta ___strncpy_from_user_done, tr11590or r4, ZERO, r5 /* r5 = original count */1591beq/u r4, r63, tr1 /* early exit if r4==0 */1592movi -(EFAULT), r6 /* r6 = reply, no real fixup */1593or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */15941595___strncpy_from_user1:1596ld.b r3, 0, r7 /* Fault address: only in reading */1597st.b r2, 0, r71598addi r2, 1, r21599addi r3, 1, r31600beq/u ZERO, r7, tr11601addi r4, -1, r4 /* return real number of copied bytes */1602bne/l ZERO, r4, tr016031604___strncpy_from_user_done:1605sub r5, r4, r6 /* If done, return copied */16061607___strncpy_from_user_exit:1608or r6, ZERO, r21609ptabs LINK, tr01610blink tr0, ZERO16111612/*1613* extern long __strnlen_user(const char *__s, long __n)1614*1615* Inputs:1616* (r2) source address1617* (r3) source size in bytes1618*1619* Ouputs:1620* (r2) -EFAULT (in case of faulting)1621* string length (otherwise)1622*/1623.global __strnlen_user1624__strnlen_user:1625pta ___strnlen_user_set_reply, tr01626pta ___strnlen_user1, tr11627or ZERO, ZERO, r5 /* r5 = counter */1628movi -(EFAULT), r6 /* r6 = reply, no real fixup */1629or ZERO, ZERO, r7 /* r7 = data, clear top byte of data */1630beq r3, ZERO, tr016311632___strnlen_user1:1633ldx.b r2, r5, r7 /* Fault address: only in reading */1634addi r3, -1, r3 /* No real fixup */1635addi r5, 1, r51636beq r3, ZERO, tr01637bne r7, ZERO, tr11638! The line below used to be active. This meant led to a junk byte lying between each pair1639! of entries in the argv & envp structures in memory. Whilst the program saw the right data1640! via the argv and envp arguments to main, it meant the 'flat' representation visible through1641! /proc/$pid/cmdline was corrupt, causing trouble with ps, for example.1642! addi r5, 1, r5 /* Include '\0' */16431644___strnlen_user_set_reply:1645or r5, ZERO, r6 /* If done, return counter */16461647___strnlen_user_exit:1648or r6, ZERO, r21649ptabs LINK, tr01650blink tr0, ZERO16511652/*1653* extern long __get_user_asm_?(void *val, long addr)1654*1655* Inputs:1656* (r2) dest address1657* (r3) source address (in User Space)1658*1659* Ouputs:1660* (r2) -EFAULT (faulting)1661* 0 (not faulting)1662*/1663.global __get_user_asm_b1664__get_user_asm_b:1665or r2, ZERO, r41666movi -(EFAULT), r2 /* r2 = reply, no real fixup */16671668___get_user_asm_b1:1669ld.b r3, 0, r5 /* r5 = data */1670st.b r4, 0, r51671or ZERO, ZERO, r216721673___get_user_asm_b_exit:1674ptabs LINK, tr01675blink tr0, ZERO167616771678.global __get_user_asm_w1679__get_user_asm_w:1680or r2, ZERO, r41681movi -(EFAULT), r2 /* r2 = reply, no real fixup */16821683___get_user_asm_w1:1684ld.w r3, 0, r5 /* r5 = data */1685st.w r4, 0, r51686or ZERO, ZERO, r216871688___get_user_asm_w_exit:1689ptabs LINK, tr01690blink tr0, ZERO169116921693.global __get_user_asm_l1694__get_user_asm_l:1695or r2, ZERO, r41696movi -(EFAULT), r2 /* r2 = reply, no real fixup */16971698___get_user_asm_l1:1699ld.l r3, 0, r5 /* r5 = data */1700st.l r4, 0, r51701or ZERO, ZERO, r217021703___get_user_asm_l_exit:1704ptabs LINK, tr01705blink tr0, ZERO170617071708.global __get_user_asm_q1709__get_user_asm_q:1710or r2, ZERO, r41711movi -(EFAULT), r2 /* r2 = reply, no real fixup */17121713___get_user_asm_q1:1714ld.q r3, 0, r5 /* r5 = data */1715st.q r4, 0, r51716or ZERO, ZERO, r217171718___get_user_asm_q_exit:1719ptabs LINK, tr01720blink tr0, ZERO17211722/*1723* extern long __put_user_asm_?(void *pval, long addr)1724*1725* Inputs:1726* (r2) kernel pointer to value1727* (r3) dest address (in User Space)1728*1729* Ouputs:1730* (r2) -EFAULT (faulting)1731* 0 (not faulting)1732*/1733.global __put_user_asm_b1734__put_user_asm_b:1735ld.b r2, 0, r4 /* r4 = data */1736movi -(EFAULT), r2 /* r2 = reply, no real fixup */17371738___put_user_asm_b1:1739st.b r3, 0, r41740or ZERO, ZERO, r217411742___put_user_asm_b_exit:1743ptabs LINK, tr01744blink tr0, ZERO174517461747.global __put_user_asm_w1748__put_user_asm_w:1749ld.w r2, 0, r4 /* r4 = data */1750movi -(EFAULT), r2 /* r2 = reply, no real fixup */17511752___put_user_asm_w1:1753st.w r3, 0, r41754or ZERO, ZERO, r217551756___put_user_asm_w_exit:1757ptabs LINK, tr01758blink tr0, ZERO175917601761.global __put_user_asm_l1762__put_user_asm_l:1763ld.l r2, 0, r4 /* r4 = data */1764movi -(EFAULT), r2 /* r2 = reply, no real fixup */17651766___put_user_asm_l1:1767st.l r3, 0, r41768or ZERO, ZERO, r217691770___put_user_asm_l_exit:1771ptabs LINK, tr01772blink tr0, ZERO177317741775.global __put_user_asm_q1776__put_user_asm_q:1777ld.q r2, 0, r4 /* r4 = data */1778movi -(EFAULT), r2 /* r2 = reply, no real fixup */17791780___put_user_asm_q1:1781st.q r3, 0, r41782or ZERO, ZERO, r217831784___put_user_asm_q_exit:1785ptabs LINK, tr01786blink tr0, ZERO17871788panic_stash_regs:1789/* The idea is : when we get an unhandled panic, we dump the registers1790to a known memory location, the just sit in a tight loop.1791This allows the human to look at the memory region through the GDB1792session (assuming the debug module's SHwy initiator isn't locked up1793or anything), to hopefully analyze the cause of the panic. */17941795/* On entry, former r15 (SP) is in DCR1796former r0 is at resvec_saved_area + 01797former r1 is at resvec_saved_area + 81798former tr0 is at resvec_saved_area + 321799DCR is the only register whose value is lost altogether.1800*/18011802movi 0xffffffff80000000, r0 ! phy of dump area1803ld.q SP, 0x000, r1 ! former r01804st.q r0, 0x000, r11805ld.q SP, 0x008, r1 ! former r11806st.q r0, 0x008, r11807st.q r0, 0x010, r21808st.q r0, 0x018, r31809st.q r0, 0x020, r41810st.q r0, 0x028, r51811st.q r0, 0x030, r61812st.q r0, 0x038, r71813st.q r0, 0x040, r81814st.q r0, 0x048, r91815st.q r0, 0x050, r101816st.q r0, 0x058, r111817st.q r0, 0x060, r121818st.q r0, 0x068, r131819st.q r0, 0x070, r141820getcon dcr, r141821st.q r0, 0x078, r141822st.q r0, 0x080, r161823st.q r0, 0x088, r171824st.q r0, 0x090, r181825st.q r0, 0x098, r191826st.q r0, 0x0a0, r201827st.q r0, 0x0a8, r211828st.q r0, 0x0b0, r221829st.q r0, 0x0b8, r231830st.q r0, 0x0c0, r241831st.q r0, 0x0c8, r251832st.q r0, 0x0d0, r261833st.q r0, 0x0d8, r271834st.q r0, 0x0e0, r281835st.q r0, 0x0e8, r291836st.q r0, 0x0f0, r301837st.q r0, 0x0f8, r311838st.q r0, 0x100, r321839st.q r0, 0x108, r331840st.q r0, 0x110, r341841st.q r0, 0x118, r351842st.q r0, 0x120, r361843st.q r0, 0x128, r371844st.q r0, 0x130, r381845st.q r0, 0x138, r391846st.q r0, 0x140, r401847st.q r0, 0x148, r411848st.q r0, 0x150, r421849st.q r0, 0x158, r431850st.q r0, 0x160, r441851st.q r0, 0x168, r451852st.q r0, 0x170, r461853st.q r0, 0x178, r471854st.q r0, 0x180, r481855st.q r0, 0x188, r491856st.q r0, 0x190, r501857st.q r0, 0x198, r511858st.q r0, 0x1a0, r521859st.q r0, 0x1a8, r531860st.q r0, 0x1b0, r541861st.q r0, 0x1b8, r551862st.q r0, 0x1c0, r561863st.q r0, 0x1c8, r571864st.q r0, 0x1d0, r581865st.q r0, 0x1d8, r591866st.q r0, 0x1e0, r601867st.q r0, 0x1e8, r611868st.q r0, 0x1f0, r621869st.q r0, 0x1f8, r63 ! bogus, but for consistency's sake...18701871ld.q SP, 0x020, r1 ! former tr01872st.q r0, 0x200, r11873gettr tr1, r11874st.q r0, 0x208, r11875gettr tr2, r11876st.q r0, 0x210, r11877gettr tr3, r11878st.q r0, 0x218, r11879gettr tr4, r11880st.q r0, 0x220, r11881gettr tr5, r11882st.q r0, 0x228, r11883gettr tr6, r11884st.q r0, 0x230, r11885gettr tr7, r11886st.q r0, 0x238, r118871888getcon sr, r11889getcon ssr, r21890getcon pssr, r31891getcon spc, r41892getcon pspc, r51893getcon intevt, r61894getcon expevt, r71895getcon pexpevt, r81896getcon tra, r91897getcon tea, r101898getcon kcr0, r111899getcon kcr1, r121900getcon vbr, r131901getcon resvec, r1419021903st.q r0, 0x240, r11904st.q r0, 0x248, r21905st.q r0, 0x250, r31906st.q r0, 0x258, r41907st.q r0, 0x260, r51908st.q r0, 0x268, r61909st.q r0, 0x270, r71910st.q r0, 0x278, r81911st.q r0, 0x280, r91912st.q r0, 0x288, r101913st.q r0, 0x290, r111914st.q r0, 0x298, r121915st.q r0, 0x2a0, r131916st.q r0, 0x2a8, r1419171918getcon SPC,r21919getcon SSR,r31920getcon EXPEVT,r41921/* Prepare to jump to C - physical address */1922movi panic_handler-CONFIG_PAGE_OFFSET, r11923ori r1, 1, r11924ptabs r1, tr01925getcon DCR, SP1926blink tr0, ZERO1927nop1928nop1929nop1930nop19311932193319341935/*1936* --- Signal Handling Section1937*/19381939/*1940* extern long long _sa_default_rt_restorer1941* extern long long _sa_default_restorer1942*1943* or, better,1944*1945* extern void _sa_default_rt_restorer(void)1946* extern void _sa_default_restorer(void)1947*1948* Code prototypes to do a sys_rt_sigreturn() or sys_sysreturn()1949* from user space. Copied into user space by signal management.1950* Both must be quad aligned and 2 quad long (4 instructions).1951*1952*/1953.balign 81954.global sa_default_rt_restorer1955sa_default_rt_restorer:1956movi 0x10, r91957shori __NR_rt_sigreturn, r91958trapa r91959nop19601961.balign 81962.global sa_default_restorer1963sa_default_restorer:1964movi 0x10, r91965shori __NR_sigreturn, r91966trapa r91967nop19681969/*1970* --- __ex_table Section1971*/19721973/*1974* User Access Exception Table.1975*/1976.section __ex_table, "a"19771978.global asm_uaccess_start /* Just a marker */1979asm_uaccess_start:19801981#ifdef CONFIG_MMU1982.long ___copy_user1, ___copy_user_exit1983.long ___copy_user2, ___copy_user_exit1984.long ___clear_user1, ___clear_user_exit1985#endif1986.long ___strncpy_from_user1, ___strncpy_from_user_exit1987.long ___strnlen_user1, ___strnlen_user_exit1988.long ___get_user_asm_b1, ___get_user_asm_b_exit1989.long ___get_user_asm_w1, ___get_user_asm_w_exit1990.long ___get_user_asm_l1, ___get_user_asm_l_exit1991.long ___get_user_asm_q1, ___get_user_asm_q_exit1992.long ___put_user_asm_b1, ___put_user_asm_b_exit1993.long ___put_user_asm_w1, ___put_user_asm_w_exit1994.long ___put_user_asm_l1, ___put_user_asm_l_exit1995.long ___put_user_asm_q1, ___put_user_asm_q_exit19961997.global asm_uaccess_end /* Just a marker */1998asm_uaccess_end:19992000200120022003/*2004* --- .init.text Section2005*/20062007__INIT20082009/*2010* void trap_init (void)2011*2012*/2013.global trap_init2014trap_init:2015addi SP, -24, SP /* Room to save r28/r29/r30 */2016st.q SP, 0, r282017st.q SP, 8, r292018st.q SP, 16, r3020192020/* Set VBR and RESVEC */2021movi LVBR_block, r192022andi r19, -4, r19 /* reset MMUOFF + reserved */2023/* For RESVEC exceptions we force the MMU off, which means we need the2024physical address. */2025movi LRESVEC_block-CONFIG_PAGE_OFFSET, r202026andi r20, -4, r20 /* reset reserved */2027ori r20, 1, r20 /* set MMUOFF */2028putcon r19, VBR2029putcon r20, RESVEC20302031/* Sanity check */2032movi LVBR_block_end, r212033andi r21, -4, r212034movi BLOCK_SIZE, r29 /* r29 = expected size */2035or r19, ZERO, r302036add r19, r29, r1920372038/*2039* Ugly, but better loop forever now than crash afterwards.2040* We should print a message, but if we touch LVBR or2041* LRESVEC blocks we should not be surprised if we get stuck2042* in trap_init().2043*/2044pta trap_init_loop, tr12045gettr tr1, r28 /* r28 = trap_init_loop */2046sub r21, r30, r30 /* r30 = actual size */20472048/*2049* VBR/RESVEC handlers overlap by being bigger than2050* allowed. Very bad. Just loop forever.2051* (r28) panic/loop address2052* (r29) expected size2053* (r30) actual size2054*/2055trap_init_loop:2056bne r19, r21, tr120572058/* Now that exception vectors are set up reset SR.BL */2059getcon SR, r222060movi SR_UNBLOCK_EXC, r232061and r22, r23, r222062putcon r22, SR20632064addi SP, 24, SP2065ptabs LINK, tr02066blink tr0, ZERO2067206820692070