summaryrefslogtreecommitdiffstats
path: root/arch/frv
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2009-06-12 09:53:47 +0200
committerArnd Bergmann <arnd@arndb.de>2009-06-12 11:32:58 +0200
commit5b02ee3d219f9e01b6e9146e25613822cfc2e5ce (patch)
tree7ce9126738c3cf4b37d67170d0e4b34818c057a9 /arch/frv
parent26a28fa4fea5b8c65713aa50c124f76a88c7924d (diff)
parent8ebf975608aaebd7feb33d77f07ba21a6380e086 (diff)
downloadop-kernel-dev-5b02ee3d219f9e01b6e9146e25613822cfc2e5ce.zip
op-kernel-dev-5b02ee3d219f9e01b6e9146e25613822cfc2e5ce.tar.gz
asm-generic: merge branch 'master' of torvalds/linux-2.6
Fixes a merge conflict against the x86 tree caused by a fix to atomic.h which I renamed to atomic_long.h. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/frv')
-rw-r--r--arch/frv/Kconfig1
-rw-r--r--arch/frv/include/asm/bitops.h29
-rw-r--r--arch/frv/include/asm/elf.h1
-rw-r--r--arch/frv/include/asm/pci.h7
-rw-r--r--arch/frv/include/asm/ptrace.h11
-rw-r--r--arch/frv/include/asm/syscall.h123
-rw-r--r--arch/frv/include/asm/thread_info.h10
-rw-r--r--arch/frv/kernel/entry.S13
-rw-r--r--arch/frv/kernel/ptrace.c755
-rw-r--r--arch/frv/kernel/signal.c10
-rw-r--r--arch/frv/kernel/uaccess.c6
-rw-r--r--arch/frv/mb93090-mb00/pci-dma-nommu.c6
-rw-r--r--arch/frv/mb93090-mb00/pci-dma.c6
13 files changed, 399 insertions, 579 deletions
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 9d1552a..8a5bd7a 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -6,6 +6,7 @@ config FRV
bool
default y
select HAVE_IDE
+ select HAVE_ARCH_TRACEHOOK
config ZONE_DMA
bool
diff --git a/arch/frv/include/asm/bitops.h b/arch/frv/include/asm/bitops.h
index 287f6f6..50ae91b 100644
--- a/arch/frv/include/asm/bitops.h
+++ b/arch/frv/include/asm/bitops.h
@@ -112,7 +112,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig
#define atomic_clear_mask(mask, v) atomic_test_and_ANDNOT_mask((mask), (v))
#define atomic_set_mask(mask, v) atomic_test_and_OR_mask((mask), (v))
-static inline int test_and_clear_bit(int nr, volatile void *addr)
+static inline int test_and_clear_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *ptr = addr;
unsigned long mask = 1UL << (nr & 31);
@@ -120,7 +120,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0;
}
-static inline int test_and_set_bit(int nr, volatile void *addr)
+static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *ptr = addr;
unsigned long mask = 1UL << (nr & 31);
@@ -128,7 +128,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0;
}
-static inline int test_and_change_bit(int nr, volatile void *addr)
+static inline int test_and_change_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *ptr = addr;
unsigned long mask = 1UL << (nr & 31);
@@ -136,22 +136,22 @@ static inline int test_and_change_bit(int nr, volatile void *addr)
return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0;
}
-static inline void clear_bit(int nr, volatile void *addr)
+static inline void clear_bit(unsigned long nr, volatile void *addr)
{
test_and_clear_bit(nr, addr);
}
-static inline void set_bit(int nr, volatile void *addr)
+static inline void set_bit(unsigned long nr, volatile void *addr)
{
test_and_set_bit(nr, addr);
}
-static inline void change_bit(int nr, volatile void * addr)
+static inline void change_bit(unsigned long nr, volatile void *addr)
{
test_and_change_bit(nr, addr);
}
-static inline void __clear_bit(int nr, volatile void * addr)
+static inline void __clear_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask;
@@ -161,7 +161,7 @@ static inline void __clear_bit(int nr, volatile void * addr)
*a &= ~mask;
}
-static inline void __set_bit(int nr, volatile void * addr)
+static inline void __set_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask;
@@ -171,7 +171,7 @@ static inline void __set_bit(int nr, volatile void * addr)
*a |= mask;
}
-static inline void __change_bit(int nr, volatile void *addr)
+static inline void __change_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask;
@@ -181,7 +181,7 @@ static inline void __change_bit(int nr, volatile void *addr)
*a ^= mask;
}
-static inline int __test_and_clear_bit(int nr, volatile void * addr)
+static inline int __test_and_clear_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask, retval;
@@ -193,7 +193,7 @@ static inline int __test_and_clear_bit(int nr, volatile void * addr)
return retval;
}
-static inline int __test_and_set_bit(int nr, volatile void * addr)
+static inline int __test_and_set_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask, retval;
@@ -205,7 +205,7 @@ static inline int __test_and_set_bit(int nr, volatile void * addr)
return retval;
}
-static inline int __test_and_change_bit(int nr, volatile void * addr)
+static inline int __test_and_change_bit(unsigned long nr, volatile void *addr)
{
volatile unsigned long *a = addr;
int mask, retval;
@@ -220,12 +220,13 @@ static inline int __test_and_change_bit(int nr, volatile void * addr)
/*
* This routine doesn't need to be atomic.
*/
-static inline int __constant_test_bit(int nr, const volatile void * addr)
+static inline int
+__constant_test_bit(unsigned long nr, const volatile void *addr)
{
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
-static inline int __test_bit(int nr, const volatile void * addr)
+static inline int __test_bit(unsigned long nr, const volatile void *addr)
{
int * a = (int *) addr;
int mask;
diff --git a/arch/frv/include/asm/elf.h b/arch/frv/include/asm/elf.h
index 7279ec07d..7bbf6e4 100644
--- a/arch/frv/include/asm/elf.h
+++ b/arch/frv/include/asm/elf.h
@@ -116,6 +116,7 @@ do { \
} while(0)
#define USE_ELF_CORE_DUMP
+#define CORE_DUMP_USE_REGSET
#define ELF_FDPIC_CORE_EFLAGS EF_FRV_FDPIC
#define ELF_EXEC_PAGESIZE 16384
diff --git a/arch/frv/include/asm/pci.h b/arch/frv/include/asm/pci.h
index 3ce227b..492b5c4 100644
--- a/arch/frv/include/asm/pci.h
+++ b/arch/frv/include/asm/pci.h
@@ -81,8 +81,7 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
- if (direction == PCI_DMA_NONE)
- BUG();
+ BUG_ON(direction == PCI_DMA_NONE);
frv_cache_wback_inv((unsigned long)bus_to_virt(dma_handle),
(unsigned long)bus_to_virt(dma_handle) + size);
@@ -99,9 +98,7 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
int nelems, int direction)
{
int i;
-
- if (direction == PCI_DMA_NONE)
- BUG();
+ BUG_ON(direction == PCI_DMA_NONE);
for (i = 0; i < nelems; i++)
frv_cache_wback_inv(sg_dma_address(&sg[i]),
diff --git a/arch/frv/include/asm/ptrace.h b/arch/frv/include/asm/ptrace.h
index cf69340..a54b535 100644
--- a/arch/frv/include/asm/ptrace.h
+++ b/arch/frv/include/asm/ptrace.h
@@ -65,6 +65,8 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
+struct task_struct;
+
/*
* we dedicate GR28 to keeping a pointer to the current exception frame
* - gr28 is destroyed on entry to the kernel from userspace
@@ -73,11 +75,18 @@ register struct pt_regs *__frame asm("gr28");
#define user_mode(regs) (!((regs)->psr & PSR_S))
#define instruction_pointer(regs) ((regs)->pc)
+#define user_stack_pointer(regs) ((regs)->sp)
extern unsigned long user_stack(const struct pt_regs *);
extern void show_regs(struct pt_regs *);
#define profile_pc(regs) ((regs)->pc)
-#endif
+
+#define task_pt_regs(task) ((task)->thread.frame0)
+
+#define arch_has_single_step() (1)
+extern void user_enable_single_step(struct task_struct *);
+extern void user_disable_single_step(struct task_struct *);
#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _ASM_PTRACE_H */
diff --git a/arch/frv/include/asm/syscall.h b/arch/frv/include/asm/syscall.h
new file mode 100644
index 0000000..70689eb
--- /dev/null
+++ b/arch/frv/include/asm/syscall.h
@@ -0,0 +1,123 @@
+/* syscall parameter access functions
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+#include <linux/err.h>
+#include <asm/ptrace.h>
+
+/*
+ * Get the system call number or -1
+ */
+static inline long syscall_get_nr(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->syscallno;
+}
+
+/*
+ * Restore the clobbered GR8 register
+ * (1st syscall arg was overwritten with syscall return or error)
+ */
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ regs->gr8 = regs->orig_gr8;
+}
+
+/*
+ * See if the syscall return value is an error, returning it if it is and 0 if
+ * not
+ */
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return IS_ERR_VALUE(regs->gr8) ? regs->gr8 : 0;
+}
+
+/*
+ * Get the syscall return value
+ */
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->gr8;
+}
+
+/*
+ * Set the syscall return value
+ */
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ if (error)
+ regs->gr8 = -error;
+ else
+ regs->gr8 = val;
+}
+
+/*
+ * Retrieve the system call arguments
+ */
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ /*
+ * Do this simply for now. If we need to start supporting
+ * fetching arguments from arbitrary indices, this will need some
+ * extra logic. Presently there are no in-tree users that depend
+ * on this behaviour.
+ */
+ BUG_ON(i);
+
+ /* Argument pattern is: GR8, GR9, GR10, GR11, GR12, GR13 */
+ switch (n) {
+ case 6: args[5] = regs->gr13;
+ case 5: args[4] = regs->gr12;
+ case 4: args[3] = regs->gr11;
+ case 3: args[2] = regs->gr10;
+ case 2: args[1] = regs->gr9;
+ case 1: args[0] = regs->gr8;
+ break;
+ default:
+ BUG();
+ }
+}
+
+/*
+ * Alter the system call arguments
+ */
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ /* Same note as above applies */
+ BUG_ON(i);
+
+ switch (n) {
+ case 6: regs->gr13 = args[5];
+ case 5: regs->gr12 = args[4];
+ case 4: regs->gr11 = args[3];
+ case 3: regs->gr10 = args[2];
+ case 2: regs->gr9 = args[1];
+ case 1: regs->gr8 = args[0];
+ break;
+ default:
+ BUG();
+ }
+}
+
+#endif /* _ASM_SYSCALL_H */
diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h
index bb53ab7..e8a5ed7 100644
--- a/arch/frv/include/asm/thread_info.h
+++ b/arch/frv/include/asm/thread_info.h
@@ -109,20 +109,20 @@ register struct thread_info *__current_thread_info asm("gr15");
* - other flags in MSW
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
-#define TIF_SIGPENDING 1 /* signal pending */
-#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
-#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */
-#define TIF_IRET 4 /* return with iret */
+#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
+#define TIF_SIGPENDING 2 /* signal pending */
+#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* OOM killer killed process */
#define TIF_FREEZE 18 /* freezing for suspend */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
-#define _TIF_IRET (1 << TIF_IRET)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_FREEZE (1 << TIF_FREEZE)
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 1da523b..356e0e3 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -886,7 +886,6 @@ system_call:
bnc icc0,#0,__syscall_badsys
ldi @(gr15,#TI_FLAGS),gr4
- ori gr4,#_TIF_SYSCALL_TRACE,gr4
andicc gr4,#_TIF_SYSCALL_TRACE,gr0,icc0
bne icc0,#0,__syscall_trace_entry
@@ -1150,11 +1149,10 @@ __entry_work_notifysig:
# perform syscall entry tracing
__syscall_trace_entry:
LEDS 0x6320
- setlos.p #0,gr8
- call do_syscall_trace
+ call syscall_trace_entry
- ldi @(gr28,#REG_SYSCALLNO),gr7
- lddi @(gr28,#REG_GR(8)) ,gr8
+ lddi.p @(gr28,#REG_GR(8)) ,gr8
+ ori gr8,#0,gr7 ; syscall_trace_entry() returned new syscallno
lddi @(gr28,#REG_GR(10)),gr10
lddi.p @(gr28,#REG_GR(12)),gr12
@@ -1169,11 +1167,10 @@ __syscall_exit_work:
beq icc0,#1,__entry_work_pending
movsg psr,gr23
- andi gr23,#~PSR_PIL,gr23 ; could let do_syscall_trace() call schedule()
+ andi gr23,#~PSR_PIL,gr23 ; could let syscall_trace_exit() call schedule()
movgs gr23,psr
- setlos.p #1,gr8
- call do_syscall_trace
+ call syscall_trace_exit
bra __entry_resume_userspace
__syscall_badsys:
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index 5e7d401..60eeed3 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -19,6 +19,9 @@
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+#include <linux/tracehook.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -33,6 +36,169 @@
*/
/*
+ * retrieve the contents of FRV userspace general registers
+ */
+static int genregs_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const struct user_int_regs *iregs = &target->thread.user->i;
+ int ret;
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ iregs, 0, sizeof(*iregs));
+ if (ret < 0)
+ return ret;
+
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ sizeof(*iregs), -1);
+}
+
+/*
+ * update the contents of the FRV userspace general registers
+ */
+static int genregs_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct user_int_regs *iregs = &target->thread.user->i;
+ unsigned int offs_gr0, offs_gr1;
+ int ret;
+
+ /* not allowed to set PSR or __status */
+ if (pos < offsetof(struct user_int_regs, psr) + sizeof(long) &&
+ pos + count > offsetof(struct user_int_regs, psr))
+ return -EIO;
+
+ if (pos < offsetof(struct user_int_regs, __status) + sizeof(long) &&
+ pos + count > offsetof(struct user_int_regs, __status))
+ return -EIO;
+
+ /* set the control regs */
+ offs_gr0 = offsetof(struct user_int_regs, gr[0]);
+ offs_gr1 = offsetof(struct user_int_regs, gr[1]);
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ iregs, 0, offs_gr0);
+ if (ret < 0)
+ return ret;
+
+ /* skip GR0/TBR */
+ ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ offs_gr0, offs_gr1);
+ if (ret < 0)
+ return ret;
+
+ /* set the general regs */
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &iregs->gr[1], offs_gr1, sizeof(*iregs));
+ if (ret < 0)
+ return ret;
+
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ sizeof(*iregs), -1);
+}
+
+/*
+ * retrieve the contents of FRV userspace FP/Media registers
+ */
+static int fpmregs_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const struct user_fpmedia_regs *fpregs = &target->thread.user->f;
+ int ret;
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ fpregs, 0, sizeof(*fpregs));
+ if (ret < 0)
+ return ret;
+
+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ sizeof(*fpregs), -1);
+}
+
+/*
+ * update the contents of the FRV userspace FP/Media registers
+ */
+static int fpmregs_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct user_fpmedia_regs *fpregs = &target->thread.user->f;
+ int ret;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ fpregs, 0, sizeof(*fpregs));
+ if (ret < 0)
+ return ret;
+
+ return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ sizeof(*fpregs), -1);
+}
+
+/*
+ * determine if the FP/Media registers have actually been used
+ */
+static int fpmregs_active(struct task_struct *target,
+ const struct user_regset *regset)
+{
+ return tsk_used_math(target) ? regset->n : 0;
+}
+
+/*
+ * Define the register sets available on the FRV under Linux
+ */
+enum frv_regset {
+ REGSET_GENERAL,
+ REGSET_FPMEDIA,
+};
+
+static const struct user_regset frv_regsets[] = {
+ /*
+ * General register format is:
+ * PSR, ISR, CCR, CCCR, LR, LCR, PC, (STATUS), SYSCALLNO, ORIG_G8
+ * GNER0-1, IACC0, TBR, GR1-63
+ */
+ [REGSET_GENERAL] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = ELF_NGREG,
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .get = genregs_get,
+ .set = genregs_set,
+ },
+ /*
+ * FPU/Media register format is:
+ * FR0-63, FNER0-1, MSR0-1, ACC0-7, ACCG0-8, FSR
+ */
+ [REGSET_FPMEDIA] = {
+ .core_note_type = NT_PRFPREG,
+ .n = sizeof(struct user_fpmedia_regs) / sizeof(long),
+ .size = sizeof(long),
+ .align = sizeof(long),
+ .get = fpmregs_get,
+ .set = fpmregs_set,
+ .active = fpmregs_active,
+ },
+};
+
+static const struct user_regset_view user_frv_native_view = {
+ .name = "frv",
+ .e_machine = EM_FRV,
+ .regsets = frv_regsets,
+ .n = ARRAY_SIZE(frv_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &user_frv_native_view;
+}
+
+/*
* Get contents of register REGNO in task TASK.
*/
static inline long get_reg(struct task_struct *task, int regno)
@@ -69,40 +235,23 @@ static inline int put_reg(struct task_struct *task, int regno,
}
/*
- * check that an address falls within the bounds of the target process's memory
- * mappings
- */
-static inline int is_user_addr_valid(struct task_struct *child,
- unsigned long start, unsigned long len)
-{
-#ifdef CONFIG_MMU
- if (start >= PAGE_OFFSET || len > PAGE_OFFSET - start)
- return -EIO;
- return 0;
-#else
- struct vm_area_struct *vma;
-
- vma = find_vma(child->mm, start);
- if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
- return 0;
-
- return -EIO;
-#endif
-}
-
-/*
* Called by kernel/ptrace.c when detaching..
*
* Control h/w single stepping
*/
-void ptrace_disable(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
+{
+ child->thread.frame0->__status |= REG__STATUS_STEP;
+}
+
+void user_disable_single_step(struct task_struct *child)
{
child->thread.frame0->__status &= ~REG__STATUS_STEP;
}
-void ptrace_enable(struct task_struct *child)
+void ptrace_disable(struct task_struct *child)
{
- child->thread.frame0->__status |= REG__STATUS_STEP;
+ user_disable_single_step(child);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -111,15 +260,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int ret;
switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA:
- ret = -EIO;
- if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
- break;
- ret = generic_ptrace_peekdata(child, addr, data);
- break;
-
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
tmp = 0;
@@ -163,15 +303,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = -EIO;
- if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
- break;
- ret = generic_ptrace_pokedata(child, addr, data);
- break;
-
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
if ((addr & 3) || addr < 0)
@@ -179,7 +310,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = 0;
switch (addr >> 2) {
- case 0 ... PT__END-1:
+ case 0 ... PT__END - 1:
ret = put_reg(child, addr >> 2, data);
break;
@@ -189,95 +320,29 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
break;
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- ptrace_disable(child);
- wake_up_process(child);
- ret = 0;
- break;
-
- /* make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL:
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- clear_tsk_thread_flag(child, TIF_SINGLESTEP);
- ptrace_disable(child);
- wake_up_process(child);
- break;
-
- case PTRACE_SINGLESTEP: /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- ptrace_enable(child);
- child->exit_code = data;
- wake_up_process(child);
- ret = 0;
- break;
-
- case PTRACE_DETACH: /* detach a process that was attached. */
- ret = ptrace_detach(child, data);
- break;
-
- case PTRACE_GETREGS: { /* Get all integer regs from the child. */
- int i;
- for (i = 0; i < PT__GPEND; i++) {
- tmp = get_reg(child, i);
- if (put_user(tmp, (unsigned long *) data)) {
- ret = -EFAULT;
- break;
- }
- data += sizeof(long);
- }
- ret = 0;
- break;
- }
-
- case PTRACE_SETREGS: { /* Set all integer regs in the child. */
- int i;
- for (i = 0; i < PT__GPEND; i++) {
- if (get_user(tmp, (unsigned long *) data)) {
- ret = -EFAULT;
- break;
- }
- put_reg(child, i, tmp);
- data += sizeof(long);
- }
- ret = 0;
- break;
- }
-
- case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */
- ret = 0;
- if (copy_to_user((void *) data,
- &child->thread.user->f,
- sizeof(child->thread.user->f)))
- ret = -EFAULT;
- break;
- }
-
- case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */
- ret = 0;
- if (copy_from_user(&child->thread.user->f,
- (void *) data,
- sizeof(child->thread.user->f)))
- ret = -EFAULT;
- break;
- }
+ case PTRACE_GETREGS: /* Get all integer regs from the child. */
+ return copy_regset_to_user(child, &user_frv_native_view,
+ REGSET_GENERAL,
+ 0, sizeof(child->thread.user->i),
+ (void __user *)data);
+
+ case PTRACE_SETREGS: /* Set all integer regs in the child. */
+ return copy_regset_from_user(child, &user_frv_native_view,
+ REGSET_GENERAL,
+ 0, sizeof(child->thread.user->i),
+ (const void __user *)data);
+
+ case PTRACE_GETFPREGS: /* Get the child FP/Media state. */
+ return copy_regset_to_user(child, &user_frv_native_view,
+ REGSET_FPMEDIA,
+ 0, sizeof(child->thread.user->f),
+ (void __user *)data);
+
+ case PTRACE_SETFPREGS: /* Set the child FP/Media state. */
+ return copy_regset_from_user(child, &user_frv_native_view,
+ REGSET_FPMEDIA,
+ 0, sizeof(child->thread.user->f),
+ (const void __user *)data);
case PTRACE_GETFDPIC:
tmp = 0;
@@ -300,414 +365,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
-int __nongprelbss kstrace;
-
-static const struct {
- const char *name;
- unsigned argmask;
-} __syscall_name_table[NR_syscalls] = {
- [0] = { "restart_syscall" },
- [1] = { "exit", 0x000001 },
- [2] = { "fork", 0xffffff },
- [3] = { "read", 0x000141 },
- [4] = { "write", 0x000141 },
- [5] = { "open", 0x000235 },
- [6] = { "close", 0x000001 },
- [7] = { "waitpid", 0x000141 },
- [8] = { "creat", 0x000025 },
- [9] = { "link", 0x000055 },
- [10] = { "unlink", 0x000005 },
- [11] = { "execve", 0x000445 },
- [12] = { "chdir", 0x000005 },
- [13] = { "time", 0x000004 },
- [14] = { "mknod", 0x000325 },
- [15] = { "chmod", 0x000025 },
- [16] = { "lchown", 0x000025 },
- [17] = { "break" },
- [18] = { "oldstat", 0x000045 },
- [19] = { "lseek", 0x000131 },
- [20] = { "getpid", 0xffffff },
- [21] = { "mount", 0x043555 },
- [22] = { "umount", 0x000005 },
- [23] = { "setuid", 0x000001 },
- [24] = { "getuid", 0xffffff },
- [25] = { "stime", 0x000004 },
- [26] = { "ptrace", 0x004413 },
- [27] = { "alarm", 0x000001 },
- [28] = { "oldfstat", 0x000041 },
- [29] = { "pause", 0xffffff },
- [30] = { "utime", 0x000045 },
- [31] = { "stty" },
- [32] = { "gtty" },
- [33] = { "access", 0x000025 },
- [34] = { "nice", 0x000001 },
- [35] = { "ftime" },
- [36] = { "sync", 0xffffff },
- [37] = { "kill", 0x000011 },
- [38] = { "rename", 0x000055 },
- [39] = { "mkdir", 0x000025 },
- [40] = { "rmdir", 0x000005 },
- [41] = { "dup", 0x000001 },
- [42] = { "pipe", 0x000004 },
- [43] = { "times", 0x000004 },
- [44] = { "prof" },
- [45] = { "brk", 0x000004 },
- [46] = { "setgid", 0x000001 },
- [47] = { "getgid", 0xffffff },
- [48] = { "signal", 0x000041 },
- [49] = { "geteuid", 0xffffff },
- [50] = { "getegid", 0xffffff },
- [51] = { "acct", 0x000005 },
- [52] = { "umount2", 0x000035 },
- [53] = { "lock" },
- [54] = { "ioctl", 0x000331 },
- [55] = { "fcntl", 0x000331 },
- [56] = { "mpx" },
- [57] = { "setpgid", 0x000011 },
- [58] = { "ulimit" },
- [60] = { "umask", 0x000002 },
- [61] = { "chroot", 0x000005 },
- [62] = { "ustat", 0x000043 },
- [63] = { "dup2", 0x000011 },
- [64] = { "getppid", 0xffffff },
- [65] = { "getpgrp", 0xffffff },
- [66] = { "setsid", 0xffffff },
- [67] = { "sigaction" },
- [68] = { "sgetmask" },
- [69] = { "ssetmask" },
- [70] = { "setreuid" },
- [71] = { "setregid" },
- [72] = { "sigsuspend" },
- [73] = { "sigpending" },
- [74] = { "sethostname" },
- [75] = { "setrlimit" },
- [76] = { "getrlimit" },
- [77] = { "getrusage" },
- [78] = { "gettimeofday" },
- [79] = { "settimeofday" },
- [80] = { "getgroups" },
- [81] = { "setgroups" },
- [82] = { "select" },
- [83] = { "symlink" },
- [84] = { "oldlstat" },
- [85] = { "readlink" },
- [86] = { "uselib" },
- [87] = { "swapon" },
- [88] = { "reboot" },
- [89] = { "readdir" },
- [91] = { "munmap", 0x000034 },
- [92] = { "truncate" },
- [93] = { "ftruncate" },
- [94] = { "fchmod" },
- [95] = { "fchown" },
- [96] = { "getpriority" },
- [97] = { "setpriority" },
- [99] = { "statfs" },
- [100] = { "fstatfs" },
- [102] = { "socketcall" },
- [103] = { "syslog" },
- [104] = { "setitimer" },
- [105] = { "getitimer" },
- [106] = { "stat" },
- [107] = { "lstat" },
- [108] = { "fstat" },
- [111] = { "vhangup" },
- [114] = { "wait4" },
- [115] = { "swapoff" },
- [116] = { "sysinfo" },
- [117] = { "ipc" },
- [118] = { "fsync" },
- [119] = { "sigreturn" },
- [120] = { "clone" },
- [121] = { "setdomainname" },
- [122] = { "uname" },
- [123] = { "modify_ldt" },
- [123] = { "cacheflush" },
- [124] = { "adjtimex" },
- [125] = { "mprotect" },
- [126] = { "sigprocmask" },
- [127] = { "create_module" },
- [128] = { "init_module" },
- [129] = { "delete_module" },
- [130] = { "get_kernel_syms" },
- [131] = { "quotactl" },
- [132] = { "getpgid" },
- [133] = { "fchdir" },
- [134] = { "bdflush" },
- [135] = { "sysfs" },
- [136] = { "personality" },
- [137] = { "afs_syscall" },
- [138] = { "setfsuid" },
- [139] = { "setfsgid" },
- [140] = { "_llseek", 0x014331 },
- [141] = { "getdents" },
- [142] = { "_newselect", 0x000141 },
- [143] = { "flock" },
- [144] = { "msync" },
- [145] = { "readv" },
- [146] = { "writev" },
- [147] = { "getsid", 0x000001 },
- [148] = { "fdatasync", 0x000001 },
- [149] = { "_sysctl", 0x000004 },
- [150] = { "mlock" },
- [151] = { "munlock" },
- [152] = { "mlockall" },
- [153] = { "munlockall" },
- [154] = { "sched_setparam" },
- [155] = { "sched_getparam" },
- [156] = { "sched_setscheduler" },
- [157] = { "sched_getscheduler" },
- [158] = { "sched_yield" },
- [159] = { "sched_get_priority_max" },
- [160] = { "sched_get_priority_min" },
- [161] = { "sched_rr_get_interval" },
- [162] = { "nanosleep", 0x000044 },
- [163] = { "mremap" },
- [164] = { "setresuid" },
- [165] = { "getresuid" },
- [166] = { "vm86" },
- [167] = { "query_module" },
- [168] = { "poll" },
- [169] = { "nfsservctl" },
- [170] = { "setresgid" },
- [171] = { "getresgid" },
- [172] = { "prctl", 0x333331 },
- [173] = { "rt_sigreturn", 0xffffff },
- [174] = { "rt_sigaction", 0x001441 },
- [175] = { "rt_sigprocmask", 0x001441 },
- [176] = { "rt_sigpending", 0x000014 },
- [177] = { "rt_sigtimedwait", 0x001444 },
- [178] = { "rt_sigqueueinfo", 0x000411 },
- [179] = { "rt_sigsuspend", 0x000014 },
- [180] = { "pread", 0x003341 },
- [181] = { "pwrite", 0x003341 },
- [182] = { "chown", 0x000115 },
- [183] = { "getcwd" },
- [184] = { "capget" },
- [185] = { "capset" },
- [186] = { "sigaltstack" },
- [187] = { "sendfile" },
- [188] = { "getpmsg" },
- [189] = { "putpmsg" },
- [190] = { "vfork", 0xffffff },
- [191] = { "ugetrlimit" },
- [192] = { "mmap2", 0x313314 },
- [193] = { "truncate64" },
- [194] = { "ftruncate64" },
- [195] = { "stat64", 0x000045 },
- [196] = { "lstat64", 0x000045 },
- [197] = { "fstat64", 0x000041 },
- [198] = { "lchown32" },
- [199] = { "getuid32", 0xffffff },
- [200] = { "getgid32", 0xffffff },
- [201] = { "geteuid32", 0xffffff },
- [202] = { "getegid32", 0xffffff },
- [203] = { "setreuid32" },
- [204] = { "setregid32" },
- [205] = { "getgroups32" },
- [206] = { "setgroups32" },
- [207] = { "fchown32" },
- [208] = { "setresuid32" },
- [209] = { "getresuid32" },
- [210] = { "setresgid32" },
- [211] = { "getresgid32" },
- [212] = { "chown32" },
- [213] = { "setuid32" },
- [214] = { "setgid32" },
- [215] = { "setfsuid32" },
- [216] = { "setfsgid32" },
- [217] = { "pivot_root" },
- [218] = { "mincore" },
- [219] = { "madvise" },
- [220] = { "getdents64" },
- [221] = { "fcntl64" },
- [223] = { "security" },
- [224] = { "gettid" },
- [225] = { "readahead" },
- [226] = { "setxattr" },
- [227] = { "lsetxattr" },
- [228] = { "fsetxattr" },
- [229] = { "getxattr" },
- [230] = { "lgetxattr" },
- [231] = { "fgetxattr" },
- [232] = { "listxattr" },
- [233] = { "llistxattr" },
- [234] = { "flistxattr" },
- [235] = { "removexattr" },
- [236] = { "lremovexattr" },
- [237] = { "fremovexattr" },
- [238] = { "tkill" },
- [239] = { "sendfile64" },
- [240] = { "futex" },
- [241] = { "sched_setaffinity" },
- [242] = { "sched_getaffinity" },
- [243] = { "set_thread_area" },
- [244] = { "get_thread_area" },
- [245] = { "io_setup" },
- [246] = { "io_destroy" },
- [247] = { "io_getevents" },
- [248] = { "io_submit" },
- [249] = { "io_cancel" },
- [250] = { "fadvise64" },
- [252] = { "exit_group", 0x000001 },
- [253] = { "lookup_dcookie" },
- [254] = { "epoll_create" },
- [255] = { "epoll_ctl" },
- [256] = { "epoll_wait" },
- [257] = { "remap_file_pages" },
- [258] = { "set_tid_address" },
- [259] = { "timer_create" },
- [260] = { "timer_settime" },
- [261] = { "timer_gettime" },
- [262] = { "timer_getoverrun" },
- [263] = { "timer_delete" },
- [264] = { "clock_settime" },
- [265] = { "clock_gettime" },
- [266] = { "clock_getres" },
- [267] = { "clock_nanosleep" },
- [268] = { "statfs64" },
- [269] = { "fstatfs64" },
- [270] = { "tgkill" },
- [271] = { "utimes" },
- [272] = { "fadvise64_64" },
- [273] = { "vserver" },
- [274] = { "mbind" },
- [275] = { "get_mempolicy" },
- [276] = { "set_mempolicy" },
- [277] = { "mq_open" },
- [278] = { "mq_unlink" },
- [279] = { "mq_timedsend" },
- [280] = { "mq_timedreceive" },
- [281] = { "mq_notify" },
- [282] = { "mq_getsetattr" },
- [283] = { "sys_kexec_load" },
-};
-
-asmlinkage void do_syscall_trace(int leaving)
+/*
+ * handle tracing of system call entry
+ * - return the revised system call number or ULONG_MAX to cause ENOSYS
+ */
+asmlinkage unsigned long syscall_trace_entry(void)
{
-#if 0
- unsigned long *argp;
- const char *name;
- unsigned argmask;
- char buffer[16];
-
- if (!kstrace)
- return;
-
- if (!current->mm)
- return;
-
- if (__frame->gr7 == __NR_close)
- return;
-
-#if 0
- if (__frame->gr7 != __NR_mmap2 &&
- __frame->gr7 != __NR_vfork &&
- __frame->gr7 != __NR_execve &&
- __frame->gr7 != __NR_exit)
- return;
-#endif
-
- argmask = 0;
- name = NULL;
- if (__frame->gr7 < NR_syscalls) {
- name = __syscall_name_table[__frame->gr7].name;
- argmask = __syscall_name_table[__frame->gr7].argmask;
- }
- if (!name) {
- sprintf(buffer, "sys_%lx", __frame->gr7);
- name = buffer;
- }
-
- if (!leaving) {
- if (!argmask) {
- printk(KERN_CRIT "[%d] %s(%lx,%lx,%lx,%lx,%lx,%lx)\n",
- current->pid,
- name,
- __frame->gr8,
- __frame->gr9,
- __frame->gr10,
- __frame->gr11,
- __frame->gr12,
- __frame->gr13);
- }
- else if (argmask == 0xffffff) {
- printk(KERN_CRIT "[%d] %s()\n",
- current->pid,
- name);
- }
- else {
- printk(KERN_CRIT "[%d] %s(",
- current->pid,
- name);
-
- argp = &__frame->gr8;
-
- do {
- switch (argmask & 0xf) {
- case 1:
- printk("%ld", (long) *argp);
- break;
- case 2:
- printk("%lo", *argp);
- break;
- case 3:
- printk("%lx", *argp);
- break;
- case 4:
- printk("%p", (void *) *argp);
- break;
- case 5:
- printk("\"%s\"", (char *) *argp);
- break;
- }
-
- argp++;
- argmask >>= 4;
- if (argmask)
- printk(",");
-
- } while (argmask);
-
- printk(")\n");
- }
- }
- else {
- if ((int)__frame->gr8 > -4096 && (int)__frame->gr8 < 4096)
- printk(KERN_CRIT "[%d] %s() = %ld\n", current->pid, name, __frame->gr8);
- else
- printk(KERN_CRIT "[%d] %s() = %lx\n", current->pid, name, __frame->gr8);
+ __frame->__status |= REG__STATUS_SYSC_ENTRY;
+ if (tracehook_report_syscall_entry(__frame)) {
+ /* tracing decided this syscall should not happen, so
+ * We'll return a bogus call number to get an ENOSYS
+ * error, but leave the original number in
+ * __frame->syscallno
+ */
+ return ULONG_MAX;
}
- return;
-#endif
-
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
-
- if (!(current->ptrace & PT_PTRACED))
- return;
- /* we need to indicate entry or exit to strace */
- if (leaving)
- __frame->__status |= REG__STATUS_SYSC_EXIT;
- else
- __frame->__status |= REG__STATUS_SYSC_ENTRY;
-
- ptrace_notify(SIGTRAP);
+ return __frame->syscallno;
+}
- /*
- * 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;
- }
+/*
+ * handle tracing of system call exit
+ */
+asmlinkage void syscall_trace_exit(void)
+{
+ __frame->__status |= REG__STATUS_SYSC_EXIT;
+ tracehook_report_syscall_exit(__frame, 0);
}
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 3bdb368..4a7a62c 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -21,6 +21,7 @@
#include <linux/unistd.h>
#include <linux/personality.h>
#include <linux/freezer.h>
+#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -516,6 +517,9 @@ static void do_signal(void)
* clear the TIF_RESTORE_SIGMASK flag */
if (test_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+ tracehook_signal_handler(signr, &info, &ka, __frame,
+ test_thread_flag(TIF_SINGLESTEP));
}
return;
@@ -564,4 +568,10 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
do_signal();
+ /* deal with notification on about to resume userspace execution */
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(__frame);
+ }
+
} /* end do_notify_resume() */
diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c
index 9fb771a..374f88d 100644
--- a/arch/frv/kernel/uaccess.c
+++ b/arch/frv/kernel/uaccess.c
@@ -23,8 +23,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
char *p, ch;
long err = -EFAULT;
- if (count < 0)
- BUG();
+ BUG_ON(count < 0);
p = dst;
@@ -76,8 +75,7 @@ long strnlen_user(const char __user *src, long count)
long err = 0;
char ch;
- if (count < 0)
- BUG();
+ BUG_ON(count < 0);
#ifndef CONFIG_MMU
if ((unsigned long) src < memory_start)
diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c
index 52ff9ae..4e1ba0b 100644
--- a/arch/frv/mb93090-mb00/pci-dma-nommu.c
+++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c
@@ -116,8 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent);
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- if (direction == DMA_NONE)
- BUG();
+ BUG_ON(direction == DMA_NONE);
frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
@@ -151,8 +150,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
frv_cache_wback_inv(sg_dma_address(&sg[i]),
sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]));
- if (direction == DMA_NONE)
- BUG();
+ BUG_ON(direction == DMA_NONE);
return nents;
}
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 3ddedeb..45954f0 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -48,8 +48,7 @@ EXPORT_SYMBOL(dma_free_coherent);
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- if (direction == DMA_NONE)
- BUG();
+ BUG_ON(direction == DMA_NONE);
frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size);
@@ -81,8 +80,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
void *vaddr;
int i;
- if (direction == DMA_NONE)
- BUG();
+ BUG_ON(direction == DMA_NONE);
dampr2 = __get_DAMPR(2);
OpenPOWER on IntegriCloud