/* we have the following possibilities to act on an interruption: *-handleinassemblyanduseshadowedregistersonly
* - save registers to kernel stack and handle in assembly or C */
/* HPMC handler */
.macro hpmc code
nop /* must be a NOP, will be patched later */
load32 PA(os_hpmc), %r3
bv,n 0(%r3)
nop
.word0/* checksum (will be patched) */
.word0/* address of handler */
.word0/* length of handler */
.endm
mfctl %isr,spc
#ifdef CONFIG_64BIT
b dbit_trap_20w
#else
b dbit_trap_20
#endif
mfctl %ior,va
.align32
.endm
/* In LP64, the space contains part of the upper 32 bits of the *fault.Wehavetoextractthisandplaceitintheva,
* zeroing the corresponding bits in the space register */
.macro space_adjust spc,va,tmp
#ifdef CONFIG_64BIT
extrd,u \spc,63,SPACEID_SHIFT,\tmp
depd %r0,63,SPACEID_SHIFT,\spc
depd \tmp,31,SPACEID_SHIFT,\va
#endif
.endm
.import swapper_pg_dir,code
/* Get the pgd. For faults on space zero (kernel space), this *issimplyswapper_pg_dir.Foruserspacefaults,the
* pgd is stored in %cr25 */
.macro get_pgd spc,reg
ldil L%PA(swapper_pg_dir),\reg
ldo R%PA(swapper_pg_dir)(\reg),\reg
or,COND(=) %r0,\spc,%r0
mfctl %cr25,\reg
.endm
*/
.macro space_check spc,tmp,fault
mfsp %sr7,\tmp /* check against %r0 which is same value as LINUX_GATEWAY_SPACE */
or,COND(<>) %r0,\spc,%r0 /* user may execute gateway page *askernel,sodefeatthespace
* check if it is */
copy \spc,\tmp
or,COND(=) %r0,\tmp,%r0 /* nullify if executing as kernel */
cmpb,COND(<>),n \tmp,\spc,\fault
.endm
/* Look up a PTE in a 2-Level scheme (faulting at each *leveliftheentryisn'tpresent * *NOTE:weuseldwevenforLP64,sincetheshortpointers *canaddressupto1TB
*/
.macro L2_ptep pmd,pte,index,va,fault
#if CONFIG_PGTABLE_LEVELS == 3
extru_safe \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
#else
extru_safe \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
#endif
dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
#if CONFIG_PGTABLE_LEVELS < 3
copy %r0,\pte
#endif
ldw,s \index(\pmd),\pmd
bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
dep %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
SHLREG \pmd,PxD_VALUE_SHIFT,\pmd
extru_safe \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */
.endm
/* Look up PTE in a 3-Level scheme. */
.macro L3_ptep pgd,pte,index,va,fault
#if CONFIG_PGTABLE_LEVELS == 3
copy %r0,\pte
extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
ldw,s \index(\pgd),\pgd
bb,>=,n \pgd,_PxD_PRESENT_BIT,\fault
shld \pgd,PxD_VALUE_SHIFT,\pgd
#endif
L2_ptep \pgd,\pte,\index,\va,\fault
.endm
/* Release page_table_lock if for user space. We use an ordered storetoensureallprioraccessesareperformedpriorto releasingthelock.Notestwmaynotbeexecuted,sowe
provide one extra nop when CONFIG_TLB_PTLOCK is defined. */
.macro ptl_unlock spc,tmp,tmp2
#ifdef CONFIG_TLB_PTLOCK 98: get_ptl \tmp
ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmp2
or,COND(=) %r0,\spc,%r0
stw,ma \tmp2,0(\tmp) 99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
insert_nops NUM_PIPELINE_INSNS - 4
#else
insert_nops NUM_PIPELINE_INSNS - 1
#endif
.endm
/* Set the _PAGE_ACCESSED bit of the PTE. Be clever and
* don't needlessly dirty the cache line if it was already set */
.macro update_accessed ptp,pte,tmp,tmp1
ldi _PAGE_ACCESSED,\tmp1
or \tmp1,\pte,\tmp
and,COND(<>) \tmp1,\pte,%r0
STREG \tmp,0(\ptp)
.endm
/* Set the dirty bit (and accessed bit). No need to be
* clever, this is only used from the dirty fault */
.macro update_dirty ptp,pte,tmp
ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
or \tmp,\pte,\pte
STREG \pte,0(\ptp)
.endm
/* We have (depending on the page size): *-38to52-bitPhysicalPageNumber *-12to26-bitpageoffset
*/ /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
* to a CPU TLB 4k PFN (4k => 12 bits to shift) */
#define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
#define PAGE_ADD_HUGE_SHIFT (REAL_HPAGE_SHIFT-12)
#define PFN_START_BIT (63-ASM_PFN_PTE_SHIFT+(63-58)-PAGE_ADD_SHIFT)
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
.macro convert_for_tlb_insert20 pte,tmp
#ifdef CONFIG_HUGETLB_PAGE
copy \pte,\tmp
extrd,u \tmp,PFN_START_BIT,PFN_START_BIT+1,\pte
/* Convert the pte and prot to tlb insertion values. How
* this happens is quite subtle, read below */
.macro make_insert_tlb spc,pte,prot,tmp
space_to_prot \spc \prot /* create prot id from space */
#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT /* need to drop DMB bit, as it's used as SPECIAL flag */
depi 0,_PAGE_SPECIAL_BIT,1,\pte
#endif
/* The following is the real subtlety. This is depositing *T<->_PAGE_REFTRAP *D<->_PAGE_DIRTY *B<->_PAGE_DMB(memorybreak) * *Thenincrediblesubtlety:Theaccessrightsare *_PAGE_GATEWAY,_PAGE_EXECand_PAGE_WRITE *See3-14oftheparisc2.0manual * *Finally,_PAGE_READgoesinthetopbitofPL1(sowe *triggeranaccessrightstrapinuserspaceiftheuser
* tries to read an unreadable page */
depd \pte,8,7,\prot
/* PAGE_USER indicates the page can be read with user privileges, *sodepositX1|11toPL1|PL2(remembertheupperbitofPL1 *contains_PAGE_READ).Whilethekernelcan'tdirectlywrite *userpageswhichhave_PAGE_WRITEzero,itcanreadpages *whichhave_PAGE_READzero(PL<=PL1).Thus,thekernel *exceptionfaulthandlerdoesn'ttriggerwhenreadingpages
* that aren't user read accessible */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion *tokernelprivilege(sowecanexecutethepageaskernel).
* Any privilege promotion page always denys read and write */
extrd,u,*= \pte,_PAGE_GATEWAY_BIT+32,1,%r0
depd %r0,11,2,\prot /* If Gateway, Set PL2 to 0 */
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
convert_for_tlb_insert20 \pte \tmp
.endm
/* Identical macro to make_insert_tlb above, except it *makesthetlbentryforthedifferentlyformattedpa11
* insertion instructions */
.macro make_insert_tlb_11 spc,pte,prot
#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT /* need to drop DMB bit, as it's used as SPECIAL flag */
depi 0,_PAGE_SPECIAL_BIT,1,\pte
#endif
zdep \spc,30,15,\prot
dep \pte,8,7,\prot
extru,= \pte,_PAGE_NO_CACHE_BIT,1,%r0
depi 1,12,1,\prot
extru,= \pte,_PAGE_USER_BIT,1,%r0
depi 7,11,3,\prot /* Set for user space (1 rsvd for read) */
extru,= \pte,_PAGE_GATEWAY_BIT,1,%r0
depi 0,11,2,\prot /* If Gateway, Set PL2 to 0 */
/* Get rid of prot bits and convert to page addr for iitlba */
/* This is for ILP32 PA2.0 only. The TLB insertion needs *toextendintoI/Ospaceiftheaddressis0xfXXXXXXX *soweextendthef'sintothetopwordoftheptein
* this case */
.macro f_extend pte,tmp
extrd,s \pte,42,4,\tmp
addi,<> 1,\tmp,%r0
extrd,s \pte,63,25,\pte
.endm
/* The alias region is comprised of a pair of 4 MB regions *alignedto8MB.Itisusedtoclear/copy/flushuserpages *usingkernelvirtualaddressescongruentwiththeuser *virtualaddress. * *Tousethealiaspage,youset%r26upwiththetoTLB *entry(identifyingthephysicalpage)and%r23upwith *thefromtlbentry(ornothingifonlyatoentry---for
* clear_user_page_asm) */
.macro do_alias spc,tmp,tmp1,va,pte,prot,fault,patype
cmpib,COND(<>),n 0,\spc,\fault
ldil L%(TMPALIAS_MAP_START),\tmp
copy \va,\tmp1
depi_safe 0,31,TMPALIAS_SIZE_BITS+1,\tmp1
cmpb,COND(<>),n \tmp,\tmp1,\fault
mfctl %cr19,\tmp /* iir */ /* get the opcode (first six bits) into \tmp */
extrw,u \tmp,5,6,\tmp /* *OnlysettingtheTbitpreventsdatacachemovein *Settingaccessrightstozeropreventsinstructioncachemovein * *Notesubtletyhere:_PAGE_GATEWAY,_PAGE_EXECand_PAGE_WRITEgo *totypefieldand_PAGE_READgoestotopbitofPL1
*/
ldi (_PAGE_REFTRAP|_PAGE_READ|_PAGE_WRITE),\prot /* *soiftheopcodeisone(i.e.thisisamemorymanagement *instruction)nullifythenextloadso\protisonlyT. *Otherwisethisisanormaldataoperation
*/
cmpiclr,= 0x01,\tmp,%r0
ldi (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
.ifc \patype,20
depd,z \prot,8,7,\prot
.else
.ifc \patype,11
depw,z \prot,8,7,\prot
.else
.error "undefined PA type to do_alias"
.endif
.endif /* *OK,itisinthetempaliasregion,checkwhether"from"or"to". *Check"subtle"noteinpacache.Sre:r23/r26.
*/
extrw,u,= \va,31-TMPALIAS_SIZE_BITS,1,%r0
or,COND(tr) %r23,%r0,\pte
or %r26,%r0,\pte
/* convert phys addr in \pte (from r23 or r26) to tlb insert format */
SHRREG \pte,PAGE_SHIFT+PAGE_ADD_SHIFT-5, \pte
depi_safe _PAGE_SIZE_ENCODING_DEFAULT, 31,5, \pte
.endm
ENTRY_CFI(syscall_exit_rfi)
mfctl %cr30,%r16 /* task_struct */
ldo TASK_REGS(%r16),%r16 /* Force iaoq to userspace, as the user has had access to our current *contextviasigcontext.AlsoFilterthePSWforthesamereason.
*/
LDREG PT_IAOQ0(%r16),%r19
depi PRIV_USER,31,2,%r19
STREG %r19,PT_IAOQ0(%r16)
LDREG PT_IAOQ1(%r16),%r19
depi PRIV_USER,31,2,%r19
STREG %r19,PT_IAOQ1(%r16)
LDREG PT_PSW(%r16),%r19
load32 USER_PSW_MASK,%r1
#ifdef CONFIG_64BIT
load32 USER_PSW_HI_MASK,%r20
depd %r20,31,32,%r1
#endif
and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
load32 USER_PSW,%r1
or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
STREG %r19,PT_PSW(%r16)
/* Set the return value for the child */
ENTRY(child_return)
BL schedule_tail, %r2
nop
finish_child_return:
mfctl %cr30,%r1
ldo TASK_REGS(%r1),%r1 /* get pt regs */
/* FIXME: I think we need to restore a few more things here. */
mfctl %cr30,%r1
ldo TASK_REGS(%r1),%r1 /* get pt regs */
reg_restore %r1
/* If the signal was received while the process was blocked on a *syscall,thenr2willtakeustosyscall_exit;otherwiser2will *takeustosyscall_exit_rfiandontointr_return.
*/
bv %r0(%r2)
LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
ENDPROC_CFI(sys_rt_sigreturn_wrapper)
ENTRY(syscall_exit) /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit *viasyscall_exit_rfiifthesignalwasreceivedwhiletheprocess *wasrunning.
*/
/* save return value now */
mfctl %cr30, %r1
STREG %r28,TASK_PT_GR28(%r1)
/* Seems to me that dp could be wrong here, if the syscall involved *callingamodule,andnothinggotroundtorestoringdponreturn.
*/
loadgp
syscall_check_resched:
/* check for reschedule */
mfctl %cr30,%r19
LDREG TASK_TI_FLAGS(%r19),%r19 /* long */
bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
.import do_signal,code
syscall_check_sig:
mfctl %cr30,%r19
LDREG TASK_TI_FLAGS(%r19),%r19
ldi (_TIF_USER_WORK_MASK & ~_TIF_NEED_RESCHED), %r26
and,COND(<>) %r19, %r26, %r0
b,n syscall_restore /* skip past if we've nothing to do */
LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
mtsar %r19
LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
LDREG TASK_PT_GR19(%r1),%r19
LDREG TASK_PT_GR20(%r1),%r20
LDREG TASK_PT_GR21(%r1),%r21
LDREG TASK_PT_GR22(%r1),%r22
LDREG TASK_PT_GR23(%r1),%r23
LDREG TASK_PT_GR24(%r1),%r24
LDREG TASK_PT_GR25(%r1),%r25
LDREG TASK_PT_GR26(%r1),%r26
LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
LDREG TASK_PT_GR29(%r1),%r29
LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
/* NOTE: We use rsm/ssm pair to make this operation atomic */
LDREG TASK_PT_GR30(%r1),%r1 /* Get user sp */
rsm PSW_SM_I, %r0
copy %r1,%r30 /* Restore user sp */
mfsp %sr3,%r1 /* Get user space id */
mtsp %r1,%sr7 /* Restore sr7 */
ssm PSW_SM_I, %r0
/* Set sr2 to zero for userspace syscalls to work. */
mtsp %r0,%sr2
mtsp %r1,%sr4 /* Restore sr4 */
mtsp %r1,%sr5 /* Restore sr5 */
mtsp %r1,%sr6 /* Restore sr6 */
depi PRIV_USER,31,2,%r31 /* ensure return to user mode. */
#ifdef CONFIG_64BIT /* decide whether to reset the wide mode bit * *Forasyscall,theWbitisstoredinthelowestbit
* of sp. Extract it and reset W if it is zero */
extrd,u,*<> %r30,63,1,%r1
rsm PSW_SM_W, %r0 /* now reset the lowest bit of sp if it was set */
xor %r30,%r1,%r30
#endif
be,n 0(%sr3,%r31) /* return to user space */
/* We have to return via an RFI, so that PSW T and R bits can be set *appropriately. *Thissetsuppt_regssowecanreturnviaintr_restore,whichisnot *themostefficientwayofdoingthings,butitworks.
*/
syscall_restore_rfi:
ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
mtctl %r2,%cr0 /* for immediate trap */
LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
ldi 0x0b,%r20 /* Create new PSW */
depi -1,13,1,%r20 /* C, Q, D, and I bits */
/* The values of SINGLESTEP_BIT and BLOCKSTEP_BIT are *setinthread_info.handconvertedtoPAbitmap
* numbers in asm-offsets.c */
/* if ((%r19.SINGLESTEP_BIT)) { %r20.27=1} */
extru,= %r19,TIF_SINGLESTEP_PA_BIT,1,%r0
depi -1,27,1,%r20 /* R bit */
/* if ((%r19.BLOCKSTEP_BIT)) { %r20.7=1} */
extru,= %r19,TIF_BLOCKSTEP_PA_BIT,1,%r0
depi -1,7,1,%r20 /* T bit */
STREG %r20,TASK_PT_PSW(%r1)
/* Always store space registers, since sr3 can be changed (e.g. fork) */
/* XXX W bit??? */ /* Now if old D bit is clear, it means we didn't save all registers *onsyscallentry,sodothatnow.ThisonlyhappensonTRACEME *calls,orifsomeoneattachedtouswhilewewereonasyscall. *Wecouldmakethismoreefficientbynotsavingr3-r18,but *thenwewouldn'tbeabletousethecommonintr_restorepath. *Itisonlyfortracedprocessesanyway,soperformanceisnot *anissue.
*/
bb,< %r2,30,pt_regs_ok /* Branch if D set */
ldo TASK_REGS(%r1),%r25
reg_save %r25 /* Save r3 to r18 */
/* Save the current sr */
mfsp %sr0,%r2
STREG %r2,TASK_PT_SR0(%r1)
/* Save the scratch sr */
mfsp %sr1,%r2
STREG %r2,TASK_PT_SR1(%r1)
/* sr2 should be set to zero for userspace syscalls */
STREG %r0,TASK_PT_SR2(%r1)
LDREG TASK_PT_GR31(%r1),%r2
depi PRIV_USER,31,2,%r2 /* ensure return to user mode. */
STREG %r2,TASK_PT_IAOQ0(%r1)
ldo 4(%r2),%r2
STREG %r2,TASK_PT_IAOQ1(%r1)
b intr_restore
copy %r25,%r16
pt_regs_ok:
LDREG TASK_PT_IAOQ0(%r1),%r2
depi PRIV_USER,31,2,%r2 /* ensure return to user mode. */
STREG %r2,TASK_PT_IAOQ0(%r1)
LDREG TASK_PT_IAOQ1(%r1),%r2
depi PRIV_USER,31,2,%r2
STREG %r2,TASK_PT_IAOQ1(%r1)
b intr_restore
copy %r25,%r16
syscall_do_resched:
load32 syscall_check_resched,%r2 /* if resched, we start over again */
load32 schedule,%r19
bv %r0(%r19) /* jumps to schedule() */
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#else
nop
#endif
END(syscall_exit)
#ifdef CONFIG_FUNCTION_TRACER
.import ftrace_function_trampoline,code
.align L1_CACHE_BYTES
ENTRY_CFI(mcount, caller)
_mcount:
.export _mcount,data /* *The64bitmcount()functionpointerneeds4dwords,ofwhichthe *firsttwoarefree.Weoptimizeithereandput2instructionsfor *callingmcount(),and2instructionsforftrace_stub().Thatwaywe *haveallononeL1cacheline.
*/
ldi 0, %arg3
b ftrace_function_trampoline
copy %r3, %arg2 /* caller original %sp */
ftrace_stub:
.globl ftrace_stub
.type ftrace_stub, @function
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp)
#endif
nop
#ifdef CONFIG_64BIT
.dword mcount
.dword 0/* code in head.S puts value of global gp here */
#endif
ENDPROC_CFI(mcount)
ldo -PT_SZ_ALGN(%sp), %sp
LDREGM -FTRACE_FRAME_SIZE(%sp), %r1 /* Adjust return point to jump back to beginning of traced function */
ldo -4(%r1), %r1
bv,n (%r1)
/* restore original return values */
LDREG 8(%r3),%ret0
LDREG 16(%r3),%ret1
/* return from function */
#ifdef CONFIG_64BIT
bve (%rp)
#else
bv %r0(%rp)
#endif
LDREGM -FRAME_SIZE(%sp),%r3
ENDPROC_CFI(return_to_handler)
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_IRQSTACKS /* void call_on_stack(unsigned long param1, void *func,
unsigned long new_stack) */
ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
ENTRY(_call_on_stack)
copy %sp, %r1
/* Regarding the HPPA calling conventions for function pointers, weassumethePICregisterisnotchangedacrosscall.For CONFIG_64BIT,theargumentpointerislefttopointatthe
argument region allocated for the call to call_on_stack. */
/* Switch to new stack. We allocate two frames. */
ldo 2*FRAME_SIZE(%arg2), %sp
# ifdef CONFIG_64BIT /* Save previous stack pointer and return pointer in frame marker */
STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp) /* Calls always use function descriptor */
LDREG 16(%arg1), %arg1
bve,l (%arg1), %rp
STREG %r1, -FRAME_SIZE-REG_SZ(%sp)
LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp
bve (%rp)
LDREG -FRAME_SIZE-REG_SZ(%sp), %sp
# else /* Save previous stack pointer and return pointer in frame marker */
STREG %r1, -FRAME_SIZE-REG_SZ(%sp)
STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp) /* Calls use function descriptor if PLABEL bit is set */
bb,>=,n %arg1, 30, 1f
depwi 0,31,2, %arg1
LDREG 0(%arg1), %arg1 1:
be,l 0(%sr4,%arg1), %sr0, %r31
copy %r31, %rp
LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp
bv (%rp)
LDREG -FRAME_SIZE-REG_SZ(%sp), %sp
# endif /* CONFIG_64BIT */
ENDPROC_CFI(call_on_stack)
#endif /* CONFIG_IRQSTACKS */
¤ 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.0.37Bemerkung:
(vorverarbeitet am 2026-09-28)
¤
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.