summaryrefslogtreecommitdiff
path: root/arch/tile/kernel
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-01-29 14:59:09 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2013-01-29 15:10:15 -0800
commitde65d816aa44f9ddd79861ae21d75010cc1fd003 (patch)
tree04a637a43b2e52a733d0dcb7595a47057571e7da /arch/tile/kernel
parent9710f581bb4c35589ac046b0cfc0deb7f369fc85 (diff)
parent5dcd14ecd41ea2b3ae3295a9b30d98769d52165f (diff)
Merge remote-tracking branch 'origin/x86/boot' into x86/mm2
Coming patches to x86/mm2 require the changes and advanced baseline in x86/boot. Resolved Conflicts: arch/x86/kernel/setup.c mm/nobootmem.c Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/compat.c22
-rw-r--r--arch/tile/kernel/compat_signal.c10
-rw-r--r--arch/tile/kernel/entry.S11
-rw-r--r--arch/tile/kernel/intvec_32.S29
-rw-r--r--arch/tile/kernel/intvec_64.S30
-rw-r--r--arch/tile/kernel/module.c2
-rw-r--r--arch/tile/kernel/pci.c27
-rw-r--r--arch/tile/kernel/pci_gx.c36
-rw-r--r--arch/tile/kernel/process.c171
-rw-r--r--arch/tile/kernel/ptrace.c140
-rw-r--r--arch/tile/kernel/signal.c9
-rw-r--r--arch/tile/kernel/sys.c8
12 files changed, 227 insertions, 268 deletions
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index d67459b9ac2a..7f72401b4f45 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -76,24 +76,6 @@ long compat_sys_fallocate(int fd, int mode,
((loff_t)len_hi << 32) | len_lo);
}
-
-
-long compat_sys_sched_rr_get_interval(compat_pid_t pid,
- struct compat_timespec __user *interval)
-{
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_sched_rr_get_interval(pid,
- (struct timespec __force __user *)&t);
- set_fs(old_fs);
- if (put_compat_timespec(&t, interval))
- return -EFAULT;
- return ret;
-}
-
/* Provide the compat syscall number to call mapping. */
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
@@ -102,9 +84,7 @@ long compat_sys_sched_rr_get_interval(compat_pid_t pid,
#define compat_sys_fadvise64_64 sys32_fadvise64_64
#define compat_sys_readahead sys32_readahead
-/* Call the trampolines to manage pt_regs where necessary. */
-#define compat_sys_execve _compat_sys_execve
-#define compat_sys_sigaltstack _compat_sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
#define sys_clone _sys_clone
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 08b4fe1717bb..2e4cc69224a6 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -197,8 +197,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
}
long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *regs)
+ struct compat_sigaltstack __user *uoss_ptr)
{
stack_t uss, uoss;
int ret;
@@ -219,7 +218,7 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
set_fs(KERNEL_DS);
ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
(stack_t __user __force *)&uoss,
- (unsigned long)compat_ptr(regs->sp));
+ (unsigned long)compat_ptr(current_pt_regs()->sp));
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
@@ -232,8 +231,9 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
}
/* The assembly shim for this function arranges to ignore the return value. */
-long compat_sys_rt_sigreturn(struct pt_regs *regs)
+long compat_sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
sigset_t set;
@@ -248,7 +248,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+ if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL) == -EFAULT)
goto badframe;
return 0;
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index c31637baff28..f116cb0bce20 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -28,17 +28,6 @@ STD_ENTRY(current_text_addr)
STD_ENDPROC(current_text_addr)
/*
- * Implement execve(). The i386 code has a note that forking from kernel
- * space results in no copy on write until the execve, so we should be
- * careful not to write to the stack here.
- */
-STD_ENTRY(kernel_execve)
- moveli TREG_SYSCALL_NR_NAME, __NR_execve
- swint1
- jrp lr
- STD_ENDPROC(kernel_execve)
-
-/*
* We don't run this function directly, but instead copy it to a page
* we map into every user process. See vdso_setup().
*
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index 6943515100f8..f212bf7cea86 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -1291,6 +1291,21 @@ STD_ENTRY(ret_from_fork)
}
STD_ENDPROC(ret_from_fork)
+STD_ENTRY(ret_from_kernel_thread)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ {
+ move r0, r31
+ jalr r30
+ }
+ FEEDBACK_REENTER(ret_from_kernel_thread)
+ {
+ movei r30, 0 /* not an NMI */
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ }
+ STD_ENDPROC(ret_from_kernel_thread)
+
/*
* Code for ill interrupt.
*/
@@ -1437,15 +1452,6 @@ STD_ENTRY_LOCAL(bad_intr)
panic "Unhandled interrupt %#x: PC %#lx"
STD_ENDPROC(bad_intr)
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY(_##x); \
- { \
- PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j x \
- }; \
- STD_ENDPROC(_##x)
-
/*
* Special-case sigreturn to not write r0 to the stack on return.
* This is technically more efficient, but it also avoids difficulties
@@ -1461,12 +1467,9 @@ STD_ENTRY_LOCAL(bad_intr)
}; \
STD_ENDPROC(_##x)
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
-PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
STD_ENTRY(_sys_clone)
push_extra_callee_saves r4
j sys_clone
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 7c06d597ffd0..54bc9a6678e8 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -1150,6 +1150,21 @@ STD_ENTRY(ret_from_fork)
}
STD_ENDPROC(ret_from_fork)
+STD_ENTRY(ret_from_kernel_thread)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ {
+ move r0, r31
+ jalr r30
+ }
+ FEEDBACK_REENTER(ret_from_kernel_thread)
+ {
+ movei r30, 0 /* not an NMI */
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ }
+ STD_ENDPROC(ret_from_kernel_thread)
+
/* Various stub interrupt handlers and syscall handlers */
STD_ENTRY_LOCAL(_kernel_double_fault)
@@ -1166,15 +1181,6 @@ STD_ENTRY_LOCAL(bad_intr)
panic "Unhandled interrupt %#x: PC %#lx"
STD_ENDPROC(bad_intr)
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY(_##x); \
- { \
- PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j x \
- }; \
- STD_ENDPROC(_##x)
-
/*
* Special-case sigreturn to not write r0 to the stack on return.
* This is technically more efficient, but it also avoids difficulties
@@ -1190,16 +1196,12 @@ STD_ENTRY_LOCAL(bad_intr)
}; \
STD_ENDPROC(_##x)
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
#ifdef CONFIG_COMPAT
-PTREGS_SYSCALL(compat_sys_execve, r3)
-PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
#endif
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
STD_ENTRY(_sys_clone)
push_extra_callee_saves r4
j sys_clone
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index 243ffebe38d6..4918d91bc3a6 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -42,8 +42,6 @@ void *module_alloc(unsigned long size)
int i = 0;
int npages;
- if (size == 0)
- return NULL;
npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
if (pages == NULL)
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index 759822687e8f..67237d34c2e2 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
* controller_id is the controller number, config type is 0 or 1 for
* config0 or config1 operations.
*/
-static int __devinit tile_pcie_open(int controller_id, int config_type)
+static int tile_pcie_open(int controller_id, int config_type)
{
char filename[32];
int fd;
@@ -97,8 +97,7 @@ static int __devinit tile_pcie_open(int controller_id, int config_type)
/*
* Get the IRQ numbers from the HV and set up the handlers for them.
*/
-static int __devinit tile_init_irqs(int controller_id,
- struct pci_controller *controller)
+static int tile_init_irqs(int controller_id, struct pci_controller *controller)
{
char filename[32];
int fd;
@@ -237,7 +236,7 @@ static int tile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
}
-static void __devinit fixup_read_and_payload_sizes(void)
+static void fixup_read_and_payload_sizes(void)
{
struct pci_dev *dev = NULL;
int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
@@ -245,7 +244,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
u16 new_values;
/* Scan for the smallest maximum payload size. */
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
u32 devcap;
int max_payload;
@@ -260,7 +259,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
/* Now, set the max_payload_size for all devices to that value. */
new_values = (max_read_size << 12) | (smallest_max_payload << 5);
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+ for_each_pci_dev(dev)
pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ,
new_values);
@@ -379,7 +378,7 @@ subsys_initcall(pcibios_init);
/*
* No bus fixups needed.
*/
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
{
/* Nothing needs to be done. */
}
@@ -458,11 +457,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
* specified bus & slot.
*/
-static int __devinit tile_cfg_read(struct pci_bus *bus,
- unsigned int devfn,
- int offset,
- int size,
- u32 *val)
+static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
+ int size, u32 *val)
{
struct pci_controller *controller = bus->sysdata;
int busnum = bus->number & 0xff;
@@ -504,11 +500,8 @@ static int __devinit tile_cfg_read(struct pci_bus *bus,
* See tile_cfg_read() for relevant comments.
* Note that "val" is the value to write, not a pointer to that value.
*/
-static int __devinit tile_cfg_write(struct pci_bus *bus,
- unsigned int devfn,
- int offset,
- int size,
- u32 val)
+static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
+ int size, u32 val)
{
struct pci_controller *controller = bus->sysdata;
int busnum = bus->number & 0xff;
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index 2ba6d052f85d..11425633b2d7 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -58,10 +58,10 @@
#define TRACE_CFG_RD(...)
#endif
-static int __devinitdata pci_probe = 1;
+static int pci_probe = 1;
/* Information on the PCIe RC ports configuration. */
-static int __devinitdata pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+static int pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
/*
* On some platforms with one or more Gx endpoint ports, we need to
@@ -72,7 +72,7 @@ static int __devinitdata pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
* the delay in seconds. If the delay is not provided, the value
* will be DEFAULT_RC_DELAY.
*/
-static int __devinitdata rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
/* Default number of seconds that the PCIe RC port probe can be delayed. */
#define DEFAULT_RC_DELAY 10
@@ -137,7 +137,7 @@ static int tile_irq_cpu(int irq)
/*
* Open a file descriptor to the TRIO shim.
*/
-static int __devinit tile_pcie_open(int trio_index)
+static int tile_pcie_open(int trio_index)
{
gxio_trio_context_t *context = &trio_contexts[trio_index];
int ret;
@@ -265,7 +265,7 @@ trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
* Create kernel irqs and set up the handlers for the legacy interrupts.
* Also some minimum initialization for the MSI support.
*/
-static int __devinit tile_init_irqs(struct pci_controller *controller)
+static int tile_init_irqs(struct pci_controller *controller)
{
int i;
int j;
@@ -459,8 +459,7 @@ static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin)
}
-static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
- controller)
+static void fixup_read_and_payload_sizes(struct pci_controller *controller)
{
gxio_trio_context_t *trio_context = controller->trio;
struct pci_bus *root_bus = controller->root_bus;
@@ -541,7 +540,7 @@ static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
}
}
-static int __devinit setup_pcie_rc_delay(char *str)
+static int setup_pcie_rc_delay(char *str)
{
unsigned long delay = 0;
unsigned long trio_index;
@@ -1016,7 +1015,7 @@ alloc_mem_map_failed:
subsys_initcall(pcibios_init);
/* Note: to be deleted after Linux 3.6 merge. */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
{
}
@@ -1024,7 +1023,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
* This can be called from the generic PCI layer, but doesn't need to
* do anything.
*/
-char __devinit *pcibios_setup(char *str)
+char *pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
pci_probe = 0;
@@ -1047,8 +1046,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
}
/* Called for each device after PCI setup is done. */
-static void __init
-pcibios_fixup_final(struct pci_dev *pdev)
+static void pcibios_fixup_final(struct pci_dev *pdev)
{
set_dma_ops(&pdev->dev, gx_pci_dma_map_ops);
set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET);
@@ -1144,11 +1142,8 @@ EXPORT_SYMBOL(pci_iounmap);
* specified bus & device.
*/
-static int __devinit tile_cfg_read(struct pci_bus *bus,
- unsigned int devfn,
- int offset,
- int size,
- u32 *val)
+static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
+ int size, u32 *val)
{
struct pci_controller *controller = bus->sysdata;
gxio_trio_context_t *trio_context = controller->trio;
@@ -1272,11 +1267,8 @@ invalid_device:
* See tile_cfg_read() for relevent comments.
* Note that "val" is the value to write, not a pointer to that value.
*/
-static int __devinit tile_cfg_write(struct pci_bus *bus,
- unsigned int devfn,
- int offset,
- int size,
- u32 val)
+static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
+ int size, u32 val)
{
struct pci_controller *controller = bus->sysdata;
gxio_trio_context_t *trio_context = controller->trio;
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 307d010696c9..0e5661e7d00d 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -157,24 +157,43 @@ void arch_release_thread_info(struct thread_info *info)
static void save_arch_state(struct thread_struct *t);
int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long stack_size,
- struct task_struct *p, struct pt_regs *regs)
+ unsigned long arg, struct task_struct *p)
{
- struct pt_regs *childregs;
+ struct pt_regs *childregs = task_pt_regs(p), *regs = current_pt_regs();
unsigned long ksp;
+ unsigned long *callee_regs;
/*
- * When creating a new kernel thread we pass sp as zero.
- * Assign it to a reasonable value now that we have the stack.
+ * Set up the stack and stack pointer appropriately for the
+ * new child to find itself woken up in __switch_to().
+ * The callee-saved registers must be on the stack to be read;
+ * the new task will then jump to assembly support to handle
+ * calling schedule_tail(), etc., and (for userspace tasks)
+ * returning to the context set up in the pt_regs.
*/
- if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0))
- sp = KSTK_TOP(p);
+ ksp = (unsigned long) childregs;
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
+ callee_regs = (unsigned long *)ksp;
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ p->thread.ksp = ksp;
- /*
- * Do not clone step state from the parent; each thread
- * must make its own lazily.
- */
- task_thread_info(p)->step_state = NULL;
+ /* Record the pid of the task that created this one. */
+ p->thread.creator_pid = current->pid;
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ /* kernel thread */
+ memset(childregs, 0, sizeof(struct pt_regs));
+ memset(&callee_regs[2], 0,
+ (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long));
+ callee_regs[0] = sp; /* r30 = function */
+ callee_regs[1] = arg; /* r31 = arg */
+ childregs->ex1 = PL_ICS_EX1(KERNEL_PL, 0);
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ return 0;
+ }
/*
* Start new thread in ret_from_fork so it schedules properly
@@ -182,46 +201,33 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
*/
p->thread.pc = (unsigned long) ret_from_fork;
- /* Save user stack top pointer so we can ID the stack vm area later. */
- p->thread.usp0 = sp;
-
- /* Record the pid of the process that created this one. */
- p->thread.creator_pid = current->pid;
+ /*
+ * Do not clone step state from the parent; each thread
+ * must make its own lazily.
+ */
+ task_thread_info(p)->step_state = NULL;
/*
* Copy the registers onto the kernel stack so the
* return-from-interrupt code will reload it into registers.
*/
- childregs = task_pt_regs(p);
- *childregs = *regs;
+ *childregs = *current_pt_regs();
childregs->regs[0] = 0; /* return value is zero */
- childregs->sp = sp; /* override with new user stack pointer */
+ if (sp)
+ childregs->sp = sp; /* override with new user stack pointer */
+ memcpy(callee_regs, &childregs->regs[CALLEE_SAVED_FIRST_REG],
+ CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
+
+ /* Save user stack top pointer so we can ID the stack vm area later. */
+ p->thread.usp0 = childregs->sp;
/*
* If CLONE_SETTLS is set, set "tp" in the new task to "r4",
* which is passed in as arg #5 to sys_clone().
*/
if (clone_flags & CLONE_SETTLS)
- childregs->tp = regs->regs[4];
+ childregs->tp = childregs->regs[4];
- /*
- * Copy the callee-saved registers from the passed pt_regs struct
- * into the context-switch callee-saved registers area.
- * This way when we start the interrupt-return sequence, the
- * callee-save registers will be correctly in registers, which
- * is how we assume the compiler leaves them as we start doing
- * the normal return-from-interrupt path after calling C code.
- * Zero out the C ABI save area to mark the top of the stack.
- */
- ksp = (unsigned long) childregs;
- ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */
- ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
- ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
- memcpy((void *)ksp, &regs->regs[CALLEE_SAVED_FIRST_REG],
- CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
- ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */
- ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
- p->thread.ksp = ksp;
#if CHIP_HAS_TILE_DMA()
/*
@@ -577,62 +583,6 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
panic("work_pending: bad flags %#x\n", thread_info_flags);
}
-/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
-SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
- void __user *, parent_tidptr, void __user *, child_tidptr,
- struct pt_regs *, regs)
-{
- if (!newsp)
- newsp = regs->sp;
- return do_fork(clone_flags, newsp, regs, 0,
- parent_tidptr, child_tidptr);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-SYSCALL_DEFINE4(execve, const char __user *, path,
- const char __user *const __user *, argv,
- const char __user *const __user *, envp,
- struct pt_regs *, regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(path);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name, argv, envp, regs);
- putname(filename);
- if (error == 0)
- single_step_execve();
-out:
- return error;
-}
-
-#ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
- compat_uptr_t __user *argv,
- compat_uptr_t __user *envp,
- struct pt_regs *regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(path);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename->name, argv, envp, regs);
- putname(filename);
- if (error == 0)
- single_step_execve();
-out:
- return error;
-}
-#endif
-
unsigned long get_wchan(struct task_struct *p)
{
struct KBacktraceIterator kbt;
@@ -650,37 +600,6 @@ unsigned long get_wchan(struct task_struct *p)
return 0;
}
-/*
- * We pass in lr as zero (cleared in kernel_thread) and the caller
- * part of the backtrace ABI on the stack also zeroed (in copy_thread)
- * so that backtraces will stop with this function.
- * Note that we don't use r0, since copy_thread() clears it.
- */
-static void start_kernel_thread(int dummy, int (*fn)(int), int arg)
-{
- do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
- regs.ex1 = PL_ICS_EX1(KERNEL_PL, 0); /* run at kernel PL, no ICS */
- regs.pc = (long) start_kernel_thread;
- regs.flags = PT_FLAGS_CALLER_SAVES; /* need to restore r1 and r2 */
- regs.regs[1] = (long) fn; /* function pointer */
- regs.regs[2] = (long) arg; /* parameter register */
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs,
- 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
/* Flush thread state. */
void flush_thread(void)
{
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index e92e40527d6d..9835312d5a91 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -19,7 +19,10 @@
#include <linux/kprobes.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
#include <asm/traps.h>
+#include <arch/chip.h>
void user_enable_single_step(struct task_struct *child)
{
@@ -45,6 +48,100 @@ void ptrace_disable(struct task_struct *child)
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
+/*
+ * Get registers from task and ready the result for userspace.
+ * Note that we localize the API issues to getregs() and putregs() at
+ * some cost in performance, e.g. we need a full pt_regs copy for
+ * PEEKUSR, and two copies for POKEUSR. But in general we expect
+ * GETREGS/PUTREGS to be the API of choice anyway.
+ */
+static char *getregs(struct task_struct *child, struct pt_regs *uregs)
+{
+ *uregs = *task_pt_regs(child);
+
+ /* Set up flags ABI bits. */
+ uregs->flags = 0;
+#ifdef CONFIG_COMPAT
+ if (task_thread_info(child)->status & TS_COMPAT)
+ uregs->flags |= PT_FLAGS_COMPAT;
+#endif
+
+ return (char *)uregs;
+}
+
+/* Put registers back to task. */
+static void putregs(struct task_struct *child, struct pt_regs *uregs)
+{
+ struct pt_regs *regs = task_pt_regs(child);
+
+ /* Don't allow overwriting the kernel-internal flags word. */
+ uregs->flags = regs->flags;
+
+ /* Only allow setting the ICS bit in the ex1 word. */
+ uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));
+
+ *regs = *uregs;
+}
+
+enum tile_regset {
+ REGSET_GPR,
+};
+
+static int tile_gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct pt_regs regs;
+
+ getregs(target, &regs);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs, 0,
+ sizeof(regs));
+}
+
+static int tile_gpr_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ struct pt_regs regs;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
+ sizeof(regs));
+ if (ret)
+ return ret;
+
+ putregs(target, &regs);
+
+ return 0;
+}
+
+static const struct user_regset tile_user_regset[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = ELF_NGREG,
+ .size = sizeof(elf_greg_t),
+ .align = sizeof(elf_greg_t),
+ .get = tile_gpr_get,
+ .set = tile_gpr_set,
+ },
+};
+
+static const struct user_regset_view tile_user_regset_view = {
+ .name = CHIP_ARCH_NAME,
+ .e_machine = ELF_ARCH,
+ .ei_osabi = ELF_OSABI,
+ .regsets = tile_user_regset,
+ .n = ARRAY_SIZE(tile_user_regset),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &tile_user_regset_view;
+}
+
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
@@ -53,14 +150,13 @@ long arch_ptrace(struct task_struct *child, long request,
long ret = -EIO;
char *childreg;
struct pt_regs copyregs;
- int ex1_offset;
switch (request) {
case PTRACE_PEEKUSR: /* Read register from pt_regs. */
if (addr >= PTREGS_SIZE)
break;
- childreg = (char *)task_pt_regs(child) + addr;
+ childreg = getregs(child, &copyregs) + addr;
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
if (addr & (sizeof(compat_long_t)-1))
@@ -79,17 +175,7 @@ long arch_ptrace(struct task_struct *child, long request,
case PTRACE_POKEUSR: /* Write register in pt_regs. */
if (addr >= PTREGS_SIZE)
break;
- childreg = (char *)task_pt_regs(child) + addr;
-
- /* Guard against overwrites of the privilege level. */
- ex1_offset = PTREGS_OFFSET_EX1;
-#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
- if (is_compat_task()) /* point at low word */
- ex1_offset += sizeof(compat_long_t);
-#endif
- if (addr == ex1_offset)
- data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
-
+ childreg = getregs(child, &copyregs) + addr;
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
if (addr & (sizeof(compat_long_t)-1))
@@ -102,24 +188,20 @@ long arch_ptrace(struct task_struct *child, long request,
break;
*(long *)childreg = data;
}
+ putregs(child, &copyregs);
ret = 0;
break;
case PTRACE_GETREGS: /* Get all registers from the child. */
- if (copy_to_user(datap, task_pt_regs(child),
- sizeof(struct pt_regs)) == 0) {
- ret = 0;
- }
+ ret = copy_regset_to_user(child, &tile_user_regset_view,
+ REGSET_GPR, 0,
+ sizeof(struct pt_regs), datap);
break;
case PTRACE_SETREGS: /* Set all registers in the child. */
- if (copy_from_user(&copyregs, datap,
- sizeof(struct pt_regs)) == 0) {
- copyregs.ex1 =
- PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
- *task_pt_regs(child) = copyregs;
- ret = 0;
- }
+ ret = copy_regset_from_user(child, &tile_user_regset_view,
+ REGSET_GPR, 0,
+ sizeof(struct pt_regs), datap);
break;
case PTRACE_GETFPREGS: /* Get the child FPU state. */
@@ -128,12 +210,16 @@ long arch_ptrace(struct task_struct *child, long request,
case PTRACE_SETOPTIONS:
/* Support TILE-specific ptrace options. */
- child->ptrace &= ~PT_TRACE_MASK_TILE;
+ BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK);
tmp = data & PTRACE_O_MASK_TILE;
data &= ~PTRACE_O_MASK_TILE;
ret = ptrace_request(child, request, addr, data);
- if (tmp & PTRACE_O_TRACEMIGRATE)
- child->ptrace |= PT_TRACE_MIGRATE;
+ if (ret == 0) {
+ unsigned int flags = child->ptrace;
+ flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT);
+ flags |= (tmp << PT_OPT_FLAG_SHIFT);
+ child->ptrace = flags;
+ }
break;
default:
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 67efb656d104..657a7ace4ab4 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -37,10 +37,10 @@
#define DEBUG_SIG 0
-SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
- stack_t __user *, uoss, struct pt_regs *, regs)
+SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
+ stack_t __user *, uoss)
{
- return do_sigaltstack(uss, uoss, regs->sp);
+ return do_sigaltstack(uss, uoss, current_pt_regs()->sp);
}
@@ -83,8 +83,9 @@ void signal_fault(const char *type, struct pt_regs *regs,
}
/* The assembly shim for this function arranges to ignore the return value. */
-SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
+SYSCALL_DEFINE0(rt_sigreturn)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
sigset_t set;
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
index b08095b402d6..b881a7be24bd 100644
--- a/arch/tile/kernel/sys.c
+++ b/arch/tile/kernel/sys.c
@@ -106,14 +106,10 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
#define sys_readahead sys32_readahead
#endif
-/* Call the trampolines to manage pt_regs where necessary. */
-#define sys_execve _sys_execve
-#define sys_sigaltstack _sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
+#undef sys_rt_sigreturn
#define sys_rt_sigreturn _sys_rt_sigreturn
#define sys_clone _sys_clone
-#ifndef __tilegx__
-#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
-#endif
/*
* Note that we can't include <linux/unistd.h> here since the header