diff options
34 files changed, 890 insertions, 502 deletions
diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 6555d1781132..941e3e2adf41 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig | |||
| @@ -29,15 +29,20 @@ config CSKY | |||
| 29 | select GENERIC_SCHED_CLOCK | 29 | select GENERIC_SCHED_CLOCK |
| 30 | select GENERIC_SMP_IDLE_THREAD | 30 | select GENERIC_SMP_IDLE_THREAD |
| 31 | select HAVE_ARCH_TRACEHOOK | 31 | select HAVE_ARCH_TRACEHOOK |
| 32 | select HAVE_ARCH_AUDITSYSCALL | ||
| 33 | select HAVE_DYNAMIC_FTRACE | ||
| 32 | select HAVE_FUNCTION_TRACER | 34 | select HAVE_FUNCTION_TRACER |
| 33 | select HAVE_FUNCTION_GRAPH_TRACER | 35 | select HAVE_FUNCTION_GRAPH_TRACER |
| 36 | select HAVE_FTRACE_MCOUNT_RECORD | ||
| 34 | select HAVE_KERNEL_GZIP | 37 | select HAVE_KERNEL_GZIP |
| 35 | select HAVE_KERNEL_LZO | 38 | select HAVE_KERNEL_LZO |
| 36 | select HAVE_KERNEL_LZMA | 39 | select HAVE_KERNEL_LZMA |
| 37 | select HAVE_PERF_EVENTS | 40 | select HAVE_PERF_EVENTS |
| 38 | select HAVE_C_RECORDMCOUNT | 41 | select HAVE_PERF_REGS |
| 42 | select HAVE_PERF_USER_STACK_DUMP | ||
| 39 | select HAVE_DMA_API_DEBUG | 43 | select HAVE_DMA_API_DEBUG |
| 40 | select HAVE_DMA_CONTIGUOUS | 44 | select HAVE_DMA_CONTIGUOUS |
| 45 | select HAVE_SYSCALL_TRACEPOINTS | ||
| 41 | select MAY_HAVE_SPARSE_IRQ | 46 | select MAY_HAVE_SPARSE_IRQ |
| 42 | select MODULES_USE_ELF_RELA if MODULES | 47 | select MODULES_USE_ELF_RELA if MODULES |
| 43 | select OF | 48 | select OF |
diff --git a/arch/csky/Makefile b/arch/csky/Makefile index 3607a6e8f66c..6b87f6c22ad6 100644 --- a/arch/csky/Makefile +++ b/arch/csky/Makefile | |||
| @@ -36,7 +36,7 @@ endif | |||
| 36 | 36 | ||
| 37 | ifneq ($(CSKYABI),) | 37 | ifneq ($(CSKYABI),) |
| 38 | MCPU_STR = $(CPUTYPE)$(FPUEXT)$(VDSPEXT)$(TEEEXT) | 38 | MCPU_STR = $(CPUTYPE)$(FPUEXT)$(VDSPEXT)$(TEEEXT) |
| 39 | KBUILD_CFLAGS += -mcpu=$(MCPU_STR) | 39 | KBUILD_CFLAGS += -mcpu=$(CPUTYPE) -Wa,-mcpu=$(MCPU_STR) |
| 40 | KBUILD_CFLAGS += -DCSKYCPU_DEF_NAME=\"$(MCPU_STR)\" | 40 | KBUILD_CFLAGS += -DCSKYCPU_DEF_NAME=\"$(MCPU_STR)\" |
| 41 | KBUILD_CFLAGS += -msoft-float -mdiv | 41 | KBUILD_CFLAGS += -msoft-float -mdiv |
| 42 | KBUILD_CFLAGS += -fno-tree-vectorize | 42 | KBUILD_CFLAGS += -fno-tree-vectorize |
diff --git a/arch/csky/abiv1/inc/abi/ckmmu.h b/arch/csky/abiv1/inc/abi/ckmmu.h index 3a002017bebe..81f37715c0d2 100644 --- a/arch/csky/abiv1/inc/abi/ckmmu.h +++ b/arch/csky/abiv1/inc/abi/ckmmu.h | |||
| @@ -40,6 +40,26 @@ static inline void write_mmu_entryhi(int value) | |||
| 40 | cpwcr("cpcr4", value); | 40 | cpwcr("cpcr4", value); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static inline unsigned long read_mmu_msa0(void) | ||
| 44 | { | ||
| 45 | return cprcr("cpcr30"); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void write_mmu_msa0(unsigned long value) | ||
| 49 | { | ||
| 50 | cpwcr("cpcr30", value); | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline unsigned long read_mmu_msa1(void) | ||
| 54 | { | ||
| 55 | return cprcr("cpcr31"); | ||
| 56 | } | ||
| 57 | |||
| 58 | static inline void write_mmu_msa1(unsigned long value) | ||
| 59 | { | ||
| 60 | cpwcr("cpcr31", value); | ||
| 61 | } | ||
| 62 | |||
| 43 | /* | 63 | /* |
| 44 | * TLB operations. | 64 | * TLB operations. |
| 45 | */ | 65 | */ |
| @@ -65,11 +85,11 @@ static inline void tlb_invalid_indexed(void) | |||
| 65 | 85 | ||
| 66 | static inline void setup_pgd(unsigned long pgd, bool kernel) | 86 | static inline void setup_pgd(unsigned long pgd, bool kernel) |
| 67 | { | 87 | { |
| 68 | cpwcr("cpcr29", pgd); | 88 | cpwcr("cpcr29", pgd | BIT(0)); |
| 69 | } | 89 | } |
| 70 | 90 | ||
| 71 | static inline unsigned long get_pgd(void) | 91 | static inline unsigned long get_pgd(void) |
| 72 | { | 92 | { |
| 73 | return cprcr("cpcr29"); | 93 | return cprcr("cpcr29") & ~BIT(0); |
| 74 | } | 94 | } |
| 75 | #endif /* __ASM_CSKY_CKMMUV1_H */ | 95 | #endif /* __ASM_CSKY_CKMMUV1_H */ |
diff --git a/arch/csky/abiv1/inc/abi/entry.h b/arch/csky/abiv1/inc/abi/entry.h index 3f3faab3d747..7ab78bd0f3b1 100644 --- a/arch/csky/abiv1/inc/abi/entry.h +++ b/arch/csky/abiv1/inc/abi/entry.h | |||
| @@ -16,9 +16,6 @@ | |||
| 16 | #define LSAVE_A4 40 | 16 | #define LSAVE_A4 40 |
| 17 | #define LSAVE_A5 44 | 17 | #define LSAVE_A5 44 |
| 18 | 18 | ||
| 19 | #define EPC_INCREASE 2 | ||
| 20 | #define EPC_KEEP 0 | ||
| 21 | |||
| 22 | .macro USPTOKSP | 19 | .macro USPTOKSP |
| 23 | mtcr sp, ss1 | 20 | mtcr sp, ss1 |
| 24 | mfcr sp, ss0 | 21 | mfcr sp, ss0 |
| @@ -29,10 +26,6 @@ | |||
| 29 | mfcr sp, ss1 | 26 | mfcr sp, ss1 |
| 30 | .endm | 27 | .endm |
| 31 | 28 | ||
| 32 | .macro INCTRAP rx | ||
| 33 | addi \rx, EPC_INCREASE | ||
| 34 | .endm | ||
| 35 | |||
| 36 | .macro SAVE_ALL epc_inc | 29 | .macro SAVE_ALL epc_inc |
| 37 | mtcr r13, ss2 | 30 | mtcr r13, ss2 |
| 38 | mfcr r13, epsr | 31 | mfcr r13, epsr |
| @@ -150,11 +143,35 @@ | |||
| 150 | cpwcr \rx, cpcr8 | 143 | cpwcr \rx, cpcr8 |
| 151 | .endm | 144 | .endm |
| 152 | 145 | ||
| 153 | .macro SETUP_MMU rx | 146 | .macro SETUP_MMU |
| 154 | lrw \rx, PHYS_OFFSET | 0xe | 147 | /* Init psr and enable ee */ |
| 155 | cpwcr \rx, cpcr30 | 148 | lrw r6, DEFAULT_PSR_VALUE |
| 156 | lrw \rx, (PHYS_OFFSET + 0x20000000) | 0xe | 149 | mtcr r6, psr |
| 157 | cpwcr \rx, cpcr31 | 150 | psrset ee |
| 151 | |||
| 152 | /* Select MMU as co-processor */ | ||
| 153 | cpseti cp15 | ||
| 154 | |||
| 155 | /* | ||
| 156 | * cpcr30 format: | ||
| 157 | * 31 - 29 | 28 - 4 | 3 | 2 | 1 | 0 | ||
| 158 | * BA Reserved C D V | ||
| 159 | */ | ||
| 160 | cprcr r6, cpcr30 | ||
| 161 | lsri r6, 28 | ||
| 162 | lsli r6, 28 | ||
| 163 | addi r6, 0xe | ||
| 164 | cpwcr r6, cpcr30 | ||
| 165 | |||
| 166 | lsri r6, 28 | ||
| 167 | addi r6, 2 | ||
| 168 | lsli r6, 28 | ||
| 169 | addi r6, 0xe | ||
| 170 | cpwcr r6, cpcr31 | ||
| 158 | .endm | 171 | .endm |
| 159 | 172 | ||
| 173 | .macro ANDI_R3 rx, imm | ||
| 174 | lsri \rx, 3 | ||
| 175 | andi \rx, (\imm >> 3) | ||
| 176 | .endm | ||
| 160 | #endif /* __ASM_CSKY_ENTRY_H */ | 177 | #endif /* __ASM_CSKY_ENTRY_H */ |
diff --git a/arch/csky/abiv1/inc/abi/regdef.h b/arch/csky/abiv1/inc/abi/regdef.h index 876689291b71..104707fbdcc1 100644 --- a/arch/csky/abiv1/inc/abi/regdef.h +++ b/arch/csky/abiv1/inc/abi/regdef.h | |||
| @@ -5,9 +5,8 @@ | |||
| 5 | #define __ASM_CSKY_REGDEF_H | 5 | #define __ASM_CSKY_REGDEF_H |
| 6 | 6 | ||
| 7 | #define syscallid r1 | 7 | #define syscallid r1 |
| 8 | #define r11_sig r11 | ||
| 9 | |||
| 10 | #define regs_syscallid(regs) regs->regs[9] | 8 | #define regs_syscallid(regs) regs->regs[9] |
| 9 | #define regs_fp(regs) regs->regs[2] | ||
| 11 | 10 | ||
| 12 | /* | 11 | /* |
| 13 | * PSR format: | 12 | * PSR format: |
| @@ -23,4 +22,6 @@ | |||
| 23 | 22 | ||
| 24 | #define SYSTRACE_SAVENUM 2 | 23 | #define SYSTRACE_SAVENUM 2 |
| 25 | 24 | ||
| 25 | #define TRAP0_SIZE 2 | ||
| 26 | |||
| 26 | #endif /* __ASM_CSKY_REGDEF_H */ | 27 | #endif /* __ASM_CSKY_REGDEF_H */ |
diff --git a/arch/csky/abiv2/cacheflush.c b/arch/csky/abiv2/cacheflush.c index d22c95ffc74d..5bb887b275e1 100644 --- a/arch/csky/abiv2/cacheflush.c +++ b/arch/csky/abiv2/cacheflush.c | |||
| @@ -34,10 +34,6 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, | |||
| 34 | { | 34 | { |
| 35 | unsigned long addr, pfn; | 35 | unsigned long addr, pfn; |
| 36 | struct page *page; | 36 | struct page *page; |
| 37 | void *va; | ||
| 38 | |||
| 39 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 40 | return; | ||
| 41 | 37 | ||
| 42 | pfn = pte_pfn(*pte); | 38 | pfn = pte_pfn(*pte); |
| 43 | if (unlikely(!pfn_valid(pfn))) | 39 | if (unlikely(!pfn_valid(pfn))) |
| @@ -47,14 +43,9 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, | |||
| 47 | if (page == ZERO_PAGE(0)) | 43 | if (page == ZERO_PAGE(0)) |
| 48 | return; | 44 | return; |
| 49 | 45 | ||
| 50 | va = page_address(page); | 46 | addr = (unsigned long) kmap_atomic(page); |
| 51 | addr = (unsigned long) va; | ||
| 52 | |||
| 53 | if (va == NULL && PageHighMem(page)) | ||
| 54 | addr = (unsigned long) kmap_atomic(page); | ||
| 55 | 47 | ||
| 56 | cache_wbinv_range(addr, addr + PAGE_SIZE); | 48 | cache_wbinv_range(addr, addr + PAGE_SIZE); |
| 57 | 49 | ||
| 58 | if (va == NULL && PageHighMem(page)) | 50 | kunmap_atomic((void *) addr); |
| 59 | kunmap_atomic((void *) addr); | ||
| 60 | } | 51 | } |
diff --git a/arch/csky/abiv2/inc/abi/ckmmu.h b/arch/csky/abiv2/inc/abi/ckmmu.h index 97230ad9427c..e4480e6bc3b3 100644 --- a/arch/csky/abiv2/inc/abi/ckmmu.h +++ b/arch/csky/abiv2/inc/abi/ckmmu.h | |||
| @@ -42,6 +42,26 @@ static inline void write_mmu_entryhi(int value) | |||
| 42 | mtcr("cr<4, 15>", value); | 42 | mtcr("cr<4, 15>", value); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static inline unsigned long read_mmu_msa0(void) | ||
| 46 | { | ||
| 47 | return mfcr("cr<30, 15>"); | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline void write_mmu_msa0(unsigned long value) | ||
| 51 | { | ||
| 52 | mtcr("cr<30, 15>", value); | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline unsigned long read_mmu_msa1(void) | ||
| 56 | { | ||
| 57 | return mfcr("cr<31, 15>"); | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline void write_mmu_msa1(unsigned long value) | ||
| 61 | { | ||
| 62 | mtcr("cr<31, 15>", value); | ||
| 63 | } | ||
| 64 | |||
| 45 | /* | 65 | /* |
| 46 | * TLB operations. | 66 | * TLB operations. |
| 47 | */ | 67 | */ |
| @@ -70,18 +90,16 @@ static inline void tlb_invalid_indexed(void) | |||
| 70 | mtcr("cr<8, 15>", 0x02000000); | 90 | mtcr("cr<8, 15>", 0x02000000); |
| 71 | } | 91 | } |
| 72 | 92 | ||
| 73 | /* setup hardrefil pgd */ | ||
| 74 | static inline unsigned long get_pgd(void) | ||
| 75 | { | ||
| 76 | return mfcr("cr<29, 15>"); | ||
| 77 | } | ||
| 78 | |||
| 79 | static inline void setup_pgd(unsigned long pgd, bool kernel) | 93 | static inline void setup_pgd(unsigned long pgd, bool kernel) |
| 80 | { | 94 | { |
| 81 | if (kernel) | 95 | if (kernel) |
| 82 | mtcr("cr<28, 15>", pgd); | 96 | mtcr("cr<28, 15>", pgd | BIT(0)); |
| 83 | else | 97 | else |
| 84 | mtcr("cr<29, 15>", pgd); | 98 | mtcr("cr<29, 15>", pgd | BIT(0)); |
| 85 | } | 99 | } |
| 86 | 100 | ||
| 101 | static inline unsigned long get_pgd(void) | ||
| 102 | { | ||
| 103 | return mfcr("cr<29, 15>") & ~BIT(0); | ||
| 104 | } | ||
| 87 | #endif /* __ASM_CSKY_CKMMUV2_H */ | 105 | #endif /* __ASM_CSKY_CKMMUV2_H */ |
diff --git a/arch/csky/abiv2/inc/abi/entry.h b/arch/csky/abiv2/inc/abi/entry.h index edc5cc04c4de..9897a16b45e5 100644 --- a/arch/csky/abiv2/inc/abi/entry.h +++ b/arch/csky/abiv2/inc/abi/entry.h | |||
| @@ -14,18 +14,11 @@ | |||
| 14 | #define LSAVE_A2 32 | 14 | #define LSAVE_A2 32 |
| 15 | #define LSAVE_A3 36 | 15 | #define LSAVE_A3 36 |
| 16 | 16 | ||
| 17 | #define EPC_INCREASE 4 | ||
| 18 | #define EPC_KEEP 0 | ||
| 19 | |||
| 20 | #define KSPTOUSP | 17 | #define KSPTOUSP |
| 21 | #define USPTOKSP | 18 | #define USPTOKSP |
| 22 | 19 | ||
| 23 | #define usp cr<14, 1> | 20 | #define usp cr<14, 1> |
| 24 | 21 | ||
| 25 | .macro INCTRAP rx | ||
| 26 | addi \rx, EPC_INCREASE | ||
| 27 | .endm | ||
| 28 | |||
| 29 | .macro SAVE_ALL epc_inc | 22 | .macro SAVE_ALL epc_inc |
| 30 | subi sp, 152 | 23 | subi sp, 152 |
| 31 | stw tls, (sp, 0) | 24 | stw tls, (sp, 0) |
| @@ -169,10 +162,80 @@ | |||
| 169 | mtcr \rx, cr<8, 15> | 162 | mtcr \rx, cr<8, 15> |
| 170 | .endm | 163 | .endm |
| 171 | 164 | ||
| 172 | .macro SETUP_MMU rx | 165 | .macro SETUP_MMU |
| 173 | lrw \rx, PHYS_OFFSET | 0xe | 166 | /* Init psr and enable ee */ |
| 174 | mtcr \rx, cr<30, 15> | 167 | lrw r6, DEFAULT_PSR_VALUE |
| 175 | lrw \rx, (PHYS_OFFSET + 0x20000000) | 0xe | 168 | mtcr r6, psr |
| 176 | mtcr \rx, cr<31, 15> | 169 | psrset ee |
| 170 | |||
| 171 | /* Invalid I/Dcache BTB BHT */ | ||
| 172 | movi r6, 7 | ||
| 173 | lsli r6, 16 | ||
| 174 | addi r6, (1<<4) | 3 | ||
| 175 | mtcr r6, cr17 | ||
| 176 | |||
| 177 | /* Invalid all TLB */ | ||
| 178 | bgeni r6, 26 | ||
| 179 | mtcr r6, cr<8, 15> /* Set MCIR */ | ||
| 180 | |||
| 181 | /* Check MMU on/off */ | ||
| 182 | mfcr r6, cr18 | ||
| 183 | btsti r6, 0 | ||
| 184 | bt 1f | ||
| 185 | |||
| 186 | /* MMU off: setup mapping tlb entry */ | ||
| 187 | movi r6, 0 | ||
| 188 | mtcr r6, cr<6, 15> /* Set MPR with 4K page size */ | ||
| 189 | |||
| 190 | grs r6, 1f /* Get current pa by PC */ | ||
| 191 | bmaski r7, (PAGE_SHIFT + 1) /* r7 = 0x1fff */ | ||
| 192 | andn r6, r7 | ||
| 193 | mtcr r6, cr<4, 15> /* Set MEH */ | ||
| 194 | |||
| 195 | mov r8, r6 | ||
| 196 | movi r7, 0x00000006 | ||
| 197 | or r8, r7 | ||
| 198 | mtcr r8, cr<2, 15> /* Set MEL0 */ | ||
| 199 | movi r7, 0x00001006 | ||
| 200 | or r8, r7 | ||
| 201 | mtcr r8, cr<3, 15> /* Set MEL1 */ | ||
| 202 | |||
| 203 | bgeni r8, 28 | ||
| 204 | mtcr r8, cr<8, 15> /* Set MCIR to write TLB */ | ||
| 205 | |||
| 206 | br 2f | ||
| 207 | 1: | ||
| 208 | /* | ||
| 209 | * MMU on: use origin MSA value from bootloader | ||
| 210 | * | ||
| 211 | * cr<30/31, 15> MSA register format: | ||
| 212 | * 31 - 29 | 28 - 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
| 213 | * BA Reserved SH WA B SO SEC C D V | ||
| 214 | */ | ||
| 215 | mfcr r6, cr<30, 15> /* Get MSA0 */ | ||
| 216 | 2: | ||
| 217 | lsri r6, 28 | ||
| 218 | lsli r6, 28 | ||
| 219 | addi r6, 0x1ce | ||
| 220 | mtcr r6, cr<30, 15> /* Set MSA0 */ | ||
| 221 | |||
| 222 | lsri r6, 28 | ||
| 223 | addi r6, 2 | ||
| 224 | lsli r6, 28 | ||
| 225 | addi r6, 0x1ce | ||
| 226 | mtcr r6, cr<31, 15> /* Set MSA1 */ | ||
| 227 | |||
| 228 | /* enable MMU */ | ||
| 229 | mfcr r6, cr18 | ||
| 230 | bseti r6, 0 | ||
| 231 | mtcr r6, cr18 | ||
| 232 | |||
| 233 | jmpi 3f /* jump to va */ | ||
| 234 | 3: | ||
| 235 | .endm | ||
| 236 | |||
| 237 | .macro ANDI_R3 rx, imm | ||
| 238 | lsri \rx, 3 | ||
| 239 | andi \rx, (\imm >> 3) | ||
| 177 | .endm | 240 | .endm |
| 178 | #endif /* __ASM_CSKY_ENTRY_H */ | 241 | #endif /* __ASM_CSKY_ENTRY_H */ |
diff --git a/arch/csky/abiv2/inc/abi/regdef.h b/arch/csky/abiv2/inc/abi/regdef.h index c72abb781bdc..d7328bbc1ce7 100644 --- a/arch/csky/abiv2/inc/abi/regdef.h +++ b/arch/csky/abiv2/inc/abi/regdef.h | |||
| @@ -5,9 +5,8 @@ | |||
| 5 | #define __ASM_CSKY_REGDEF_H | 5 | #define __ASM_CSKY_REGDEF_H |
| 6 | 6 | ||
| 7 | #define syscallid r7 | 7 | #define syscallid r7 |
| 8 | #define r11_sig r11 | ||
| 9 | |||
| 10 | #define regs_syscallid(regs) regs->regs[3] | 8 | #define regs_syscallid(regs) regs->regs[3] |
| 9 | #define regs_fp(regs) regs->regs[4] | ||
| 11 | 10 | ||
| 12 | /* | 11 | /* |
| 13 | * PSR format: | 12 | * PSR format: |
| @@ -23,4 +22,6 @@ | |||
| 23 | 22 | ||
| 24 | #define SYSTRACE_SAVENUM 5 | 23 | #define SYSTRACE_SAVENUM 5 |
| 25 | 24 | ||
| 25 | #define TRAP0_SIZE 4 | ||
| 26 | |||
| 26 | #endif /* __ASM_CSKY_REGDEF_H */ | 27 | #endif /* __ASM_CSKY_REGDEF_H */ |
diff --git a/arch/csky/abiv2/mcount.S b/arch/csky/abiv2/mcount.S index c633379956f5..326402e65f9e 100644 --- a/arch/csky/abiv2/mcount.S +++ b/arch/csky/abiv2/mcount.S | |||
| @@ -61,10 +61,17 @@ | |||
| 61 | addi sp, 16 | 61 | addi sp, 16 |
| 62 | .endm | 62 | .endm |
| 63 | 63 | ||
| 64 | .macro nop32_stub | ||
| 65 | nop32 | ||
| 66 | nop32 | ||
| 67 | nop32 | ||
| 68 | .endm | ||
| 69 | |||
| 64 | ENTRY(ftrace_stub) | 70 | ENTRY(ftrace_stub) |
| 65 | jmp lr | 71 | jmp lr |
| 66 | END(ftrace_stub) | 72 | END(ftrace_stub) |
| 67 | 73 | ||
| 74 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
| 68 | ENTRY(_mcount) | 75 | ENTRY(_mcount) |
| 69 | mcount_enter | 76 | mcount_enter |
| 70 | 77 | ||
| @@ -76,7 +83,7 @@ ENTRY(_mcount) | |||
| 76 | bf skip_ftrace | 83 | bf skip_ftrace |
| 77 | 84 | ||
| 78 | mov a0, lr | 85 | mov a0, lr |
| 79 | subi a0, MCOUNT_INSN_SIZE | 86 | subi a0, 4 |
| 80 | ldw a1, (sp, 24) | 87 | ldw a1, (sp, 24) |
| 81 | 88 | ||
| 82 | jsr r26 | 89 | jsr r26 |
| @@ -101,13 +108,41 @@ skip_ftrace: | |||
| 101 | mcount_exit | 108 | mcount_exit |
| 102 | #endif | 109 | #endif |
| 103 | END(_mcount) | 110 | END(_mcount) |
| 111 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
| 112 | ENTRY(_mcount) | ||
| 113 | mov t1, lr | ||
| 114 | ldw lr, (sp, 0) | ||
| 115 | addi sp, 4 | ||
| 116 | jmp t1 | ||
| 117 | ENDPROC(_mcount) | ||
| 118 | |||
| 119 | ENTRY(ftrace_caller) | ||
| 120 | mcount_enter | ||
| 121 | |||
| 122 | ldw a0, (sp, 16) | ||
| 123 | subi a0, 4 | ||
| 124 | ldw a1, (sp, 24) | ||
| 125 | |||
| 126 | nop | ||
| 127 | GLOBAL(ftrace_call) | ||
| 128 | nop32_stub | ||
| 129 | |||
| 130 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 131 | nop | ||
| 132 | GLOBAL(ftrace_graph_call) | ||
| 133 | nop32_stub | ||
| 134 | #endif | ||
| 135 | |||
| 136 | mcount_exit | ||
| 137 | ENDPROC(ftrace_caller) | ||
| 138 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
| 104 | 139 | ||
| 105 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 140 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 106 | ENTRY(ftrace_graph_caller) | 141 | ENTRY(ftrace_graph_caller) |
| 107 | mov a0, sp | 142 | mov a0, sp |
| 108 | addi a0, 24 | 143 | addi a0, 24 |
| 109 | ldw a1, (sp, 16) | 144 | ldw a1, (sp, 16) |
| 110 | subi a1, MCOUNT_INSN_SIZE | 145 | subi a1, 4 |
| 111 | mov a2, r8 | 146 | mov a2, r8 |
| 112 | lrw r26, prepare_ftrace_return | 147 | lrw r26, prepare_ftrace_return |
| 113 | jsr r26 | 148 | jsr r26 |
diff --git a/arch/csky/abiv2/memmove.S b/arch/csky/abiv2/memmove.S index b0c42ecf1889..5721e73ad3d8 100644 --- a/arch/csky/abiv2/memmove.S +++ b/arch/csky/abiv2/memmove.S | |||
| @@ -35,11 +35,7 @@ ENTRY(memmove) | |||
| 35 | .L_len_larger_16bytes: | 35 | .L_len_larger_16bytes: |
| 36 | subi r1, 16 | 36 | subi r1, 16 |
| 37 | subi r0, 16 | 37 | subi r0, 16 |
| 38 | #if defined(__CSKY_VDSPV2__) | 38 | #if defined(__CK860__) |
| 39 | vldx.8 vr0, (r1), r19 | ||
| 40 | PRE_BNEZAD (r18) | ||
| 41 | vstx.8 vr0, (r0), r19 | ||
| 42 | #elif defined(__CK860__) | ||
| 43 | ldw r3, (r1, 12) | 39 | ldw r3, (r1, 12) |
| 44 | stw r3, (r0, 12) | 40 | stw r3, (r0, 12) |
| 45 | ldw r3, (r1, 8) | 41 | ldw r3, (r1, 8) |
diff --git a/arch/csky/include/asm/Kbuild b/arch/csky/include/asm/Kbuild index 95f4e550db8a..a9b63efef416 100644 --- a/arch/csky/include/asm/Kbuild +++ b/arch/csky/include/asm/Kbuild | |||
| @@ -12,7 +12,6 @@ generic-y += dma-mapping.h | |||
| 12 | generic-y += emergency-restart.h | 12 | generic-y += emergency-restart.h |
| 13 | generic-y += exec.h | 13 | generic-y += exec.h |
| 14 | generic-y += fb.h | 14 | generic-y += fb.h |
| 15 | generic-y += ftrace.h | ||
| 16 | generic-y += futex.h | 15 | generic-y += futex.h |
| 17 | generic-y += gpio.h | 16 | generic-y += gpio.h |
| 18 | generic-y += hardirq.h | 17 | generic-y += hardirq.h |
diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h index 7547c45312a8..ba35d93ecda2 100644 --- a/arch/csky/include/asm/ftrace.h +++ b/arch/csky/include/asm/ftrace.h | |||
| @@ -4,10 +4,26 @@ | |||
| 4 | #ifndef __ASM_CSKY_FTRACE_H | 4 | #ifndef __ASM_CSKY_FTRACE_H |
| 5 | #define __ASM_CSKY_FTRACE_H | 5 | #define __ASM_CSKY_FTRACE_H |
| 6 | 6 | ||
| 7 | #define MCOUNT_INSN_SIZE 4 | 7 | #define MCOUNT_INSN_SIZE 14 |
| 8 | 8 | ||
| 9 | #define HAVE_FUNCTION_GRAPH_FP_TEST | 9 | #define HAVE_FUNCTION_GRAPH_FP_TEST |
| 10 | 10 | ||
| 11 | #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | 11 | #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR |
| 12 | 12 | ||
| 13 | #define MCOUNT_ADDR ((unsigned long)_mcount) | ||
| 14 | |||
| 15 | #ifndef __ASSEMBLY__ | ||
| 16 | |||
| 17 | extern void _mcount(unsigned long); | ||
| 18 | |||
| 19 | extern void ftrace_graph_call(void); | ||
| 20 | |||
| 21 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
| 22 | { | ||
| 23 | return addr; | ||
| 24 | } | ||
| 25 | |||
| 26 | struct dyn_arch_ftrace { | ||
| 27 | }; | ||
| 28 | #endif /* !__ASSEMBLY__ */ | ||
| 13 | #endif /* __ASM_CSKY_FTRACE_H */ | 29 | #endif /* __ASM_CSKY_FTRACE_H */ |
diff --git a/arch/csky/include/asm/mmu_context.h b/arch/csky/include/asm/mmu_context.h index b2905c0485a7..734db3a122e1 100644 --- a/arch/csky/include/asm/mmu_context.h +++ b/arch/csky/include/asm/mmu_context.h | |||
| @@ -14,23 +14,10 @@ | |||
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <abi/ckmmu.h> | 15 | #include <abi/ckmmu.h> |
| 16 | 16 | ||
| 17 | static inline void tlbmiss_handler_setup_pgd(unsigned long pgd, bool kernel) | ||
| 18 | { | ||
| 19 | pgd -= PAGE_OFFSET; | ||
| 20 | pgd += PHYS_OFFSET; | ||
| 21 | pgd |= 1; | ||
| 22 | setup_pgd(pgd, kernel); | ||
| 23 | } | ||
| 24 | |||
| 25 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 17 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
| 26 | tlbmiss_handler_setup_pgd((unsigned long)pgd, 0) | 18 | setup_pgd(__pa(pgd), false) |
| 27 | #define TLBMISS_HANDLER_SETUP_PGD_KERNEL(pgd) \ | 19 | #define TLBMISS_HANDLER_SETUP_PGD_KERNEL(pgd) \ |
| 28 | tlbmiss_handler_setup_pgd((unsigned long)pgd, 1) | 20 | setup_pgd(__pa(pgd), true) |
| 29 | |||
| 30 | static inline unsigned long tlb_get_pgd(void) | ||
| 31 | { | ||
| 32 | return ((get_pgd() - PHYS_OFFSET) & ~1) + PAGE_OFFSET; | ||
| 33 | } | ||
| 34 | 21 | ||
| 35 | #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) | 22 | #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) |
| 36 | #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) | 23 | #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) |
diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h index 73cf2bd66a13..9738eacefdc7 100644 --- a/arch/csky/include/asm/page.h +++ b/arch/csky/include/asm/page.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include <linux/const.h> | 8 | #include <linux/const.h> |
| 9 | 9 | ||
| 10 | /* | 10 | /* |
| 11 | * PAGE_SHIFT determines the page size | 11 | * PAGE_SHIFT determines the page size: 4KB |
| 12 | */ | 12 | */ |
| 13 | #define PAGE_SHIFT 12 | 13 | #define PAGE_SHIFT 12 |
| 14 | #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) | 14 | #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) |
| @@ -17,12 +17,18 @@ | |||
| 17 | #define THREAD_MASK (~(THREAD_SIZE - 1)) | 17 | #define THREAD_MASK (~(THREAD_SIZE - 1)) |
| 18 | #define THREAD_SHIFT (PAGE_SHIFT + 1) | 18 | #define THREAD_SHIFT (PAGE_SHIFT + 1) |
| 19 | 19 | ||
| 20 | |||
| 20 | /* | 21 | /* |
| 21 | * NOTE: virtual isn't really correct, actually it should be the offset into the | 22 | * For C-SKY "User-space:Kernel-space" is "2GB:2GB" fixed by hardware and there |
| 22 | * memory node, but we have no highmem, so that works for now. | 23 | * are two segment registers (MSA0 + MSA1) to mapping 512MB + 512MB physical |
| 23 | * TODO: implement (fast) pfn<->pgdat_idx conversion functions, this makes lots | 24 | * address region. We use them mapping kernel 1GB direct-map address area and |
| 24 | * of the shifts unnecessary. | 25 | * for more than 1GB of memory we use highmem. |
| 25 | */ | 26 | */ |
| 27 | #define PAGE_OFFSET 0x80000000 | ||
| 28 | #define SSEG_SIZE 0x20000000 | ||
| 29 | #define LOWMEM_LIMIT (SSEG_SIZE * 2) | ||
| 30 | |||
| 31 | #define PHYS_OFFSET_OFFSET (CONFIG_RAM_BASE & (SSEG_SIZE - 1)) | ||
| 26 | 32 | ||
| 27 | #ifndef __ASSEMBLY__ | 33 | #ifndef __ASSEMBLY__ |
| 28 | 34 | ||
| @@ -50,9 +56,6 @@ struct page; | |||
| 50 | 56 | ||
| 51 | struct vm_area_struct; | 57 | struct vm_area_struct; |
| 52 | 58 | ||
| 53 | /* | ||
| 54 | * These are used to make use of C type-checking.. | ||
| 55 | */ | ||
| 56 | typedef struct { unsigned long pte_low; } pte_t; | 59 | typedef struct { unsigned long pte_low; } pte_t; |
| 57 | #define pte_val(x) ((x).pte_low) | 60 | #define pte_val(x) ((x).pte_low) |
| 58 | 61 | ||
| @@ -69,18 +72,13 @@ typedef struct page *pgtable_t; | |||
| 69 | #define __pgd(x) ((pgd_t) { (x) }) | 72 | #define __pgd(x) ((pgd_t) { (x) }) |
| 70 | #define __pgprot(x) ((pgprot_t) { (x) }) | 73 | #define __pgprot(x) ((pgprot_t) { (x) }) |
| 71 | 74 | ||
| 72 | #endif /* !__ASSEMBLY__ */ | 75 | extern unsigned long va_pa_offset; |
| 73 | 76 | ||
| 74 | #define PHYS_OFFSET (CONFIG_RAM_BASE & ~(LOWMEM_LIMIT - 1)) | 77 | #define ARCH_PFN_OFFSET PFN_DOWN(va_pa_offset + PHYS_OFFSET_OFFSET) |
| 75 | #define PHYS_OFFSET_OFFSET (CONFIG_RAM_BASE & (LOWMEM_LIMIT - 1)) | ||
| 76 | #define ARCH_PFN_OFFSET PFN_DOWN(CONFIG_RAM_BASE) | ||
| 77 | 78 | ||
| 78 | #define PAGE_OFFSET 0x80000000 | 79 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + va_pa_offset) |
| 79 | #define LOWMEM_LIMIT 0x40000000 | 80 | #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - va_pa_offset)) |
| 80 | 81 | ||
| 81 | #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET) | ||
| 82 | #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - \ | ||
| 83 | PHYS_OFFSET)) | ||
| 84 | #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) | 82 | #define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) |
| 85 | 83 | ||
| 86 | #define MAP_NR(x) PFN_DOWN((unsigned long)(x) - PAGE_OFFSET - \ | 84 | #define MAP_NR(x) PFN_DOWN((unsigned long)(x) - PAGE_OFFSET - \ |
| @@ -90,15 +88,10 @@ typedef struct page *pgtable_t; | |||
| 90 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ | 88 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ |
| 91 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 89 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
| 92 | 90 | ||
| 93 | /* | ||
| 94 | * main RAM and kernel working space are coincident at 0x80000000, but to make | ||
| 95 | * life more interesting, there's also an uncached virtual shadow at 0xb0000000 | ||
| 96 | * - these mappings are fixed in the MMU | ||
| 97 | */ | ||
| 98 | |||
| 99 | #define pfn_to_kaddr(x) __va(PFN_PHYS(x)) | 91 | #define pfn_to_kaddr(x) __va(PFN_PHYS(x)) |
| 100 | 92 | ||
| 101 | #include <asm-generic/memory_model.h> | 93 | #include <asm-generic/memory_model.h> |
| 102 | #include <asm-generic/getorder.h> | 94 | #include <asm-generic/getorder.h> |
| 103 | 95 | ||
| 96 | #endif /* !__ASSEMBLY__ */ | ||
| 104 | #endif /* __ASM_CSKY_PAGE_H */ | 97 | #endif /* __ASM_CSKY_PAGE_H */ |
diff --git a/arch/csky/include/asm/perf_event.h b/arch/csky/include/asm/perf_event.h index ea8193122294..572093e11001 100644 --- a/arch/csky/include/asm/perf_event.h +++ b/arch/csky/include/asm/perf_event.h | |||
| @@ -4,4 +4,12 @@ | |||
| 4 | #ifndef __ASM_CSKY_PERF_EVENT_H | 4 | #ifndef __ASM_CSKY_PERF_EVENT_H |
| 5 | #define __ASM_CSKY_PERF_EVENT_H | 5 | #define __ASM_CSKY_PERF_EVENT_H |
| 6 | 6 | ||
| 7 | #include <abi/regdef.h> | ||
| 8 | |||
| 9 | #define perf_arch_fetch_caller_regs(regs, __ip) { \ | ||
| 10 | (regs)->pc = (__ip); \ | ||
| 11 | regs_fp(regs) = (unsigned long) __builtin_frame_address(0); \ | ||
| 12 | asm volatile("mov %0, sp\n":"=r"((regs)->usp)); \ | ||
| 13 | } | ||
| 14 | |||
| 7 | #endif /* __ASM_PERF_EVENT_ELF_H */ | 15 | #endif /* __ASM_PERF_EVENT_ELF_H */ |
diff --git a/arch/csky/include/asm/ptrace.h b/arch/csky/include/asm/ptrace.h new file mode 100644 index 000000000000..d0aba7b32417 --- /dev/null +++ b/arch/csky/include/asm/ptrace.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | ||
| 3 | |||
| 4 | #ifndef __ASM_CSKY_PTRACE_H | ||
| 5 | #define __ASM_CSKY_PTRACE_H | ||
| 6 | |||
| 7 | #include <uapi/asm/ptrace.h> | ||
| 8 | #include <asm/traps.h> | ||
| 9 | #include <linux/types.h> | ||
| 10 | |||
| 11 | #ifndef __ASSEMBLY__ | ||
| 12 | |||
| 13 | #define PS_S 0x80000000 /* Supervisor Mode */ | ||
| 14 | |||
| 15 | #define arch_has_single_step() (1) | ||
| 16 | #define current_pt_regs() \ | ||
| 17 | ({ (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1; }) | ||
| 18 | |||
| 19 | #define user_stack_pointer(regs) ((regs)->usp) | ||
| 20 | |||
| 21 | #define user_mode(regs) (!((regs)->sr & PS_S)) | ||
| 22 | #define instruction_pointer(regs) ((regs)->pc) | ||
| 23 | #define profile_pc(regs) instruction_pointer(regs) | ||
| 24 | |||
| 25 | static inline bool in_syscall(struct pt_regs const *regs) | ||
| 26 | { | ||
| 27 | return ((regs->sr >> 16) & 0xff) == VEC_TRAP0; | ||
| 28 | } | ||
| 29 | |||
| 30 | static inline void forget_syscall(struct pt_regs *regs) | ||
| 31 | { | ||
| 32 | regs->sr &= ~(0xff << 16); | ||
| 33 | } | ||
| 34 | |||
| 35 | static inline unsigned long regs_return_value(struct pt_regs *regs) | ||
| 36 | { | ||
| 37 | return regs->a0; | ||
| 38 | } | ||
| 39 | |||
| 40 | #endif /* __ASSEMBLY__ */ | ||
| 41 | #endif /* __ASM_CSKY_PTRACE_H */ | ||
diff --git a/arch/csky/include/asm/syscall.h b/arch/csky/include/asm/syscall.h index bc0d8717d28b..f624fa3bbc22 100644 --- a/arch/csky/include/asm/syscall.h +++ b/arch/csky/include/asm/syscall.h | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | #include <abi/regdef.h> | 8 | #include <abi/regdef.h> |
| 9 | #include <uapi/linux/audit.h> | 9 | #include <uapi/linux/audit.h> |
| 10 | 10 | ||
| 11 | extern void *sys_call_table[]; | ||
| 12 | |||
| 11 | static inline int | 13 | static inline int |
| 12 | syscall_get_nr(struct task_struct *task, struct pt_regs *regs) | 14 | syscall_get_nr(struct task_struct *task, struct pt_regs *regs) |
| 13 | { | 15 | { |
| @@ -15,6 +17,13 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs) | |||
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | static inline void | 19 | static inline void |
| 20 | syscall_set_nr(struct task_struct *task, struct pt_regs *regs, | ||
| 21 | int sysno) | ||
| 22 | { | ||
| 23 | regs_syscallid(regs) = sysno; | ||
| 24 | } | ||
| 25 | |||
| 26 | static inline void | ||
| 18 | syscall_rollback(struct task_struct *task, struct pt_regs *regs) | 27 | syscall_rollback(struct task_struct *task, struct pt_regs *regs) |
| 19 | { | 28 | { |
| 20 | regs->a0 = regs->orig_a0; | 29 | regs->a0 = regs->orig_a0; |
diff --git a/arch/csky/include/asm/thread_info.h b/arch/csky/include/asm/thread_info.h index 0e9d035d712b..0b546a55a8bf 100644 --- a/arch/csky/include/asm/thread_info.h +++ b/arch/csky/include/asm/thread_info.h | |||
| @@ -51,29 +51,26 @@ static inline struct thread_info *current_thread_info(void) | |||
| 51 | 51 | ||
| 52 | #endif /* !__ASSEMBLY__ */ | 52 | #endif /* !__ASSEMBLY__ */ |
| 53 | 53 | ||
| 54 | /* entry.S relies on these definitions! | ||
| 55 | * bits 0-5 are tested at every exception exit | ||
| 56 | */ | ||
| 57 | #define TIF_SIGPENDING 0 /* signal pending */ | 54 | #define TIF_SIGPENDING 0 /* signal pending */ |
| 58 | #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ | 55 | #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ |
| 59 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ | 56 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ |
| 60 | #define TIF_SYSCALL_TRACE 5 /* syscall trace active */ | 57 | #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ |
| 61 | #define TIF_DELAYED_TRACE 14 /* single step a syscall */ | 58 | #define TIF_SYSCALL_TRACEPOINT 4 /* syscall tracepoint instrumentation */ |
| 59 | #define TIF_SYSCALL_AUDIT 5 /* syscall auditing */ | ||
| 62 | #define TIF_POLLING_NRFLAG 16 /* poll_idle() is TIF_NEED_RESCHED */ | 60 | #define TIF_POLLING_NRFLAG 16 /* poll_idle() is TIF_NEED_RESCHED */ |
| 63 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 61 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
| 64 | #define TIF_FREEZE 19 /* thread is freezing for suspend */ | ||
| 65 | #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ | 62 | #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ |
| 66 | #define TIF_SECCOMP 21 /* secure computing */ | 63 | #define TIF_SECCOMP 21 /* secure computing */ |
| 67 | 64 | ||
| 68 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 65 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
| 69 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | 66 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) |
| 70 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 67 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
| 71 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 68 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
| 72 | #define _TIF_DELAYED_TRACE (1 << TIF_DELAYED_TRACE) | 69 | #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) |
| 73 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 70 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) |
| 71 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | ||
| 74 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) | 72 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) |
| 75 | #define _TIF_FREEZE (1 << TIF_FREEZE) | 73 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) |
| 76 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | 74 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) |
| 77 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) | ||
| 78 | 75 | ||
| 79 | #endif /* _ASM_CSKY_THREAD_INFO_H */ | 76 | #endif /* _ASM_CSKY_THREAD_INFO_H */ |
diff --git a/arch/csky/include/asm/unistd.h b/arch/csky/include/asm/unistd.h index 284487477a61..da7a18295615 100644 --- a/arch/csky/include/asm/unistd.h +++ b/arch/csky/include/asm/unistd.h | |||
| @@ -2,3 +2,5 @@ | |||
| 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. |
| 3 | 3 | ||
| 4 | #include <uapi/asm/unistd.h> | 4 | #include <uapi/asm/unistd.h> |
| 5 | |||
| 6 | #define NR_syscalls (__NR_syscalls) | ||
diff --git a/arch/csky/include/uapi/asm/perf_regs.h b/arch/csky/include/uapi/asm/perf_regs.h new file mode 100644 index 000000000000..ee323d818592 --- /dev/null +++ b/arch/csky/include/uapi/asm/perf_regs.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. | ||
| 3 | |||
| 4 | #ifndef _ASM_CSKY_PERF_REGS_H | ||
| 5 | #define _ASM_CSKY_PERF_REGS_H | ||
| 6 | |||
| 7 | /* Index of struct pt_regs */ | ||
| 8 | enum perf_event_csky_regs { | ||
| 9 | PERF_REG_CSKY_TLS, | ||
| 10 | PERF_REG_CSKY_LR, | ||
| 11 | PERF_REG_CSKY_PC, | ||
| 12 | PERF_REG_CSKY_SR, | ||
| 13 | PERF_REG_CSKY_SP, | ||
| 14 | PERF_REG_CSKY_ORIG_A0, | ||
| 15 | PERF_REG_CSKY_A0, | ||
| 16 | PERF_REG_CSKY_A1, | ||
| 17 | PERF_REG_CSKY_A2, | ||
| 18 | PERF_REG_CSKY_A3, | ||
| 19 | PERF_REG_CSKY_REGS0, | ||
| 20 | PERF_REG_CSKY_REGS1, | ||
| 21 | PERF_REG_CSKY_REGS2, | ||
| 22 | PERF_REG_CSKY_REGS3, | ||
| 23 | PERF_REG_CSKY_REGS4, | ||
| 24 | PERF_REG_CSKY_REGS5, | ||
| 25 | PERF_REG_CSKY_REGS6, | ||
| 26 | PERF_REG_CSKY_REGS7, | ||
| 27 | PERF_REG_CSKY_REGS8, | ||
| 28 | PERF_REG_CSKY_REGS9, | ||
| 29 | #if defined(__CSKYABIV2__) | ||
| 30 | PERF_REG_CSKY_EXREGS0, | ||
| 31 | PERF_REG_CSKY_EXREGS1, | ||
| 32 | PERF_REG_CSKY_EXREGS2, | ||
| 33 | PERF_REG_CSKY_EXREGS3, | ||
| 34 | PERF_REG_CSKY_EXREGS4, | ||
| 35 | PERF_REG_CSKY_EXREGS5, | ||
| 36 | PERF_REG_CSKY_EXREGS6, | ||
| 37 | PERF_REG_CSKY_EXREGS7, | ||
| 38 | PERF_REG_CSKY_EXREGS8, | ||
| 39 | PERF_REG_CSKY_EXREGS9, | ||
| 40 | PERF_REG_CSKY_EXREGS10, | ||
| 41 | PERF_REG_CSKY_EXREGS11, | ||
| 42 | PERF_REG_CSKY_EXREGS12, | ||
| 43 | PERF_REG_CSKY_EXREGS13, | ||
| 44 | PERF_REG_CSKY_EXREGS14, | ||
| 45 | PERF_REG_CSKY_HI, | ||
| 46 | PERF_REG_CSKY_LO, | ||
| 47 | PERF_REG_CSKY_DCSR, | ||
| 48 | #endif | ||
| 49 | PERF_REG_CSKY_MAX, | ||
| 50 | }; | ||
| 51 | #endif /* _ASM_CSKY_PERF_REGS_H */ | ||
diff --git a/arch/csky/include/uapi/asm/ptrace.h b/arch/csky/include/uapi/asm/ptrace.h index a4eaa8ddf0b1..4e248d5b86ef 100644 --- a/arch/csky/include/uapi/asm/ptrace.h +++ b/arch/csky/include/uapi/asm/ptrace.h | |||
| @@ -48,20 +48,5 @@ struct user_fp { | |||
| 48 | unsigned long reserved; | 48 | unsigned long reserved; |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | #ifdef __KERNEL__ | ||
| 52 | |||
| 53 | #define PS_S 0x80000000 /* Supervisor Mode */ | ||
| 54 | |||
| 55 | #define arch_has_single_step() (1) | ||
| 56 | #define current_pt_regs() \ | ||
| 57 | ({ (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1; }) | ||
| 58 | |||
| 59 | #define user_stack_pointer(regs) ((regs)->usp) | ||
| 60 | |||
| 61 | #define user_mode(regs) (!((regs)->sr & PS_S)) | ||
| 62 | #define instruction_pointer(regs) ((regs)->pc) | ||
| 63 | #define profile_pc(regs) instruction_pointer(regs) | ||
| 64 | |||
| 65 | #endif /* __KERNEL__ */ | ||
| 66 | #endif /* __ASSEMBLY__ */ | 51 | #endif /* __ASSEMBLY__ */ |
| 67 | #endif /* _CSKY_PTRACE_H */ | 52 | #endif /* _CSKY_PTRACE_H */ |
diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile index 484e6d3a3647..1624b04bffb5 100644 --- a/arch/csky/kernel/Makefile +++ b/arch/csky/kernel/Makefile | |||
| @@ -9,6 +9,8 @@ obj-$(CONFIG_SMP) += smp.o | |||
| 9 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o | 9 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o |
| 10 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 10 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 11 | obj-$(CONFIG_CSKY_PMU_V1) += perf_event.o | 11 | obj-$(CONFIG_CSKY_PMU_V1) += perf_event.o |
| 12 | obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o | ||
| 13 | obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o | ||
| 12 | 14 | ||
| 13 | ifdef CONFIG_FUNCTION_TRACER | 15 | ifdef CONFIG_FUNCTION_TRACER |
| 14 | CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) | 16 | CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) |
diff --git a/arch/csky/kernel/atomic.S b/arch/csky/kernel/atomic.S index d2357c8f85bd..5b84f11485ae 100644 --- a/arch/csky/kernel/atomic.S +++ b/arch/csky/kernel/atomic.S | |||
| @@ -12,11 +12,10 @@ | |||
| 12 | * If *ptr != oldval && return 1, | 12 | * If *ptr != oldval && return 1, |
| 13 | * else *ptr = newval return 0. | 13 | * else *ptr = newval return 0. |
| 14 | */ | 14 | */ |
| 15 | #ifdef CONFIG_CPU_HAS_LDSTEX | ||
| 16 | ENTRY(csky_cmpxchg) | 15 | ENTRY(csky_cmpxchg) |
| 17 | USPTOKSP | 16 | USPTOKSP |
| 18 | mfcr a3, epc | 17 | mfcr a3, epc |
| 19 | INCTRAP a3 | 18 | addi a3, TRAP0_SIZE |
| 20 | 19 | ||
| 21 | subi sp, 8 | 20 | subi sp, 8 |
| 22 | stw a3, (sp, 0) | 21 | stw a3, (sp, 0) |
| @@ -24,6 +23,7 @@ ENTRY(csky_cmpxchg) | |||
| 24 | stw a3, (sp, 4) | 23 | stw a3, (sp, 4) |
| 25 | 24 | ||
| 26 | psrset ee | 25 | psrset ee |
| 26 | #ifdef CONFIG_CPU_HAS_LDSTEX | ||
| 27 | 1: | 27 | 1: |
| 28 | ldex a3, (a2) | 28 | ldex a3, (a2) |
| 29 | cmpne a0, a3 | 29 | cmpne a0, a3 |
| @@ -33,27 +33,7 @@ ENTRY(csky_cmpxchg) | |||
| 33 | bez a3, 1b | 33 | bez a3, 1b |
| 34 | 2: | 34 | 2: |
| 35 | sync.is | 35 | sync.is |
| 36 | mvc a0 | ||
| 37 | ldw a3, (sp, 0) | ||
| 38 | mtcr a3, epc | ||
| 39 | ldw a3, (sp, 4) | ||
| 40 | mtcr a3, epsr | ||
| 41 | addi sp, 8 | ||
| 42 | KSPTOUSP | ||
| 43 | rte | ||
| 44 | END(csky_cmpxchg) | ||
| 45 | #else | 36 | #else |
| 46 | ENTRY(csky_cmpxchg) | ||
| 47 | USPTOKSP | ||
| 48 | mfcr a3, epc | ||
| 49 | INCTRAP a3 | ||
| 50 | |||
| 51 | subi sp, 8 | ||
| 52 | stw a3, (sp, 0) | ||
| 53 | mfcr a3, epsr | ||
| 54 | stw a3, (sp, 4) | ||
| 55 | |||
| 56 | psrset ee | ||
| 57 | 1: | 37 | 1: |
| 58 | ldw a3, (a2) | 38 | ldw a3, (a2) |
| 59 | cmpne a0, a3 | 39 | cmpne a0, a3 |
| @@ -61,6 +41,7 @@ ENTRY(csky_cmpxchg) | |||
| 61 | 2: | 41 | 2: |
| 62 | stw a1, (a2) | 42 | stw a1, (a2) |
| 63 | 3: | 43 | 3: |
| 44 | #endif | ||
| 64 | mvc a0 | 45 | mvc a0 |
| 65 | ldw a3, (sp, 0) | 46 | ldw a3, (sp, 0) |
| 66 | mtcr a3, epc | 47 | mtcr a3, epc |
| @@ -71,6 +52,7 @@ ENTRY(csky_cmpxchg) | |||
| 71 | rte | 52 | rte |
| 72 | END(csky_cmpxchg) | 53 | END(csky_cmpxchg) |
| 73 | 54 | ||
| 55 | #ifndef CONFIG_CPU_HAS_LDSTEX | ||
| 74 | /* | 56 | /* |
| 75 | * Called from tlbmodified exception | 57 | * Called from tlbmodified exception |
| 76 | */ | 58 | */ |
diff --git a/arch/csky/kernel/entry.S b/arch/csky/kernel/entry.S index 5137ed9062bd..a7e84ccccbd8 100644 --- a/arch/csky/kernel/entry.S +++ b/arch/csky/kernel/entry.S | |||
| @@ -40,7 +40,8 @@ ENTRY(csky_\name) | |||
| 40 | WR_MCIR a2 | 40 | WR_MCIR a2 |
| 41 | #endif | 41 | #endif |
| 42 | bclri r6, 0 | 42 | bclri r6, 0 |
| 43 | lrw a2, PHYS_OFFSET | 43 | lrw a2, va_pa_offset |
| 44 | ld.w a2, (a2, 0) | ||
| 44 | subu r6, a2 | 45 | subu r6, a2 |
| 45 | bseti r6, 31 | 46 | bseti r6, 31 |
| 46 | 47 | ||
| @@ -50,7 +51,8 @@ ENTRY(csky_\name) | |||
| 50 | addu r6, a2 | 51 | addu r6, a2 |
| 51 | ldw r6, (r6) | 52 | ldw r6, (r6) |
| 52 | 53 | ||
| 53 | lrw a2, PHYS_OFFSET | 54 | lrw a2, va_pa_offset |
| 55 | ld.w a2, (a2, 0) | ||
| 54 | subu r6, a2 | 56 | subu r6, a2 |
| 55 | bseti r6, 31 | 57 | bseti r6, 31 |
| 56 | 58 | ||
| @@ -91,7 +93,7 @@ ENTRY(csky_\name) | |||
| 91 | mfcr a3, ss2 | 93 | mfcr a3, ss2 |
| 92 | mfcr r6, ss3 | 94 | mfcr r6, ss3 |
| 93 | mfcr a2, ss4 | 95 | mfcr a2, ss4 |
| 94 | SAVE_ALL EPC_KEEP | 96 | SAVE_ALL 0 |
| 95 | .endm | 97 | .endm |
| 96 | .macro tlbop_end is_write | 98 | .macro tlbop_end is_write |
| 97 | RD_MEH a2 | 99 | RD_MEH a2 |
| @@ -99,7 +101,6 @@ ENTRY(csky_\name) | |||
| 99 | mov a0, sp | 101 | mov a0, sp |
| 100 | movi a1, \is_write | 102 | movi a1, \is_write |
| 101 | jbsr do_page_fault | 103 | jbsr do_page_fault |
| 102 | movi r11_sig, 0 /* r11 = 0, Not a syscall. */ | ||
| 103 | jmpi ret_from_exception | 104 | jmpi ret_from_exception |
| 104 | .endm | 105 | .endm |
| 105 | 106 | ||
| @@ -118,7 +119,7 @@ jbsr csky_cmpxchg_fixup | |||
| 118 | tlbop_end 1 | 119 | tlbop_end 1 |
| 119 | 120 | ||
| 120 | ENTRY(csky_systemcall) | 121 | ENTRY(csky_systemcall) |
| 121 | SAVE_ALL EPC_INCREASE | 122 | SAVE_ALL TRAP0_SIZE |
| 122 | 123 | ||
| 123 | psrset ee, ie | 124 | psrset ee, ie |
| 124 | 125 | ||
| @@ -136,8 +137,9 @@ ENTRY(csky_systemcall) | |||
| 136 | bmaski r10, THREAD_SHIFT | 137 | bmaski r10, THREAD_SHIFT |
| 137 | andn r9, r10 | 138 | andn r9, r10 |
| 138 | ldw r8, (r9, TINFO_FLAGS) | 139 | ldw r8, (r9, TINFO_FLAGS) |
| 139 | btsti r8, TIF_SYSCALL_TRACE | 140 | ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT) |
| 140 | bt 1f | 141 | cmpnei r8, 0 |
| 142 | bt csky_syscall_trace | ||
| 141 | #if defined(__CSKYABIV2__) | 143 | #if defined(__CSKYABIV2__) |
| 142 | subi sp, 8 | 144 | subi sp, 8 |
| 143 | stw r5, (sp, 0x4) | 145 | stw r5, (sp, 0x4) |
| @@ -150,10 +152,9 @@ ENTRY(csky_systemcall) | |||
| 150 | stw a0, (sp, LSAVE_A0) /* Save return value */ | 152 | stw a0, (sp, LSAVE_A0) /* Save return value */ |
| 151 | jmpi ret_from_exception | 153 | jmpi ret_from_exception |
| 152 | 154 | ||
| 153 | 1: | 155 | csky_syscall_trace: |
| 154 | movi a0, 0 /* enter system call */ | 156 | mov a0, sp /* sp = pt_regs pointer */ |
| 155 | mov a1, sp /* sp = pt_regs pointer */ | 157 | jbsr syscall_trace_enter |
| 156 | jbsr syscall_trace | ||
| 157 | /* Prepare args before do system call */ | 158 | /* Prepare args before do system call */ |
| 158 | ldw a0, (sp, LSAVE_A0) | 159 | ldw a0, (sp, LSAVE_A0) |
| 159 | ldw a1, (sp, LSAVE_A1) | 160 | ldw a1, (sp, LSAVE_A1) |
| @@ -173,9 +174,8 @@ ENTRY(csky_systemcall) | |||
| 173 | #endif | 174 | #endif |
| 174 | stw a0, (sp, LSAVE_A0) /* Save return value */ | 175 | stw a0, (sp, LSAVE_A0) /* Save return value */ |
| 175 | 176 | ||
| 176 | movi a0, 1 /* leave system call */ | 177 | mov a0, sp /* right now, sp --> pt_regs */ |
| 177 | mov a1, sp /* right now, sp --> pt_regs */ | 178 | jbsr syscall_trace_exit |
| 178 | jbsr syscall_trace | ||
| 179 | br ret_from_exception | 179 | br ret_from_exception |
| 180 | 180 | ||
| 181 | ENTRY(ret_from_kernel_thread) | 181 | ENTRY(ret_from_kernel_thread) |
| @@ -190,14 +190,11 @@ ENTRY(ret_from_fork) | |||
| 190 | bmaski r10, THREAD_SHIFT | 190 | bmaski r10, THREAD_SHIFT |
| 191 | andn r9, r10 | 191 | andn r9, r10 |
| 192 | ldw r8, (r9, TINFO_FLAGS) | 192 | ldw r8, (r9, TINFO_FLAGS) |
| 193 | movi r11_sig, 1 | 193 | ANDI_R3 r8, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT) |
| 194 | btsti r8, TIF_SYSCALL_TRACE | 194 | cmpnei r8, 0 |
| 195 | bf 3f | 195 | bf ret_from_exception |
| 196 | movi a0, 1 | 196 | mov a0, sp /* sp = pt_regs pointer */ |
| 197 | mov a1, sp /* sp = pt_regs pointer */ | 197 | jbsr syscall_trace_exit |
| 198 | jbsr syscall_trace | ||
| 199 | 3: | ||
| 200 | jbsr ret_from_exception | ||
| 201 | 198 | ||
| 202 | ret_from_exception: | 199 | ret_from_exception: |
| 203 | ld syscallid, (sp, LSAVE_PSR) | 200 | ld syscallid, (sp, LSAVE_PSR) |
| @@ -212,41 +209,30 @@ ret_from_exception: | |||
| 212 | bmaski r10, THREAD_SHIFT | 209 | bmaski r10, THREAD_SHIFT |
| 213 | andn r9, r10 | 210 | andn r9, r10 |
| 214 | 211 | ||
| 215 | resume_userspace: | ||
| 216 | ldw r8, (r9, TINFO_FLAGS) | 212 | ldw r8, (r9, TINFO_FLAGS) |
| 217 | andi r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) | 213 | andi r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED) |
| 218 | cmpnei r8, 0 | 214 | cmpnei r8, 0 |
| 219 | bt exit_work | 215 | bt exit_work |
| 220 | 1: RESTORE_ALL | 216 | 1: |
| 217 | RESTORE_ALL | ||
| 221 | 218 | ||
| 222 | exit_work: | 219 | exit_work: |
| 220 | lrw syscallid, ret_from_exception | ||
| 221 | mov lr, syscallid | ||
| 222 | |||
| 223 | btsti r8, TIF_NEED_RESCHED | 223 | btsti r8, TIF_NEED_RESCHED |
| 224 | bt work_resched | 224 | bt work_resched |
| 225 | /* If thread_info->flag is empty, RESTORE_ALL */ | 225 | |
| 226 | cmpnei r8, 0 | 226 | mov a0, sp |
| 227 | bf 1b | 227 | mov a1, r8 |
| 228 | mov a1, sp | 228 | jmpi do_notify_resume |
| 229 | mov a0, r8 | ||
| 230 | mov a2, r11_sig /* syscall? */ | ||
| 231 | btsti r8, TIF_SIGPENDING /* delivering a signal? */ | ||
| 232 | /* prevent further restarts(set r11 = 0) */ | ||
| 233 | clrt r11_sig | ||
| 234 | jbsr do_notify_resume /* do signals */ | ||
| 235 | br resume_userspace | ||
| 236 | 229 | ||
| 237 | work_resched: | 230 | work_resched: |
| 238 | lrw syscallid, ret_from_exception | ||
| 239 | mov r15, syscallid /* Return address in link */ | ||
| 240 | jmpi schedule | 231 | jmpi schedule |
| 241 | 232 | ||
| 242 | ENTRY(sys_rt_sigreturn) | ||
| 243 | movi r11_sig, 0 | ||
| 244 | jmpi do_rt_sigreturn | ||
| 245 | |||
| 246 | ENTRY(csky_trap) | 233 | ENTRY(csky_trap) |
| 247 | SAVE_ALL EPC_KEEP | 234 | SAVE_ALL 0 |
| 248 | psrset ee | 235 | psrset ee |
| 249 | movi r11_sig, 0 /* r11 = 0, Not a syscall. */ | ||
| 250 | mov a0, sp /* Push Stack pointer arg */ | 236 | mov a0, sp /* Push Stack pointer arg */ |
| 251 | jbsr trap_c /* Call C-level trap handler */ | 237 | jbsr trap_c /* Call C-level trap handler */ |
| 252 | jmpi ret_from_exception | 238 | jmpi ret_from_exception |
| @@ -261,7 +247,7 @@ ENTRY(csky_get_tls) | |||
| 261 | 247 | ||
| 262 | /* increase epc for continue */ | 248 | /* increase epc for continue */ |
| 263 | mfcr a0, epc | 249 | mfcr a0, epc |
| 264 | INCTRAP a0 | 250 | addi a0, TRAP0_SIZE |
| 265 | mtcr a0, epc | 251 | mtcr a0, epc |
| 266 | 252 | ||
| 267 | /* get current task thread_info with kernel 8K stack */ | 253 | /* get current task thread_info with kernel 8K stack */ |
| @@ -278,9 +264,8 @@ ENTRY(csky_get_tls) | |||
| 278 | rte | 264 | rte |
| 279 | 265 | ||
| 280 | ENTRY(csky_irq) | 266 | ENTRY(csky_irq) |
| 281 | SAVE_ALL EPC_KEEP | 267 | SAVE_ALL 0 |
| 282 | psrset ee | 268 | psrset ee |
| 283 | movi r11_sig, 0 /* r11 = 0, Not a syscall. */ | ||
| 284 | 269 | ||
| 285 | #ifdef CONFIG_PREEMPT | 270 | #ifdef CONFIG_PREEMPT |
| 286 | mov r9, sp /* Get current stack pointer */ | 271 | mov r9, sp /* Get current stack pointer */ |
diff --git a/arch/csky/kernel/ftrace.c b/arch/csky/kernel/ftrace.c index 274c431f1810..44f4880179b7 100644 --- a/arch/csky/kernel/ftrace.c +++ b/arch/csky/kernel/ftrace.c | |||
| @@ -3,6 +3,137 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/ftrace.h> | 4 | #include <linux/ftrace.h> |
| 5 | #include <linux/uaccess.h> | 5 | #include <linux/uaccess.h> |
| 6 | #include <asm/cacheflush.h> | ||
| 7 | |||
| 8 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
| 9 | |||
| 10 | #define NOP 0x4000 | ||
| 11 | #define NOP32_HI 0xc400 | ||
| 12 | #define NOP32_LO 0x4820 | ||
| 13 | #define PUSH_LR 0x14d0 | ||
| 14 | #define MOVIH_LINK 0xea3a | ||
| 15 | #define ORI_LINK 0xef5a | ||
| 16 | #define JSR_LINK 0xe8fa | ||
| 17 | #define BSR_LINK 0xe000 | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Gcc-csky with -pg will insert stub in function prologue: | ||
| 21 | * push lr | ||
| 22 | * jbsr _mcount | ||
| 23 | * nop32 | ||
| 24 | * nop32 | ||
| 25 | * | ||
| 26 | * If the (callee - current_pc) is less then 64MB, we'll use bsr: | ||
| 27 | * push lr | ||
| 28 | * bsr _mcount | ||
| 29 | * nop32 | ||
| 30 | * nop32 | ||
| 31 | * else we'll use (movih + ori + jsr): | ||
| 32 | * push lr | ||
| 33 | * movih r26, ... | ||
| 34 | * ori r26, ... | ||
| 35 | * jsr r26 | ||
| 36 | * | ||
| 37 | * (r26 is our reserved link-reg) | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | static inline void make_jbsr(unsigned long callee, unsigned long pc, | ||
| 41 | uint16_t *call, bool nolr) | ||
| 42 | { | ||
| 43 | long offset; | ||
| 44 | |||
| 45 | call[0] = nolr ? NOP : PUSH_LR; | ||
| 46 | |||
| 47 | offset = (long) callee - (long) pc; | ||
| 48 | |||
| 49 | if (unlikely(offset < -67108864 || offset > 67108864)) { | ||
| 50 | call[1] = MOVIH_LINK; | ||
| 51 | call[2] = callee >> 16; | ||
| 52 | call[3] = ORI_LINK; | ||
| 53 | call[4] = callee & 0xffff; | ||
| 54 | call[5] = JSR_LINK; | ||
| 55 | call[6] = 0; | ||
| 56 | } else { | ||
| 57 | offset = offset >> 1; | ||
| 58 | |||
| 59 | call[1] = BSR_LINK | | ||
| 60 | ((uint16_t)((unsigned long) offset >> 16) & 0x3ff); | ||
| 61 | call[2] = (uint16_t)((unsigned long) offset & 0xffff); | ||
| 62 | call[3] = call[5] = NOP32_HI; | ||
| 63 | call[4] = call[6] = NOP32_LO; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | static uint16_t nops[7] = {NOP, NOP32_HI, NOP32_LO, NOP32_HI, NOP32_LO, | ||
| 68 | NOP32_HI, NOP32_LO}; | ||
| 69 | static int ftrace_check_current_nop(unsigned long hook) | ||
| 70 | { | ||
| 71 | uint16_t olds[7]; | ||
| 72 | unsigned long hook_pos = hook - 2; | ||
| 73 | |||
| 74 | if (probe_kernel_read((void *)olds, (void *)hook_pos, sizeof(nops))) | ||
| 75 | return -EFAULT; | ||
| 76 | |||
| 77 | if (memcmp((void *)nops, (void *)olds, sizeof(nops))) { | ||
| 78 | pr_err("%p: nop but get (%04x %04x %04x %04x %04x %04x %04x)\n", | ||
| 79 | (void *)hook_pos, | ||
| 80 | olds[0], olds[1], olds[2], olds[3], olds[4], olds[5], | ||
| 81 | olds[6]); | ||
| 82 | |||
| 83 | return -EINVAL; | ||
| 84 | } | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int ftrace_modify_code(unsigned long hook, unsigned long target, | ||
| 90 | bool enable, bool nolr) | ||
| 91 | { | ||
| 92 | uint16_t call[7]; | ||
| 93 | |||
| 94 | unsigned long hook_pos = hook - 2; | ||
| 95 | int ret = 0; | ||
| 96 | |||
| 97 | make_jbsr(target, hook, call, nolr); | ||
| 98 | |||
| 99 | ret = probe_kernel_write((void *)hook_pos, enable ? call : nops, | ||
| 100 | sizeof(nops)); | ||
| 101 | if (ret) | ||
| 102 | return -EPERM; | ||
| 103 | |||
| 104 | flush_icache_range(hook_pos, hook_pos + MCOUNT_INSN_SIZE); | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
| 110 | { | ||
| 111 | int ret = ftrace_check_current_nop(rec->ip); | ||
| 112 | |||
| 113 | if (ret) | ||
| 114 | return ret; | ||
| 115 | |||
| 116 | return ftrace_modify_code(rec->ip, addr, true, false); | ||
| 117 | } | ||
| 118 | |||
| 119 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | ||
| 120 | unsigned long addr) | ||
| 121 | { | ||
| 122 | return ftrace_modify_code(rec->ip, addr, false, false); | ||
| 123 | } | ||
| 124 | |||
| 125 | int ftrace_update_ftrace_func(ftrace_func_t func) | ||
| 126 | { | ||
| 127 | int ret = ftrace_modify_code((unsigned long)&ftrace_call, | ||
| 128 | (unsigned long)func, true, true); | ||
| 129 | return ret; | ||
| 130 | } | ||
| 131 | |||
| 132 | int __init ftrace_dyn_arch_init(void) | ||
| 133 | { | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
| 6 | 137 | ||
| 7 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 138 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 8 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | 139 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, |
| @@ -43,8 +174,21 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
| 43 | *(unsigned long *)frame_pointer = return_hooker; | 174 | *(unsigned long *)frame_pointer = return_hooker; |
| 44 | } | 175 | } |
| 45 | } | 176 | } |
| 46 | #endif | 177 | |
| 178 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
| 179 | int ftrace_enable_ftrace_graph_caller(void) | ||
| 180 | { | ||
| 181 | return ftrace_modify_code((unsigned long)&ftrace_graph_call, | ||
| 182 | (unsigned long)&ftrace_graph_caller, true, true); | ||
| 183 | } | ||
| 184 | |||
| 185 | int ftrace_disable_ftrace_graph_caller(void) | ||
| 186 | { | ||
| 187 | return ftrace_modify_code((unsigned long)&ftrace_graph_call, | ||
| 188 | (unsigned long)&ftrace_graph_caller, false, true); | ||
| 189 | } | ||
| 190 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
| 191 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
| 47 | 192 | ||
| 48 | /* _mcount is defined in abi's mcount.S */ | 193 | /* _mcount is defined in abi's mcount.S */ |
| 49 | extern void _mcount(void); | ||
| 50 | EXPORT_SYMBOL(_mcount); | 194 | EXPORT_SYMBOL(_mcount); |
diff --git a/arch/csky/kernel/head.S b/arch/csky/kernel/head.S index 9c4ec473b76b..61989f9241c0 100644 --- a/arch/csky/kernel/head.S +++ b/arch/csky/kernel/head.S | |||
| @@ -7,16 +7,11 @@ | |||
| 7 | 7 | ||
| 8 | __HEAD | 8 | __HEAD |
| 9 | ENTRY(_start) | 9 | ENTRY(_start) |
| 10 | /* set super user mode */ | 10 | SETUP_MMU |
| 11 | lrw a3, DEFAULT_PSR_VALUE | ||
| 12 | mtcr a3, psr | ||
| 13 | psrset ee | ||
| 14 | |||
| 15 | SETUP_MMU a3 | ||
| 16 | 11 | ||
| 17 | /* set stack point */ | 12 | /* set stack point */ |
| 18 | lrw a3, init_thread_union + THREAD_SIZE | 13 | lrw r6, init_thread_union + THREAD_SIZE |
| 19 | mov sp, a3 | 14 | mov sp, r6 |
| 20 | 15 | ||
| 21 | jmpi csky_start | 16 | jmpi csky_start |
| 22 | END(_start) | 17 | END(_start) |
| @@ -24,53 +19,12 @@ END(_start) | |||
| 24 | #ifdef CONFIG_SMP | 19 | #ifdef CONFIG_SMP |
| 25 | .align 10 | 20 | .align 10 |
| 26 | ENTRY(_start_smp_secondary) | 21 | ENTRY(_start_smp_secondary) |
| 27 | /* Invalid I/Dcache BTB BHT */ | 22 | SETUP_MMU |
| 28 | movi a3, 7 | ||
| 29 | lsli a3, 16 | ||
| 30 | addi a3, (1<<4) | 3 | ||
| 31 | mtcr a3, cr17 | ||
| 32 | |||
| 33 | tlbi.alls | ||
| 34 | |||
| 35 | /* setup PAGEMASK */ | ||
| 36 | movi a3, 0 | ||
| 37 | mtcr a3, cr<6, 15> | ||
| 38 | |||
| 39 | /* setup MEL0/MEL1 */ | ||
| 40 | grs a0, _start_smp_pc | ||
| 41 | _start_smp_pc: | ||
| 42 | bmaski a1, 13 | ||
| 43 | andn a0, a1 | ||
| 44 | movi a1, 0x00000006 | ||
| 45 | movi a2, 0x00001006 | ||
| 46 | or a1, a0 | ||
| 47 | or a2, a0 | ||
| 48 | mtcr a1, cr<2, 15> | ||
| 49 | mtcr a2, cr<3, 15> | ||
| 50 | |||
| 51 | /* setup MEH */ | ||
| 52 | mtcr a0, cr<4, 15> | ||
| 53 | |||
| 54 | /* write TLB */ | ||
| 55 | bgeni a3, 28 | ||
| 56 | mtcr a3, cr<8, 15> | ||
| 57 | |||
| 58 | SETUP_MMU a3 | ||
| 59 | |||
| 60 | /* enable MMU */ | ||
| 61 | movi a3, 1 | ||
| 62 | mtcr a3, cr18 | ||
| 63 | |||
| 64 | jmpi _goto_mmu_on | ||
| 65 | _goto_mmu_on: | ||
| 66 | lrw a3, DEFAULT_PSR_VALUE | ||
| 67 | mtcr a3, psr | ||
| 68 | psrset ee | ||
| 69 | 23 | ||
| 70 | /* set stack point */ | 24 | /* set stack point */ |
| 71 | lrw a3, secondary_stack | 25 | lrw r6, secondary_stack |
| 72 | ld.w a3, (a3, 0) | 26 | ld.w r6, (r6, 0) |
| 73 | mov sp, a3 | 27 | mov sp, r6 |
| 74 | 28 | ||
| 75 | jmpi csky_start_secondary | 29 | jmpi csky_start_secondary |
| 76 | END(_start_smp_secondary) | 30 | END(_start_smp_secondary) |
diff --git a/arch/csky/kernel/perf_callchain.c b/arch/csky/kernel/perf_callchain.c new file mode 100644 index 000000000000..e68ff375c8f8 --- /dev/null +++ b/arch/csky/kernel/perf_callchain.c | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. | ||
| 3 | |||
| 4 | #include <linux/perf_event.h> | ||
| 5 | #include <linux/uaccess.h> | ||
| 6 | |||
| 7 | /* Kernel callchain */ | ||
| 8 | struct stackframe { | ||
| 9 | unsigned long fp; | ||
| 10 | unsigned long lr; | ||
| 11 | }; | ||
| 12 | |||
| 13 | static int unwind_frame_kernel(struct stackframe *frame) | ||
| 14 | { | ||
| 15 | if (kstack_end((void *)frame->fp)) | ||
| 16 | return -EPERM; | ||
| 17 | if (frame->fp & 0x3 || frame->fp < TASK_SIZE) | ||
| 18 | return -EPERM; | ||
| 19 | |||
| 20 | *frame = *(struct stackframe *)frame->fp; | ||
| 21 | if (__kernel_text_address(frame->lr)) { | ||
| 22 | int graph = 0; | ||
| 23 | |||
| 24 | frame->lr = ftrace_graph_ret_addr(NULL, &graph, frame->lr, | ||
| 25 | NULL); | ||
| 26 | } | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | |||
| 30 | static void notrace walk_stackframe(struct stackframe *fr, | ||
| 31 | struct perf_callchain_entry_ctx *entry) | ||
| 32 | { | ||
| 33 | do { | ||
| 34 | perf_callchain_store(entry, fr->lr); | ||
| 35 | } while (unwind_frame_kernel(fr) >= 0); | ||
| 36 | } | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Get the return address for a single stackframe and return a pointer to the | ||
| 40 | * next frame tail. | ||
| 41 | */ | ||
| 42 | static unsigned long user_backtrace(struct perf_callchain_entry_ctx *entry, | ||
| 43 | unsigned long fp, unsigned long reg_lr) | ||
| 44 | { | ||
| 45 | struct stackframe buftail; | ||
| 46 | unsigned long lr = 0; | ||
| 47 | unsigned long *user_frame_tail = (unsigned long *)fp; | ||
| 48 | |||
| 49 | /* Check accessibility of one struct frame_tail beyond */ | ||
| 50 | if (!access_ok(user_frame_tail, sizeof(buftail))) | ||
| 51 | return 0; | ||
| 52 | if (__copy_from_user_inatomic(&buftail, user_frame_tail, | ||
| 53 | sizeof(buftail))) | ||
| 54 | return 0; | ||
| 55 | |||
| 56 | if (reg_lr != 0) | ||
| 57 | lr = reg_lr; | ||
| 58 | else | ||
| 59 | lr = buftail.lr; | ||
| 60 | |||
| 61 | fp = buftail.fp; | ||
| 62 | perf_callchain_store(entry, lr); | ||
| 63 | |||
| 64 | return fp; | ||
| 65 | } | ||
| 66 | |||
| 67 | /* | ||
| 68 | * This will be called when the target is in user mode | ||
| 69 | * This function will only be called when we use | ||
| 70 | * "PERF_SAMPLE_CALLCHAIN" in | ||
| 71 | * kernel/events/core.c:perf_prepare_sample() | ||
| 72 | * | ||
| 73 | * How to trigger perf_callchain_[user/kernel] : | ||
| 74 | * $ perf record -e cpu-clock --call-graph fp ./program | ||
| 75 | * $ perf report --call-graph | ||
| 76 | * | ||
| 77 | * On C-SKY platform, the program being sampled and the C library | ||
| 78 | * need to be compiled with * -mbacktrace, otherwise the user | ||
| 79 | * stack will not contain function frame. | ||
| 80 | */ | ||
| 81 | void perf_callchain_user(struct perf_callchain_entry_ctx *entry, | ||
| 82 | struct pt_regs *regs) | ||
| 83 | { | ||
| 84 | unsigned long fp = 0; | ||
| 85 | |||
| 86 | /* C-SKY does not support virtualization. */ | ||
| 87 | if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) | ||
| 88 | return; | ||
| 89 | |||
| 90 | fp = regs->regs[4]; | ||
| 91 | perf_callchain_store(entry, regs->pc); | ||
| 92 | |||
| 93 | /* | ||
| 94 | * While backtrace from leaf function, lr is normally | ||
| 95 | * not saved inside frame on C-SKY, so get lr from pt_regs | ||
| 96 | * at the sample point. However, lr value can be incorrect if | ||
| 97 | * lr is used as temp register | ||
| 98 | */ | ||
| 99 | fp = user_backtrace(entry, fp, regs->lr); | ||
| 100 | |||
| 101 | while (fp && !(fp & 0x3) && entry->nr < entry->max_stack) | ||
| 102 | fp = user_backtrace(entry, fp, 0); | ||
| 103 | } | ||
| 104 | |||
| 105 | void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, | ||
| 106 | struct pt_regs *regs) | ||
| 107 | { | ||
| 108 | struct stackframe fr; | ||
| 109 | |||
| 110 | /* C-SKY does not support virtualization. */ | ||
| 111 | if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { | ||
| 112 | pr_warn("C-SKY does not support perf in guest mode!"); | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | |||
| 116 | fr.fp = regs->regs[4]; | ||
| 117 | fr.lr = regs->lr; | ||
| 118 | walk_stackframe(&fr, entry); | ||
| 119 | } | ||
diff --git a/arch/csky/kernel/perf_regs.c b/arch/csky/kernel/perf_regs.c new file mode 100644 index 000000000000..eb32838b8210 --- /dev/null +++ b/arch/csky/kernel/perf_regs.c | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. | ||
| 3 | |||
| 4 | #include <linux/errno.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/perf_event.h> | ||
| 7 | #include <linux/bug.h> | ||
| 8 | #include <asm/perf_regs.h> | ||
| 9 | #include <asm/ptrace.h> | ||
| 10 | |||
| 11 | u64 perf_reg_value(struct pt_regs *regs, int idx) | ||
| 12 | { | ||
| 13 | if (WARN_ON_ONCE((u32)idx >= PERF_REG_CSKY_MAX)) | ||
| 14 | return 0; | ||
| 15 | |||
| 16 | return (u64)*((u32 *)regs + idx); | ||
| 17 | } | ||
| 18 | |||
| 19 | #define REG_RESERVED (~((1ULL << PERF_REG_CSKY_MAX) - 1)) | ||
| 20 | |||
| 21 | int perf_reg_validate(u64 mask) | ||
| 22 | { | ||
| 23 | if (!mask || mask & REG_RESERVED) | ||
| 24 | return -EINVAL; | ||
| 25 | |||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | u64 perf_reg_abi(struct task_struct *task) | ||
| 30 | { | ||
| 31 | return PERF_SAMPLE_REGS_ABI_32; | ||
| 32 | } | ||
| 33 | |||
| 34 | void perf_get_regs_user(struct perf_regs *regs_user, | ||
| 35 | struct pt_regs *regs, | ||
| 36 | struct pt_regs *regs_user_copy) | ||
| 37 | { | ||
| 38 | regs_user->regs = task_pt_regs(current); | ||
| 39 | regs_user->abi = perf_reg_abi(current); | ||
| 40 | } | ||
diff --git a/arch/csky/kernel/ptrace.c b/arch/csky/kernel/ptrace.c index f2f12fff36f7..313623a19ecb 100644 --- a/arch/csky/kernel/ptrace.c +++ b/arch/csky/kernel/ptrace.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. |
| 3 | 3 | ||
| 4 | #include <linux/audit.h> | ||
| 4 | #include <linux/elf.h> | 5 | #include <linux/elf.h> |
| 5 | #include <linux/errno.h> | 6 | #include <linux/errno.h> |
| 6 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| @@ -11,6 +12,7 @@ | |||
| 11 | #include <linux/sched/task_stack.h> | 12 | #include <linux/sched/task_stack.h> |
| 12 | #include <linux/signal.h> | 13 | #include <linux/signal.h> |
| 13 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
| 15 | #include <linux/tracehook.h> | ||
| 14 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
| 15 | #include <linux/user.h> | 17 | #include <linux/user.h> |
| 16 | 18 | ||
| @@ -22,6 +24,9 @@ | |||
| 22 | 24 | ||
| 23 | #include <abi/regdef.h> | 25 | #include <abi/regdef.h> |
| 24 | 26 | ||
| 27 | #define CREATE_TRACE_POINTS | ||
| 28 | #include <trace/events/syscalls.h> | ||
| 29 | |||
| 25 | /* sets the trace bits. */ | 30 | /* sets the trace bits. */ |
| 26 | #define TRACE_MODE_SI (1 << 14) | 31 | #define TRACE_MODE_SI (1 << 14) |
| 27 | #define TRACE_MODE_RUN 0 | 32 | #define TRACE_MODE_RUN 0 |
| @@ -207,35 +212,27 @@ long arch_ptrace(struct task_struct *child, long request, | |||
| 207 | return ret; | 212 | return ret; |
| 208 | } | 213 | } |
| 209 | 214 | ||
| 210 | /* | 215 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) |
| 211 | * If process's system calls is traces, do some corresponding handles in this | ||
| 212 | * function before entering system call function and after exiting system call | ||
| 213 | * function. | ||
| 214 | */ | ||
| 215 | asmlinkage void syscall_trace(int why, struct pt_regs *regs) | ||
| 216 | { | 216 | { |
| 217 | long saved_why; | 217 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
| 218 | /* | 218 | if (tracehook_report_syscall_entry(regs)) |
| 219 | * Save saved_why, why is used to denote syscall entry/exit; | 219 | syscall_set_nr(current, regs, -1); |
| 220 | * why = 0:entry, why = 1: exit | 220 | |
| 221 | */ | 221 | if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) |
| 222 | saved_why = regs->regs[SYSTRACE_SAVENUM]; | 222 | trace_sys_enter(regs, syscall_get_nr(current, regs)); |
| 223 | regs->regs[SYSTRACE_SAVENUM] = why; | 223 | |
| 224 | 224 | audit_syscall_entry(regs_syscallid(regs), regs->a0, regs->a1, regs->a2, regs->a3); | |
| 225 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | 225 | } |
| 226 | ? 0x80 : 0)); | 226 | |
| 227 | 227 | asmlinkage void syscall_trace_exit(struct pt_regs *regs) | |
| 228 | /* | 228 | { |
| 229 | * this isn't the same as continuing with a signal, but it will do | 229 | audit_syscall_exit(regs); |
| 230 | * for normal use. strace only continues with a signal if the | 230 | |
| 231 | * stopping signal is not SIGTRAP. -brl | 231 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
| 232 | */ | 232 | tracehook_report_syscall_exit(regs, 0); |
| 233 | if (current->exit_code) { | ||
| 234 | send_sig(current->exit_code, current, 1); | ||
| 235 | current->exit_code = 0; | ||
| 236 | } | ||
| 237 | 233 | ||
| 238 | regs->regs[SYSTRACE_SAVENUM] = saved_why; | 234 | if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) |
| 235 | trace_sys_exit(regs, syscall_get_return_value(current, regs)); | ||
| 239 | } | 236 | } |
| 240 | 237 | ||
| 241 | extern void show_stack(struct task_struct *task, unsigned long *stack); | 238 | extern void show_stack(struct task_struct *task, unsigned long *stack); |
diff --git a/arch/csky/kernel/setup.c b/arch/csky/kernel/setup.c index dff8b89444ec..23ee604aafdb 100644 --- a/arch/csky/kernel/setup.c +++ b/arch/csky/kernel/setup.c | |||
| @@ -142,18 +142,24 @@ void __init setup_arch(char **cmdline_p) | |||
| 142 | #endif | 142 | #endif |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | asmlinkage __visible void __init csky_start(unsigned int unused, void *param) | 145 | unsigned long va_pa_offset; |
| 146 | EXPORT_SYMBOL(va_pa_offset); | ||
| 147 | |||
| 148 | asmlinkage __visible void __init csky_start(unsigned int unused, | ||
| 149 | void *dtb_start) | ||
| 146 | { | 150 | { |
| 147 | /* Clean up bss section */ | 151 | /* Clean up bss section */ |
| 148 | memset(__bss_start, 0, __bss_stop - __bss_start); | 152 | memset(__bss_start, 0, __bss_stop - __bss_start); |
| 149 | 153 | ||
| 154 | va_pa_offset = read_mmu_msa0() & ~(SSEG_SIZE - 1); | ||
| 155 | |||
| 150 | pre_trap_init(); | 156 | pre_trap_init(); |
| 151 | pre_mmu_init(); | 157 | pre_mmu_init(); |
| 152 | 158 | ||
| 153 | if (param == NULL) | 159 | if (dtb_start == NULL) |
| 154 | early_init_dt_scan(__dtb_start); | 160 | early_init_dt_scan(__dtb_start); |
| 155 | else | 161 | else |
| 156 | early_init_dt_scan(param); | 162 | early_init_dt_scan(dtb_start); |
| 157 | 163 | ||
| 158 | start_kernel(); | 164 | start_kernel(); |
| 159 | 165 | ||
diff --git a/arch/csky/kernel/signal.c b/arch/csky/kernel/signal.c index 207a891479d2..04a43cfd4e09 100644 --- a/arch/csky/kernel/signal.c +++ b/arch/csky/kernel/signal.c | |||
| @@ -1,26 +1,10 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | ||
| 3 | 2 | ||
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/mm.h> | ||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/signal.h> | 3 | #include <linux/signal.h> |
| 4 | #include <linux/uaccess.h> | ||
| 8 | #include <linux/syscalls.h> | 5 | #include <linux/syscalls.h> |
| 9 | #include <linux/errno.h> | ||
| 10 | #include <linux/wait.h> | ||
| 11 | #include <linux/ptrace.h> | ||
| 12 | #include <linux/unistd.h> | ||
| 13 | #include <linux/stddef.h> | ||
| 14 | #include <linux/highuid.h> | ||
| 15 | #include <linux/personality.h> | ||
| 16 | #include <linux/tty.h> | ||
| 17 | #include <linux/binfmts.h> | ||
| 18 | #include <linux/tracehook.h> | 6 | #include <linux/tracehook.h> |
| 19 | #include <linux/freezer.h> | ||
| 20 | #include <linux/uaccess.h> | ||
| 21 | 7 | ||
| 22 | #include <asm/setup.h> | ||
| 23 | #include <asm/pgtable.h> | ||
| 24 | #include <asm/traps.h> | 8 | #include <asm/traps.h> |
| 25 | #include <asm/ucontext.h> | 9 | #include <asm/ucontext.h> |
| 26 | #include <asm/vdso.h> | 10 | #include <asm/vdso.h> |
| @@ -29,110 +13,117 @@ | |||
| 29 | 13 | ||
| 30 | #ifdef CONFIG_CPU_HAS_FPU | 14 | #ifdef CONFIG_CPU_HAS_FPU |
| 31 | #include <abi/fpu.h> | 15 | #include <abi/fpu.h> |
| 32 | 16 | static int restore_fpu_state(struct sigcontext __user *sc) | |
| 33 | static int restore_fpu_state(struct sigcontext *sc) | ||
| 34 | { | 17 | { |
| 35 | int err = 0; | 18 | int err = 0; |
| 36 | struct user_fp user_fp; | 19 | struct user_fp user_fp; |
| 37 | 20 | ||
| 38 | err = copy_from_user(&user_fp, &sc->sc_user_fp, sizeof(user_fp)); | 21 | err = __copy_from_user(&user_fp, &sc->sc_user_fp, sizeof(user_fp)); |
| 39 | 22 | ||
| 40 | restore_from_user_fp(&user_fp); | 23 | restore_from_user_fp(&user_fp); |
| 41 | 24 | ||
| 42 | return err; | 25 | return err; |
| 43 | } | 26 | } |
| 44 | 27 | ||
| 45 | static int save_fpu_state(struct sigcontext *sc) | 28 | static int save_fpu_state(struct sigcontext __user *sc) |
| 46 | { | 29 | { |
| 47 | struct user_fp user_fp; | 30 | struct user_fp user_fp; |
| 48 | 31 | ||
| 49 | save_to_user_fp(&user_fp); | 32 | save_to_user_fp(&user_fp); |
| 50 | 33 | ||
| 51 | return copy_to_user(&sc->sc_user_fp, &user_fp, sizeof(user_fp)); | 34 | return __copy_to_user(&sc->sc_user_fp, &user_fp, sizeof(user_fp)); |
| 52 | } | 35 | } |
| 53 | #else | 36 | #else |
| 54 | static inline int restore_fpu_state(struct sigcontext *sc) { return 0; } | 37 | #define restore_fpu_state(sigcontext) (0) |
| 55 | static inline int save_fpu_state(struct sigcontext *sc) { return 0; } | 38 | #define save_fpu_state(sigcontext) (0) |
| 56 | #endif | 39 | #endif |
| 57 | 40 | ||
| 58 | struct rt_sigframe { | 41 | struct rt_sigframe { |
| 59 | int sig; | ||
| 60 | struct siginfo *pinfo; | ||
| 61 | void *puc; | ||
| 62 | struct siginfo info; | 42 | struct siginfo info; |
| 63 | struct ucontext uc; | 43 | struct ucontext uc; |
| 64 | }; | 44 | }; |
| 65 | 45 | ||
| 66 | static int | 46 | static long restore_sigcontext(struct pt_regs *regs, |
| 67 | restore_sigframe(struct pt_regs *regs, | 47 | struct sigcontext __user *sc) |
| 68 | struct sigcontext *sc, int *pr2) | ||
| 69 | { | 48 | { |
| 70 | int err = 0; | 49 | int err = 0; |
| 71 | 50 | ||
| 72 | /* Always make any pending restarted system calls return -EINTR */ | 51 | /* sc_pt_regs is structured the same as the start of pt_regs */ |
| 73 | current_thread_info()->task->restart_block.fn = do_no_restart_syscall; | 52 | err |= __copy_from_user(regs, &sc->sc_pt_regs, sizeof(struct pt_regs)); |
| 74 | |||
| 75 | err |= copy_from_user(regs, &sc->sc_pt_regs, sizeof(struct pt_regs)); | ||
| 76 | 53 | ||
| 54 | /* Restore the floating-point state. */ | ||
| 77 | err |= restore_fpu_state(sc); | 55 | err |= restore_fpu_state(sc); |
| 78 | 56 | ||
| 79 | *pr2 = regs->a0; | ||
| 80 | return err; | 57 | return err; |
| 81 | } | 58 | } |
| 82 | 59 | ||
| 83 | asmlinkage int | 60 | SYSCALL_DEFINE0(rt_sigreturn) |
| 84 | do_rt_sigreturn(void) | ||
| 85 | { | 61 | { |
| 86 | sigset_t set; | ||
| 87 | int a0; | ||
| 88 | struct pt_regs *regs = current_pt_regs(); | 62 | struct pt_regs *regs = current_pt_regs(); |
| 89 | struct rt_sigframe *frame = (struct rt_sigframe *)(regs->usp); | 63 | struct rt_sigframe __user *frame; |
| 64 | struct task_struct *task; | ||
| 65 | sigset_t set; | ||
| 66 | |||
| 67 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 68 | current->restart_block.fn = do_no_restart_syscall; | ||
| 69 | |||
| 70 | frame = (struct rt_sigframe __user *)regs->usp; | ||
| 90 | 71 | ||
| 91 | if (!access_ok(frame, sizeof(*frame))) | 72 | if (!access_ok(frame, sizeof(*frame))) |
| 92 | goto badframe; | 73 | goto badframe; |
| 74 | |||
| 93 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 75 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 94 | goto badframe; | 76 | goto badframe; |
| 95 | 77 | ||
| 96 | sigdelsetmask(&set, (sigmask(SIGKILL) | sigmask(SIGSTOP))); | 78 | set_current_blocked(&set); |
| 97 | spin_lock_irq(¤t->sighand->siglock); | ||
| 98 | current->blocked = set; | ||
| 99 | recalc_sigpending(); | ||
| 100 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 101 | 79 | ||
| 102 | if (restore_sigframe(regs, &frame->uc.uc_mcontext, &a0)) | 80 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
| 103 | goto badframe; | 81 | goto badframe; |
| 104 | 82 | ||
| 105 | return a0; | 83 | if (restore_altstack(&frame->uc.uc_stack)) |
| 84 | goto badframe; | ||
| 85 | |||
| 86 | return regs->a0; | ||
| 106 | 87 | ||
| 107 | badframe: | 88 | badframe: |
| 108 | force_sig(SIGSEGV, current); | 89 | task = current; |
| 90 | force_sig(SIGSEGV, task); | ||
| 109 | return 0; | 91 | return 0; |
| 110 | } | 92 | } |
| 111 | 93 | ||
| 112 | static int setup_sigframe(struct sigcontext *sc, struct pt_regs *regs) | 94 | static int setup_sigcontext(struct rt_sigframe __user *frame, |
| 95 | struct pt_regs *regs) | ||
| 113 | { | 96 | { |
| 97 | struct sigcontext __user *sc = &frame->uc.uc_mcontext; | ||
| 114 | int err = 0; | 98 | int err = 0; |
| 115 | 99 | ||
| 116 | err |= copy_to_user(&sc->sc_pt_regs, regs, sizeof(struct pt_regs)); | 100 | err |= __copy_to_user(&sc->sc_pt_regs, regs, sizeof(struct pt_regs)); |
| 117 | err |= save_fpu_state(sc); | 101 | err |= save_fpu_state(sc); |
| 118 | 102 | ||
| 119 | return err; | 103 | return err; |
| 120 | } | 104 | } |
| 121 | 105 | ||
| 122 | static inline void * | 106 | static inline void __user *get_sigframe(struct ksignal *ksig, |
| 123 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 107 | struct pt_regs *regs, size_t framesize) |
| 124 | { | 108 | { |
| 125 | unsigned long usp; | 109 | unsigned long sp; |
| 110 | /* Default to using normal stack */ | ||
| 111 | sp = regs->usp; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * If we are on the alternate signal stack and would overflow it, don't. | ||
| 115 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
| 116 | */ | ||
| 117 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) | ||
| 118 | return (void __user __force *)(-1UL); | ||
| 126 | 119 | ||
| 127 | /* Default to using normal stack. */ | 120 | /* This is the X/Open sanctioned signal stack switching. */ |
| 128 | usp = regs->usp; | 121 | sp = sigsp(sp, ksig) - framesize; |
| 129 | 122 | ||
| 130 | /* This is the X/Open sanctioned signal stack switching. */ | 123 | /* Align the stack frame. */ |
| 131 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(usp)) { | 124 | sp &= -8UL; |
| 132 | if (!on_sig_stack(usp)) | 125 | |
| 133 | usp = current->sas_ss_sp + current->sas_ss_size; | 126 | return (void __user *)sp; |
| 134 | } | ||
| 135 | return (void *)((usp - frame_size) & -8UL); | ||
| 136 | } | 127 | } |
| 137 | 128 | ||
| 138 | static int | 129 | static int |
| @@ -140,205 +131,128 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) | |||
| 140 | { | 131 | { |
| 141 | struct rt_sigframe *frame; | 132 | struct rt_sigframe *frame; |
| 142 | int err = 0; | 133 | int err = 0; |
| 143 | |||
| 144 | struct csky_vdso *vdso = current->mm->context.vdso; | 134 | struct csky_vdso *vdso = current->mm->context.vdso; |
| 145 | 135 | ||
| 146 | frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); | 136 | frame = get_sigframe(ksig, regs, sizeof(*frame)); |
| 147 | if (!frame) | 137 | if (!access_ok(frame, sizeof(*frame))) |
| 148 | return 1; | 138 | return -EFAULT; |
| 149 | 139 | ||
| 150 | err |= __put_user(ksig->sig, &frame->sig); | ||
| 151 | err |= __put_user(&frame->info, &frame->pinfo); | ||
| 152 | err |= __put_user(&frame->uc, &frame->puc); | ||
| 153 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); | 140 | err |= copy_siginfo_to_user(&frame->info, &ksig->info); |
| 154 | 141 | ||
| 155 | /* Create the ucontext. */ | 142 | /* Create the ucontext. */ |
| 156 | err |= __put_user(0, &frame->uc.uc_flags); | 143 | err |= __put_user(0, &frame->uc.uc_flags); |
| 157 | err |= __put_user(0, &frame->uc.uc_link); | 144 | err |= __put_user(NULL, &frame->uc.uc_link); |
| 158 | err |= __put_user((void *)current->sas_ss_sp, | 145 | err |= __save_altstack(&frame->uc.uc_stack, regs->usp); |
| 159 | &frame->uc.uc_stack.ss_sp); | 146 | err |= setup_sigcontext(frame, regs); |
| 160 | err |= __put_user(sas_ss_flags(regs->usp), | 147 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 161 | &frame->uc.uc_stack.ss_flags); | ||
| 162 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
| 163 | err |= setup_sigframe(&frame->uc.uc_mcontext, regs); | ||
| 164 | err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
| 165 | |||
| 166 | if (err) | 148 | if (err) |
| 167 | goto give_sigsegv; | 149 | return -EFAULT; |
| 168 | 150 | ||
| 169 | /* Set up registers for signal handler */ | 151 | /* Set up to return from userspace. */ |
| 170 | regs->usp = (unsigned long)frame; | 152 | regs->lr = (unsigned long)(vdso->rt_signal_retcode); |
| 171 | regs->pc = (unsigned long)ksig->ka.sa.sa_handler; | ||
| 172 | regs->lr = (unsigned long)vdso->rt_signal_retcode; | ||
| 173 | 153 | ||
| 174 | adjust_stack: | 154 | /* |
| 175 | regs->a0 = ksig->sig; /* first arg is signo */ | 155 | * Set up registers for signal handler. |
| 176 | regs->a1 = (unsigned long)(&(frame->info)); | 156 | * Registers that we don't modify keep the value they had from |
| 177 | regs->a2 = (unsigned long)(&(frame->uc)); | 157 | * user-space at the time we took the signal. |
| 178 | return err; | 158 | * We always pass siginfo and mcontext, regardless of SA_SIGINFO, |
| 159 | * since some things rely on this (e.g. glibc's debug/segfault.c). | ||
| 160 | */ | ||
| 161 | regs->pc = (unsigned long)ksig->ka.sa.sa_handler; | ||
| 162 | regs->usp = (unsigned long)frame; | ||
| 163 | regs->a0 = ksig->sig; /* a0: signal number */ | ||
| 164 | regs->a1 = (unsigned long)(&(frame->info)); /* a1: siginfo pointer */ | ||
| 165 | regs->a2 = (unsigned long)(&(frame->uc)); /* a2: ucontext pointer */ | ||
| 179 | 166 | ||
| 180 | give_sigsegv: | 167 | return 0; |
| 181 | if (ksig->sig == SIGSEGV) | ||
| 182 | ksig->ka.sa.sa_handler = SIG_DFL; | ||
| 183 | force_sig(SIGSEGV, current); | ||
| 184 | goto adjust_stack; | ||
| 185 | } | 168 | } |
| 186 | 169 | ||
| 187 | /* | 170 | static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) |
| 188 | * OK, we're invoking a handler | ||
| 189 | */ | ||
| 190 | static int | ||
| 191 | handle_signal(struct ksignal *ksig, struct pt_regs *regs) | ||
| 192 | { | 171 | { |
| 193 | int ret; | ||
| 194 | sigset_t *oldset = sigmask_to_save(); | 172 | sigset_t *oldset = sigmask_to_save(); |
| 173 | int ret; | ||
| 195 | 174 | ||
| 196 | /* | 175 | /* Are we from a system call? */ |
| 197 | * set up the stack frame, regardless of SA_SIGINFO, | 176 | if (in_syscall(regs)) { |
| 198 | * and pass info anyway. | 177 | /* Avoid additional syscall restarting via ret_from_exception */ |
| 199 | */ | 178 | forget_syscall(regs); |
| 200 | ret = setup_rt_frame(ksig, oldset, regs); | 179 | |
| 180 | /* If so, check system call restarting.. */ | ||
| 181 | switch (regs->a0) { | ||
| 182 | case -ERESTART_RESTARTBLOCK: | ||
| 183 | case -ERESTARTNOHAND: | ||
| 184 | regs->a0 = -EINTR; | ||
| 185 | break; | ||
| 201 | 186 | ||
| 202 | if (ret != 0) { | 187 | case -ERESTARTSYS: |
| 203 | force_sigsegv(ksig->sig, current); | 188 | if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { |
| 204 | return ret; | 189 | regs->a0 = -EINTR; |
| 190 | break; | ||
| 191 | } | ||
| 192 | /* fallthrough */ | ||
| 193 | case -ERESTARTNOINTR: | ||
| 194 | regs->a0 = regs->orig_a0; | ||
| 195 | regs->pc -= TRAP0_SIZE; | ||
| 196 | break; | ||
| 197 | } | ||
| 205 | } | 198 | } |
| 206 | 199 | ||
| 207 | /* Block the signal if we were successful. */ | 200 | /* Set up the stack frame */ |
| 208 | spin_lock_irq(¤t->sighand->siglock); | 201 | ret = setup_rt_frame(ksig, oldset, regs); |
| 209 | sigorsets(¤t->blocked, ¤t->blocked, &ksig->ka.sa.sa_mask); | ||
| 210 | if (!(ksig->ka.sa.sa_flags & SA_NODEFER)) | ||
| 211 | sigaddset(¤t->blocked, ksig->sig); | ||
| 212 | recalc_sigpending(); | ||
| 213 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 214 | 202 | ||
| 215 | return 0; | 203 | signal_setup_done(ret, ksig, 0); |
| 216 | } | 204 | } |
| 217 | 205 | ||
| 218 | /* | 206 | static void do_signal(struct pt_regs *regs) |
| 219 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
| 220 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
| 221 | * mistake. | ||
| 222 | * | ||
| 223 | * Note that we go through the signals twice: once to check the signals | ||
| 224 | * that the kernel can handle, and then we build all the user-level signal | ||
| 225 | * handling stack-frames in one go after that. | ||
| 226 | */ | ||
| 227 | static void do_signal(struct pt_regs *regs, int syscall) | ||
| 228 | { | 207 | { |
| 229 | unsigned int retval = 0, continue_addr = 0, restart_addr = 0; | ||
| 230 | struct ksignal ksig; | 208 | struct ksignal ksig; |
| 231 | 209 | ||
| 232 | /* | 210 | if (get_signal(&ksig)) { |
| 233 | * We want the common case to go fast, which | 211 | /* Actually deliver the signal */ |
| 234 | * is why we may in certain cases get here from | 212 | handle_signal(&ksig, regs); |
| 235 | * kernel mode. Just return without doing anything | ||
| 236 | * if so. | ||
| 237 | */ | ||
| 238 | if (!user_mode(regs)) | ||
| 239 | return; | 213 | return; |
| 214 | } | ||
| 240 | 215 | ||
| 241 | /* | 216 | /* Did we come from a system call? */ |
| 242 | * If we were from a system call, check for system call restarting... | 217 | if (in_syscall(regs)) { |
| 243 | */ | 218 | /* Avoid additional syscall restarting via ret_from_exception */ |
| 244 | if (syscall) { | 219 | forget_syscall(regs); |
| 245 | continue_addr = regs->pc; | ||
| 246 | #if defined(__CSKYABIV2__) | ||
| 247 | restart_addr = continue_addr - 4; | ||
| 248 | #else | ||
| 249 | restart_addr = continue_addr - 2; | ||
| 250 | #endif | ||
| 251 | retval = regs->a0; | ||
| 252 | 220 | ||
| 253 | /* | 221 | /* Restart the system call - no handlers present */ |
| 254 | * Prepare for system call restart. We do this here so that a | 222 | switch (regs->a0) { |
| 255 | * debugger will see the already changed. | ||
| 256 | */ | ||
| 257 | switch (retval) { | ||
| 258 | case -ERESTARTNOHAND: | 223 | case -ERESTARTNOHAND: |
| 259 | case -ERESTARTSYS: | 224 | case -ERESTARTSYS: |
| 260 | case -ERESTARTNOINTR: | 225 | case -ERESTARTNOINTR: |
| 261 | regs->a0 = regs->orig_a0; | 226 | regs->a0 = regs->orig_a0; |
| 262 | regs->pc = restart_addr; | 227 | regs->pc -= TRAP0_SIZE; |
| 263 | break; | 228 | break; |
| 264 | case -ERESTART_RESTARTBLOCK: | 229 | case -ERESTART_RESTARTBLOCK: |
| 265 | regs->a0 = -EINTR; | 230 | regs->a0 = regs->orig_a0; |
| 231 | regs_syscallid(regs) = __NR_restart_syscall; | ||
| 232 | regs->pc -= TRAP0_SIZE; | ||
| 266 | break; | 233 | break; |
| 267 | } | 234 | } |
| 268 | } | 235 | } |
| 269 | 236 | ||
| 270 | if (try_to_freeze()) | ||
| 271 | goto no_signal; | ||
| 272 | |||
| 273 | /* | 237 | /* |
| 274 | * Get the signal to deliver. When running under ptrace, at this | 238 | * If there is no signal to deliver, we just put the saved |
| 275 | * point the debugger may change all our registers ... | 239 | * sigmask back. |
| 276 | */ | 240 | */ |
| 277 | if (get_signal(&ksig)) { | 241 | restore_saved_sigmask(); |
| 278 | /* | ||
| 279 | * Depending on the signal settings we may need to revert the | ||
| 280 | * decision to restart the system call. But skip this if a | ||
| 281 | * debugger has chosen to restart at a different PC. | ||
| 282 | */ | ||
| 283 | if (regs->pc == restart_addr) { | ||
| 284 | if (retval == -ERESTARTNOHAND || | ||
| 285 | (retval == -ERESTARTSYS && | ||
| 286 | !(ksig.ka.sa.sa_flags & SA_RESTART))) { | ||
| 287 | regs->a0 = -EINTR; | ||
| 288 | regs->pc = continue_addr; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | /* Whee! Actually deliver the signal. */ | ||
| 293 | if (handle_signal(&ksig, regs) == 0) { | ||
| 294 | /* | ||
| 295 | * A signal was successfully delivered; the saved | ||
| 296 | * sigmask will have been stored in the signal frame, | ||
| 297 | * and will be restored by sigreturn, so we can simply | ||
| 298 | * clear the TIF_RESTORE_SIGMASK flag. | ||
| 299 | */ | ||
| 300 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
| 301 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 302 | } | ||
| 303 | return; | ||
| 304 | } | ||
| 305 | |||
| 306 | no_signal: | ||
| 307 | if (syscall) { | ||
| 308 | /* | ||
| 309 | * Handle restarting a different system call. As above, | ||
| 310 | * if a debugger has chosen to restart at a different PC, | ||
| 311 | * ignore the restart. | ||
| 312 | */ | ||
| 313 | if (retval == -ERESTART_RESTARTBLOCK | ||
| 314 | && regs->pc == continue_addr) { | ||
| 315 | #if defined(__CSKYABIV2__) | ||
| 316 | regs->regs[3] = __NR_restart_syscall; | ||
| 317 | regs->pc -= 4; | ||
| 318 | #else | ||
| 319 | regs->regs[9] = __NR_restart_syscall; | ||
| 320 | regs->pc -= 2; | ||
| 321 | #endif | ||
| 322 | } | ||
| 323 | |||
| 324 | /* | ||
| 325 | * If there's no signal to deliver, we just put the saved | ||
| 326 | * sigmask back. | ||
| 327 | */ | ||
| 328 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
| 329 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 330 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | 242 | } |
| 334 | 243 | ||
| 335 | asmlinkage void | 244 | /* |
| 336 | do_notify_resume(unsigned int thread_flags, struct pt_regs *regs, int syscall) | 245 | * notification of userspace execution resumption |
| 246 | * - triggered by the _TIF_WORK_MASK flags | ||
| 247 | */ | ||
| 248 | asmlinkage void do_notify_resume(struct pt_regs *regs, | ||
| 249 | unsigned long thread_info_flags) | ||
| 337 | { | 250 | { |
| 338 | if (thread_flags & _TIF_SIGPENDING) | 251 | /* Handle pending signal delivery */ |
| 339 | do_signal(regs, syscall); | 252 | if (thread_info_flags & _TIF_SIGPENDING) |
| 253 | do_signal(regs); | ||
| 340 | 254 | ||
| 341 | if (thread_flags & _TIF_NOTIFY_RESUME) { | 255 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 342 | clear_thread_flag(TIF_NOTIFY_RESUME); | 256 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 343 | tracehook_notify_resume(regs); | 257 | tracehook_notify_resume(regs); |
| 344 | } | 258 | } |
diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c index d6f4b66b93e2..18041f46ded1 100644 --- a/arch/csky/mm/fault.c +++ b/arch/csky/mm/fault.c | |||
| @@ -15,9 +15,9 @@ | |||
| 15 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
| 16 | #include <linux/version.h> | 16 | #include <linux/version.h> |
| 17 | #include <linux/vt_kern.h> | 17 | #include <linux/vt_kern.h> |
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/extable.h> | 18 | #include <linux/extable.h> |
| 20 | #include <linux/uaccess.h> | 19 | #include <linux/uaccess.h> |
| 20 | #include <linux/perf_event.h> | ||
| 21 | 21 | ||
| 22 | #include <asm/hardirq.h> | 22 | #include <asm/hardirq.h> |
| 23 | #include <asm/mmu_context.h> | 23 | #include <asm/mmu_context.h> |
| @@ -82,7 +82,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, | |||
| 82 | 82 | ||
| 83 | unsigned long pgd_base; | 83 | unsigned long pgd_base; |
| 84 | 84 | ||
| 85 | pgd_base = tlb_get_pgd(); | 85 | pgd_base = (unsigned long)__va(get_pgd()); |
| 86 | pgd = (pgd_t *)pgd_base + offset; | 86 | pgd = (pgd_t *)pgd_base + offset; |
| 87 | pgd_k = init_mm.pgd + offset; | 87 | pgd_k = init_mm.pgd + offset; |
| 88 | 88 | ||
| @@ -107,6 +107,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, | |||
| 107 | return; | 107 | return; |
| 108 | } | 108 | } |
| 109 | #endif | 109 | #endif |
| 110 | |||
| 111 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); | ||
| 110 | /* | 112 | /* |
| 111 | * If we're in an interrupt or have no user | 113 | * If we're in an interrupt or have no user |
| 112 | * context, we must not take the fault.. | 114 | * context, we must not take the fault.. |
| @@ -154,10 +156,15 @@ good_area: | |||
| 154 | goto bad_area; | 156 | goto bad_area; |
| 155 | BUG(); | 157 | BUG(); |
| 156 | } | 158 | } |
| 157 | if (fault & VM_FAULT_MAJOR) | 159 | if (fault & VM_FAULT_MAJOR) { |
| 158 | tsk->maj_flt++; | 160 | tsk->maj_flt++; |
| 159 | else | 161 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, |
| 162 | address); | ||
| 163 | } else { | ||
| 160 | tsk->min_flt++; | 164 | tsk->min_flt++; |
| 165 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, | ||
| 166 | address); | ||
| 167 | } | ||
| 161 | 168 | ||
| 162 | up_read(&mm->mmap_sem); | 169 | up_read(&mm->mmap_sem); |
| 163 | return; | 170 | return; |
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 68841d01162c..f71666899245 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
| @@ -397,6 +397,9 @@ if ($arch eq "x86_64") { | |||
| 397 | } elsif ($arch eq "nds32") { | 397 | } elsif ($arch eq "nds32") { |
| 398 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; | 398 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; |
| 399 | $alignment = 2; | 399 | $alignment = 2; |
| 400 | } elsif ($arch eq "csky") { | ||
| 401 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$"; | ||
| 402 | $alignment = 2; | ||
| 400 | } else { | 403 | } else { |
| 401 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; | 404 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; |
| 402 | } | 405 | } |
