Message ID | 1344966752-16102-9-git-send-email-catalin.marinas@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, On Tue, Aug 14, 2012 at 06:52:09PM +0100, Catalin Marinas wrote: > diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h > new file mode 100644 > index 0000000..ef54125 > --- /dev/null > +++ b/arch/arm64/include/asm/cputype.h > @@ -0,0 +1,49 @@ > +/* > + * Copyright (C) 2012 ARM Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > +#ifndef __ASM_CPUTYPE_H > +#define __ASM_CPUTYPE_H > + > +#define ID_MIDR_EL1 "midr_el1" > +#define ID_CTR_EL0 "ctr_el0" > + > +#define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" > +#define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" > +#define ID_AA64AFR0_EL1 "id_aa64afr0_el1" > +#define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" > +#define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" > + > +#define read_cpuid(reg) ({ \ > + u64 __val; \ > + asm("mrs %0, " reg : "=r" (__val)); \ > + __val; \ > +}) > + > +/* > + * The CPU ID never changes at run time, so we might as well tell the > + * compiler that it's constant. Use this function to read the CPU ID > + * rather than directly reading processor_id or read_cpuid() directly. > + */ > +static inline u32 __attribute_const__ read_cpuid_id(void) > +{ > + return read_cpuid(ID_MIDR_EL1); > +} > + > +static inline u32 __attribute_const__ read_cpuid_cachetype(void) > +{ > + return read_cpuid(ID_CTR_EL0); > +} Is this perhaps a carry-over from arch/arm? Abstracting out read_cpuid() doesn't seem to buy anything here, just opencode the one-line assembly in each. Might as well cleanup the naming a little too while you're at it, i.e. read_cpu_id() and read_cpu_cachetype(). > diff --git a/arch/arm64/include/asm/procinfo.h b/arch/arm64/include/asm/procinfo.h > new file mode 100644 > index 0000000..81fece9 > --- /dev/null > +++ b/arch/arm64/include/asm/procinfo.h > @@ -0,0 +1,44 @@ > +/* > + * Based on arch/arm/include/asm/procinfo.h > + * > + * Copyright (C) 1996-1999 Russell King > + * Copyright (C) 2012 ARM Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > +#ifndef __ASM_PROCINFO_H > +#define __ASM_PROCINFO_H > + > +#ifdef __KERNEL__ > + > +/* > + * Note! struct processor is always defined if we're > + * using MULTI_CPU, otherwise this entry is unused, > + * but still exists. Stale comment? > + * > + * NOTE! The following structure is defined by assembly > + * language, NOT C code. For more information, check: > + * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S Stale references. Also, no current arm64 implementation uses this. Premature abstraction perhaps? > +struct proc_info_list { > + unsigned int cpu_val; > + unsigned int cpu_mask; > + unsigned long __cpu_flush; /* used by head.S */ > + const char *cpu_name; > +}; > + > +#else /* __KERNEL__ */ > +#include <asm/elf.h> > +#warning "Please include asm/elf.h instead" > +#endif /* __KERNEL__ */ > +#endif > diff --git a/arch/arm64/mm/proc-syms.c b/arch/arm64/mm/proc-syms.c > new file mode 100644 > index 0000000..2d99ef9 > --- /dev/null > +++ b/arch/arm64/mm/proc-syms.c > @@ -0,0 +1,31 @@ > +/* > + * Based on arch/arm/mm/proc-syms.c > + * > + * Copyright (C) 2000-2002 Russell King > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/export.h> > +#include <linux/mm.h> > + > +#include <asm/cacheflush.h> > +#include <asm/proc-fns.h> > +#include <asm/tlbflush.h> > +#include <asm/page.h> > + > +EXPORT_SYMBOL(__cpuc_flush_kern_all); > +EXPORT_SYMBOL(__cpuc_flush_user_all); > +EXPORT_SYMBOL(__cpuc_flush_user_range); > +EXPORT_SYMBOL(__cpuc_coherent_kern_range); > +EXPORT_SYMBOL(__cpuc_flush_dcache_area); See comment on other email about putting function pointers in a struct instead. > diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S > new file mode 100644 > index 0000000..453f517 > --- /dev/null > +++ b/arch/arm64/mm/proc.S > @@ -0,0 +1,193 @@ > + .section ".proc.info.init", #alloc, #execinstr > + > + .type __v8_proc_info, #object > +__v8_proc_info: > + .long 0x000f0000 // Required ID value > + .long 0x000f0000 // Mask for ID > + b __cpu_setup > + nop > + .quad cpu_name > + .long 0 > + .size __v8_proc_info, . - __v8_proc_info I know this is a carry-over from arch/arm, but how about moving this to more of a C construct similar to arch/powerpc/kernel/cputable.c instead? It's considerably easier to read that way, and it's convenient to have the definitions all in one place, making it easier to share some of the functions, etc. -Olof
On Tuesday 14 August 2012, Catalin Marinas wrote: > diff --git a/arch/arm64/include/asm/procinfo.h b/arch/arm64/include/asm/procinfo.h > new file mode 100644 > index 0000000..81fece9 > --- /dev/null > +++ b/arch/arm64/include/asm/procinfo.h > @@ -0,0 +1,44 @@ > +/* > + * Based on arch/arm/include/asm/procinfo.h > + * > + * Copyright (C) 1996-1999 Russell King > + * Copyright (C) 2012 ARM Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see <http://www.gnu.org/licenses/>. > + */ > +#ifndef __ASM_PROCINFO_H > +#define __ASM_PROCINFO_H > + > +#ifdef __KERNEL__ > + > +/* > + * Note! struct processor is always defined if we're > + * using MULTI_CPU, otherwise this entry is unused, > + * but still exists. > + * > + * NOTE! The following structure is defined by assembly > + * language, NOT C code. For more information, check: > + * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S > + */ > +struct proc_info_list { > + unsigned int cpu_val; > + unsigned int cpu_mask; > + unsigned long __cpu_flush; /* used by head.S */ > + const char *cpu_name; > +}; > + > +#else /* __KERNEL__ */ > +#include <asm/elf.h> > +#warning "Please include asm/elf.h instead" > +#endif /* __KERNEL__ */ > +#endif I think you forgot to remove this file when you removed MULTI_CPU. Arnd
On Wed, Aug 15, 2012 at 01:10:43AM +0100, Olof Johansson wrote: > On Tue, Aug 14, 2012 at 06:52:09PM +0100, Catalin Marinas wrote: > > > diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h > > new file mode 100644 > > index 0000000..ef54125 > > --- /dev/null > > +++ b/arch/arm64/include/asm/cputype.h > > @@ -0,0 +1,49 @@ > > +#define ID_MIDR_EL1 "midr_el1" > > +#define ID_CTR_EL0 "ctr_el0" > > + > > +#define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" > > +#define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" > > +#define ID_AA64AFR0_EL1 "id_aa64afr0_el1" > > +#define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" > > +#define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" > > + > > +#define read_cpuid(reg) ({ \ > > + u64 __val; \ > > + asm("mrs %0, " reg : "=r" (__val)); \ > > + __val; \ > > +}) > > + > > +/* > > + * The CPU ID never changes at run time, so we might as well tell the > > + * compiler that it's constant. Use this function to read the CPU ID > > + * rather than directly reading processor_id or read_cpuid() directly. > > + */ > > +static inline u32 __attribute_const__ read_cpuid_id(void) > > +{ > > + return read_cpuid(ID_MIDR_EL1); > > +} > > + > > +static inline u32 __attribute_const__ read_cpuid_cachetype(void) > > +{ > > + return read_cpuid(ID_CTR_EL0); > > +} > > Is this perhaps a carry-over from arch/arm? Abstracting out read_cpuid() > doesn't seem to buy anything here, just opencode the one-line assembly > in each. It doesn't buy much but it's more readable to use read_cpuid() in places like hw_breakpoint.c than open coding the assembly. I could get rid of the ID_* macros and just pass the register name direcly to read_cpuid(). > Might as well cleanup the naming a little too while you're at it, i.e. > read_cpu_id() and read_cpu_cachetype(). These were defined for convenience, a bit less typing. But they have the intended name. > > --- /dev/null > > +++ b/arch/arm64/mm/proc-syms.c ... > > +EXPORT_SYMBOL(__cpuc_flush_kern_all); > > +EXPORT_SYMBOL(__cpuc_flush_user_all); > > +EXPORT_SYMBOL(__cpuc_flush_user_range); > > +EXPORT_SYMBOL(__cpuc_coherent_kern_range); > > +EXPORT_SYMBOL(__cpuc_flush_dcache_area); > > See comment on other email about putting function pointers in a struct > instead. There is no need to support multiple CPU architectures with different implementations, so allowing these functions to be called without indirection is better. > > diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S > > new file mode 100644 > > index 0000000..453f517 > > --- /dev/null > > +++ b/arch/arm64/mm/proc.S > > @@ -0,0 +1,193 @@ > > + .section ".proc.info.init", #alloc, #execinstr > > + > > + .type __v8_proc_info, #object > > +__v8_proc_info: > > + .long 0x000f0000 // Required ID value > > + .long 0x000f0000 // Mask for ID > > + b __cpu_setup > > + nop > > + .quad cpu_name > > + .long 0 > > + .size __v8_proc_info, . - __v8_proc_info > > I know this is a carry-over from arch/arm, but how about moving this > to more of a C construct similar to arch/powerpc/kernel/cputable.c > instead? It's considerably easier to read that way, and it's convenient > to have the definitions all in one place, making it easier to share some > of the functions, etc. I can do this, it would be indeed cleaner.
On Wed, Aug 15, 2012 at 02:56:05PM +0100, Arnd Bergmann wrote: > On Tuesday 14 August 2012, Catalin Marinas wrote: > > --- /dev/null > > +++ b/arch/arm64/include/asm/procinfo.h ... > > +struct proc_info_list { > > + unsigned int cpu_val; > > + unsigned int cpu_mask; > > + unsigned long __cpu_flush; /* used by head.S */ > > + const char *cpu_name; > > +}; > > + > > +#else /* __KERNEL__ */ > > +#include <asm/elf.h> > > +#warning "Please include asm/elf.h instead" > > +#endif /* __KERNEL__ */ > > +#endif > > I think you forgot to remove this file when you removed MULTI_CPU. proc_info_list() structure is still used just for the CPU name and setup function (e.g. we need to apply errata workaround on a certain CPU). But as Olof suggested, I better move all this to a cputable.c file.
On Monday 20 August 2012, Catalin Marinas wrote: > > > --- /dev/null > > > +++ b/arch/arm64/mm/proc-syms.c > ... > > > +EXPORT_SYMBOL(__cpuc_flush_kern_all); > > > +EXPORT_SYMBOL(__cpuc_flush_user_all); > > > +EXPORT_SYMBOL(__cpuc_flush_user_range); > > > +EXPORT_SYMBOL(__cpuc_coherent_kern_range); > > > +EXPORT_SYMBOL(__cpuc_flush_dcache_area); > > > > See comment on other email about putting function pointers in a struct > > instead. > > There is no need to support multiple CPU architectures with different > implementations, so allowing these functions to be called without > indirection is better. What is the __cpuc prefix about then? Could you just drop it? Arnd
On Mon, Aug 20, 2012 at 09:47:07PM +0100, Arnd Bergmann wrote: > On Monday 20 August 2012, Catalin Marinas wrote: > > > > --- /dev/null > > > > +++ b/arch/arm64/mm/proc-syms.c > > ... > > > > +EXPORT_SYMBOL(__cpuc_flush_kern_all); > > > > +EXPORT_SYMBOL(__cpuc_flush_user_all); > > > > +EXPORT_SYMBOL(__cpuc_flush_user_range); > > > > +EXPORT_SYMBOL(__cpuc_coherent_kern_range); > > > > +EXPORT_SYMBOL(__cpuc_flush_dcache_area); > > > > > > See comment on other email about putting function pointers in a struct > > > instead. > > > > There is no need to support multiple CPU architectures with different > > implementations, so allowing these functions to be called without > > indirection is better. > > What is the __cpuc prefix about then? Could you just drop it? It can be dropped indeed.
On Wed, Aug 15, 2012 at 01:10:43AM +0100, Olof Johansson wrote: > On Tue, Aug 14, 2012 at 06:52:09PM +0100, Catalin Marinas wrote: > > +#ifndef __ASM_CPUTYPE_H > > +#define __ASM_CPUTYPE_H > > + > > +#define ID_MIDR_EL1 "midr_el1" > > +#define ID_CTR_EL0 "ctr_el0" > > + > > +#define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" > > +#define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" > > +#define ID_AA64AFR0_EL1 "id_aa64afr0_el1" > > +#define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" > > +#define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" > > + > > +#define read_cpuid(reg) ({ \ > > + u64 __val; \ > > + asm("mrs %0, " reg : "=r" (__val)); \ > > + __val; \ > > +}) > > + > > +/* > > + * The CPU ID never changes at run time, so we might as well tell the > > + * compiler that it's constant. Use this function to read the CPU ID > > + * rather than directly reading processor_id or read_cpuid() directly. > > + */ > > +static inline u32 __attribute_const__ read_cpuid_id(void) > > +{ > > + return read_cpuid(ID_MIDR_EL1); > > +} > > + > > +static inline u32 __attribute_const__ read_cpuid_cachetype(void) > > +{ > > + return read_cpuid(ID_CTR_EL0); > > +} > > Is this perhaps a carry-over from arch/arm? Abstracting out read_cpuid() > doesn't seem to buy anything here, just opencode the one-line assembly > in each. read_cpuid() is called from several other files under arch/arm64 and also used in expressions, so it's a good abstraction. > > --- /dev/null > > +++ b/arch/arm64/mm/proc.S > > @@ -0,0 +1,193 @@ > > + .section ".proc.info.init", #alloc, #execinstr > > + > > + .type __v8_proc_info, #object > > +__v8_proc_info: > > + .long 0x000f0000 // Required ID value > > + .long 0x000f0000 // Mask for ID > > + b __cpu_setup > > + nop > > + .quad cpu_name > > + .long 0 > > + .size __v8_proc_info, . - __v8_proc_info > > I know this is a carry-over from arch/arm, but how about moving this > to more of a C construct similar to arch/powerpc/kernel/cputable.c > instead? It's considerably easier to read that way, and it's convenient > to have the definitions all in one place, making it easier to share some > of the functions, etc. Done in version 3. It's easier to read :).
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h new file mode 100644 index 0000000..ef54125 --- /dev/null +++ b/arch/arm64/include/asm/cputype.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_CPUTYPE_H +#define __ASM_CPUTYPE_H + +#define ID_MIDR_EL1 "midr_el1" +#define ID_CTR_EL0 "ctr_el0" + +#define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" +#define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" +#define ID_AA64AFR0_EL1 "id_aa64afr0_el1" +#define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" +#define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" + +#define read_cpuid(reg) ({ \ + u64 __val; \ + asm("mrs %0, " reg : "=r" (__val)); \ + __val; \ +}) + +/* + * The CPU ID never changes at run time, so we might as well tell the + * compiler that it's constant. Use this function to read the CPU ID + * rather than directly reading processor_id or read_cpuid() directly. + */ +static inline u32 __attribute_const__ read_cpuid_id(void) +{ + return read_cpuid(ID_MIDR_EL1); +} + +static inline u32 __attribute_const__ read_cpuid_cachetype(void) +{ + return read_cpuid(ID_CTR_EL0); +} + +#endif diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h new file mode 100644 index 0000000..520331b --- /dev/null +++ b/arch/arm64/include/asm/proc-fns.h @@ -0,0 +1,51 @@ +/* + * Based on arch/arm/include/asm/proc-fns.h + * + * Copyright (C) 1997-1999 Russell King + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_PROCFNS_H +#define __ASM_PROCFNS_H + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +#include <asm/page.h> + +struct mm_struct; + +extern void cpu_proc_init(void); +extern void cpu_proc_fin(void); +extern void cpu_do_idle(void); +extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); +extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); + +#include <asm/memory.h> + +#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) + +#define cpu_get_pgd() \ +({ \ + unsigned long pg; \ + asm("mrs %0, ttbr0_el1\n" \ + : "=r" (pg)); \ + pg &= ~0xffff000000003ffful; \ + (pgd_t *)phys_to_virt(pg); \ +}) + +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* __ASM_PROCFNS_H */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h new file mode 100644 index 0000000..ebf2b22 --- /dev/null +++ b/arch/arm64/include/asm/processor.h @@ -0,0 +1,174 @@ +/* + * Based on arch/arm/include/asm/processor.h + * + * Copyright (C) 1995-1999 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_PROCESSOR_H +#define __ASM_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#ifdef __KERNEL__ + +#include <linux/string.h> + +#include <asm/fpsimd.h> +#include <asm/hw_breakpoint.h> +#include <asm/ptrace.h> +#include <asm/types.h> + +#ifdef __KERNEL__ +#define STACK_TOP_MAX TASK_SIZE_64 +#ifdef CONFIG_AARCH32_EMULATION +#define AARCH32_VECTORS_BASE 0xffff0000 +#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ + AARCH32_VECTORS_BASE : STACK_TOP_MAX) +#else +#define STACK_TOP STACK_TOP_MAX +#endif /* CONFIG_AARCH32_EMULATION */ +#endif /* __KERNEL__ */ + +struct debug_info { + /* Have we suspended stepping by a debugger? */ + int suspended_step; + /* Allow breakpoints and watchpoints to be disabled for this thread. */ + int bps_disabled; + int wps_disabled; + /* Hardware breakpoints pinned to this task. */ + struct perf_event *hbp[ARM_MAX_HBP_SLOTS]; +}; + +struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +struct thread_struct { + struct cpu_context cpu_context; /* cpu context */ + unsigned long tp_value; + struct fpsimd_state fpsimd_state; + unsigned long fault_address; /* fault info */ + struct debug_info debug; /* debugging */ +}; + +#define INIT_THREAD { } + +static inline void start_thread_common(struct pt_regs *regs, unsigned long pc) +{ + memset(regs, 0, sizeof(*regs)); + regs->syscallno = ~0UL; + regs->pc = pc; +} + +static inline void start_thread(struct pt_regs *regs, unsigned long pc, + unsigned long sp) +{ + unsigned long *stack = (unsigned long *)sp; + + start_thread_common(regs, pc); + regs->pstate = PSR_MODE_EL0t; + regs->sp = sp; + regs->regs[2] = stack[2]; /* x2 (envp) */ + regs->regs[1] = stack[1]; /* x1 (argv) */ + regs->regs[0] = stack[0]; /* x0 (argc) */ +} + +#ifdef CONFIG_AARCH32_EMULATION +static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc, + unsigned long sp) +{ + unsigned int *stack = (unsigned int *)sp; + + start_thread_common(regs, pc); + regs->pstate = COMPAT_PSR_MODE_USR; + if (pc & 1) + regs->pstate |= COMPAT_PSR_T_BIT; + regs->compat_sp = sp; + regs->regs[2] = stack[2]; /* x2 (envp) */ + regs->regs[1] = stack[1]; /* x1 (argv) */ + regs->regs[0] = stack[0]; /* x0 (argc) */ +} +#endif + +/* Forward declaration, a strange C thing */ +struct task_struct; + +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +unsigned long get_wchan(struct task_struct *p); + +#define cpu_relax() barrier() + +/* Thread switching */ +extern struct task_struct *cpu_switch_to(struct task_struct *prev, + struct task_struct *next); + +/* + * Create a new kernel thread + */ +extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); + +#define task_pt_regs(p) \ + ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) + +#define KSTK_EIP(tsk) task_pt_regs(tsk)->pc +#define KSTK_ESP(tsk) task_pt_regs(tsk)->sp + +/* + * Prefetching support + */ +#define ARCH_HAS_PREFETCH +static inline void prefetch(const void *ptr) +{ + asm volatile("prfm pldl1keep, %a0\n" : : "p" (ptr)); +} + +#define ARCH_HAS_PREFETCHW +static inline void prefetchw(const void *ptr) +{ + asm volatile("prfm pstl1keep, %a0\n" : : "p" (ptr)); +} + +#define ARCH_HAS_SPINLOCK_PREFETCH +static inline void spin_lock_prefetch(const void *x) +{ + prefetchw(x); +} + +#define HAVE_ARCH_PICK_MMAP_LAYOUT + +#endif + +#endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/include/asm/procinfo.h b/arch/arm64/include/asm/procinfo.h new file mode 100644 index 0000000..81fece9 --- /dev/null +++ b/arch/arm64/include/asm/procinfo.h @@ -0,0 +1,44 @@ +/* + * Based on arch/arm/include/asm/procinfo.h + * + * Copyright (C) 1996-1999 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef __ASM_PROCINFO_H +#define __ASM_PROCINFO_H + +#ifdef __KERNEL__ + +/* + * Note! struct processor is always defined if we're + * using MULTI_CPU, otherwise this entry is unused, + * but still exists. + * + * NOTE! The following structure is defined by assembly + * language, NOT C code. For more information, check: + * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S + */ +struct proc_info_list { + unsigned int cpu_val; + unsigned int cpu_mask; + unsigned long __cpu_flush; /* used by head.S */ + const char *cpu_name; +}; + +#else /* __KERNEL__ */ +#include <asm/elf.h> +#warning "Please include asm/elf.h instead" +#endif /* __KERNEL__ */ +#endif diff --git a/arch/arm64/mm/proc-syms.c b/arch/arm64/mm/proc-syms.c new file mode 100644 index 0000000..2d99ef9 --- /dev/null +++ b/arch/arm64/mm/proc-syms.c @@ -0,0 +1,31 @@ +/* + * Based on arch/arm/mm/proc-syms.c + * + * Copyright (C) 2000-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/export.h> +#include <linux/mm.h> + +#include <asm/cacheflush.h> +#include <asm/proc-fns.h> +#include <asm/tlbflush.h> +#include <asm/page.h> + +EXPORT_SYMBOL(__cpuc_flush_kern_all); +EXPORT_SYMBOL(__cpuc_flush_user_all); +EXPORT_SYMBOL(__cpuc_flush_user_range); +EXPORT_SYMBOL(__cpuc_coherent_kern_range); +EXPORT_SYMBOL(__cpuc_flush_dcache_area); diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S new file mode 100644 index 0000000..453f517 --- /dev/null +++ b/arch/arm64/mm/proc.S @@ -0,0 +1,193 @@ +/* + * Based on arch/arm/mm/proc.S + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * Author: Catalin Marinas <catalin.marinas@arm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/asm-offsets.h> +#include <asm/hwcap.h> +#include <asm/pgtable-hwdef.h> +#include <asm/pgtable.h> + +#include "proc-macros.S" + +#ifndef CONFIG_SMP +/* PTWs cacheable, inner/outer WBWA not shareable */ +#define TCR_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA +#else +/* PTWs cacheable, inner/outer WBWA shareable */ +#define TCR_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED +#endif + +#define MAIR(attr, mt) ((attr) << ((mt) * 8)) + +ENTRY(cpu_proc_init) + ret +ENDPROC(cpu_proc_init) + +ENTRY(cpu_proc_fin) + ret +ENDPROC(cpu_proc_fin) + +/* + * cpu_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the same state + * as it would be if it had been reset, and branch to what would be the + * reset vector. It must be executed with the flat identity mapping. + * + * - loc - location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_reset) + mrs x1, sctlr_el1 + bic x1, x1, #1 + msr sctlr_el1, x1 // disable the MMU + isb + ret x0 +ENDPROC(cpu_reset) + +/* + * cpu_do_idle() + * + * Idle the processor (wait for interrupt). + */ +ENTRY(cpu_do_idle) + dsb sy // WFI may enter a low-power mode + wfi + ret +ENDPROC(cpu_do_idle) + +/* + * cpu_switch_mm(pgd_phys, tsk) + * + * Set the translation table base pointer to be pgd_phys. + * + * - pgd_phys - physical address of new TTB + */ +ENTRY(cpu_do_switch_mm) + mmid w1, x1 // get mm->context.id + bfi x0, x1, #48, #16 // set the ASID + msr ttbr0_el1, x0 // set TTBR0 + isb + ret +ENDPROC(cpu_do_switch_mm) + +cpu_name: + .ascii "AArch64 Processor" + .align + + .section ".text.init", #alloc, #execinstr + +/* + * __cpu_setup + * + * Initialise the processor for turning the MMU on. Return in x0 the + * value of the SCTLR_EL1 register. + */ +__cpu_setup: +#ifdef CONFIG_SMP + /* TODO: only do this for certain CPUs */ + /* + * Enable SMP/nAMP mode. + */ + mrs x0, actlr_el1 + tbnz x0, #6, 1f // already enabled? + orr x0, x0, #1 << 6 + msr actlr_el1, x0 +1: +#endif + /* + * Preserve the link register across the function call. + */ + mov x28, lr + bl __cpuc_flush_dcache_all + mov lr, x28 + ic iallu // I+BTB cache invalidate + dsb sy + + mov x0, #3 << 20 + msr cpacr_el1, x0 // Enable FP/ASIMD + mov x0, #1 + msr oslar_el1, x0 // Set the debug OS lock + tlbi vmalle1is // invalidate I + D TLBs + /* + * Memory region attributes for LPAE: + * + * n = AttrIndx[2:0] + * n MAIR + * DEVICE_nGnRnE 000 00000000 + * DEVICE_nGnRE 001 00000100 + * DEVICE_GRE 010 00001100 + * NORMAL_NC 011 01000100 + * NORMAL 100 11111111 + */ + ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ + MAIR(0x04, MT_DEVICE_nGnRE) | \ + MAIR(0x0c, MT_DEVICE_GRE) | \ + MAIR(0x44, MT_NORMAL_NC) | \ + MAIR(0xff, MT_NORMAL) + msr mair_el1, x5 + /* + * Prepare SCTLR + */ + adr x5, crval + ldp w5, w6, [x5] + mrs x0, sctlr_el1 + bic x0, x0, x5 // clear bits + orr x0, x0, x6 // set bits + /* + * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for + * both user and kernel. + */ + ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \ + TCR_ASID16 | (1 << 31) +#ifdef CONFIG_ARM64_64K_PAGES + orr x10, x10, TCR_TG0_64K + orr x10, x10, TCR_TG1_64K +#endif + msr tcr_el1, x10 + ret // return to head.S +ENDPROC(__cpu_setup) + + /* + * n n T + * U E WT T UD US IHBS + * CE0 XWHW CZ ME TEEA S + * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM + * 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved + * .... .100 .... 01.1 11.1 ..01 0001 1101 < software settings + */ + .type crval, #object +crval: + .word 0x030802e2 // clear + .word 0x0405d11d // set + + .section ".proc.info.init", #alloc, #execinstr + + .type __v8_proc_info, #object +__v8_proc_info: + .long 0x000f0000 // Required ID value + .long 0x000f0000 // Mask for ID + b __cpu_setup + nop + .quad cpu_name + .long 0 + .size __v8_proc_info, . - __v8_proc_info