Browse Source

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

Pull Xtensa updates from Max Filippov:

 - clearly mark references to spilled register locations with SPILL_SLOT
   macros

 - clean up xtensa ptrace: use generic tracehooks, move internal kernel
   definitions from uapi/asm to asm, make locally-used functions static,
   fix code style and alignment

 - use command line parameters passed to ISS as kernel command line.

* tag 'xtensa-20170507' of git://github.com/jcmvbkbc/linux-xtensa:
  xtensa: clean up access to spilled registers locations
  xtensa: use generic tracehooks
  xtensa: move internal ptrace definitions from uapi/asm to asm
  xtensa: clean up xtensa/kernel/ptrace.c
  xtensa: drop unused fast_io_protect function
  xtensa: use ITLB_HIT_BIT instead of hardcoded number
  xtensa: ISS: update kernel command line in platform_setup
  xtensa: ISS: add argc/argv simcall definitions
  xtensa: ISS: cleanup setup.c
Linus Torvalds 8 years ago
parent
commit
d9dc089583

+ 15 - 0
arch/xtensa/include/asm/processor.h

@@ -113,6 +113,21 @@
  */
 #define MAKE_PC_FROM_RA(ra,sp)    (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
 
+/* Spill slot location for the register reg in the spill area under the stack
+ * pointer sp. reg must be in the range [0..4).
+ */
+#define SPILL_SLOT(sp, reg) (*(((unsigned long *)(sp)) - 4 + (reg)))
+
+/* Spill slot location for the register reg in the spill area under the stack
+ * pointer sp for the call8. reg must be in the range [4..8).
+ */
+#define SPILL_SLOT_CALL8(sp, reg) (*(((unsigned long *)(sp)) - 12 + (reg)))
+
+/* Spill slot location for the register reg in the spill area under the stack
+ * pointer sp for the call12. reg must be in the range [4..12).
+ */
+#define SPILL_SLOT_CALL12(sp, reg) (*(((unsigned long *)(sp)) - 16 + (reg)))
+
 typedef struct {
 	unsigned long seg;
 } mm_segment_t;

+ 39 - 0
arch/xtensa/include/asm/ptrace.h

@@ -12,6 +12,45 @@
 
 #include <uapi/asm/ptrace.h>
 
+/*
+ * Kernel stack
+ *
+ *		+-----------------------+  -------- STACK_SIZE
+ *		|     register file     |  |
+ *		+-----------------------+  |
+ *		|    struct pt_regs     |  |
+ *		+-----------------------+  | ------ PT_REGS_OFFSET
+ * double	:  16 bytes spill area  :  |  ^
+ * excetion	:- - - - - - - - - - - -:  |  |
+ * frame	:    struct pt_regs     :  |  |
+ *		:- - - - - - - - - - - -:  |  |
+ *		|                       |  |  |
+ *		|     memory stack      |  |  |
+ *		|                       |  |  |
+ *		~                       ~  ~  ~
+ *		~                       ~  ~  ~
+ *		|                       |  |  |
+ *		|                       |  |  |
+ *		+-----------------------+  |  | --- STACK_BIAS
+ *		|  struct task_struct   |  |  |  ^
+ *  current --> +-----------------------+  |  |  |
+ *		|  struct thread_info   |  |  |  |
+ *		+-----------------------+ --------
+ */
+
+#define KERNEL_STACK_SIZE (2 * PAGE_SIZE)
+
+/*  Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables). */
+
+#define EXC_TABLE_KSTK		0x004	/* Kernel Stack */
+#define EXC_TABLE_DOUBLE_SAVE	0x008	/* Double exception save area for a0 */
+#define EXC_TABLE_FIXUP		0x00c	/* Fixup handler */
+#define EXC_TABLE_PARAM		0x010	/* For passing a parameter to fixup */
+#define EXC_TABLE_SYSCALL_SAVE	0x014	/* For fast syscall handler */
+#define EXC_TABLE_FAST_USER	0x100	/* Fast user exception handler */
+#define EXC_TABLE_FAST_KERNEL	0x200	/* Fast kernel exception handler */
+#define EXC_TABLE_DEFAULT	0x300	/* Default C-Handler */
+#define EXC_TABLE_SIZE		0x400
 
 #ifndef __ASSEMBLY__
 

+ 0 - 40
arch/xtensa/include/uapi/asm/ptrace.h

@@ -11,46 +11,6 @@
 #ifndef _UAPI_XTENSA_PTRACE_H
 #define _UAPI_XTENSA_PTRACE_H
 
-/*
- * Kernel stack
- *
- * 		+-----------------------+  -------- STACK_SIZE
- * 		|     register file     |  |
- * 		+-----------------------+  |
- * 		|    struct pt_regs     |  |
- * 		+-----------------------+  | ------ PT_REGS_OFFSET
- * double 	:  16 bytes spill area  :  |  ^
- * excetion 	:- - - - - - - - - - - -:  |  |
- * frame	:    struct pt_regs     :  |  |
- * 		:- - - - - - - - - - - -:  |  |
- * 		|                       |  |  |
- * 		|     memory stack      |  |  |
- * 		|                       |  |  |
- * 		~                       ~  ~  ~
- * 		~                       ~  ~  ~
- * 		|                       |  |  |
- * 		|                       |  |  |
- * 		+-----------------------+  |  | --- STACK_BIAS
- * 		|  struct task_struct   |  |  |  ^
- *  current --> +-----------------------+  |  |  |
- * 		|  struct thread_info   |  |  |  |
- *		+-----------------------+ --------
- */
-
-#define KERNEL_STACK_SIZE (2 * PAGE_SIZE)
-
-/*  Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables). */
-
-#define EXC_TABLE_KSTK		0x004	/* Kernel Stack */
-#define EXC_TABLE_DOUBLE_SAVE	0x008	/* Double exception save area for a0 */
-#define EXC_TABLE_FIXUP		0x00c	/* Fixup handler */
-#define EXC_TABLE_PARAM		0x010	/* For passing a parameter to fixup */
-#define EXC_TABLE_SYSCALL_SAVE	0x014	/* For fast syscall handler */
-#define EXC_TABLE_FAST_USER	0x100	/* Fast user exception handler */
-#define EXC_TABLE_FAST_KERNEL	0x200	/* Fast kernel exception handler */
-#define EXC_TABLE_DEFAULT	0x300	/* Default C-Handler */
-#define EXC_TABLE_SIZE		0x400
-
 /* Registers used by strace */
 
 #define REG_A_BASE	0x0000

+ 0 - 24
arch/xtensa/kernel/coprocessor.S

@@ -26,30 +26,6 @@
 #include <asm/signal.h>
 #include <asm/tlbflush.h>
 
-/*
- * 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
- *
- *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
- *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
- */
-
-/* IO protection is currently unsupported. */
-
-ENTRY(fast_io_protect)
-
-	wsr	a0, excsave1
-	movi	a0, unrecoverable_exception
-	callx0	a0
-
-ENDPROC(fast_io_protect)
-
 #if XTENSA_HAVE_COPROCESSORS
 
 /*

+ 2 - 1
arch/xtensa/kernel/entry.S

@@ -1899,10 +1899,11 @@ ENTRY(system_call)
 	movi	a4, do_syscall_trace_enter
 	s32i	a3, a2, PT_SYSCALL
 	callx4	a4
+	mov	a3, a6
 
 	/* syscall = sys_call_table[syscall_nr] */
 
-	movi	a4, sys_call_table;
+	movi	a4, sys_call_table
 	movi	a5, __NR_syscall_count
 	movi	a6, -ENOSYS
 	bgeu	a3, a5, 1f

+ 4 - 4
arch/xtensa/kernel/process.c

@@ -204,8 +204,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
 #endif
 
 	/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
-	*((int*)childregs - 3) = (unsigned long)childregs;
-	*((int*)childregs - 4) = 0;
+	SPILL_SLOT(childregs, 1) = (unsigned long)childregs;
+	SPILL_SLOT(childregs, 0) = 0;
 
 	p->thread.sp = (unsigned long)childregs;
 
@@ -266,8 +266,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
 		/* pass parameters to ret_from_kernel_thread:
 		 * a2 = thread_fn, a3 = thread_fn arg
 		 */
-		*((int *)childregs - 1) = thread_fn_arg;
-		*((int *)childregs - 2) = usp_thread_fn;
+		SPILL_SLOT(childregs, 3) = thread_fn_arg;
+		SPILL_SLOT(childregs, 2) = usp_thread_fn;
 
 		/* Childregs are only used when we're going to userspace
 		 * in which case start_thread will set them up.

+ 77 - 93
arch/xtensa/kernel/ptrace.c

@@ -1,4 +1,3 @@
-// TODO some minor issues
 /*
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -24,13 +23,14 @@
 #include <linux/security.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
+#include <linux/tracehook.h>
+#include <linux/uaccess.h>
 
 #include <asm/coprocessor.h>
 #include <asm/elf.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
-#include <linux/uaccess.h>
 
 
 void user_enable_single_step(struct task_struct *child)
@@ -52,7 +52,7 @@ void ptrace_disable(struct task_struct *child)
 	/* Nothing to do.. */
 }
 
-int ptrace_getregs(struct task_struct *child, void __user *uregs)
+static int ptrace_getregs(struct task_struct *child, void __user *uregs)
 {
 	struct pt_regs *regs = task_pt_regs(child);
 	xtensa_gregset_t __user *gregset = uregs;
@@ -73,12 +73,12 @@ int ptrace_getregs(struct task_struct *child, void __user *uregs)
 
 	for (i = 0; i < XCHAL_NUM_AREGS; i++)
 		__put_user(regs->areg[i],
-				gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS));
+			   gregset->a + ((wb * 4 + i) % XCHAL_NUM_AREGS));
 
 	return 0;
 }
 
-int ptrace_setregs(struct task_struct *child, void __user *uregs)
+static int ptrace_setregs(struct task_struct *child, void __user *uregs)
 {
 	struct pt_regs *regs = task_pt_regs(child);
 	xtensa_gregset_t *gregset = uregs;
@@ -107,7 +107,7 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
 		unsigned long rotws, wmask;
 
 		rotws = (((ws | (ws << WSBITS)) >> wb) &
-				((1 << WSBITS) - 1)) & ~1;
+			 ((1 << WSBITS) - 1)) & ~1;
 		wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
 			(rotws & 0xF) | 1;
 		regs->windowbase = wb;
@@ -115,19 +115,19 @@ int ptrace_setregs(struct task_struct *child, void __user *uregs)
 		regs->wmask = wmask;
 	}
 
-	if (wb != 0 &&  __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
-				gregset->a, wb * 16))
+	if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
+					gregset->a, wb * 16))
 		return -EFAULT;
 
 	if (__copy_from_user(regs->areg, gregset->a + wb * 4,
-				(WSBITS - wb) * 16))
+			     (WSBITS - wb) * 16))
 		return -EFAULT;
 
 	return 0;
 }
 
 
-int ptrace_getxregs(struct task_struct *child, void __user *uregs)
+static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
 {
 	struct pt_regs *regs = task_pt_regs(child);
 	struct thread_info *ti = task_thread_info(child);
@@ -151,7 +151,7 @@ int ptrace_getxregs(struct task_struct *child, void __user *uregs)
 	return ret ? -EFAULT : 0;
 }
 
-int ptrace_setxregs(struct task_struct *child, void __user *uregs)
+static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
 {
 	struct thread_info *ti = task_thread_info(child);
 	struct pt_regs *regs = task_pt_regs(child);
@@ -177,7 +177,8 @@ int ptrace_setxregs(struct task_struct *child, void __user *uregs)
 	return ret ? -EFAULT : 0;
 }
 
-int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret)
+static int ptrace_peekusr(struct task_struct *child, long regno,
+			  long __user *ret)
 {
 	struct pt_regs *regs;
 	unsigned long tmp;
@@ -186,86 +187,87 @@ int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret)
 	tmp = 0;  /* Default return value. */
 
 	switch(regno) {
+	case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+		tmp = regs->areg[regno - REG_AR_BASE];
+		break;
 
-		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
-			tmp = regs->areg[regno - REG_AR_BASE];
-			break;
-
-		case REG_A_BASE ... REG_A_BASE + 15:
-			tmp = regs->areg[regno - REG_A_BASE];
-			break;
+	case REG_A_BASE ... REG_A_BASE + 15:
+		tmp = regs->areg[regno - REG_A_BASE];
+		break;
 
-		case REG_PC:
-			tmp = regs->pc;
-			break;
+	case REG_PC:
+		tmp = regs->pc;
+		break;
 
-		case REG_PS:
-			/* Note:  PS.EXCM is not set while user task is running;
-			 * its being set in regs is for exception handling
-			 * convenience.  */
-			tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
-			break;
+	case REG_PS:
+		/* Note: PS.EXCM is not set while user task is running;
+		 * its being set in regs is for exception handling
+		 * convenience.
+		 */
+		tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
+		break;
 
-		case REG_WB:
-			break;		/* tmp = 0 */
+	case REG_WB:
+		break;		/* tmp = 0 */
 
-		case REG_WS:
+	case REG_WS:
 		{
 			unsigned long wb = regs->windowbase;
 			unsigned long ws = regs->windowstart;
-			tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
+			tmp = ((ws >> wb) | (ws << (WSBITS - wb))) &
+				((1 << WSBITS) - 1);
 			break;
 		}
-		case REG_LBEG:
-			tmp = regs->lbeg;
-			break;
+	case REG_LBEG:
+		tmp = regs->lbeg;
+		break;
 
-		case REG_LEND:
-			tmp = regs->lend;
-			break;
+	case REG_LEND:
+		tmp = regs->lend;
+		break;
 
-		case REG_LCOUNT:
-			tmp = regs->lcount;
-			break;
+	case REG_LCOUNT:
+		tmp = regs->lcount;
+		break;
 
-		case REG_SAR:
-			tmp = regs->sar;
-			break;
+	case REG_SAR:
+		tmp = regs->sar;
+		break;
 
-		case SYSCALL_NR:
-			tmp = regs->syscall;
-			break;
+	case SYSCALL_NR:
+		tmp = regs->syscall;
+		break;
 
-		default:
-			return -EIO;
+	default:
+		return -EIO;
 	}
 	return put_user(tmp, ret);
 }
 
-int ptrace_pokeusr(struct task_struct *child, long regno, long val)
+static int ptrace_pokeusr(struct task_struct *child, long regno, long val)
 {
 	struct pt_regs *regs;
 	regs = task_pt_regs(child);
 
 	switch (regno) {
-		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
-			regs->areg[regno - REG_AR_BASE] = val;
-			break;
+	case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+		regs->areg[regno - REG_AR_BASE] = val;
+		break;
 
-		case REG_A_BASE ... REG_A_BASE + 15:
-			regs->areg[regno - REG_A_BASE] = val;
-			break;
+	case REG_A_BASE ... REG_A_BASE + 15:
+		regs->areg[regno - REG_A_BASE] = val;
+		break;
 
-		case REG_PC:
-			regs->pc = val;
-			break;
+	case REG_PC:
+		regs->pc = val;
+		break;
 
-		case SYSCALL_NR:
-			regs->syscall = val;
-			break;
+	case SYSCALL_NR:
+		regs->syscall = val;
+		break;
 
-		default:
-			return -EIO;
+	default:
+		return -EIO;
 	}
 	return 0;
 }
@@ -467,39 +469,21 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ret;
 }
 
-void do_syscall_trace(void)
-{
-	/*
-	 * The 0x80 provides a way for the tracing parent to distinguish
-	 * between a syscall stop and SIGTRAP delivery
-	 */
-	ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
-
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
-}
-
-void do_syscall_trace_enter(struct pt_regs *regs)
+unsigned long do_syscall_trace_enter(struct pt_regs *regs)
 {
-	if (test_thread_flag(TIF_SYSCALL_TRACE)
-			&& (current->ptrace & PT_PTRACED))
-		do_syscall_trace();
+	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    tracehook_report_syscall_entry(regs))
+		return -1;
 
-#if 0
-	audit_syscall_entry(...);
-#endif
+	return regs->areg[2];
 }
 
 void do_syscall_trace_leave(struct pt_regs *regs)
 {
-	if ((test_thread_flag(TIF_SYSCALL_TRACE))
-			&& (current->ptrace & PT_PTRACED))
-		do_syscall_trace();
+	int step;
+
+	step = test_thread_flag(TIF_SINGLESTEP);
+
+	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, step);
 }

+ 4 - 5
arch/xtensa/kernel/setup.c

@@ -317,8 +317,9 @@ static inline int mem_reserve(unsigned long start, unsigned long end)
 
 void __init setup_arch(char **cmdline_p)
 {
-	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
+	platform_setup(cmdline_p);
+	strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
 
 	/* Reserve some memory regions */
 
@@ -382,8 +383,6 @@ void __init setup_arch(char **cmdline_p)
 
 	unflatten_and_copy_device_tree();
 
-	platform_setup(cmdline_p);
-
 #ifdef CONFIG_SMP
 	smp_init_cpus();
 #endif
@@ -453,9 +452,9 @@ void cpu_reset(void)
 			tmpaddr += SZ_512M;
 
 		/* Invalidate mapping in the selected temporary area */
-		if (itlb_probe(tmpaddr) & 0x8)
+		if (itlb_probe(tmpaddr) & BIT(ITLB_HIT_BIT))
 			invalidate_itlb_entry(itlb_probe(tmpaddr));
-		if (itlb_probe(tmpaddr + PAGE_SIZE) & 0x8)
+		if (itlb_probe(tmpaddr + PAGE_SIZE) & BIT(ITLB_HIT_BIT))
 			invalidate_itlb_entry(itlb_probe(tmpaddr + PAGE_SIZE));
 
 		/*

+ 5 - 5
arch/xtensa/kernel/signal.c

@@ -91,14 +91,14 @@ flush_window_regs_user(struct pt_regs *regs)
 			inc = 1;
 
 		} else if (m & 4) {		/* call8 */
-			if (copy_to_user((void*)(sp - 32),
-					   &regs->areg[(base + 1) * 4], 16))
+			if (copy_to_user(&SPILL_SLOT_CALL8(sp, 4),
+					 &regs->areg[(base + 1) * 4], 16))
 				goto errout;
 			inc = 2;
 
 		} else if (m & 8) {	/* call12 */
-			if (copy_to_user((void*)(sp - 48),
-					   &regs->areg[(base + 1) * 4], 32))
+			if (copy_to_user(&SPILL_SLOT_CALL12(sp, 4),
+					 &regs->areg[(base + 1) * 4], 32))
 				goto errout;
 			inc = 3;
 		}
@@ -106,7 +106,7 @@ flush_window_regs_user(struct pt_regs *regs)
 		/* Save current frame a0..a3 under next SP */
 
 		sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS];
-		if (copy_to_user((void*)(sp - 16), &regs->areg[base * 4], 16))
+		if (copy_to_user(&SPILL_SLOT(sp, 0), &regs->areg[base * 4], 16))
 			goto errout;
 
 		/* Get current stack pointer for next loop iteration. */

+ 8 - 27
arch/xtensa/kernel/stacktrace.c

@@ -23,14 +23,6 @@
  */
 extern int common_exception_return;
 
-/* A struct that maps to the part of the frame containing the a0 and
- * a1 registers.
- */
-struct frame_start {
-	unsigned long a0;
-	unsigned long a1;
-};
-
 void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
 			   int (*ufn)(struct stackframe *frame, void *data),
 			   void *data)
@@ -96,26 +88,16 @@ void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
 	/* Start from the a1 register. */
 	/* a1 = regs->areg[1]; */
 	while (a0 != 0 && depth--) {
-		struct frame_start frame_start;
-		/* Get the location for a1, a0 for the
-		 * previous frame from the current a1.
-		 */
-		unsigned long *psp = (unsigned long *)a1;
-
-		psp -= 4;
+		pc = MAKE_PC_FROM_RA(a0, pc);
 
 		/* Check if the region is OK to access. */
-		if (!access_ok(VERIFY_READ, psp, sizeof(frame_start)))
+		if (!access_ok(VERIFY_READ, &SPILL_SLOT(a1, 0), 8))
 			return;
 		/* Copy a1, a0 from user space stack frame. */
-		if (__copy_from_user_inatomic(&frame_start, psp,
-					      sizeof(frame_start)))
+		if (__get_user(a0, &SPILL_SLOT(a1, 0)) ||
+		    __get_user(a1, &SPILL_SLOT(a1, 1)))
 			return;
 
-		pc = MAKE_PC_FROM_RA(a0, pc);
-		a0 = frame_start.a0;
-		a1 = frame_start.a1;
-
 		frame.pc = pc;
 		frame.sp = a1;
 
@@ -147,7 +129,6 @@ void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
 	 */
 	while (a1 > sp_start && a1 < sp_end && depth--) {
 		struct stackframe frame;
-		unsigned long *psp = (unsigned long *)a1;
 
 		frame.pc = pc;
 		frame.sp = a1;
@@ -171,8 +152,8 @@ void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
 		sp_start = a1;
 
 		pc = MAKE_PC_FROM_RA(a0, pc);
-		a0 = *(psp - 4);
-		a1 = *(psp - 3);
+		a0 = SPILL_SLOT(a1, 0);
+		a1 = SPILL_SLOT(a1, 1);
 	}
 }
 EXPORT_SYMBOL(xtensa_backtrace_kernel);
@@ -196,8 +177,8 @@ void walk_stackframe(unsigned long *sp,
 
 		sp = (unsigned long *)a1;
 
-		a0 = *(sp - 4);
-		a1 = *(sp - 3);
+		a0 = SPILL_SLOT(a1, 0);
+		a1 = SPILL_SLOT(a1, 1);
 
 		if (a1 <= (unsigned long)sp)
 			break;

+ 20 - 0
arch/xtensa/platforms/iss/include/platform/simcall.h

@@ -6,6 +6,7 @@
  * for more details.
  *
  * Copyright (C) 2001 Tensilica Inc.
+ * Copyright (C) 2017 Cadence Design Systems Inc.
  */
 
 #ifndef _XTENSA_PLATFORM_ISS_SIMCALL_H
@@ -49,6 +50,10 @@
 #define SYS_bind        30
 #define SYS_ioctl	31
 
+#define SYS_iss_argc	1000	/* returns value of argc */
+#define SYS_iss_argv_size 1001	/* bytes needed for argv & arg strings */
+#define SYS_iss_set_argv 1002	/* saves argv & arg strings at given addr */
+
 /*
  * SYS_select_one specifiers
  */
@@ -118,5 +123,20 @@ static inline int simc_lseek(int fd, uint32_t off, int whence)
 	return __simc(SYS_lseek, fd, off, whence);
 }
 
+static inline int simc_argc(void)
+{
+	return __simc(SYS_iss_argc, 0, 0, 0);
+}
+
+static inline int simc_argv_size(void)
+{
+	return __simc(SYS_iss_argv_size, 0, 0, 0);
+}
+
+static inline void simc_argv(void *buf)
+{
+	__simc(SYS_iss_set_argv, (int)buf, 0, 0);
+}
+
 #endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */
 

+ 23 - 20
arch/xtensa/platforms/iss/setup.c

@@ -8,6 +8,7 @@
  *          Joe Taylor <joe@tensilica.com>
  *
  * Copyright 2001 - 2005 Tensilica Inc.
+ * Copyright 2017 Cadence Design Systems Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -15,6 +16,7 @@
  * option) any later version.
  *
  */
+#include <linux/bootmem.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -31,13 +33,13 @@
 
 #include <asm/platform.h>
 #include <asm/bootparam.h>
+#include <asm/setup.h>
 
 #include <platform/simcall.h>
 
 
 void __init platform_init(bp_tag_t* bootparam)
 {
-
 }
 
 void platform_halt(void)
@@ -59,26 +61,10 @@ void platform_restart(void)
 	/* control never gets here */
 }
 
-extern void iss_net_poll(void);
-
-const char twirl[]="|/-\\|/-\\";
-
 void platform_heartbeat(void)
 {
-#if 0
-	static int i = 0, j = 0;
-
-	if (--i < 0) {
-		i = 99;
-		printk("\r%c\r", twirl[j++]);
-		if (j == 8)
-			j = 0;
-	}
-#endif
 }
 
-
-
 static int
 iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
@@ -87,12 +73,29 @@ iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
 }
 
 static struct notifier_block iss_panic_block = {
-	iss_panic_event,
-	NULL,
-	0
+	.notifier_call = iss_panic_event,
 };
 
 void __init platform_setup(char **p_cmdline)
 {
+	int argc = simc_argc();
+	int argv_size = simc_argv_size();
+
+	if (argc > 1) {
+		void **argv = alloc_bootmem(argv_size);
+		char *cmdline = alloc_bootmem(argv_size);
+		int i;
+
+		cmdline[0] = 0;
+		simc_argv((void *)argv);
+
+		for (i = 1; i < argc; ++i) {
+			if (i > 1)
+				strcat(cmdline, " ");
+			strcat(cmdline, argv[i]);
+		}
+		*p_cmdline = cmdline;
+	}
+
 	atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block);
 }