|
@@ -35,6 +35,7 @@
|
|
#include <linux/context_tracking.h>
|
|
#include <linux/context_tracking.h>
|
|
|
|
|
|
#include <linux/uaccess.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
+#include <linux/pkeys.h>
|
|
#include <asm/page.h>
|
|
#include <asm/page.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/switch_to.h>
|
|
#include <asm/switch_to.h>
|
|
@@ -1787,6 +1788,61 @@ static int pmu_set(struct task_struct *target,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_PPC_MEM_KEYS
|
|
|
|
+static int pkey_active(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset)
|
|
|
|
+{
|
|
|
|
+ if (!arch_pkeys_enabled())
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ return regset->n;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pkey_get(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ void *kbuf, void __user *ubuf)
|
|
|
|
+{
|
|
|
|
+ BUILD_BUG_ON(TSO(amr) + sizeof(unsigned long) != TSO(iamr));
|
|
|
|
+ BUILD_BUG_ON(TSO(iamr) + sizeof(unsigned long) != TSO(uamor));
|
|
|
|
+
|
|
|
|
+ if (!arch_pkeys_enabled())
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
|
|
|
+ &target->thread.amr, 0,
|
|
|
|
+ ELF_NPKEY * sizeof(unsigned long));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pkey_set(struct task_struct *target,
|
|
|
|
+ const struct user_regset *regset,
|
|
|
|
+ unsigned int pos, unsigned int count,
|
|
|
|
+ const void *kbuf, const void __user *ubuf)
|
|
|
|
+{
|
|
|
|
+ u64 new_amr;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (!arch_pkeys_enabled())
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ /* Only the AMR can be set from userspace */
|
|
|
|
+ if (pos != 0 || count != sizeof(new_amr))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
|
|
|
+ &new_amr, 0, sizeof(new_amr));
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ /* UAMOR determines which bits of the AMR can be set from userspace. */
|
|
|
|
+ target->thread.amr = (new_amr & target->thread.uamor) |
|
|
|
|
+ (target->thread.amr & ~target->thread.uamor);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_PPC_MEM_KEYS */
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* These are our native regset flavors.
|
|
* These are our native regset flavors.
|
|
*/
|
|
*/
|
|
@@ -1821,6 +1877,9 @@ enum powerpc_regset {
|
|
REGSET_EBB, /* EBB registers */
|
|
REGSET_EBB, /* EBB registers */
|
|
REGSET_PMR, /* Performance Monitor Registers */
|
|
REGSET_PMR, /* Performance Monitor Registers */
|
|
#endif
|
|
#endif
|
|
|
|
+#ifdef CONFIG_PPC_MEM_KEYS
|
|
|
|
+ REGSET_PKEY, /* AMR register */
|
|
|
|
+#endif
|
|
};
|
|
};
|
|
|
|
|
|
static const struct user_regset native_regsets[] = {
|
|
static const struct user_regset native_regsets[] = {
|
|
@@ -1926,6 +1985,13 @@ static const struct user_regset native_regsets[] = {
|
|
.active = pmu_active, .get = pmu_get, .set = pmu_set
|
|
.active = pmu_active, .get = pmu_get, .set = pmu_set
|
|
},
|
|
},
|
|
#endif
|
|
#endif
|
|
|
|
+#ifdef CONFIG_PPC_MEM_KEYS
|
|
|
|
+ [REGSET_PKEY] = {
|
|
|
|
+ .core_note_type = NT_PPC_PKEY, .n = ELF_NPKEY,
|
|
|
|
+ .size = sizeof(u64), .align = sizeof(u64),
|
|
|
|
+ .active = pkey_active, .get = pkey_get, .set = pkey_set
|
|
|
|
+ },
|
|
|
|
+#endif
|
|
};
|
|
};
|
|
|
|
|
|
static const struct user_regset_view user_ppc_native_view = {
|
|
static const struct user_regset_view user_ppc_native_view = {
|