Commit 6dec8c15 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xtensa-20190917' of git://github.com/jcmvbkbc/linux-xtensa

Pull Xtensa updates from Max Filippov:

 - add support for xtensa call0 ABI in userspace

 - update xtensa virt board DTS for PCI root complex in KIO range

 - remove free_initrd_mem

* tag 'xtensa-20190917' of git://github.com/jcmvbkbc/linux-xtensa:
  xtensa: virt: move PCI root complex to KIO range
  xtensa: add support for call0 ABI in userspace
  xtensa: clean up PS_WOE_BIT usage
  xtensa: remove free_initrd_mem
parents d5902844 982792f4
...@@ -385,6 +385,54 @@ config FAST_SYSCALL_SPILL_REGISTERS ...@@ -385,6 +385,54 @@ config FAST_SYSCALL_SPILL_REGISTERS
If unsure, say N. 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 endmenu
config XTENSA_CALIBRATE_CCOUNT config XTENSA_CALIBRATE_CCOUNT
......
...@@ -52,12 +52,12 @@ pci { ...@@ -52,12 +52,12 @@ pci {
#size-cells = <2>; #size-cells = <2>;
#interrupt-cells = <0x1>; #interrupt-cells = <0x1>;
bus-range = <0x0 0x3f>; bus-range = <0x0 0x3e>;
reg = <0xc0000000 0x04000000>; reg = <0xf0100000 0x03f00000>;
// BUS_ADDRESS(3) CPU_PHYSICAL(1) SIZE(2) // BUS_ADDRESS(3) CPU_PHYSICAL(1) SIZE(2)
ranges = <0x01000000 0x0 0xc4000000 0xc4000000 0x0 0x04000000>, ranges = <0x01000000 0x0 0xf0000000 0xf0000000 0x0 0x00010000>,
<0x02000000 0x0 0xc8000000 0xc8000000 0x0 0x18000000>; <0x02000000 0x0 0xf4000000 0xf4000000 0x0 0x08000000>;
// PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(2) // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(2)
interrupt-map = < interrupt-map = <
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define IOADDR(x) (XCHAL_KIO_BYPASS_VADDR + (x)) #define IOADDR(x) (XCHAL_KIO_BYPASS_VADDR + (x))
#define IO_SPACE_LIMIT ~0 #define IO_SPACE_LIMIT ~0
#define PCI_IOBASE ((void __iomem *)XCHAL_KIO_BYPASS_VADDR)
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
......
...@@ -176,14 +176,21 @@ struct thread_struct { ...@@ -176,14 +176,21 @@ struct thread_struct {
/* /*
* Do necessary setup to start up a newly executed thread. * 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. * set_thread_state in signal.c depends on it.
*/ */
#define USER_PS_VALUE ((1 << PS_WOE_BIT) | \ #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) | \ (1 << PS_CALLINC_SHIFT) | \
(USER_RING << PS_RING_SHIFT) | \ (USER_RING << PS_RING_SHIFT) | \
(1 << PS_UM_BIT) | \ (1 << PS_UM_BIT) | \
(1 << PS_EXCM_BIT)) (1 << PS_EXCM_BIT))
#endif
/* Clearing a0 terminates the backtrace. */ /* Clearing a0 terminates the backtrace. */
#define start_thread(regs, new_pc, new_sp) \ #define start_thread(regs, new_pc, new_sp) \
......
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
/* PS register fields. */ /* PS register fields. */
#define PS_WOE_BIT 18 #define PS_WOE_BIT 18
#define PS_WOE_MASK 0x00040000
#define PS_CALLINC_SHIFT 16 #define PS_CALLINC_SHIFT 16
#define PS_CALLINC_MASK 0x00030000 #define PS_CALLINC_MASK 0x00030000
#define PS_OWB_SHIFT 8 #define PS_OWB_SHIFT 8
......
...@@ -414,7 +414,7 @@ common_exception: ...@@ -414,7 +414,7 @@ common_exception:
movi a3, LOCKLEVEL movi a3, LOCKLEVEL
.Lexception: .Lexception:
movi a0, 1 << PS_WOE_BIT movi a0, PS_WOE_MASK
or a3, a3, a0 or a3, a3, a0
#else #else
addi a2, a2, -EXCCAUSE_LEVEL1_INTERRUPT addi a2, a2, -EXCCAUSE_LEVEL1_INTERRUPT
...@@ -422,7 +422,7 @@ common_exception: ...@@ -422,7 +422,7 @@ common_exception:
extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH extui a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
# a3 = PS.INTLEVEL # a3 = PS.INTLEVEL
moveqz a3, a0, a2 # a3 = LOCKLEVEL iff interrupt moveqz a3, a0, a2 # a3 = LOCKLEVEL iff interrupt
movi a2, 1 << PS_WOE_BIT movi a2, PS_WOE_MASK
or a3, a3, a2 or a3, a3, a2
rsr a2, exccause rsr a2, exccause
#endif #endif
...@@ -922,7 +922,7 @@ ENTRY(unrecoverable_exception) ...@@ -922,7 +922,7 @@ ENTRY(unrecoverable_exception)
wsr a1, windowbase wsr a1, windowbase
rsync rsync
movi a1, (1 << PS_WOE_BIT) | LOCKLEVEL movi a1, PS_WOE_MASK | LOCKLEVEL
wsr a1, ps wsr a1, ps
rsync rsync
...@@ -1003,7 +1003,41 @@ ENTRY(fast_alloca) ...@@ -1003,7 +1003,41 @@ ENTRY(fast_alloca)
4: j _WindowUnderflow4 4: j _WindowUnderflow4
ENDPROC(fast_alloca) 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. * fast system calls.
* *
* WARNING: The kernel doesn't save the entire user context before * WARNING: The kernel doesn't save the entire user context before
...@@ -1359,7 +1393,7 @@ ENTRY(fast_syscall_spill_registers) ...@@ -1359,7 +1393,7 @@ ENTRY(fast_syscall_spill_registers)
rsr a3, excsave1 rsr a3, excsave1
l32i a1, a3, EXC_TABLE_KSTK l32i a1, a3, EXC_TABLE_KSTK
movi a4, (1 << PS_WOE_BIT) | LOCKLEVEL movi a4, PS_WOE_MASK | LOCKLEVEL
wsr a4, ps wsr a4, ps
rsync rsync
......
...@@ -193,7 +193,7 @@ ENTRY(_startup) ...@@ -193,7 +193,7 @@ ENTRY(_startup)
movi a1, start_info movi a1, start_info
l32i a1, a1, 0 l32i a1, a1, 0
movi a2, (1 << PS_WOE_BIT) | LOCKLEVEL movi a2, PS_WOE_MASK | LOCKLEVEL
# WOE=1, INTLEVEL=LOCKLEVEL, UM=0 # WOE=1, INTLEVEL=LOCKLEVEL, UM=0
wsr a2, ps # (enable reg-windows; progmode stack) wsr a2, ps # (enable reg-windows; progmode stack)
rsync rsync
......
...@@ -61,7 +61,6 @@ struct screen_info screen_info = { ...@@ -61,7 +61,6 @@ struct screen_info screen_info = {
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
extern unsigned long initrd_start; extern unsigned long initrd_start;
extern unsigned long initrd_end; extern unsigned long initrd_end;
int initrd_is_mapped = 0;
extern int initrd_below_start_ok; extern int initrd_below_start_ok;
#endif #endif
...@@ -332,13 +331,11 @@ void __init setup_arch(char **cmdline_p) ...@@ -332,13 +331,11 @@ void __init setup_arch(char **cmdline_p)
/* Reserve some memory regions */ /* Reserve some memory regions */
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start < initrd_end) { if (initrd_start < initrd_end &&
initrd_is_mapped = mem_reserve(__pa(initrd_start), !mem_reserve(__pa(initrd_start), __pa(initrd_end)))
__pa(initrd_end)) == 0;
initrd_below_start_ok = 1; initrd_below_start_ok = 1;
} else { else
initrd_start = 0; initrd_start = 0;
}
#endif #endif
mem_reserve(__pa(_stext), __pa(_end)); mem_reserve(__pa(_stext), __pa(_end));
......
...@@ -335,7 +335,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, ...@@ -335,7 +335,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
{ {
struct rt_sigframe *frame; struct rt_sigframe *frame;
int err = 0, sig = ksig->sig; int err = 0, sig = ksig->sig;
unsigned long sp, ra, tp; unsigned long sp, ra, tp, ps;
unsigned int base;
sp = regs->areg[1]; sp = regs->areg[1];
...@@ -385,17 +386,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set, ...@@ -385,17 +386,26 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
/* Set up registers for signal handler; preserve the threadptr */ /* Set up registers for signal handler; preserve the threadptr */
tp = regs->threadptr; tp = regs->threadptr;
ps = regs->ps;
start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler, start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler,
(unsigned long) frame); (unsigned long) frame);
/* Set up a stack frame for a call4 /* Set up a stack frame for a call4 if userspace uses windowed ABI */
* Note: PS.CALLINC is set to one by start_thread if (ps & PS_WOE_MASK) {
*/ base = 4;
regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; regs->areg[base] =
regs->areg[6] = (unsigned long) sig; (((unsigned long) ra) & 0x3fffffff) | 0x40000000;
regs->areg[7] = (unsigned long) &frame->info; ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) |
regs->areg[8] = (unsigned long) &frame->uc; (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->threadptr = tp;
regs->ps = ps;
pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n", pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n",
current->comm, current->pid, sig, frame, regs->pc); current->comm, current->pid, sig, frame, regs->pc);
......
...@@ -44,6 +44,11 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth, ...@@ -44,6 +44,11 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data))
return; return;
if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) ||
(IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) &&
!(regs->ps & PS_WOE_MASK)))
return;
/* Two steps: /* Two steps:
* *
* 1. Look through the register window for the * 1. Look through the register window for the
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
extern void kernel_exception(void); extern void kernel_exception(void);
extern void user_exception(void); extern void user_exception(void);
extern void fast_illegal_instruction_user(void);
extern void fast_syscall_user(void); extern void fast_syscall_user(void);
extern void fast_alloca(void); extern void fast_alloca(void);
extern void fast_unaligned(void); extern void fast_unaligned(void);
...@@ -87,6 +88,9 @@ typedef struct { ...@@ -87,6 +88,9 @@ typedef struct {
static dispatch_init_table_t __initdata dispatch_init_table[] = { 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_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
{ EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user }, { EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user },
{ EXCCAUSE_SYSTEM_CALL, 0, system_call }, { EXCCAUSE_SYSTEM_CALL, 0, system_call },
......
...@@ -203,16 +203,6 @@ void __init mem_init(void) ...@@ -203,16 +203,6 @@ void __init mem_init(void)
(unsigned long)(__bss_stop - __bss_start) >> 10); (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) static void __init parse_memmap_one(char *p)
{ {
char *oldp; char *oldp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment