You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branch 'anton/abiv2' into next
This series adds support for building the powerpc 64-bit LE kernel using the new ABI v2. We already supported running ABI v2 userspace programs but this adds support for building the kernel itself using the new ABI.
This commit is contained in:
@@ -113,8 +113,13 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS-$(CONFIG_PPC64) := -mtraceback=no -mcall-aixdesc
|
||||
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv1)
|
||||
CFLAGS-$(CONFIG_PPC64) := -mtraceback=no
|
||||
ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y)
|
||||
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2,-mcall-aixdesc)
|
||||
AFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mabi=elfv2)
|
||||
else
|
||||
CFLAGS-$(CONFIG_PPC64) += -mcall-aixdesc
|
||||
endif
|
||||
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mcmodel=medium,-mminimal-toc)
|
||||
CFLAGS-$(CONFIG_PPC64) += $(call cc-option,-mno-pointers-to-nested-functions)
|
||||
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 $(MULTIPLEWORD)
|
||||
@@ -151,7 +156,7 @@ endif
|
||||
CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
|
||||
|
||||
KBUILD_CPPFLAGS += -Iarch/$(ARCH)
|
||||
KBUILD_AFLAGS += -Iarch/$(ARCH)
|
||||
KBUILD_AFLAGS += -Iarch/$(ARCH) $(AFLAGS-y)
|
||||
KBUILD_CFLAGS += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
|
||||
CPP = $(CC) -E $(KBUILD_CFLAGS)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ udelay:
|
||||
mfspr r4,SPRN_PVR
|
||||
srwi r4,r4,16
|
||||
cmpwi 0,r4,1 /* 601 ? */
|
||||
bne .udelay_not_601
|
||||
bne .Ludelay_not_601
|
||||
00: li r0,86 /* Instructions / microsecond? */
|
||||
mtctr r0
|
||||
10: addi r0,r0,0 /* NOP */
|
||||
@@ -54,7 +54,7 @@ udelay:
|
||||
bne 00b
|
||||
blr
|
||||
|
||||
.udelay_not_601:
|
||||
.Ludelay_not_601:
|
||||
mulli r4,r3,1000 /* nanoseconds */
|
||||
/* Change r4 to be the number of ticks using:
|
||||
* (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
|
||||
|
||||
@@ -42,15 +42,47 @@ void __patch_exception(int exc, unsigned long addr);
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define OP_RT_RA_MASK 0xffff0000UL
|
||||
#define LIS_R2 0x3c020000UL
|
||||
#define ADDIS_R2_R12 0x3c4c0000UL
|
||||
#define ADDI_R2_R2 0x38420000UL
|
||||
|
||||
static inline unsigned long ppc_function_entry(void *func)
|
||||
{
|
||||
#ifdef CONFIG_PPC64
|
||||
#if defined(CONFIG_PPC64)
|
||||
#if defined(_CALL_ELF) && _CALL_ELF == 2
|
||||
u32 *insn = func;
|
||||
|
||||
/*
|
||||
* On PPC64 the function pointer actually points to the function's
|
||||
* descriptor. The first entry in the descriptor is the address
|
||||
* of the function text.
|
||||
* A PPC64 ABIv2 function may have a local and a global entry
|
||||
* point. We need to use the local entry point when patching
|
||||
* functions, so identify and step over the global entry point
|
||||
* sequence.
|
||||
*
|
||||
* The global entry point sequence is always of the form:
|
||||
*
|
||||
* addis r2,r12,XXXX
|
||||
* addi r2,r2,XXXX
|
||||
*
|
||||
* A linker optimisation may convert the addis to lis:
|
||||
*
|
||||
* lis r2,XXXX
|
||||
* addi r2,r2,XXXX
|
||||
*/
|
||||
if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
|
||||
((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
|
||||
((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
|
||||
return (unsigned long)(insn + 2);
|
||||
else
|
||||
return (unsigned long)func;
|
||||
#else
|
||||
/*
|
||||
* On PPC64 ABIv1 the function pointer actually points to the
|
||||
* function's descriptor. The first entry in the descriptor is the
|
||||
* address of the function text.
|
||||
*/
|
||||
return ((func_descr_t *)func)->entry;
|
||||
#endif
|
||||
#else
|
||||
return (unsigned long)func;
|
||||
#endif
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#define _ASM_POWERPC_CONTEXT_TRACKING_H
|
||||
|
||||
#ifdef CONFIG_CONTEXT_TRACKING
|
||||
#define SCHEDULE_USER bl .schedule_user
|
||||
#define SCHEDULE_USER bl schedule_user
|
||||
#else
|
||||
#define SCHEDULE_USER bl .schedule
|
||||
#define SCHEDULE_USER bl schedule
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -174,10 +174,10 @@ exc_##label##_book3e:
|
||||
mtlr r16;
|
||||
#define TLB_MISS_STATS_D(name) \
|
||||
addi r9,r13,MMSTAT_DSTATS+name; \
|
||||
bl .tlb_stat_inc;
|
||||
bl tlb_stat_inc;
|
||||
#define TLB_MISS_STATS_I(name) \
|
||||
addi r9,r13,MMSTAT_ISTATS+name; \
|
||||
bl .tlb_stat_inc;
|
||||
bl tlb_stat_inc;
|
||||
#define TLB_MISS_STATS_X(name) \
|
||||
ld r8,PACA_EXTLB+EX_TLB_ESR(r13); \
|
||||
cmpdi cr2,r8,-1; \
|
||||
@@ -185,7 +185,7 @@ exc_##label##_book3e:
|
||||
addi r9,r13,MMSTAT_DSTATS+name; \
|
||||
b 62f; \
|
||||
61: addi r9,r13,MMSTAT_ISTATS+name; \
|
||||
62: bl .tlb_stat_inc;
|
||||
62: bl tlb_stat_inc;
|
||||
#define TLB_MISS_STATS_SAVE_INFO \
|
||||
std r14,EX_TLB_ESR(r12); /* save ESR */
|
||||
#define TLB_MISS_STATS_SAVE_INFO_BOLTED \
|
||||
|
||||
@@ -517,7 +517,7 @@ label##_relon_hv: \
|
||||
#define DISABLE_INTS RECONCILE_IRQ_STATE(r10,r11)
|
||||
|
||||
#define ADD_NVGPRS \
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
|
||||
#define RUNLATCH_ON \
|
||||
BEGIN_FTR_SECTION \
|
||||
|
||||
@@ -61,6 +61,7 @@ struct dyn_arch_ftrace {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && !defined(__ASSEMBLY__)
|
||||
#if !defined(_CALL_ELF) || _CALL_ELF != 2
|
||||
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||
static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
|
||||
{
|
||||
@@ -72,6 +73,7 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
|
||||
*/
|
||||
return !strcmp(sym + 4, name + 3);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 && !__ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_POWERPC_FTRACE */
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
*/
|
||||
#define TRACE_WITH_FRAME_BUFFER(func) \
|
||||
mflr r0; \
|
||||
stdu r1, -32(r1); \
|
||||
stdu r1, -STACK_FRAME_OVERHEAD(r1); \
|
||||
std r0, 16(r1); \
|
||||
stdu r1, -32(r1); \
|
||||
stdu r1, -STACK_FRAME_OVERHEAD(r1); \
|
||||
bl func; \
|
||||
ld r1, 0(r1); \
|
||||
ld r1, 0(r1);
|
||||
@@ -36,8 +36,8 @@
|
||||
* have to call a C function so call a wrapper that saves all the
|
||||
* C-clobbered registers.
|
||||
*/
|
||||
#define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
|
||||
#define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
|
||||
#define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(trace_hardirqs_on)
|
||||
#define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(trace_hardirqs_off)
|
||||
|
||||
/*
|
||||
* This is used by assembly code to soft-disable interrupts first and
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <asm/probes.h>
|
||||
#include <asm/code-patching.h>
|
||||
|
||||
#define __ARCH_WANT_KPROBES_INSN_SLOT
|
||||
|
||||
@@ -56,9 +57,9 @@ typedef ppc_opcode_t kprobe_opcode_t;
|
||||
if ((colon = strchr(name, ':')) != NULL) { \
|
||||
colon++; \
|
||||
if (*colon != '\0' && *colon != '.') \
|
||||
addr = *(kprobe_opcode_t **)addr; \
|
||||
addr = (kprobe_opcode_t *)ppc_function_entry(addr); \
|
||||
} else if (name[0] != '.') \
|
||||
addr = *(kprobe_opcode_t **)addr; \
|
||||
addr = (kprobe_opcode_t *)ppc_function_entry(addr); \
|
||||
} else { \
|
||||
char dot_name[KSYM_NAME_LEN]; \
|
||||
dot_name[0] = '.'; \
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _ASM_POWERPC_LINKAGE_H
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
#if !defined(_CALL_ELF) || _CALL_ELF != 2
|
||||
#define cond_syscall(x) \
|
||||
asm ("\t.weak " #x "\n\t.set " #x ", sys_ni_syscall\n" \
|
||||
"\t.weak ." #x "\n\t.set ." #x ", .sys_ni_syscall\n")
|
||||
@@ -9,5 +10,6 @@
|
||||
asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \
|
||||
"\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_POWERPC_LINKAGE_H */
|
||||
|
||||
@@ -35,6 +35,7 @@ struct mod_arch_specific {
|
||||
#ifdef __powerpc64__
|
||||
unsigned int stubs_section; /* Index of stubs section in module */
|
||||
unsigned int toc_section; /* What section is the TOC? */
|
||||
bool toc_fixed; /* Have we fixed up .TOC.? */
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
unsigned long toc;
|
||||
unsigned long tramp;
|
||||
@@ -77,6 +78,9 @@ struct mod_arch_specific {
|
||||
# endif /* MODULE */
|
||||
#endif
|
||||
|
||||
bool is_module_trampoline(u32 *insns);
|
||||
int module_trampoline_target(struct module *mod, u32 *trampoline,
|
||||
unsigned long *target);
|
||||
|
||||
struct exception_table_entry;
|
||||
void sort_ex_table(struct exception_table_entry *start,
|
||||
|
||||
@@ -57,7 +57,7 @@ BEGIN_FW_FTR_SECTION; \
|
||||
LDX_BE r10,0,r10; /* get log write index */ \
|
||||
cmpd cr1,r11,r10; \
|
||||
beq+ cr1,33f; \
|
||||
bl .accumulate_stolen_time; \
|
||||
bl accumulate_stolen_time; \
|
||||
ld r12,_MSR(r1); \
|
||||
andi. r10,r12,MSR_PR; /* Restore cr0 (coming from user) */ \
|
||||
33: \
|
||||
@@ -189,9 +189,45 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
|
||||
#define __STK_REG(i) (112 + ((i)-14)*8)
|
||||
#define STK_REG(i) __STK_REG(__REG_##i)
|
||||
|
||||
#if defined(_CALL_ELF) && _CALL_ELF == 2
|
||||
#define STK_GOT 24
|
||||
#define __STK_PARAM(i) (32 + ((i)-3)*8)
|
||||
#else
|
||||
#define STK_GOT 40
|
||||
#define __STK_PARAM(i) (48 + ((i)-3)*8)
|
||||
#endif
|
||||
#define STK_PARAM(i) __STK_PARAM(__REG_##i)
|
||||
|
||||
#if defined(_CALL_ELF) && _CALL_ELF == 2
|
||||
|
||||
#define _GLOBAL(name) \
|
||||
.section ".text"; \
|
||||
.align 2 ; \
|
||||
.type name,@function; \
|
||||
.globl name; \
|
||||
name:
|
||||
|
||||
#define _GLOBAL_TOC(name) \
|
||||
.section ".text"; \
|
||||
.align 2 ; \
|
||||
.type name,@function; \
|
||||
.globl name; \
|
||||
name: \
|
||||
0: addis r2,r12,(.TOC.-0b)@ha; \
|
||||
addi r2,r2,(.TOC.-0b)@l; \
|
||||
.localentry name,.-name
|
||||
|
||||
#define _KPROBE(name) \
|
||||
.section ".kprobes.text","a"; \
|
||||
.align 2 ; \
|
||||
.type name,@function; \
|
||||
.globl name; \
|
||||
name:
|
||||
|
||||
#define DOTSYM(a) a
|
||||
|
||||
#else
|
||||
|
||||
#define XGLUE(a,b) a##b
|
||||
#define GLUE(a,b) XGLUE(a,b)
|
||||
|
||||
@@ -209,19 +245,7 @@ name: \
|
||||
.type GLUE(.,name),@function; \
|
||||
GLUE(.,name):
|
||||
|
||||
#define _INIT_GLOBAL(name) \
|
||||
__REF; \
|
||||
.align 2 ; \
|
||||
.globl name; \
|
||||
.globl GLUE(.,name); \
|
||||
.section ".opd","aw"; \
|
||||
name: \
|
||||
.quad GLUE(.,name); \
|
||||
.quad .TOC.@tocbase; \
|
||||
.quad 0; \
|
||||
.previous; \
|
||||
.type GLUE(.,name),@function; \
|
||||
GLUE(.,name):
|
||||
#define _GLOBAL_TOC(name) _GLOBAL(name)
|
||||
|
||||
#define _KPROBE(name) \
|
||||
.section ".kprobes.text","a"; \
|
||||
@@ -237,29 +261,9 @@ name: \
|
||||
.type GLUE(.,name),@function; \
|
||||
GLUE(.,name):
|
||||
|
||||
#define _STATIC(name) \
|
||||
.section ".text"; \
|
||||
.align 2 ; \
|
||||
.section ".opd","aw"; \
|
||||
name: \
|
||||
.quad GLUE(.,name); \
|
||||
.quad .TOC.@tocbase; \
|
||||
.quad 0; \
|
||||
.previous; \
|
||||
.type GLUE(.,name),@function; \
|
||||
GLUE(.,name):
|
||||
#define DOTSYM(a) GLUE(.,a)
|
||||
|
||||
#define _INIT_STATIC(name) \
|
||||
__REF; \
|
||||
.align 2 ; \
|
||||
.section ".opd","aw"; \
|
||||
name: \
|
||||
.quad GLUE(.,name); \
|
||||
.quad .TOC.@tocbase; \
|
||||
.quad 0; \
|
||||
.previous; \
|
||||
.type GLUE(.,name),@function; \
|
||||
GLUE(.,name):
|
||||
#endif
|
||||
|
||||
#else /* 32-bit */
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
|
||||
(unsigned long)_stext < end;
|
||||
}
|
||||
|
||||
#if !defined(_CALL_ELF) || _CALL_ELF != 2
|
||||
#undef dereference_function_descriptor
|
||||
static inline void *dereference_function_descriptor(void *ptr)
|
||||
{
|
||||
@@ -49,6 +50,7 @@ static inline void *dereference_function_descriptor(void *ptr)
|
||||
ptr = p;
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ COMPAT_SYS_SPU(fcntl)
|
||||
SYSCALL(ni_syscall)
|
||||
SYSCALL_SPU(setpgid)
|
||||
SYSCALL(ni_syscall)
|
||||
SYSX(sys_ni_syscall,sys_olduname, sys_olduname)
|
||||
SYSX(sys_ni_syscall,sys_olduname,sys_olduname)
|
||||
SYSCALL_SPU(umask)
|
||||
SYSCALL_SPU(chroot)
|
||||
COMPAT_SYS(ustat)
|
||||
@@ -258,7 +258,7 @@ SYSCALL_SPU(tgkill)
|
||||
COMPAT_SYS_SPU(utimes)
|
||||
COMPAT_SYS_SPU(statfs64)
|
||||
COMPAT_SYS_SPU(fstatfs64)
|
||||
SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64)
|
||||
SYSX(sys_ni_syscall,ppc_fadvise64_64,ppc_fadvise64_64)
|
||||
PPC_SYS_SPU(rtas)
|
||||
OLDSYS(debug_setcontext)
|
||||
SYSCALL(ni_syscall)
|
||||
@@ -295,7 +295,7 @@ SYSCALL_SPU(mkdirat)
|
||||
SYSCALL_SPU(mknodat)
|
||||
SYSCALL_SPU(fchownat)
|
||||
COMPAT_SYS_SPU(futimesat)
|
||||
SYSX_SPU(sys_newfstatat, sys_fstatat64, sys_fstatat64)
|
||||
SYSX_SPU(sys_newfstatat,sys_fstatat64,sys_fstatat64)
|
||||
SYSCALL_SPU(unlinkat)
|
||||
SYSCALL_SPU(renameat)
|
||||
SYSCALL_SPU(linkat)
|
||||
|
||||
@@ -291,9 +291,17 @@ do { \
|
||||
#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
|
||||
#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
|
||||
#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
|
||||
#define R_PPC64_TLSGD 107
|
||||
#define R_PPC64_TLSLD 108
|
||||
#define R_PPC64_TOCSAVE 109
|
||||
|
||||
#define R_PPC64_REL16 249
|
||||
#define R_PPC64_REL16_LO 250
|
||||
#define R_PPC64_REL16_HI 251
|
||||
#define R_PPC64_REL16_HA 252
|
||||
|
||||
/* Keep this the last entry. */
|
||||
#define R_PPC64_NUM 107
|
||||
#define R_PPC64_NUM 253
|
||||
|
||||
/* There's actually a third entry here, but it's unused */
|
||||
struct ppc64_opd_entry
|
||||
|
||||
@@ -94,12 +94,12 @@ _GLOBAL(setup_altivec_idle)
|
||||
_GLOBAL(__setup_cpu_e6500)
|
||||
mflr r6
|
||||
#ifdef CONFIG_PPC64
|
||||
bl .setup_altivec_ivors
|
||||
bl setup_altivec_ivors
|
||||
/* Touch IVOR42 only if the CPU supports E.HV category */
|
||||
mfspr r10,SPRN_MMUCFG
|
||||
rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
|
||||
beq 1f
|
||||
bl .setup_lrat_ivor
|
||||
bl setup_lrat_ivor
|
||||
1:
|
||||
#endif
|
||||
bl setup_pw20_idle
|
||||
@@ -164,15 +164,15 @@ _GLOBAL(__setup_cpu_e5500)
|
||||
#ifdef CONFIG_PPC_BOOK3E_64
|
||||
_GLOBAL(__restore_cpu_e6500)
|
||||
mflr r5
|
||||
bl .setup_altivec_ivors
|
||||
bl setup_altivec_ivors
|
||||
/* Touch IVOR42 only if the CPU supports E.HV category */
|
||||
mfspr r10,SPRN_MMUCFG
|
||||
rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
|
||||
beq 1f
|
||||
bl .setup_lrat_ivor
|
||||
bl setup_lrat_ivor
|
||||
1:
|
||||
bl .setup_pw20_idle
|
||||
bl .setup_altivec_idle
|
||||
bl setup_pw20_idle
|
||||
bl setup_altivec_idle
|
||||
bl __restore_cpu_e5500
|
||||
mtlr r5
|
||||
blr
|
||||
@@ -181,9 +181,9 @@ _GLOBAL(__restore_cpu_e5500)
|
||||
mflr r4
|
||||
bl __e500_icache_setup
|
||||
bl __e500_dcache_setup
|
||||
bl .__setup_base_ivors
|
||||
bl .setup_perfmon_ivor
|
||||
bl .setup_doorbell_ivors
|
||||
bl __setup_base_ivors
|
||||
bl setup_perfmon_ivor
|
||||
bl setup_doorbell_ivors
|
||||
/*
|
||||
* We only want to touch IVOR38-41 if we're running on hardware
|
||||
* that supports category E.HV. The architectural way to determine
|
||||
@@ -192,7 +192,7 @@ _GLOBAL(__restore_cpu_e5500)
|
||||
mfspr r10,SPRN_MMUCFG
|
||||
rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
|
||||
beq 1f
|
||||
bl .setup_ehv_ivors
|
||||
bl setup_ehv_ivors
|
||||
1:
|
||||
mtlr r4
|
||||
blr
|
||||
@@ -201,9 +201,9 @@ _GLOBAL(__setup_cpu_e5500)
|
||||
mflr r5
|
||||
bl __e500_icache_setup
|
||||
bl __e500_dcache_setup
|
||||
bl .__setup_base_ivors
|
||||
bl .setup_perfmon_ivor
|
||||
bl .setup_doorbell_ivors
|
||||
bl __setup_base_ivors
|
||||
bl setup_perfmon_ivor
|
||||
bl setup_doorbell_ivors
|
||||
/*
|
||||
* We only want to touch IVOR38-41 if we're running on hardware
|
||||
* that supports category E.HV. The architectural way to determine
|
||||
@@ -212,7 +212,7 @@ _GLOBAL(__setup_cpu_e5500)
|
||||
mfspr r10,SPRN_MMUCFG
|
||||
rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
|
||||
beq 1f
|
||||
bl .setup_ehv_ivors
|
||||
bl setup_ehv_ivors
|
||||
b 2f
|
||||
1:
|
||||
ld r10,CPU_SPEC_FEATURES(r4)
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
* System calls.
|
||||
*/
|
||||
.section ".toc","aw"
|
||||
.SYS_CALL_TABLE:
|
||||
.tc .sys_call_table[TC],.sys_call_table
|
||||
SYS_CALL_TABLE:
|
||||
.tc sys_call_table[TC],sys_call_table
|
||||
|
||||
/* This value is used to mark exception frames on the stack. */
|
||||
exception_marker:
|
||||
@@ -106,7 +106,7 @@ BEGIN_FW_FTR_SECTION
|
||||
LDX_BE r10,0,r10 /* get log write index */
|
||||
cmpd cr1,r11,r10
|
||||
beq+ cr1,33f
|
||||
bl .accumulate_stolen_time
|
||||
bl accumulate_stolen_time
|
||||
REST_GPR(0,r1)
|
||||
REST_4GPRS(3,r1)
|
||||
REST_2GPRS(7,r1)
|
||||
@@ -143,7 +143,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
|
||||
std r10,SOFTE(r1)
|
||||
|
||||
#ifdef SHOW_SYSCALLS
|
||||
bl .do_show_syscall
|
||||
bl do_show_syscall
|
||||
REST_GPR(0,r1)
|
||||
REST_4GPRS(3,r1)
|
||||
REST_2GPRS(7,r1)
|
||||
@@ -162,7 +162,7 @@ system_call: /* label this so stack traces look sane */
|
||||
* Need to vector to 32 Bit or default sys_call_table here,
|
||||
* based on caller's run-mode / personality.
|
||||
*/
|
||||
ld r11,.SYS_CALL_TABLE@toc(2)
|
||||
ld r11,SYS_CALL_TABLE@toc(2)
|
||||
andi. r10,r10,_TIF_32BIT
|
||||
beq 15f
|
||||
addi r11,r11,8 /* use 32-bit syscall entries */
|
||||
@@ -174,14 +174,14 @@ system_call: /* label this so stack traces look sane */
|
||||
clrldi r8,r8,32
|
||||
15:
|
||||
slwi r0,r0,4
|
||||
ldx r10,r11,r0 /* Fetch system call handler [ptr] */
|
||||
mtctr r10
|
||||
ldx r12,r11,r0 /* Fetch system call handler [ptr] */
|
||||
mtctr r12
|
||||
bctrl /* Call handler */
|
||||
|
||||
syscall_exit:
|
||||
std r3,RESULT(r1)
|
||||
#ifdef SHOW_SYSCALLS
|
||||
bl .do_show_syscall_exit
|
||||
bl do_show_syscall_exit
|
||||
ld r3,RESULT(r1)
|
||||
#endif
|
||||
CURRENT_THREAD_INFO(r12, r1)
|
||||
@@ -248,9 +248,9 @@ syscall_error:
|
||||
|
||||
/* Traced system call support */
|
||||
syscall_dotrace:
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .do_syscall_trace_enter
|
||||
bl do_syscall_trace_enter
|
||||
/*
|
||||
* Restore argument registers possibly just changed.
|
||||
* We use the return value of do_syscall_trace_enter
|
||||
@@ -308,7 +308,7 @@ syscall_exit_work:
|
||||
4: /* Anything else left to do? */
|
||||
SET_DEFAULT_THREAD_PPR(r3, r10) /* Set thread.ppr = 3 */
|
||||
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
|
||||
beq .ret_from_except_lite
|
||||
beq ret_from_except_lite
|
||||
|
||||
/* Re-enable interrupts */
|
||||
#ifdef CONFIG_PPC_BOOK3E
|
||||
@@ -319,10 +319,10 @@ syscall_exit_work:
|
||||
mtmsrd r10,1
|
||||
#endif /* CONFIG_PPC_BOOK3E */
|
||||
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .do_syscall_trace_leave
|
||||
b .ret_from_except
|
||||
bl do_syscall_trace_leave
|
||||
b ret_from_except
|
||||
|
||||
/* Save non-volatile GPRs, if not already saved. */
|
||||
_GLOBAL(save_nvgprs)
|
||||
@@ -345,42 +345,44 @@ _GLOBAL(save_nvgprs)
|
||||
*/
|
||||
|
||||
_GLOBAL(ppc_fork)
|
||||
bl .save_nvgprs
|
||||
bl .sys_fork
|
||||
bl save_nvgprs
|
||||
bl sys_fork
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ppc_vfork)
|
||||
bl .save_nvgprs
|
||||
bl .sys_vfork
|
||||
bl save_nvgprs
|
||||
bl sys_vfork
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ppc_clone)
|
||||
bl .save_nvgprs
|
||||
bl .sys_clone
|
||||
bl save_nvgprs
|
||||
bl sys_clone
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ppc32_swapcontext)
|
||||
bl .save_nvgprs
|
||||
bl .compat_sys_swapcontext
|
||||
bl save_nvgprs
|
||||
bl compat_sys_swapcontext
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ppc64_swapcontext)
|
||||
bl .save_nvgprs
|
||||
bl .sys_swapcontext
|
||||
bl save_nvgprs
|
||||
bl sys_swapcontext
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ret_from_fork)
|
||||
bl .schedule_tail
|
||||
bl schedule_tail
|
||||
REST_NVGPRS(r1)
|
||||
li r3,0
|
||||
b syscall_exit
|
||||
|
||||
_GLOBAL(ret_from_kernel_thread)
|
||||
bl .schedule_tail
|
||||
bl schedule_tail
|
||||
REST_NVGPRS(r1)
|
||||
ld r14, 0(r14)
|
||||
mtlr r14
|
||||
mr r3,r15
|
||||
#if defined(_CALL_ELF) && _CALL_ELF == 2
|
||||
mr r12,r14
|
||||
#endif
|
||||
blrl
|
||||
li r3,0
|
||||
b syscall_exit
|
||||
@@ -611,7 +613,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
|
||||
_GLOBAL(ret_from_except)
|
||||
ld r11,_TRAP(r1)
|
||||
andi. r0,r11,1
|
||||
bne .ret_from_except_lite
|
||||
bne ret_from_except_lite
|
||||
REST_NVGPRS(r1)
|
||||
|
||||
_GLOBAL(ret_from_except_lite)
|
||||
@@ -661,23 +663,23 @@ _GLOBAL(ret_from_except_lite)
|
||||
#endif
|
||||
1: andi. r0,r4,_TIF_NEED_RESCHED
|
||||
beq 2f
|
||||
bl .restore_interrupts
|
||||
bl restore_interrupts
|
||||
SCHEDULE_USER
|
||||
b .ret_from_except_lite
|
||||
b ret_from_except_lite
|
||||
2:
|
||||
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
|
||||
andi. r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM
|
||||
bne 3f /* only restore TM if nothing else to do */
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .restore_tm_state
|
||||
bl restore_tm_state
|
||||
b restore
|
||||
3:
|
||||
#endif
|
||||
bl .save_nvgprs
|
||||
bl .restore_interrupts
|
||||
bl save_nvgprs
|
||||
bl restore_interrupts
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .do_notify_resume
|
||||
b .ret_from_except
|
||||
bl do_notify_resume
|
||||
b ret_from_except
|
||||
|
||||
resume_kernel:
|
||||
/* check current_thread_info, _TIF_EMULATE_STACK_STORE */
|
||||
@@ -730,7 +732,7 @@ resume_kernel:
|
||||
* sure we are soft-disabled first and reconcile irq state.
|
||||
*/
|
||||
RECONCILE_IRQ_STATE(r3,r4)
|
||||
1: bl .preempt_schedule_irq
|
||||
1: bl preempt_schedule_irq
|
||||
|
||||
/* Re-test flags and eventually loop */
|
||||
CURRENT_THREAD_INFO(r9, r1)
|
||||
@@ -792,7 +794,7 @@ restore_no_replay:
|
||||
*/
|
||||
do_restore:
|
||||
#ifdef CONFIG_PPC_BOOK3E
|
||||
b .exception_return_book3e
|
||||
b exception_return_book3e
|
||||
#else
|
||||
/*
|
||||
* Clear the reservation. If we know the CPU tracks the address of
|
||||
@@ -907,7 +909,7 @@ restore_check_irq_replay:
|
||||
*
|
||||
* Still, this might be useful for things like hash_page
|
||||
*/
|
||||
bl .__check_irq_replay
|
||||
bl __check_irq_replay
|
||||
cmpwi cr0,r3,0
|
||||
beq restore_no_replay
|
||||
|
||||
@@ -928,13 +930,13 @@ restore_check_irq_replay:
|
||||
cmpwi cr0,r3,0x500
|
||||
bne 1f
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD;
|
||||
bl .do_IRQ
|
||||
b .ret_from_except
|
||||
bl do_IRQ
|
||||
b ret_from_except
|
||||
1: cmpwi cr0,r3,0x900
|
||||
bne 1f
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD;
|
||||
bl .timer_interrupt
|
||||
b .ret_from_except
|
||||
bl timer_interrupt
|
||||
b ret_from_except
|
||||
#ifdef CONFIG_PPC_DOORBELL
|
||||
1:
|
||||
#ifdef CONFIG_PPC_BOOK3E
|
||||
@@ -948,14 +950,14 @@ restore_check_irq_replay:
|
||||
#endif /* CONFIG_PPC_BOOK3E */
|
||||
bne 1f
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD;
|
||||
bl .doorbell_exception
|
||||
b .ret_from_except
|
||||
bl doorbell_exception
|
||||
b ret_from_except
|
||||
#endif /* CONFIG_PPC_DOORBELL */
|
||||
1: b .ret_from_except /* What else to do here ? */
|
||||
1: b ret_from_except /* What else to do here ? */
|
||||
|
||||
unrecov_restore:
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .unrecoverable_exception
|
||||
bl unrecoverable_exception
|
||||
b unrecov_restore
|
||||
|
||||
#ifdef CONFIG_PPC_RTAS
|
||||
@@ -1021,7 +1023,7 @@ _GLOBAL(enter_rtas)
|
||||
std r6,PACASAVEDMSR(r13)
|
||||
|
||||
/* Setup our real return addr */
|
||||
LOAD_REG_ADDR(r4,.rtas_return_loc)
|
||||
LOAD_REG_ADDR(r4,rtas_return_loc)
|
||||
clrldi r4,r4,2 /* convert to realmode address */
|
||||
mtlr r4
|
||||
|
||||
@@ -1045,7 +1047,7 @@ _GLOBAL(enter_rtas)
|
||||
rfid
|
||||
b . /* prevent speculative execution */
|
||||
|
||||
_STATIC(rtas_return_loc)
|
||||
rtas_return_loc:
|
||||
FIXUP_ENDIAN
|
||||
|
||||
/* relocation is off at this point */
|
||||
@@ -1054,7 +1056,7 @@ _STATIC(rtas_return_loc)
|
||||
|
||||
bcl 20,31,$+4
|
||||
0: mflr r3
|
||||
ld r3,(1f-0b)(r3) /* get &.rtas_restore_regs */
|
||||
ld r3,(1f-0b)(r3) /* get &rtas_restore_regs */
|
||||
|
||||
mfmsr r6
|
||||
li r0,MSR_RI
|
||||
@@ -1071,9 +1073,9 @@ _STATIC(rtas_return_loc)
|
||||
b . /* prevent speculative execution */
|
||||
|
||||
.align 3
|
||||
1: .llong .rtas_restore_regs
|
||||
1: .llong rtas_restore_regs
|
||||
|
||||
_STATIC(rtas_restore_regs)
|
||||
rtas_restore_regs:
|
||||
/* relocation is on at this point */
|
||||
REST_GPR(2, r1) /* Restore the TOC */
|
||||
REST_GPR(13, r1) /* Restore paca */
|
||||
@@ -1173,7 +1175,7 @@ _GLOBAL(mcount)
|
||||
_GLOBAL(_mcount)
|
||||
blr
|
||||
|
||||
_GLOBAL(ftrace_caller)
|
||||
_GLOBAL_TOC(ftrace_caller)
|
||||
/* Taken from output of objdump from lib64/glibc */
|
||||
mflr r3
|
||||
ld r11, 0(r1)
|
||||
@@ -1197,10 +1199,7 @@ _GLOBAL(ftrace_graph_stub)
|
||||
_GLOBAL(ftrace_stub)
|
||||
blr
|
||||
#else
|
||||
_GLOBAL(mcount)
|
||||
blr
|
||||
|
||||
_GLOBAL(_mcount)
|
||||
_GLOBAL_TOC(_mcount)
|
||||
/* Taken from output of objdump from lib64/glibc */
|
||||
mflr r3
|
||||
ld r11, 0(r1)
|
||||
@@ -1238,7 +1237,7 @@ _GLOBAL(ftrace_graph_caller)
|
||||
ld r11, 112(r1)
|
||||
addi r3, r11, 16
|
||||
|
||||
bl .prepare_ftrace_return
|
||||
bl prepare_ftrace_return
|
||||
nop
|
||||
|
||||
ld r0, 128(r1)
|
||||
@@ -1254,7 +1253,7 @@ _GLOBAL(return_to_handler)
|
||||
mr r31, r1
|
||||
stdu r1, -112(r1)
|
||||
|
||||
bl .ftrace_return_to_handler
|
||||
bl ftrace_return_to_handler
|
||||
nop
|
||||
|
||||
/* return value has real return address */
|
||||
@@ -1284,7 +1283,7 @@ _GLOBAL(mod_return_to_handler)
|
||||
*/
|
||||
ld r2, PACATOC(r13)
|
||||
|
||||
bl .ftrace_return_to_handler
|
||||
bl ftrace_return_to_handler
|
||||
nop
|
||||
|
||||
/* return value has real return address */
|
||||
|
||||
@@ -499,7 +499,7 @@ exc_##n##_bad_stack: \
|
||||
CHECK_NAPPING(); \
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD; \
|
||||
bl hdlr; \
|
||||
b .ret_from_except_lite;
|
||||
b ret_from_except_lite;
|
||||
|
||||
/* This value is used to mark exception frames on the stack. */
|
||||
.section ".toc","aw"
|
||||
@@ -550,11 +550,11 @@ interrupt_end_book3e:
|
||||
CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL,
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON_CRIT(0x100)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
bl special_reg_save
|
||||
CHECK_NAPPING();
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .unknown_exception
|
||||
bl unknown_exception
|
||||
b ret_from_crit_except
|
||||
|
||||
/* Machine Check Interrupt */
|
||||
@@ -562,11 +562,11 @@ interrupt_end_book3e:
|
||||
MC_EXCEPTION_PROLOG(0x000, BOOKE_INTERRUPT_MACHINE_CHECK,
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON_MC(0x000)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
bl special_reg_save
|
||||
CHECK_NAPPING();
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .machine_check_exception
|
||||
bl machine_check_exception
|
||||
b ret_from_mc_except
|
||||
|
||||
/* Data Storage Interrupt */
|
||||
@@ -591,7 +591,7 @@ interrupt_end_book3e:
|
||||
|
||||
/* External Input Interrupt */
|
||||
MASKABLE_EXCEPTION(0x500, BOOKE_INTERRUPT_EXTERNAL,
|
||||
external_input, .do_IRQ, ACK_NONE)
|
||||
external_input, do_IRQ, ACK_NONE)
|
||||
|
||||
/* Alignment */
|
||||
START_EXCEPTION(alignment);
|
||||
@@ -612,9 +612,9 @@ interrupt_end_book3e:
|
||||
std r14,_DSISR(r1)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
ld r14,PACA_EXGEN+EX_R14(r13)
|
||||
bl .save_nvgprs
|
||||
bl .program_check_exception
|
||||
b .ret_from_except
|
||||
bl save_nvgprs
|
||||
bl program_check_exception
|
||||
b ret_from_except
|
||||
|
||||
/* Floating Point Unavailable Interrupt */
|
||||
START_EXCEPTION(fp_unavailable);
|
||||
@@ -625,13 +625,13 @@ interrupt_end_book3e:
|
||||
ld r12,_MSR(r1)
|
||||
andi. r0,r12,MSR_PR;
|
||||
beq- 1f
|
||||
bl .load_up_fpu
|
||||
bl load_up_fpu
|
||||
b fast_exception_return
|
||||
1: INTS_DISABLE
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .kernel_fp_unavailable_exception
|
||||
b .ret_from_except
|
||||
bl kernel_fp_unavailable_exception
|
||||
b ret_from_except
|
||||
|
||||
/* Altivec Unavailable Interrupt */
|
||||
START_EXCEPTION(altivec_unavailable);
|
||||
@@ -644,16 +644,16 @@ BEGIN_FTR_SECTION
|
||||
ld r12,_MSR(r1)
|
||||
andi. r0,r12,MSR_PR;
|
||||
beq- 1f
|
||||
bl .load_up_altivec
|
||||
bl load_up_altivec
|
||||
b fast_exception_return
|
||||
1:
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
#endif
|
||||
INTS_DISABLE
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .altivec_unavailable_exception
|
||||
b .ret_from_except
|
||||
bl altivec_unavailable_exception
|
||||
b ret_from_except
|
||||
|
||||
/* AltiVec Assist */
|
||||
START_EXCEPTION(altivec_assist);
|
||||
@@ -662,39 +662,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON(0x220)
|
||||
INTS_DISABLE
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
BEGIN_FTR_SECTION
|
||||
bl .altivec_assist_exception
|
||||
bl altivec_assist_exception
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
#else
|
||||
bl .unknown_exception
|
||||
bl unknown_exception
|
||||
#endif
|
||||
b .ret_from_except
|
||||
b ret_from_except
|
||||
|
||||
|
||||
/* Decrementer Interrupt */
|
||||
MASKABLE_EXCEPTION(0x900, BOOKE_INTERRUPT_DECREMENTER,
|
||||
decrementer, .timer_interrupt, ACK_DEC)
|
||||
decrementer, timer_interrupt, ACK_DEC)
|
||||
|
||||
/* Fixed Interval Timer Interrupt */
|
||||
MASKABLE_EXCEPTION(0x980, BOOKE_INTERRUPT_FIT,
|
||||
fixed_interval, .unknown_exception, ACK_FIT)
|
||||
fixed_interval, unknown_exception, ACK_FIT)
|
||||
|
||||
/* Watchdog Timer Interrupt */
|
||||
START_EXCEPTION(watchdog);
|
||||
CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG,
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON_CRIT(0x9f0)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
bl special_reg_save
|
||||
CHECK_NAPPING();
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
#ifdef CONFIG_BOOKE_WDT
|
||||
bl .WatchdogException
|
||||
bl WatchdogException
|
||||
#else
|
||||
bl .unknown_exception
|
||||
bl unknown_exception
|
||||
#endif
|
||||
b ret_from_crit_except
|
||||
|
||||
@@ -712,10 +712,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON(0xf20)
|
||||
INTS_DISABLE
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .unknown_exception
|
||||
b .ret_from_except
|
||||
bl unknown_exception
|
||||
b ret_from_except
|
||||
|
||||
/* Debug exception as a critical interrupt*/
|
||||
START_EXCEPTION(debug_crit);
|
||||
@@ -774,9 +774,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
mr r4,r14
|
||||
ld r14,PACA_EXCRIT+EX_R14(r13)
|
||||
ld r15,PACA_EXCRIT+EX_R15(r13)
|
||||
bl .save_nvgprs
|
||||
bl .DebugException
|
||||
b .ret_from_except
|
||||
bl save_nvgprs
|
||||
bl DebugException
|
||||
b ret_from_except
|
||||
|
||||
kernel_dbg_exc:
|
||||
b . /* NYI */
|
||||
@@ -839,9 +839,9 @@ kernel_dbg_exc:
|
||||
mr r4,r14
|
||||
ld r14,PACA_EXDBG+EX_R14(r13)
|
||||
ld r15,PACA_EXDBG+EX_R15(r13)
|
||||
bl .save_nvgprs
|
||||
bl .DebugException
|
||||
b .ret_from_except
|
||||
bl save_nvgprs
|
||||
bl DebugException
|
||||
b ret_from_except
|
||||
|
||||
START_EXCEPTION(perfmon);
|
||||
NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR,
|
||||
@@ -850,23 +850,23 @@ kernel_dbg_exc:
|
||||
INTS_DISABLE
|
||||
CHECK_NAPPING()
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .performance_monitor_exception
|
||||
b .ret_from_except_lite
|
||||
bl performance_monitor_exception
|
||||
b ret_from_except_lite
|
||||
|
||||
/* Doorbell interrupt */
|
||||
MASKABLE_EXCEPTION(0x280, BOOKE_INTERRUPT_DOORBELL,
|
||||
doorbell, .doorbell_exception, ACK_NONE)
|
||||
doorbell, doorbell_exception, ACK_NONE)
|
||||
|
||||
/* Doorbell critical Interrupt */
|
||||
START_EXCEPTION(doorbell_crit);
|
||||
CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL,
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON_CRIT(0x2a0)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
bl special_reg_save
|
||||
CHECK_NAPPING();
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .unknown_exception
|
||||
bl unknown_exception
|
||||
b ret_from_crit_except
|
||||
|
||||
/*
|
||||
@@ -878,21 +878,21 @@ kernel_dbg_exc:
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON(0x2c0)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
INTS_RESTORE_HARD
|
||||
bl .unknown_exception
|
||||
b .ret_from_except
|
||||
bl unknown_exception
|
||||
b ret_from_except
|
||||
|
||||
/* Guest Doorbell critical Interrupt */
|
||||
START_EXCEPTION(guest_doorbell_crit);
|
||||
CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT,
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON_CRIT(0x2e0)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
bl special_reg_save
|
||||
CHECK_NAPPING();
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .unknown_exception
|
||||
bl unknown_exception
|
||||
b ret_from_crit_except
|
||||
|
||||
/* Hypervisor call */
|
||||
@@ -901,10 +901,10 @@ kernel_dbg_exc:
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON(0x310)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
INTS_RESTORE_HARD
|
||||
bl .unknown_exception
|
||||
b .ret_from_except
|
||||
bl unknown_exception
|
||||
b ret_from_except
|
||||
|
||||
/* Embedded Hypervisor priviledged */
|
||||
START_EXCEPTION(ehpriv);
|
||||
@@ -912,10 +912,10 @@ kernel_dbg_exc:
|
||||
PROLOG_ADDITION_NONE)
|
||||
EXCEPTION_COMMON(0x320)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
INTS_RESTORE_HARD
|
||||
bl .unknown_exception
|
||||
b .ret_from_except
|
||||
bl unknown_exception
|
||||
b ret_from_except
|
||||
|
||||
/* LRAT Error interrupt */
|
||||
START_EXCEPTION(lrat_error);
|
||||
@@ -1014,16 +1014,16 @@ storage_fault_common:
|
||||
mr r5,r15
|
||||
ld r14,PACA_EXGEN+EX_R14(r13)
|
||||
ld r15,PACA_EXGEN+EX_R15(r13)
|
||||
bl .do_page_fault
|
||||
bl do_page_fault
|
||||
cmpdi r3,0
|
||||
bne- 1f
|
||||
b .ret_from_except_lite
|
||||
1: bl .save_nvgprs
|
||||
b ret_from_except_lite
|
||||
1: bl save_nvgprs
|
||||
mr r5,r3
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
ld r4,_DAR(r1)
|
||||
bl .bad_page_fault
|
||||
b .ret_from_except
|
||||
bl bad_page_fault
|
||||
b ret_from_except
|
||||
|
||||
/*
|
||||
* Alignment exception doesn't fit entirely in the 0x100 bytes so it
|
||||
@@ -1035,10 +1035,10 @@ alignment_more:
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
ld r14,PACA_EXGEN+EX_R14(r13)
|
||||
ld r15,PACA_EXGEN+EX_R15(r13)
|
||||
bl .save_nvgprs
|
||||
bl save_nvgprs
|
||||
INTS_RESTORE_HARD
|
||||
bl .alignment_exception
|
||||
b .ret_from_except
|
||||
bl alignment_exception
|
||||
b ret_from_except
|
||||
|
||||
/*
|
||||
* We branch here from entry_64.S for the last stage of the exception
|
||||
@@ -1172,7 +1172,7 @@ bad_stack_book3e:
|
||||
std r12,0(r11)
|
||||
ld r2,PACATOC(r13)
|
||||
1: addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
bl .kernel_bad_stack
|
||||
bl kernel_bad_stack
|
||||
b 1b
|
||||
|
||||
/*
|
||||
@@ -1521,13 +1521,13 @@ _GLOBAL(start_initialization_book3e)
|
||||
* and always use AS 0, so we just set it up to match our link
|
||||
* address and never use 0 based addresses.
|
||||
*/
|
||||
bl .initial_tlb_book3e
|
||||
bl initial_tlb_book3e
|
||||
|
||||
/* Init global core bits */
|
||||
bl .init_core_book3e
|
||||
bl init_core_book3e
|
||||
|
||||
/* Init per-thread bits */
|
||||
bl .init_thread_book3e
|
||||
bl init_thread_book3e
|
||||
|
||||
/* Return to common init code */
|
||||
tovirt(r28,r28)
|
||||
@@ -1548,7 +1548,7 @@ _GLOBAL(start_initialization_book3e)
|
||||
*/
|
||||
_GLOBAL(book3e_secondary_core_init_tlb_set)
|
||||
li r4,1
|
||||
b .generic_secondary_smp_init
|
||||
b generic_secondary_smp_init
|
||||
|
||||
_GLOBAL(book3e_secondary_core_init)
|
||||
mflr r28
|
||||
@@ -1558,18 +1558,18 @@ _GLOBAL(book3e_secondary_core_init)
|
||||
bne 2f
|
||||
|
||||
/* Setup TLB for this core */
|
||||
bl .initial_tlb_book3e
|
||||
bl initial_tlb_book3e
|
||||
|
||||
/* We can return from the above running at a different
|
||||
* address, so recalculate r2 (TOC)
|
||||
*/
|
||||
bl .relative_toc
|
||||
bl relative_toc
|
||||
|
||||
/* Init global core bits */
|
||||
2: bl .init_core_book3e
|
||||
2: bl init_core_book3e
|
||||
|
||||
/* Init per-thread bits */
|
||||
3: bl .init_thread_book3e
|
||||
3: bl init_thread_book3e
|
||||
|
||||
/* Return to common init code at proper virtual address.
|
||||
*
|
||||
@@ -1596,14 +1596,14 @@ _GLOBAL(book3e_secondary_thread_init)
|
||||
mflr r28
|
||||
b 3b
|
||||
|
||||
_STATIC(init_core_book3e)
|
||||
init_core_book3e:
|
||||
/* Establish the interrupt vector base */
|
||||
LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e)
|
||||
mtspr SPRN_IVPR,r3
|
||||
sync
|
||||
blr
|
||||
|
||||
_STATIC(init_thread_book3e)
|
||||
init_thread_book3e:
|
||||
lis r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h
|
||||
mtspr SPRN_EPCR,r3
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -105,11 +105,9 @@ __ftrace_make_nop(struct module *mod,
|
||||
struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
unsigned int op;
|
||||
unsigned int jmp[5];
|
||||
unsigned long ptr;
|
||||
unsigned long ip = rec->ip;
|
||||
unsigned long tramp;
|
||||
int offset;
|
||||
void *tramp;
|
||||
|
||||
/* read where this goes */
|
||||
if (probe_kernel_read(&op, (void *)ip, sizeof(int)))
|
||||
@@ -122,96 +120,41 @@ __ftrace_make_nop(struct module *mod,
|
||||
}
|
||||
|
||||
/* lets find where the pointer goes */
|
||||
tramp = find_bl_target(ip, op);
|
||||
tramp = (void *)find_bl_target(ip, op);
|
||||
|
||||
/*
|
||||
* On PPC64 the trampoline looks like:
|
||||
* 0x3d, 0x82, 0x00, 0x00, addis r12,r2, <high>
|
||||
* 0x39, 0x8c, 0x00, 0x00, addi r12,r12, <low>
|
||||
* Where the bytes 2,3,6 and 7 make up the 32bit offset
|
||||
* to the TOC that holds the pointer.
|
||||
* to jump to.
|
||||
* 0xf8, 0x41, 0x00, 0x28, std r2,40(r1)
|
||||
* 0xe9, 0x6c, 0x00, 0x20, ld r11,32(r12)
|
||||
* The actually address is 32 bytes from the offset
|
||||
* into the TOC.
|
||||
* 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12)
|
||||
*/
|
||||
pr_devel("ip:%lx jumps to %p", ip, tramp);
|
||||
|
||||
pr_devel("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc);
|
||||
|
||||
/* Find where the trampoline jumps to */
|
||||
if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
|
||||
printk(KERN_ERR "Failed to read %lx\n", tramp);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
pr_devel(" %08x %08x", jmp[0], jmp[1]);
|
||||
|
||||
/* verify that this is what we expect it to be */
|
||||
if (((jmp[0] & 0xffff0000) != 0x3d820000) ||
|
||||
((jmp[1] & 0xffff0000) != 0x398c0000) ||
|
||||
(jmp[2] != 0xf8410028) ||
|
||||
(jmp[3] != 0xe96c0020) ||
|
||||
(jmp[4] != 0xe84c0028)) {
|
||||
if (!is_module_trampoline(tramp)) {
|
||||
printk(KERN_ERR "Not a trampoline\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The bottom half is signed extended */
|
||||
offset = ((unsigned)((unsigned short)jmp[0]) << 16) +
|
||||
(int)((short)jmp[1]);
|
||||
|
||||
pr_devel(" %x ", offset);
|
||||
|
||||
/* get the address this jumps too */
|
||||
tramp = mod->arch.toc + offset + 32;
|
||||
pr_devel("toc: %lx", tramp);
|
||||
|
||||
if (probe_kernel_read(jmp, (void *)tramp, 8)) {
|
||||
printk(KERN_ERR "Failed to read %lx\n", tramp);
|
||||
if (module_trampoline_target(mod, tramp, &ptr)) {
|
||||
printk(KERN_ERR "Failed to get trampoline target\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
pr_devel(" %08x %08x\n", jmp[0], jmp[1]);
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
ptr = ((unsigned long)jmp[1] << 32) + jmp[0];
|
||||
#else
|
||||
ptr = ((unsigned long)jmp[0] << 32) + jmp[1];
|
||||
#endif
|
||||
pr_devel("trampoline target %lx", ptr);
|
||||
|
||||
/* This should match what was called */
|
||||
if (ptr != ppc_function_entry((void *)addr)) {
|
||||
printk(KERN_ERR "addr does not match %lx\n", ptr);
|
||||
printk(KERN_ERR "addr %lx does not match expected %lx\n",
|
||||
ptr, ppc_function_entry((void *)addr));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to nop the line, but the next line is
|
||||
* 0xe8, 0x41, 0x00, 0x28 ld r2,40(r1)
|
||||
* This needs to be turned to a nop too.
|
||||
*/
|
||||
if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE))
|
||||
return -EFAULT;
|
||||
|
||||
if (op != 0xe8410028) {
|
||||
printk(KERN_ERR "Next line is not ld! (%08x)\n", op);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Milton Miller pointed out that we can not blindly do nops.
|
||||
* If a task was preempted when calling a trace function,
|
||||
* the nops will remove the way to restore the TOC in r2
|
||||
* and the r2 TOC will get corrupted.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Replace:
|
||||
* bl <tramp> <==== will be replaced with "b 1f"
|
||||
* ld r2,40(r1)
|
||||
* 1:
|
||||
* Our original call site looks like:
|
||||
*
|
||||
* bl <tramp>
|
||||
* ld r2,XX(r1)
|
||||
*
|
||||
* Milton Miller pointed out that we can not simply nop the branch.
|
||||
* If a task was preempted when calling a trace function, the nops
|
||||
* will remove the way to restore the TOC in r2 and the r2 TOC will
|
||||
* get corrupted.
|
||||
*
|
||||
* Use a b +8 to jump over the load.
|
||||
*/
|
||||
op = 0x48000008; /* b +8 */
|
||||
|
||||
@@ -349,19 +292,24 @@ static int
|
||||
__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
unsigned int op[2];
|
||||
unsigned long ip = rec->ip;
|
||||
void *ip = (void *)rec->ip;
|
||||
|
||||
/* read where this goes */
|
||||
if (probe_kernel_read(op, (void *)ip, MCOUNT_INSN_SIZE * 2))
|
||||
if (probe_kernel_read(op, ip, sizeof(op)))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* It should be pointing to two nops or
|
||||
* b +8; ld r2,40(r1)
|
||||
* We expect to see:
|
||||
*
|
||||
* b +8
|
||||
* ld r2,XX(r1)
|
||||
*
|
||||
* The load offset is different depending on the ABI. For simplicity
|
||||
* just mask it out when doing the compare.
|
||||
*/
|
||||
if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) &&
|
||||
((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) {
|
||||
printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]);
|
||||
if ((op[0] != 0x48000008) || ((op[1] & 0xffff00000) != 0xe8410000)) {
|
||||
printk(KERN_ERR "Unexpected call sequence: %x %x\n",
|
||||
op[0], op[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -371,23 +319,16 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* create the branch to the trampoline */
|
||||
op[0] = create_branch((unsigned int *)ip,
|
||||
rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
|
||||
if (!op[0]) {
|
||||
printk(KERN_ERR "REL24 out of range!\n");
|
||||
/* Ensure branch is within 24 bits */
|
||||
if (create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
|
||||
printk(KERN_ERR "Branch out of range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* ld r2,40(r1) */
|
||||
op[1] = 0xe8410028;
|
||||
|
||||
pr_devel("write to %lx\n", rec->ip);
|
||||
|
||||
if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2))
|
||||
return -EPERM;
|
||||
|
||||
flush_icache_range(ip, ip + 8);
|
||||
if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
|
||||
printk(KERN_ERR "REL24 out of range!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user