EXCEPTION_ENTRY(_data_page_fault_handler)
CLEAR_LWA_FLAG(r3) /* set up parameters for do_page_fault */
l.ori r5,r0,0x300 // exception vector 1:
l.addi r3,r1,0 // pt_regs /* r4 set be EXCEPTION_HANDLE */ // effective address of fault
#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
l.lwz r6,PT_PC(r3) // address of an offending insn
l.lwz r6,0(r6) // instruction that caused pf
ENTRY(_sys_call_handler) /* r1, EPCR, ESR a already saved */
l.sw PT_GPR2(r1),r2 /* r3-r8 must be saved because syscall restart relies *onusbeingabletorestartthesyscallargs...technically *theyshouldbeclobbered,otherwise
*/
l.sw PT_GPR3(r1),r3 /* *r4alreadysaved *r4holdstheEEARaddressofthefault,useitasscreatchregand *thenloadtheoriginalr4
*/
CLEAR_LWA_FLAG(r4)
l.lwz r4,PT_GPR4(r1)
l.sw PT_GPR5(r1),r5
l.sw PT_GPR6(r1),r6
l.sw PT_GPR7(r1),r7
l.sw PT_GPR8(r1),r8
l.sw PT_GPR9(r1),r9 /* r10 already saved */
l.sw PT_GPR11(r1),r11 /* orig_gpr11 must be set for syscalls */
l.sw PT_ORIG_GPR11(r1),r11 /* r12,r13 already saved */
/* r14-r28 (even) aren't touched by the syscall fast path below *sowedon'tneedtosavethem.However,thefunctionsthatreturn *touserspaceviaacalltoswitch()DOneedtosavethesebecause *switch()effectivelyclobbersthem...savingtheseregistersfor *suchfunctionsishandledintheirsyscallwrappers(seefork,vfork, *andclone,below).
/* r30 is the only register we clobber in the fast path */ /* r30 already saved */ /* l.sw PT_GPR30(r1),r30 */
_syscall_check_trace_enter: /* syscalls run with interrupts enabled */
TRACE_IRQS_ON_SYSCALL
ENABLE_INTERRUPTS(r29) // enable interrupts, r29 is temp
/* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
l.lwz r30,TI_FLAGS(r10)
l.andi r30,r30,_TIF_SYSCALL_TRACE
l.sfne r30,r0
l.bf _syscall_trace_enter
l.nop
_syscall_check: /* Ensure that the syscall number is reasonable */
l.sfgeui r11,__NR_syscalls
l.bf _syscall_badsys
l.nop
_syscall_return: /* All syscalls return here... just pay attention to ret_from_fork *whichdoesitinaround-aboutway.
*/
l.sw PT_GPR11(r1),r11 // save return value
_syscall_check_trace_leave: /* r30 is a callee-saved register so this should still hold the *_TIF_SYSCALL_TRACEflagfrom_syscall_check_trace_enterabove... *_syscall_trace_leaveexpectssyscallresulttobeinpt_regs->r11.
*/
l.sfne r30,r0
l.bf _syscall_trace_leave
l.nop
/* This is where the exception-return code begins... interrupts need to be *disabledtherestofthewayherebecausewecan'taffordtomissany
* interrupts that set NEED_RESCHED or SIGNALPENDING... really true? */
_syscall_check_work:
#ifdef CONFIG_DEBUG_RSEQ
l.jal rseq_syscall
l.ori r3,r1,0
#endif /* Here we need to disable interrupts */
DISABLE_INTERRUPTS(r27,r29)
TRACE_IRQS_OFF
l.lwz r30,TI_FLAGS(r10)
l.andi r30,r30,_TIF_WORK_MASK
l.sfne r30,r0
l.bnf _syscall_resume_userspace
l.nop
/* Work pending follows a different return path, so we need to *makesurethatallthecall-savedregistersgetintopt_regs *beforebranching...
*/
l.sw PT_GPR14(r1),r14
l.sw PT_GPR16(r1),r16
l.sw PT_GPR18(r1),r18
l.sw PT_GPR20(r1),r20
l.sw PT_GPR22(r1),r22
l.sw PT_GPR24(r1),r24
l.sw PT_GPR26(r1),r26
l.sw PT_GPR28(r1),r28
/* _work_pending needs to be called with interrupts disabled */
l.j _work_pending
l.nop
/* This is the hot path for returning to userspace from a syscall. If there's *worktobedoneandthebranchto_work_pendingwastakenabove,thenthe *returntouserspacewillbedoneviathenormalexceptionreturnpath... *thatpathrestores_all_registersandwilloverwritethe"clobbered" *registerswithwhatevergarbageisinpt_regs--that'sOKbecausethose *registersareclobberedanywayandbecausetheextraworkisinsignificant *inthecontextoftheextraworkthat_work_pendingisdoing.
/* Once again, syscalls are special and only guarantee to preserve the
* same registers as a normal function call */
/* The assumption here is that the registers r14-r28 (even) are untouched and *don'tneedtoberestored...besurethatthat'sreallythecase!
*/
/* This is still too much... we should only be restoring what we actually *clobbered...weshouldevenbeusing'scratch'(odd)regsabovesothat *wedon'tneedtorestoreanything,hardly...
*/
l.lwz r2,PT_GPR2(r1)
/* Restore args */ /* r3-r8 are technically clobbered, but syscall restart needs these *toberestored...
*/
l.lwz r3,PT_GPR3(r1)
l.lwz r4,PT_GPR4(r1)
l.lwz r5,PT_GPR5(r1)
l.lwz r6,PT_GPR6(r1)
l.lwz r7,PT_GPR7(r1)
l.lwz r8,PT_GPR8(r1)
/* r30 is the only register we clobber in the fast path */
l.lwz r30,PT_GPR30(r1)
/* Here we use r13-r19 (odd) as scratch regs */
l.lwz r13,PT_PC(r1)
l.lwz r15,PT_SR(r1)
l.lwz r1,PT_SP(r1) /* Interrupts need to be disabled for setting EPCR and ESR *sothatanotherinterruptdoesn'tcomeinhereandclobber
* them before we can use them for our l.rfe */
DISABLE_INTERRUPTS(r17,r19)
l.mtspr r0,r13,SPR_EPCR_BASE
l.mtspr r0,r15,SPR_ESR_BASE
l.rfe
/* End of hot path! *Keepthebelowtracinganderrorhandlingoutofthehotpath...
*/
_syscall_trace_enter: /* Here we pass pt_regs to do_syscall_trace_enter. Make sure *thatfunctionisreallygettingalltheinfoitneedsas *pt_regsisn'tacompletesetofuserspaceregs,justthe *onesrelevanttothesyscall... * *Noteuseofdelayslotforsettingargument.
*/
l.jal do_syscall_trace_enter
l.addi r3,r1,0
_syscall_badsys: /* Here we effectively pretend to have executed an imaginary *syscallthatreturns-ENOSYSandthenreturntotheregular *syscallhotpath. *Notethat"returnvalue"issetinthedelayslot...
*/
l.j _syscall_return
l.addi r11,r0,-ENOSYS
/******* END SYSCALL HANDLING *******/
/* ---[ 0xd00: Floating Point exception ]-------------------------------- */
/* _switch MUST never lay on page boundry, cause it runs from *effectiveaddressesandbeeinginterruptedbyiTLBmisswouldkillit. *dTLBmissseemstoneveraccourinthebadplacesincedataaccesses *arefromtaskstructureswhicharealwayspagealigned. * *TheproblemhappensinRESTORE_ALLwherewefirstsettheEPCR *register,thenloadthepreviousregistervaluesandonlyattheendcall *thel.rfeinstruction.IfgetTLBmissinbeetwentheEPCRregistergets *garbledandweendupcallingl.rfewiththewrongEPCR.(sameprobably *holdsforESR) * *Toavoidthisproblemsitissufficienttoalign_switchto *someniceroundnumbersmallerthanit'ssize...
*/
/* ABI rules apply here... we either enter _switch via schedule() or via *animaginarycalltowhichweshallreturnatreturn_from_fork.Either *way,weareafunctioncallandonlyneedtopreservethecallee-saved *registerswhenwereturn.Assuch,wedon'tneedtosavetheregisters *onthestackthatwewon'tbereturningastheywere...
*/
.align0x400
ENTRY(_switch) /* We don't store SR as _switch only gets called in a context where
* the SR will be the same going in and coming out... */
/* Set up new pt_regs struct for saving task state */
l.addi r1,r1,-(INT_FRAME_SIZE)
/* No need to store r1/PT_SP as it goes into KSP below */
l.sw PT_GPR2(r1),r2
l.sw PT_GPR9(r1),r9
/* Save callee-saved registers to the new pt_regs */
l.sw PT_GPR14(r1),r14
l.sw PT_GPR16(r1),r16
l.sw PT_GPR18(r1),r18
l.sw PT_GPR20(r1),r20
l.sw PT_GPR22(r1),r22
l.sw PT_GPR24(r1),r24
l.sw PT_GPR26(r1),r26
l.sw PT_GPR28(r1),r28
l.sw PT_GPR30(r1),r30
l.addi r11,r10,0/* Save old 'current' to 'last' return value*/
/* We use thread_info->ksp for storing the address of the above *structuresothatwecangetbacktoitlater...wedon'twant *tolosethevalueofthread_info->ksp,though,sostoreitas *pt_regs->spsothatwecaneasilyrestoreitwhenwearemade *liveagain...
*/
/* Save the old value of thread_info->ksp as pt_regs->sp */
l.lwz r29,TI_KSP(r10)
l.sw PT_SP(r1),r29
/* Swap kernel stack pointers */
l.sw TI_KSP(r10),r1 /* Save old stack pointer */
l.or r10,r4,r0 /* Set up new current_thread_info */
l.lwz r1,TI_KSP(r10) /* Load new stack pointer */
/* Restore the old value of thread_info->ksp */
l.lwz r29,PT_SP(r1)
l.sw TI_KSP(r10),r29
/* ...and restore the registers, except r11 because the return value *hasalreadybeensetabove.
*/
l.lwz r2,PT_GPR2(r1)
l.lwz r9,PT_GPR9(r1) /* No need to restore r10 */ /* ...and do not restore r11 */
/* Unwind stack to pre-switch state */
l.addi r1,r1,(INT_FRAME_SIZE)
/* Return via the link-register back to where we 'came from', where *thatmaybeeitherschedule(),ret_from_fork(),or *ret_from_kernel_thread().Ifwearereturningtoanewthread, *weareexpectedtohavesetuptheargtoschedule_tailalready, *hencewedosohereunconditionally:
*/
l.lwz r3,TI_TASK(r3) /* Load 'prev' as schedule_tail arg */
l.jr r9
l.nop
/* These all use the delay slot for setting the argument register, so the *jumpisalwayshappeningafterthel.addiinstruction. * *Thesearealljustwrappersthatdon'ttouchthelink-registerr9,sothe *returnfromthe"real"syscallfunctionwillreturnbacktothesyscall *codethatdidthel.jalthatbroughtushere.
*/
/* fork requires that we save all the callee-saved registers because they *arealleffectivelyclobberedbythecallto_switch.Herewestore *alltheregistersthataren'ttouchedbythesyscallfastpathandthus *weren'tsavedthere.
*/
/* This is a catch-all syscall for atomic instructions for the OpenRISC 1000. *Thefunctionstakesavariablenumberofparametersdependingonwhich *particularflavourofatomicyouwant...parameter1isaflagidentifying *theatomicinquestion.Currently,thisfunctionimplementsthe *followingvariants: * *XCHG: *@flag:1 *@ptr1: *@ptr2: *Atomicallyexchangethevaluesinpointers1and2. *
*/
ENTRY(sys_or1k_atomic) /* FIXME: This ignores r3 and always does an XCHG */
DISABLE_INTERRUPTS(r17,r19)
l.lwz r29,0(r4)
l.lwz r27,0(r5)
l.sw 0(r4),r27
l.sw 0(r5),r29
ENABLE_INTERRUPTS(r17)
l.jr r9
l.or r11,r0,r0
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.