| .align 32 |
| .globl __flushw_user |
| .type __flushw_user,#function |
| __flushw_user: |
| rdpr %otherwin, %g1 |
| brz,pn %g1, 2f |
| clr %g2 |
| 1: save %sp, -128, %sp |
| rdpr %otherwin, %g1 |
| brnz,pt %g1, 1b |
| add %g2, 1, %g2 |
| 1: sub %g2, 1, %g2 |
| brnz,pt %g2, 1b |
| restore %g0, %g0, %g0 |
| 2: retl |
| nop |
| .size __flushw_user,.-__flushw_user |
| |
| /* Flush %fp and %i7 to the stack for all register |
| * windows active inside of the cpu. This allows |
| * show_stack_trace() to avoid using an expensive |
| * 'flushw'. |
| */ |
| .globl stack_trace_flush |
| .type stack_trace_flush,#function |
| stack_trace_flush: |
| rdpr %pstate, %o0 |
| wrpr %o0, PSTATE_IE, %pstate |
| |
| rdpr %cwp, %g1 |
| rdpr %canrestore, %g2 |
| sub %g1, 1, %g3 |
| |
| 1: brz,pn %g2, 2f |
| sub %g2, 1, %g2 |
| wrpr %g3, %cwp |
| stx %fp, [%sp + STACK_BIAS + RW_V9_I6] |
| stx %i7, [%sp + STACK_BIAS + RW_V9_I7] |
| ba,pt %xcc, 1b |
| sub %g3, 1, %g3 |
| |
| 2: wrpr %g1, %cwp |
| wrpr %o0, %pstate |
| |
| retl |
| nop |
| .size stack_trace_flush,.-stack_trace_flush |
| |
| #ifdef CONFIG_PERF_EVENTS |
| .globl perf_arch_fetch_caller_regs |
| .type perf_arch_fetch_caller_regs,#function |
| perf_arch_fetch_caller_regs: |
| /* We always read the %pstate into %o5 since we will use |
| * that to construct a fake %tstate to store into the regs. |
| */ |
| rdpr %pstate, %o5 |
| brz,pn %o2, 50f |
| mov %o2, %g7 |
| |
| /* Turn off interrupts while we walk around the register |
| * window by hand. |
| */ |
| wrpr %o5, PSTATE_IE, %pstate |
| |
| /* The %canrestore tells us how many register windows are |
| * still live in the chip above us, past that we have to |
| * walk the frame as saved on the stack. We stash away |
| * the %cwp in %g1 so we can return back to the original |
| * register window. |
| */ |
| rdpr %cwp, %g1 |
| rdpr %canrestore, %g2 |
| sub %g1, 1, %g3 |
| |
| /* We have the skip count in %g7, if it hits zero then |
| * %fp/%i7 are the registers we need. Otherwise if our |
| * %canrestore count maintained in %g2 hits zero we have |
| * to start traversing the stack. |
| */ |
| 10: brz,pn %g2, 4f |
| sub %g2, 1, %g2 |
| wrpr %g3, %cwp |
| subcc %g7, 1, %g7 |
| bne,pt %xcc, 10b |
| sub %g3, 1, %g3 |
| |
| /* We found the values we need in the cpu's register |
| * windows. |
| */ |
| mov %fp, %g3 |
| ba,pt %xcc, 3f |
| mov %i7, %g2 |
| |
| 50: mov %fp, %g3 |
| ba,pt %xcc, 2f |
| mov %i7, %g2 |
| |
| /* We hit the end of the valid register windows in the |
| * cpu, start traversing the stack frame. |
| */ |
| 4: mov %fp, %g3 |
| |
| 20: ldx [%g3 + STACK_BIAS + RW_V9_I7], %g2 |
| subcc %g7, 1, %g7 |
| bne,pn %xcc, 20b |
| ldx [%g3 + STACK_BIAS + RW_V9_I6], %g3 |
| |
| /* Restore the current register window position and |
| * re-enable interrupts. |
| */ |
| 3: wrpr %g1, %cwp |
| wrpr %o5, %pstate |
| |
| 2: stx %g3, [%o0 + PT_V9_FP] |
| sllx %o5, 8, %o5 |
| stx %o5, [%o0 + PT_V9_TSTATE] |
| stx %g2, [%o0 + PT_V9_TPC] |
| add %g2, 4, %g2 |
| retl |
| stx %g2, [%o0 + PT_V9_TNPC] |
| .size perf_arch_fetch_caller_regs,.-perf_arch_fetch_caller_regs |
| #endif /* CONFIG_PERF_EVENTS */ |
| |
| #ifdef CONFIG_SMP |
| .globl hard_smp_processor_id |
| .type hard_smp_processor_id,#function |
| hard_smp_processor_id: |
| #endif |
| .globl real_hard_smp_processor_id |
| .type real_hard_smp_processor_id,#function |
| real_hard_smp_processor_id: |
| __GET_CPUID(%o0) |
| retl |
| nop |
| #ifdef CONFIG_SMP |
| .size hard_smp_processor_id,.-hard_smp_processor_id |
| #endif |
| .size real_hard_smp_processor_id,.-real_hard_smp_processor_id |