From f348f5c232408cb44451cc5ba52a4b326b6034da Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 24 Jul 2019 17:10:32 +0300 Subject: xtensa: remove free_initrd_mem The xtensa free_initrd_mem() verifies that initrd is mapped and then frees its memory using free_reserved_area(). The initrd is considered mapped when its memory was successfully reserved with mem_reserve(). Resetting initrd_start to 0 in case of mem_reserve() failure allows to switch to generic free_initrd_mem() implementation. Signed-off-by: Mike Rapoport Message-Id: <1563977432-8376-1-git-send-email-rppt@linux.ibm.com> Signed-off-by: Max Filippov --- arch/xtensa/kernel/setup.c | 9 +++------ arch/xtensa/mm/init.c | 10 ---------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 7c3106093c75..e0e1e1892b86 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -61,7 +61,6 @@ struct screen_info screen_info = { #ifdef CONFIG_BLK_DEV_INITRD extern unsigned long initrd_start; extern unsigned long initrd_end; -int initrd_is_mapped = 0; extern int initrd_below_start_ok; #endif @@ -332,13 +331,11 @@ void __init setup_arch(char **cmdline_p) /* Reserve some memory regions */ #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start < initrd_end) { - initrd_is_mapped = mem_reserve(__pa(initrd_start), - __pa(initrd_end)) == 0; + if (initrd_start < initrd_end && + !mem_reserve(__pa(initrd_start), __pa(initrd_end))) initrd_below_start_ok = 1; - } else { + else initrd_start = 0; - } #endif mem_reserve(__pa(_stext), __pa(_end)); diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 79467c749416..d898ed67d890 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -203,16 +203,6 @@ void __init mem_init(void) (unsigned long)(__bss_stop - __bss_start) >> 10); } -#ifdef CONFIG_BLK_DEV_INITRD -extern int initrd_is_mapped; - -void free_initrd_mem(unsigned long start, unsigned long end) -{ - if (initrd_is_mapped) - free_reserved_area((void *)start, (void *)end, -1, "initrd"); -} -#endif - static void __init parse_memmap_one(char *p) { char *oldp; -- cgit v1.2.3 From 9e1e41c44782741c727688a19e5624d039b0de7e Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 30 Aug 2019 11:16:06 -0700 Subject: xtensa: clean up PS_WOE_BIT usage PS_WOE_BIT is mainly used to generate PS.WOE mask in the code. Introduce PS_WOE_MASK macro and use it instead. Signed-off-by: Max Filippov --- arch/xtensa/include/asm/processor.h | 2 +- arch/xtensa/include/asm/regs.h | 1 + arch/xtensa/kernel/entry.S | 8 ++++---- arch/xtensa/kernel/head.S | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 19f6b54e358b..0b4efec9e19e 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -179,7 +179,7 @@ struct thread_struct { * Note: We set-up ps as if we did a call4 to the new pc. * set_thread_state in signal.c depends on it. */ -#define USER_PS_VALUE ((1 << PS_WOE_BIT) | \ +#define USER_PS_VALUE (PS_WOE_MASK | \ (1 << PS_CALLINC_SHIFT) | \ (USER_RING << PS_RING_SHIFT) | \ (1 << PS_UM_BIT) | \ diff --git a/arch/xtensa/include/asm/regs.h b/arch/xtensa/include/asm/regs.h index 477594e5817f..ce184e7dee91 100644 --- a/arch/xtensa/include/asm/regs.h +++ b/arch/xtensa/include/asm/regs.h @@ -81,6 +81,7 @@ /* PS register fields. */ #define PS_WOE_BIT 18 +#define PS_WOE_MASK 0x00040000 #define PS_CALLINC_SHIFT 16 #define PS_CALLINC_MASK 0x00030000 #define PS_OWB_SHIFT 8 diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 183fa8e0bb5b..9afe8f612f23 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -414,7 +414,7 @@ common_exception: movi a3, LOCKLEVEL .Lexception: - movi a0, 1 << PS_WOE_BIT + movi a0, PS_WOE_MASK or a3, a3, a0 #else addi a2, a2, -EXCCAUSE_LEVEL1_INTERRUPT @@ -422,7 +422,7 @@ common_exception: extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH # a3 = PS.INTLEVEL moveqz a3, a0, a2 # a3 = LOCKLEVEL iff interrupt - movi a2, 1 << PS_WOE_BIT + movi a2, PS_WOE_MASK or a3, a3, a2 rsr a2, exccause #endif @@ -922,7 +922,7 @@ ENTRY(unrecoverable_exception) wsr a1, windowbase rsync - movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a1, PS_WOE_MASK | LOCKLEVEL wsr a1, ps rsync @@ -1359,7 +1359,7 @@ ENTRY(fast_syscall_spill_registers) rsr a3, excsave1 l32i a1, a3, EXC_TABLE_KSTK - movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a4, PS_WOE_MASK | LOCKLEVEL wsr a4, ps rsync diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index 7f009719304e..4ae998b5a348 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -193,7 +193,7 @@ ENTRY(_startup) movi a1, start_info l32i a1, a1, 0 - movi a2, (1 << PS_WOE_BIT) | LOCKLEVEL + movi a2, PS_WOE_MASK | LOCKLEVEL # WOE=1, INTLEVEL=LOCKLEVEL, UM=0 wsr a2, ps # (enable reg-windows; progmode stack) rsync -- cgit v1.2.3 From 09f8a6db20e6ed8eab1b2b23d09d2458f6e15062 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 12 Jan 2015 09:44:44 +0300 Subject: xtensa: add support for call0 ABI in userspace Provide a Kconfig choice to select whether only the default ABI, only call0 ABI or both are supported. The default for XEA2 is windowed, but it may change for XEA3. Call0 only runs userspace with PS.WOE disabled. Supporting both windowed and call0 ABIs is tricky, as there's no indication in the ELF binaries which ABI they use. So it is done by probing: each process is started with PS.WOE disabled, but the handler of an illegal instruction exception taken with PS.WOE retries faulting instruction after enabling PS.WOE. It must happen before any signal is delivered to the process, otherwise it may be delivered incorrectly. Signed-off-by: Max Filippov --- arch/xtensa/Kconfig | 48 +++++++++++++++++++++++++++++++++++++ arch/xtensa/include/asm/processor.h | 9 ++++++- arch/xtensa/kernel/entry.S | 34 ++++++++++++++++++++++++++ arch/xtensa/kernel/signal.c | 26 +++++++++++++------- arch/xtensa/kernel/stacktrace.c | 5 ++++ arch/xtensa/kernel/traps.c | 4 ++++ 6 files changed, 117 insertions(+), 9 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index ebc135bda921..fb64469ca8f0 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -385,6 +385,54 @@ config FAST_SYSCALL_SPILL_REGISTERS If unsure, say N. +config USER_ABI_CALL0 + bool + +choice + prompt "Userspace ABI" + default USER_ABI_DEFAULT + help + Select supported userspace ABI. + + If unsure, choose the default ABI. + +config USER_ABI_DEFAULT + bool "Default ABI only" + help + Assume default userspace ABI. For XEA2 cores it is windowed ABI. + call0 ABI binaries may be run on such kernel, but signal delivery + will not work correctly for them. + +config USER_ABI_CALL0_ONLY + bool "Call0 ABI only" + select USER_ABI_CALL0 + help + Select this option to support only call0 ABI in userspace. + Windowed ABI binaries will crash with a segfault caused by + an illegal instruction exception on the first 'entry' opcode. + + Choose this option if you're planning to run only user code + built with call0 ABI. + +config USER_ABI_CALL0_PROBE + bool "Support both windowed and call0 ABI by probing" + select USER_ABI_CALL0 + help + Select this option to support both windowed and call0 userspace + ABIs. When enabled all processes are started with PS.WOE disabled + and a fast user exception handler for an illegal instruction is + used to turn on PS.WOE bit on the first 'entry' opcode executed by + the userspace. + + This option should be enabled for the kernel that must support + both call0 and windowed ABIs in userspace at the same time. + + Note that Xtensa ISA does not guarantee that entry opcode will + raise an illegal instruction exception on cores with XEA2 when + PS.WOE is disabled, check whether the target core supports it. + +endchoice + endmenu config XTENSA_CALIBRATE_CCOUNT diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 0b4efec9e19e..7495520d7a3e 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h @@ -176,14 +176,21 @@ struct thread_struct { /* * Do necessary setup to start up a newly executed thread. - * Note: We set-up ps as if we did a call4 to the new pc. + * Note: When windowed ABI is used for userspace we set-up ps + * as if we did a call4 to the new pc. * set_thread_state in signal.c depends on it. */ +#if IS_ENABLED(CONFIG_USER_ABI_CALL0) +#define USER_PS_VALUE ((USER_RING << PS_RING_SHIFT) | \ + (1 << PS_UM_BIT) | \ + (1 << PS_EXCM_BIT)) +#else #define USER_PS_VALUE (PS_WOE_MASK | \ (1 << PS_CALLINC_SHIFT) | \ (USER_RING << PS_RING_SHIFT) | \ (1 << PS_UM_BIT) | \ (1 << PS_EXCM_BIT)) +#endif /* Clearing a0 terminates the backtrace. */ #define start_thread(regs, new_pc, new_sp) \ diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 9afe8f612f23..9e3676879168 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -1003,7 +1003,41 @@ ENTRY(fast_alloca) 4: j _WindowUnderflow4 ENDPROC(fast_alloca) +#ifdef CONFIG_USER_ABI_CALL0_PROBE /* + * fast illegal instruction handler. + * + * This is used to fix up user PS.WOE on the exception caused + * by the first opcode related to register window. If PS.WOE is + * already set it goes directly to the common user exception handler. + * + * Entry condition: + * + * a0: trashed, original value saved on stack (PT_AREG0) + * a1: a1 + * a2: new stack pointer, original in DEPC + * a3: a3 + * depc: a2, original value saved on stack (PT_DEPC) + * excsave_1: dispatch table + */ + +ENTRY(fast_illegal_instruction_user) + + rsr a0, ps + bbsi.l a0, PS_WOE_BIT, user_exception + s32i a3, a2, PT_AREG3 + movi a3, PS_WOE_MASK + or a0, a0, a3 + wsr a0, ps + l32i a3, a2, PT_AREG3 + l32i a0, a2, PT_AREG0 + rsr a2, depc + rfe + +ENDPROC(fast_illegal_instruction_user) +#endif + + /* * fast system calls. * * WARNING: The kernel doesn't save the entire user context before diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index fbedf2aba09d..dae83cddd6ca 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -335,7 +335,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, { struct rt_sigframe *frame; int err = 0, sig = ksig->sig; - unsigned long sp, ra, tp; + unsigned long sp, ra, tp, ps; + unsigned int base; sp = regs->areg[1]; @@ -385,17 +386,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, /* Set up registers for signal handler; preserve the threadptr */ tp = regs->threadptr; + ps = regs->ps; start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler, (unsigned long) frame); - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; - regs->areg[6] = (unsigned long) sig; - regs->areg[7] = (unsigned long) &frame->info; - regs->areg[8] = (unsigned long) &frame->uc; + /* Set up a stack frame for a call4 if userspace uses windowed ABI */ + if (ps & PS_WOE_MASK) { + base = 4; + regs->areg[base] = + (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) | + (1 << PS_CALLINC_SHIFT); + } else { + base = 0; + regs->areg[base] = (unsigned long) ra; + } + regs->areg[base + 2] = (unsigned long) sig; + regs->areg[base + 3] = (unsigned long) &frame->info; + regs->areg[base + 4] = (unsigned long) &frame->uc; regs->threadptr = tp; + regs->ps = ps; pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n", current->comm, current->pid, sig, frame, regs->pc); diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c index b9f82510c650..c822abb93d20 100644 --- a/arch/xtensa/kernel/stacktrace.c +++ b/arch/xtensa/kernel/stacktrace.c @@ -44,6 +44,11 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth, if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) return; + if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) || + (IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) && + !(regs->ps & PS_WOE_MASK))) + return; + /* Two steps: * * 1. Look through the register window for the diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index f060348c1b23..4a6c495ce9b6 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -51,6 +51,7 @@ extern void kernel_exception(void); extern void user_exception(void); +extern void fast_illegal_instruction_user(void); extern void fast_syscall_user(void); extern void fast_alloca(void); extern void fast_unaligned(void); @@ -87,6 +88,9 @@ typedef struct { static dispatch_init_table_t __initdata dispatch_init_table[] = { +#ifdef CONFIG_USER_ABI_CALL0_PROBE +{ EXCCAUSE_ILLEGAL_INSTRUCTION, USER, fast_illegal_instruction_user }, +#endif { EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction}, { EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user }, { EXCCAUSE_SYSTEM_CALL, 0, system_call }, -- cgit v1.2.3 From 982792f45894878b9ec13df81e6e02209b34cb11 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 1 Sep 2019 23:55:49 -0700 Subject: xtensa: virt: move PCI root complex to KIO range Move PCI configuration space, MMIO and memory to the KIO range to free vmalloc area and use static TLB to access them. Move MMIO to the beginning of KIO and define PCI_IOBASE as XCHAL_KIO_BYPASS_VADDR to match it. Reduce number of supported PCI buses to 0x3f so that ECAM window fits into first 64MB of the KIO. Reduce size of the PCI memory window to 128MB so that it fits into KIO. Signed-off-by: Max Filippov --- arch/xtensa/boot/dts/virt.dts | 8 ++++---- arch/xtensa/include/asm/io.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/xtensa/boot/dts/virt.dts b/arch/xtensa/boot/dts/virt.dts index 6aecbc0f3549..a9dcd87b6eb1 100644 --- a/arch/xtensa/boot/dts/virt.dts +++ b/arch/xtensa/boot/dts/virt.dts @@ -52,12 +52,12 @@ #size-cells = <2>; #interrupt-cells = <0x1>; - bus-range = <0x0 0x3f>; - reg = <0xc0000000 0x04000000>; + bus-range = <0x0 0x3e>; + reg = <0xf0100000 0x03f00000>; // BUS_ADDRESS(3) CPU_PHYSICAL(1) SIZE(2) - ranges = <0x01000000 0x0 0xc4000000 0xc4000000 0x0 0x04000000>, - <0x02000000 0x0 0xc8000000 0xc8000000 0x0 0x18000000>; + ranges = <0x01000000 0x0 0xf0000000 0xf0000000 0x0 0x00010000>, + <0x02000000 0x0 0xf4000000 0xf4000000 0x0 0x08000000>; // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(2) interrupt-map = < diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h index da3e783f896b..988e08530a5c 100644 --- a/arch/xtensa/include/asm/io.h +++ b/arch/xtensa/include/asm/io.h @@ -21,6 +21,7 @@ #define IOADDR(x) (XCHAL_KIO_BYPASS_VADDR + (x)) #define IO_SPACE_LIMIT ~0 +#define PCI_IOBASE ((void __iomem *)XCHAL_KIO_BYPASS_VADDR) #ifdef CONFIG_MMU -- cgit v1.2.3