13473 lines
401 KiB
Diff
13473 lines
401 KiB
Diff
From 099672494b5fbd626031f313bbdbc42d1eb3f02d Mon Sep 17 00:00:00 2001
|
||
From: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Wed, 22 May 2024 16:36:55 +0800
|
||
Subject: [PATCH] Squashed commit of the following:
|
||
|
||
commit 909ad06b3bf629d9af4e143347c1d1ef8a3a5808
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Wed May 22 16:23:13 2024 +0800
|
||
|
||
fix mte_sync_tags() parameters after rebase to 6.6.0-27.0.0.
|
||
|
||
commit 1cbf51371b0539a45f816419b2da82cf36162b4a
|
||
Author: ljl <ljl2013@163.com>
|
||
Date: Mon Mar 25 08:01:32 2024 +0000
|
||
|
||
IEE SI: Removed redundant codes.
|
||
|
||
commit 0178bfc79ad1769a36f4165348a671d2182cff55
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Mon Mar 25 11:01:11 2024 +0800
|
||
|
||
Fix bugs on qemu when opening CONFIG_CREDP.
|
||
|
||
commit 8e714f6e8f2ace5a6fc900b4bce6b03c83c41870
|
||
Author: ljl <ljl2013@163.com>
|
||
Date: Thu Mar 21 04:44:26 2024 +0000
|
||
|
||
IEE SI: Remove PAN operations as BTLB BUG is already fixed.
|
||
|
||
commit 7b5fc74cb99e377d3bc59da81612cd6f3dd8a4d8
|
||
Author: ljl <lvjinglin2013@163.com>
|
||
Date: Wed Mar 20 18:31:47 2024 +0800
|
||
|
||
IEE SI: Migration of iee rwx gate.
|
||
|
||
commit aad2c7e89c9c4ad8ff0fb3ee53cd1b974144a283
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Mon Mar 18 15:32:43 2024 +0800
|
||
|
||
modify slub.c set_track_prepare()
|
||
|
||
commit 7452bac06ec09bf8321dfdbfb8b6a429d2cd8637
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Thu Mar 21 11:26:19 2024 +0800
|
||
|
||
Set pgd of lm Privileged.
|
||
|
||
commit 33934cfc3eed798a3a687bf86c6bd92697e68ba9
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Tue Mar 19 17:14:32 2024 +0800
|
||
|
||
Delete some redundant code and put trans_pgd into IEE.
|
||
|
||
commit 2bfe9008a72f8b8ac237bc7a5f99f9d40e84c247
|
||
Author: zhangshiyang17@mails.ucas.ac.cn <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Mon Mar 18 11:47:50 2024 +0000
|
||
|
||
Fix bugs on physical when opening CONFIG_IEE and CONFIG_PTP.
|
||
|
||
commit dafa2df600757511ce3e8f178e05e28adabdf39b
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Mon Mar 18 10:40:42 2024 +0800
|
||
|
||
Fix bugs on qemu when opening CONFIG_IEE and CONFIG_PTP.
|
||
|
||
commit 9231a9f6b34c62090b5f202c9c64a52bfdac7a73
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Thu Mar 14 16:34:53 2024 +0800
|
||
|
||
Fix compiling bugs of CONFIG_PTP.
|
||
|
||
commit 6469df3bcce32896c2cb297d3cd7ead82c33f35d
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Thu Mar 14 11:10:00 2024 +0800
|
||
|
||
Fix bugs on qemu when opening CONFIG_IEE and CONFIG_INTERRUPTABLE.
|
||
|
||
commit 5f1773dada622a3514c9ed6aa72dd50e918f2664
|
||
Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
|
||
Date: Wed Mar 13 17:31:39 2024 +0800
|
||
|
||
Fix bugs on qemu when opening CONFIG_IEE.
|
||
|
||
commit 73f433a093fa84cffa5e11e86bed6f17c9b30a39
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Tue Mar 12 15:32:29 2024 +0800
|
||
|
||
fix the map of IEE_SI_TEXT.
|
||
|
||
commit 9b92deb4b2338093d9b04f4b81f162855b31c983
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Sun Mar 10 16:11:13 2024 +0800
|
||
|
||
modified to be able to compile.
|
||
can start the kernel with qemu and successfully reach `start_kernel()`.
|
||
|
||
commit e892ec4790d72e9433b48b0221e7e6dc4c361dd9
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Thu Mar 7 14:27:45 2024 +0800
|
||
|
||
fix some conflicts
|
||
|
||
commit fdec7e39345e81e867e01258487f88801b790b02
|
||
Author: liuzh <liuzhh@zgclab.edu.cn>
|
||
Date: Wed Mar 6 12:31:11 2024 +0800
|
||
|
||
migrate openeuler-commit code. (need some fix before compiling)
|
||
---
|
||
Makefile | 3 +-
|
||
arch/arm64/Kconfig | 18 +
|
||
arch/arm64/include/asm/assembler.h | 67 +
|
||
arch/arm64/include/asm/daifflags.h | 16 +
|
||
arch/arm64/include/asm/efi.h | 4 +
|
||
arch/arm64/include/asm/fixmap.h | 3 +
|
||
arch/arm64/include/asm/hw_breakpoint.h | 12 +
|
||
arch/arm64/include/asm/iee-access.h | 36 +
|
||
arch/arm64/include/asm/iee-cred.h | 150 ++
|
||
arch/arm64/include/asm/iee-def.h | 74 +
|
||
arch/arm64/include/asm/iee-si.h | 64 +
|
||
arch/arm64/include/asm/iee-slab.h | 23 +
|
||
arch/arm64/include/asm/iee-token.h | 40 +
|
||
arch/arm64/include/asm/iee.h | 10 +
|
||
arch/arm64/include/asm/kernel-pgtable.h | 21 +
|
||
arch/arm64/include/asm/koi.h | 335 +++++
|
||
arch/arm64/include/asm/memory.h | 24 +
|
||
arch/arm64/include/asm/mmu_context.h | 20 +
|
||
arch/arm64/include/asm/pgalloc.h | 4 +
|
||
arch/arm64/include/asm/pgtable-hwdef.h | 11 +
|
||
arch/arm64/include/asm/pgtable.h | 304 +++-
|
||
arch/arm64/include/asm/pointer_auth.h | 5 +
|
||
arch/arm64/include/asm/sysreg.h | 58 +
|
||
arch/arm64/include/asm/tlb.h | 9 +
|
||
arch/arm64/include/asm/tlbflush.h | 58 +-
|
||
arch/arm64/kernel/Makefile | 2 +
|
||
arch/arm64/kernel/armv8_deprecated.c | 16 +
|
||
arch/arm64/kernel/asm-offsets.c | 11 +
|
||
arch/arm64/kernel/cpu_errata.c | 12 +
|
||
arch/arm64/kernel/cpufeature.c | 79 +
|
||
arch/arm64/kernel/debug-monitors.c | 4 +
|
||
arch/arm64/kernel/entry-common.c | 4 +
|
||
arch/arm64/kernel/entry.S | 611 ++++++++
|
||
arch/arm64/kernel/fpsimd.c | 4 +
|
||
arch/arm64/kernel/head.S | 56 +
|
||
arch/arm64/kernel/hibernate.c | 14 +
|
||
arch/arm64/kernel/hw_breakpoint.c | 99 ++
|
||
arch/arm64/kernel/iee/Makefile | 1 +
|
||
arch/arm64/kernel/iee/iee-func.c | 187 +++
|
||
arch/arm64/kernel/iee/iee-gate.S | 174 +++
|
||
arch/arm64/kernel/iee/iee.c | 1360 +++++++++++++++++
|
||
arch/arm64/kernel/koi/Makefile | 1 +
|
||
arch/arm64/kernel/koi/koi.c | 1327 +++++++++++++++++
|
||
arch/arm64/kernel/mte.c | 5 +
|
||
arch/arm64/kernel/process.c | 19 +-
|
||
arch/arm64/kernel/proton-pack.c | 8 +
|
||
arch/arm64/kernel/setup.c | 33 +
|
||
arch/arm64/kernel/traps.c | 26 +
|
||
arch/arm64/kernel/vmlinux.lds.S | 61 +
|
||
arch/arm64/mm/context.c | 91 +-
|
||
arch/arm64/mm/fault.c | 9 +
|
||
arch/arm64/mm/fixmap.c | 74 +-
|
||
arch/arm64/mm/init.c | 34 +
|
||
arch/arm64/mm/mmu.c | 1780 +++++++++++++++++++----
|
||
arch/arm64/mm/pgd.c | 39 +
|
||
arch/arm64/mm/proc.S | 28 +
|
||
arch/arm64/mm/trans_pgd.c | 46 +
|
||
drivers/firmware/efi/arm-runtime.c | 4 +
|
||
drivers/firmware/efi/memmap.c | 20 +
|
||
drivers/tty/serial/earlycon.c | 4 +
|
||
drivers/usb/early/ehci-dbgp.c | 4 +
|
||
fs/coredump.c | 8 +
|
||
fs/exec.c | 20 +
|
||
fs/nfs/flexfilelayout/flexfilelayout.c | 9 +
|
||
fs/nfs/nfs4idmap.c | 9 +
|
||
fs/nfsd/auth.c | 38 +
|
||
fs/nfsd/nfs4callback.c | 12 +-
|
||
fs/nfsd/nfs4recover.c | 9 +
|
||
fs/nfsd/nfsfh.c | 9 +
|
||
fs/open.c | 26 +
|
||
fs/overlayfs/dir.c | 9 +
|
||
fs/overlayfs/super.c | 12 +
|
||
fs/smb/client/cifs_spnego.c | 9 +
|
||
fs/smb/client/cifsacl.c | 9 +
|
||
include/asm-generic/early_ioremap.h | 3 +
|
||
include/asm-generic/fixmap.h | 18 +
|
||
include/asm-generic/pgalloc.h | 54 +
|
||
include/asm-generic/vmlinux.lds.h | 24 +-
|
||
include/linux/cred.h | 45 +-
|
||
include/linux/efi.h | 9 +
|
||
include/linux/iee-func.h | 27 +
|
||
include/linux/module.h | 1 +
|
||
include/linux/sched.h | 19 +
|
||
init/main.c | 28 +-
|
||
kernel/cred.c | 182 +++
|
||
kernel/exit.c | 8 +
|
||
kernel/fork.c | 316 ++--
|
||
kernel/groups.c | 7 +
|
||
kernel/kthread.c | 13 +
|
||
kernel/smpboot.c | 9 +
|
||
kernel/sys.c | 107 ++
|
||
kernel/umh.c | 10 +
|
||
kernel/user_namespace.c | 18 +
|
||
mm/Kconfig | 12 +
|
||
mm/damon/ops-common.c | 1 +
|
||
mm/debug_vm_pgtable.c | 24 +
|
||
mm/early_ioremap.c | 57 +
|
||
mm/huge_memory.c | 30 +-
|
||
mm/init-mm.c | 17 +
|
||
mm/memory.c | 14 +
|
||
mm/slub.c | 198 ++-
|
||
mm/sparse-vmemmap.c | 21 +
|
||
mm/vmalloc.c | 2 +-
|
||
net/dns_resolver/dns_key.c | 9 +
|
||
security/commoncap.c | 169 +++
|
||
security/keys/keyctl.c | 23 +
|
||
security/keys/process_keys.c | 53 +
|
||
security/security.c | 15 +
|
||
109 files changed, 8945 insertions(+), 397 deletions(-)
|
||
create mode 100644 arch/arm64/include/asm/iee-access.h
|
||
create mode 100644 arch/arm64/include/asm/iee-cred.h
|
||
create mode 100644 arch/arm64/include/asm/iee-def.h
|
||
create mode 100644 arch/arm64/include/asm/iee-si.h
|
||
create mode 100644 arch/arm64/include/asm/iee-slab.h
|
||
create mode 100644 arch/arm64/include/asm/iee-token.h
|
||
create mode 100644 arch/arm64/include/asm/iee.h
|
||
create mode 100644 arch/arm64/include/asm/koi.h
|
||
create mode 100644 arch/arm64/kernel/iee/Makefile
|
||
create mode 100644 arch/arm64/kernel/iee/iee-func.c
|
||
create mode 100644 arch/arm64/kernel/iee/iee-gate.S
|
||
create mode 100644 arch/arm64/kernel/iee/iee.c
|
||
create mode 100644 arch/arm64/kernel/koi/Makefile
|
||
create mode 100644 arch/arm64/kernel/koi/koi.c
|
||
create mode 100644 include/linux/iee-func.h
|
||
|
||
diff --git a/Makefile b/Makefile
|
||
index 8e6d9b894b1e..20c367b5957d 100644
|
||
--- a/Makefile
|
||
+++ b/Makefile
|
||
@@ -554,7 +554,7 @@ LINUXINCLUDE := \
|
||
-I$(objtree)/include \
|
||
$(USERINCLUDE)
|
||
|
||
-KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE
|
||
+KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE -march=armv8.1-a
|
||
|
||
KBUILD_CFLAGS :=
|
||
KBUILD_CFLAGS += -std=gnu11
|
||
@@ -563,6 +563,7 @@ KBUILD_CFLAGS += -funsigned-char
|
||
KBUILD_CFLAGS += -fno-common
|
||
KBUILD_CFLAGS += -fno-PIE
|
||
KBUILD_CFLAGS += -fno-strict-aliasing
|
||
+KBUILD_CFLAGS += -march=armv8.1-a
|
||
|
||
KBUILD_CPPFLAGS := -D__KERNEL__
|
||
KBUILD_RUSTFLAGS := $(rust_common_flags) \
|
||
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
||
index 2a875546bdc7..7448afc90c0a 100644
|
||
--- a/arch/arm64/Kconfig
|
||
+++ b/arch/arm64/Kconfig
|
||
@@ -1730,6 +1730,24 @@ config UNMAP_KERNEL_AT_EL0
|
||
|
||
If unsure, say Y.
|
||
|
||
+# Config for iee
|
||
+config IEE
|
||
+ depends on ARM64
|
||
+ depends on ARM64_PAN
|
||
+ depends on ARM64_VA_BITS_48
|
||
+ depends on ARM64_4K_PAGES
|
||
+ def_bool y
|
||
+
|
||
+# Config for support of interruption of iee
|
||
+config IEE_INTERRUPTABLE
|
||
+ depends on IEE
|
||
+ def_bool n
|
||
+
|
||
+# Config for credentials isolation
|
||
+config CREDP
|
||
+ depends on IEE
|
||
+ def_bool y
|
||
+
|
||
config MITIGATE_SPECTRE_BRANCH_HISTORY
|
||
bool "Mitigate Spectre style attacks against branch history" if EXPERT
|
||
default y
|
||
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
|
||
index 38b23786aeb4..6af10d509c2e 100644
|
||
--- a/arch/arm64/include/asm/assembler.h
|
||
+++ b/arch/arm64/include/asm/assembler.h
|
||
@@ -26,6 +26,41 @@
|
||
#include <asm/ptrace.h>
|
||
#include <asm/thread_info.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ .macro iee_si_restore_daif, flags:req
|
||
+ msr daifclr, #0xf
|
||
+ tbnz \flags, #6, 114221f
|
||
+ tbnz \flags, #7, 114210f
|
||
+ tbnz \flags, #8, 114100f
|
||
+ msr daifset, #0b000
|
||
+ b 114514f
|
||
+114221:
|
||
+ tbnz \flags, #7, 114211f
|
||
+ tbnz \flags, #8, 114101f
|
||
+ msr daifset, #0b001
|
||
+ b 114514f
|
||
+114211:
|
||
+ tbnz \flags, #8, 114111f
|
||
+ msr daifset, #0b011
|
||
+ b 114514f
|
||
+114210:
|
||
+ tbnz \flags, #8, 114110f
|
||
+ msr daifset, #0b010
|
||
+ b 114514f
|
||
+114100:
|
||
+ msr daifset, #0b100
|
||
+ b 114514f
|
||
+114101:
|
||
+ msr daifset, #0b101
|
||
+ b 114514f
|
||
+114110:
|
||
+ msr daifset, #0b110
|
||
+ b 114514f
|
||
+114111:
|
||
+ msr daifset, #0b111
|
||
+114514:
|
||
+ .endm
|
||
+#endif
|
||
/*
|
||
* Provide a wxN alias for each wN register so what we can paste a xN
|
||
* reference after a 'w' to obtain the 32-bit version.
|
||
@@ -52,7 +87,11 @@ alternative_else_nop_endif
|
||
|
||
.macro disable_daif
|
||
disable_allint
|
||
+// #ifdef CONFIG_IEE
|
||
+// msr daifset, #0x7
|
||
+// #else
|
||
msr daifset, #0xf
|
||
+// #endif
|
||
.endm
|
||
|
||
.macro enable_daif
|
||
@@ -69,7 +108,11 @@ alternative_else_nop_endif
|
||
.endm
|
||
|
||
.macro restore_irq, flags
|
||
+// #ifdef CONFIG_IEE
|
||
+// iee_si_restore_daif \flags
|
||
+// #else
|
||
msr daif, \flags
|
||
+// #endif
|
||
.endm
|
||
|
||
.macro enable_dbg
|
||
@@ -77,20 +120,44 @@ alternative_else_nop_endif
|
||
.endm
|
||
|
||
.macro disable_step_tsk, flgs, tmp
|
||
+// #ifdef CONFIG_IEE
|
||
+// 1145:
|
||
+// tbz \flgs, #TIF_SINGLESTEP, 9990f
|
||
+// mrs \tmp, mdscr_el1
|
||
+// bic \tmp, \tmp, #DBG_MDSCR_SS
|
||
+// orr \tmp, \tmp, #DBG_MDSCR_MDE
|
||
+// msr mdscr_el1, \tmp
|
||
+// isb // Synchronise with enable_dbg
|
||
+// mrs \tmp, mdscr_el1
|
||
+// tbz \tmp, #15, 1145b
|
||
+// #else
|
||
tbz \flgs, #TIF_SINGLESTEP, 9990f
|
||
mrs \tmp, mdscr_el1
|
||
bic \tmp, \tmp, #DBG_MDSCR_SS
|
||
msr mdscr_el1, \tmp
|
||
isb // Synchronise with enable_dbg
|
||
+// #endif
|
||
9990:
|
||
.endm
|
||
|
||
/* call with daif masked */
|
||
.macro enable_step_tsk, flgs, tmp
|
||
+// #ifdef CONFIG_IEE
|
||
+// 1146:
|
||
+// tbz \flgs, #TIF_SINGLESTEP, 9990f
|
||
+// mrs \tmp, mdscr_el1
|
||
+// orr \tmp, \tmp, #DBG_MDSCR_SS
|
||
+// orr \tmp, \tmp, #DBG_MDSCR_MDE
|
||
+// msr mdscr_el1, \tmp
|
||
+// isb // Synchronise with enable_dbg
|
||
+// mrs \tmp, mdscr_el1
|
||
+// tbz \tmp, #15, 1146b
|
||
+// #else
|
||
tbz \flgs, #TIF_SINGLESTEP, 9990f
|
||
mrs \tmp, mdscr_el1
|
||
orr \tmp, \tmp, #DBG_MDSCR_SS
|
||
msr mdscr_el1, \tmp
|
||
+// #endif
|
||
9990:
|
||
.endm
|
||
|
||
diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
|
||
index 2417cc6b1631..cb5b4c2e03b8 100644
|
||
--- a/arch/arm64/include/asm/daifflags.h
|
||
+++ b/arch/arm64/include/asm/daifflags.h
|
||
@@ -26,11 +26,19 @@ static inline void local_daif_mask(void)
|
||
(read_sysreg_s(SYS_ICC_PMR_EL1) == (GIC_PRIO_IRQOFF |
|
||
GIC_PRIO_PSR_I_SET)));
|
||
|
||
+// #ifdef CONFIG_IEE
|
||
+// asm volatile(
|
||
+// "msr daifset, #0x7 // local_daif_mask\n"
|
||
+// :
|
||
+// :
|
||
+// : "memory");
|
||
+// #else
|
||
asm volatile(
|
||
"msr daifset, #0xf // local_daif_mask\n"
|
||
:
|
||
:
|
||
: "memory");
|
||
+// #endif
|
||
|
||
/* Don't really care for a dsb here, we don't intend to enable IRQs */
|
||
if (system_uses_irq_prio_masking())
|
||
@@ -118,7 +126,11 @@ static inline void local_daif_restore(unsigned long flags)
|
||
gic_write_pmr(pmr);
|
||
}
|
||
|
||
+// #ifdef CONFIG_IEE
|
||
+// iee_si_write_daif(flags);
|
||
+// #else
|
||
write_sysreg(flags, daif);
|
||
+// #endif
|
||
|
||
/* If we can take asynchronous errors we can take NMIs */
|
||
if (system_uses_nmi()) {
|
||
@@ -151,7 +163,11 @@ static inline void local_daif_inherit(struct pt_regs *regs)
|
||
* system_has_prio_mask_debugging() won't restore the I bit if it can
|
||
* use the pmr instead.
|
||
*/
|
||
+// #ifdef CONFIG_IEE
|
||
+// iee_si_write_daif(flags);
|
||
+// #else
|
||
write_sysreg(flags, daif);
|
||
+// #endif
|
||
|
||
/* The ALLINT field is at the same position in pstate and ALLINT */
|
||
if (system_uses_nmi()) {
|
||
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
|
||
index bcd5622aa096..76c4bd6c2b20 100644
|
||
--- a/arch/arm64/include/asm/efi.h
|
||
+++ b/arch/arm64/include/asm/efi.h
|
||
@@ -58,7 +58,11 @@ void arch_efi_call_virt_teardown(void);
|
||
#define arch_efi_save_flags(state_flags) \
|
||
((void)((state_flags) = read_sysreg(daif)))
|
||
|
||
+// #ifdef CONFIG_IEE
|
||
+// #define arch_efi_restore_flags(state_flags) iee_si_write_daif(state_flags)
|
||
+// #else
|
||
#define arch_efi_restore_flags(state_flags) write_sysreg(state_flags, daif)
|
||
+// #endif
|
||
|
||
|
||
/* arch specific definitions used by the stub code */
|
||
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
|
||
index 58c294a96676..095a0731dce3 100644
|
||
--- a/arch/arm64/include/asm/fixmap.h
|
||
+++ b/arch/arm64/include/asm/fixmap.h
|
||
@@ -108,6 +108,9 @@ void __init fixmap_copy(pgd_t *pgdir);
|
||
#define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
|
||
|
||
extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
|
||
+#ifdef CONFIG_PTP
|
||
+extern void __iee_set_fixmap_pre_init(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
|
||
+#endif
|
||
|
||
#include <asm-generic/fixmap.h>
|
||
|
||
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
|
||
index 84055329cd8b..f72d89bb9a32 100644
|
||
--- a/arch/arm64/include/asm/hw_breakpoint.h
|
||
+++ b/arch/arm64/include/asm/hw_breakpoint.h
|
||
@@ -104,6 +104,18 @@ static inline void decode_ctrl_reg(u32 reg,
|
||
write_sysreg(VAL, dbg##REG##N##_el1);\
|
||
} while (0)
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#define IEE_SI_AARCH64_DBG_READ(N, REG, VAL) do{\
|
||
+ VAL = this_cpu_read(iee_si_user_##REG##N);\
|
||
+} while (0)
|
||
+
|
||
+#define IEE_SI_AARCH64_DBG_WRITE(N, REG, VAL) do{\
|
||
+ u64 __val = (u64)(VAL); \
|
||
+ this_cpu_write(iee_si_user_##REG##N, __val);\
|
||
+ iee_rwx_gate_entry(IEE_WRITE_AFSR0);\
|
||
+} while (0)
|
||
+#endif
|
||
+
|
||
struct task_struct;
|
||
struct notifier_block;
|
||
struct perf_event_attr;
|
||
diff --git a/arch/arm64/include/asm/iee-access.h b/arch/arm64/include/asm/iee-access.h
|
||
new file mode 100644
|
||
index 000000000000..79604c21a510
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-access.h
|
||
@@ -0,0 +1,36 @@
|
||
+#ifndef _LINUX_IEE_ACCESS_H
|
||
+#define _LINUX_IEE_ACCESS_H
|
||
+
|
||
+#include <asm/iee-def.h>
|
||
+#include <asm/iee-slab.h>
|
||
+
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+void iee_write_in_byte(void *ptr, u64 data, int length)
|
||
+{
|
||
+ iee_rw_gate(IEE_WRITE_IN_BYTE, ptr, data, length);
|
||
+}
|
||
+
|
||
+void iee_memset(void *ptr, int data, size_t n)
|
||
+{
|
||
+ iee_rw_gate(IEE_MEMSET, ptr, data, n);
|
||
+}
|
||
+
|
||
+void iee_set_track(struct track *ptr, struct track *data)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_TRACK, ptr, data);
|
||
+}
|
||
+
|
||
+void iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_FREEPTR, pptr, ptr);
|
||
+}
|
||
+
|
||
+void iee_write_entry_task(struct task_struct *tsk)
|
||
+{
|
||
+ iee_rw_gate(IEE_WRITE_ENTRY_TASK, tsk);
|
||
+}
|
||
+#endif
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee-cred.h b/arch/arm64/include/asm/iee-cred.h
|
||
new file mode 100644
|
||
index 000000000000..b8c3bb53f98a
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-cred.h
|
||
@@ -0,0 +1,150 @@
|
||
+#ifndef _LINUX_IEE_CRED_H
|
||
+#define _LINUX_IEE_CRED_H
|
||
+
|
||
+#include <linux/cred.h>
|
||
+#include <asm/iee-def.h>
|
||
+
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+
|
||
+#ifdef CONFIG_CREDP
|
||
+static void __maybe_unused iee_copy_cred(const struct cred *old, struct cred *new)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_COPY_CRED,old,new);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_uid(struct cred *cred, kuid_t uid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_UID,cred,uid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_gid(struct cred *cred, kgid_t gid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_GID,cred,gid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_suid(struct cred *cred, kuid_t suid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_SUID,cred,suid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_sgid(struct cred *cred, kgid_t sgid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_SGID,cred,sgid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_euid(struct cred *cred, kuid_t euid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_EUID,cred,euid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_egid(struct cred *cred, kgid_t egid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_EGID,cred,egid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_FSUID,cred,fsuid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_FSGID,cred,fsgid);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_user(struct cred *cred, struct user_struct *user)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_USER,cred,user);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_USER_NS,cred,user_ns);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_UCOUNTS,cred,ucounts);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_group_info(struct cred *cred, struct group_info *group_info)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_GROUP_INFO,cred,group_info);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_securebits(struct cred *cred, unsigned securebits)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_SECUREBITS,cred,securebits);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_CAP_INHER,cred,cap_inheritable);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_CAP_PERM,cred,cap_permitted);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_CAP_EFFECT,cred,cap_effective);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_CAP_BSET,cred,cap_bset);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_CAP_AMBIENT,cred,cap_ambient);
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_KEYS
|
||
+static void __maybe_unused iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_JIT_KEYRING,cred,jit_keyring);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_SESS_KEYRING,cred,session_keyring);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_PROC_KEYRING,cred,process_keyring);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_THREAD_KEYRING,cred,thread_keyring);
|
||
+}
|
||
+
|
||
+static void __maybe_unused iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_REQ_KEYRING,cred,request_key_auth);
|
||
+}
|
||
+#endif
|
||
+
|
||
+static void __maybe_unused iee_set_cred_atomic_set_usage(struct cred *cred, int i)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_ATSET_USAGE,cred,i);
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_SECURITY
|
||
+static void __maybe_unused iee_set_cred_security(struct cred *cred, void *security)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_SECURITY,cred,security);
|
||
+}
|
||
+#endif
|
||
+
|
||
+static void __maybe_unused iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_RCU,cred,rcu);
|
||
+}
|
||
+#endif
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee-def.h b/arch/arm64/include/asm/iee-def.h
|
||
new file mode 100644
|
||
index 000000000000..76e59259e4d1
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-def.h
|
||
@@ -0,0 +1,74 @@
|
||
+// Function Identifiers with Parameters Description
|
||
+
|
||
+#define IEE_WRITE_IN_BYTE 0 // Parameters: void *ptr, __u64 data, int length
|
||
+#define IEE_OP_SET_PTE 1 // Parameters: pte_t *ptep, pte_t pte
|
||
+#define IEE_OP_SET_PMD 2 // Parameters: pmd_t *pmdp, pmd_t pmd
|
||
+#define IEE_OP_SET_PUD 3 // Parameters: pud_t *pudp, pud_t pud
|
||
+#define IEE_OP_SET_P4D 4 // Parameters: p4d_t *p4dp, p4d_t p4d
|
||
+#define IEE_OP_SET_BM_PTE 5 // Parameters: pte_t *ptep, pte_t pte
|
||
+#define IEE_OP_SET_SWAPPER_PGD 6 // Parameters: pgd_t *pgdp, pgd_t pgd
|
||
+#define IEE_OP_SET_TRAMP_PGD 7 // Parameters: pgd_t *pgdp, pgd_t pgd
|
||
+#define IEE_OP_SET_CMPXCHG 8 // Parameters: pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval
|
||
+#define IEE_OP_SET_XCHG 9 // Parameters: pte_t *ptep, pteval_t pteval
|
||
+#define IEE_OP_COPY_CRED 10 // Parameters: struct cred *old, struct cred *new
|
||
+#define IEE_OP_SET_CRED_UID 11 // Parameters: struct cred *cred, kuid_t uid
|
||
+#define IEE_OP_SET_CRED_GID 12 // Parameters: struct cred *cred, kgid_t gid
|
||
+#define IEE_OP_SET_CRED_SUID 13 // Parameters: struct cred *cred, kuid_t suid
|
||
+#define IEE_OP_SET_CRED_SGID 14 // Parameters: struct cred *cred, kgid_t sgid
|
||
+#define IEE_OP_SET_CRED_EUID 15 // Parameters: struct cred *cred, kuid_t euid
|
||
+#define IEE_OP_SET_CRED_EGID 16 // Parameters: struct cred *cred, kgid_t egid
|
||
+#define IEE_OP_SET_CRED_FSUID 17 // Parameters: struct cred *cred, kuid_t fsuid
|
||
+#define IEE_OP_SET_CRED_FSGID 18 // Parameters: struct cred *cred, kgid_t fsgid
|
||
+#define IEE_OP_SET_CRED_USER 19 // Parameters: struct cred *cred, struct user_struct *user
|
||
+#define IEE_OP_SET_CRED_USER_NS 20 // Parameters: struct cred *cred, struct user_namespace *user_ns
|
||
+#define IEE_OP_SET_CRED_GROUP_INFO 21 // Parameters: struct cred *cred, struct group_info *group_info
|
||
+#define IEE_OP_SET_CRED_SECUREBITS 22 // Parameters: struct cred *cred, unsigned securebits
|
||
+#define IEE_OP_SET_CRED_CAP_INHER 23 // Parameters: struct cred *cred, kernel_cap_t cap_inheritable
|
||
+#define IEE_OP_SET_CRED_CAP_PERM 24 // Parameters: struct cred *cred, kernel_cap_t cap_permitted
|
||
+#define IEE_OP_SET_CRED_CAP_EFFECT 25 // Parameters: struct cred *cred, kernel_cap_t cap_effective
|
||
+#define IEE_OP_SET_CRED_CAP_BSET 26 // Parameters: struct cred *cred, kernel_cap_t cap_bset
|
||
+#define IEE_OP_SET_CRED_CAP_AMBIENT 27 // Parameters: struct cred *cred, kernel_cap_t cap_ambient
|
||
+#define IEE_OP_SET_CRED_JIT_KEYRING 28 // Parameters: struct cred *cred, unsigned char jit_keyring
|
||
+#define IEE_OP_SET_CRED_SESS_KEYRING 29 // Parameters: struct cred *cred, struct key *session_keyring
|
||
+#define IEE_OP_SET_CRED_PROC_KEYRING 30 // Parameters: struct cred *cred, struct key *process_keyring
|
||
+#define IEE_OP_SET_CRED_THREAD_KEYRING 31 // Parameters: struct cred *cred, struct key *thread_keyring
|
||
+#define IEE_OP_SET_CRED_REQ_KEYRING 32 // Parameters: struct cred *cred, struct key *request_key_auth
|
||
+#define IEE_OP_SET_CRED_NON_RCU 33 // Parameters: struct cred *cred, int non_rcu
|
||
+#define IEE_OP_SET_CRED_ATSET_USAGE 34 // Parameters: struct cred *cred, int i
|
||
+#define IEE_OP_SET_CRED_ATOP_USAGE 35 // Parameters: struct cred *cred, int flag
|
||
+#define IEE_OP_SET_CRED_SECURITY 36 // Parameters: struct cred *cred, void *security
|
||
+#define IEE_OP_SET_CRED_RCU 37 // Parameters: struct cred *cred, struct rcu_head *rcu
|
||
+#define IEE_MEMSET 38 // Parameters: void *ptr, int data, size_t n
|
||
+#define IEE_OP_SET_TRACK 39 // Parameters: struct track *ptr, struct track *data
|
||
+#define IEE_OP_SET_FREEPTR 40 // Parameters: void **pptr, void *ptr
|
||
+#define IEE_OP_SET_PTE_U 41 // Parameters: pte_t *ptep, pte_t pte
|
||
+#define IEE_OP_SET_PTE_P 42 // Parameters: pte_t *ptep, pte_t pte
|
||
+#define IEE_SET_TOKEN_MM 43 // Parameters: struct task_token *token, struct mm_struct *mm
|
||
+#define IEE_SET_TOKEN_PGD 44 // Parameters: struct task_token *token, pgd_t *pgd
|
||
+#define IEE_INIT_TOKEN 45 // Parameters: struct task_struct *tsk, void *kernel_stack, void *iee_stack
|
||
+#define IEE_FREE_TOKEN 46 // Parameters: struct task_struct *tsk
|
||
+#define IEE_READ_TOKEN_STACK 47 // Parameters: struct task_struct *tsk
|
||
+#define IEE_WRITE_ENTRY_TASK 48 // Parameters: struct task_struct *tsk
|
||
+#define IEE_OP_SET_CRED_UCOUNTS 49 // Parameters: struct cred *cred, struct ucounts *ucounts
|
||
+#ifdef CONFIG_KOI
|
||
+#define IEE_READ_KOI_STACK 50 // Parameters: struct task_struct *tsk
|
||
+#define IEE_WRITE_KOI_STACK 51 // Parameters: struct task_struct *tsk, unsigned long koi_stack
|
||
+#define IEE_READ_TOKEN_TTBR1 52 // Parameters: struct task_struct *tsk
|
||
+#define IEE_WRITE_TOKEN_TTBR1 53 // Parameters: struct task_struct *tsk, unsigned long current_ttbr1
|
||
+#define IEE_READ_KOI_KERNEL_STACK 54 // Parameters: struct task_struct *tsk
|
||
+#define IEE_WRITE_KOI_KERNEL_STACK 55 // Parameters: struct task_struct *tsk, unsigned long kernel_stack
|
||
+#define IEE_READ_KOI_STACK_BASE 56 // Parameters: struct task_struct *tsk
|
||
+#define IEE_WRITE_KOI_STACK_BASE 57 // Parameters: struct task_struct *tsk, unsigned long koi_stack_base
|
||
+#endif
|
||
+
|
||
+/* Add new IEE ops here */
|
||
+
|
||
+#define AT_ADD 1
|
||
+#define AT_INC_NOT_ZERO 2
|
||
+#define AT_SUB_AND_TEST 3
|
||
+/* Atomic ops for atomic_t */
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+#define IEE_SWITCH_TO_KERNEL 7
|
||
+#define IEE_SWITCH_TO_KOI 8
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee-si.h b/arch/arm64/include/asm/iee-si.h
|
||
new file mode 100644
|
||
index 000000000000..e67d81db66a5
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-si.h
|
||
@@ -0,0 +1,64 @@
|
||
+#ifndef _LINUX_IEE_SI_H
|
||
+#define _LINUX_IEE_SI_H
|
||
+
|
||
+#include <asm/sysreg.h>
|
||
+#define __iee_si_code __section(".iee.si_text")
|
||
+#define __iee_si_data __section(".iee.si_data")
|
||
+
|
||
+/* Used for copying globals that iee rwx gate needs. */
|
||
+extern unsigned long iee_base_idmap_pg_dir;
|
||
+extern unsigned long iee_base_reserved_pg_dir;
|
||
+extern unsigned long iee_base__bp_harden_el1_vectors;
|
||
+extern bool iee_init_done;
|
||
+extern unsigned long iee_si_tcr;
|
||
+
|
||
+/* The following are __init functions used for iee si initialization. */
|
||
+extern void iee_si_prepare_data(void);
|
||
+
|
||
+extern unsigned long __iee_si_start[];
|
||
+// Handler function for sensitive inst
|
||
+u64 iee_si_handler(int flag, ...);
|
||
+/*
|
||
+ * TODO: scan a page to check whether it contains sensitive instructions
|
||
+ * return 1 when finding sensitive inst, 0 on safe page.
|
||
+ */
|
||
+extern int iee_si_scan_page(unsigned long addr);
|
||
+
|
||
+
|
||
+#define DBG_MDSCR_SS (1 << 0)
|
||
+#define DBG_MDSCR_MDE (1 << 15)
|
||
+
|
||
+#define IEE_SI_TEST 0
|
||
+#define IEE_WRITE_SCTLR 1
|
||
+#define IEE_WRITE_TTBR0 2
|
||
+#define IEE_WRITE_VBAR 3
|
||
+#define IEE_WRITE_TCR 4
|
||
+#define IEE_WRITE_MDSCR 5
|
||
+#define IEE_CONTEXT_SWITCH 6
|
||
+// #define IEE_WRITE_AFSR0 10
|
||
+/* Provide ttbr1 switch gate for KOI */
|
||
+#ifdef CONFIG_KOI
|
||
+#define IEE_SWITCH_TO_KERNEL 7
|
||
+#define IEE_SWITCH_TO_KOI 8
|
||
+#endif
|
||
+/* MASK modify-permitted bits on IEE protected sys registers */
|
||
+#define IEE_SCTLR_MASK (SCTLR_EL1_CP15BEN | SCTLR_EL1_SED | SCTLR_EL1_UCT | SCTLR_EL1_UCI |\
|
||
+ SCTLR_EL1_BT0 | SCTLR_EL1_BT1 | SCTLR_EL1_TCF0_MASK | SCTLR_ELx_DSSBS |\
|
||
+ SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB|\
|
||
+ SCTLR_EL1_SPINTMASK | SCTLR_EL1_NMI | SCTLR_EL1_TIDCP | SCTLR_EL1_MSCEn|\
|
||
+ SCTLR_ELx_ENTP2 | SCTLR_EL1_TCF_MASK)
|
||
+#define IEE_TTBR0_MASK ~0
|
||
+#define IEE_TTBR1_MASK ~0
|
||
+#define IEE_TCR_MASK (TCR_HD | TCR_T0SZ_MASK | TCR_E0PD1)
|
||
+#define IEE_MDSCR_MASK (DBG_MDSCR_SS | DBG_MDSCR_MDE)
|
||
+
|
||
+#define IEE_DBGBCR_BT 0b0000 << 20
|
||
+#define IEE_DBGBCR_SSC 0b00 << 14
|
||
+#define IEE_DBGBCR_HMC 0b1 << 13
|
||
+#define IEE_DBGBCR_BAS 0b1111 << 5
|
||
+#define IEE_DBGBCR_PMC 0b11 << 1
|
||
+#define IEE_DBGBCR_E 0b1
|
||
+#define IEE_DBGBCR IEE_DBGBCR_BT | IEE_DBGBCR_SSC | IEE_DBGBCR_HMC | IEE_DBGBCR_BAS \
|
||
+ | IEE_DBGBCR_PMC | IEE_DBGBCR_E
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee-slab.h b/arch/arm64/include/asm/iee-slab.h
|
||
new file mode 100644
|
||
index 000000000000..4f3c17c7da00
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-slab.h
|
||
@@ -0,0 +1,23 @@
|
||
+#ifndef _LINUX_IEE_SLAB_H
|
||
+#define _LINUX_IEE_SLAB_H
|
||
+/*
|
||
+ * Tracking user of a slab.
|
||
+ */
|
||
+#include <linux/stackdepot.h>
|
||
+
|
||
+#define TRACK_ADDRS_COUNT 16
|
||
+struct track {
|
||
+ unsigned long addr; /* Called from address */
|
||
+#ifdef CONFIG_STACKDEPOT
|
||
+ depot_stack_handle_t handle;
|
||
+#endif
|
||
+ int cpu; /* Was running on cpu */
|
||
+ int pid; /* Pid context */
|
||
+ unsigned long when; /* When did the operation occur */
|
||
+};
|
||
+
|
||
+enum track_item { TRACK_ALLOC, TRACK_FREE };
|
||
+
|
||
+typedef struct { unsigned long v; } freeptr_t;
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee-token.h b/arch/arm64/include/asm/iee-token.h
|
||
new file mode 100644
|
||
index 000000000000..152474e1a187
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee-token.h
|
||
@@ -0,0 +1,40 @@
|
||
+#ifndef _LINUX_IEE_TOKEN_H
|
||
+#define _LINUX_IEE_TOKEN_H
|
||
+
|
||
+#include <asm/iee-def.h>
|
||
+
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+struct task_token;
|
||
+struct task_struct;
|
||
+struct mm_struct;
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+void iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm)
|
||
+{
|
||
+ iee_rw_gate(IEE_SET_TOKEN_MM, tsk, mm);
|
||
+}
|
||
+
|
||
+void iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd)
|
||
+{
|
||
+ iee_rw_gate(IEE_SET_TOKEN_PGD, tsk, pgd);
|
||
+}
|
||
+
|
||
+void iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack)
|
||
+{
|
||
+ iee_rw_gate(IEE_INIT_TOKEN, tsk, kernel_stack, iee_stack);
|
||
+}
|
||
+
|
||
+void iee_free_token(struct task_struct *tsk)
|
||
+{
|
||
+ iee_rw_gate(IEE_FREE_TOKEN, tsk);
|
||
+}
|
||
+
|
||
+unsigned long iee_read_token_stack(struct task_struct *tsk)
|
||
+{
|
||
+ unsigned long ret;
|
||
+ ret = iee_rw_gate(IEE_READ_TOKEN_STACK, tsk);
|
||
+ return ret;
|
||
+}
|
||
+#endif
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/iee.h b/arch/arm64/include/asm/iee.h
|
||
new file mode 100644
|
||
index 000000000000..598f6d0b2626
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/iee.h
|
||
@@ -0,0 +1,10 @@
|
||
+#ifndef _LINUX_IEE_H
|
||
+#define _LINUX_IEE_H
|
||
+#define __iee_code __section(".iee.text")
|
||
+#define __iee_header __section(".iee.text.header")
|
||
+
|
||
+u64 iee_dispatch(int flag, ...);
|
||
+
|
||
+#include <asm/iee-def.h>
|
||
+
|
||
+#endif
|
||
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
|
||
index 85d26143faa5..e7a3081ce285 100644
|
||
--- a/arch/arm64/include/asm/kernel-pgtable.h
|
||
+++ b/arch/arm64/include/asm/kernel-pgtable.h
|
||
@@ -118,4 +118,25 @@
|
||
#define SWAPPER_RX_MMUFLAGS (SWAPPER_RW_MMUFLAGS | PTE_RDONLY)
|
||
#endif
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+#ifdef CONFIG_ARM64_4K_PAGES // zgcXXX: it has been deleted in 6.6.
|
||
+#define ARM64_SWAPPER_USES_SECTION_MAPS 1
|
||
+#else
|
||
+#define ARM64_SWAPPER_USES_SECTION_MAPS 0
|
||
+#endif
|
||
+
|
||
+#define SWAPPER_MM_MMUFLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS) // zgcXXX: warning: 6.6 delete this macro. should delete this line later.
|
||
+
|
||
+#define SWAPPER_PTE_FLAGS_IDMAP (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED | PTE_RDONLY)
|
||
+#define SWAPPER_PMD_FLAGS_IDMAP (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S | PMD_SECT_RDONLY)
|
||
+
|
||
+#if ARM64_SWAPPER_USES_SECTION_MAPS
|
||
+#define SWAPPER_MM_MMUFLAGS_IDMAP (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS_IDMAP)
|
||
+#else
|
||
+#define SWAPPER_MM_MMUFLAGS_IDMAP (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS_IDMAP)
|
||
+#endif
|
||
+
|
||
+#endif
|
||
+
|
||
#endif /* __ASM_KERNEL_PGTABLE_H */
|
||
diff --git a/arch/arm64/include/asm/koi.h b/arch/arm64/include/asm/koi.h
|
||
new file mode 100644
|
||
index 000000000000..48d9a1378a1d
|
||
--- /dev/null
|
||
+++ b/arch/arm64/include/asm/koi.h
|
||
@@ -0,0 +1,335 @@
|
||
+#include "linux/mm.h"
|
||
+#include "asm/current.h"
|
||
+#include "asm/pgtable-hwdef.h"
|
||
+#include "asm/pgtable-types.h"
|
||
+#include "asm/pgtable.h"
|
||
+#include "linux/mm_types.h"
|
||
+#include "linux/pgtable.h"
|
||
+#include "linux/printk.h"
|
||
+#include "linux/slab.h"
|
||
+#include "linux/string.h"
|
||
+#include <linux/sched.h>
|
||
+#include "linux/hashtable.h"
|
||
+#include "linux/module.h"
|
||
+#include "linux/vmalloc.h"
|
||
+#include "stacktrace.h"
|
||
+#include "asm/mmu.h"
|
||
+#ifdef CONFIG_IEE
|
||
+#include "asm/iee-si.h"
|
||
+#include "asm/iee-def.h"
|
||
+#endif
|
||
+
|
||
+#define HASH_TABLE_BIT 10
|
||
+#define HASH_TABLE_LEN (1 << HASH_TABLE_BIT)
|
||
+#define HASH_KEY_MASK ((1 << HASH_TABLE_BIT) - 1)
|
||
+
|
||
+#define MAX_VAR_NAME 64
|
||
+#define DRIVER_ISOLATION_VAR_ARRAY_SIZE 32
|
||
+#define DRIVER_ISOLATION_MAX_VAL 256
|
||
+
|
||
+extern struct hlist_head koi_mem_htbl[1024];
|
||
+extern spinlock_t koi_mem_htbl_spin_lock;
|
||
+extern unsigned long koi_swapper_ttbr1;
|
||
+extern s64 koi_offset;
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+#endif
|
||
+
|
||
+DECLARE_PER_CPU(unsigned long[PAGE_SIZE / sizeof(unsigned long)],
|
||
+ koi_irq_current_ttbr1);
|
||
+
|
||
+/**
|
||
+* struct koi_mem_hash_node -
|
||
+*@mod:pointer to driver module
|
||
+*@mem_list_head:free memory list head
|
||
+*@ko_mm: mm_struct in each driver
|
||
+*@pgdp:entry to Page Global Directory :pgd
|
||
+*@node:hash linked list node
|
||
+*@addr_htbl[1 << (HASH_TABLE_BIT)]:
|
||
+*@rcu:
|
||
+*/
|
||
+struct koi_mem_hash_node {
|
||
+ struct module *mod;
|
||
+ struct list_head mem_list_head;
|
||
+ struct mm_struct *ko_mm;
|
||
+ pgd_t *pgdp;
|
||
+ unsigned long ko_ttbr1;
|
||
+ struct hlist_node node;
|
||
+ struct hlist_head addr_htbl[1 << (HASH_TABLE_BIT)];
|
||
+ struct rcu_head rcu;
|
||
+ // used to protect free mem list
|
||
+ spinlock_t spin_lock;
|
||
+ // used to protect addr hashtable
|
||
+ spinlock_t addr_htbl_spin_lock;
|
||
+};
|
||
+//describe the global shared var
|
||
+struct shared_variable_descriptor {
|
||
+ unsigned int id;
|
||
+ unsigned int type;
|
||
+ char name[MAX_VAR_NAME];
|
||
+ unsigned long offset;
|
||
+ unsigned int size;
|
||
+ unsigned int self_ptr_ids[DRIVER_ISOLATION_VAR_ARRAY_SIZE];
|
||
+};
|
||
+
|
||
+int koi_do_switch_to_kernel_pgtbl(void);
|
||
+
|
||
+int koi_copy_pagetable(struct mm_struct *ko_mm, pgd_t *koi_pg_dir,
|
||
+ unsigned long addr, unsigned long end);
|
||
+
|
||
+void koi_create_pagetable(struct module *mod);
|
||
+
|
||
+void koi_map_kostack(struct module *mod);
|
||
+unsigned long koi_mem_alloc(struct module *mod, unsigned long orig_addr,
|
||
+ unsigned long size);
|
||
+void koi_mem_free(struct module *mod, unsigned long addr, unsigned long size,
|
||
+ bool is_const, int count, ...);
|
||
+void *koi_mem_lookup(struct module *mod, unsigned long addr);
|
||
+void koi_mem_free_callback(struct module *mod, unsigned long addr,
|
||
+ unsigned long size, void (*func)(void *));
|
||
+void koi_map_mem(struct module *mod, unsigned long addr, unsigned long size);
|
||
+void koi_mem_free_to_user(struct module *mod, unsigned long addr,
|
||
+ unsigned long size);
|
||
+
|
||
+unsigned long koi_ttbr_ctor(struct module *mod);
|
||
+extern void koi_do_switch_to_kernel_stack(void);
|
||
+extern void koi_do_switch_to_ko_stack(void);
|
||
+
|
||
+#define switch_pgtable(ttbr1) \
|
||
+ do { \
|
||
+ write_sysreg(ttbr1, ttbr1_el1); \
|
||
+ isb(); \
|
||
+ asm volatile(ALTERNATIVE("nop; nop; nop", \
|
||
+ "ic iallu; dsb nsh; isb", \
|
||
+ ARM64_WORKAROUND_CAVIUM_27456)); \
|
||
+ } while (0);
|
||
+
|
||
+#ifndef CONFIG_IEE
|
||
+#define koi_switch_to_ko() \
|
||
+ do { \
|
||
+ unsigned long flags, ko_ttbr1, cur_sp; \
|
||
+ unsigned long *ptr; \
|
||
+ struct task_token *token; \
|
||
+ asm volatile("mrs %0, daif\n" \
|
||
+ "msr daifset, #2\n" \
|
||
+ "isb\n" \
|
||
+ "mov %1, sp\n" \
|
||
+ : "=r"(flags), "=r"(cur_sp) \
|
||
+ :); \
|
||
+ if (!on_irq_stack(cur_sp, NULL)) { \
|
||
+ koi_do_switch_to_ko_stack(); \
|
||
+ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
|
||
+ token = (struct task_token *)((unsigned long)current + \
|
||
+ koi_offset); \
|
||
+ token->current_ttbr1 = ko_ttbr1 & (~TTBR_ASID_MASK); \
|
||
+ } else { \
|
||
+ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
|
||
+ __kern_my_cpu_offset()); \
|
||
+ *ptr = ko_ttbr1 & ~(TTBR_ASID_MASK); \
|
||
+ } \
|
||
+ switch_pgtable(ko_ttbr1); \
|
||
+ asm volatile("msr daif, %0\n" \
|
||
+ "isb\n" \
|
||
+ : \
|
||
+ : "r"(flags)); \
|
||
+ } while (0);
|
||
+
|
||
+#define koi_switch_to_kernel() \
|
||
+ do { \
|
||
+ unsigned long cur_sp, flags, asid; \
|
||
+ unsigned long *ptr; \
|
||
+ struct task_token *token; \
|
||
+ asm volatile("mrs %0, daif\n" \
|
||
+ "msr daifset, #2\n" \
|
||
+ "isb\n" \
|
||
+ "mov %1, sp\n" \
|
||
+ "mov %2, ttbr0_el1\n" \
|
||
+ : "=r"(flags), "=r"(cur_sp), "=r"(asid) \
|
||
+ :); \
|
||
+ asid &= ~USER_ASID_FLAG; \
|
||
+ asid &= TTBR_ASID_MASK; \
|
||
+ switch_pgtable(koi_swapper_ttbr1); \
|
||
+ if (!on_irq_stack(cur_sp, NULL)) { \
|
||
+ token = (struct task_token *)((unsigned long)current + \
|
||
+ koi_offset); \
|
||
+ token->current_ttbr1 = koi_swapper_ttbr1; \
|
||
+ koi_do_switch_to_kernel_stack(); \
|
||
+ } else { \
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
|
||
+ __kern_my_cpu_offset()); \
|
||
+ *ptr = koi_swapper_ttbr1; \
|
||
+ } \
|
||
+ asm volatile("msr daif, %0\n" \
|
||
+ "isb\n" \
|
||
+ : \
|
||
+ : "r"(flags)); \
|
||
+ } while (0);
|
||
+#else
|
||
+#define koi_switch_to_ko() \
|
||
+ do { \
|
||
+ unsigned long cur_sp, flags, ko_ttbr1; \
|
||
+ unsigned long *ptr; \
|
||
+ asm volatile("mrs %0, daif\n" \
|
||
+ "msr daifset, #2\n" \
|
||
+ "isb\n" \
|
||
+ "mov %1, sp\n" \
|
||
+ : "=r"(flags), "=r"(cur_sp) \
|
||
+ :); \
|
||
+ if (!on_irq_stack(cur_sp, NULL)) { \
|
||
+ koi_do_switch_to_ko_stack(); \
|
||
+ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
|
||
+ iee_rw_gate(IEE_WRITE_TOKEN_TTBR1, current, \
|
||
+ ko_ttbr1 &(~TTBR_ASID_MASK)); \
|
||
+ } else { \
|
||
+ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
|
||
+ __kern_my_cpu_offset()); \
|
||
+ *ptr = ko_ttbr1 & (~TTBR_ASID_MASK); \
|
||
+ } \
|
||
+ iee_rwx_gate_entry(IEE_SWITCH_TO_KOI, ko_ttbr1); \
|
||
+ asm volatile("msr daif, %0\n" \
|
||
+ "isb\n" \
|
||
+ : \
|
||
+ : "r"(flags)); \
|
||
+ } while (0);
|
||
+
|
||
+#define koi_switch_to_kernel() \
|
||
+ do { \
|
||
+ unsigned long flags, cur_sp; \
|
||
+ unsigned long *ptr; \
|
||
+ asm volatile("mrs %0, daif\n" \
|
||
+ "msr daifset, #2\n" \
|
||
+ "isb\n" \
|
||
+ "mov %1, sp\n" \
|
||
+ : "=r"(flags), "=r"(cur_sp) \
|
||
+ :); \
|
||
+ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL); \
|
||
+ if (!on_irq_stack(cur_sp, NULL)) { \
|
||
+ iee_rw_gate(IEE_WRITE_TOKEN_TTBR1, current, \
|
||
+ koi_swapper_ttbr1); \
|
||
+ koi_do_switch_to_kernel_stack(); \
|
||
+ } else { \
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
|
||
+ __kern_my_cpu_offset()); \
|
||
+ *ptr = koi_swapper_ttbr1; \
|
||
+ } \
|
||
+ asm volatile("msr daif, %0\n" \
|
||
+ "isb\n" \
|
||
+ : \
|
||
+ : "r"(flags)); \
|
||
+ } while (0);
|
||
+#endif
|
||
+//kzalloc function in driver space
|
||
+static __maybe_unused noinline void *
|
||
+koi_kzalloc_wrapper(struct module *mod, size_t size, gfp_t flags)
|
||
+{
|
||
+ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
+ void *addr;
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ koi_switch_to_kernel();
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk("mem node for module: %s not found\n", mod->name);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ addr = kzalloc(size, flags);
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
|
||
+ (unsigned long)addr + PAGE_SIZE * cnt);
|
||
+ koi_switch_to_ko();
|
||
+ return addr;
|
||
+}
|
||
+//kmalloc function in driver space
|
||
+static __maybe_unused __always_inline void *
|
||
+koi_kmalloc_wrapper(struct module *mod, size_t size, gfp_t flags)
|
||
+{
|
||
+ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
+ void *addr;
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ koi_switch_to_kernel();
|
||
+
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk("mem node for module: %s not found\n", mod->name);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ addr = kmalloc(cnt * PAGE_SIZE, flags);
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
|
||
+ (unsigned long)addr + PAGE_SIZE * cnt);
|
||
+ koi_switch_to_ko();
|
||
+ return (void *)addr;
|
||
+}
|
||
+//vmalloc function in driver space
|
||
+static __maybe_unused void *koi_vmalloc_wrapper(struct module *mod,
|
||
+ unsigned long size)
|
||
+{
|
||
+ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
+ void *addr;
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ koi_switch_to_kernel();
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk("mem node for module: %s not found\n", mod->name);
|
||
+ koi_switch_to_ko();
|
||
+ return 0;
|
||
+ }
|
||
+ addr = vmalloc(cnt * PAGE_SIZE);
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
|
||
+ (unsigned long)addr + PAGE_SIZE * cnt);
|
||
+ koi_switch_to_ko();
|
||
+ return addr;
|
||
+}
|
||
+//kmalloc_array function in driver space
|
||
+static __maybe_unused void *koi_kmalloc_array_wrapper(struct module *mod,
|
||
+ size_t n, size_t size,
|
||
+ gfp_t flags)
|
||
+{
|
||
+ int kpage;
|
||
+ void *addr;
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ koi_switch_to_kernel();
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk("mem node for module: %s not found\n", mod->name);
|
||
+ koi_switch_to_ko();
|
||
+ return 0;
|
||
+ }
|
||
+ kpage = (n * size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||
+ n = (kpage * PAGE_SIZE) / size;
|
||
+ addr = kmalloc_array(n, size, flags);
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
|
||
+ (unsigned long)addr + PAGE_SIZE * kpage);
|
||
+ koi_switch_to_ko();
|
||
+ return addr;
|
||
+}
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
|
||
index fde4186cc387..6309e5514a16 100644
|
||
--- a/arch/arm64/include/asm/memory.h
|
||
+++ b/arch/arm64/include/asm/memory.h
|
||
@@ -190,6 +190,13 @@ extern u64 vabits_actual;
|
||
#endif
|
||
|
||
extern s64 memstart_addr;
|
||
+
|
||
+#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+extern s64 memstart_addr_init;
|
||
+extern s64 iee_offset;
|
||
+#define LOGICAL_RANDOM (long long int)((long unsigned int)__va(memstart_addr_init) & (~PAGE_OFFSET))
|
||
+#endif
|
||
+
|
||
/* PHYS_OFFSET - the physical address of the start of memory. */
|
||
#define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
|
||
|
||
@@ -310,6 +317,23 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
|
||
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
|
||
#define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+#define KOI_OFFSET ((unsigned long)BIT(vabits_actual - 2))
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+#ifdef CONFIG_IEE_OFFSET
|
||
+#define IEE_OFFSET ((CONFIG_IEE_OFFSET) - LOGICAL_RANDOM)
|
||
+#else
|
||
+#define IEE_OFFSET (((unsigned long)BIT(vabits_actual - 2)) - LOGICAL_RANDOM)
|
||
+#endif
|
||
+#define __phys_to_iee(x) (__phys_to_virt(x) + IEE_OFFSET)
|
||
+#define SET_UPAGE(x) __pgprot(pgprot_val(x) | PTE_USER)
|
||
+#define SET_PPAGE(x) __pgprot(pgprot_val(x) & (~PTE_USER))
|
||
+#define SET_INVALID(x) __pgprot(pgprot_val(x) & (~PTE_VALID))
|
||
+#define SET_NG(x) __pgprot(pgprot_val(x) | PTE_NG)
|
||
+#endif
|
||
+
|
||
/*
|
||
* Convert a page to/from a physical address
|
||
*/
|
||
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
|
||
index a6fb325424e7..cca5994dabfb 100644
|
||
--- a/arch/arm64/include/asm/mmu_context.h
|
||
+++ b/arch/arm64/include/asm/mmu_context.h
|
||
@@ -24,6 +24,9 @@
|
||
#include <asm/cputype.h>
|
||
#include <asm/sysreg.h>
|
||
#include <asm/tlbflush.h>
|
||
+#ifdef CONFIG_IEE
|
||
+#define INIT_ASID 0x2
|
||
+#endif
|
||
|
||
extern bool rodata_full;
|
||
|
||
@@ -43,7 +46,12 @@ static inline void cpu_set_reserved_ttbr0_nosync(void)
|
||
{
|
||
unsigned long ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ ttbr |= FIELD_PREP(TTBR_ASID_MASK, 1);
|
||
+ iee_rwx_gate_entry(IEE_WRITE_ttbr0_el1, ttbr);
|
||
+#else
|
||
write_sysreg(ttbr, ttbr0_el1);
|
||
+#endif
|
||
}
|
||
|
||
static inline void cpu_set_reserved_ttbr0(void)
|
||
@@ -79,7 +87,11 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
|
||
|
||
tcr &= ~TCR_T0SZ_MASK;
|
||
tcr |= t0sz << TCR_T0SZ_OFFSET;
|
||
+#ifdef CONFIG_IEE
|
||
+ iee_rwx_gate_entry(IEE_WRITE_tcr_el1, tcr);
|
||
+#else
|
||
write_sysreg(tcr, tcr_el1);
|
||
+#endif
|
||
isb();
|
||
}
|
||
|
||
@@ -144,7 +156,11 @@ static inline void cpu_install_ttbr0(phys_addr_t ttbr0, unsigned long t0sz)
|
||
__cpu_set_tcr_t0sz(t0sz);
|
||
|
||
/* avoid cpu_switch_mm() and its SW-PAN and CNP interactions */
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_rwx_gate_entry(IEE_WRITE_ttbr0_el1, ttbr0);
|
||
+ #else
|
||
write_sysreg(ttbr0, ttbr0_el1);
|
||
+ #endif
|
||
isb();
|
||
}
|
||
|
||
@@ -174,6 +190,10 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
|
||
ttbr1 |= TTBR_CNP_BIT;
|
||
}
|
||
|
||
+ #ifdef CONFIG_IEE
|
||
+ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, ASID(current->active_mm));
|
||
+ #endif
|
||
+
|
||
replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
|
||
|
||
__cpu_install_idmap(idmap);
|
||
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
|
||
index 237224484d0f..4e3304da8421 100644
|
||
--- a/arch/arm64/include/asm/pgalloc.h
|
||
+++ b/arch/arm64/include/asm/pgalloc.h
|
||
@@ -63,6 +63,10 @@ static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
|
||
extern pgd_t *pgd_alloc(struct mm_struct *mm);
|
||
extern void pgd_free(struct mm_struct *mm, pgd_t *pgdp);
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+pgd_t *koi_pgd_alloc(void);
|
||
+#endif
|
||
+
|
||
static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
|
||
pmdval_t prot)
|
||
{
|
||
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
|
||
index e4944d517c99..7f60e568c964 100644
|
||
--- a/arch/arm64/include/asm/pgtable-hwdef.h
|
||
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
|
||
@@ -84,6 +84,13 @@
|
||
#define CONT_PMD_SIZE (CONT_PMDS * PMD_SIZE)
|
||
#define CONT_PMD_MASK (~(CONT_PMD_SIZE - 1))
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#define PGD_APT_RO (_AT(pudval_t, 1) << 62)
|
||
+#endif
|
||
+#define PGD_APT (_AT(pudval_t, 1) << 61)
|
||
+#define PGD_PXN (_AT(pudval_t, 1) << 59)
|
||
+#define PGD_UXN (_AT(pudval_t, 1) << 60)
|
||
+
|
||
/*
|
||
* Hardware page table definitions.
|
||
*
|
||
@@ -285,6 +292,10 @@
|
||
#define TCR_TCMA0 (UL(1) << 57)
|
||
#define TCR_TCMA1 (UL(1) << 58)
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#define TCR_HPD1 (UL(1) << 42)
|
||
+#endif
|
||
+
|
||
/*
|
||
* TTBR.
|
||
*/
|
||
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
|
||
index 8d68d00de0a4..6f8d5b85bfd7 100644
|
||
--- a/arch/arm64/include/asm/pgtable.h
|
||
+++ b/arch/arm64/include/asm/pgtable.h
|
||
@@ -34,6 +34,9 @@
|
||
#include <linux/mm_types.h>
|
||
#include <linux/sched.h>
|
||
#include <linux/page_table_check.h>
|
||
+#ifdef CONFIG_PTP
|
||
+#include <asm/iee.h>
|
||
+#endif
|
||
|
||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||
#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
|
||
@@ -156,6 +159,30 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
|
||
#define pud_access_permitted(pud, write) \
|
||
(pte_access_permitted(pud_pte(pud), (write)))
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+static inline bool in_tramp_pgdir(void *addr);
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+
|
||
+static void iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_TRAMP_PGD, pgdp, pgd);
|
||
+}
|
||
+
|
||
+static noinline pteval_t iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval)
|
||
+{
|
||
+ pteval_t ret;
|
||
+ ret = iee_rw_gate(IEE_OP_SET_XCHG, ptep, pteval);
|
||
+ return (pteval_t)ret;
|
||
+}
|
||
+
|
||
+static noinline pteval_t iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval)
|
||
+{
|
||
+ pteval_t ret;
|
||
+ ret = iee_rw_gate(IEE_OP_SET_CMPXCHG, ptep, old_pteval, new_pteval);
|
||
+ return (pteval_t)ret;
|
||
+}
|
||
+#endif
|
||
+
|
||
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
|
||
{
|
||
pte_val(pte) &= ~pgprot_val(prot);
|
||
@@ -262,6 +289,64 @@ static inline pte_t pte_mkdevmap(pte_t pte)
|
||
|
||
static inline void __set_pte(pte_t *ptep, pte_t pte)
|
||
{
|
||
+#ifdef CONFIG_KOI
|
||
+ if (!pte_none(pte)) {
|
||
+ pte = __pte(pte_val(pte) | PTE_NG);
|
||
+ }
|
||
+#endif
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_rw_gate(IEE_OP_SET_PTE, ptep, pte);
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+#else
|
||
+ WRITE_ONCE(*ptep, pte);
|
||
+
|
||
+ /*
|
||
+ * Only if the new pte is valid and kernel, otherwise TLB maintenance
|
||
+ * or update_mmu_cache() have the necessary barriers.
|
||
+ */
|
||
+ if (pte_valid_not_user(pte)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+#endif
|
||
+}
|
||
+
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+static inline void iee_set_bm_pte(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ // If it is pre init, write once.
|
||
+ // Else, write once will cause exception. So it is safe.
|
||
+ unsigned long flags;
|
||
+ unsigned long res;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile("at s1e1r, %0"::"r"(__phys_to_iee(__pa_symbol(ptep))));
|
||
+ isb();
|
||
+ res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+ if(res & 0x1)
|
||
+ WRITE_ONCE(*ptep,pte);
|
||
+ else
|
||
+ iee_rw_gate(IEE_OP_SET_BM_PTE, ptep, pte);
|
||
+
|
||
+ /*
|
||
+ * Only if the new pte is valid and kernel, otherwise TLB maintenance
|
||
+ * or update_mmu_cache() have the necessary barriers.
|
||
+ */
|
||
+ if (pte_valid_not_user(pte)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
+
|
||
+static inline void iee_set_fixmap_pte_pre_init(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+#ifdef CONFIG_KOI
|
||
+ if (!pte_none(pte)) {
|
||
+ pte = __pte(pte_val(pte) | PTE_NG);
|
||
+ }
|
||
+#endif
|
||
WRITE_ONCE(*ptep, pte);
|
||
|
||
/*
|
||
@@ -273,6 +358,7 @@ static inline void __set_pte(pte_t *ptep, pte_t pte)
|
||
isb();
|
||
}
|
||
}
|
||
+#endif
|
||
|
||
static inline pte_t __ptep_get(pte_t *ptep)
|
||
{
|
||
@@ -546,6 +632,95 @@ static inline void __set_pte_at(struct mm_struct *mm,
|
||
__set_pte(ptep, pte);
|
||
}
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+static inline void iee_set_pte_upage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_rw_gate(IEE_OP_SET_PTE_U, ptep, pte);
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+#else
|
||
+ WRITE_ONCE(*ptep, pte);
|
||
+ if (pte_valid_not_user(pte)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+#endif
|
||
+}
|
||
+
|
||
+static inline void iee_set_pte_ppage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_rw_gate(IEE_OP_SET_PTE_P, ptep, pte);
|
||
+#else
|
||
+ WRITE_ONCE(*ptep, pte);
|
||
+#endif
|
||
+ if (pte_valid_not_user(pte)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmd);
|
||
+static inline void __set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||
+ pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+ if (pte_present(pmd_pte(pmd)) && pte_user_exec(pmd_pte(pmd)) && !pte_special(pmd_pte(pmd)))
|
||
+ __sync_icache_dcache(pmd_pte(pmd));
|
||
+
|
||
+ /*
|
||
+ * If the PTE would provide user space access to the tags associated
|
||
+ * with it then ensure that the MTE tags are synchronised. Although
|
||
+ * pte_access_permitted() returns false for exec only mappings, they
|
||
+ * don't expose tags (instruction fetches don't check tags).
|
||
+ */
|
||
+ if (system_supports_mte() && pte_access_permitted(pmd_pte(pmd), false) &&
|
||
+ !pte_special(pmd_pte(pmd)) && pte_tagged(pmd_pte(pmd)))
|
||
+ mte_sync_tags(pmd_pte(pmd), PMD_SIZE >> PAGE_SHIFT);
|
||
+
|
||
+ __check_safe_pte_update(mm, (pte_t *)pmdp, pmd_pte(pmd));
|
||
+
|
||
+ set_pmd(pmdp, pmd);
|
||
+}
|
||
+
|
||
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||
+ pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+ page_table_check_pmd_set(mm, pmdp, pmd);
|
||
+ return __set_pmd_at(mm, addr, pmdp, pmd);
|
||
+}
|
||
+
|
||
+static inline void set_pud(pud_t *pudp, pud_t pud);
|
||
+static inline void __set_pud_at(struct mm_struct *mm, unsigned long addr,
|
||
+ pud_t *pudp, pud_t pud)
|
||
+{
|
||
+ if (pte_present(pud_pte(pud)) && pte_user_exec(pud_pte(pud)) && !pte_special(pud_pte(pud)))
|
||
+ __sync_icache_dcache(pud_pte(pud));
|
||
+
|
||
+ /*
|
||
+ * If the PTE would provide user space access to the tags associated
|
||
+ * with it then ensure that the MTE tags are synchronised. Although
|
||
+ * pte_access_permitted() returns false for exec only mappings, they
|
||
+ * don't expose tags (instruction fetches don't check tags).
|
||
+ */
|
||
+ if (system_supports_mte() && pte_access_permitted(pud_pte(pud), false) &&
|
||
+ !pte_special(pud_pte(pud)) && pte_tagged(pud_pte(pud)))
|
||
+ mte_sync_tags(pud_pte(pud), PUD_SIZE >> PAGE_SHIFT);
|
||
+
|
||
+ __check_safe_pte_update(mm, (pte_t *)pudp, pud_pte(pud));
|
||
+
|
||
+ set_pud(pudp, pud);
|
||
+}
|
||
+
|
||
+static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
|
||
+ pud_t *pudp, pud_t pud)
|
||
+{
|
||
+ page_table_check_pud_set(mm, pudp, pud);
|
||
+ return __set_pud_at(mm, addr, pudp, pud);
|
||
+}
|
||
+#else
|
||
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||
pmd_t *pmdp, pmd_t pmd)
|
||
{
|
||
@@ -561,7 +736,7 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
|
||
return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud),
|
||
PUD_SIZE >> PAGE_SHIFT);
|
||
}
|
||
-
|
||
+#endif
|
||
#define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d))
|
||
#define __phys_to_p4d_val(phys) __phys_to_pte_val(phys)
|
||
|
||
@@ -640,7 +815,14 @@ static inline bool in_swapper_pgdir(void *addr)
|
||
((unsigned long)swapper_pg_dir & PAGE_MASK);
|
||
}
|
||
|
||
-static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||
+#ifdef CONFIG_PTP
|
||
+static inline bool in_tramp_pgdir(void *addr)
|
||
+{
|
||
+ return ((unsigned long)addr & PAGE_MASK) ==
|
||
+ ((unsigned long)tramp_pg_dir & PAGE_MASK);
|
||
+}
|
||
+
|
||
+static inline void iee_set_fixmap_pmd_pre_init(pmd_t *pmdp, pmd_t pmd)
|
||
{
|
||
#ifdef __PAGETABLE_PMD_FOLDED
|
||
if (in_swapper_pgdir(pmdp)) {
|
||
@@ -648,7 +830,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||
return;
|
||
}
|
||
#endif /* __PAGETABLE_PMD_FOLDED */
|
||
-
|
||
WRITE_ONCE(*pmdp, pmd);
|
||
|
||
if (pmd_valid(pmd)) {
|
||
@@ -656,6 +837,32 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||
isb();
|
||
}
|
||
}
|
||
+#endif
|
||
+
|
||
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+#ifdef __PAGETABLE_PMD_FOLDED
|
||
+ if (in_swapper_pgdir(pmdp)) {
|
||
+ set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
|
||
+ return;
|
||
+ }
|
||
+#endif /* __PAGETABLE_PMD_FOLDED */
|
||
+#ifdef CONFIG_KOI
|
||
+ pmdval_t val = pmd_val(pmd);
|
||
+ if (pmd_valid(pmd) && !(val & PMD_TABLE_BIT)) {
|
||
+ pmd = __pmd(val | PMD_SECT_NG);
|
||
+ }
|
||
+#endif
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_rw_gate(IEE_OP_SET_PMD, pmdp, pmd);
|
||
+#else
|
||
+ WRITE_ONCE(*pmdp, pmd);
|
||
+#endif
|
||
+ if (pmd_valid(pmd)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
|
||
static inline void pmd_clear(pmd_t *pmdp)
|
||
{
|
||
@@ -675,6 +882,12 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
||
/* Find an entry in the third-level page table. */
|
||
#define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#define pte_set_fixmap_init(addr) ((pte_t *)iee_set_fixmap_offset_pre_init(FIX_PTE, addr))
|
||
+#define pte_set_fixmap_offset_init(pmd, addr) pte_set_fixmap_init(pte_offset_phys(pmd, addr))
|
||
+#define pte_clear_fixmap_init() clear_fixmap_init(FIX_PTE)
|
||
+#endif
|
||
+
|
||
#define pte_set_fixmap(addr) ((pte_t *)set_fixmap_offset(FIX_PTE, addr))
|
||
#define pte_set_fixmap_offset(pmd, addr) pte_set_fixmap(pte_offset_phys(pmd, addr))
|
||
#define pte_clear_fixmap() clear_fixmap(FIX_PTE)
|
||
@@ -703,7 +916,9 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
||
#define pud_user(pud) pte_user(pud_pte(pud))
|
||
#define pud_user_exec(pud) pte_user_exec(pud_pte(pud))
|
||
|
||
-static inline void set_pud(pud_t *pudp, pud_t pud)
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+static inline void iee_set_fixmap_pud_pre_init(pud_t *pudp, pud_t pud)
|
||
{
|
||
#ifdef __PAGETABLE_PUD_FOLDED
|
||
if (in_swapper_pgdir(pudp)) {
|
||
@@ -711,7 +926,6 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
|
||
return;
|
||
}
|
||
#endif /* __PAGETABLE_PUD_FOLDED */
|
||
-
|
||
WRITE_ONCE(*pudp, pud);
|
||
|
||
if (pud_valid(pud)) {
|
||
@@ -719,6 +933,33 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
|
||
isb();
|
||
}
|
||
}
|
||
+#endif
|
||
+
|
||
+static inline void set_pud(pud_t *pudp, pud_t pud)
|
||
+{
|
||
+#ifdef __PAGETABLE_PUD_FOLDED
|
||
+ if (in_swapper_pgdir(pudp)) {
|
||
+ set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud)));
|
||
+ return;
|
||
+ }
|
||
+#endif /* __PAGETABLE_PUD_FOLDED */
|
||
+#ifdef CONFIG_KOI
|
||
+ pudval_t val = pud_val(pud);
|
||
+ if (pud_valid(pud) && !(val & PUD_TABLE_BIT)) {
|
||
+ // There is no PUD_SEC_NG, so we use PMD_SECT_NG instead.
|
||
+ pud = __pud(val | PMD_SECT_NG);
|
||
+ }
|
||
+#endif
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_rw_gate(IEE_OP_SET_PUD, pudp, pud);
|
||
+#else
|
||
+ WRITE_ONCE(*pudp, pud);
|
||
+#endif
|
||
+ if (pud_valid(pud)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
|
||
static inline void pud_clear(pud_t *pudp)
|
||
{
|
||
@@ -738,6 +979,12 @@ static inline pmd_t *pud_pgtable(pud_t pud)
|
||
/* Find an entry in the second-level page table. */
|
||
#define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#define pmd_set_fixmap_init(addr) ((pmd_t *)iee_set_fixmap_offset_pre_init(FIX_PMD, addr))
|
||
+#define pmd_set_fixmap_offset_init(pud, addr) pmd_set_fixmap_init(pmd_offset_phys(pud, addr))
|
||
+#define pmd_clear_fixmap_init() clear_fixmap_init(FIX_PMD)
|
||
+#endif
|
||
+
|
||
#define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
|
||
#define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr))
|
||
#define pmd_clear_fixmap() clear_fixmap(FIX_PMD)
|
||
@@ -769,15 +1016,26 @@ static inline pmd_t *pud_pgtable(pud_t pud)
|
||
#define p4d_none(p4d) (!p4d_val(p4d))
|
||
#define p4d_bad(p4d) (!(p4d_val(p4d) & 2))
|
||
#define p4d_present(p4d) (p4d_val(p4d))
|
||
+#define p4d_valid(p4d) pte_valid(p4d_pte(p4d))
|
||
|
||
static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
|
||
{
|
||
- if (in_swapper_pgdir(p4dp)) {
|
||
+ if (in_swapper_pgdir(p4dp))
|
||
+ {
|
||
set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
|
||
return;
|
||
}
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+ if(in_tramp_pgdir(p4dp))
|
||
+ {
|
||
+ iee_set_tramp_pgd_pre_init((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
|
||
+ return;
|
||
+ }
|
||
+ iee_rw_gate(IEE_OP_SET_P4D, p4dp, p4d);
|
||
+#else
|
||
WRITE_ONCE(*p4dp, p4d);
|
||
+#endif
|
||
dsb(ishst);
|
||
isb();
|
||
}
|
||
@@ -800,6 +1058,12 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
|
||
/* Find an entry in the first-level page table. */
|
||
#define pud_offset_phys(dir, addr) (p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#define pud_set_fixmap_init(addr) ((pud_t *)iee_set_fixmap_offset_pre_init(FIX_PUD, addr))
|
||
+#define pud_set_fixmap_offset_init(p4d, addr) pud_set_fixmap_init(pud_offset_phys(p4d, addr))
|
||
+#define pud_clear_fixmap_init() clear_fixmap_init(FIX_PUD)
|
||
+#endif
|
||
+
|
||
#define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
|
||
#define pud_set_fixmap_offset(p4d, addr) pud_set_fixmap(pud_offset_phys(p4d, addr))
|
||
#define pud_clear_fixmap() clear_fixmap(FIX_PUD)
|
||
@@ -826,6 +1090,10 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
|
||
#define pgd_ERROR(e) \
|
||
pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#define pgd_set_fixmap_init(addr) ((pgd_t *)iee_set_fixmap_offset_pre_init(FIX_PGD, addr))
|
||
+#define pgd_clear_fixmap_init() clear_fixmap_init(FIX_PGD)
|
||
+#endif
|
||
#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
|
||
#define pgd_clear_fixmap() clear_fixmap(FIX_PGD)
|
||
|
||
@@ -912,8 +1180,13 @@ static inline int __ptep_test_and_clear_young(struct vm_area_struct *vma,
|
||
do {
|
||
old_pte = pte;
|
||
pte = pte_mkold(pte);
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_val(pte) = iee_set_cmpxchg_relaxed(ptep,
|
||
+ pte_val(old_pte), pte_val(pte));
|
||
+ #else
|
||
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
||
pte_val(old_pte), pte_val(pte));
|
||
+ #endif
|
||
} while (pte_val(pte) != pte_val(old_pte));
|
||
|
||
return pte_young(pte);
|
||
@@ -952,8 +1225,12 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
||
static inline pte_t __ptep_get_and_clear(struct mm_struct *mm,
|
||
unsigned long address, pte_t *ptep)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ pteval_t pteval= iee_set_xchg_relaxed((pte_t *)&pte_val(*ptep), (pteval_t)0);
|
||
+ pte_t pte = __pte(pteval);
|
||
+ #else
|
||
pte_t pte = __pte(xchg_relaxed(&pte_val(*ptep), 0));
|
||
-
|
||
+ #endif
|
||
page_table_check_pte_clear(mm, pte);
|
||
|
||
return pte;
|
||
@@ -995,7 +1272,12 @@ static inline pte_t __get_and_clear_full_ptes(struct mm_struct *mm,
|
||
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
|
||
unsigned long address, pmd_t *pmdp)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ pteval_t pteval= iee_set_xchg_relaxed((pte_t *)&pmd_val(*pmdp), (pteval_t)0);
|
||
+ pmd_t pmd = __pmd(pteval);
|
||
+ #else
|
||
pmd_t pmd = __pmd(xchg_relaxed(&pmd_val(*pmdp), 0));
|
||
+ #endif
|
||
|
||
page_table_check_pmd_clear(mm, pmd);
|
||
|
||
@@ -1012,8 +1294,12 @@ static inline void ___ptep_set_wrprotect(struct mm_struct *mm,
|
||
do {
|
||
old_pte = pte;
|
||
pte = pte_wrprotect(pte);
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_val(pte) = iee_set_cmpxchg_relaxed(ptep,pte_val(old_pte), pte_val(pte));
|
||
+ #else
|
||
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
||
pte_val(old_pte), pte_val(pte));
|
||
+ #endif
|
||
} while (pte_val(pte) != pte_val(old_pte));
|
||
}
|
||
|
||
@@ -1049,7 +1335,11 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
|
||
unsigned long address, pmd_t *pmdp, pmd_t pmd)
|
||
{
|
||
page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
|
||
+ #ifdef CONFIG_PTP
|
||
+ return __pmd((pmdval_t)iee_set_xchg_relaxed((pte_t *)&pmd_val(*pmdp), (pmdval_t)pmd_val(pmd)));
|
||
+ #else
|
||
return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
|
||
+ #endif
|
||
}
|
||
#endif
|
||
|
||
diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h
|
||
index d2e0306e65d3..8352e92d4536 100644
|
||
--- a/arch/arm64/include/asm/pointer_auth.h
|
||
+++ b/arch/arm64/include/asm/pointer_auth.h
|
||
@@ -108,8 +108,13 @@ static __always_inline void ptrauth_enable(void)
|
||
{
|
||
if (!system_supports_address_auth())
|
||
return;
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
|
||
+ SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
|
||
SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
|
||
+ #endif
|
||
isb();
|
||
}
|
||
|
||
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
|
||
index 42358b8d678e..1e2d11e57fe3 100644
|
||
--- a/arch/arm64/include/asm/sysreg.h
|
||
+++ b/arch/arm64/include/asm/sysreg.h
|
||
@@ -1116,6 +1116,64 @@
|
||
write_sysreg_s(__scs_new, sysreg); \
|
||
} while (0)
|
||
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+#define SYS_TCR_IEE_SI TCR_HPD1 | TCR_A1
|
||
+
|
||
+extern void iee_rwx_gate_entry(int flag, ...);
|
||
+#define IEE_SI_TEST 0
|
||
+#define IEE_WRITE_sctlr_el1 1
|
||
+#define IEE_WRITE_ttbr0_el1 2
|
||
+#define IEE_WRITE_vbar_el1 3
|
||
+#define IEE_WRITE_tcr_el1 4
|
||
+#define IEE_WRITE_mdscr_el1 5
|
||
+#define IEE_WRITE_AFSR0 10
|
||
+
|
||
+#define sysreg_clear_set_iee_si(sysreg, clear, set) do { \
|
||
+ u64 __scs_val = read_sysreg(sysreg); \
|
||
+ u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set); \
|
||
+ if (__scs_new != __scs_val) \
|
||
+ iee_rwx_gate_entry(IEE_WRITE_##sysreg, __scs_new); \
|
||
+} while (0)
|
||
+
|
||
+#define IEE_SI_WRITE_DAIF_SEL "msr daifclr, #0xf\n\t" \
|
||
+ "tbnz %x0, #6, 114221f\n\t" \
|
||
+ "tbnz %x0, #7, 114210f\n\t" \
|
||
+ "tbnz %x0, #8, 114100f\n\t" \
|
||
+ "msr daifset, #0b000\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114221:\n\t" \
|
||
+ "tbnz %x0, #7, 114211f\n\t" \
|
||
+ "tbnz %x0, #8, 114101f\n\t" \
|
||
+ "msr daifset, #0b001\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114211:\n\t" \
|
||
+ "tbnz %x0, #8, 114111f\n\t" \
|
||
+ "msr daifset, #0b011\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114210:\n\t" \
|
||
+ "tbnz %x0, #8, 114110f\n\t" \
|
||
+ "msr daifset, #0b010\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114100:\n\t" \
|
||
+ "msr daifset, #0b100\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114101:\n\t" \
|
||
+ "msr daifset, #0b101\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114110:\n\t" \
|
||
+ "msr daifset, #0b110\n\t" \
|
||
+ "b 114514f\n\t" \
|
||
+"114111:\n\t" \
|
||
+ "msr daifset, #0b111\n\t" \
|
||
+"114514:\n\t"
|
||
+
|
||
+#define iee_si_write_daif(v) do { \
|
||
+ u64 __val = (u64)(v); \
|
||
+ asm volatile(IEE_SI_WRITE_DAIF_SEL: : "rZ" (__val));} while (0)
|
||
+#endif
|
||
+
|
||
#define read_sysreg_par() ({ \
|
||
u64 par; \
|
||
asm(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412)); \
|
||
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
|
||
index 2c29239d05c3..955f99317790 100644
|
||
--- a/arch/arm64/include/asm/tlb.h
|
||
+++ b/arch/arm64/include/asm/tlb.h
|
||
@@ -11,8 +11,17 @@
|
||
#include <linux/pagemap.h>
|
||
#include <linux/swap.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
static inline void __tlb_remove_table(void *_table)
|
||
{
|
||
+#ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(page_to_phys((struct page *)_table));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)page_address((struct page *)_table));
|
||
+#endif
|
||
free_page_and_swap_cache((struct page *)_table);
|
||
}
|
||
|
||
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
|
||
index 831c314d75ff..7775628528c6 100644
|
||
--- a/arch/arm64/include/asm/tlbflush.h
|
||
+++ b/arch/arm64/include/asm/tlbflush.h
|
||
@@ -49,6 +49,7 @@
|
||
|
||
#define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0)
|
||
|
||
+
|
||
#define __tlbi_user(op, arg) do { \
|
||
if (arm64_kernel_unmapped_at_el0()) \
|
||
__tlbi(op, (arg) | USER_ASID_FLAG); \
|
||
@@ -258,6 +259,10 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
|
||
asid = __TLBI_VADDR(0, ASID(mm));
|
||
__tlbi(aside1is, asid);
|
||
__tlbi_user(aside1is, asid);
|
||
+ #if defined(CONFIG_IEE) || defined (CONFIG_KOI)
|
||
+ if (!arm64_kernel_unmapped_at_el0())
|
||
+ __tlbi(aside1is, asid | USER_ASID_FLAG);
|
||
+ #endif
|
||
dsb(ish);
|
||
mmu_notifier_arch_invalidate_secondary_tlbs(mm, 0, -1UL);
|
||
}
|
||
@@ -273,6 +278,10 @@ static inline void __flush_tlb_page_nosync(struct mm_struct *mm,
|
||
__tlbi_user(vale1is, addr);
|
||
mmu_notifier_arch_invalidate_secondary_tlbs(mm, uaddr & PAGE_MASK,
|
||
(uaddr & PAGE_MASK) + PAGE_SIZE);
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ if (!arm64_kernel_unmapped_at_el0())
|
||
+ __tlbi(vale1is, addr | USER_ASID_FLAG);
|
||
+ #endif
|
||
}
|
||
|
||
static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
|
||
@@ -366,6 +375,45 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
|
||
* 2. If there is 1 page remaining, flush it through non-range operations. Range
|
||
* operations can only span an even number of pages.
|
||
*/
|
||
+#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+#define __flush_tlb_range_op(op, start, pages, stride, \
|
||
+ asid, tlb_level, tlbi_user) \
|
||
+do { \
|
||
+ int num = 0; \
|
||
+ int scale = 0; \
|
||
+ unsigned long addr; \
|
||
+ \
|
||
+ while (pages > 0) { \
|
||
+ if (!system_supports_tlb_range() || \
|
||
+ pages % 2 == 1) { \
|
||
+ addr = __TLBI_VADDR(start, asid); \
|
||
+ __tlbi_level(op, addr, tlb_level); \
|
||
+ if (!arm64_kernel_unmapped_at_el0()) /* added for IEE */ \
|
||
+ __tlbi_level(op, addr | USER_ASID_FLAG, tlb_level); \
|
||
+ if (tlbi_user) \
|
||
+ __tlbi_user_level(op, addr, tlb_level); \
|
||
+ start += stride; \
|
||
+ pages -= stride >> PAGE_SHIFT; \
|
||
+ continue; \
|
||
+ } \
|
||
+ \
|
||
+ num = __TLBI_RANGE_NUM(pages, scale); \
|
||
+ if (num >= 0) { \
|
||
+ addr = __TLBI_VADDR_RANGE(start, asid, scale, \
|
||
+ num, tlb_level); \
|
||
+ __tlbi(r##op, addr); \
|
||
+ if (!arm64_kernel_unmapped_at_el0()) /* added for IEE */ \
|
||
+ __tlbi(r##op, addr | USER_ASID_FLAG); \
|
||
+ if (tlbi_user) \
|
||
+ __tlbi_user(r##op, addr); \
|
||
+ start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
|
||
+ pages -= __TLBI_RANGE_PAGES(num, scale); \
|
||
+ } \
|
||
+ scale++; \
|
||
+ } \
|
||
+} while (0)
|
||
+
|
||
+#else
|
||
#define __flush_tlb_range_op(op, start, pages, stride, \
|
||
asid, tlb_level, tlbi_user) \
|
||
do { \
|
||
@@ -399,6 +447,8 @@ do { \
|
||
} \
|
||
} while (0)
|
||
|
||
+#endif //if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+
|
||
#define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
|
||
__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false)
|
||
|
||
@@ -467,7 +517,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
|
||
return;
|
||
}
|
||
|
||
- start = __TLBI_VADDR(start, 0);
|
||
+ start = __TLBI_VADDR(start, 0);
|
||
end = __TLBI_VADDR(end, 0);
|
||
|
||
dsb(ishst);
|
||
@@ -483,9 +533,9 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
|
||
*/
|
||
static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
|
||
{
|
||
- unsigned long addr = __TLBI_VADDR(kaddr, 0);
|
||
-
|
||
- dsb(ishst);
|
||
+ unsigned long addr = __TLBI_VADDR(kaddr, 0);
|
||
+
|
||
+ dsb(ishst);
|
||
__tlbi(vaae1is, addr);
|
||
dsb(ish);
|
||
isb();
|
||
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
|
||
index 21ef9c21a400..44eb76cc54d7 100644
|
||
--- a/arch/arm64/kernel/Makefile
|
||
+++ b/arch/arm64/kernel/Makefile
|
||
@@ -36,6 +36,8 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
|
||
syscall.o proton-pack.o idreg-override.o idle.o \
|
||
patching.o
|
||
|
||
+obj-y += iee/
|
||
+obj-$(CONFIG_KOI) += koi/
|
||
obj-$(CONFIG_AARCH32_EL0) += binfmt_elf32.o sys32.o signal32.o \
|
||
sys_compat.o
|
||
obj-$(CONFIG_AARCH32_EL0) += sigreturn32.o
|
||
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
|
||
index fd0f291e215e..c008e46b5fc0 100644
|
||
--- a/arch/arm64/kernel/armv8_deprecated.c
|
||
+++ b/arch/arm64/kernel/armv8_deprecated.c
|
||
@@ -306,11 +306,19 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
|
||
|
||
static int cp15_barrier_set_hw_mode(bool enable)
|
||
{
|
||
+#ifdef CONFIG_IEE
|
||
+ if (enable)
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
|
||
+ else
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
|
||
+ return 0;
|
||
+#else
|
||
if (enable)
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
|
||
else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
|
||
return 0;
|
||
+#endif
|
||
}
|
||
|
||
static bool try_emulate_cp15_barrier(struct pt_regs *regs, u32 insn)
|
||
@@ -341,11 +349,19 @@ static int setend_set_hw_mode(bool enable)
|
||
if (!cpu_supports_mixed_endian_el0())
|
||
return -EINVAL;
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ if (enable)
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
|
||
+ else
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
|
||
+ return 0;
|
||
+#else
|
||
if (enable)
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_SED, 0);
|
||
else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SED);
|
||
return 0;
|
||
+#endif
|
||
}
|
||
|
||
static int __a32_setend_handler(struct pt_regs *regs, u32 big_endian)
|
||
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
|
||
index e997ad275afb..e105f633355a 100644
|
||
--- a/arch/arm64/kernel/asm-offsets.c
|
||
+++ b/arch/arm64/kernel/asm-offsets.c
|
||
@@ -97,6 +97,17 @@ int main(void)
|
||
DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct ftrace_regs, direct_tramp));
|
||
#endif
|
||
DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs));
|
||
+#ifdef CONFIG_IEE
|
||
+ DEFINE(iee_from_token_offset, offsetof(struct task_token, iee_stack));
|
||
+ DEFINE(kernel_from_token_offset, offsetof(struct task_token, kernel_stack));
|
||
+ DEFINE(mm_from_task_offset, offsetof(struct task_struct, mm));
|
||
+#endif
|
||
+#ifdef CONFIG_KOI
|
||
+ DEFINE(koi_kernel_from_token_offset, offsetof(struct task_token, koi_kernel_stack));
|
||
+ DEFINE(koi_from_token_offset, offsetof(struct task_token, koi_stack));
|
||
+ DEFINE(ttbr1_from_token_offset, offsetof(struct task_token, current_ttbr1));
|
||
+ DEFINE(koi_stack_base_from_token_offset, offsetof(struct task_token, koi_stack_base));
|
||
+#endif
|
||
BLANK();
|
||
#endif
|
||
#ifdef CONFIG_AARCH32_EL0
|
||
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
|
||
index 46813132a09f..412006aa323c 100644
|
||
--- a/arch/arm64/kernel/cpu_errata.c
|
||
+++ b/arch/arm64/kernel/cpu_errata.c
|
||
@@ -80,7 +80,11 @@ hisilicon_1980005_enable(const struct arm64_cpu_capabilities *__unused)
|
||
__set_bit(ARM64_HAS_CACHE_IDC, system_cpucaps);
|
||
arm64_ftr_reg_ctrel0.sys_val |= BIT(CTR_EL0_IDC_SHIFT);
|
||
arm64_ftr_reg_ctrel0.strict_mask &= ~BIT(CTR_EL0_IDC_SHIFT);
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#endif
|
||
}
|
||
#endif
|
||
|
||
@@ -132,7 +136,11 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
|
||
enable_uct_trap = true;
|
||
|
||
if (enable_uct_trap)
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#endif
|
||
}
|
||
|
||
#ifdef CONFIG_ARM64_ERRATUM_1463225
|
||
@@ -147,7 +155,11 @@ has_cortex_a76_erratum_1463225(const struct arm64_cpu_capabilities *entry,
|
||
static void __maybe_unused
|
||
cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
|
||
{
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCI, 0);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCI, 0);
|
||
+#endif
|
||
}
|
||
|
||
#ifdef CONFIG_HISILICON_ERRATUM_HIP08_RU_PREFETCH
|
||
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
|
||
index 74e445251b51..ebc1e776b175 100644
|
||
--- a/arch/arm64/kernel/cpufeature.c
|
||
+++ b/arch/arm64/kernel/cpufeature.c
|
||
@@ -94,6 +94,10 @@
|
||
#include <asm/vectors.h>
|
||
#include <asm/virt.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <asm/iee-si.h>
|
||
+#endif
|
||
+
|
||
/* Kernel representation of AT_HWCAP and AT_HWCAP2 */
|
||
static DECLARE_BITMAP(elf_hwcap, MAX_CPU_FEATURES) __read_mostly;
|
||
|
||
@@ -1612,7 +1616,11 @@ static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unu
|
||
* value.
|
||
*/
|
||
if (!(read_cpuid_cachetype() & BIT(CTR_EL0_IDC_SHIFT)))
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
|
||
+#endif
|
||
}
|
||
|
||
static bool has_cache_dic(const struct arm64_cpu_capabilities *entry,
|
||
@@ -1873,7 +1881,11 @@ static inline void __cpu_enable_hw_dbm(void)
|
||
{
|
||
u64 tcr = read_sysreg(tcr_el1) | TCR_HD;
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ iee_rwx_gate_entry(IEE_WRITE_tcr_el1, tcr);
|
||
+#else
|
||
write_sysreg(tcr, tcr_el1);
|
||
+#endif
|
||
isb();
|
||
local_flush_tlb_all();
|
||
}
|
||
@@ -2056,7 +2068,9 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
|
||
*/
|
||
WARN_ON_ONCE(in_interrupt());
|
||
|
||
+ #ifndef CONFIG_IEE
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPAN, 0);
|
||
+ #endif
|
||
set_pstate_pan(1);
|
||
}
|
||
#endif /* CONFIG_ARM64_PAN */
|
||
@@ -2121,7 +2135,11 @@ static bool has_generic_auth(const struct arm64_cpu_capabilities *entry,
|
||
static void cpu_enable_e0pd(struct arm64_cpu_capabilities const *cap)
|
||
{
|
||
if (this_cpu_has_cap(ARM64_HAS_E0PD))
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(tcr_el1, 0, TCR_E0PD1);
|
||
+#else
|
||
sysreg_clear_set(tcr_el1, 0, TCR_E0PD1);
|
||
+#endif
|
||
}
|
||
#endif /* CONFIG_ARM64_E0PD */
|
||
|
||
@@ -2214,7 +2232,11 @@ static void nmi_enable(const struct arm64_cpu_capabilities *__unused)
|
||
* avoid leaving things masked.
|
||
*/
|
||
_allint_clear();
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_SPINTMASK, SCTLR_EL1_NMI);
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPINTMASK, SCTLR_EL1_NMI);
|
||
+ #endif
|
||
isb();
|
||
}
|
||
#endif
|
||
@@ -2229,7 +2251,11 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
|
||
* So, be strict and forbid other BRs using other registers to
|
||
* jump onto a PACIxSP instruction:
|
||
*/
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_BT0 | SCTLR_EL1_BT1);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_BT0 | SCTLR_EL1_BT1);
|
||
+#endif
|
||
isb();
|
||
}
|
||
#endif /* CONFIG_ARM64_BTI */
|
||
@@ -2237,7 +2263,11 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
|
||
#ifdef CONFIG_ARM64_MTE
|
||
static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_ELx_ATA | SCTLR_EL1_ATA0);
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_ATA | SCTLR_EL1_ATA0);
|
||
+ #endif
|
||
|
||
mte_cpu_setup();
|
||
|
||
@@ -2271,7 +2301,11 @@ static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, in
|
||
|
||
static void cpu_trap_el0_impdef(const struct arm64_cpu_capabilities *__unused)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_TIDCP);
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_TIDCP);
|
||
+ #endif
|
||
}
|
||
|
||
static void cpu_enable_dit(const struct arm64_cpu_capabilities *__unused)
|
||
@@ -2281,7 +2315,11 @@ static void cpu_enable_dit(const struct arm64_cpu_capabilities *__unused)
|
||
|
||
static void cpu_enable_mops(const struct arm64_cpu_capabilities *__unused)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_MSCEn);
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_MSCEn);
|
||
+ #endif
|
||
}
|
||
|
||
/* Internal helper functions to match cpu capability type */
|
||
@@ -3475,6 +3513,43 @@ static void __init setup_system_capabilities(void)
|
||
enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU);
|
||
}
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+static void iee_si_test_end(void)
|
||
+{
|
||
+ pr_info("IEE: testing iee_exec_entry sctlr...\n");
|
||
+ iee_rwx_gate_entry(IEE_WRITE_SCTLR, read_sysreg(sctlr_el1)& ~SCTLR_ELx_M);
|
||
+ pr_info("IEE: testing iee_exec_entry ttbr0_el1...\n");
|
||
+ iee_rwx_gate_entry(IEE_WRITE_TTBR0, read_sysreg(ttbr0_el1));
|
||
+ pr_info("IEE: testing iee_exec_entry vbar...\n");
|
||
+ iee_rwx_gate_entry(IEE_WRITE_VBAR, read_sysreg(vbar_el1));
|
||
+ pr_info("IEE: testing iee_exec_entry tcr...\n");
|
||
+ iee_rwx_gate_entry(IEE_WRITE_TCR, read_sysreg(tcr_el1));
|
||
+ // pr_info("IEE: testing iee_exec_entry mdscr...\n");
|
||
+ // iee_rwx_gate_entry(IEE_WRITE_MDSCR, read_sysreg(mdscr_el1));
|
||
+ // pr_info("IEE: testing iee_exec_entry afsr0...\n");
|
||
+ // iee_rwx_gate_entry(IEE_WRITE_AFSR0);
|
||
+ #ifdef CONFIG_KOI
|
||
+ write_sysreg(read_sysreg(ttbr0_el1)+0x3000000000000, ttbr0_el1);
|
||
+ pr_info("IEE: current TTBR1_EL1:%llx, TTBR0:%llx\n", read_sysreg(ttbr1_el1), read_sysreg(ttbr0_el1));
|
||
+ pr_info("IEE: testing iee_exec_entry switch to koi...\n");
|
||
+ iee_rwx_gate_entry(IEE_SWITCH_TO_KOI, phys_to_ttbr(__pa_symbol(swapper_pg_dir)));
|
||
+ pr_info("IEE: current TTBR1_EL1:%llx, TTBR0:%llx\n", read_sysreg(ttbr1_el1), read_sysreg(ttbr0_el1));
|
||
+ pr_info("IEE: testing iee_exec_entry switch to kernel...\n");
|
||
+ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL);
|
||
+ #endif
|
||
+}
|
||
+
|
||
+/* Finish iee rwx gate initializations. */
|
||
+static void __init iee_si_init_done(void)
|
||
+{
|
||
+ // Prepare data for iee rwx gate
|
||
+ iee_si_prepare_data();
|
||
+ // All initialization is done. Do some simple tests.
|
||
+ iee_si_test_end();
|
||
+}
|
||
+#endif
|
||
+
|
||
void __init setup_cpu_features(void)
|
||
{
|
||
u32 cwg;
|
||
@@ -3502,6 +3577,10 @@ void __init setup_cpu_features(void)
|
||
if (!cwg)
|
||
pr_warn("No Cache Writeback Granule information, assuming %d\n",
|
||
ARCH_DMA_MINALIGN);
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_si_init_done();
|
||
+ #endif
|
||
}
|
||
|
||
static int enable_mismatched_32bit_el0(unsigned int cpu)
|
||
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
|
||
index 745aefddd9a3..265417e0ad81 100644
|
||
--- a/arch/arm64/kernel/debug-monitors.c
|
||
+++ b/arch/arm64/kernel/debug-monitors.c
|
||
@@ -36,10 +36,14 @@ u8 debug_monitors_arch(void)
|
||
*/
|
||
static void mdscr_write(u32 mdscr)
|
||
{
|
||
+// #ifdef CONFIG_IEE
|
||
+// iee_rwx_gate_entry(IEE_WRITE_mdscr_el1, mdscr);
|
||
+// #else
|
||
unsigned long flags;
|
||
flags = local_daif_save();
|
||
write_sysreg(mdscr, mdscr_el1);
|
||
local_daif_restore(flags);
|
||
+// #endif
|
||
}
|
||
NOKPROBE_SYMBOL(mdscr_write);
|
||
|
||
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
|
||
index 08274e4317b2..0d259e355c90 100644
|
||
--- a/arch/arm64/kernel/entry-common.c
|
||
+++ b/arch/arm64/kernel/entry-common.c
|
||
@@ -156,7 +156,11 @@ asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs)
|
||
* mode. Before this function is called it is not safe to call regular kernel
|
||
* code, instrumentable code, or any code which may trigger an exception.
|
||
*/
|
||
+#ifdef CONFIG_IEE
|
||
+void noinstr arm64_enter_nmi(struct pt_regs *regs)
|
||
+#else
|
||
static void noinstr arm64_enter_nmi(struct pt_regs *regs)
|
||
+#endif
|
||
{
|
||
regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
|
||
|
||
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
|
||
index 7fcbee0f6c0e..dee813ee6aad 100644
|
||
--- a/arch/arm64/kernel/entry.S
|
||
+++ b/arch/arm64/kernel/entry.S
|
||
@@ -29,12 +29,391 @@
|
||
#include <asm/asm-uaccess.h>
|
||
#include <asm/unistd.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <asm/iee-def.h>
|
||
+
|
||
+#define BAD_SP_EL0 0
|
||
+#define BAD_ELR_EL1 1
|
||
+#define BAD_TCR_EL1 2
|
||
+#define BAD_IEE_SI 4
|
||
+#endif
|
||
+
|
||
.macro clear_gp_regs
|
||
.irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
|
||
mov x\n, xzr
|
||
.endr
|
||
.endm
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+#ifdef CONFIG_IEE
|
||
+/*
|
||
+ * This function is used to switch to ko stack in glue code
|
||
+ */
|
||
+SYM_FUNC_START(koi_do_switch_to_ko_stack)
|
||
+ sub sp, sp, #48
|
||
+ stp x29, x30, [sp]
|
||
+ str x2, [sp, #16]
|
||
+ stp x0, x1, [sp, #32]
|
||
+
|
||
+ // iee_rw_gate(IEE_WRITE_KERNEL_STACK, current, sp)
|
||
+ mov x0, #IEE_WRITE_KOI_KERNEL_STACK
|
||
+ mrs x1, sp_el0
|
||
+ add x2, sp, #48
|
||
+
|
||
+ bl iee_rw_gate
|
||
+
|
||
+ // iee_rw_gate(IEE_READ_KOI_STACK, current)
|
||
+ mov x0, #IEE_READ_KOI_STACK
|
||
+ mrs x1, sp_el0
|
||
+ bl iee_rw_gate
|
||
+
|
||
+ ldp x29, x30, [sp]
|
||
+ ldr x2, [sp, #16]
|
||
+ add x1, sp, #32
|
||
+ mov sp, x0
|
||
+ ldp x0, x1, [x1]
|
||
+
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_do_switch_to_ko_stack)
|
||
+
|
||
+/*
|
||
+ * This fucntion is used to switch to kernel stack in glue code
|
||
+ */
|
||
+SYM_FUNC_START(koi_do_switch_to_kernel_stack)
|
||
+ sub sp, sp, #48
|
||
+ stp x29, x30, [sp]
|
||
+ str x2, [sp, #16]
|
||
+ stp x0, x1, [sp, #32]
|
||
+ // iee_rw_gate(IEE_WRITE_KOI_STACK, current, sp)
|
||
+ mov x0, #IEE_WRITE_KOI_STACK
|
||
+ mrs x1, sp_el0
|
||
+ add x2, sp, #48
|
||
+ bl iee_rw_gate
|
||
+
|
||
+ // iee_rw_gate(IEE_READ_KOI_KERNEL_STACK, current)
|
||
+ mov x0, #IEE_READ_KOI_KERNEL_STACK
|
||
+ mrs x1, sp_el0
|
||
+ bl iee_rw_gate
|
||
+
|
||
+ ldp x29, x30, [sp]
|
||
+ ldr x2, [sp, #16]
|
||
+ add x1, sp, #32
|
||
+ mov sp, x0
|
||
+ ldp x0, x1, [x1]
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_do_switch_to_kernel_stack)
|
||
+
|
||
+/*
|
||
+ * Before switch to ko's pgtable, we must switch current stack to ko's stack.
|
||
+ * We have stored registers to kernel stack, and we need to restore them from ko's stack after switching,
|
||
+ * so we need to copy from kernel stack to ko stack
|
||
+ * the memory region to copy is [sp, stack_top)
|
||
+ * void koi_switch_to_ko_stack(void);
|
||
+ */
|
||
+SYM_FUNC_START(koi_switch_to_ko_stack)
|
||
+ mrs x17, pan
|
||
+ msr pan, 0x0
|
||
+
|
||
+ sub sp, sp, #32
|
||
+ str x17, [sp, #16]
|
||
+ stp x30, x29, [sp]
|
||
+
|
||
+ // current sp stores in x1
|
||
+ add x1, x1, #176
|
||
+ // current sp_el0 stores in x0
|
||
+ bl _iee_write_koi_kernel_stack
|
||
+
|
||
+ mrs x0, sp_el0
|
||
+ bl _iee_read_koi_stack
|
||
+
|
||
+ ldr x17, [sp, #16]
|
||
+ ldp x30, x29, [sp]
|
||
+ add sp, sp, #32
|
||
+
|
||
+ msr pan, x17
|
||
+
|
||
+ sub x0, x0, #176
|
||
+ mov x1, sp
|
||
+ mov x2, #176
|
||
+
|
||
+ // memcpy(current->driver_stack, current->kernel_stack, 176)
|
||
+ mov x16, lr
|
||
+ bl memcpy
|
||
+ mov lr, x16
|
||
+
|
||
+ mov sp, x0
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_ko_stack)
|
||
+
|
||
+SYM_FUNC_START(koi_switch_to_kernel_stack)
|
||
+ /*
|
||
+ * current sp belongs to driver stack, and the bottom 160 bytes saves registers when exception occurred,
|
||
+ * so we should add 160 to current sp, and store it in task_struct
|
||
+ * also, fetch kernel sp from task_struct, copy the bottom 160 bytes from driver stack to kernel stack
|
||
+ */
|
||
+ mrs x17, pan
|
||
+ msr pan, 0x0
|
||
+
|
||
+ sub sp, sp, #32
|
||
+ stp x30, x29, [sp]
|
||
+ str x17, [sp, #16]
|
||
+
|
||
+ mrs x0, sp_el0
|
||
+ add x1, sp, #192
|
||
+ bl _iee_write_koi_stack
|
||
+
|
||
+ mrs x0, sp_el0
|
||
+ bl _iee_read_koi_kernel_stack
|
||
+
|
||
+ ldr x17, [sp, #16]
|
||
+ ldp x30, x29, [sp]
|
||
+ add sp, sp, #32
|
||
+
|
||
+ msr pan, x17
|
||
+
|
||
+ // x0 = kernel_stack
|
||
+ sub x0, x0, #160
|
||
+ mov x1, sp
|
||
+ // x2 = 160
|
||
+ mov x2, #160
|
||
+
|
||
+ mov x16, lr
|
||
+ bl memcpy
|
||
+ mov lr, x16
|
||
+
|
||
+ mov sp, x0
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_kernel_stack)
|
||
+#else
|
||
+/*
|
||
+ * This function is used to switch to ko stack in glue code
|
||
+ */
|
||
+SYM_FUNC_START(koi_do_switch_to_ko_stack)
|
||
+ sub sp, sp, #16
|
||
+ stp x16, x17, [sp]
|
||
+ mrs x17, sp_el0
|
||
+ adrp x16, koi_offset
|
||
+ ldr x16, [x16, #:lo12:koi_offset]
|
||
+ add x17, x17, x16
|
||
+ add x16, sp, #16
|
||
+ str x16, [x17, #koi_kernel_from_token_offset]
|
||
+ ldr x16, [x17, #koi_from_token_offset]
|
||
+ mov x17, sp
|
||
+ mov sp, x16
|
||
+ ldp x16, x17, [x17]
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_do_switch_to_ko_stack)
|
||
+
|
||
+/*
|
||
+ * This fucntion is used to switch to kernel stack in glue code
|
||
+ */
|
||
+SYM_FUNC_START(koi_do_switch_to_kernel_stack)
|
||
+ sub sp, sp, #16
|
||
+ stp x16, x17, [sp]
|
||
+ mrs x17, sp_el0
|
||
+ adrp x16, koi_offset
|
||
+ ldr x16, [x16, #:lo12:koi_offset]
|
||
+ add x17, x17, x16
|
||
+ add x16, sp, #16
|
||
+ str x16, [x17, #koi_from_token_offset]
|
||
+ ldr x16, [x17, #koi_kernel_from_token_offset]
|
||
+ mov x17, sp
|
||
+ mov sp, x16
|
||
+ ldp x16, x17, [x17]
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_do_switch_to_kernel_stack)
|
||
+
|
||
+/*
|
||
+ * Before switch to ko's pgtable, we must switch current stack to ko's stack.
|
||
+ * We have stored registers to kernel stack, and we need to restore them from ko's stack after switching,
|
||
+ * so we need to copy from kernel stack to ko stack
|
||
+ * the memory region to copy is [sp, stack_top)
|
||
+ * void koi_switch_to_ko_stack(unsigned long stack_top);
|
||
+ */
|
||
+SYM_FUNC_START(koi_switch_to_ko_stack)
|
||
+ // current sp stores in x1
|
||
+ add x3, x1, #176
|
||
+ adrp x4, koi_offset
|
||
+ ldr x4, [x4, #:lo12:koi_offset]
|
||
+ add x4, x0, x4
|
||
+ // current sp_el0 stores in x0
|
||
+ str x3, [x4, #koi_kernel_from_token_offset]
|
||
+ ldr x0, [x4, #koi_from_token_offset]
|
||
+ sub x0, x0, #176
|
||
+ mov x2, #176
|
||
+
|
||
+ // memcpy(current->driver_stack, current->kernel_stack, 176)
|
||
+ mov x16, lr
|
||
+ bl memcpy
|
||
+ mov lr, x16
|
||
+
|
||
+ mov sp, x0
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_ko_stack)
|
||
+
|
||
+SYM_FUNC_START(koi_switch_to_kernel_stack)
|
||
+ /*
|
||
+ * current sp belongs to driver stack, and the bottom 176 bytes saves registers when exception occurred,
|
||
+ * so we should add 176 to current sp, and store it in task_struct
|
||
+ * also, fetch kernel sp from task_struct, copy the bottom 176 bytes from driver stack to kernel stack
|
||
+ */
|
||
+ mov x1, sp
|
||
+ add x3, sp, #160
|
||
+
|
||
+ mrs x16, sp_el0
|
||
+ adrp x2, koi_offset
|
||
+ ldr x2, [x2, #:lo12:koi_offset]
|
||
+ add x16, x16, x2
|
||
+ str x3, [x16, #koi_from_token_offset]
|
||
+ // sp points to kernel_stack
|
||
+ ldr x0, [x16, #koi_kernel_from_token_offset]
|
||
+
|
||
+ // x0 = kernel_stack
|
||
+ sub x0, x0, #160
|
||
+ // x2 = 160
|
||
+ mov x2, #160
|
||
+ mov x16, lr
|
||
+ // memcpy(kernel_stack, driver_stack, 160)
|
||
+ bl memcpy
|
||
+ mov lr, x16
|
||
+ mov sp, x0
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_kernel_stack)
|
||
+#endif
|
||
+
|
||
+SYM_FUNC_START(koi_switch_to_ko_pgtbl)
|
||
+ stp x0, x1, [sp, #16 * 1]
|
||
+ stp x2, x3, [sp, #16 * 2]
|
||
+ stp x4, x5, [sp, #16 * 3]
|
||
+ stp x6, x7, [sp, #16 * 4]
|
||
+ stp x8, x9, [sp, #16 * 5]
|
||
+ stp x10, x11, [sp, #16 * 6]
|
||
+ stp x12, x13, [sp, #16 * 7]
|
||
+ stp x14, x15, [sp, #16 * 8]
|
||
+ stp x16, x17, [sp, #16 * 9]
|
||
+ stp x18, x30, [sp, #16 * 10]
|
||
+
|
||
+ adrp x0, koi_swapper_ttbr1
|
||
+ ldr x0, [x0, #:lo12:koi_swapper_ttbr1]
|
||
+ cbz x0, 0f
|
||
+ bl koi_do_switch_to_ko_pgtbl
|
||
+ // if x0 == 0, don't need to switch pgtable and stack, jump to 0
|
||
+ cbz x0, 0f
|
||
+ mov x19, x0
|
||
+ // if current on task's kernel stack, switch to ko stack
|
||
+ mrs x0, sp_el0
|
||
+ mov x1, sp
|
||
+ ldr x2, [x0, TSK_STACK]
|
||
+ eor x2, x2, x1
|
||
+ and x2, x2, #~(THREAD_SIZE - 1)
|
||
+ cbnz x2, 1f
|
||
+
|
||
+ bl koi_switch_to_ko_stack
|
||
+1:
|
||
+#ifndef CONFIG_IEE
|
||
+ msr ttbr1_el1, x19
|
||
+ isb
|
||
+ nop
|
||
+ nop
|
||
+ nop
|
||
+#else
|
||
+ mov x0, #IEE_SWITCH_TO_KOI
|
||
+ mov x1, x19
|
||
+ bl iee_rwx_gate_entry
|
||
+#endif
|
||
+0:
|
||
+
|
||
+ ldp x0, x1, [sp, #16 * 1]
|
||
+ ldp x2, x3, [sp, #16 * 2]
|
||
+ ldp x4, x5, [sp, #16 * 3]
|
||
+ ldp x6, x7, [sp, #16 * 4]
|
||
+ ldp x8, x9, [sp, #16 * 5]
|
||
+ ldp x10, x11, [sp, #16 * 6]
|
||
+ ldp x12, x13, [sp, #16 * 7]
|
||
+ ldp x14, x15, [sp, #16 * 8]
|
||
+ ldp x16, x17, [sp, #16 * 9]
|
||
+ ldp x18, x30, [sp, #16 * 10]
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_ko_pgtbl)
|
||
+
|
||
+.pushsection ".koi.text", "ax"
|
||
+SYM_FUNC_START(koi_switch_to_kernel_pgtbl)
|
||
+ sub sp, sp, #160
|
||
+ stp x0, x1, [sp, #16 * 0]
|
||
+ stp x2, x3, [sp, #16 * 1]
|
||
+ stp x4, x5, [sp, #16 * 2]
|
||
+ stp x6, x7, [sp, #16 * 3]
|
||
+ stp x8, x9, [sp, #16 * 4]
|
||
+ stp x10, x11, [sp, #16 * 5]
|
||
+
|
||
+ stp x12, x13, [sp, #16 * 6]
|
||
+ stp x14, x15, [sp, #16 * 7]
|
||
+ stp x16, x17, [sp, #16 * 8]
|
||
+ stp x18, x30, [sp, #16 * 9]
|
||
+ // check whether paging init finished
|
||
+ adrp x0, koi_swapper_ttbr1
|
||
+ ldr x0, [x0, #:lo12:koi_swapper_ttbr1]
|
||
+ cbz x0, 0f
|
||
+
|
||
+ bl koi_do_switch_to_kernel_pgtbl
|
||
+ /*
|
||
+ * koi_do_switch_to_kernel_pgtbl return 0 indicates
|
||
+ * that when exception occurred, the isolated ko is executing under koi pgtbl,
|
||
+ * so we need to switch stack to kernel stack after switch pgtbl back to koi_swapper_ttbr1.
|
||
+ */
|
||
+ cbz x0, 0f
|
||
+#ifndef CONFIG_IEE
|
||
+ mrs x0, sp_el0
|
||
+ adrp x1, koi_offset
|
||
+ ldr x1, [x1, #:lo12:koi_offset]
|
||
+ add x0, x0, x1
|
||
+ mov x16, sp
|
||
+ ldr x17, [x0, koi_stack_base_from_token_offset]
|
||
+ eor x17, x17, x16
|
||
+ and x17, x17, #~(THREAD_SIZE - 1)
|
||
+ cbnz x17, 0f
|
||
+#else
|
||
+ // save current pan
|
||
+ mrs x17, pan
|
||
+ // disable pan
|
||
+ msr pan, 0x0
|
||
+ mrs x0, sp_el0
|
||
+ bl _iee_read_koi_stack_base
|
||
+ // restore pan
|
||
+ msr pan, x17
|
||
+
|
||
+ mov x16, sp
|
||
+ eor x0, x0, x16
|
||
+ and x0, x0, #~(THREAD_SIZE - 1)
|
||
+ cbnz x0, 0f
|
||
+#endif
|
||
+ bl koi_switch_to_kernel_stack
|
||
+0:
|
||
+
|
||
+ ldp x0, x1, [sp, #16 * 0]
|
||
+ ldp x2, x3, [sp, #16 * 1]
|
||
+ ldp x4, x5, [sp, #16 * 2]
|
||
+ ldp x6, x7, [sp, #16 * 3]
|
||
+ ldp x8, x9, [sp, #16 * 4]
|
||
+ ldp x10, x11, [sp, #16 * 5]
|
||
+ ldp x12, x13, [sp, #16 * 6]
|
||
+ ldp x14, x15, [sp, #16 * 7]
|
||
+ ldp x16, x17, [sp, #16 * 8]
|
||
+ ldp x18, x30, [sp, #16 * 9]
|
||
+ add sp, sp, #160
|
||
+ ret
|
||
+SYM_FUNC_END(koi_switch_to_kernel_pgtbl)
|
||
+.popsection
|
||
+#endif
|
||
+
|
||
.macro kernel_ventry, el:req, ht:req, regsize:req, label:req
|
||
.align 7
|
||
.Lventry_start\@:
|
||
@@ -151,6 +530,17 @@ alternative_else_nop_endif
|
||
#endif
|
||
.endm
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+// SP_EL0 check failed.
|
||
+SYM_FUNC_START_LOCAL(sp_el0_check_failed)
|
||
+ mov x0, sp
|
||
+ mov x1, #BAD_SP_EL0
|
||
+ mrs x2, esr_el1
|
||
+ bl iee_bad_mode
|
||
+ ASM_BUG()
|
||
+SYM_FUNC_END(sp_el0_check_failed)
|
||
+#endif
|
||
+
|
||
/* Clear the MTE asynchronous tag check faults */
|
||
.macro clear_mte_async_tcf thread_sctlr
|
||
#ifdef CONFIG_ARM64_MTE
|
||
@@ -224,6 +614,14 @@ alternative_cb_end
|
||
ldr_this_cpu tsk, __entry_task, x20
|
||
msr sp_el0, tsk
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ // tsk check.
|
||
+ ldr_this_cpu x19, __entry_task, x20
|
||
+ mrs x20, sp_el0
|
||
+ cmp x19, x20
|
||
+ b.ne sp_el0_check_failed
|
||
+#endif
|
||
+
|
||
/*
|
||
* Ensure MDSCR_EL1.SS is clear, since we can unmask debug exceptions
|
||
* when scheduling.
|
||
@@ -276,6 +674,13 @@ alternative_else_nop_endif
|
||
|
||
scs_load_current
|
||
.else
|
||
+#ifdef CONFIG_IEE
|
||
+ // tsk check.
|
||
+ ldr_this_cpu x19, __entry_task, x20
|
||
+ mrs x20, sp_el0
|
||
+ cmp x19, x20
|
||
+ b.ne sp_el0_check_failed
|
||
+#endif
|
||
add x21, sp, #PT_REGS_SIZE
|
||
get_current_task tsk
|
||
.endif /* \el == 0 */
|
||
@@ -333,9 +738,11 @@ alternative_else_nop_endif
|
||
.endm
|
||
|
||
.macro kernel_exit, el
|
||
+ #ifndef CONFIG_IEE
|
||
.if \el != 0
|
||
disable_daif
|
||
.endif
|
||
+ #endif
|
||
|
||
#ifdef CONFIG_ARM64_PSEUDO_NMI
|
||
alternative_if_not ARM64_HAS_GIC_PRIO_MASKING
|
||
@@ -411,6 +818,41 @@ alternative_else_nop_endif
|
||
|
||
msr elr_el1, x21 // set up the return data
|
||
msr spsr_el1, x22
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+ .if \el == 0
|
||
+
|
||
+ #ifndef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
+ // SET hpd1 = 0 start
|
||
+ mrs x0, tcr_el1
|
||
+ and x0, x0, #0xFFFFFBFFFFFFFFFF
|
||
+ and x0, x0, #0xFFFFFFFFFFBFFFFF
|
||
+ msr tcr_el1, x0
|
||
+ // SET hpd1 = 0 end
|
||
+
|
||
+ disable_daif
|
||
+
|
||
+ // Check ELR_EL1
|
||
+ mrs x0, elr_el1
|
||
+ lsr x0, x0, #48
|
||
+ tst x0, #0xffff
|
||
+ b.ne 5f
|
||
+ #endif
|
||
+
|
||
+ .endif
|
||
+
|
||
+#else
|
||
+#ifdef CONFIG_KOI
|
||
+ .if \el==0
|
||
+ mrs x0, tcr_el1
|
||
+ and x0, x0, #0xFFFFFFFFFFBFFFFF
|
||
+ msr tcr_el1,x0
|
||
+ .endif
|
||
+#endif
|
||
+
|
||
+#endif
|
||
+
|
||
ldp x0, x1, [sp, #16 * 0]
|
||
ldp x2, x3, [sp, #16 * 1]
|
||
ldp x4, x5, [sp, #16 * 2]
|
||
@@ -569,12 +1011,167 @@ SYM_CODE_START_LOCAL(__bad_stack)
|
||
SYM_CODE_END(__bad_stack)
|
||
#endif /* CONFIG_VMAP_STACK */
|
||
|
||
+/*
|
||
+ * iee exception entry
|
||
+ */
|
||
+ .macro iee_exception_entry, el
|
||
+
|
||
+ /* Check whether exception is permmited. */
|
||
+ ldr x1, =__iee_si_no_irq
|
||
+ cmp x1, x22
|
||
+ b.hi 1148f
|
||
+ ldr x1, =__iee_si_end
|
||
+ cmp x1, x22
|
||
+ b.lo 1148f
|
||
+ /* ELR check fail */
|
||
+ mov x0, sp
|
||
+ mov x1, #BAD_IEE_SI
|
||
+ mrs x2, esr_el1
|
||
+ bl iee_bad_mode
|
||
+ ASM_BUG()
|
||
+1148:
|
||
+
|
||
+ /* el0 set hpds */
|
||
+ .if \el == 0
|
||
+
|
||
+ #ifndef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
+ /* SET hpd1 = 1 start */
|
||
+ mrs x0, tcr_el1
|
||
+ orr x0, x0, #0x0000040000000000
|
||
+ orr x0, x0, #0x0000000000400000
|
||
+ msr tcr_el1, x0
|
||
+ /* SET hpd1 = 1 end */
|
||
+
|
||
+ disable_daif
|
||
+
|
||
+ /* Check TCR_EL1 */
|
||
+ mrs x0, tcr_el1
|
||
+ tst x0, #0x0000040000000000
|
||
+ b.eq 5f
|
||
+ tst x0, #0x0000000000400000
|
||
+ b.ne 6f
|
||
+
|
||
+5:
|
||
+ /* TCR_EL1 check fail */
|
||
+ mov x0, sp
|
||
+ mov x1, #BAD_TCR_EL1
|
||
+ mrs x2, esr_el1
|
||
+ bl iee_bad_mode
|
||
+ ASM_BUG()
|
||
+
|
||
+6:
|
||
+ nop
|
||
+ #endif
|
||
+
|
||
+ .else
|
||
+#ifdef CONFIG_IEE_INTERRUPTABLE
|
||
+ /* el1 save elr_el1 and set pan */
|
||
+ /* Check ELR_EL1 */
|
||
+ ldr x1, =__iee_code_start
|
||
+ cmp x1, x22
|
||
+ b.hi 7f
|
||
+ ldr x1, =__iee_code_end
|
||
+ cmp x1, x22
|
||
+ b.lo 7f
|
||
+ /* Exception from iee code */
|
||
+ /* Switch to kernel stack */
|
||
+ mrs x0, sp_el0 /* x0 -> task_struct(VA) */
|
||
+ adrp x2, iee_offset
|
||
+ ldr x2, [x2, #:lo12:iee_offset]
|
||
+ add x1, x0, x2 /* x1 -> task_token(IEE) */
|
||
+ // store iee stack
|
||
+ mov x3, sp
|
||
+ str x3, [x1, #iee_from_token_offset]
|
||
+ // load kernel stack
|
||
+ ldr x3, [x1, #kernel_from_token_offset]
|
||
+ mov sp, x3
|
||
+ sub sp, sp, #PT_REGS_SIZE
|
||
+ /* Enable PAN */
|
||
+ msr pan, #0x1
|
||
+
|
||
+7:
|
||
+ /* Exception from kernel code */
|
||
+ mov x0, #0x0
|
||
+ mov x1, #0x0
|
||
+ mov x2, #0x0
|
||
+ mov x3, #0x0
|
||
+#endif
|
||
+ .endif
|
||
+ .endm
|
||
+
|
||
+/*
|
||
+ * iee exception exit
|
||
+ */
|
||
+ .macro iee_exception_exit, el
|
||
+ // Disable daif
|
||
+ disable_daif
|
||
+
|
||
+ .if \el == 1
|
||
+#ifdef CONFIG_IEE_INTERRUPTABLE
|
||
+ /* el1 pop elr_el1 and set pan */
|
||
+ /* Check ELR_EL1 */
|
||
+ ldr x1, =__iee_code_start
|
||
+ cmp x1, x22
|
||
+ b.hi 9f
|
||
+ ldr x1, =__iee_code_end
|
||
+ cmp x1, x22
|
||
+ b.lo 9f
|
||
+ /* Eret iee code */
|
||
+ /* Disable PAN */
|
||
+ msr pan, #0x0
|
||
+ /* Switch to iee stack */
|
||
+ add sp, sp, #PT_REGS_SIZE
|
||
+ mrs x0, sp_el0 /* x0 -> task_struct */
|
||
+ adrp x2, iee_offset
|
||
+ ldr x2, [x2, #:lo12:iee_offset]
|
||
+ add x1, x0, x2 /* x1 -> task_token(IEE) */
|
||
+ // store kernel stack
|
||
+ mov x3, sp
|
||
+ str x3, [x1, #kernel_from_token_offset]
|
||
+ // load iee stack
|
||
+ ldr x2, [x1, #iee_from_token_offset]
|
||
+ mov sp, x2
|
||
+ /* Load ELR_EL1 from iee stack */
|
||
+ ldr x21, [sp, #S_PC]
|
||
+ /* Check the modify of ELR_EL1 */
|
||
+ cmp x21, x22
|
||
+ b.ne 8f
|
||
+ /* ELR_EL1 not modified */
|
||
+ b 9f
|
||
+
|
||
+8:
|
||
+ // ELR_EL1 modified
|
||
+ mov x0, sp
|
||
+ mov x1, #BAD_ELR_EL1
|
||
+ mrs x2, esr_el1
|
||
+ bl iee_bad_mode
|
||
+ ASM_BUG()
|
||
+
|
||
+9:
|
||
+ // Eret kernel code
|
||
+ mov x0, #0x0
|
||
+ mov x1, #0x0
|
||
+ mov x2, #0x0
|
||
+ mov x3, #0x0
|
||
+#endif
|
||
+ .endif
|
||
+ .endm
|
||
|
||
.macro entry_handler el:req, ht:req, regsize:req, label:req
|
||
SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)
|
||
kernel_entry \el, \regsize
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_exception_entry \el
|
||
+ #endif
|
||
+
|
||
mov x0, sp
|
||
bl el\el\ht\()_\regsize\()_\label\()_handler
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_exception_exit \el
|
||
+ #endif
|
||
+
|
||
.if \el == 0
|
||
b ret_to_user
|
||
.else
|
||
@@ -844,6 +1441,13 @@ SYM_FUNC_START(cpu_switch_to)
|
||
ldr lr, [x8]
|
||
mov sp, x9
|
||
msr sp_el0, x1
|
||
+#ifdef CONFIG_IEE
|
||
+ // tsk check.
|
||
+ ldr_this_cpu x8, __entry_task, x9
|
||
+ mrs x9, sp_el0
|
||
+ cmp x8, x9
|
||
+ b.ne sp_el0_check_failed
|
||
+#endif
|
||
ptrauth_keys_install_kernel x1, x8, x9, x10
|
||
scs_save x0
|
||
scs_load_current
|
||
@@ -1033,6 +1637,13 @@ SYM_CODE_START(__sdei_asm_handler)
|
||
mrs x28, sp_el0
|
||
ldr_this_cpu dst=x0, sym=__entry_task, tmp=x1
|
||
msr sp_el0, x0
|
||
+#ifdef CONFIG_IEE
|
||
+ // tsk check.
|
||
+ ldr_this_cpu x0, __entry_task, x1
|
||
+ mrs x1, sp_el0
|
||
+ cmp x0, x1
|
||
+ b.ne sp_el0_check_failed
|
||
+#endif
|
||
|
||
/* If we interrupted the kernel point to the previous stack/frame. */
|
||
and x0, x3, #0xc
|
||
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
|
||
index 5cdfcc9e3e54..c0af965bd92e 100644
|
||
--- a/arch/arm64/kernel/fpsimd.c
|
||
+++ b/arch/arm64/kernel/fpsimd.c
|
||
@@ -1309,7 +1309,11 @@ void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
|
||
isb();
|
||
|
||
/* Allow EL0 to access TPIDR2 */
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_rwx_gate_entry(IEE_WRITE_sctlr_el1, read_sysreg(SCTLR_EL1) | SCTLR_ELx_ENTP2);
|
||
+ #else
|
||
write_sysreg(read_sysreg(SCTLR_EL1) | SCTLR_ELx_ENTP2, SCTLR_EL1);
|
||
+ #endif
|
||
isb();
|
||
}
|
||
|
||
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
|
||
index 6517bf2644a0..5c75e069d877 100644
|
||
--- a/arch/arm64/kernel/head.S
|
||
+++ b/arch/arm64/kernel/head.S
|
||
@@ -464,6 +464,42 @@ SYM_FUNC_END(create_kernel_mapping)
|
||
set_this_cpu_offset \tmp1
|
||
.endm
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ .macro init_cpu_task_checked tsk, tmp1, tmp2
|
||
+ msr sp_el0, \tsk
|
||
+ // tsk check.
|
||
+ adrp x29, __per_cpu_offset
|
||
+ mrs \tmp1, sp_el0
|
||
+ ldr \tmp2, [\tmp1, #TSK_TI_CPU] /* cpu number */
|
||
+1:
|
||
+ cmp \tmp2, #0
|
||
+ b.eq 2f
|
||
+ add x29, x29, #8
|
||
+ sub \tmp2, \tmp2, #1
|
||
+ b 1b
|
||
+2:
|
||
+ ldr \tmp2, [x29, #:lo12:__per_cpu_offset] /* cpu offset */
|
||
+ adr_l x29, __entry_task
|
||
+ ldr x29, [x29, \tmp2]
|
||
+ cmp x29, \tmp1
|
||
+ b.ne sp_el0_check_failed
|
||
+
|
||
+ ldr \tmp1, [\tsk, #TSK_STACK]
|
||
+ add sp, \tmp1, #THREAD_SIZE
|
||
+ sub sp, sp, #PT_REGS_SIZE
|
||
+
|
||
+ stp xzr, xzr, [sp, #S_STACKFRAME]
|
||
+ add x29, sp, #S_STACKFRAME
|
||
+
|
||
+ scs_load_current
|
||
+
|
||
+ adr_l \tmp1, __per_cpu_offset
|
||
+ ldr w\tmp2, [\tsk, #TSK_TI_CPU]
|
||
+ ldr \tmp1, [\tmp1, \tmp2, lsl #3]
|
||
+ set_this_cpu_offset \tmp1
|
||
+ .endm
|
||
+#endif
|
||
+
|
||
/*
|
||
* The following fragment of code is executed with the MMU enabled.
|
||
*
|
||
@@ -661,6 +697,18 @@ SYM_FUNC_START_LOCAL(secondary_startup)
|
||
SYM_FUNC_END(secondary_startup)
|
||
|
||
.text
|
||
+#ifdef CONFIG_IEE
|
||
+// SP_EL0 check failed.
|
||
+SYM_FUNC_START_LOCAL(sp_el0_check_failed)
|
||
+ 1:
|
||
+ nop
|
||
+ nop
|
||
+ nop
|
||
+ nop
|
||
+ b 1f
|
||
+SYM_FUNC_END(sp_el0_check_failed)
|
||
+#endif
|
||
+
|
||
SYM_FUNC_START_LOCAL(__secondary_switched)
|
||
mov x0, x20
|
||
bl set_cpu_boot_mode_flag
|
||
@@ -677,7 +725,11 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
|
||
ldr x2, [x0, #CPU_BOOT_TASK]
|
||
cbz x2, __secondary_too_slow
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ init_cpu_task_checked x2, x1, x3
|
||
+#else
|
||
init_cpu_task x2, x1, x3
|
||
+#endif
|
||
|
||
#ifdef CONFIG_ARM64_PTR_AUTH
|
||
ptrauth_keys_init_cpu x2, x3, x4, x5
|
||
@@ -746,6 +798,10 @@ SYM_FUNC_START(__enable_mmu)
|
||
cmp x3, #ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX
|
||
b.gt __no_granule_support
|
||
phys_to_ttbr x2, x2
|
||
+#ifdef CONFIG_IEE
|
||
+ mov x3, #1
|
||
+ bfi x2, x3, #48, #16 // ASID 1 is used by IEE rwx gate.
|
||
+#endif
|
||
msr ttbr0_el1, x2 // load TTBR0
|
||
load_ttbr1 x1, x1, x3
|
||
|
||
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
|
||
index 02870beb271e..1c14428a3ed4 100644
|
||
--- a/arch/arm64/kernel/hibernate.c
|
||
+++ b/arch/arm64/kernel/hibernate.c
|
||
@@ -34,6 +34,10 @@
|
||
#include <asm/trans_pgd.h>
|
||
#include <asm/virt.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
/*
|
||
* Hibernate core relies on this value being 0 on resume, and marks it
|
||
* __nosavedata assuming it will keep the resume kernel's '0' value. This
|
||
@@ -197,12 +201,22 @@ static int create_safe_exec_page(void *src_start, size_t length,
|
||
phys_addr_t trans_ttbr0;
|
||
unsigned long t0sz;
|
||
int rc;
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
if (!page)
|
||
return -ENOMEM;
|
||
|
||
memcpy(page, src_start, length);
|
||
caches_clean_inval_pou((unsigned long)page, (unsigned long)page + length);
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(page_address(page)));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)page_address(page));
|
||
+ #endif
|
||
+
|
||
rc = trans_pgd_idmap_page(&trans_info, &trans_ttbr0, &t0sz, page);
|
||
if (rc)
|
||
return rc;
|
||
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
|
||
index d39a8787edf2..b5ac4b7670bc 100644
|
||
--- a/arch/arm64/kernel/hw_breakpoint.c
|
||
+++ b/arch/arm64/kernel/hw_breakpoint.c
|
||
@@ -26,6 +26,10 @@
|
||
#include <asm/cputype.h>
|
||
#include <asm/system_misc.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <asm/iee-si.h>
|
||
+#endif
|
||
+
|
||
/* Breakpoint currently in use for each BRP. */
|
||
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
|
||
|
||
@@ -102,13 +106,68 @@ int hw_breakpoint_slots(int type)
|
||
WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
|
||
WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+#define IEE_SI_READ_WB_REG_CASE(OFF, N, REG, VAL) \
|
||
+ case (OFF + N): \
|
||
+ IEE_SI_AARCH64_DBG_READ(N, REG, VAL); \
|
||
+ break
|
||
+
|
||
+#define IEE_SI_WRITE_WB_REG_CASE(OFF, N, REG, VAL) \
|
||
+ case (OFF + N): \
|
||
+ IEE_SI_AARCH64_DBG_WRITE(N, REG, VAL); \
|
||
+ break
|
||
+
|
||
+#define IEE_SI_GEN_READ_REG_CASES(OFF, REG, VAL) \
|
||
+ IEE_SI_READ_WB_REG_CASE(OFF, 0, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 1, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 2, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 3, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 4, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 5, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 6, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 7, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 8, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 9, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 10, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 11, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 12, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 13, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
|
||
+
|
||
+#define IEE_SI_GEN_WRITE_REG_CASES(OFF, REG, VAL) \
|
||
+ IEE_SI_WRITE_WB_REG_CASE(OFF, 0, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 1, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 2, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 3, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 4, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 5, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 6, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 7, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 8, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 9, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 10, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 11, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 12, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 13, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
|
||
+ WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
|
||
+
|
||
+#endif
|
||
+
|
||
static u64 read_wb_reg(int reg, int n)
|
||
{
|
||
u64 val = 0;
|
||
|
||
switch (reg + n) {
|
||
+// #ifdef CONFIG_IEE
|
||
+// IEE_SI_GEN_READ_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
|
||
+// IEE_SI_GEN_READ_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
|
||
+// #else
|
||
GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
|
||
GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
|
||
+// #endif
|
||
GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
|
||
GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
|
||
default:
|
||
@@ -122,8 +181,13 @@ NOKPROBE_SYMBOL(read_wb_reg);
|
||
static void write_wb_reg(int reg, int n, u64 val)
|
||
{
|
||
switch (reg + n) {
|
||
+// #ifdef CONFIG_IEE
|
||
+// IEE_SI_GEN_WRITE_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
|
||
+// IEE_SI_GEN_WRITE_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
|
||
+// #else
|
||
GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
|
||
GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
|
||
+// #endif
|
||
GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
|
||
GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
|
||
default:
|
||
@@ -171,6 +235,10 @@ static int is_a32_compat_bp(struct perf_event *bp)
|
||
return tsk && is_a32_compat_thread(task_thread_info(tsk));
|
||
}
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
|
||
+#endif
|
||
+
|
||
/**
|
||
* hw_breakpoint_slot_setup - Find and setup a perf slot according to
|
||
* operations
|
||
@@ -191,6 +259,37 @@ static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
|
||
{
|
||
int i;
|
||
struct perf_event **slot;
|
||
+// reserve hw breakpoint 0 for iee rwx gate in kernel sapce.
|
||
+// #ifdef CONFIG_IEE
|
||
+// struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||
+// if (arch_check_bp_in_kernelspace(info)){
|
||
+// for (i = 1; i < max_slots; ++i) { // search from hw breakpoint 1
|
||
+// slot = &slots[i];
|
||
+// switch (ops) {
|
||
+// case HW_BREAKPOINT_INSTALL:
|
||
+// if (!*slot) {
|
||
+// *slot = bp;
|
||
+// return i;
|
||
+// }
|
||
+// break;
|
||
+// case HW_BREAKPOINT_UNINSTALL:
|
||
+// if (*slot == bp) {
|
||
+// *slot = NULL;
|
||
+// return i;
|
||
+// }
|
||
+// break;
|
||
+// case HW_BREAKPOINT_RESTORE:
|
||
+// if (*slot == bp)
|
||
+// return i;
|
||
+// break;
|
||
+// default:
|
||
+// pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
|
||
+// return -EINVAL;
|
||
+// }
|
||
+// }
|
||
+// return -ENOSPC;
|
||
+// }
|
||
+// #endif
|
||
|
||
for (i = 0; i < max_slots; ++i) {
|
||
slot = &slots[i];
|
||
diff --git a/arch/arm64/kernel/iee/Makefile b/arch/arm64/kernel/iee/Makefile
|
||
new file mode 100644
|
||
index 000000000000..123c68c5cc4e
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/iee/Makefile
|
||
@@ -0,0 +1 @@
|
||
+obj-$(CONFIG_IEE) += iee.o iee-gate.o iee-func.o
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/kernel/iee/iee-func.c b/arch/arm64/kernel/iee/iee-func.c
|
||
new file mode 100644
|
||
index 000000000000..7764dbd41555
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/iee/iee-func.c
|
||
@@ -0,0 +1,187 @@
|
||
+#include "asm/pgtable.h"
|
||
+#include <linux/memory.h>
|
||
+#include <linux/mm.h>
|
||
+#include <asm/tlb.h>
|
||
+#include <asm/tlbflush.h>
|
||
+#include <asm/pgalloc.h>
|
||
+
|
||
+void set_iee_page_valid(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+
|
||
+ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
|
||
+ return;
|
||
+
|
||
+ pte = __pte(pte_val(pte) | 0x1);
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void set_iee_page_invalid(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+
|
||
+ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
|
||
+ return;
|
||
+
|
||
+ pte = __pte(pte_val(pte) & ~0x1);
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_logical_mem_ro(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+
|
||
+ if(addr < PAGE_OFFSET)
|
||
+ return;
|
||
+
|
||
+ pte = __pte((pte_val(pte) | PTE_RDONLY) & ~PTE_DBM);
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_logical_mem_rw(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+
|
||
+ if((addr < PAGE_OFFSET) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 2))))
|
||
+ return;
|
||
+
|
||
+ pte = __pte(pte_val(pte) | PTE_DBM);
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_token_page_valid(void *token, void *new)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(((pte_val(pte) | 0x1) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(new)));
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_token_page_invalid(void *token)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(((pte_val(pte) & ~((unsigned long)0x1)) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(token - IEE_OFFSET)));
|
||
+ set_pte(ptep, pte);
|
||
+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_kernel_ppage(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+
|
||
+ int i;
|
||
+ for(i = 0; i < 4; i++)
|
||
+ {
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(pte_val(pte) & ~PTE_USER & ~PTE_NG);
|
||
+ iee_set_pte_ppage(ptep, pte);
|
||
+ ptep++;
|
||
+ }
|
||
+ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+void iee_set_kernel_upage(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d_t p4d = READ_ONCE(*p4dp);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+
|
||
+ int i;
|
||
+ for(i = 0; i < 4; i++)
|
||
+ {
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(pte_val(pte) | PTE_USER | PTE_NG);
|
||
+ iee_set_pte_upage(ptep, pte);
|
||
+ ptep++;
|
||
+ }
|
||
+ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/kernel/iee/iee-gate.S b/arch/arm64/kernel/iee/iee-gate.S
|
||
new file mode 100644
|
||
index 000000000000..6de99a018bde
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/iee/iee-gate.S
|
||
@@ -0,0 +1,174 @@
|
||
+#include <asm/asm-offsets.h>
|
||
+#include <linux/linkage.h>
|
||
+#include <asm/bug.h>
|
||
+#include <asm-generic/export.h>
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+
|
||
+SYM_FUNC_START(iee_rw_gate)
|
||
+ /* save daif, close irq */
|
||
+ mrs x13, daif
|
||
+ msr daifset, #0x2
|
||
+ isb
|
||
+ /* save lr */
|
||
+ sub sp, sp, #16
|
||
+ stp x29, x30, [sp]
|
||
+ bl iee_protected_rw_gate
|
||
+ /* restore lr */
|
||
+ ldp x29, x30, [sp]
|
||
+ add sp, sp, #16
|
||
+ /* restore daif */
|
||
+ msr daif, x13
|
||
+ ret
|
||
+SYM_FUNC_END(iee_rw_gate)
|
||
+#if defined(CONFIG_CREDP) || defined(CONFIG_KOI)
|
||
+EXPORT_SYMBOL(iee_rw_gate)
|
||
+#endif
|
||
+
|
||
+ .pushsection ".iee.text.header", "ax"
|
||
+
|
||
+SYM_FUNC_START(iee_protected_rw_gate)
|
||
+ mrs x9, pan
|
||
+ /* disable PAN */
|
||
+ msr pan, #0x0
|
||
+ /* switch to iee stack */
|
||
+ mrs x9, sp_el0 /* x9 -> task_struct */
|
||
+ adrp x12, iee_offset
|
||
+ ldr x12, [x12, #:lo12:iee_offset]
|
||
+ add x11, x9, x12 /* x11 -> task_token(IEE) */
|
||
+ // store kernel stack
|
||
+ mov x10, sp
|
||
+ str x10, [x11, #kernel_from_token_offset]
|
||
+ // load iee stack
|
||
+ ldr x10, [x11, #iee_from_token_offset]
|
||
+ mov sp, x10
|
||
+#ifdef CONFIG_IEE_INTERRUPTABLE
|
||
+ isb
|
||
+ /* restore daif */
|
||
+ msr daif, x13
|
||
+ sub sp, sp, #16
|
||
+ stp x29, x30, [sp]
|
||
+#else
|
||
+ sub sp, sp, #16
|
||
+ stp x13, x30, [sp]
|
||
+#endif
|
||
+ /* call iee func */
|
||
+ bl iee_dispatch
|
||
+#ifdef CONFIG_IEE_INTERRUPTABLE
|
||
+ ldp x29, x30, [sp]
|
||
+ add sp, sp, #16
|
||
+ /* store and disable daif */
|
||
+ mrs x13, daif
|
||
+ msr daifset, #0x2
|
||
+ isb
|
||
+#else
|
||
+ ldp x13, x30, [sp]
|
||
+ add sp, sp, #16
|
||
+#endif
|
||
+ /* switch to kernel stack */
|
||
+ mrs x9, sp_el0 /* x9 -> task_struct(VA) */
|
||
+ adrp x12, iee_offset
|
||
+ ldr x12, [x12, #:lo12:iee_offset]
|
||
+ add x11, x9, x12 /* x11 -> task_token(IEE) */
|
||
+ // store iee stack
|
||
+ mov x10, sp
|
||
+ str x10, [x11, #iee_from_token_offset]
|
||
+ // load kernel stack
|
||
+ ldr x10, [x11, #kernel_from_token_offset]
|
||
+ mov sp, x10
|
||
+ /* enable PAN */
|
||
+ msr pan, #0x1
|
||
+ ret
|
||
+SYM_FUNC_END(iee_protected_rw_gate)
|
||
+
|
||
+ .popsection
|
||
+
|
||
+#include <asm/asm-bug.h>
|
||
+#define BAD_IEE 4
|
||
+#define BAD_IEE_SI 5
|
||
+
|
||
+#define SYS_TCR_EL1_HPD1 0x40000000000
|
||
+#define SYS_TCR_EL1_A1 0x400000
|
||
+
|
||
+ .pushsection ".iee.exec_entry", "ax"
|
||
+
|
||
+SYM_FUNC_START(iee_rwx_gate_entry)
|
||
+ /* Disable irq first. */
|
||
+ mrs x15, daif // use x15 to restore daif
|
||
+ msr DAIFSet, #0xf
|
||
+ isb
|
||
+
|
||
+ /* Set HPD1 = 0 to exec follwing codes in U RWX page */
|
||
+ mrs x9, tcr_el1
|
||
+ bic x9, x9, #SYS_TCR_EL1_HPD1
|
||
+ bic x9, x9, #SYS_TCR_EL1_A1
|
||
+ msr tcr_el1, x9
|
||
+ isb
|
||
+
|
||
+ b iee_rwx_gate_tramp
|
||
+SYM_FUNC_END(iee_rwx_gate_entry)
|
||
+ .popsection
|
||
+
|
||
+ .pushsection ".iee.si_text", "awx"
|
||
+
|
||
+SYM_FUNC_START(iee_rwx_gate_tramp)
|
||
+ /* Check tcr val. */
|
||
+ mrs x10, tcr_el1
|
||
+ adrp x12, iee_si_tcr // tcr val shall be const after init
|
||
+ ldr x12, [x12, #:lo12:iee_si_tcr]
|
||
+ cbz x12, 1f
|
||
+ cmp x12, x10
|
||
+ b.ne 3f
|
||
+1:
|
||
+ mov x13, sp
|
||
+ /* If iee hasn't been initialized, skip stack switch. */
|
||
+ ldr x11, =iee_init_done
|
||
+ ldr x10, [x11]
|
||
+ cbz x10, 2f
|
||
+
|
||
+ /* Switch to iee stack */
|
||
+ mrs x9, sp_el0 // x9 -> task_struct
|
||
+ adrp x12, iee_offset
|
||
+ ldr x12, [x12, #:lo12:iee_offset]
|
||
+ add x11, x9, x12 // x11 -> task_token(IEE)
|
||
+ // load iee stack
|
||
+ ldr x10, [x11, #iee_from_token_offset]
|
||
+ mov sp, x10
|
||
+
|
||
+ /* x15 stores daif and x13 stores previous sp */
|
||
+2:
|
||
+ stp x15, x13, [sp, #-32]!
|
||
+ stp x29, x30, [sp, #16]
|
||
+ bl iee_si_handler // enter actual handler
|
||
+ ldp x29, x30, [sp, #16]
|
||
+
|
||
+ b iee_rwx_gate_exit // jump to iee exit
|
||
+3:
|
||
+ mov x0, sp
|
||
+ mov x1, #BAD_IEE_SI
|
||
+ mrs x2, esr_el1
|
||
+ bl iee_bad_mode
|
||
+ ASM_BUG()
|
||
+SYM_FUNC_END(iee_rwx_gate_tramp)
|
||
+
|
||
+ .popsection
|
||
+
|
||
+ .pushsection ".iee.exec_exit", "ax"
|
||
+
|
||
+SYM_FUNC_START(iee_rwx_gate_exit)
|
||
+ ldp x15, x13, [sp], #32
|
||
+ mov sp, x13 // switch to kernel stack
|
||
+ mrs x9, tcr_el1
|
||
+ orr x9, x9, #SYS_TCR_EL1_HPD1
|
||
+ orr x9, x9, #SYS_TCR_EL1_A1
|
||
+ msr tcr_el1, x9
|
||
+/* --------Page boundary-------- */
|
||
+ isb
|
||
+ msr daif, x15
|
||
+ isb
|
||
+ ret
|
||
+SYM_FUNC_END(iee_rwx_gate_exit)
|
||
+
|
||
+ .popsection
|
||
+
|
||
+#endif
|
||
diff --git a/arch/arm64/kernel/iee/iee.c b/arch/arm64/kernel/iee/iee.c
|
||
new file mode 100644
|
||
index 000000000000..6b9f7d40df67
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/iee/iee.c
|
||
@@ -0,0 +1,1360 @@
|
||
+#include "linux/sched.h"
|
||
+#include <linux/stdarg.h>
|
||
+#include <asm/pgtable-types.h>
|
||
+#include <asm/iee.h>
|
||
+#include <asm/iee-si.h>
|
||
+#include <asm/sysreg.h>
|
||
+#include <linux/pgtable.h>
|
||
+#include <linux/cred.h>
|
||
+#include <asm/iee-slab.h>
|
||
+#include <asm/percpu.h>
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+extern struct cred init_cred;
|
||
+extern s64 memstart_addr;
|
||
+
|
||
+void __iee_code _iee_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
|
||
+void __iee_code _iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd);
|
||
+void __iee_code _iee_set_pte(pte_t *ptep, pte_t pte);
|
||
+void __iee_code _iee_set_pmd(pmd_t *pmdp, pmd_t pmd);
|
||
+void __iee_code _iee_set_pud(pud_t *pudp, pud_t pud);
|
||
+void __iee_code _iee_set_p4d(p4d_t *p4dp, p4d_t p4d);
|
||
+void __iee_code _iee_set_bm_pte(pte_t *ptep, pte_t pte);
|
||
+pteval_t __iee_code _iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval);
|
||
+pteval_t __iee_code _iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval);
|
||
+void __iee_code _iee_write_in_byte(void *ptr, __u64 data, int length);
|
||
+void __iee_code _iee_set_cred_uid(struct cred *cred, kuid_t uid);
|
||
+void __iee_code _iee_set_cred_gid(struct cred *cred, kgid_t gid);
|
||
+void __iee_code _iee_copy_cred(struct cred *old, struct cred *new);
|
||
+void __iee_code _iee_set_cred_suid(struct cred *cred, kuid_t suid);
|
||
+void __iee_code _iee_set_cred_sgid(struct cred *cred, kgid_t sgid);
|
||
+void __iee_code _iee_set_cred_euid(struct cred *cred, kuid_t euid);
|
||
+void __iee_code _iee_set_cred_egid(struct cred *cred, kgid_t egid);
|
||
+void __iee_code _iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid);
|
||
+void __iee_code _iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid);
|
||
+void __iee_code _iee_set_cred_user(struct cred *cred, struct user_struct *user);
|
||
+void __iee_code _iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns);
|
||
+void __iee_code _iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts);
|
||
+void __iee_code _iee_set_cred_group_info(struct cred *cred, struct group_info *group_info);
|
||
+void __iee_code _iee_set_cred_securebits(struct cred *cred, unsigned securebits);
|
||
+void __iee_code _iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable);
|
||
+void __iee_code _iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted);
|
||
+void __iee_code _iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective);
|
||
+void __iee_code _iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset);
|
||
+void __iee_code _iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient);
|
||
+void __iee_code _iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring);
|
||
+void __iee_code _iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring);
|
||
+void __iee_code _iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring);
|
||
+void __iee_code _iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring);
|
||
+void __iee_code _iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth);
|
||
+void __iee_code _iee_set_cred_non_rcu(struct cred *cred, int non_rcu);
|
||
+void __iee_code _iee_set_cred_atomic_set_usage(struct cred *cred, int i);
|
||
+bool __iee_code _iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr);
|
||
+void __iee_code _iee_set_cred_security(struct cred *cred, void *security);
|
||
+void __iee_code _iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu);
|
||
+void __iee_code _iee_memset(void *ptr, int data, size_t n);
|
||
+void __iee_code _iee_set_track(struct track *ptr, struct track *data);
|
||
+void __iee_code _iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr);
|
||
+void __iee_code _iee_set_pte_upage(pte_t *ptep, pte_t pte);
|
||
+void __iee_code _iee_set_pte_ppage(pte_t *ptep, pte_t pte);
|
||
+void __iee_code _iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm);
|
||
+void __iee_code _iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd);
|
||
+void __iee_code _iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack);
|
||
+void __iee_code _iee_free_token(struct task_struct *tsk);
|
||
+unsigned long __iee_code _iee_read_token_stack(struct task_struct *tsk);
|
||
+void __iee_code _iee_write_entry_task(struct task_struct *tsk);
|
||
+#ifdef CONFIG_KOI
|
||
+unsigned long __iee_code _iee_read_koi_stack(struct task_struct *tsk);
|
||
+void __iee_code _iee_write_koi_stack(struct task_struct *tsk, unsigned long koi_stack);
|
||
+unsigned long __iee_code _iee_read_token_ttbr1(struct task_struct *tsk);
|
||
+void __iee_code _iee_write_token_ttbr1(struct task_struct *tsk, unsigned long current_ttbr1);
|
||
+unsigned long __iee_code _iee_read_koi_kernel_stack(struct task_struct *tsk);
|
||
+void __iee_code _iee_write_koi_kernel_stack(struct task_struct *tsk, unsigned long kernel_stack);
|
||
+unsigned long __iee_code _iee_read_koi_stack_base(struct task_struct *tsk);
|
||
+void __iee_code _iee_write_koi_stack_base(struct task_struct *tsk, unsigned long koi_stack_base);
|
||
+#endif
|
||
+
|
||
+/* wrapper functions */
|
||
+void __iee_code iee_wrapper_write_in_byte(va_list args) {
|
||
+ void *ptr = va_arg(args, void *);
|
||
+ __u64 data = va_arg(args, __u64);
|
||
+ int length = va_arg(args, int);
|
||
+ _iee_write_in_byte(ptr, data, length);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_pte(va_list args) {
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pte_t pte = va_arg(args, pte_t);
|
||
+ _iee_set_pte(ptep, pte);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_pmd(va_list args) {
|
||
+ pmd_t *pmdp = va_arg(args, pmd_t *);
|
||
+ pmd_t pmd = va_arg(args, pmd_t);
|
||
+ _iee_set_pmd(pmdp, pmd);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_p4d(va_list args) {
|
||
+ p4d_t *p4dp = va_arg(args, p4d_t *);
|
||
+ p4d_t p4d = va_arg(args, p4d_t);
|
||
+ _iee_set_p4d(p4dp, p4d);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_pud(va_list args) {
|
||
+ pud_t *pudp = va_arg(args, pud_t *);
|
||
+ pud_t pud = va_arg(args, pud_t);
|
||
+ _iee_set_pud(pudp, pud);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_bm_pte(va_list args) {
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pte_t pte = va_arg(args, pte_t);
|
||
+ _iee_set_bm_pte(ptep, pte);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_swapper_pgd(va_list args) {
|
||
+ pgd_t *pgdp = va_arg(args, pgd_t *);
|
||
+ pgd_t pgd = va_arg(args, pgd_t);
|
||
+ _iee_set_swapper_pgd(pgdp, pgd);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_tramp_pgd(va_list args) {
|
||
+ pgd_t *pgdp = va_arg(args, pgd_t *);
|
||
+ pgd_t pgd = va_arg(args, pgd_t);
|
||
+ _iee_set_tramp_pgd_pre_init(pgdp, pgd);
|
||
+}
|
||
+
|
||
+pteval_t __iee_code iee_wrapper_set_xchg(va_list args) {
|
||
+ pteval_t ret;
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pteval_t pteval = va_arg(args, pteval_t);
|
||
+ ret = _iee_set_xchg_relaxed(ptep, pteval);
|
||
+ return (u64)ret;
|
||
+}
|
||
+
|
||
+pteval_t __iee_code iee_wrapper_set_cmpxchg(va_list args) {
|
||
+ pteval_t ret;
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pteval_t old_pteval = va_arg(args, pteval_t);
|
||
+ pteval_t new_pteval = va_arg(args, pteval_t);
|
||
+ ret = _iee_set_cmpxchg_relaxed(ptep, old_pteval, new_pteval);
|
||
+ return (u64)ret;
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_uid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kuid_t uid = va_arg(args, kuid_t);
|
||
+ _iee_set_cred_uid(cred, uid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_gid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kgid_t gid = va_arg(args, kgid_t);
|
||
+ _iee_set_cred_gid(cred, gid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_copy_cred(va_list args) {
|
||
+ struct cred *old = va_arg(args, struct cred *);
|
||
+ struct cred *new = va_arg(args, struct cred *);
|
||
+ _iee_copy_cred(old, new);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_suid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kuid_t suid = va_arg(args, kuid_t);
|
||
+ _iee_set_cred_suid(cred, suid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_sgid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kgid_t sgid = va_arg(args, kgid_t);
|
||
+ _iee_set_cred_sgid(cred, sgid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_euid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kuid_t euid = va_arg(args, kuid_t);
|
||
+ _iee_set_cred_euid(cred, euid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_egid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kgid_t egid = va_arg(args, kgid_t);
|
||
+ _iee_set_cred_egid(cred, egid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_fsuid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kuid_t fsuid = va_arg(args, kuid_t);
|
||
+ _iee_set_cred_fsuid(cred, fsuid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_fsgid(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kgid_t fsgid = va_arg(args, kgid_t);
|
||
+ _iee_set_cred_fsgid(cred, fsgid);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_user(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct user_struct *user = va_arg(args, struct user_struct *);
|
||
+ _iee_set_cred_user(cred, user);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_user_ns(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct user_namespace *user_ns = va_arg(args, struct user_namespace *);
|
||
+ _iee_set_cred_user_ns(cred, user_ns);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_ucounts(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct ucounts *ucounts = va_arg(args, struct ucounts *);
|
||
+ _iee_set_cred_ucounts(cred, ucounts);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_group_info(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct group_info *group_info = va_arg(args, struct group_info *);
|
||
+ _iee_set_cred_group_info(cred, group_info);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_securebits(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ unsigned securebits = va_arg(args, unsigned);
|
||
+ _iee_set_cred_securebits(cred, securebits);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_cap_inheritable(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kernel_cap_t cap_inheritable = va_arg(args, kernel_cap_t);
|
||
+ _iee_set_cred_cap_inheritable(cred, cap_inheritable);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_cap_permitted(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kernel_cap_t cap_permitted = va_arg(args, kernel_cap_t);
|
||
+ _iee_set_cred_cap_permitted(cred, cap_permitted);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_cap_effective(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kernel_cap_t cap_effective = va_arg(args, kernel_cap_t);
|
||
+ _iee_set_cred_cap_effective(cred, cap_effective);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_cap_bset(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kernel_cap_t cap_bset = va_arg(args, kernel_cap_t);
|
||
+ _iee_set_cred_cap_bset(cred, cap_bset);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_cap_ambient(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ kernel_cap_t cap_ambient = va_arg(args, kernel_cap_t);
|
||
+ _iee_set_cred_cap_ambient(cred, cap_ambient);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_jit_keyring(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ unsigned long jit_keyring = va_arg(args, unsigned long);
|
||
+ _iee_set_cred_jit_keyring(cred, (unsigned char)jit_keyring);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_session_keyring(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct key *session_keyring = va_arg(args, struct key *);
|
||
+ _iee_set_cred_session_keyring(cred, session_keyring);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_process_keyring(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct key *process_keyring = va_arg(args, struct key *);
|
||
+ _iee_set_cred_process_keyring(cred, process_keyring);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_thread_keyring(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct key *thread_keyring = va_arg(args, struct key *);
|
||
+ _iee_set_cred_thread_keyring(cred, thread_keyring);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_request_key_auth(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct key *request_key_auth = va_arg(args, struct key *);
|
||
+ _iee_set_cred_request_key_auth(cred, request_key_auth);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_non_rcu(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ int non_rcu = va_arg(args, int);
|
||
+ _iee_set_cred_non_rcu(cred, non_rcu);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_atomic_set_usage(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ int i = va_arg(args, int);
|
||
+ _iee_set_cred_atomic_set_usage(cred, i);
|
||
+}
|
||
+
|
||
+u64 __iee_code iee_wrapper_set_cred_atomic_op_usage(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ int flag = va_arg(args, int);
|
||
+ int nr = va_arg(args, int);
|
||
+ return (u64)_iee_set_cred_atomic_op_usage(cred, flag, nr);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_security(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ void *security = va_arg(args, void *);
|
||
+ _iee_set_cred_security(cred, security);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_cred_rcu(va_list args) {
|
||
+ struct cred *cred = va_arg(args, struct cred *);
|
||
+ struct rcu_head *rcu = va_arg(args, struct rcu_head *);
|
||
+ _iee_set_cred_rcu(cred, rcu);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_memset(va_list args) {
|
||
+ void *ptr = va_arg(args, void *);
|
||
+ int data = va_arg(args, int);
|
||
+ size_t n = va_arg(args, size_t);
|
||
+ _iee_memset(ptr, data, n);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_track(va_list args) {
|
||
+ struct track *ptr = va_arg(args, struct track *);
|
||
+ struct track *data = va_arg(args, struct track *);
|
||
+ _iee_set_track(ptr, data);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_freeptr(va_list args) {
|
||
+ freeptr_t *pptr = va_arg(args, freeptr_t *);
|
||
+ freeptr_t ptr = va_arg(args, freeptr_t);
|
||
+ _iee_set_freeptr(pptr, ptr);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_pte_upage(va_list args) {
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pte_t pte = va_arg(args, pte_t);
|
||
+ _iee_set_pte_upage(ptep, pte);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_pte_ppage(va_list args) {
|
||
+ pte_t *ptep = va_arg(args, pte_t *);
|
||
+ pte_t pte = va_arg(args, pte_t);
|
||
+ _iee_set_pte_ppage(ptep, pte);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_token_mm(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ struct mm_struct *mm = va_arg(args, struct mm_struct *);
|
||
+ _iee_set_token_mm(tsk, mm);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_set_token_pgd(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ pgd_t *pgd = va_arg(args, pgd_t *);
|
||
+ _iee_set_token_pgd(tsk, pgd);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_init_token(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ void *kernel_stack = va_arg(args, void *);
|
||
+ void *iee_stack = va_arg(args, void *);
|
||
+ _iee_init_token(tsk, kernel_stack, iee_stack);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_free_token(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ _iee_free_token(tsk);
|
||
+}
|
||
+
|
||
+u64 __iee_code iee_wrapper_read_token_stack(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ return (u64)_iee_read_token_stack(tsk);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_write_entry_task(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ _iee_write_entry_task(tsk);
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+u64 __iee_code iee_wrapper_read_koi_stack(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ return (u64)_iee_read_koi_stack(tsk);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_write_koi_stack(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ unsigned long koi_stack = va_arg(args, unsigned long);
|
||
+ _iee_write_koi_stack(tsk, koi_stack);
|
||
+}
|
||
+
|
||
+u64 __iee_code iee_wrapper_read_token_ttbr1(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ return (u64)_iee_read_token_ttbr1(tsk);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_write_token_ttbr1(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ unsigned long current_ttbr1 = va_arg(args, unsigned long);
|
||
+ _iee_write_token_ttbr1(tsk, current_ttbr1);
|
||
+}
|
||
+
|
||
+u64 __iee_code iee_wrapper_read_koi_kernel_stack(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ return (u64)_iee_read_koi_kernel_stack(tsk);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_write_koi_kernel_stack(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ unsigned long kernel_stack = va_arg(args, unsigned long);
|
||
+ _iee_write_koi_kernel_stack(tsk, kernel_stack);
|
||
+}
|
||
+
|
||
+u64 __iee_code iee_wrapper_read_koi_stack_base(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ return (u64)_iee_read_koi_stack_base(tsk);
|
||
+}
|
||
+
|
||
+void __iee_code iee_wrapper_write_koi_stack_base(va_list args) {
|
||
+ struct task_struct *tsk = va_arg(args, struct task_struct *);
|
||
+ unsigned long koi_stack_base = va_arg(args, unsigned long);
|
||
+ _iee_write_koi_stack_base(tsk, koi_stack_base);
|
||
+}
|
||
+#endif
|
||
+// Define the function pointer type for wrapper functions.
|
||
+// Each function pointer conforms to a standardized calling convention
|
||
+// using a variable argument list (va_list) as its parameter.
|
||
+// This allows dynamic invocation of different functions with various arguments.
|
||
+typedef void (*iee_wrapper_func)(va_list args);
|
||
+iee_wrapper_func iee_wrappers[] = {
|
||
+ iee_wrapper_write_in_byte,
|
||
+ iee_wrapper_set_pte,
|
||
+ iee_wrapper_set_pmd,
|
||
+ iee_wrapper_set_pud,
|
||
+ iee_wrapper_set_p4d,
|
||
+ iee_wrapper_set_bm_pte,
|
||
+ iee_wrapper_set_swapper_pgd,
|
||
+ iee_wrapper_set_tramp_pgd,
|
||
+ (iee_wrapper_func)iee_wrapper_set_cmpxchg,
|
||
+ (iee_wrapper_func)iee_wrapper_set_xchg,
|
||
+ iee_wrapper_copy_cred,
|
||
+ iee_wrapper_set_cred_uid,
|
||
+ iee_wrapper_set_cred_gid,
|
||
+ iee_wrapper_set_cred_suid,
|
||
+ iee_wrapper_set_cred_sgid,
|
||
+ iee_wrapper_set_cred_euid,
|
||
+ iee_wrapper_set_cred_egid,
|
||
+ iee_wrapper_set_cred_fsuid,
|
||
+ iee_wrapper_set_cred_fsgid,
|
||
+ iee_wrapper_set_cred_user,
|
||
+ iee_wrapper_set_cred_user_ns,
|
||
+ iee_wrapper_set_cred_group_info,
|
||
+ iee_wrapper_set_cred_securebits,
|
||
+ iee_wrapper_set_cred_cap_inheritable,
|
||
+ iee_wrapper_set_cred_cap_permitted,
|
||
+ iee_wrapper_set_cred_cap_effective,
|
||
+ iee_wrapper_set_cred_cap_bset,
|
||
+ iee_wrapper_set_cred_cap_ambient,
|
||
+ iee_wrapper_set_cred_jit_keyring,
|
||
+ iee_wrapper_set_cred_session_keyring,
|
||
+ iee_wrapper_set_cred_process_keyring,
|
||
+ iee_wrapper_set_cred_thread_keyring,
|
||
+ iee_wrapper_set_cred_request_key_auth,
|
||
+ iee_wrapper_set_cred_non_rcu,
|
||
+ iee_wrapper_set_cred_atomic_set_usage,
|
||
+ (iee_wrapper_func)iee_wrapper_set_cred_atomic_op_usage,
|
||
+ iee_wrapper_set_cred_security,
|
||
+ iee_wrapper_set_cred_rcu,
|
||
+ iee_wrapper_memset,
|
||
+ iee_wrapper_set_track,
|
||
+ iee_wrapper_set_freeptr,
|
||
+ iee_wrapper_set_pte_upage,
|
||
+ iee_wrapper_set_pte_ppage,
|
||
+ iee_wrapper_set_token_mm,
|
||
+ iee_wrapper_set_token_pgd,
|
||
+ iee_wrapper_init_token,
|
||
+ iee_wrapper_free_token,
|
||
+ (iee_wrapper_func)iee_wrapper_read_token_stack,
|
||
+ iee_wrapper_write_entry_task,
|
||
+ iee_wrapper_set_cred_ucounts,
|
||
+#ifdef CONFIG_KOI
|
||
+ (iee_wrapper_func)iee_wrapper_read_koi_stack,
|
||
+ iee_wrapper_write_koi_stack,
|
||
+ (iee_wrapper_func)iee_wrapper_read_token_ttbr1,
|
||
+ iee_wrapper_write_token_ttbr1,
|
||
+ (iee_wrapper_func)iee_wrapper_read_koi_kernel_stack,
|
||
+ iee_wrapper_write_koi_kernel_stack,
|
||
+ (iee_wrapper_func)iee_wrapper_read_koi_stack_base,
|
||
+ iee_wrapper_write_koi_stack_base
|
||
+#endif
|
||
+};
|
||
+
|
||
+u64 __iee_code iee_dispatch(int flag, ...){
|
||
+ va_list pArgs;
|
||
+
|
||
+ va_start(pArgs, flag);
|
||
+
|
||
+ switch(flag)
|
||
+ {
|
||
+ case IEE_OP_SET_CMPXCHG:
|
||
+ {
|
||
+ pteval_t ret = iee_wrapper_set_cmpxchg(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return (u64)ret;
|
||
+ }
|
||
+ case IEE_OP_SET_XCHG:
|
||
+ {
|
||
+ pteval_t ret = iee_wrapper_set_xchg(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return (u64)ret;
|
||
+ }
|
||
+ case IEE_OP_SET_CRED_ATOP_USAGE:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_set_cred_atomic_op_usage(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+ case IEE_READ_TOKEN_STACK:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_read_token_stack(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+#ifdef CONFIG_KOI
|
||
+ case IEE_READ_KOI_STACK:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_read_koi_stack(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+ case IEE_READ_TOKEN_TTBR1:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_read_token_ttbr1(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+ case IEE_READ_KOI_KERNEL_STACK:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_read_koi_kernel_stack(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+ case IEE_READ_KOI_STACK_BASE:
|
||
+ {
|
||
+ u64 ret = iee_wrapper_read_koi_stack_base(pArgs);
|
||
+ va_end(pArgs);
|
||
+ return ret;
|
||
+ }
|
||
+#endif
|
||
+ default:
|
||
+ {
|
||
+ #ifndef CONFIG_KOI
|
||
+ if((flag < IEE_WRITE_IN_BYTE) | (flag > IEE_OP_SET_CRED_UCOUNTS))
|
||
+ panic("Invalid iee flag.\n");
|
||
+ #else
|
||
+ if((flag < IEE_WRITE_IN_BYTE) | (flag > IEE_WRITE_KOI_STACK_BASE))
|
||
+ panic("Invalid iee flag.\n");
|
||
+ #endif
|
||
+ iee_wrappers[flag](pArgs);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ va_end(pArgs);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+unsigned long __iee_code _iee_read_koi_stack(struct task_struct *tsk)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ return (unsigned long)token->koi_stack;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_write_koi_stack(struct task_struct *tsk, unsigned long koi_stack)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->koi_stack = koi_stack;
|
||
+}
|
||
+
|
||
+unsigned long __iee_code _iee_read_token_ttbr1(struct task_struct *tsk)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ return token->current_ttbr1;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_write_token_ttbr1(struct task_struct *tsk, unsigned long current_ttbr1)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->current_ttbr1 = current_ttbr1;
|
||
+}
|
||
+
|
||
+unsigned long __iee_code _iee_read_koi_kernel_stack(struct task_struct *tsk)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ return token->koi_kernel_stack;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_write_koi_kernel_stack(struct task_struct *tsk, unsigned long kernel_stack)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->koi_kernel_stack = kernel_stack;
|
||
+}
|
||
+
|
||
+unsigned long __iee_code _iee_read_koi_stack_base(struct task_struct *tsk)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ return (unsigned long)token->koi_stack_base;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_write_koi_stack_base(struct task_struct *tsk, unsigned long koi_stack_base)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->koi_stack_base = koi_stack_base;
|
||
+}
|
||
+#endif
|
||
+
|
||
+// Protect the __entry_task.
|
||
+__attribute__((aligned(PAGE_SIZE))) DECLARE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
|
||
+void __iee_code _iee_write_entry_task(struct task_struct *tsk)
|
||
+{
|
||
+ // Add check of tsk.
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+
|
||
+ unsigned long flags;
|
||
+ unsigned long res;
|
||
+ struct task_struct **entry_addr;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile("at s1e1r, %0"::"r"(token));
|
||
+ isb();
|
||
+ res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+
|
||
+ // If it is logical map, that means it is not a token.
|
||
+ if(__phys_to_iee(res & PTE_ADDR_MASK) == (((unsigned long)token) & PTE_ADDR_MASK))
|
||
+ panic("Trying to forge a token.\n");
|
||
+
|
||
+ if(!token->valid)
|
||
+ panic("Trying to write a wrong task into __entry_task.\n");
|
||
+ entry_addr = (struct task_struct **)__phys_to_iee(__pa(SHIFT_PERCPU_PTR(__entry_task,__kern_my_cpu_offset())));
|
||
+ *entry_addr = tsk;
|
||
+}
|
||
+
|
||
+unsigned long __iee_code _iee_read_token_stack(struct task_struct *tsk)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ return (unsigned long)token->iee_stack;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_free_token(struct task_struct *tsk)
|
||
+{
|
||
+ _iee_memset(tsk, 0, sizeof(struct task_token));
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+extern unsigned long koi_swapper_ttbr1;
|
||
+#endif
|
||
+void __iee_code _iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->kernel_stack = kernel_stack;
|
||
+ token->iee_stack = iee_stack;
|
||
+ token->valid = true;
|
||
+#ifdef CONFIG_KOI
|
||
+ token->koi_kernel_stack = NULL;
|
||
+ token->koi_stack = NULL;
|
||
+ token->koi_stack_base = NULL;
|
||
+ token->current_ttbr1 = 0;
|
||
+#endif
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->mm = mm;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd)
|
||
+{
|
||
+ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+ token->pgd = pgd;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr)
|
||
+{
|
||
+ pptr = (freeptr_t *)__phys_to_iee(__pa(pptr));
|
||
+ *pptr = ptr;
|
||
+}
|
||
+
|
||
+#pragma GCC push_options
|
||
+#pragma GCC optimize("O0")
|
||
+void __iee_code _iee_memset(void *ptr, int data, size_t n)
|
||
+{
|
||
+ char *_ptr = (char *)__phys_to_iee(__pa(ptr));
|
||
+
|
||
+ while (n--)
|
||
+ *_ptr++ = data;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_memcpy(void *dst, void *src, size_t n)
|
||
+{
|
||
+ char *_dst = (char *)__phys_to_iee(__pa(dst));
|
||
+ char *_src = (char *)src;
|
||
+
|
||
+ while(n--)
|
||
+ *_dst++ = *_src++;
|
||
+}
|
||
+#pragma GCC pop_options
|
||
+
|
||
+void __iee_code _iee_set_track(struct track *ptr, struct track *data)
|
||
+{
|
||
+ _iee_memcpy(ptr, data, sizeof(struct track));
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu)
|
||
+{
|
||
+ if(cred == &init_cred)
|
||
+ cred = (struct cred *)__phys_to_iee(__pa_symbol(cred));
|
||
+ else
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ #ifdef CONFIG_CREDP
|
||
+ *((struct rcu_head **)(&(cred->rcu.func))) = rcu;
|
||
+ #endif
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_security(struct cred *cred, void *security)
|
||
+{
|
||
+ if(cred == &init_cred)
|
||
+ cred = (struct cred *)__phys_to_iee(__pa_symbol(cred));
|
||
+ else
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->security = security;
|
||
+}
|
||
+
|
||
+bool __iee_code _iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ switch (flag)
|
||
+ {
|
||
+ case AT_ADD: {
|
||
+ atomic_long_add(nr, &cred->usage);
|
||
+ return 0;
|
||
+ }
|
||
+ case AT_INC_NOT_ZERO: {
|
||
+ return atomic_long_inc_not_zero(&cred->usage);
|
||
+ }
|
||
+ case AT_SUB_AND_TEST: {
|
||
+ return atomic_long_sub_and_test(nr, &cred->usage);
|
||
+ }
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_atomic_set_usage(struct cred *cred, int i)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ atomic_long_set(&cred->usage,i);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_non_rcu(struct cred *cred, int non_rcu)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->non_rcu = non_rcu;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->session_keyring = session_keyring;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->process_keyring = process_keyring;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->thread_keyring = thread_keyring;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->request_key_auth = request_key_auth;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->jit_keyring = jit_keyring;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->cap_inheritable = cap_inheritable;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->cap_permitted = cap_permitted;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->cap_effective = cap_effective;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->cap_bset = cap_bset;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->cap_ambient = cap_ambient;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_securebits(struct cred *cred, unsigned securebits)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->securebits = securebits;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_group_info(struct cred *cred, struct group_info *group_info)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->group_info = group_info;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->ucounts = ucounts;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->user_ns = user_ns;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_user(struct cred *cred, struct user_struct *user)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->user = user;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->fsgid = fsgid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->fsuid = fsuid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_egid(struct cred *cred, kgid_t egid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->egid = egid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_euid(struct cred *cred, kuid_t euid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->euid = euid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_sgid(struct cred *cred, kgid_t sgid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->sgid = sgid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_suid(struct cred *cred, kuid_t suid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->suid = suid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_copy_cred(struct cred *old, struct cred *new)
|
||
+{
|
||
+ #ifdef CONFIG_CREDP
|
||
+ struct rcu_head *rcu = (struct rcu_head *)(new->rcu.func);
|
||
+ struct cred *_new = (struct cred *)__phys_to_iee(__pa(new));
|
||
+ _iee_memcpy(new,old,sizeof(struct cred));
|
||
+ *(struct rcu_head **)(&(_new->rcu.func)) = rcu;
|
||
+ *(struct rcu_head *)(_new->rcu.func) = *(struct rcu_head *)(old->rcu.func);
|
||
+ #endif
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_gid(struct cred *cred, kgid_t gid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->gid = gid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_cred_uid(struct cred *cred, kuid_t uid)
|
||
+{
|
||
+ cred = (struct cred *)__phys_to_iee(__pa(cred));
|
||
+ cred->uid = uid;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_write_in_byte(void *ptr, __u64 data, int length)
|
||
+{
|
||
+ ptr = (void *)__phys_to_iee(__pa(ptr));
|
||
+ switch(length) {
|
||
+ case 8: {
|
||
+ *(__u64 *)ptr = data;
|
||
+ break;
|
||
+ }
|
||
+ case 4: {
|
||
+ *(__u32 *)ptr = (__u32)data;
|
||
+ break;
|
||
+ }
|
||
+ case 2: {
|
||
+ *(__u16 *)ptr = (__u16)data;
|
||
+ break;
|
||
+ }
|
||
+ case 1: {
|
||
+ *(__u8 *)ptr = (__u8)data;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+pteval_t __iee_code _iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval)
|
||
+{
|
||
+ pteval_t ret = xchg_relaxed((pteval_t *)(__phys_to_iee(__pa(ptep))), pteval);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+pteval_t __iee_code _iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval)
|
||
+{
|
||
+ pteval_t pteval = cmpxchg_relaxed((pteval_t *)(__phys_to_iee(__pa(ptep))), old_pteval, new_pteval);
|
||
+ return pteval;
|
||
+}
|
||
+
|
||
+/* Check if addr is allocated in IEE page */
|
||
+static inline bool check_addr_in_iee_valid(unsigned long addr)
|
||
+{
|
||
+ unsigned long flags;
|
||
+ unsigned long res;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile("at s1e1r, %0"::"r"(addr));
|
||
+ isb();
|
||
+ res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+
|
||
+ // If it is not logical map, that means it is a token.
|
||
+ if(__phys_to_iee(res & PTE_ADDR_MASK) != addr)
|
||
+ return false;
|
||
+
|
||
+ return !(res & 0x1);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
|
||
+{
|
||
+ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
|
||
+{
|
||
+ if(!(pgd_val(pgd) & PMD_SECT_VALID))
|
||
+ {
|
||
+ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if ((pgd_val(pgd) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pgd_to_phys(pgd))))
|
||
+ panic("You can't use non-iee-pgtable\n");
|
||
+
|
||
+ if((pgdp >= pgd_offset_pgd((pgd_t *)swapper_pg_dir, PAGE_OFFSET + BIT(vabits_actual - 2))) && (pgdp < pgd_offset_pgd((pgd_t *)swapper_pg_dir, PAGE_OFFSET + BIT(vabits_actual - 1))) && !(pgd_val(pgd) & PGD_APT))
|
||
+ panic("Set IEE pgd U page.\n");
|
||
+
|
||
+ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_p4d(p4d_t *p4dp, p4d_t p4d)
|
||
+{
|
||
+ if(!(p4d_val(p4d) & PMD_SECT_VALID))
|
||
+ {
|
||
+ WRITE_ONCE(*((p4d_t *)(__phys_to_iee(__pa(p4dp)))), p4d);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if ((p4d_val(p4d) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__p4d_to_phys(p4d))))
|
||
+ panic("You can't use non-iee-pgtable\n");
|
||
+
|
||
+ WRITE_ONCE(*((p4d_t *)(__phys_to_iee(__pa(p4dp)))), p4d);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_pud(pud_t *pudp, pud_t pud)
|
||
+{
|
||
+ if(!(pud_val(pud) & PMD_SECT_VALID))
|
||
+ {
|
||
+ WRITE_ONCE(*((pud_t *)(__phys_to_iee(__pa(pudp)))), pud);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if ((pud_val(pud) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pud_to_phys(pud))))
|
||
+ panic("You can't use non-iee-pgtable\n");
|
||
+
|
||
+ WRITE_ONCE(*((pud_t *)(__phys_to_iee(__pa(pudp)))), pud);
|
||
+}
|
||
+
|
||
+// Return true if the modify does not break DEP.
|
||
+static inline bool check_pmd_dep(char *addr, pmd_t pmd)
|
||
+{
|
||
+ // DEP for kernel code and readonly data
|
||
+ // _text: .text start addr, __init_begin: .rodata end addr
|
||
+ if (addr >= _stext && addr < _etext)
|
||
+ {
|
||
+ if ((PTE_WRITE & pmd_val(pmd)) || // DBM == 1 --> writable
|
||
+ !(PTE_RDONLY & pmd_val(pmd))) // DBM == 0 && AP[2] = 0 --> writable
|
||
+ {
|
||
+ panic("Can't make kernel's text/readonly page as writable!\n"
|
||
+ "addr = 0x%16llx, pmd_val = 0x%16llx",
|
||
+ (u64)addr, pmd_val(pmd));
|
||
+ }
|
||
+ }
|
||
+ return true;
|
||
+}
|
||
+
|
||
+// Return true if the pmd table is a part of kernel page table.
|
||
+// TODO : Optimize to get lower overhead.
|
||
+static inline bool is_kernel_pmd_table(pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+ int i = 0,j = 0;
|
||
+ for(i = 0; i < PAGE_SIZE/sizeof(pgd_t); i++)
|
||
+ {
|
||
+ pgd_t *pgdp = (pgd_t *)swapper_pg_dir + i;
|
||
+ if((pgd_val(*pgdp) & PMD_SECT_VALID) && (pgd_val(*pgdp) & PMD_TABLE_BIT))
|
||
+ {
|
||
+ for(j = 0; j < PAGE_SIZE/sizeof(pud_t); j++)
|
||
+ {
|
||
+ pud_t *pudp = (pud_t *)__va(__pgd_to_phys(*pgdp)) + i;
|
||
+ if((pud_val(*pudp) & PMD_SECT_VALID) && (pud_val(*pudp) & PMD_TABLE_BIT))
|
||
+ {
|
||
+ pmd_t *current_pmdp = __va(__pud_to_phys(*pudp));
|
||
+ if((unsigned long)current_pmdp == ((unsigned long)pmdp & PAGE_MASK))
|
||
+ return true;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ return false;
|
||
+}
|
||
+
|
||
+// Return true if it is mapped to a physical range containing IEE page.
|
||
+// TODO : Optimize to get lower overhead.
|
||
+static inline bool check_addr_range_in_iee_valid(pmd_t pmd)
|
||
+{
|
||
+ int i = 0;
|
||
+ unsigned long addr = __phys_to_iee(__pmd_to_phys(pmd));
|
||
+ for(i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++)
|
||
+ {
|
||
+ if(check_addr_in_iee_valid(addr + PAGE_SIZE * i))
|
||
+ return true;
|
||
+ }
|
||
+ return false;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_pmd(pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+ char * addr = (char *)__phys_to_kimg(__pmd_to_phys(pmd));
|
||
+
|
||
+ if(!(pmd_val(pmd) & PMD_SECT_VALID))
|
||
+ {
|
||
+ WRITE_ONCE(*((pmd_t *)(__phys_to_iee(__pa(pmdp)))), pmd);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ // Check if the pte table is legally allocated.
|
||
+ if ((pmd_val(pmd) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pmd_to_phys(pmd))))
|
||
+ panic("You can't use non-iee-pgtable\n");
|
||
+
|
||
+ // Avoid mapping a huge pmd as U page.
|
||
+ if(!(pmd_val(pmd) & PMD_TABLE_BIT) && (pmd_val(pmd) & PMD_SECT_USER) && is_kernel_pmd_table(pmdp, pmd))
|
||
+ panic("Set a block descriptor in kernel space U page.\n");
|
||
+
|
||
+ // Avoid mapping a huge pmd to IEE physical page.
|
||
+ if(!(pmd_val(pmd) & PMD_TABLE_BIT) && check_addr_range_in_iee_valid(pmd))
|
||
+ panic("Mapping IEE physical page to a huge pmd.\n");
|
||
+
|
||
+ if(!check_pmd_dep(addr, pmd))
|
||
+ return;
|
||
+
|
||
+ WRITE_ONCE(*((pmd_t *)(__phys_to_iee(__pa(pmdp)))), pmd);
|
||
+}
|
||
+
|
||
+// Return true if the pte table is a part of kernel page table.
|
||
+// TODO : Optimize to get lower overhead.
|
||
+static inline bool is_kernel_pte_table(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ return false;
|
||
+}
|
||
+
|
||
+// Return true if it does not change the privilage or add new U page in kernel.
|
||
+static inline bool check_privilage_safe(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ if(!(pte_val(pte) & PTE_VALID))
|
||
+ return true;
|
||
+
|
||
+ if((pte_val(*ptep) & PTE_VALID))
|
||
+ {
|
||
+ if((pte_val(*ptep) & PTE_USER) != (pte_val(pte) & PTE_USER))
|
||
+ panic("Incorrectly change privilage.\n");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if((pte_val(pte) & PTE_USER) && is_kernel_pte_table(ptep, pte))
|
||
+ panic("Add new U page in kernel space.\n");
|
||
+ }
|
||
+ return true;
|
||
+}
|
||
+
|
||
+// TODO : When adding a new executable page, check it for DEP.
|
||
+static inline bool safely_adding_new_exec_page(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ return true;
|
||
+}
|
||
+
|
||
+// Return true if it is only changing prot of a pte.
|
||
+static inline bool is_changing_pte_prot(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ if(((pte_val(*ptep) ^ pte_val(pte)) & PTE_ADDR_MASK) == 0)
|
||
+ return true;
|
||
+ else
|
||
+ return false;
|
||
+}
|
||
+
|
||
+// Return true if the modify does not break DEP.
|
||
+static inline bool check_pte_dep(char *addr, pte_t pte)
|
||
+{
|
||
+ // DEP for kernel code and readonly data
|
||
+ // _text: .text start addr, __init_begin: .rodata end addr
|
||
+ if (addr >= _stext && addr < _etext)
|
||
+ {
|
||
+ if ((PTE_WRITE & pte_val(pte)) // DBM == 1 --> writable
|
||
+ || !(PTE_RDONLY & pte_val(pte))) // DBM == 0 && AP[2] = 0 --> writable
|
||
+ {
|
||
+ panic("Can't make kernel's text/readonly page as writable!\n"
|
||
+ "addr = 0x%16llx, pte_val = 0x%16llx",
|
||
+ (u64)addr, pte_val(pte));
|
||
+ }
|
||
+ }
|
||
+ return true;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_pte(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ char * addr = (char *)__phys_to_kimg(__pte_to_phys(pte));
|
||
+
|
||
+ if(!(pte_val(pte) & PTE_VALID))
|
||
+ {
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ // Avoid modify privilage unsafely.
|
||
+ if(!check_privilage_safe(ptep, pte))
|
||
+ panic("You are modify privilage unsafely.\n");
|
||
+
|
||
+ // Avoid mapping a new executable page.
|
||
+ if(!safely_adding_new_exec_page(ptep, pte))
|
||
+ panic("You are adding a new executable page unsafely.\n");
|
||
+
|
||
+ // Avoid mapping a new VA to IEE PA.
|
||
+ if(!is_changing_pte_prot(ptep, pte) &&
|
||
+ check_addr_in_iee_valid(__phys_to_iee(__pte_to_phys(pte))))
|
||
+ panic("You are remmaping IEE page to other VA.\n");
|
||
+
|
||
+ // Avoid mapping a writable VA to kernel code PA.
|
||
+ if(!check_pte_dep(addr, pte))
|
||
+ return;
|
||
+
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
|
||
+}
|
||
+
|
||
+// Return true if it only sets U page and modify NG.
|
||
+static inline bool is_setting_upage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ if(((pte_val(*ptep) ^ pte_val(pte)) & ~(PTE_USER | PTE_NG)) != 0)
|
||
+ panic("Incorrectly setting U page.\n");
|
||
+ if((pte_val(pte) & PTE_USER) != PTE_USER)
|
||
+ panic("Using error interface to set P page.\n");
|
||
+ return true;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_pte_upage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ // Check if it only change the prot.
|
||
+ if(!is_setting_upage(ptep,pte))
|
||
+ panic("Incorrectly setting U page.\n");
|
||
+
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
|
||
+}
|
||
+
|
||
+// Return true if it only sets P page and modify NG.
|
||
+static inline bool is_setting_ppage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ if(((pte_val(*ptep) ^ pte_val(pte)) & ~(PTE_USER | PTE_NG)) != 0)
|
||
+ panic("Incorrectly setting P page.\n");
|
||
+ if((pte_val(pte) & PTE_USER) != 0)
|
||
+ panic("Using error interface to set U page.\n");
|
||
+ return true;
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_pte_ppage(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ // Check if it only change the prot.
|
||
+ if(!is_setting_ppage(ptep,pte))
|
||
+ panic("Incorrectly setting P page.\n");
|
||
+
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
|
||
+}
|
||
+
|
||
+void __iee_code _iee_set_bm_pte(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa_symbol(ptep)))), pte);
|
||
+}
|
||
+
|
||
+/* Data in iee_si_base is visible to all pgd while iee_si_data is private. */
|
||
+unsigned long iee_base_idmap_pg_dir __iee_si_data;
|
||
+unsigned long iee_base_reserved_pg_dir __iee_si_data;
|
||
+unsigned long iee_base__bp_harden_el1_vectors __iee_si_data;
|
||
+bool iee_init_done __iee_si_data;
|
||
+unsigned long iee_si_tcr __iee_si_data;
|
||
+
|
||
+static u64 __iee_si_code inline iee_si_mask(unsigned long mask, unsigned long new_val, unsigned long old_val)
|
||
+{
|
||
+ return (new_val & mask) | (old_val & ~mask);
|
||
+}
|
||
+/*
|
||
+ * handler function for requests of executing sensitive instrutions.
|
||
+ */
|
||
+u64 __iee_si_code iee_si_handler(int flag, ...)
|
||
+{
|
||
+ va_list pArgs;
|
||
+ u64 old_val, new_val;
|
||
+
|
||
+ // BUG_ON(flag > IEE_WRITE_MDSCR);
|
||
+ va_start(pArgs, flag);
|
||
+ switch (flag) {
|
||
+ case IEE_SI_TEST:
|
||
+ break;
|
||
+ case IEE_WRITE_SCTLR: {
|
||
+ old_val = read_sysreg(sctlr_el1);
|
||
+ new_val = va_arg(pArgs, u64);
|
||
+ new_val = iee_si_mask(IEE_SCTLR_MASK, new_val, old_val);
|
||
+ write_sysreg(new_val, sctlr_el1);
|
||
+ break;
|
||
+ }
|
||
+ case IEE_WRITE_TTBR0:
|
||
+ case IEE_CONTEXT_SWITCH: {
|
||
+ u64 new_asid, new_phys, old_phys, token_phys;
|
||
+ struct task_struct *tsk;
|
||
+ struct task_token *token;
|
||
+ new_val = va_arg(pArgs, u64);
|
||
+ new_phys = (new_val & PAGE_MASK) & ~TTBR_ASID_MASK;
|
||
+ new_asid = new_val >> 48;
|
||
+
|
||
+ // Check ASID first
|
||
+ if (new_phys == iee_base_reserved_pg_dir){
|
||
+ if (new_asid != 1)
|
||
+ panic("IEE SI warning: reserved_pg_dir ASID invalid: %llx:%llx", new_asid, new_val);
|
||
+ }
|
||
+ // Already reserved asid 1 for iee rwx gate.
|
||
+ else if (new_asid == 0){
|
||
+ new_val |= FIELD_PREP(TTBR_ASID_MASK, 1);
|
||
+ printk("IEE SI: Modify ASID of %llx to 1.", new_val);
|
||
+ }
|
||
+ // TO DO: operations to protect idmap_pg_dir
|
||
+ else if (new_phys == iee_base_idmap_pg_dir)
|
||
+ {
|
||
+ // printk("IEE SI: switch to idmap_pg_dir.);
|
||
+ }
|
||
+ else if (new_asid % 2 ==0)
|
||
+ panic("IEE SI warning: TTBR0 ASID invalid: %llx:%llx", new_asid, new_val);
|
||
+
|
||
+ /* Skip verification if iee hasn't been initialized. */
|
||
+ if (iee_init_done){
|
||
+ // Verify current sp_el0 with iee token info
|
||
+ asm volatile("mrs %x0, sp_el0":"=r"(tsk));
|
||
+ token = (struct task_token *)__phys_to_iee(__pa(tsk));
|
||
+
|
||
+ /*
|
||
+ * token->pgd != NULL means it is a user task, then we need to check whether current ttbr0 is correct.
|
||
+ */
|
||
+ if (token->pgd){
|
||
+ old_val = read_sysreg(ttbr0_el1);
|
||
+ // When TTBR0 is reserved_pg_dir then no checking is available.
|
||
+ if (old_val != iee_base_reserved_pg_dir){
|
||
+ old_phys = (old_val & PAGE_MASK) & ~TTBR_ASID_MASK;
|
||
+ token_phys = __pa(token->pgd);
|
||
+ if (old_phys != token_phys)
|
||
+ panic("IEE SI warning: Pgd set error. old ttbr0:%lx, token ttbr0:%lx, token pgd:%lx",
|
||
+ (unsigned long)old_phys, (unsigned long)token_phys, (unsigned long)(token->pgd));
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ // all checks are done.
|
||
+ write_sysreg(new_val, ttbr0_el1);
|
||
+
|
||
+ // SET ASID in TTBR1 when context switch
|
||
+ if (flag == IEE_CONTEXT_SWITCH){
|
||
+ new_val = (read_sysreg(ttbr1_el1) & ~TTBR_ASID_MASK) | FIELD_PREP(TTBR_ASID_MASK, new_asid-1);
|
||
+ write_sysreg(new_val, ttbr1_el1);
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ case IEE_WRITE_VBAR: {
|
||
+ u64 el1_vector;
|
||
+ new_val = va_arg(pArgs, u64);
|
||
+ el1_vector = iee_base__bp_harden_el1_vectors;
|
||
+ if(new_val == el1_vector || new_val == el1_vector+SZ_2K ||
|
||
+ new_val == el1_vector+SZ_2K*2 || new_val == el1_vector+SZ_2K*3)
|
||
+ write_sysreg(new_val, vbar_el1);
|
||
+ break;
|
||
+ }
|
||
+ case IEE_WRITE_TCR: {
|
||
+ old_val = read_sysreg(tcr_el1);
|
||
+ new_val = va_arg(pArgs, u64);
|
||
+ new_val = iee_si_mask(IEE_TCR_MASK, new_val, old_val);
|
||
+ write_sysreg(new_val, tcr_el1);
|
||
+ break;
|
||
+ }
|
||
+ case IEE_WRITE_MDSCR: {
|
||
+ old_val = read_sysreg(mdscr_el1);
|
||
+ new_val = va_arg(pArgs, u64);
|
||
+ new_val = iee_si_mask(IEE_MDSCR_MASK, new_val, old_val);
|
||
+ write_sysreg(new_val, mdscr_el1);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ va_end(pArgs);
|
||
+ return 0;
|
||
+}
|
||
+/*
|
||
+ * TODO: scan a page to check whether it contains sensitive instructions
|
||
+ * return 1 when finding sensitive inst, 0 on safe page.
|
||
+ */
|
||
+int iee_si_scan_page(unsigned long addr);
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/kernel/koi/Makefile b/arch/arm64/kernel/koi/Makefile
|
||
new file mode 100644
|
||
index 000000000000..9be8710b714a
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/koi/Makefile
|
||
@@ -0,0 +1 @@
|
||
+obj-y += koi.o
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/kernel/koi/koi.c b/arch/arm64/kernel/koi/koi.c
|
||
new file mode 100644
|
||
index 000000000000..716ba16ab358
|
||
--- /dev/null
|
||
+++ b/arch/arm64/kernel/koi/koi.c
|
||
@@ -0,0 +1,1327 @@
|
||
+#include "asm/koi.h"
|
||
+#include "linux/compiler_attributes.h"
|
||
+#include "linux/compiler_types.h"
|
||
+#include "asm/barrier.h"
|
||
+#include "asm-generic/bug.h"
|
||
+#include "asm-generic/errno-base.h"
|
||
+#include "asm-generic/memory_model.h"
|
||
+#include "asm-generic/pgtable-nop4d.h"
|
||
+#include "asm-generic/rwonce.h"
|
||
+#include "asm/pgalloc.h"
|
||
+#include "asm/memory.h"
|
||
+#include "linux/bitfield.h"
|
||
+#include "linux/compiler.h"
|
||
+#include "linux/types.h"
|
||
+#include "linux/spinlock.h"
|
||
+#include "linux/spinlock_types.h"
|
||
+#include "linux/kernel.h"
|
||
+#include "linux/rculist.h"
|
||
+#include "linux/rcupdate.h"
|
||
+#include "linux/list.h"
|
||
+#include "asm/current.h"
|
||
+#include "linux/compiler_types.h"
|
||
+#include "asm-generic/barrier.h"
|
||
+#include "asm-generic/rwonce.h"
|
||
+#include "asm-generic/pgalloc.h"
|
||
+#include "asm/cpufeature.h"
|
||
+#include "asm/kvm_hyp.h"
|
||
+#include "asm/mmu.h"
|
||
+#include "asm/mmu_context.h"
|
||
+#include "asm/page-def.h"
|
||
+#include "asm/pgalloc.h"
|
||
+#include "asm/pgtable-hwdef.h"
|
||
+#include "asm/pgtable-types.h"
|
||
+#include "asm/pgtable.h"
|
||
+#include "asm/string.h"
|
||
+#include "asm/sysreg.h"
|
||
+#include "linux/bitfield.h"
|
||
+#include "linux/compiler.h"
|
||
+#include "linux/export.h"
|
||
+#include "linux/gfp.h"
|
||
+#include "linux/huge_mm.h"
|
||
+#include "linux/kallsyms.h"
|
||
+#include "linux/kconfig.h"
|
||
+#include "linux/kern_levels.h"
|
||
+#include "linux/kernel.h"
|
||
+#include "linux/list.h"
|
||
+#include "linux/lockdep.h"
|
||
+#include "linux/mm.h"
|
||
+#include "linux/mm_types.h"
|
||
+#include "linux/pgtable.h"
|
||
+#include "linux/printk.h"
|
||
+#include "linux/rculist.h"
|
||
+#include "linux/rcupdate.h"
|
||
+#include "linux/rmap.h"
|
||
+#include "linux/sched.h"
|
||
+#include "linux/stddef.h"
|
||
+#include "linux/string.h"
|
||
+#include "linux/swap.h"
|
||
+#include "linux/swapops.h"
|
||
+#include "linux/types.h"
|
||
+#include "linux/slab.h"
|
||
+#include "linux/string.h"
|
||
+#include "linux/hashtable.h"
|
||
+
|
||
+#define __koi_code __section(".koi.text")
|
||
+#define __koi_data __section(".data..koi")
|
||
+
|
||
+extern unsigned long __koi_code_start[];
|
||
+extern unsigned long __koi_code_end[];
|
||
+extern unsigned long __koi_data_start[];
|
||
+extern unsigned long __koi_data_end[];
|
||
+#ifdef CONFIG_IEE
|
||
+extern unsigned long __iee_si_base_start[];
|
||
+extern unsigned long __iee_exec_entry_start[];
|
||
+extern unsigned long __iee_exec_entry_end[];
|
||
+#endif
|
||
+
|
||
+__koi_data unsigned long koi_swapper_ttbr1 = 0;
|
||
+EXPORT_SYMBOL(koi_swapper_ttbr1);
|
||
+#define KOI_SWAPPER_MASK 0x0000fffffffffff0
|
||
+
|
||
+__attribute__((aligned(PAGE_SIZE)))
|
||
+DEFINE_PER_CPU(unsigned long[PAGE_SIZE / sizeof(unsigned long)],
|
||
+ koi_irq_current_ttbr1);
|
||
+EXPORT_SYMBOL(koi_irq_current_ttbr1);
|
||
+
|
||
+extern void koi_switch_to_ko_stack(unsigned long stack_top);
|
||
+extern void init_ko_mm(struct mm_struct *ko_mm, pgd_t *pgdp);
|
||
+extern void koi_check_and_switch_context(struct mm_struct *mm);
|
||
+extern int koi_add_page_mapping(unsigned long dst, unsigned long src);
|
||
+extern unsigned long _iee_read_token_ttbr1(struct task_struct *tsk);
|
||
+/**
|
||
+*struct koi_mem_list - maintain a linked list of free memory in the kernel
|
||
+*@addr: stating address of this memory
|
||
+*@size: the size of the memory
|
||
+*@list: the head of the koi_mem_list
|
||
+*@rcu: for rcu
|
||
+*/
|
||
+struct koi_mem_list {
|
||
+ unsigned long addr;
|
||
+ unsigned long size;
|
||
+ struct list_head list;
|
||
+ struct rcu_head rcu;
|
||
+};
|
||
+//mapping parameter pointer to copy
|
||
+struct koi_addr_map {
|
||
+ unsigned long buffer_addr;
|
||
+ unsigned long orig_addr;
|
||
+ int offset;
|
||
+ struct hlist_node node;
|
||
+ struct rcu_head rcu;
|
||
+};
|
||
+
|
||
+DEFINE_HASHTABLE(koi_mem_htbl, HASH_TABLE_BIT);
|
||
+EXPORT_SYMBOL(koi_mem_htbl);
|
||
+DEFINE_SPINLOCK(koi_mem_htbl_spin_lock);
|
||
+EXPORT_SYMBOL(koi_mem_htbl_spin_lock);
|
||
+
|
||
+EXPORT_SYMBOL(koi_do_switch_to_ko_stack);
|
||
+EXPORT_SYMBOL(koi_do_switch_to_kernel_stack);
|
||
+
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+
|
||
+/**
|
||
+* koi_ttbr_ctor - return ttbr1 for the given driver module
|
||
+*/
|
||
+unsigned long koi_ttbr_ctor(struct module *mod)
|
||
+{
|
||
+ struct koi_mem_hash_node *ko;
|
||
+ struct mm_struct *ko_mm;
|
||
+ unsigned long ttbr1;
|
||
+ unsigned long asid;
|
||
+ int bkt;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
|
||
+ if (ko->mod == mod) {
|
||
+ ko_mm = ko->ko_mm;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (!ko_mm) {
|
||
+ printk(KERN_ERR "cannot found module %s in koi_mem_htbl",
|
||
+ mod->name);
|
||
+ return 0;
|
||
+ }
|
||
+ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
|
||
+ asid &= TTBR_ASID_MASK;
|
||
+ ttbr1 = ko->ko_ttbr1 | asid;
|
||
+ // koi_check_and_switch_context(ko_mm);
|
||
+ // asid = ASID(ko_mm);
|
||
+ // ttbr1 = ko->ko_ttbr1 | FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
+ return ttbr1;
|
||
+}
|
||
+EXPORT_SYMBOL(koi_ttbr_ctor);
|
||
+//release the hash node
|
||
+static __maybe_unused void koi_mem_hash_node_free(struct rcu_head *rcu)
|
||
+{
|
||
+ struct koi_mem_hash_node *node =
|
||
+ container_of(rcu, struct koi_mem_hash_node, rcu);
|
||
+ kfree(node);
|
||
+}
|
||
+//release free memory linked list nodes
|
||
+static void koi_mem_node_free(struct rcu_head *rcu)
|
||
+{
|
||
+ struct koi_mem_list *mem_node =
|
||
+ container_of(rcu, struct koi_mem_list, rcu);
|
||
+ kfree(mem_node);
|
||
+}
|
||
+//release the node in koi_addr_map
|
||
+static void koi_addr_map_node_free(struct rcu_head *rcu)
|
||
+{
|
||
+ struct koi_addr_map *addr_map_node =
|
||
+ container_of(rcu, struct koi_addr_map, rcu);
|
||
+ kfree(addr_map_node);
|
||
+}
|
||
+
|
||
+#ifndef CONFIG_IEE
|
||
+/*
|
||
+ * This function is used to switch to ko's pgtable.
|
||
+ */
|
||
+__koi_code noinline unsigned long koi_do_switch_to_ko_pgtbl(void)
|
||
+{
|
||
+ struct koi_mem_hash_node *ko;
|
||
+ // struct mm_struct *ko_mm;
|
||
+ unsigned long addr;
|
||
+ unsigned long ttbr1, asid;
|
||
+ unsigned long *ptr;
|
||
+ struct task_token *token_addr =
|
||
+ (struct task_token *)((unsigned long)current +
|
||
+ (unsigned long)koi_offset);
|
||
+ int bkt;
|
||
+ asm volatile(" mrs %0, elr_el1\n" : "=r"(addr));
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, __kern_my_cpu_offset());
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
|
||
+ if (ko->mod->init_layout.base != NULL) {
|
||
+ if (addr >= (unsigned long)ko->mod->init_layout.base &&
|
||
+ addr < (unsigned long)(ko->mod->init_layout.base +
|
||
+ ko->mod->init_layout.size)) {
|
||
+ if (token_addr->current_ttbr1 == ko->ko_ttbr1 ||
|
||
+ *ptr == ko->ko_ttbr1) {
|
||
+ // ko_mm = ko->ko_mm;
|
||
+ // koi_check_and_switch_context(ko_mm);
|
||
+ // asid = ASID(ko_mm);
|
||
+ // ttbr1 = ko->ko_ttbr1;
|
||
+ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
+ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
|
||
+ asid &= TTBR_ASID_MASK;
|
||
+ ttbr1 = ko->ko_ttbr1 | asid;
|
||
+ rcu_read_unlock();
|
||
+ return ttbr1;
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ if (addr >= (unsigned long)ko->mod->core_layout.base &&
|
||
+ addr < (unsigned long)ko->mod->core_layout.base +
|
||
+ ko->mod->core_layout.size) {
|
||
+ if (token_addr->current_ttbr1 == ko->ko_ttbr1 ||
|
||
+ *ptr == ko->ko_ttbr1) {
|
||
+ // ko_mm = ko->ko_mm;
|
||
+ // koi_check_and_switch_context(ko_mm);
|
||
+ // asid = ASID(ko_mm);
|
||
+ // ttbr1 = ko->ko_ttbr1;
|
||
+ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
+ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
|
||
+ asid &= TTBR_ASID_MASK;
|
||
+ ttbr1 = ko->ko_ttbr1 | asid;
|
||
+ rcu_read_unlock();
|
||
+ return ttbr1;
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ return 0;
|
||
+}
|
||
+/**
|
||
+* koi_do_switch_to_kernel_pgtbl - switch to kernel pagetable
|
||
+*/
|
||
+__koi_code noinline int koi_do_switch_to_kernel_pgtbl(void)
|
||
+{
|
||
+ unsigned long curr_ttbr1, asid;
|
||
+ // if (!cpu_online(smp_processor_id()))
|
||
+ // return 0;
|
||
+ asm volatile(" mrs %0, ttbr1_el1\n" : "=r"(curr_ttbr1));
|
||
+ if ((curr_ttbr1 & KOI_SWAPPER_MASK) ==
|
||
+ (koi_swapper_ttbr1 & KOI_SWAPPER_MASK)) {
|
||
+ return 0;
|
||
+ }
|
||
+ if (((curr_ttbr1 & TTBR_ASID_MASK) >> 48) <= 1) {
|
||
+ return 0;
|
||
+ }
|
||
+ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
|
||
+ asid &= ~USER_ASID_FLAG;
|
||
+ asid &= TTBR_ASID_MASK;
|
||
+ write_sysreg(koi_swapper_ttbr1 | asid, ttbr1_el1);
|
||
+ isb();
|
||
+ asm volatile(ALTERNATIVE("nop; nop; nop", "ic iallu; dsb nsh; isb",
|
||
+ ARM64_WORKAROUND_CAVIUM_27456));
|
||
+ return 1;
|
||
+}
|
||
+#else
|
||
+__koi_code noinline unsigned long koi_do_switch_to_ko_pgtbl(void)
|
||
+{
|
||
+ struct koi_mem_hash_node *ko;
|
||
+ struct mm_struct *ko_mm;
|
||
+ unsigned long addr, ttbr1, asid, pan_flag, current_ttbr1;
|
||
+ unsigned long *ptr;
|
||
+ int bkt;
|
||
+ asm volatile("mrs %0, pan\n"
|
||
+ "msr pan, 0x0\n"
|
||
+ : "=r"(pan_flag)
|
||
+ :);
|
||
+ current_ttbr1 = _iee_read_token_ttbr1(current);
|
||
+ asm volatile("msr pan, %0\n" : : "r"(pan_flag));
|
||
+ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, __kern_my_cpu_offset());
|
||
+ if (current_ttbr1 == 0 && *ptr == 0)
|
||
+ return 0;
|
||
+ asm volatile(" mrs %0, elr_el1\n" : "=r"(addr));
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
|
||
+ if (ko->mod->init_layout.base != NULL) {
|
||
+ if (addr >= (unsigned long)ko->mod->init_layout.base &&
|
||
+ addr < (unsigned long)(ko->mod->init_layout.base +
|
||
+ ko->mod->init_layout.size)) {
|
||
+ rcu_read_unlock();
|
||
+ if (current_ttbr1 == ko->ko_ttbr1 || *ptr == ko->ko_ttbr1) {
|
||
+ // ko_mm = ko->ko_mm;
|
||
+ // koi_check_and_switch_context(ko_mm);
|
||
+ // asid = ASID(ko_mm);
|
||
+ // ttbr1 = ko->ko_ttbr1;
|
||
+ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK,
|
||
+ // asid);
|
||
+ return ko->ko_ttbr1;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ if (addr >= (unsigned long)ko->mod->core_layout.base &&
|
||
+ addr < (unsigned long)ko->mod->core_layout.base +
|
||
+ ko->mod->core_layout.size) {
|
||
+ rcu_read_unlock();
|
||
+ if (current_ttbr1 == ko->ko_ttbr1 || *ptr == ko->ko_ttbr1) {
|
||
+ // ko_mm = ko->ko_mm;
|
||
+ // koi_check_and_switch_context(ko_mm);
|
||
+ // asid = ASID(ko_mm);
|
||
+ // ttbr1 = ko->ko_ttbr1;
|
||
+ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
+ return ko->ko_ttbr1;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+__koi_code noinline int koi_do_switch_to_kernel_pgtbl(void)
|
||
+{
|
||
+ unsigned long curr_ttbr1;
|
||
+ // if (!cpu_online(smp_processor_id()))
|
||
+ // return 0;
|
||
+ asm volatile(" mrs %0, ttbr1_el1\n" : "=r"(curr_ttbr1));
|
||
+ if ((curr_ttbr1 & KOI_SWAPPER_MASK) ==
|
||
+ (koi_swapper_ttbr1 & KOI_SWAPPER_MASK)) {
|
||
+ return 0;
|
||
+ }
|
||
+ if (((curr_ttbr1 & TTBR_ASID_MASK) >> 48) <= 1) {
|
||
+ return 0;
|
||
+ }
|
||
+ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL);
|
||
+ return 1;
|
||
+}
|
||
+#endif
|
||
+/**
|
||
+* koi_save_ttbr - save ttbr of each driver module
|
||
+* @mod: driver module
|
||
+* @pgdp:pointer to driver module top page table,pgd
|
||
+*/
|
||
+static void koi_save_ttbr(struct module *mod, pgd_t *pgdp,
|
||
+ struct koi_mem_hash_node *node)
|
||
+{
|
||
+ phys_addr_t ttbr1 = phys_to_ttbr(virt_to_phys(pgdp));
|
||
+ if (system_supports_cnp())
|
||
+ ttbr1 |= TTBR_CNP_BIT;
|
||
+ node->ko_ttbr1 = ttbr1;
|
||
+}
|
||
+/**
|
||
+*kio_normal_page - to obtain the pointer of the corresponding struct page structure
|
||
+*from a given page table entry(pte)
|
||
+*/
|
||
+struct page *koi_normal_page(pte_t pte)
|
||
+{
|
||
+ unsigned long pfn = pte_pfn(pte);
|
||
+
|
||
+ if (IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL)) {
|
||
+ if (likely(!pte_special(pte)))
|
||
+ goto check_pfn;
|
||
+ if (is_zero_pfn(pfn)) {
|
||
+ printk(KERN_ERR "zero pfn found! pte=0x%16lx\n", pte);
|
||
+ return NULL;
|
||
+ }
|
||
+ if (pte_devmap(pte)) {
|
||
+ printk(KERN_ERR "pte for dev found! pte=0x%16lx\n",
|
||
+ pte);
|
||
+ return NULL;
|
||
+ }
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+check_pfn:
|
||
+ return pfn_to_page(pfn);
|
||
+}
|
||
+
|
||
+/**
|
||
+ * Copy one pte. Returns 0 if succeeded, or -EAGAIN if one preallocated page
|
||
+ * is required to copy this pte.
|
||
+*/
|
||
+static inline int koi_copy_present_pte(pte_t *dst_pte, pte_t *src_pte,
|
||
+ unsigned long addr,
|
||
+ struct page **prealloc)
|
||
+{
|
||
+ pte_t pte = *src_pte;
|
||
+ struct page *page;
|
||
+
|
||
+ page = koi_normal_page(pte);
|
||
+ if (!page) {
|
||
+ printk(KERN_ERR "pte_page unavailable. Impossible.....\n");
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ set_pte(dst_pte, pte);
|
||
+ return 0;
|
||
+}
|
||
+/**
|
||
+* copy huge pmd from kernel space to driver space.
|
||
+*/
|
||
+static int koi_copy_huge_pmd(struct mm_struct *ko_mm, pmd_t *dst_pmd,
|
||
+ pmd_t *src_pmd, unsigned long addr)
|
||
+{
|
||
+ spinlock_t *src_ptl;
|
||
+ pmd_t pmd;
|
||
+ int ret = -ENOMEM;
|
||
+
|
||
+ src_ptl = pmd_lockptr(&init_mm, src_pmd);
|
||
+ spin_lock_bh(src_ptl);
|
||
+
|
||
+ ret = -EAGAIN;
|
||
+ pmd = *src_pmd;
|
||
+
|
||
+ set_pte((pte_t *)dst_pmd, pmd_pte(pmd));
|
||
+ ret = 0;
|
||
+ spin_unlock_bh(src_ptl);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int __koi_pte_alloc(struct mm_struct *mm, pmd_t *pmd)
|
||
+{
|
||
+ spinlock_t *ptl;
|
||
+ pgtable_t new = pte_alloc_one(mm);
|
||
+ if (!new)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ /*
|
||
+ * Ensure all pte setup (eg. pte page lock and page clearing) are
|
||
+ * visible before the pte is made visible to other CPUs by being
|
||
+ * put into page tables.
|
||
+ *
|
||
+ * The other side of the story is the pointer chasing in the page
|
||
+ * table walking code (when walking the page table without locking;
|
||
+ * ie. most of the time). Fortunately, these data accesses consist
|
||
+ * of a chain of data-dependent loads, meaning most CPUs (alpha
|
||
+ * being the notable exception) will already guarantee loads are
|
||
+ * seen in-order. See the alpha page table accessors for the
|
||
+ * smp_rmb() barriers in page table walking code.
|
||
+ */
|
||
+ smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
|
||
+
|
||
+ ptl = pmd_lockptr(mm, pmd);
|
||
+ spin_lock_bh(ptl);
|
||
+ if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_t *pte = (pte_t *)page_address(new);
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(pte));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)pte);
|
||
+ #endif
|
||
+ mm_inc_nr_ptes(mm);
|
||
+ pmd_populate(mm, pmd, new);
|
||
+ new = NULL;
|
||
+ }
|
||
+ spin_unlock_bh(ptl);
|
||
+ if (new)
|
||
+ pte_free(mm, new);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#define koi_pte_alloc(mm, pmd) (unlikely(pmd_none(*(pmd))) && __koi_pte_alloc(mm, pmd))
|
||
+
|
||
+#define koi_pte_offset_map_lock(mm, pmd, address, ptlp) \
|
||
+({ \
|
||
+ spinlock_t *__ptl = pte_lockptr(mm, pmd); \
|
||
+ pte_t *__pte = pte_offset_map(pmd, address); \
|
||
+ *(ptlp) = __ptl; \
|
||
+ spin_lock_bh(__ptl); \
|
||
+ __pte; \
|
||
+})
|
||
+
|
||
+#define koi_pte_alloc_map_lock(mm, pmd, address, ptlp) \
|
||
+ (koi_pte_alloc(mm, pmd) ? \
|
||
+ NULL : koi_pte_offset_map_lock(mm, pmd, address, ptlp))
|
||
+
|
||
+/**
|
||
+*koi_copy_pte_range - copy pte from kernel space to driver space
|
||
+*/
|
||
+static int koi_copy_pte_range(struct mm_struct *ko_mm, pmd_t *dst_pmd,
|
||
+ pmd_t *src_pmd, unsigned long addr,
|
||
+ unsigned long end)
|
||
+{
|
||
+ pte_t *src_pte, *dst_pte;
|
||
+ spinlock_t *src_ptl, *dst_ptl;
|
||
+ int ret = 0;
|
||
+ struct page *prealloc = NULL;
|
||
+again:
|
||
+ dst_pte = koi_pte_alloc_map_lock(ko_mm, dst_pmd, addr, &dst_ptl);
|
||
+ if (!dst_pte) {
|
||
+ ret = -ENOMEM;
|
||
+ goto out;
|
||
+ }
|
||
+ src_pte = pte_offset_map(src_pmd, addr);
|
||
+ src_ptl = pte_lockptr(&init_mm, src_pmd);
|
||
+ spin_lock_bh(src_ptl);
|
||
+ arch_enter_lazy_mmu_mode();
|
||
+
|
||
+ do {
|
||
+ if (pte_none(*src_pte))
|
||
+ continue;
|
||
+ if (unlikely(!pte_present(*src_pte))) {
|
||
+ continue;
|
||
+ }
|
||
+ /* koi_copy_present_pte() will clear `*prealloc` if consumed */
|
||
+ ret = koi_copy_present_pte(dst_pte, src_pte, addr, &prealloc);
|
||
+ if (unlikely(ret == -EAGAIN))
|
||
+ break;
|
||
+ if (unlikely(prealloc)) {
|
||
+ put_page(prealloc);
|
||
+ prealloc = NULL;
|
||
+ }
|
||
+ } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
|
||
+ arch_leave_lazy_mmu_mode();
|
||
+ spin_unlock_bh(src_ptl);
|
||
+ spin_unlock_bh(dst_ptl);
|
||
+
|
||
+ if (ret) {
|
||
+ WARN_ON_ONCE(ret != -EAGAIN);
|
||
+ ret = 0;
|
||
+ }
|
||
+ if (addr != end)
|
||
+ goto again;
|
||
+out:
|
||
+ if (unlikely(prealloc))
|
||
+ put_page(prealloc);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int __koi_pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
|
||
+{
|
||
+ spinlock_t *ptl;
|
||
+ pmd_t *new = pmd_alloc_one(mm, address);
|
||
+ if (!new)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ smp_wmb(); /* See comment in __pte_alloc */
|
||
+
|
||
+ ptl = pud_lockptr(mm, pud);
|
||
+ spin_lock_bh(ptl);
|
||
+ if (!pud_present(*pud)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(new));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+ #endif
|
||
+ mm_inc_nr_pmds(mm);
|
||
+ pud_populate(mm, pud, new);
|
||
+ } else /* Another has populated it */
|
||
+ pmd_free(mm, new);
|
||
+ spin_unlock_bh(ptl);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static inline pmd_t *koi_pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
|
||
+{
|
||
+ return (unlikely(pud_none(*pud)) && __koi_pmd_alloc(mm, pud, address))?
|
||
+ NULL: pmd_offset(pud, address);
|
||
+}
|
||
+
|
||
+/**
|
||
+*kio_copy_pmd_range - copy pmd from kernel to driver space
|
||
+*/
|
||
+static inline int koi_copy_pmd_range(struct mm_struct *ko_mm, pud_t *dst_pud,
|
||
+ pud_t *src_pud, unsigned long addr,
|
||
+ unsigned long end)
|
||
+{
|
||
+ pmd_t *src_pmd, *dst_pmd;
|
||
+ unsigned long next;
|
||
+ int err;
|
||
+
|
||
+ dst_pmd = koi_pmd_alloc(ko_mm, dst_pud, addr);
|
||
+ if (!dst_pmd) {
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ src_pmd = pmd_offset(src_pud, addr);
|
||
+ do {
|
||
+ next = pmd_addr_end(addr, end);
|
||
+ // CONFIG_TRANSPARENT_HUGEPAGE is enabled, so we must add copy_huge_pmd
|
||
+ if (is_swap_pmd(*src_pmd) || pmd_trans_huge(*src_pmd) ||
|
||
+ (pmd_devmap(*src_pmd))) {
|
||
+ err = koi_copy_huge_pmd(ko_mm, dst_pmd, src_pmd, addr);
|
||
+ if (err == -ENOMEM)
|
||
+ return -ENOMEM;
|
||
+ if (!err)
|
||
+ continue;
|
||
+ }
|
||
+ if (pmd_none_or_clear_bad(src_pmd)) {
|
||
+ continue;
|
||
+ }
|
||
+ if (koi_copy_pte_range(ko_mm, dst_pmd, src_pmd, addr, next))
|
||
+ return -ENOMEM;
|
||
+ } while (dst_pmd++, src_pmd++, addr = next, addr != end);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+int __koi_pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address)
|
||
+{
|
||
+ pud_t *new = pud_alloc_one(mm, address);
|
||
+ if (!new)
|
||
+ return -ENOMEM;
|
||
+
|
||
+ smp_wmb(); /* See comment in __pte_alloc */
|
||
+
|
||
+ spin_lock_bh(&mm->page_table_lock);
|
||
+ if (!p4d_present(*p4d)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(new));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+ #endif
|
||
+ mm_inc_nr_puds(mm);
|
||
+ p4d_populate(mm, p4d, new);
|
||
+ } else /* Another has populated it */
|
||
+ pud_free(mm, new);
|
||
+ spin_unlock_bh(&mm->page_table_lock);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static inline pud_t *koi_pud_alloc(struct mm_struct *mm, p4d_t *p4d,
|
||
+ unsigned long address)
|
||
+{
|
||
+ return (unlikely(p4d_none(*p4d)) && __koi_pud_alloc(mm, p4d, address)) ?
|
||
+ NULL : pud_offset(p4d, address);
|
||
+}
|
||
+
|
||
+/**
|
||
+*koi_copy_pud_range - copy pud from kernel to driver
|
||
+*/
|
||
+static inline int koi_copy_pud_range(struct mm_struct *ko_mm, p4d_t *dst_p4d,
|
||
+ p4d_t *src_p4d, unsigned long addr,
|
||
+ unsigned long end)
|
||
+{
|
||
+ pud_t *src_pud, *dst_pud;
|
||
+ unsigned long next;
|
||
+ dst_pud = koi_pud_alloc(ko_mm, dst_p4d, addr);
|
||
+ if (!dst_pud)
|
||
+ return -ENOMEM;
|
||
+ src_pud = pud_offset(src_p4d, addr);
|
||
+ do {
|
||
+ next = pud_addr_end(addr, end);
|
||
+ if (pud_trans_huge(*src_pud) || pud_devmap(*src_pud)) {
|
||
+ continue;
|
||
+ /* fall through */
|
||
+ }
|
||
+ if (pud_none_or_clear_bad(src_pud))
|
||
+ continue;
|
||
+ if (koi_copy_pmd_range(ko_mm, dst_pud, src_pud, addr, next))
|
||
+ return -ENOMEM;
|
||
+ } while (dst_pud++, src_pud++, addr = next, addr != end);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/**
|
||
+* koi_copy_p4d_range - map the kernel pagetable to the driver space level by level
|
||
+* @ko_mm: the mm_struct of driver module
|
||
+* @dst_pgd: destination pgd
|
||
+* @src_pgd: source pgd
|
||
+* @addr: the start of address
|
||
+* @end: the end of address
|
||
+*/
|
||
+static inline int koi_copy_p4d_range(struct mm_struct *ko_mm, pgd_t *dst_pgd,
|
||
+ pgd_t *src_pgd, unsigned long addr,
|
||
+ unsigned long end)
|
||
+{
|
||
+ p4d_t *src_p4d, *dst_p4d;
|
||
+ unsigned long next;
|
||
+ dst_p4d = p4d_alloc(ko_mm, dst_pgd, addr);
|
||
+ if (!dst_p4d)
|
||
+ return -ENOMEM;
|
||
+ src_p4d = p4d_offset(src_pgd, addr);
|
||
+ do {
|
||
+ next = p4d_addr_end(addr, end);
|
||
+ if (p4d_none_or_clear_bad(src_p4d))
|
||
+ continue;
|
||
+ if (koi_copy_pud_range(ko_mm, dst_p4d, src_p4d, addr, next)) {
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ } while (dst_p4d++, src_p4d++, addr = next, addr != end);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/**
|
||
+*int koi_copy_pagetable - map the address range from "addr" to "end" to the driver pagetable
|
||
+*@ko_mm: the mm_struct of the driver module
|
||
+*@koi_pg_dir: koi_pg_dir, related to the driver module, the entry for driver pagetable
|
||
+*@addr: the starting address of mapping zone
|
||
+*@end: the end address of mapping zone
|
||
+*/
|
||
+int koi_copy_pagetable(struct mm_struct *ko_mm, pgd_t *koi_pg_dir,
|
||
+ unsigned long addr, unsigned long end)
|
||
+{
|
||
+ int ret = 0;
|
||
+ unsigned long next;
|
||
+
|
||
+ pgd_t *src_pgd, *dst_pgd;
|
||
+
|
||
+ src_pgd = pgd_offset_pgd(swapper_pg_dir, addr);
|
||
+ dst_pgd = pgd_offset_pgd(koi_pg_dir, addr);
|
||
+ do {
|
||
+ next = pgd_addr_end(addr, end);
|
||
+ if (pgd_none_or_clear_bad(src_pgd))
|
||
+ continue;
|
||
+ if (unlikely(koi_copy_p4d_range(ko_mm, dst_pgd, src_pgd, addr,
|
||
+ next))) {
|
||
+ ret = -ENOMEM;
|
||
+ break;
|
||
+ }
|
||
+ } while (dst_pgd++, src_pgd++, addr = next, addr != end);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+void koi_set_rdonly(unsigned long addr, pgd_t *pgdir)
|
||
+{
|
||
+ p4d_t *p4dp;
|
||
+ pud_t *pudp;
|
||
+ pmd_t *pmdp;
|
||
+ pte_t *ptep;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+ if (pgd_none(*pgdp) || pgd_bad(*pgdp)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ p4dp = p4d_offset(pgdp, addr);
|
||
+ if (p4d_none(*p4dp) || p4d_bad(*p4dp)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ pudp = pud_offset(p4dp, addr);
|
||
+ if (pud_none(*pudp) || pud_bad(*pudp)) {
|
||
+ return;
|
||
+ }
|
||
+ pmdp = pmd_offset(pudp, addr);
|
||
+ if (pmd_none(*pmdp) || pmd_bad(*pmdp)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ ptep = pte_offset_kernel(pmdp, addr);
|
||
+ if (pte_none(*ptep)) {
|
||
+ printk(KERN_ERR "ptep 0x%llx not available\n", ptep);
|
||
+ return;
|
||
+ }
|
||
+ set_pte(ptep, __pte(pte_val(*ptep) | PTE_RDONLY));
|
||
+ printk(KERN_ERR "set_readonly successfully\n");
|
||
+ return;
|
||
+}
|
||
+
|
||
+/**
|
||
+* koi_create_pagetable - create pagetable for driver
|
||
+* @mod: driver module
|
||
+* 1.create a new koi_mem_hash_node new_node
|
||
+* 2.create page table return the pgd address, init the new_node->pgdp
|
||
+* 3.create and init the new_node->ko_mm
|
||
+* 4.map swapper_ttbr1 to the newly created pagetable
|
||
+* 5.map the interrupt vector table to the newly created pagetable
|
||
+* 6.map the init_layout of the module
|
||
+* 7.map the core_layout of the module
|
||
+* 8.map switch_to_kernel_pgtable into driver view
|
||
+* 9.map share memory
|
||
+*/
|
||
+void koi_create_pagetable(struct module *mod)
|
||
+{
|
||
+ int ret = 0, cpu;
|
||
+ unsigned long vbar, addr, ttbr1;
|
||
+ pgd_t *pgdp;
|
||
+ unsigned long *ptr;
|
||
+ struct koi_mem_list *new_mem_node;
|
||
+ struct koi_mem_hash_node *new_node =
|
||
+ kzalloc(sizeof(struct koi_mem_hash_node), GFP_KERNEL);
|
||
+ if (!new_node) {
|
||
+ printk(KERN_ERR "NULL new_node\n");
|
||
+ return;
|
||
+ };
|
||
+ if (koi_swapper_ttbr1 == 0) {
|
||
+ pgdp = lm_alias(swapper_pg_dir);
|
||
+ ttbr1 = phys_to_ttbr(virt_to_phys(pgdp));
|
||
+ if (system_supports_cnp() &&
|
||
+ !WARN_ON(pgdp != lm_alias(swapper_pg_dir)))
|
||
+ ttbr1 |= TTBR_CNP_BIT;
|
||
+#ifdef CONFIG_IEE
|
||
+ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, 1);
|
||
+#endif
|
||
+ koi_swapper_ttbr1 = ttbr1;
|
||
+ // __WRITE_ONCE(koi_swapper_ttbr1, ttbr1);
|
||
+ // koi_set_rdonly(&koi_swapper_ttbr1, swapper_pg_dir);
|
||
+ }
|
||
+ new_node->pgdp = koi_pgd_alloc();
|
||
+ new_node->ko_mm =
|
||
+ kzalloc(sizeof(struct mm_struct) +
|
||
+ sizeof(unsigned long) * BITS_TO_LONGS(NR_CPUS),
|
||
+ GFP_KERNEL);
|
||
+ init_ko_mm(new_node->ko_mm, new_node->pgdp);
|
||
+ new_node->mod = mod;
|
||
+ koi_save_ttbr(mod, new_node->pgdp, new_node);
|
||
+ printk(KERN_ERR "copying koi_data, start=0x%16llx, end=0x%16llx\n",
|
||
+ (unsigned long)__koi_data_start, (unsigned long)__koi_data_end);
|
||
+ // copy koi_swapper_ttbr1, which records page dir base for kernel view
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)__koi_data_start,
|
||
+ (unsigned long)__koi_data_end);
|
||
+ asm volatile("mrs %0, VBAR_EL1\n" : "=r"(vbar) :);
|
||
+
|
||
+ // copy interrupt vectors
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp, vbar & PAGE_MASK,
|
||
+ (vbar + PAGE_SIZE) & PAGE_MASK);
|
||
+
|
||
+ // copy module init_layout, which contains init data and text in driver
|
||
+ ret = koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)mod->init_layout.base,
|
||
+ (unsigned long)mod->init_layout.base +
|
||
+ mod->init_layout.size);
|
||
+ if (ret != 0)
|
||
+ printk(KERN_ERR
|
||
+ "\033[33mError occur when copying init_layout, Eno:%d\033[0m\n",
|
||
+ ret);
|
||
+
|
||
+ // copy module core_layout, which contains non-init data and text in driver
|
||
+ ret = koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)mod->core_layout.base,
|
||
+ (unsigned long)mod->core_layout.base +
|
||
+ mod->core_layout.size);
|
||
+ if (ret != 0)
|
||
+ printk(KERN_ERR
|
||
+ "\033[33mError occur when copying core_layout, Eno: %d\033[0m\n",
|
||
+ ret);
|
||
+
|
||
+ // mapping switch_to_kernel_pgtable into driver view, which is used to switch to kernel view when entering INT
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)__koi_code_start,
|
||
+ (unsigned long)__koi_code_end);
|
||
+
|
||
+ for_each_possible_cpu (cpu) {
|
||
+ ptr = per_cpu(irq_stack_ptr, cpu);
|
||
+ printk(KERN_ERR
|
||
+ "\033[33mirq_stack_ptr on cpu %d addr=0x%16llx, end=0x%16llx\033[0m\n",
|
||
+ cpu, (unsigned long)ptr,
|
||
+ (unsigned long)ptr + IRQ_STACK_SIZE);
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)ptr,
|
||
+ (unsigned long)ptr + IRQ_STACK_SIZE);
|
||
+ }
|
||
+
|
||
+ for_each_possible_cpu (cpu) {
|
||
+ ptr = per_cpu(koi_irq_current_ttbr1, cpu);
|
||
+ printk(KERN_ERR
|
||
+ "\033[33mirq_current_ptr on cpu %d addr=0x%16llx, end=0x%16llx\033[0m\n",
|
||
+ cpu, (unsigned long)ptr, (unsigned long)ptr + PAGE_SIZE);
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)ptr,
|
||
+ (unsigned long)ptr + PAGE_SIZE);
|
||
+ }
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+ // mapping iee_rwx_gate_entry and iee_si_base to ko's pagetable
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
|
||
+ (unsigned long)__iee_si_base_start,
|
||
+ (unsigned long)__iee_exec_entry_end);
|
||
+#endif
|
||
+
|
||
+ // alloc 16KB memory for new ko, and add it into hashtable
|
||
+ addr = (unsigned long)kmalloc(THREAD_SIZE, GFP_KERNEL);
|
||
+ if ((void *)addr == NULL) {
|
||
+ printk(KERN_ERR "alloc buffer error\n");
|
||
+ }
|
||
+ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp, addr,
|
||
+ addr + THREAD_SIZE);
|
||
+
|
||
+ new_mem_node = kmalloc(sizeof(struct koi_mem_list), GFP_KERNEL);
|
||
+ if (new_mem_node == NULL) {
|
||
+ printk(KERN_ERR "alloc new_mem_node error\n");
|
||
+ }
|
||
+ new_mem_node->addr = addr;
|
||
+ new_mem_node->size = THREAD_SIZE;
|
||
+
|
||
+ new_node->mem_list_head =
|
||
+ (struct list_head)LIST_HEAD_INIT(new_node->mem_list_head);
|
||
+ hash_init(new_node->addr_htbl);
|
||
+ spin_lock_init(&new_node->addr_htbl_spin_lock);
|
||
+ spin_lock_init(&new_node->spin_lock);
|
||
+
|
||
+ spin_lock(&new_node->spin_lock);
|
||
+ list_add_rcu(&new_mem_node->list, &new_node->mem_list_head);
|
||
+ spin_unlock(&new_node->spin_lock);
|
||
+
|
||
+ spin_lock(&koi_mem_htbl_spin_lock);
|
||
+ hash_add_rcu(koi_mem_htbl, &new_node->node,
|
||
+ (unsigned long)new_node->mod);
|
||
+ spin_unlock(&koi_mem_htbl_spin_lock);
|
||
+}
|
||
+/**
|
||
+* koi_mem_alloc
|
||
+*@mod: driver module
|
||
+*@orig_addr: the starting address of the parameter in kernel
|
||
+*@size: the size of the parameter
|
||
+*/
|
||
+unsigned long koi_mem_alloc(struct module *mod, unsigned long orig_addr,
|
||
+ unsigned long size)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ struct koi_mem_list *mem_node;
|
||
+ struct koi_addr_map *new_addr_node;
|
||
+ unsigned long addr = 0, flags;
|
||
+ struct koi_mem_list *new_mem_node;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return 0;
|
||
+ }
|
||
+ spin_lock_irqsave(&target->spin_lock, flags);
|
||
+ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
|
||
+ if (mem_node->size >= size) {
|
||
+ addr = mem_node->addr;
|
||
+ mem_node->size -= size;
|
||
+ if (mem_node->size == 0) {
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ } else {
|
||
+ new_mem_node =
|
||
+ kmalloc(sizeof(struct koi_mem_list),
|
||
+ GFP_ATOMIC);
|
||
+ new_mem_node->addr = addr + size;
|
||
+ new_mem_node->size = mem_node->size;
|
||
+ list_replace_rcu(&mem_node->list,
|
||
+ &new_mem_node->list);
|
||
+ }
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ }
|
||
+ }
|
||
+ spin_unlock_irqrestore(&target->spin_lock, flags);
|
||
+ if (!addr) {
|
||
+ addr = (unsigned long)kmalloc(THREAD_SIZE, GFP_KERNEL);
|
||
+ if ((void *)addr == NULL) {
|
||
+ return 0;
|
||
+ }
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, addr,
|
||
+ addr + THREAD_SIZE);
|
||
+ mem_node = kmalloc(sizeof(struct koi_mem_list), GFP_KERNEL);
|
||
+ if (!mem_node) {
|
||
+ printk(KERN_ERR "NULL mem_node\n");
|
||
+ }
|
||
+ if (size > THREAD_SIZE) {
|
||
+ return 0;
|
||
+ }
|
||
+ mem_node->addr = addr + size;
|
||
+ mem_node->size = THREAD_SIZE - size;
|
||
+ spin_lock_irqsave(&target->spin_lock, flags);
|
||
+ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
|
||
+ spin_unlock_irqrestore(&target->spin_lock, flags);
|
||
+ }
|
||
+
|
||
+ new_addr_node = kzalloc(sizeof(struct koi_addr_map), GFP_KERNEL);
|
||
+ new_addr_node->buffer_addr = addr;
|
||
+ new_addr_node->orig_addr = orig_addr;
|
||
+ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
|
||
+ hash_add_rcu(target->addr_htbl, &new_addr_node->node,
|
||
+ new_addr_node->buffer_addr);
|
||
+ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
|
||
+ return addr;
|
||
+}
|
||
+EXPORT_SYMBOL(koi_mem_alloc);
|
||
+// find the parameter pointer corresponding to the copy
|
||
+noinline void *koi_mem_lookup(struct module *mod, unsigned long addr)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ struct koi_addr_map *addr_map_node;
|
||
+ unsigned long orig_addr = addr;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
|
||
+ orig_addr) {
|
||
+ if (addr_map_node->buffer_addr == addr) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (addr_map_node) {
|
||
+ return (void *)(addr_map_node->orig_addr);
|
||
+ } else {
|
||
+ return NULL;
|
||
+ }
|
||
+}
|
||
+EXPORT_SYMBOL(koi_mem_lookup);
|
||
+/**
|
||
+* kio_mem_free - recycle a copy of the copied parameters and synchronize the parameters
|
||
+* @mod: driver module
|
||
+* @addr: the starting addr of parameter
|
||
+* @size: the size of the parameter
|
||
+* @is_const: const pointers or not
|
||
+* @count: contry the number of parameters
|
||
+*/
|
||
+noinline void koi_mem_free(struct module *mod, unsigned long addr,
|
||
+ unsigned long size, bool is_const, int count, ...)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ struct koi_mem_list *mem_node;
|
||
+ struct list_head *pos = NULL;
|
||
+ struct koi_addr_map *addr_map_node;
|
||
+ unsigned long orig_size = size;
|
||
+ unsigned long orig_addr = addr;
|
||
+ va_list valist;
|
||
+ int i;
|
||
+ unsigned int offset;
|
||
+ unsigned long flags;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
|
||
+ orig_addr) {
|
||
+ if (addr_map_node->buffer_addr == orig_addr) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ va_start(valist, count);
|
||
+ for (i = 0; i < count; i++) {
|
||
+ offset = va_arg(valist, int);
|
||
+ *(unsigned long *)(addr_map_node->buffer_addr + offset) =
|
||
+ *(unsigned long *)(addr_map_node->orig_addr + offset);
|
||
+ }
|
||
+ va_end(valist);
|
||
+ memcpy((void *)addr_map_node->orig_addr,
|
||
+ (void *)addr_map_node->buffer_addr, orig_size);
|
||
+
|
||
+ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
|
||
+ hlist_del_init_rcu(&addr_map_node->node);
|
||
+ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
|
||
+ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
|
||
+
|
||
+ spin_lock_irqsave(&target->spin_lock, flags);
|
||
+ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
|
||
+ if (mem_node->addr + mem_node->size == addr) {
|
||
+ pos = mem_node->list.prev;
|
||
+ addr = mem_node->addr;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size == mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size < mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
|
||
+ mem_node->addr = addr;
|
||
+ mem_node->size = size;
|
||
+ if (pos)
|
||
+ list_add_rcu(&mem_node->list, pos);
|
||
+ else
|
||
+ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
|
||
+ spin_unlock_irqrestore(&target->spin_lock, flags);
|
||
+}
|
||
+EXPORT_SYMBOL(koi_mem_free);
|
||
+/**
|
||
+* koi_mem_free_callback - used to recycle the copy of parameter.
|
||
+*@addr: the address of the parameter
|
||
+*@(*func)(void*): callback func, used to release the copy of the parameter pointer
|
||
+*/
|
||
+noinline void koi_mem_free_callback(struct module *mod, unsigned long addr,
|
||
+ unsigned long size, void (*func)(void *))
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ struct koi_mem_list *mem_node;
|
||
+ struct list_head *pos = NULL;
|
||
+ struct koi_addr_map *addr_map_node;
|
||
+ unsigned long flags;
|
||
+ unsigned long orig_size = size;
|
||
+ unsigned long orig_addr = addr;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk("mem node for module: %s not found\n", mod->name);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
|
||
+ orig_addr) {
|
||
+ if (addr_map_node->buffer_addr == orig_addr) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (addr_map_node != NULL) {
|
||
+ memcpy((void *)addr_map_node->orig_addr,
|
||
+ (void *)addr_map_node->buffer_addr, orig_size);
|
||
+ func((void *)addr_map_node->orig_addr);
|
||
+ } else {
|
||
+ printk("Cannot find addr_map_node in addr_htbl, maybe addr is in kernel space!!\n");
|
||
+ func((void *)orig_addr);
|
||
+ }
|
||
+
|
||
+ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
|
||
+ if (addr_map_node != NULL) {
|
||
+ hlist_del_init_rcu(&addr_map_node->node);
|
||
+ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
|
||
+ }
|
||
+ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
|
||
+ spin_lock_irqsave(&target->spin_lock, flags);
|
||
+ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
|
||
+ if (mem_node->addr + mem_node->size == addr) {
|
||
+ pos = mem_node->list.prev;
|
||
+ addr = mem_node->addr;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size == mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size < mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
|
||
+ mem_node->addr = addr;
|
||
+ mem_node->size = size;
|
||
+ if (pos)
|
||
+ list_add_rcu(&mem_node->list, pos);
|
||
+ else
|
||
+ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
|
||
+ spin_unlock_irqrestore(&target->spin_lock, flags);
|
||
+}
|
||
+EXPORT_SYMBOL(koi_mem_free_callback);
|
||
+
|
||
+void koi_map_mem(struct module *mod, unsigned long addr, unsigned long size)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod)
|
||
+ break;
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return;
|
||
+ }
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp, addr & PAGE_MASK,
|
||
+ (addr + size + PAGE_SIZE) & PAGE_MASK);
|
||
+}
|
||
+EXPORT_SYMBOL(koi_map_mem);
|
||
+/**
|
||
+* koi_mem_free_to_user - function 'copy_to_user' in driver space
|
||
+*/
|
||
+void koi_mem_free_to_user(struct module *mod, unsigned long addr,
|
||
+ unsigned long size)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ struct koi_mem_list *mem_node;
|
||
+ struct list_head *pos = NULL;
|
||
+ struct koi_addr_map *addr_map_node;
|
||
+ unsigned long flags;
|
||
+ unsigned long orig_size = size;
|
||
+ unsigned long orig_addr = addr;
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
|
||
+ orig_addr) {
|
||
+ if (addr_map_node->buffer_addr == orig_addr) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (copy_to_user((void *)addr_map_node->orig_addr,
|
||
+ (void *)addr_map_node->buffer_addr, orig_size)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
|
||
+ hlist_del_init_rcu(&addr_map_node->node);
|
||
+ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
|
||
+ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
|
||
+ spin_lock_irqsave(&target->spin_lock, flags);
|
||
+ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
|
||
+ if (mem_node->addr + mem_node->size == addr) {
|
||
+ pos = mem_node->list.prev;
|
||
+ addr = mem_node->addr;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size == mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ size += mem_node->size;
|
||
+ list_del_rcu(&mem_node->list);
|
||
+ call_rcu(&mem_node->rcu, koi_mem_node_free);
|
||
+ } else if (addr + size < mem_node->addr) {
|
||
+ if (!pos)
|
||
+ pos = mem_node->list.prev;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
|
||
+ mem_node->addr = addr;
|
||
+ mem_node->size = size;
|
||
+ if (pos)
|
||
+ list_add_rcu(&mem_node->list, pos);
|
||
+ else
|
||
+ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
|
||
+ spin_unlock_irqrestore(&target->spin_lock, flags);
|
||
+}
|
||
+EXPORT_SYMBOL(koi_mem_free_to_user);
|
||
+// map the driver stack to kernel
|
||
+void koi_map_kostack(struct module *mod)
|
||
+{
|
||
+ struct koi_mem_hash_node *target = NULL;
|
||
+ void *koi_stack;
|
||
+ unsigned long cur_sp;
|
||
+ asm volatile("mov %0, sp\n" : "=r"(cur_sp) :);
|
||
+ if (on_irq_stack(cur_sp, NULL)) {
|
||
+ return;
|
||
+ }
|
||
+#ifndef CONFIG_IEE
|
||
+ unsigned long res, alloc_token;
|
||
+ struct task_token *token_addr =
|
||
+ (struct task_token *)((unsigned long)current +
|
||
+ (unsigned long)koi_offset);
|
||
+ if (token_addr->koi_stack_base != NULL)
|
||
+ return;
|
||
+#else
|
||
+ koi_stack = iee_rw_gate(IEE_READ_KOI_STACK, current);
|
||
+ if (koi_stack != NULL)
|
||
+ return;
|
||
+#endif
|
||
+ koi_stack =
|
||
+ (void *)__get_free_pages(THREADINFO_GFP & ~__GFP_ACCOUNT, 3);
|
||
+ free_pages(koi_stack + 4 * PAGE_SIZE, 2);
|
||
+ printk(KERN_ERR "alloc dstack start=0x%16llx, end=0x%16llx\n",
|
||
+ koi_stack, koi_stack + THREAD_SIZE);
|
||
+#ifndef CONFIG_IEE
|
||
+ token_addr->koi_stack =
|
||
+ (struct pt_regs *)(THREAD_SIZE + (unsigned long)koi_stack) - 1;
|
||
+ token_addr->koi_stack_base = koi_stack;
|
||
+#else
|
||
+ iee_rw_gate(
|
||
+ IEE_WRITE_KOI_STACK, current,
|
||
+ (unsigned long)((struct pt_regs *)(THREAD_SIZE +
|
||
+ (unsigned long)koi_stack) -
|
||
+ 1));
|
||
+ iee_rw_gate(IEE_WRITE_KOI_STACK_BASE, current,
|
||
+ (unsigned long)koi_stack);
|
||
+#endif
|
||
+ rcu_read_lock();
|
||
+ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
|
||
+ (unsigned long)mod) {
|
||
+ if (target->mod == mod) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ rcu_read_unlock();
|
||
+ if (target == NULL) {
|
||
+ printk(KERN_ERR "mem node for module: %s not found\n",
|
||
+ mod->name);
|
||
+ return;
|
||
+ }
|
||
+ koi_copy_pagetable(target->ko_mm, target->pgdp,
|
||
+ (unsigned long)koi_stack,
|
||
+ (unsigned long)koi_stack + THREAD_SIZE);
|
||
+ printk(KERN_ERR "create ko stack: 0x%16llx\n",
|
||
+ (unsigned long)koi_stack);
|
||
+}
|
||
+EXPORT_SYMBOL(koi_map_kostack);
|
||
\ No newline at end of file
|
||
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
|
||
index cea96ee75d22..cbddc8e464e4 100644
|
||
--- a/arch/arm64/kernel/mte.c
|
||
+++ b/arch/arm64/kernel/mte.c
|
||
@@ -79,8 +79,13 @@ int memcmp_pages(struct page *page1, struct page *page2)
|
||
static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
|
||
{
|
||
/* Enable MTE Sync Mode for EL1. */
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_TCF_MASK,
|
||
+ SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF_MASK,
|
||
SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
|
||
+#endif
|
||
isb();
|
||
|
||
pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
|
||
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
|
||
index 068e5bb2661b..c98bc1a24fc7 100644
|
||
--- a/arch/arm64/kernel/process.c
|
||
+++ b/arch/arm64/kernel/process.c
|
||
@@ -467,11 +467,24 @@ static void ssbs_thread_switch(struct task_struct *next)
|
||
* This is *only* for exception entry from EL0, and is not valid until we
|
||
* __switch_to() a user task.
|
||
*/
|
||
+#ifdef CONFIG_IEE
|
||
+// Put __entry_task in a isolated page to protect it.
|
||
+__attribute__((aligned(PAGE_SIZE))) DEFINE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
|
||
+extern void iee_write_entry_task(struct task_struct *tsk);
|
||
+#else
|
||
DEFINE_PER_CPU(struct task_struct *, __entry_task);
|
||
+#endif
|
||
|
||
static void entry_task_switch(struct task_struct *next)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(next == &init_task)
|
||
+ iee_write_entry_task((struct task_struct *)__va(__pa_symbol(next)));
|
||
+ else
|
||
+ iee_write_entry_task(next);
|
||
+ #else
|
||
__this_cpu_write(__entry_task, next);
|
||
+ #endif
|
||
}
|
||
|
||
/*
|
||
@@ -506,11 +519,15 @@ static void erratum_1418040_new_exec(void)
|
||
*/
|
||
void update_sctlr_el1(u64 sctlr)
|
||
{
|
||
- /*
|
||
+ /*
|
||
* EnIA must not be cleared while in the kernel as this is necessary for
|
||
* in-kernel PAC. It will be cleared on kernel exit if needed.
|
||
*/
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_USER_MASK & ~SCTLR_ELx_ENIA, sctlr);
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_USER_MASK & ~SCTLR_ELx_ENIA, sctlr);
|
||
+ #endif
|
||
|
||
/* ISB required for the kernel uaccess routines when setting TCF0. */
|
||
isb();
|
||
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
|
||
index 58a97861bfc5..c7839247327d 100644
|
||
--- a/arch/arm64/kernel/proton-pack.c
|
||
+++ b/arch/arm64/kernel/proton-pack.c
|
||
@@ -551,7 +551,11 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
|
||
return state;
|
||
|
||
if (spectre_v4_mitigations_off()) {
|
||
+#ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_ELx_DSSBS);
|
||
+#else
|
||
sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
|
||
+#endif
|
||
set_pstate_ssbs(1);
|
||
return SPECTRE_VULNERABLE;
|
||
}
|
||
@@ -975,7 +979,11 @@ static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
|
||
if (arm64_kernel_unmapped_at_el0())
|
||
return;
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ iee_rwx_gate_entry(IEE_WRITE_vbar_el1, v);
|
||
+#else
|
||
write_sysreg(v, vbar_el1);
|
||
+#endif
|
||
isb();
|
||
}
|
||
|
||
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
|
||
index 95cb22c083c8..df73a583a733 100644
|
||
--- a/arch/arm64/kernel/setup.c
|
||
+++ b/arch/arm64/kernel/setup.c
|
||
@@ -33,6 +33,11 @@
|
||
#include <linux/scs.h>
|
||
#include <linux/mm.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#include <asm/iee-si.h>
|
||
+#endif
|
||
+
|
||
#include <asm/acpi.h>
|
||
#include <asm/fixmap.h>
|
||
#include <asm/cpu.h>
|
||
@@ -335,10 +340,30 @@ u64 cpu_logical_map(unsigned int cpu)
|
||
return __cpu_logical_map[cpu];
|
||
}
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+/* used for secure modification of vbar*/
|
||
+extern char __bp_harden_el1_vectors[];
|
||
+/* prepare iee rwx gate for senario of ttbr1=init_pg_dir */
|
||
+static void __init iee_si_init_early(void)
|
||
+{
|
||
+ /* prepare data used for iee rwx gate. */
|
||
+ iee_base_idmap_pg_dir = phys_to_ttbr(__pa_symbol(idmap_pg_dir));
|
||
+ iee_base_reserved_pg_dir = phys_to_ttbr(__pa_symbol(reserved_pg_dir))
|
||
+ | FIELD_PREP(TTBR_ASID_MASK, 1);
|
||
+ iee_base__bp_harden_el1_vectors = (unsigned long)__bp_harden_el1_vectors;
|
||
+ iee_si_tcr = 0;
|
||
+}
|
||
+#endif
|
||
+
|
||
void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
||
{
|
||
setup_initial_init_mm(_stext, _etext, _edata, _end);
|
||
|
||
+ #ifdef CONFIG_IEE
|
||
+ init_new_context(&init_task, &init_mm);
|
||
+ atomic64_set(&init_mm.context.id, (1UL << get_cpu_asid_bits()) | INIT_ASID);
|
||
+ #endif
|
||
+
|
||
*cmdline_p = boot_command_line;
|
||
|
||
kaslr_init();
|
||
@@ -371,6 +396,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
||
*/
|
||
local_daif_restore(DAIF_PROCCTX_NOIRQ);
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ /*
|
||
+ * Map iee si codes to init_pg_dir to run the following
|
||
+ * cpu_uninstall_idmap() which writes ttbr0.
|
||
+ */
|
||
+ iee_si_init_early();
|
||
+#endif
|
||
+
|
||
/*
|
||
* TTBR0 is only used for the identity mapping at this stage. Make it
|
||
* point to zero page to avoid speculatively fetching new entries.
|
||
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
|
||
index b7b7afb4a8c7..168a9390d6e9 100644
|
||
--- a/arch/arm64/kernel/traps.c
|
||
+++ b/arch/arm64/kernel/traps.c
|
||
@@ -902,6 +902,32 @@ const char *esr_get_class_string(unsigned long esr)
|
||
return esr_class_str[ESR_ELx_EC(esr)];
|
||
}
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+extern void arm64_enter_nmi(struct pt_regs *regs);
|
||
+static const char *handler[]= {
|
||
+ "SP_EL0",
|
||
+ "ELR_EL1",
|
||
+ "TCR_EL1",
|
||
+ "TTBR0 ASID"
|
||
+ "IEE_SI"
|
||
+};
|
||
+
|
||
+asmlinkage void notrace iee_bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
|
||
+{
|
||
+ arm64_enter_nmi(regs);
|
||
+
|
||
+ console_verbose();
|
||
+
|
||
+ pr_crit("IEE : Bad mode in %s check detected on CPU%d, code 0x%08x -- %s\n",
|
||
+ handler[reason], smp_processor_id(), esr,
|
||
+ esr_get_class_string(esr));
|
||
+
|
||
+ __show_regs(regs);
|
||
+ local_daif_mask();
|
||
+ panic("bad mode");
|
||
+}
|
||
+#endif
|
||
+
|
||
/*
|
||
* bad_el0_sync handles unexpected, but potentially recoverable synchronous
|
||
* exceptions taken from EL0.
|
||
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
|
||
index 3cd7e76cc562..287eaba7a15b 100644
|
||
--- a/arch/arm64/kernel/vmlinux.lds.S
|
||
+++ b/arch/arm64/kernel/vmlinux.lds.S
|
||
@@ -134,6 +134,52 @@ jiffies = jiffies_64;
|
||
#define UNWIND_DATA_SECTIONS
|
||
#endif
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#define IEE_TEXT \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __iee_code_start = .; \
|
||
+ *(.iee.text.header) \
|
||
+ *(.iee.text) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __iee_code_end = .;
|
||
+#else
|
||
+#define IEE_TEXT
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+#define IEE_SI_TEXT \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __iee_si_data_start = .; \
|
||
+ *(.iee.si_data) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __iee_exec_entry_start = .; \
|
||
+ __iee_si_no_irq = . + (16); \
|
||
+ *(.iee.exec_entry) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __iee_si_start = .; \
|
||
+ *(.iee.si_text) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ . += PAGE_SIZE - (24); \
|
||
+ __iee_si_end = . + (24); \
|
||
+ __iee_exec_exit = .; \
|
||
+ *(.iee.exec_exit) \
|
||
+ . = ALIGN(PAGE_SIZE);
|
||
+
|
||
+#else
|
||
+#define IEE_SI_TEXT
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+#define KOI_TEXT \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __koi_code_start = .; \
|
||
+ *(.koi.text) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __koi_code_end = .;
|
||
+#else
|
||
+#define KOI_TEXT
|
||
+#endif
|
||
+
|
||
/*
|
||
* The size of the PE/COFF section that covers the kernel image, which
|
||
* runs from _stext to _edata, must be a round multiple of the PE/COFF
|
||
@@ -176,10 +222,13 @@ SECTIONS
|
||
SOFTIRQENTRY_TEXT
|
||
ENTRY_TEXT
|
||
TEXT_TEXT
|
||
+ IEE_TEXT
|
||
SCHED_TEXT
|
||
LOCK_TEXT
|
||
KPROBES_TEXT
|
||
HYPERVISOR_TEXT
|
||
+ IEE_SI_TEXT
|
||
+ KOI_TEXT
|
||
*(.gnu.warning)
|
||
}
|
||
|
||
@@ -318,6 +367,18 @@ SECTIONS
|
||
. += INIT_DIR_SIZE;
|
||
init_pg_end = .;
|
||
|
||
+ #ifdef CONFIG_IEE
|
||
+ . = ALIGN(PAGE_SIZE*8);
|
||
+ init_iee_stack_begin = .;
|
||
+ . += PAGE_SIZE*4;
|
||
+ init_iee_stack_end = .;
|
||
+
|
||
+ . = ALIGN(PAGE_SIZE);
|
||
+ init_iee_si_stack_begin = .;
|
||
+ . += PAGE_SIZE*4;
|
||
+ init_iee_si_stack_end = .;
|
||
+ #endif
|
||
+
|
||
. = ALIGN(SEGMENT_ALIGN);
|
||
__pecoff_data_size = ABSOLUTE(. - __initdata_begin);
|
||
_end = .;
|
||
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
|
||
index 188197590fc9..97e1f86046cf 100644
|
||
--- a/arch/arm64/mm/context.c
|
||
+++ b/arch/arm64/mm/context.c
|
||
@@ -17,6 +17,10 @@
|
||
#include <asm/smp.h>
|
||
#include <asm/tlbflush.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <asm/iee-si.h>
|
||
+#endif
|
||
+
|
||
static u32 asid_bits;
|
||
static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
|
||
|
||
@@ -39,7 +43,11 @@ static unsigned long *pinned_asid_map;
|
||
#define asid2ctxid(asid, genid) ((asid) | (genid))
|
||
|
||
/* Get the ASIDBits supported by the current CPU */
|
||
+#ifdef CONFIG_IEE
|
||
+u32 get_cpu_asid_bits(void)
|
||
+#else
|
||
static u32 get_cpu_asid_bits(void)
|
||
+#endif
|
||
{
|
||
u32 asid;
|
||
int fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR0_EL1),
|
||
@@ -212,6 +220,38 @@ static u64 new_context(struct mm_struct *mm)
|
||
return asid2ctxid(asid, generation);
|
||
}
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+/*
|
||
+ * This function is used to check and allocate ASID for ko's pgd
|
||
+ * The mm MUST point to the isolated kos' mm_struct, other behaviours are undefined.
|
||
+ */
|
||
+void koi_check_and_switch_context(struct mm_struct *mm) {
|
||
+ u64 asid = atomic64_read(&mm->context.id);
|
||
+ u64 old_active_asid;
|
||
+ unsigned long flags;
|
||
+ unsigned int cpu;
|
||
+
|
||
+ old_active_asid = atomic64_read(this_cpu_ptr(&active_asids));
|
||
+ if (old_active_asid && asid_gen_match(asid) && atomic64_cmpxchg_relaxed(this_cpu_ptr(&active_asids), old_active_asid, asid)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ raw_spin_lock_irqsave(&cpu_asid_lock, flags);
|
||
+ asid = atomic64_read(&mm->context.id);
|
||
+ if (!asid_gen_match(asid)) {
|
||
+ asid = new_context(mm);
|
||
+ atomic64_set(&mm->context.id, asid);
|
||
+ }
|
||
+
|
||
+ cpu = smp_processor_id();
|
||
+ if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
|
||
+ local_flush_tlb_all();
|
||
+
|
||
+ atomic64_set(this_cpu_ptr(&active_asids), asid);
|
||
+ raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
|
||
+}
|
||
+#endif
|
||
+
|
||
void check_and_switch_context(struct mm_struct *mm)
|
||
{
|
||
unsigned long flags;
|
||
@@ -348,7 +388,9 @@ asmlinkage void post_ttbr_update_workaround(void)
|
||
|
||
void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
|
||
{
|
||
+ #ifndef CONFIG_IEE
|
||
unsigned long ttbr1 = read_sysreg(ttbr1_el1);
|
||
+ #endif
|
||
unsigned long asid = ASID(mm);
|
||
unsigned long ttbr0 = phys_to_ttbr(pgd_phys);
|
||
|
||
@@ -360,14 +402,28 @@ void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
|
||
if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN))
|
||
ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
|
||
- /* Set ASID in TTBR1 since TCR.A1 is set */
|
||
+ #ifdef CONFIG_IEE
|
||
+ ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid+1);
|
||
+ iee_rwx_gate_entry(IEE_CONTEXT_SWITCH, ttbr0);
|
||
+ // TODO : if defined CONFIG_IEE and defined CONFIG_KOI
|
||
+ #else
|
||
+ /* Set ASID in TTBR0 since TCR.A1 is set 0*/
|
||
+
|
||
+ #ifdef CONFIG_KOI
|
||
+ ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid+1);
|
||
+ ttbr1 &= ~TTBR_ASID_MASK;
|
||
+ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
+ #else
|
||
ttbr1 &= ~TTBR_ASID_MASK;
|
||
ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
|
||
-
|
||
+
|
||
+ #endif
|
||
cpu_set_reserved_ttbr0_nosync();
|
||
write_sysreg(ttbr1, ttbr1_el1);
|
||
write_sysreg(ttbr0, ttbr0_el1);
|
||
isb();
|
||
+ #endif
|
||
+
|
||
post_ttbr_update_workaround();
|
||
}
|
||
|
||
@@ -375,11 +431,21 @@ static int asids_update_limit(void)
|
||
{
|
||
unsigned long num_available_asids = NUM_USER_ASIDS;
|
||
|
||
- if (arm64_kernel_unmapped_at_el0()) {
|
||
- num_available_asids /= 2;
|
||
- if (pinned_asid_map)
|
||
- set_kpti_asid_bits(pinned_asid_map);
|
||
- }
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ num_available_asids /= 2;
|
||
+ if (pinned_asid_map) {
|
||
+ unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
|
||
+ memset(pinned_asid_map, 0xaa, len);
|
||
+ __set_bit(INIT_ASID, pinned_asid_map);
|
||
+ }
|
||
+ #else
|
||
+ if (arm64_kernel_unmapped_at_el0()) {
|
||
+ num_available_asids /= 2;
|
||
+ if (pinned_asid_map)
|
||
+ set_kpti_asid_bits(pinned_asid_map);
|
||
+ }
|
||
+ #endif
|
||
+
|
||
/*
|
||
* Expect allocation after rollover to fail if we don't have at least
|
||
* one more ASID than CPUs. ASID #0 is reserved for init_mm.
|
||
@@ -400,6 +466,10 @@ arch_initcall(asids_update_limit);
|
||
|
||
static int asids_init(void)
|
||
{
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ unsigned int len;
|
||
+ #endif
|
||
+
|
||
asid_bits = get_cpu_asid_bits();
|
||
atomic64_set(&asid_generation, ASID_FIRST_VERSION);
|
||
asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
|
||
@@ -410,6 +480,11 @@ static int asids_init(void)
|
||
pinned_asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
|
||
nr_pinned_asids = 0;
|
||
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
|
||
+ memset(asid_map, 0xaa, len);
|
||
+ __set_bit(INIT_ASID, asid_map);
|
||
+ #else
|
||
/*
|
||
* We cannot call set_reserved_asid_bits() here because CPU
|
||
* caps are not finalized yet, so it is safer to assume KPTI
|
||
@@ -417,6 +492,8 @@ static int asids_init(void)
|
||
*/
|
||
if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
|
||
set_kpti_asid_bits(asid_map);
|
||
+ #endif
|
||
+
|
||
return 0;
|
||
}
|
||
early_initcall(asids_init);
|
||
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
|
||
index 4ea07caba71c..de1d57c2b30f 100644
|
||
--- a/arch/arm64/mm/fault.c
|
||
+++ b/arch/arm64/mm/fault.c
|
||
@@ -261,7 +261,11 @@ int __ptep_set_access_flags(struct vm_area_struct *vma,
|
||
pteval ^= PTE_RDONLY;
|
||
pteval |= pte_val(entry);
|
||
pteval ^= PTE_RDONLY;
|
||
+ #ifdef CONFIG_PTP
|
||
+ pteval = iee_set_cmpxchg_relaxed(ptep, old_pteval, pteval);
|
||
+ #else
|
||
pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval);
|
||
+ #endif
|
||
} while (pteval != old_pteval);
|
||
|
||
/* Invalidate a stale read-only entry */
|
||
@@ -376,8 +380,13 @@ static void do_tag_recovery(unsigned long addr, unsigned long esr,
|
||
* It will be done lazily on the other CPUs when they will hit a
|
||
* tag fault.
|
||
*/
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_TCF_MASK,
|
||
+ SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF, NONE));
|
||
+ #else
|
||
sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF_MASK,
|
||
SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF, NONE));
|
||
+ #endif
|
||
isb();
|
||
}
|
||
|
||
diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
|
||
index bfc02568805a..580ecb596d2d 100644
|
||
--- a/arch/arm64/mm/fixmap.c
|
||
+++ b/arch/arm64/mm/fixmap.c
|
||
@@ -32,6 +32,22 @@ static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __page_aligned_bss;
|
||
static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
|
||
static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+void *bm_pte_addr = (void *)bm_pte;
|
||
+void *bm_pmd_addr = (void *)bm_pmd;
|
||
+void *bm_pud_addr = (void *)bm_pud;
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+extern void __iee_p4d_populate_pre_init(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot);
|
||
+extern void __iee_pud_populate_pre_init(pud_t *pudp, phys_addr_t pmdp, pudval_t prot);
|
||
+extern void __iee_pmd_populate_pre_init(pmd_t *pmdp, phys_addr_t ptep,
|
||
+ pmdval_t prot);
|
||
+
|
||
+extern void iee_set_p4d_pre_init(p4d_t *p4dp, p4d_t p4d);
|
||
+#define set_pgd_init(pgdptr, pgdval) iee_set_p4d_pre_init((p4d_t *)(pgdptr), (p4d_t) { pgdval })
|
||
+#endif
|
||
+
|
||
static inline pte_t *fixmap_pte(unsigned long addr)
|
||
{
|
||
return &bm_pte[BM_PTE_TABLE_IDX(addr)][pte_index(addr)];
|
||
@@ -44,7 +60,11 @@ static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr)
|
||
|
||
if (pmd_none(pmd)) {
|
||
ptep = bm_pte[BM_PTE_TABLE_IDX(addr)];
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_pmd_populate_pre_init(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE);
|
||
+ #else
|
||
__pmd_populate(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE);
|
||
+ #endif
|
||
}
|
||
}
|
||
|
||
@@ -55,8 +75,13 @@ static void __init early_fixmap_init_pmd(pud_t *pudp, unsigned long addr,
|
||
pud_t pud = READ_ONCE(*pudp);
|
||
pmd_t *pmdp;
|
||
|
||
- if (pud_none(pud))
|
||
+ if (pud_none(pud)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_pud_populate_pre_init(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
|
||
+ #else
|
||
__pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
|
||
+ #endif
|
||
+ }
|
||
|
||
pmdp = pmd_offset_kimg(pudp, addr);
|
||
do {
|
||
@@ -82,8 +107,13 @@ static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr,
|
||
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
|
||
}
|
||
|
||
- if (p4d_none(p4d))
|
||
+ if (p4d_none(p4d)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_p4d_populate_pre_init(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
|
||
+ #else
|
||
__p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
|
||
+ #endif
|
||
+ }
|
||
|
||
pudp = pud_offset_kimg(p4dp, addr);
|
||
early_fixmap_init_pmd(pudp, addr, end);
|
||
@@ -106,6 +136,27 @@ void __init early_fixmap_init(void)
|
||
early_fixmap_init_pud(p4dp, addr, end);
|
||
}
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+extern void iee_set_pte_pre_init(pte_t *ptep, pte_t pte);
|
||
+void __iee_set_fixmap_pre_init(enum fixed_addresses idx,
|
||
+ phys_addr_t phys, pgprot_t flags)
|
||
+{
|
||
+ unsigned long addr = __fix_to_virt(idx);
|
||
+ pte_t *ptep;
|
||
+
|
||
+ BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
|
||
+
|
||
+ ptep = fixmap_pte(addr);
|
||
+
|
||
+ if (pgprot_val(flags)) {
|
||
+ iee_set_pte_pre_init(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
|
||
+ } else {
|
||
+ iee_set_pte_pre_init(ptep, __pte(0));
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ }
|
||
+}
|
||
+#endif
|
||
+
|
||
/*
|
||
* Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
|
||
* ever need to use IPIs for TLB broadcasting, then we're in trouble here.
|
||
@@ -121,9 +172,17 @@ void __set_fixmap(enum fixed_addresses idx,
|
||
ptep = fixmap_pte(addr);
|
||
|
||
if (pgprot_val(flags)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_bm_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
|
||
+ #else
|
||
__set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
|
||
+ #endif
|
||
} else {
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_bm_pte(ptep, __pte(0));
|
||
+ #else
|
||
__pte_clear(&init_mm, addr, ptep);
|
||
+ #endif
|
||
flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
}
|
||
}
|
||
@@ -179,8 +238,13 @@ void __init fixmap_copy(pgd_t *pgdir)
|
||
* live in the carveout for the swapper_pg_dir. We can simply
|
||
* re-use the existing dir for the fixmap.
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pgd_init(pgd_offset_pgd(pgdir, FIXADDR_TOT_START),
|
||
+ READ_ONCE(*pgd_offset_k(FIXADDR_TOT_START)));
|
||
+ #else
|
||
set_pgd(pgd_offset_pgd(pgdir, FIXADDR_TOT_START),
|
||
READ_ONCE(*pgd_offset_k(FIXADDR_TOT_START)));
|
||
+ #endif
|
||
} else if (CONFIG_PGTABLE_LEVELS > 3) {
|
||
pgd_t *bm_pgdp;
|
||
p4d_t *bm_p4dp;
|
||
@@ -194,9 +258,15 @@ void __init fixmap_copy(pgd_t *pgdir)
|
||
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
|
||
bm_pgdp = pgd_offset_pgd(pgdir, FIXADDR_TOT_START);
|
||
bm_p4dp = p4d_offset(bm_pgdp, FIXADDR_TOT_START);
|
||
+ #ifdef CONFIG_PTP
|
||
+ bm_pudp = pud_set_fixmap_offset_init(bm_p4dp, FIXADDR_TOT_START);
|
||
+ __iee_pud_populate_pre_init(bm_pudp, __pa(lm_alias(bm_pmd)), PMD_TYPE_TABLE);
|
||
+ pud_clear_fixmap_init();
|
||
+ #else
|
||
bm_pudp = pud_set_fixmap_offset(bm_p4dp, FIXADDR_TOT_START);
|
||
pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd));
|
||
pud_clear_fixmap();
|
||
+ #endif
|
||
} else {
|
||
BUG();
|
||
}
|
||
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
|
||
index 8c8d7653ba84..4190f5c10d68 100644
|
||
--- a/arch/arm64/mm/init.c
|
||
+++ b/arch/arm64/mm/init.c
|
||
@@ -55,8 +55,19 @@
|
||
* that cannot be mistaken for a real physical address.
|
||
*/
|
||
s64 memstart_addr __ro_after_init = -1;
|
||
+#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+s64 memstart_addr_init __ro_after_init = -1;
|
||
+#endif
|
||
+#ifdef CONFIG_KOI
|
||
+s64 koi_offset __ro_after_init = -1;
|
||
+EXPORT_SYMBOL(koi_offset);
|
||
+#endif
|
||
+#ifdef CONFIG_IEE
|
||
+s64 iee_offset __ro_after_init = -1;
|
||
+#endif
|
||
EXPORT_SYMBOL(memstart_addr);
|
||
|
||
+
|
||
/*
|
||
* If the corresponding config options are enabled, we create both ZONE_DMA
|
||
* and ZONE_DMA32. By default ZONE_DMA covers the 32-bit addressable memory
|
||
@@ -421,7 +432,11 @@ early_param("memmap", parse_memmap_opt);
|
||
|
||
void __init arm64_memblock_init(void)
|
||
{
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ s64 linear_region_size = BIT(vabits_actual - 2);
|
||
+ #else
|
||
s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);
|
||
+ #endif
|
||
|
||
/*
|
||
* Corner case: 52-bit VA capable systems running KVM in nVHE mode may
|
||
@@ -438,13 +453,24 @@ void __init arm64_memblock_init(void)
|
||
}
|
||
|
||
/* Remove memory above our supported physical address size */
|
||
+ #ifdef CONFIG_IEE
|
||
+ // If config iee, phys size can not be above 0x400000000000
|
||
+ if(__pa_symbol(_end) > BIT_ULL(vabits_actual - 2))
|
||
+ panic("Image on too high phys mem.\n");
|
||
+ else
|
||
+ memblock_remove(BIT_ULL(vabits_actual - 2), ULLONG_MAX);
|
||
+ #else
|
||
memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX);
|
||
+ #endif
|
||
|
||
/*
|
||
* Select a suitable value for the base of physical memory.
|
||
*/
|
||
memstart_addr = round_down(memblock_start_of_DRAM(),
|
||
ARM64_MEMSTART_ALIGN);
|
||
+ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+ memstart_addr_init = memstart_addr;
|
||
+ #endif
|
||
|
||
if ((memblock_end_of_DRAM() - memstart_addr) > linear_region_size)
|
||
pr_warn("Memory doesn't fit in the linear mapping, VA_BITS too small\n");
|
||
@@ -531,6 +557,14 @@ void __init arm64_memblock_init(void)
|
||
((range * memstart_offset_seed) >> 16);
|
||
}
|
||
}
|
||
+
|
||
+ #ifdef CONFIG_KOI
|
||
+ koi_offset = memstart_addr - memstart_addr_init + KOI_OFFSET;
|
||
+ #endif
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_offset = memstart_addr - memstart_addr_init + ((unsigned long)BIT(vabits_actual - 2));
|
||
+ #endif
|
||
+ //printk(KERN_ERR "koi_offset: 0x%16llx\n", koi_offset);
|
||
|
||
/*
|
||
* Register the kernel text, kernel data, initrd, and initial
|
||
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
|
||
index 4142a75a414e..094f3798441d 100644
|
||
--- a/arch/arm64/mm/mmu.c
|
||
+++ b/arch/arm64/mm/mmu.c
|
||
@@ -6,6 +6,7 @@
|
||
* Copyright (C) 2012 ARM Ltd.
|
||
*/
|
||
|
||
+#include "asm/pgtable.h"
|
||
#include <linux/cache.h>
|
||
#include <linux/export.h>
|
||
#include <linux/kernel.h>
|
||
@@ -40,6 +41,11 @@
|
||
#include <asm/tlbflush.h>
|
||
#include <asm/pgalloc.h>
|
||
#include <asm/kfence.h>
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#include <asm/iee.h>
|
||
+#include <asm/iee-si.h>
|
||
+#endif
|
||
|
||
#define NO_BLOCK_MAPPINGS BIT(0)
|
||
#define NO_CONT_MAPPINGS BIT(1)
|
||
@@ -76,8 +82,282 @@ EXPORT_SYMBOL(empty_zero_page);
|
||
static DEFINE_SPINLOCK(swapper_pgdir_lock);
|
||
static DEFINE_MUTEX(fixmap_lock);
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+extern struct cred init_cred;
|
||
+
|
||
+extern unsigned long init_iee_stack_begin[];
|
||
+extern unsigned long init_iee_stack_end[];
|
||
+extern unsigned long __iee_si_data_start[];
|
||
+extern unsigned long __iee_exec_entry_start[];
|
||
+extern unsigned long __iee_si_start[];
|
||
+extern unsigned long __iee_si_end[];
|
||
+
|
||
+extern void *bm_pte_addr;
|
||
+extern void *bm_pmd_addr;
|
||
+extern void *bm_pud_addr;
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+
|
||
+/* Funcs to set pgtable before iee initialized. */
|
||
+static void iee_set_swapper_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
|
||
+{
|
||
+ pgd_t *fixmap_pgdp;
|
||
+
|
||
+ spin_lock(&swapper_pgdir_lock);
|
||
+ fixmap_pgdp = pgd_set_fixmap_init(__pa_symbol(pgdp));
|
||
+ WRITE_ONCE(*fixmap_pgdp, pgd);
|
||
+ /*
|
||
+ * We need dsb(ishst) here to ensure the page-table-walker sees
|
||
+ * our new entry before set_p?d() returns. The fixmap's
|
||
+ * flush_tlb_kernel_range() via clear_fixmap() does this for us.
|
||
+ */
|
||
+ pgd_clear_fixmap_init();
|
||
+ spin_unlock(&swapper_pgdir_lock);
|
||
+}
|
||
+
|
||
+void iee_set_p4d_pre_init(p4d_t *p4dp, p4d_t p4d)
|
||
+{
|
||
+ if (in_swapper_pgdir(p4dp)) {
|
||
+ iee_set_swapper_pgd_pre_init((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ WRITE_ONCE(*p4dp, p4d);
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+}
|
||
+
|
||
+static inline void iee_set_pud_pre_init(pud_t *pudp, pud_t pud)
|
||
+{
|
||
+#ifdef __PAGETABLE_PUD_FOLDED
|
||
+ if (in_swapper_pgdir(pudp)) {
|
||
+ iee_set_swapper_pgd_pre_init((pgd_t *)pudp, __pgd(pud_val(pud)));
|
||
+ return;
|
||
+ }
|
||
+#endif /* __PAGETABLE_PUD_FOLDED */
|
||
+#ifdef CONFIG_KOI
|
||
+ pudval_t val = pud_val(pud);
|
||
+ if (pud_valid(pud) && !(val & PUD_TABLE_BIT)) {
|
||
+ // There is no PUD_SEC_NG, so we use PMD_SECT_NG instead.
|
||
+ pud = __pud(val | PMD_SECT_NG);
|
||
+ }
|
||
+#endif
|
||
+ WRITE_ONCE(*pudp, pud);
|
||
+
|
||
+ if (pud_valid(pud)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
+
|
||
+static inline void iee_set_pmd_pre_init(pmd_t *pmdp, pmd_t pmd)
|
||
+{
|
||
+#ifdef __PAGETABLE_PMD_FOLDED
|
||
+ if (in_swapper_pgdir(pmdp)) {
|
||
+ iee_set_swapper_pgd_pre_init((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
|
||
+ return;
|
||
+ }
|
||
+#endif /* __PAGETABLE_PMD_FOLDED */
|
||
+#ifdef CONFIG_KOI
|
||
+ pmdval_t val = pmd_val(pmd);
|
||
+ if (pmd_valid(pmd) && !(val & PMD_TABLE_BIT)) {
|
||
+ pmd = __pmd(val | PMD_SECT_NG);
|
||
+ }
|
||
+#endif
|
||
+ WRITE_ONCE(*pmdp, pmd);
|
||
+
|
||
+ if (pmd_valid(pmd)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+void __iee_p4d_populate_pre_init(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
|
||
+{
|
||
+ iee_set_p4d_pre_init(p4dp, __p4d(__phys_to_p4d_val(pudp) | prot));
|
||
+}
|
||
+
|
||
+void __iee_pud_populate_pre_init(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
|
||
+{
|
||
+ iee_set_pud_pre_init(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
|
||
+}
|
||
+
|
||
+void __iee_pmd_populate_pre_init(pmd_t *pmdp, phys_addr_t ptep,
|
||
+ pmdval_t prot)
|
||
+{
|
||
+ iee_set_pmd_pre_init(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot));
|
||
+}
|
||
+
|
||
+/* Funcs to set fixmap before iee initialized. */
|
||
+bool pgattr_change_is_safe(u64 old, u64 new);
|
||
+static int iee_pud_set_huge_fixmap(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
|
||
+{
|
||
+ pud_t new_pud = pfn_pud(__phys_to_pfn(phys), mk_pud_sect_prot(prot));
|
||
+
|
||
+ /* Only allow permission changes for now */
|
||
+ if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)),
|
||
+ pud_val(new_pud)))
|
||
+ return 0;
|
||
+
|
||
+ VM_BUG_ON(phys & ~PUD_MASK);
|
||
+ iee_set_fixmap_pud_pre_init(pudp, new_pud);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static int iee_pmd_set_huge_fixmap(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot)
|
||
+{
|
||
+ pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), mk_pmd_sect_prot(prot));
|
||
+
|
||
+ /* Only allow permission changes for now */
|
||
+ if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)),
|
||
+ pmd_val(new_pmd)))
|
||
+ return 0;
|
||
+
|
||
+ VM_BUG_ON(phys & ~PMD_MASK);
|
||
+ iee_set_fixmap_pmd_pre_init(pmdp, new_pmd);
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static inline void __iee_pmd_populate_fixmap(pmd_t *pmdp, phys_addr_t ptep,
|
||
+ pmdval_t prot)
|
||
+{
|
||
+ iee_set_fixmap_pmd_pre_init(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot));
|
||
+}
|
||
+
|
||
+static inline void __iee_pud_populate_fixmap(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
|
||
+{
|
||
+ iee_set_fixmap_pud_pre_init(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
|
||
+}
|
||
+#endif /* END CONFIG_PTP*/
|
||
+
|
||
+void iee_set_pte_pre_init(pte_t *ptep, pte_t pte)
|
||
+{
|
||
+#ifdef CONFIG_KOI
|
||
+ if (!pte_none(pte)) {
|
||
+ pte = __pte(pte_val(pte) | PTE_NG);
|
||
+ }
|
||
+#endif
|
||
+ WRITE_ONCE(*ptep, pte);
|
||
+
|
||
+ /*
|
||
+ * Only if the new pte is valid and kernel, otherwise TLB maintenance
|
||
+ * or update_mmu_cache() have the necessary barriers.
|
||
+ */
|
||
+ if (pte_valid_not_user(pte)) {
|
||
+ dsb(ishst);
|
||
+ isb();
|
||
+ }
|
||
+}
|
||
+
|
||
+static void __init iee_set_token_page_valid_pre_init(void *token, void *new)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(((pte_val(pte) | 0x1) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(new)));
|
||
+ iee_set_pte_pre_init(ptep, pte);
|
||
+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
|
||
+ isb();
|
||
+}
|
||
+#endif /* END CONFIG_IEE*/
|
||
+
|
||
+#if defined(CONFIG_KOI) && !defined(CONFIG_IEE)
|
||
+int koi_add_page_mapping(unsigned long dst, unsigned long src)
|
||
+{
|
||
+ pgd_t *src_pgdp, *dst_pgdp;
|
||
+ p4d_t *src_p4dp, *dst_p4dp;
|
||
+ pud_t *src_pudp, *dst_pudp;
|
||
+ pmd_t *src_pmdp, *dst_pmdp;
|
||
+ pte_t *src_ptep, *dst_ptep;
|
||
+
|
||
+ src_pgdp = pgd_offset_pgd(swapper_pg_dir, src);
|
||
+ dst_pgdp = pgd_offset_pgd(swapper_pg_dir, dst);
|
||
+
|
||
+ src_p4dp = p4d_offset(src_pgdp, src);
|
||
+ dst_p4dp = p4d_alloc(&init_mm, dst_pgdp, dst);
|
||
+ if (!dst_p4dp) {
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ src_pudp = pud_offset(src_p4dp, src);
|
||
+ dst_pudp = pud_alloc(&init_mm, dst_p4dp, dst);
|
||
+ if (!dst_pudp) {
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ if (pud_val(*src_pudp) & PMD_TABLE_BIT) {
|
||
+ src_pmdp = pmd_offset(src_pudp, src);
|
||
+ dst_pmdp = pmd_alloc(&init_mm, dst_pudp, dst);
|
||
+ if (!dst_pmdp) {
|
||
+ return -ENOMEM;
|
||
+ }
|
||
+ if (pmd_val(*src_pmdp) & PMD_TABLE_BIT) {
|
||
+ src_ptep = pte_offset_kernel(src_pmdp, src);
|
||
+ dst_ptep = pte_alloc_map(&init_mm, dst_pmdp, dst);
|
||
+ set_pte(dst_ptep, *src_ptep);
|
||
+ } else {
|
||
+ set_pte((pte_t *)dst_pmdp, pmd_pte(*src_pmdp));
|
||
+ }
|
||
+ } else {
|
||
+ set_pte((pte_t *)dst_pudp, pud_pte(*src_pudp));
|
||
+ }
|
||
+
|
||
+
|
||
+ flush_tlb_kernel_range(dst, dst+PAGE_SIZE);
|
||
+ isb();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+void koi_remove_page_mapping(unsigned long addr) {
|
||
+ pgd_t *src_pgdp;
|
||
+ p4d_t *src_p4dp;
|
||
+ pud_t *src_pudp;
|
||
+ pmd_t *src_pmdp;
|
||
+ pte_t *src_ptep;
|
||
+
|
||
+ src_pgdp = pgd_offset_pgd(swapper_pg_dir, addr);
|
||
+ if (pgd_none(*src_pgdp) || pgd_bad(*src_pgdp))
|
||
+ return;
|
||
+ src_p4dp = p4d_offset(src_pgdp, addr);
|
||
+ if (p4d_none(*src_p4dp) || p4d_bad(*src_p4dp))
|
||
+ return;
|
||
+ src_pudp = pud_offset(src_p4dp, addr);
|
||
+ if (pud_none(*src_pudp))
|
||
+ return;
|
||
+ if (pud_val(*src_pudp) & PMD_TABLE_BIT) {
|
||
+ src_pmdp = pmd_offset(src_pudp, addr);
|
||
+ if (pmd_none(*src_pmdp))
|
||
+ return;
|
||
+ if (pmd_val(*src_pmdp) & PMD_TABLE_BIT) {
|
||
+ src_ptep = pte_offset_kernel(src_pmdp, addr);
|
||
+ if(!pte_none(*src_ptep))
|
||
+ pte_clear(&init_mm, addr, src_ptep);
|
||
+ } else {
|
||
+ pmd_clear(src_pmdp);
|
||
+ }
|
||
+ } else {
|
||
+ pud_clear(src_pudp);
|
||
+ }
|
||
+
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
+}
|
||
+#endif
|
||
+
|
||
void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ spin_lock(&swapper_pgdir_lock);
|
||
+ iee_rw_gate(IEE_OP_SET_SWAPPER_PGD, pgdp, pgd);
|
||
+ spin_unlock(&swapper_pgdir_lock);
|
||
+ #else
|
||
pgd_t *fixmap_pgdp;
|
||
|
||
spin_lock(&swapper_pgdir_lock);
|
||
@@ -90,6 +370,7 @@ void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
|
||
*/
|
||
pgd_clear_fixmap();
|
||
spin_unlock(&swapper_pgdir_lock);
|
||
+ #endif
|
||
}
|
||
|
||
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
||
@@ -118,7 +399,11 @@ static phys_addr_t __init early_pgtable_alloc(int shift)
|
||
* slot will be free, so we can (ab)use the FIX_PTE slot to initialise
|
||
* any level of table.
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ ptr = pte_set_fixmap_init(phys);
|
||
+ #else
|
||
ptr = pte_set_fixmap(phys);
|
||
+ #endif
|
||
|
||
memset(ptr, 0, PAGE_SIZE);
|
||
|
||
@@ -126,11 +411,16 @@ static phys_addr_t __init early_pgtable_alloc(int shift)
|
||
* Implicit barriers also ensure the zeroed page is visible to the page
|
||
* table walker
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_clear_fixmap_init();
|
||
+ #else
|
||
pte_clear_fixmap();
|
||
+ #endif
|
||
|
||
return phys;
|
||
}
|
||
|
||
+
|
||
bool pgattr_change_is_safe(u64 old, u64 new)
|
||
{
|
||
/*
|
||
@@ -178,7 +468,11 @@ static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
|
||
do {
|
||
pte_t old_pte = __ptep_get(ptep);
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_fixmap_pte_pre_init(ptep, pfn_pte(__phys_to_pfn(phys), prot));
|
||
+ #else
|
||
__set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));
|
||
+ #endif
|
||
|
||
/*
|
||
* After the PTE entry has been populated once, we
|
||
@@ -211,7 +505,11 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
|
||
pmdval |= PMD_TABLE_PXN;
|
||
BUG_ON(!pgtable_alloc);
|
||
pte_phys = pgtable_alloc(PAGE_SHIFT);
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_pmd_populate_fixmap(pmdp, pte_phys, pmdval);
|
||
+ #else
|
||
__pmd_populate(pmdp, pte_phys, pmdval);
|
||
+ #endif
|
||
pmd = READ_ONCE(*pmdp);
|
||
}
|
||
BUG_ON(pmd_bad(pmd));
|
||
@@ -248,7 +546,11 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
|
||
/* try section mapping first */
|
||
if (((addr | next | phys) & ~PMD_MASK) == 0 &&
|
||
(flags & NO_BLOCK_MAPPINGS) == 0) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_pmd_set_huge_fixmap(pmdp, phys, prot);
|
||
+ #else
|
||
pmd_set_huge(pmdp, phys, prot);
|
||
+ #endif
|
||
|
||
/*
|
||
* After the PMD entry has been populated once, we
|
||
@@ -289,7 +591,11 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
|
||
pudval |= PUD_TABLE_PXN;
|
||
BUG_ON(!pgtable_alloc);
|
||
pmd_phys = pgtable_alloc(PMD_SHIFT);
|
||
- __pud_populate(pudp, pmd_phys, pudval);
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_pud_populate_fixmap(pudp, pmd_phys, PUD_TYPE_TABLE);
|
||
+ #else
|
||
+ __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE);
|
||
+ #endif
|
||
pud = READ_ONCE(*pudp);
|
||
}
|
||
BUG_ON(pud_bad(pud));
|
||
@@ -345,7 +651,11 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
|
||
if (pud_sect_supported() &&
|
||
((addr | next | phys) & ~PUD_MASK) == 0 &&
|
||
(flags & NO_BLOCK_MAPPINGS) == 0) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_pud_set_huge_fixmap(pudp, phys, prot);
|
||
+ #else
|
||
pud_set_huge(pudp, phys, prot);
|
||
+ #endif
|
||
|
||
/*
|
||
* After the PUD entry has been populated once, we
|
||
@@ -374,6 +684,10 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
|
||
{
|
||
unsigned long addr, end, next;
|
||
pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
|
||
+ #ifdef CONFIG_IEE
|
||
+ p4d_t *p4dp;
|
||
+ p4d_t p4d;
|
||
+ #endif
|
||
|
||
/*
|
||
* If the virtual and physical address don't have the same offset
|
||
@@ -390,10 +704,14 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
|
||
next = pgd_addr_end(addr, end);
|
||
alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
|
||
flags);
|
||
+ #ifdef CONFIG_IEE
|
||
+ p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d = READ_ONCE(*p4dp);
|
||
+ __p4d_populate(p4dp, __p4d_to_phys(p4d), (PGD_APT | PUD_TYPE_TABLE));
|
||
+ #endif
|
||
phys += next - addr;
|
||
} while (pgdp++, addr = next, addr != end);
|
||
}
|
||
-
|
||
static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
|
||
unsigned long virt, phys_addr_t size,
|
||
pgprot_t prot,
|
||
@@ -413,162 +731,844 @@ void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
|
||
phys_addr_t (*pgtable_alloc)(int), int flags);
|
||
#endif
|
||
|
||
-static phys_addr_t __pgd_pgtable_alloc(int shift)
|
||
+#ifdef CONFIG_PTP
|
||
+static int __init iee_pud_set_huge_pre_init(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
|
||
{
|
||
- void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
|
||
- BUG_ON(!ptr);
|
||
+ pud_t new_pud = pfn_pud(__phys_to_pfn(phys), mk_pud_sect_prot(prot));
|
||
|
||
- /* Ensure the zeroed page is visible to the page table walker */
|
||
- dsb(ishst);
|
||
- return __pa(ptr);
|
||
+ /* Only allow permission changes for now */
|
||
+ if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)),
|
||
+ pud_val(new_pud)))
|
||
+ return 0;
|
||
+
|
||
+ VM_BUG_ON(phys & ~PUD_MASK);
|
||
+ iee_set_pud_pre_init(pudp, new_pud);
|
||
+ return 1;
|
||
}
|
||
|
||
-static phys_addr_t pgd_pgtable_alloc(int shift)
|
||
+static int __init iee_pmd_set_huge_pre_init(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot)
|
||
{
|
||
- phys_addr_t pa = __pgd_pgtable_alloc(shift);
|
||
- struct ptdesc *ptdesc = page_ptdesc(phys_to_page(pa));
|
||
-
|
||
- /*
|
||
- * Call proper page table ctor in case later we need to
|
||
- * call core mm functions like apply_to_page_range() on
|
||
- * this pre-allocated page table.
|
||
- *
|
||
- * We don't select ARCH_ENABLE_SPLIT_PMD_PTLOCK if pmd is
|
||
- * folded, and if so pagetable_pte_ctor() becomes nop.
|
||
- */
|
||
- if (shift == PAGE_SHIFT)
|
||
- BUG_ON(!pagetable_pte_ctor(ptdesc));
|
||
- else if (shift == PMD_SHIFT)
|
||
- BUG_ON(!pagetable_pmd_ctor(ptdesc));
|
||
+ pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), mk_pmd_sect_prot(prot));
|
||
|
||
- return pa;
|
||
-}
|
||
+ /* Only allow permission changes for now */
|
||
+ if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)),
|
||
+ pmd_val(new_pmd)))
|
||
+ return 0;
|
||
|
||
-/*
|
||
- * This function can only be used to modify existing table entries,
|
||
- * without allocating new levels of table. Note that this permits the
|
||
- * creation of new section or page entries.
|
||
- */
|
||
-void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
|
||
- phys_addr_t size, pgprot_t prot)
|
||
-{
|
||
- if (virt < PAGE_OFFSET) {
|
||
- pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
|
||
- &phys, virt);
|
||
- return;
|
||
- }
|
||
- __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
|
||
- NO_CONT_MAPPINGS);
|
||
+ VM_BUG_ON(phys & ~PMD_MASK);
|
||
+ iee_set_pmd_pre_init(pmdp, new_pmd);
|
||
+ return 1;
|
||
}
|
||
|
||
-void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
|
||
- unsigned long virt, phys_addr_t size,
|
||
- pgprot_t prot, bool page_mappings_only)
|
||
+static __init void iee_init_pte_pre_init(pmd_t *pmdp, unsigned long addr, unsigned long end,
|
||
+ phys_addr_t phys, pgprot_t prot)
|
||
{
|
||
- int flags = 0;
|
||
-
|
||
- BUG_ON(mm == &init_mm);
|
||
+ pte_t *ptep;
|
||
|
||
- if (page_mappings_only)
|
||
- flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
+ ptep = pte_set_fixmap_offset_init(pmdp, addr);
|
||
+ do {
|
||
+ pte_t old_pte = READ_ONCE(*ptep);
|
||
|
||
- __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
|
||
- pgd_pgtable_alloc, flags);
|
||
-}
|
||
+ iee_set_pte_pre_init(ptep, pfn_pte(__phys_to_pfn(phys), prot));
|
||
|
||
-static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
|
||
- phys_addr_t size, pgprot_t prot)
|
||
-{
|
||
- if (virt < PAGE_OFFSET) {
|
||
- pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
|
||
- &phys, virt);
|
||
- return;
|
||
- }
|
||
+ /*
|
||
+ * After the PTE entry has been populated once, we
|
||
+ * only allow updates to the permission attributes.
|
||
+ */
|
||
+ BUG_ON(!pgattr_change_is_safe(pte_val(old_pte),
|
||
+ READ_ONCE(pte_val(*ptep))));
|
||
|
||
- __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
|
||
- NO_CONT_MAPPINGS);
|
||
+ phys += PAGE_SIZE;
|
||
+ } while (ptep++, addr += PAGE_SIZE, addr != end);
|
||
|
||
- /* flush the TLBs after updating live kernel mappings */
|
||
- flush_tlb_kernel_range(virt, virt + size);
|
||
+ pte_clear_fixmap_init();
|
||
}
|
||
|
||
-static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
|
||
- phys_addr_t end, pgprot_t prot, int flags)
|
||
+static __init void iee_alloc_init_cont_pte_pre_init(pmd_t *pmdp, unsigned long addr,
|
||
+ unsigned long end, phys_addr_t phys,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
{
|
||
- __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
|
||
- prot, early_pgtable_alloc, flags);
|
||
-}
|
||
+ unsigned long next;
|
||
+ pmd_t pmd = READ_ONCE(*pmdp);
|
||
|
||
-void __init mark_linear_text_alias_ro(void)
|
||
-{
|
||
- /*
|
||
- * Remove the write permissions from the linear alias of .text/.rodata
|
||
- */
|
||
- update_mapping_prot(__pa_symbol(_stext), (unsigned long)lm_alias(_stext),
|
||
- (unsigned long)__init_begin - (unsigned long)_stext,
|
||
- PAGE_KERNEL_RO);
|
||
-}
|
||
+ BUG_ON(pmd_sect(pmd));
|
||
+ if (pmd_none(pmd)) {
|
||
+ pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN;
|
||
+ phys_addr_t pte_phys;
|
||
|
||
-#ifdef CONFIG_KFENCE
|
||
+ if (flags & NO_EXEC_MAPPINGS)
|
||
+ pmdval |= PMD_TABLE_PXN;
|
||
+ BUG_ON(!pgtable_alloc);
|
||
+ pte_phys = pgtable_alloc(PAGE_SHIFT);
|
||
+ __iee_pmd_populate_pre_init(pmdp, pte_phys, pmdval);
|
||
+ pmd = READ_ONCE(*pmdp);
|
||
+ }
|
||
+ BUG_ON(pmd_bad(pmd));
|
||
|
||
-bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
|
||
+ do {
|
||
+ pgprot_t __prot = prot;
|
||
|
||
-/* early_param() will be parsed before map_mem() below. */
|
||
-static int __init parse_kfence_early_init(char *arg)
|
||
-{
|
||
- int val;
|
||
+ next = pte_cont_addr_end(addr, end);
|
||
|
||
- if (get_option(&arg, &val))
|
||
- kfence_early_init = !!val;
|
||
+ /* use a contiguous mapping if the range is suitably aligned */
|
||
+ if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
|
||
+ (flags & NO_CONT_MAPPINGS) == 0)
|
||
+ __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
|
||
|
||
-#if IS_ENABLED(CONFIG_KFENCE_MUST_EARLY_INIT)
|
||
- kfence_must_early_init = (val == -1) ? true : false;
|
||
-#endif
|
||
+ iee_init_pte_pre_init(pmdp, addr, next, phys, __prot);
|
||
|
||
- return 0;
|
||
+ phys += next - addr;
|
||
+ } while (addr = next, addr != end);
|
||
}
|
||
-early_param("kfence.sample_interval", parse_kfence_early_init);
|
||
|
||
-static phys_addr_t __init arm64_kfence_alloc_pool(void)
|
||
+static __init void iee_init_pmd_pre_init(pud_t *pudp, unsigned long addr, unsigned long end,
|
||
+ phys_addr_t phys, pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int), int flags)
|
||
{
|
||
- phys_addr_t kfence_pool;
|
||
+ unsigned long next;
|
||
+ pmd_t *pmdp;
|
||
|
||
- if (!kfence_early_init)
|
||
- return 0;
|
||
+ pmdp = pmd_set_fixmap_offset_init(pudp, addr);
|
||
+ do {
|
||
+ pmd_t old_pmd = READ_ONCE(*pmdp);
|
||
|
||
- kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
|
||
- if (!kfence_pool) {
|
||
- pr_err("failed to allocate kfence pool\n");
|
||
- kfence_early_init = false;
|
||
- return 0;
|
||
- }
|
||
+ next = pmd_addr_end(addr, end);
|
||
|
||
- /* Temporarily mark as NOMAP. */
|
||
- memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
|
||
+ /* try section mapping first */
|
||
+ if (((addr | next | phys) & ~PMD_MASK) == 0 &&
|
||
+ (flags & NO_BLOCK_MAPPINGS) == 0) {
|
||
+ iee_pmd_set_huge_pre_init(pmdp, phys, prot);
|
||
+
|
||
+ /*
|
||
+ * After the PMD entry has been populated once, we
|
||
+ * only allow updates to the permission attributes.
|
||
+ */
|
||
+ BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd),
|
||
+ READ_ONCE(pmd_val(*pmdp))));
|
||
+ } else {
|
||
+ iee_alloc_init_cont_pte_pre_init(pmdp, addr, next, phys, prot,
|
||
+ pgtable_alloc, flags);
|
||
+
|
||
+ BUG_ON(pmd_val(old_pmd) != 0 &&
|
||
+ pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
|
||
+ }
|
||
+ phys += next - addr;
|
||
+ } while (pmdp++, addr = next, addr != end);
|
||
+
|
||
+ pmd_clear_fixmap_init();
|
||
+}
|
||
+
|
||
+static __init void iee_alloc_init_cont_pmd_pre_init(pud_t *pudp, unsigned long addr,
|
||
+ unsigned long end, phys_addr_t phys,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int), int flags)
|
||
+{
|
||
+ unsigned long next;
|
||
+ pud_t pud = READ_ONCE(*pudp);
|
||
+
|
||
+ /*
|
||
+ * Check for initial section mappings in the pgd/pud.
|
||
+ */
|
||
+ BUG_ON(pud_sect(pud));
|
||
+ if (pud_none(pud)) {
|
||
+ pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN;
|
||
+ phys_addr_t pmd_phys;
|
||
+
|
||
+ if (flags & NO_EXEC_MAPPINGS)
|
||
+ pudval |= PUD_TABLE_PXN;
|
||
+ BUG_ON(!pgtable_alloc);
|
||
+ pmd_phys = pgtable_alloc(PMD_SHIFT);
|
||
+ __iee_pud_populate_pre_init(pudp, pmd_phys, pudval);
|
||
+ pud = READ_ONCE(*pudp);
|
||
+ }
|
||
+ BUG_ON(pud_bad(pud));
|
||
+
|
||
+ do {
|
||
+ pgprot_t __prot = prot;
|
||
+
|
||
+ next = pmd_cont_addr_end(addr, end);
|
||
+
|
||
+ /* use a contiguous mapping if the range is suitably aligned */
|
||
+ if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
|
||
+ (flags & NO_CONT_MAPPINGS) == 0)
|
||
+ __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
|
||
+
|
||
+ iee_init_pmd_pre_init(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
|
||
+
|
||
+ phys += next - addr;
|
||
+ } while (addr = next, addr != end);
|
||
+}
|
||
+
|
||
+static __init void iee_alloc_init_pud_pre_init(pgd_t *pgdp, unsigned long addr, unsigned long end,
|
||
+ phys_addr_t phys, pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
+{
|
||
+ unsigned long next;
|
||
+ pud_t *pudp;
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d_t p4d = READ_ONCE(*p4dp);
|
||
+
|
||
+ if (p4d_none(p4d)) {
|
||
+ p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN;
|
||
+ phys_addr_t pud_phys;
|
||
+
|
||
+ if (flags & NO_EXEC_MAPPINGS)
|
||
+ p4dval |= P4D_TABLE_PXN;
|
||
+ BUG_ON(!pgtable_alloc);
|
||
+ pud_phys = pgtable_alloc(PUD_SHIFT);
|
||
+ __iee_p4d_populate_pre_init(p4dp, pud_phys, p4dval);
|
||
+ p4d = READ_ONCE(*p4dp);
|
||
+ }
|
||
+ BUG_ON(p4d_bad(p4d));
|
||
+
|
||
+ pudp = pud_set_fixmap_offset_init(p4dp, addr);
|
||
+ do {
|
||
+ pud_t old_pud = READ_ONCE(*pudp);
|
||
+
|
||
+ next = pud_addr_end(addr, end);
|
||
+
|
||
+ /*
|
||
+ * For 4K granule only, attempt to put down a 1GB block
|
||
+ */
|
||
+ if (pud_sect_supported() &&
|
||
+ ((addr | next | phys) & ~PUD_MASK) == 0 &&
|
||
+ (flags & NO_BLOCK_MAPPINGS) == 0) {
|
||
+ iee_pud_set_huge_pre_init(pudp, phys, prot);
|
||
+
|
||
+ /*
|
||
+ * After the PUD entry has been populated once, we
|
||
+ * only allow updates to the permission attributes.
|
||
+ */
|
||
+ BUG_ON(!pgattr_change_is_safe(pud_val(old_pud),
|
||
+ READ_ONCE(pud_val(*pudp))));
|
||
+ } else {
|
||
+ iee_alloc_init_cont_pmd_pre_init(pudp, addr, next, phys, prot,
|
||
+ pgtable_alloc, flags);
|
||
+
|
||
+ BUG_ON(pud_val(old_pud) != 0 &&
|
||
+ pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
|
||
+ }
|
||
+ phys += next - addr;
|
||
+ } while (pudp++, addr = next, addr != end);
|
||
+
|
||
+ pud_clear_fixmap_init();
|
||
+}
|
||
+
|
||
+static __init void __iee_create_pgd_mapping_locked_pre_init(pgd_t *pgdir, phys_addr_t phys,
|
||
+ unsigned long virt, phys_addr_t size,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
+{
|
||
+ unsigned long addr, end, next;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
|
||
+ p4d_t *p4dp;
|
||
+ p4d_t p4d;
|
||
+
|
||
+ /*
|
||
+ * If the virtual and physical address don't have the same offset
|
||
+ * within a page, we cannot map the region as the caller expects.
|
||
+ */
|
||
+ if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
|
||
+ return;
|
||
+
|
||
+ phys &= PAGE_MASK;
|
||
+ addr = virt & PAGE_MASK;
|
||
+ end = PAGE_ALIGN(virt + size);
|
||
+
|
||
+ do {
|
||
+ next = pgd_addr_end(addr, end);
|
||
+ iee_alloc_init_pud_pre_init(pgdp, addr, next, phys, prot, pgtable_alloc,
|
||
+ flags);
|
||
+ p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d = READ_ONCE(*p4dp);
|
||
+ __iee_p4d_populate_pre_init(p4dp, __p4d_to_phys(p4d), (PGD_APT | PUD_TYPE_TABLE));
|
||
+ phys += next - addr;
|
||
+ } while (pgdp++, addr = next, addr != end);
|
||
+}
|
||
+
|
||
+static __init void __iee_create_pgd_mapping_pre_init(pgd_t *pgdir, phys_addr_t phys,
|
||
+ unsigned long virt, phys_addr_t size,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
+{
|
||
+ mutex_lock(&fixmap_lock);
|
||
+ __iee_create_pgd_mapping_locked_pre_init(pgdir, phys, virt, size, prot,
|
||
+ pgtable_alloc, flags);
|
||
+ mutex_unlock(&fixmap_lock);
|
||
+}
|
||
+#endif
|
||
+
|
||
+static phys_addr_t __pgd_pgtable_alloc(int shift)
|
||
+{
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
+ void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
|
||
+ BUG_ON(!ptr);
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(ptr));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)ptr);
|
||
+ #endif
|
||
+
|
||
+ /* Ensure the zeroed page is visible to the page table walker */
|
||
+ dsb(ishst);
|
||
+ return __pa(ptr);
|
||
+}
|
||
+
|
||
+static phys_addr_t pgd_pgtable_alloc(int shift)
|
||
+{
|
||
+ phys_addr_t pa = __pgd_pgtable_alloc(shift);
|
||
+ struct ptdesc *ptdesc = page_ptdesc(phys_to_page(pa));
|
||
+
|
||
+ /*
|
||
+ * Call proper page table ctor in case later we need to
|
||
+ * call core mm functions like apply_to_page_range() on
|
||
+ * this pre-allocated page table.
|
||
+ *
|
||
+ * We don't select ARCH_ENABLE_SPLIT_PMD_PTLOCK if pmd is
|
||
+ * folded, and if so pagetable_pte_ctor() becomes nop.
|
||
+ */
|
||
+ if (shift == PAGE_SHIFT)
|
||
+ BUG_ON(!pagetable_pte_ctor(ptdesc));
|
||
+ else if (shift == PMD_SHIFT)
|
||
+ BUG_ON(!pagetable_pmd_ctor(ptdesc));
|
||
+
|
||
+ return pa;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * This function can only be used to modify existing table entries,
|
||
+ * without allocating new levels of table. Note that this permits the
|
||
+ * creation of new section or page entries.
|
||
+ */
|
||
+void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
|
||
+ phys_addr_t size, pgprot_t prot)
|
||
+{
|
||
+ if (virt < PAGE_OFFSET) {
|
||
+ pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
|
||
+ &phys, virt);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_create_pgd_mapping_pre_init(init_mm.pgd, phys, virt, size, prot, NULL,
|
||
+ NO_CONT_MAPPINGS);
|
||
+ #else
|
||
+ __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
|
||
+ NO_CONT_MAPPINGS);
|
||
+ #endif
|
||
+}
|
||
+
|
||
+void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
|
||
+ unsigned long virt, phys_addr_t size,
|
||
+ pgprot_t prot, bool page_mappings_only)
|
||
+{
|
||
+ int flags = 0;
|
||
+
|
||
+ BUG_ON(mm == &init_mm);
|
||
+
|
||
+ if (page_mappings_only)
|
||
+ flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
+
|
||
+ __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
|
||
+ pgd_pgtable_alloc, flags);
|
||
+}
|
||
+
|
||
+static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
|
||
+ phys_addr_t size, pgprot_t prot)
|
||
+{
|
||
+ if (virt < PAGE_OFFSET) {
|
||
+ pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
|
||
+ &phys, virt);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
|
||
+ NO_CONT_MAPPINGS);
|
||
+
|
||
+ /* flush the TLBs after updating live kernel mappings */
|
||
+ flush_tlb_kernel_range(virt, virt + size);
|
||
+}
|
||
+
|
||
+static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
|
||
+ phys_addr_t end, pgprot_t prot, int flags)
|
||
+{
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_create_pgd_mapping_pre_init(pgdp, start, __phys_to_virt(start), end - start,
|
||
+ prot, early_pgtable_alloc, flags);
|
||
+ #else
|
||
+ __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
|
||
+ prot, early_pgtable_alloc, flags);
|
||
+ #endif
|
||
+}
|
||
+
|
||
+void __init mark_linear_text_alias_ro(void)
|
||
+{
|
||
+ /*
|
||
+ * Remove the write permissions from the linear alias of .text/.rodata
|
||
+ */
|
||
+ update_mapping_prot(__pa_symbol(_stext), (unsigned long)lm_alias(_stext),
|
||
+ (unsigned long)__init_begin - (unsigned long)_stext,
|
||
+ PAGE_KERNEL_RO);
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_KFENCE
|
||
+
|
||
+bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
|
||
+
|
||
+/* early_param() will be parsed before map_mem() below. */
|
||
+static int __init parse_kfence_early_init(char *arg)
|
||
+{
|
||
+ int val;
|
||
+
|
||
+ if (get_option(&arg, &val))
|
||
+ kfence_early_init = !!val;
|
||
+
|
||
+#if IS_ENABLED(CONFIG_KFENCE_MUST_EARLY_INIT)
|
||
+ kfence_must_early_init = (val == -1) ? true : false;
|
||
+#endif
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+early_param("kfence.sample_interval", parse_kfence_early_init);
|
||
+
|
||
+static phys_addr_t __init arm64_kfence_alloc_pool(void)
|
||
+{
|
||
+ phys_addr_t kfence_pool;
|
||
+
|
||
+ if (!kfence_early_init)
|
||
+ return 0;
|
||
+
|
||
+ kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
|
||
+ if (!kfence_pool) {
|
||
+ pr_err("failed to allocate kfence pool\n");
|
||
+ kfence_early_init = false;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Temporarily mark as NOMAP. */
|
||
+ memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
|
||
+
|
||
+ return kfence_pool;
|
||
+}
|
||
+
|
||
+static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
|
||
+{
|
||
+ if (!kfence_pool)
|
||
+ return;
|
||
+
|
||
+ /* KFENCE pool needs page-level mapping. */
|
||
+ __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
|
||
+ pgprot_tagged(PAGE_KERNEL),
|
||
+ NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
|
||
+ memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
|
||
+ __kfence_pool = phys_to_virt(kfence_pool);
|
||
+}
|
||
+#else /* CONFIG_KFENCE */
|
||
+
|
||
+static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
|
||
+static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
|
||
+
|
||
+#endif /* CONFIG_KFENCE */
|
||
+
|
||
+static void __init map_mem(pgd_t *pgdp)
|
||
+{
|
||
+ static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
|
||
+ phys_addr_t kernel_start = __pa_symbol(_stext);
|
||
+ phys_addr_t kernel_end = __pa_symbol(__init_begin);
|
||
+ phys_addr_t start, end;
|
||
+ phys_addr_t early_kfence_pool;
|
||
+ int flags = NO_EXEC_MAPPINGS;
|
||
+ u64 i;
|
||
+
|
||
+ /*
|
||
+ * Setting hierarchical PXNTable attributes on table entries covering
|
||
+ * the linear region is only possible if it is guaranteed that no table
|
||
+ * entries at any level are being shared between the linear region and
|
||
+ * the vmalloc region. Check whether this is true for the PGD level, in
|
||
+ * which case it is guaranteed to be true for all other levels as well.
|
||
+ */
|
||
+ BUILD_BUG_ON(pgd_index(direct_map_end - 1) == pgd_index(direct_map_end));
|
||
+
|
||
+ early_kfence_pool = arm64_kfence_alloc_pool();
|
||
+
|
||
+ if (can_set_direct_map())
|
||
+ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
+ #endif
|
||
+ /*
|
||
+ * Take care not to create a writable alias for the
|
||
+ * read-only text and rodata sections of the kernel image.
|
||
+ * So temporarily mark them as NOMAP to skip mappings in
|
||
+ * the following for-loop
|
||
+ */
|
||
+ memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
|
||
+
|
||
+ /* map all the memory banks */
|
||
+ for_each_mem_range(i, &start, &end) {
|
||
+ if (start >= end)
|
||
+ break;
|
||
+ /*
|
||
+ * The linear map must allow allocation tags reading/writing
|
||
+ * if MTE is present. Otherwise, it has the same attributes as
|
||
+ * PAGE_KERNEL.
|
||
+ */
|
||
+ __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
|
||
+ flags);
|
||
+ }
|
||
|
||
- return kfence_pool;
|
||
+ /*
|
||
+ * Map the linear alias of the [_stext, __init_begin) interval
|
||
+ * as non-executable now, and remove the write permission in
|
||
+ * mark_linear_text_alias_ro() below (which will be called after
|
||
+ * alternative patching has completed). This makes the contents
|
||
+ * of the region accessible to subsystems such as hibernate,
|
||
+ * but protects it from inadvertent modification or execution.
|
||
+ * Note that contiguous mappings cannot be remapped in this way,
|
||
+ * so we should avoid them here.
|
||
+ */
|
||
+ #ifdef CONFIG_IEE
|
||
+ __map_memblock(pgdp, kernel_start, kernel_end,
|
||
+ PAGE_KERNEL, flags);
|
||
+ #else
|
||
+ __map_memblock(pgdp, kernel_start, kernel_end,
|
||
+ PAGE_KERNEL, NO_CONT_MAPPINGS);
|
||
+ #endif
|
||
+ memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
|
||
+ arm64_kfence_map_pool(early_kfence_pool, pgdp);
|
||
+}
|
||
+
|
||
+void mark_rodata_ro(void)
|
||
+{
|
||
+ unsigned long section_size;
|
||
+
|
||
+ /*
|
||
+ * mark .rodata as read only. Use __init_begin rather than __end_rodata
|
||
+ * to cover NOTES and EXCEPTION_TABLE.
|
||
+ */
|
||
+ section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
|
||
+ update_mapping_prot(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
|
||
+ section_size, PAGE_KERNEL_RO);
|
||
+
|
||
+ debug_checkwx();
|
||
+}
|
||
+
|
||
+static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
|
||
+ pgprot_t prot, struct vm_struct *vma,
|
||
+ int flags, unsigned long vm_flags)
|
||
+{
|
||
+ phys_addr_t pa_start = __pa_symbol(va_start);
|
||
+ unsigned long size = va_end - va_start;
|
||
+
|
||
+ BUG_ON(!PAGE_ALIGNED(pa_start));
|
||
+ BUG_ON(!PAGE_ALIGNED(size));
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_create_pgd_mapping_pre_init(pgdp, pa_start, (unsigned long)va_start, size, prot,
|
||
+ early_pgtable_alloc, flags);
|
||
+ #else
|
||
+ __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot,
|
||
+ early_pgtable_alloc, flags);
|
||
+ #endif
|
||
+
|
||
+ if (!(vm_flags & VM_NO_GUARD))
|
||
+ size += PAGE_SIZE;
|
||
+
|
||
+ vma->addr = va_start;
|
||
+ vma->phys_addr = pa_start;
|
||
+ vma->size = size;
|
||
+ vma->flags = VM_MAP | vm_flags;
|
||
+ vma->caller = __builtin_return_address(0);
|
||
+
|
||
+ vm_area_add_early(vma);
|
||
+}
|
||
+
|
||
+static pgprot_t kernel_exec_prot(void)
|
||
+{
|
||
+ return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
+static int __init map_entry_trampoline(void)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ pgprot_t prot = kernel_exec_prot();
|
||
+ phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
|
||
+
|
||
+ /* The trampoline is always mapped and can therefore be global */
|
||
+ pgprot_val(prot) &= ~PTE_NG;
|
||
+
|
||
+ /* Map only the text into the trampoline page table */
|
||
+ memset(tramp_pg_dir, 0, PGD_SIZE);
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_logical_mem_ro((unsigned long)tramp_pg_dir);
|
||
+ #endif
|
||
+ __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
|
||
+ entry_tramp_text_size(), prot,
|
||
+ __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
|
||
+
|
||
+ /* Map both the text and data into the kernel page table */
|
||
+ for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
|
||
+ __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
|
||
+ pa_start + i * PAGE_SIZE, prot);
|
||
+
|
||
+ if (IS_ENABLED(CONFIG_RELOCATABLE))
|
||
+ __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
|
||
+ pa_start + i * PAGE_SIZE, PAGE_KERNEL_RO);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+core_initcall(map_entry_trampoline);
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Open coded check for BTI, only for use to determine configuration
|
||
+ * for early mappings for before the cpufeature code has run.
|
||
+ */
|
||
+static bool arm64_early_this_cpu_has_bti(void)
|
||
+{
|
||
+ u64 pfr1;
|
||
+
|
||
+ if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
|
||
+ return false;
|
||
+
|
||
+ pfr1 = __read_sysreg_by_encoding(SYS_ID_AA64PFR1_EL1);
|
||
+ return cpuid_feature_extract_unsigned_field(pfr1,
|
||
+ ID_AA64PFR1_EL1_BT_SHIFT);
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+/* Set PMD APTable of iee si codes as (1,1) to revert it to ROX P pages when HPD1=0. */
|
||
+static void __init iee_si_set_pmd_APtable(unsigned long addr, pgd_t *pgdir)
|
||
+{
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
+
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ pud_t *pudp = pud_set_fixmap_offset_init(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_set_fixmap_offset_init(pudp, addr);
|
||
+
|
||
+ pmd_t pmd = READ_ONCE(*pmdp);
|
||
+
|
||
+ __iee_pmd_populate_pre_init(pmdp, __pmd_to_phys(pmd), PGD_APT_RO | PGD_APT | PMD_TYPE_TABLE);
|
||
+
|
||
+ pud_clear_fixmap_init();
|
||
+ pmd_clear_fixmap_init();
|
||
+ #else
|
||
+ pud_t *pudp = pud_set_fixmap_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_set_fixmap_offset(pudp, addr);
|
||
+
|
||
+ pmd_t pmd = READ_ONCE(*pmdp);
|
||
+
|
||
+ __pmd_populate(pmdp, __pmd_to_phys(pmd), PGD_APT_RO | PGD_APT | PMD_TYPE_TABLE);
|
||
+
|
||
+ pud_clear_fixmap();
|
||
+ pmd_clear_fixmap();
|
||
+ #endif
|
||
+}
|
||
+/* Set PMD APTable of iee si codes as (1,1) to revert it to ROX P pages when HPD1=0. */
|
||
+static void __init mark_iee_si_pmd_APtable(pgd_t *pgdir)
|
||
+{
|
||
+ unsigned long addr = (unsigned long)__iee_si_start;
|
||
+ iee_si_set_pmd_APtable(addr, pgdir);
|
||
+ // iee rwx gate exit may be mapped by another pmd.
|
||
+ iee_si_set_pmd_APtable(addr + PAGE_SIZE, pgdir);
|
||
+}
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Create fine-grained mappings for the kernel.
|
||
+ */
|
||
+static void __init map_kernel(pgd_t *pgdp)
|
||
+{
|
||
+ static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
|
||
+ vmlinux_initdata, vmlinux_data;
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ static struct vm_struct vmlinux_iee_code, vmlinux_iee_data, vmlinux_iee_gate, vmlinux_text_end;
|
||
+ #endif
|
||
+
|
||
+ /*
|
||
+ * External debuggers may need to write directly to the text
|
||
+ * mapping to install SW breakpoints. Allow this (only) when
|
||
+ * explicitly requested with rodata=off.
|
||
+ */
|
||
+ pgprot_t text_prot = kernel_exec_prot();
|
||
+
|
||
+ /*
|
||
+ * If we have a CPU that supports BTI and a kernel built for
|
||
+ * BTI then mark the kernel executable text as guarded pages
|
||
+ * now so we don't have to rewrite the page tables later.
|
||
+ */
|
||
+ if (arm64_early_this_cpu_has_bti())
|
||
+ text_prot = __pgprot_modify(text_prot, PTE_GP, PTE_GP);
|
||
+
|
||
+ /*
|
||
+ * Only rodata will be remapped with different permissions later on,
|
||
+ * all other segments are allowed to use contiguous mappings.
|
||
+ */
|
||
+ #ifdef CONFIG_IEE
|
||
+ map_kernel_segment(pgdp, _stext, __iee_si_data_start, text_prot, &vmlinux_text,
|
||
+ 0, VM_NO_GUARD);
|
||
+ /* Set iee si data RW. */
|
||
+ map_kernel_segment(pgdp, __iee_si_data_start, __iee_exec_entry_start, SET_NG(PAGE_KERNEL),
|
||
+ &vmlinux_iee_data, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
|
||
+ /* Set iee entry codes NG. */
|
||
+ map_kernel_segment(pgdp, __iee_exec_entry_start, __iee_si_start, SET_NG(text_prot), &vmlinux_iee_gate,
|
||
+ NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
|
||
+ /* Map __iee_si_start - __iee_si_end as U RWX pages and set PMD APTABLE = (1,1). */
|
||
+ map_kernel_segment(pgdp, __iee_si_start, __iee_si_end, SET_NG((PAGE_KERNEL_EXEC)),
|
||
+ &vmlinux_iee_code, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
|
||
+ mark_iee_si_pmd_APtable(pgdp);
|
||
+
|
||
+ map_kernel_segment(pgdp, __iee_si_end, _etext, text_prot, &vmlinux_text_end, 0,
|
||
+ VM_NO_GUARD);
|
||
+
|
||
+ map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
|
||
+ &vmlinux_rodata, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
|
||
+ &vmlinux_inittext, 0, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
|
||
+ &vmlinux_initdata, 0, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, 0);
|
||
+ #else
|
||
+ map_kernel_segment(pgdp, _stext, _etext, text_prot, &vmlinux_text, 0,
|
||
+ VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
|
||
+ &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
|
||
+ &vmlinux_inittext, 0, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
|
||
+ &vmlinux_initdata, 0, VM_NO_GUARD);
|
||
+ map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
|
||
+ #endif
|
||
+
|
||
+
|
||
+ fixmap_copy(pgdp);
|
||
+ kasan_copy_shadow(pgdp);
|
||
+}
|
||
+
|
||
+static void __init create_idmap(void)
|
||
+{
|
||
+ u64 start = __pa_symbol(__idmap_text_start);
|
||
+ u64 size = __pa_symbol(__idmap_text_end) - start;
|
||
+ pgd_t *pgd = idmap_pg_dir;
|
||
+ u64 pgd_phys;
|
||
+
|
||
+ /* check if we need an additional level of translation */
|
||
+ if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
|
||
+ pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
|
||
+ set_pgd(&idmap_pg_dir[start >> VA_BITS],
|
||
+ __pgd(pgd_phys | P4D_TYPE_TABLE));
|
||
+ pgd = __va(pgd_phys);
|
||
+ }
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_create_pgd_mapping_pre_init(pgd, start, start, size, PAGE_KERNEL_ROX,
|
||
+ early_pgtable_alloc, 0);
|
||
+ #else
|
||
+ __create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
|
||
+ early_pgtable_alloc, 0);
|
||
+ #endif
|
||
+
|
||
+ if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
|
||
+ extern u32 __idmap_kpti_flag;
|
||
+ u64 pa = __pa_symbol(&__idmap_kpti_flag);
|
||
+
|
||
+ /*
|
||
+ * The KPTI G-to-nG conversion code needs a read-write mapping
|
||
+ * of its synchronization flag in the ID map.
|
||
+ */
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_create_pgd_mapping_pre_init(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
|
||
+ early_pgtable_alloc, 0);
|
||
+ #else
|
||
+ __create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
|
||
+ early_pgtable_alloc, 0);
|
||
+ #endif
|
||
+ }
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+static void __create_pgd_mapping_for_iee_locked(pgd_t *pgdir, phys_addr_t phys,
|
||
+ unsigned long virt, phys_addr_t size,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
+{
|
||
+ unsigned long addr, end, next;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
|
||
+ p4d_t *p4dp;
|
||
+ p4d_t p4d;
|
||
+
|
||
+ /*
|
||
+ * If the virtual and physical address don't have the same offset
|
||
+ * within a page, we cannot map the region as the caller expects.
|
||
+ */
|
||
+ if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
|
||
+ return;
|
||
+
|
||
+ phys &= PAGE_MASK;
|
||
+ addr = virt & PAGE_MASK;
|
||
+ end = PAGE_ALIGN(virt + size);
|
||
+
|
||
+ do {
|
||
+ next = pgd_addr_end(addr, end);
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_alloc_init_pud_pre_init(pgdp, addr, next, phys, prot, pgtable_alloc,
|
||
+ flags);
|
||
+ #else
|
||
+ alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
|
||
+ flags);
|
||
+ #endif
|
||
+ p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d = READ_ONCE(*p4dp);
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_p4d_populate_pre_init(p4dp, __p4d_to_phys(p4d), (PGD_APT | PGD_PXN | PGD_UXN | PUD_TYPE_TABLE));
|
||
+ #else
|
||
+ __p4d_populate(p4dp, __p4d_to_phys(p4d), (PGD_APT | PGD_PXN | PGD_UXN | PUD_TYPE_TABLE));
|
||
+ #endif
|
||
+ phys += next - addr;
|
||
+ } while (pgdp++, addr = next, addr != end);
|
||
+}
|
||
+
|
||
+static void __create_pgd_mapping_for_iee(pgd_t *pgdir, phys_addr_t phys,
|
||
+ unsigned long virt, phys_addr_t size,
|
||
+ pgprot_t prot,
|
||
+ phys_addr_t (*pgtable_alloc)(int),
|
||
+ int flags)
|
||
+{
|
||
+ mutex_lock(&fixmap_lock);
|
||
+ __create_pgd_mapping_for_iee_locked(pgdir, phys, virt, size, prot,
|
||
+ pgtable_alloc, flags);
|
||
+ mutex_unlock(&fixmap_lock);
|
||
}
|
||
|
||
-static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
|
||
+static void __init __map_memblock_for_iee(pgd_t *pgdp, phys_addr_t start,
|
||
+ phys_addr_t end, pgprot_t prot, int flags)
|
||
{
|
||
- if (!kfence_pool)
|
||
- return;
|
||
-
|
||
- /* KFENCE pool needs page-level mapping. */
|
||
- __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
|
||
- pgprot_tagged(PAGE_KERNEL),
|
||
- NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
|
||
- memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
|
||
- __kfence_pool = phys_to_virt(kfence_pool);
|
||
+ #ifdef CONFIG_PTP
|
||
+ __create_pgd_mapping_for_iee(pgdp, start, __phys_to_iee(start), end - start,
|
||
+ prot, early_pgtable_alloc, flags);
|
||
+ #else
|
||
+ __create_pgd_mapping_for_iee(pgdp, start, __phys_to_iee(start), end - start,
|
||
+ prot, early_pgtable_alloc, flags);
|
||
+ #endif
|
||
}
|
||
-#else /* CONFIG_KFENCE */
|
||
|
||
-static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
|
||
-static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
|
||
-
|
||
-#endif /* CONFIG_KFENCE */
|
||
-
|
||
-static void __init map_mem(pgd_t *pgdp)
|
||
+static void __init map_iee(pgd_t *pgdp)
|
||
{
|
||
static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
|
||
phys_addr_t kernel_start = __pa_symbol(_stext);
|
||
@@ -578,6 +1578,8 @@ static void __init map_mem(pgd_t *pgdp)
|
||
int flags = NO_EXEC_MAPPINGS;
|
||
u64 i;
|
||
|
||
+ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
+
|
||
/*
|
||
* Setting hierarchical PXNTable attributes on table entries covering
|
||
* the linear region is only possible if it is guaranteed that no table
|
||
@@ -589,9 +1591,6 @@ static void __init map_mem(pgd_t *pgdp)
|
||
|
||
early_kfence_pool = arm64_kfence_alloc_pool();
|
||
|
||
- if (can_set_direct_map())
|
||
- flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
|
||
-
|
||
/*
|
||
* Take care not to create a writable alias for the
|
||
* read-only text and rodata sections of the kernel image.
|
||
@@ -609,12 +1608,11 @@ static void __init map_mem(pgd_t *pgdp)
|
||
* if MTE is present. Otherwise, it has the same attributes as
|
||
* PAGE_KERNEL.
|
||
*/
|
||
- __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
|
||
- flags);
|
||
+ __map_memblock_for_iee(pgdp, start, end, SET_NG(SET_INVALID(SET_UPAGE(PAGE_KERNEL))), flags);
|
||
}
|
||
|
||
/*
|
||
- * Map the linear alias of the [_stext, __init_begin) interval
|
||
+ * Map the linear alias of the [_text, __init_begin) interval
|
||
* as non-executable now, and remove the write permission in
|
||
* mark_linear_text_alias_ro() below (which will be called after
|
||
* alternative patching has completed). This makes the contents
|
||
@@ -623,178 +1621,384 @@ static void __init map_mem(pgd_t *pgdp)
|
||
* Note that contiguous mappings cannot be remapped in this way,
|
||
* so we should avoid them here.
|
||
*/
|
||
- __map_memblock(pgdp, kernel_start, kernel_end,
|
||
- PAGE_KERNEL, NO_CONT_MAPPINGS);
|
||
+ __map_memblock_for_iee(pgdp, kernel_start, kernel_end,
|
||
+ SET_NG(SET_INVALID(SET_UPAGE(PAGE_KERNEL))), flags);
|
||
memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
|
||
arm64_kfence_map_pool(early_kfence_pool, pgdp);
|
||
}
|
||
|
||
-void mark_rodata_ro(void)
|
||
+/*
|
||
+ * Change page access permission, whereas not handling huge pages.
|
||
+ * Only used on IEE init functions.
|
||
+ */
|
||
+static void __init iee_si_set_page_attr(unsigned long addr, pteval_t attr)
|
||
{
|
||
- unsigned long section_size;
|
||
+ unsigned long flag;
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
|
||
- /*
|
||
- * mark .rodata as read only. Use __init_begin rather than __end_rodata
|
||
- * to cover NOTES and EXCEPTION_TABLE.
|
||
- */
|
||
- section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
|
||
- update_mapping_prot(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
|
||
- section_size, PAGE_KERNEL_RO);
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
|
||
- debug_checkwx();
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+
|
||
+ if(attr & PTE_RDONLY)
|
||
+ pte = __pte((pte_val(pte) | PTE_RDONLY) & ~PTE_DBM);
|
||
+ pte = __pte(pte_val(pte) | attr);
|
||
+ #ifdef CONFIG_PTP
|
||
+ // Write pgtable in IEE directly.
|
||
+ flag = local_daif_save();
|
||
+ asm volatile ("msr pan, #0");
|
||
+ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
|
||
+ asm volatile ("msr pan, #1");
|
||
+ local_daif_restore(flag);
|
||
+ #else
|
||
+ WRITE_ONCE(*ptep, pte);
|
||
+ #endif
|
||
+}
|
||
+
|
||
+/* Prepare data used for iee rwx gates. These data are setted only once. */
|
||
+void __init iee_si_prepare_data(void)
|
||
+{
|
||
+ unsigned long va;
|
||
+ // Record current TCR val after system init.
|
||
+ iee_si_tcr = read_sysreg(tcr_el1) & ~(SYS_TCR_IEE_SI);
|
||
+ // Mark iee data as RO and move it to iee after setting up.
|
||
+ va = (unsigned long)__iee_si_data_start;
|
||
+ iee_si_set_page_attr(va, PTE_RDONLY);
|
||
+ iee_si_set_page_attr(lm_alias(va)+iee_offset, 0x1 | PTE_RDONLY);
|
||
+ // Set iee sensitive inst code page U RWX here to hide it from kernel.
|
||
+ va = (unsigned long)__iee_si_start;
|
||
+ iee_si_set_page_attr(va, PTE_USER);
|
||
+ va = (unsigned long)__iee_si_start + PAGE_SIZE;
|
||
+ iee_si_set_page_attr(va, PTE_USER);
|
||
+ flush_tlb_all();
|
||
}
|
||
|
||
-static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
|
||
- pgprot_t prot, struct vm_struct *vma,
|
||
- int flags, unsigned long vm_flags)
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_PTP
|
||
+// Attention : Using set_xxx without adding offset.
|
||
+static void __init set_iee_valid_pre_init(unsigned long addr)
|
||
{
|
||
- phys_addr_t pa_start = __pa_symbol(va_start);
|
||
- unsigned long size = va_end - va_start;
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
|
||
- BUG_ON(!PAGE_ALIGNED(pa_start));
|
||
- BUG_ON(!PAGE_ALIGNED(size));
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
|
||
- __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot,
|
||
- early_pgtable_alloc, flags);
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
|
||
- if (!(vm_flags & VM_NO_GUARD))
|
||
- size += PAGE_SIZE;
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
|
||
- vma->addr = va_start;
|
||
- vma->phys_addr = pa_start;
|
||
- vma->size = size;
|
||
- vma->flags = VM_MAP | vm_flags;
|
||
- vma->caller = __builtin_return_address(0);
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
|
||
- vm_area_add_early(vma);
|
||
+ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
|
||
+ return;
|
||
+
|
||
+ pte = __pte(pte_val(pte) | 0x1);
|
||
+ iee_set_pte_pre_init(ptep, pte);
|
||
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
||
+ isb();
|
||
}
|
||
|
||
-static pgprot_t kernel_exec_prot(void)
|
||
+static void __init move_pte_table_into_iee(pmd_t *pmdp, unsigned long addr, unsigned long end)
|
||
{
|
||
- return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
|
||
+ pmd_t pmd = READ_ONCE(*pmdp);
|
||
+ unsigned long iee_addr = __phys_to_iee(__pmd_to_phys(pmd));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
}
|
||
|
||
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
-static int __init map_entry_trampoline(void)
|
||
+static void __init move_pmd_table_into_iee(pud_t *pudp, unsigned long addr, unsigned long end)
|
||
{
|
||
- int i;
|
||
+ unsigned long next;
|
||
+ pud_t pud = READ_ONCE(*pudp);
|
||
+ pmd_t *pmdp;
|
||
+ pmd_t pmd;
|
||
+ unsigned long iee_addr = __phys_to_iee(__pud_to_phys(pud));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
|
||
- pgprot_t prot = kernel_exec_prot();
|
||
- phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
|
||
+ pmdp = pmd_offset(pudp, addr);
|
||
+ do {
|
||
+ next = pmd_addr_end(addr, end);
|
||
+ pmd = READ_ONCE(*pmdp);
|
||
+ if((pmd_val(pmd) & PMD_TABLE_BIT) == 0)
|
||
+ {
|
||
+ continue;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ move_pte_table_into_iee(pmdp, addr, next);
|
||
+ }
|
||
+ } while (pmdp++, addr = next, addr != end);
|
||
+}
|
||
|
||
- /* The trampoline is always mapped and can therefore be global */
|
||
- pgprot_val(prot) &= ~PTE_NG;
|
||
+static void __init move_pud_table_into_iee(pgd_t *pgdp, unsigned long addr, unsigned long end)
|
||
+{
|
||
+ unsigned long next;
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d_t p4d = READ_ONCE(*p4dp);
|
||
+ pud_t *pudp;
|
||
+ pud_t pud;
|
||
+ unsigned long iee_addr = __phys_to_iee(__p4d_to_phys(p4d));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
|
||
- /* Map only the text into the trampoline page table */
|
||
- memset(tramp_pg_dir, 0, PGD_SIZE);
|
||
- __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
|
||
- entry_tramp_text_size(), prot,
|
||
- __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
|
||
+ pudp = pud_offset(p4dp, addr);
|
||
+ do {
|
||
+ next = pud_addr_end(addr, end);
|
||
+ pud = READ_ONCE(*pudp);
|
||
+ if ((pud_val(pud) & PUD_TABLE_BIT) == 0)
|
||
+ {
|
||
+ continue;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ move_pmd_table_into_iee(pudp, addr, next);
|
||
+ }
|
||
+ } while (pudp++, addr = next, addr != end);
|
||
+}
|
||
|
||
- /* Map both the text and data into the kernel page table */
|
||
- for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
|
||
- __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
|
||
- pa_start + i * PAGE_SIZE, prot);
|
||
+static void __init init_iee_for_one_region(pgd_t *pgdir, unsigned long va_start, unsigned long va_end)
|
||
+{
|
||
+ unsigned long addr, end, next;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start);
|
||
|
||
- if (IS_ENABLED(CONFIG_RELOCATABLE))
|
||
- __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
|
||
- pa_start + i * PAGE_SIZE, PAGE_KERNEL_RO);
|
||
+ addr = va_start & PAGE_MASK;
|
||
+ end = PAGE_ALIGN(va_end);
|
||
|
||
- return 0;
|
||
+ do {
|
||
+ next = pgd_addr_end(addr, end);
|
||
+ move_pud_table_into_iee(pgdp, addr, next);
|
||
+ } while (pgdp++, addr = next, addr != end);
|
||
}
|
||
-core_initcall(map_entry_trampoline);
|
||
-#endif
|
||
|
||
-/*
|
||
- * Open coded check for BTI, only for use to determine configuration
|
||
- * for early mappings for before the cpufeature code has run.
|
||
- */
|
||
-static bool arm64_early_this_cpu_has_bti(void)
|
||
+static void __init init_iee(void)
|
||
{
|
||
- u64 pfr1;
|
||
+ unsigned long iee_addr;
|
||
+ phys_addr_t start, end;
|
||
+ u64 i;
|
||
+ pgd_t *pgdp;
|
||
+
|
||
+ #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
+ // handling 1-level tramp page table tramp_pg_dir
|
||
+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(tramp_pg_dir));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
+ #endif
|
||
+ // handling 1-level page table swapper_pg_dir
|
||
+ pgdp = swapper_pg_dir;
|
||
+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(swapper_pg_dir));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
+ // handling 2/3/4-level page table for kernel
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)_text, (unsigned long)_etext);
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)__start_rodata, (unsigned long)__inittext_begin);
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)__inittext_begin, (unsigned long)__inittext_end);
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)__initdata_begin, (unsigned long)__initdata_end);
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)_data, (unsigned long)_end);
|
||
+ // handling 2/3/4-level page table for fixmap i.e. remap bm_xxx
|
||
+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pte_addr));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pmd_addr));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pud_addr));
|
||
+ set_iee_valid_pre_init(iee_addr);
|
||
+ // handling 2/3/4-level page table for logical mem and iee
|
||
+ for_each_mem_range(i, &start, &end) {
|
||
+ if (start >= end)
|
||
+ break;
|
||
+ /*
|
||
+ * The linear map must allow allocation tags reading/writing
|
||
+ * if MTE is present. Otherwise, it has the same attributes as
|
||
+ * PAGE_KERNEL.
|
||
+ */
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)__va(start), (unsigned long)__va(end));
|
||
+ init_iee_for_one_region(pgdp, (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end));
|
||
+ }
|
||
+}
|
||
|
||
- if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
|
||
- return false;
|
||
+static void iee_set_kernel_upage_pre_init(unsigned long addr)
|
||
+{
|
||
+ pgd_t *pgdir = swapper_pg_dir;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
|
||
|
||
- pfr1 = __read_sysreg_by_encoding(SYS_ID_AA64PFR1_EL1);
|
||
- return cpuid_feature_extract_unsigned_field(pfr1,
|
||
- ID_AA64PFR1_EL1_BT_SHIFT);
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d_t p4d = READ_ONCE(*p4dp);
|
||
+
|
||
+ pud_t *pudp = pud_offset(p4dp, addr);
|
||
+
|
||
+ pmd_t *pmdp = pmd_offset(pudp, addr);
|
||
+
|
||
+ pte_t *ptep = pte_offset_kernel(pmdp, addr);
|
||
+
|
||
+ int i;
|
||
+ for(i = 0; i < 4; i++)
|
||
+ {
|
||
+ pte_t pte = READ_ONCE(*ptep);
|
||
+ pte = __pte(pte_val(pte) | PTE_USER | PTE_NG);
|
||
+ iee_set_pte_pre_init(ptep, pte);
|
||
+ ptep++;
|
||
+ }
|
||
+ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
|
||
+ isb();
|
||
}
|
||
|
||
-/*
|
||
- * Create fine-grained mappings for the kernel.
|
||
- */
|
||
-static void __init map_kernel(pgd_t *pgdp)
|
||
+static void __init iee_set_pte_table_ro(pmd_t *pmdp, unsigned long addr, unsigned long end)
|
||
{
|
||
- static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
|
||
- vmlinux_initdata, vmlinux_data;
|
||
+ pmd_t pmd = READ_ONCE(*pmdp);
|
||
+ unsigned long logical_addr = (unsigned long)__va(__pmd_to_phys(pmd));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+}
|
||
|
||
- /*
|
||
- * External debuggers may need to write directly to the text
|
||
- * mapping to install SW breakpoints. Allow this (only) when
|
||
- * explicitly requested with rodata=off.
|
||
- */
|
||
- pgprot_t text_prot = kernel_exec_prot();
|
||
+static void __init iee_set_pmd_table_ro(pud_t *pudp, unsigned long addr, unsigned long end)
|
||
+{
|
||
+ unsigned long next;
|
||
+ pud_t pud = READ_ONCE(*pudp);
|
||
+ pmd_t *pmdp;
|
||
+ pmd_t pmd;
|
||
+ unsigned long logical_addr = (unsigned long)__va(__pud_to_phys(pud));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
|
||
- /*
|
||
- * If we have a CPU that supports BTI and a kernel built for
|
||
- * BTI then mark the kernel executable text as guarded pages
|
||
- * now so we don't have to rewrite the page tables later.
|
||
- */
|
||
- if (arm64_early_this_cpu_has_bti())
|
||
- text_prot = __pgprot_modify(text_prot, PTE_GP, PTE_GP);
|
||
+ pmdp = pmd_offset(pudp, addr);
|
||
+ do {
|
||
+ next = pmd_addr_end(addr, end);
|
||
+ pmd = READ_ONCE(*pmdp);
|
||
+ if((pmd_val(pmd) & PMD_TABLE_BIT) == 0)
|
||
+ {
|
||
+ continue;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ iee_set_pte_table_ro(pmdp, addr, next);
|
||
+ }
|
||
+ } while (pmdp++, addr = next, addr != end);
|
||
+}
|
||
|
||
- /*
|
||
- * Only rodata will be remapped with different permissions later on,
|
||
- * all other segments are allowed to use contiguous mappings.
|
||
- */
|
||
- map_kernel_segment(pgdp, _stext, _etext, text_prot, &vmlinux_text, 0,
|
||
- VM_NO_GUARD);
|
||
- map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
|
||
- &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
|
||
- map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
|
||
- &vmlinux_inittext, 0, VM_NO_GUARD);
|
||
- map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
|
||
- &vmlinux_initdata, 0, VM_NO_GUARD);
|
||
- map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
|
||
+static void __init iee_set_pud_table_ro(pgd_t *pgdp, unsigned long addr, unsigned long end)
|
||
+{
|
||
+ unsigned long next;
|
||
+ p4d_t *p4dp = p4d_offset(pgdp, addr);
|
||
+ p4d_t p4d = READ_ONCE(*p4dp);
|
||
+ pud_t *pudp;
|
||
+ pud_t pud;
|
||
+ unsigned long logical_addr = (unsigned long)__va(__p4d_to_phys(p4d));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
|
||
- fixmap_copy(pgdp);
|
||
- kasan_copy_shadow(pgdp);
|
||
+ pudp = pud_offset(p4dp, addr);
|
||
+ do {
|
||
+ next = pud_addr_end(addr, end);
|
||
+ pud = READ_ONCE(*pudp);
|
||
+ if ((pud_val(pud) & PUD_TABLE_BIT) == 0)
|
||
+ {
|
||
+ continue;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ iee_set_pmd_table_ro(pudp, addr, next);
|
||
+ }
|
||
+ } while (pudp++, addr = next, addr != end);
|
||
}
|
||
|
||
-static void __init create_idmap(void)
|
||
+static void __init iee_mark_pgtable_for_one_region_ro(pgd_t *pgdir, unsigned long va_start, unsigned long va_end)
|
||
{
|
||
- u64 start = __pa_symbol(__idmap_text_start);
|
||
- u64 size = __pa_symbol(__idmap_text_end) - start;
|
||
- pgd_t *pgd = idmap_pg_dir;
|
||
- u64 pgd_phys;
|
||
+ unsigned long addr, end, next;
|
||
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start);
|
||
|
||
- /* check if we need an additional level of translation */
|
||
- if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
|
||
- pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
|
||
- set_pgd(&idmap_pg_dir[start >> VA_BITS],
|
||
- __pgd(pgd_phys | P4D_TYPE_TABLE));
|
||
- pgd = __va(pgd_phys);
|
||
- }
|
||
- __create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
|
||
- early_pgtable_alloc, 0);
|
||
+ addr = va_start & PAGE_MASK;
|
||
+ end = PAGE_ALIGN(va_end);
|
||
|
||
- if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
|
||
- extern u32 __idmap_kpti_flag;
|
||
- u64 pa = __pa_symbol(&__idmap_kpti_flag);
|
||
+ do {
|
||
+ next = pgd_addr_end(addr, end);
|
||
+ iee_set_pud_table_ro(pgdp, addr, next);
|
||
+ } while (pgdp++, addr = next, addr != end);
|
||
+}
|
||
|
||
+static void __init iee_mark_all_lm_pgtable_ro(void)
|
||
+{
|
||
+ unsigned long logical_addr;
|
||
+ phys_addr_t start, end;
|
||
+ u64 i;
|
||
+ pgd_t *pgdp;
|
||
+
|
||
+ // handling static allocated page table
|
||
+ #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
||
+ // handling 1-level tramp page table tramp_pg_dir
|
||
+ logical_addr = (unsigned long)__va(__pa_symbol(tramp_pg_dir));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+ #endif
|
||
+ // handling 1-level page table swapper_pg_dir
|
||
+ pgdp = swapper_pg_dir;
|
||
+ iee_set_logical_mem_ro((unsigned long)swapper_pg_dir);
|
||
+ logical_addr = (unsigned long)__va(__pa_symbol(swapper_pg_dir));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+
|
||
+ // handling 2/3/4-level page table for kernel
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_text, (unsigned long)_etext);
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__start_rodata, (unsigned long)__inittext_begin);
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__inittext_begin, (unsigned long)__inittext_end);
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__initdata_begin, (unsigned long)__initdata_end);
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_data, (unsigned long)_end);
|
||
+
|
||
+ // handling 2/3/4-level page table for fixmap i.e. remap bm_xxx
|
||
+ logical_addr = (unsigned long)__va(__pa_symbol(bm_pte_addr));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+
|
||
+ iee_set_logical_mem_ro((unsigned long)bm_pmd_addr);
|
||
+ logical_addr = (unsigned long)__va(__pa_symbol(bm_pmd_addr));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+
|
||
+ iee_set_logical_mem_ro((unsigned long)bm_pud_addr);
|
||
+ logical_addr = (unsigned long)__va(__pa_symbol(bm_pud_addr));
|
||
+ iee_set_logical_mem_ro(logical_addr);
|
||
+
|
||
+ // handling 2/3/4-level page table for logical mem and iee
|
||
+ for_each_mem_range(i, &start, &end) {
|
||
+ if (start >= end)
|
||
+ break;
|
||
/*
|
||
- * The KPTI G-to-nG conversion code needs a read-write mapping
|
||
- * of its synchronization flag in the ID map.
|
||
+ * The linear map must allow allocation tags reading/writing
|
||
+ * if MTE is present. Otherwise, it has the same attributes as
|
||
+ * PAGE_KERNEL.
|
||
*/
|
||
- __create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
|
||
- early_pgtable_alloc, 0);
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__va(start), (unsigned long)__va(end));
|
||
+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end));
|
||
}
|
||
}
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+extern s64 koi_offset;
|
||
+#endif
|
||
|
||
void __init paging_init(void)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ unsigned long SP_EL0;
|
||
+ void *new;
|
||
+ void *init_token;
|
||
+ struct task_token *token;
|
||
+ unsigned long tcr;
|
||
+
|
||
+ // Check if cpu has PAN and HPDS.
|
||
+ if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
|
||
+ ID_AA64MMFR1_EL1_PAN_SHIFT))
|
||
+ panic("Architecture doesn't support PAN, please disable CONFIG_IEE.\n");
|
||
+
|
||
+ if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
|
||
+ ID_AA64MMFR1_EL1_HPDS_SHIFT))
|
||
+ panic("Architecture doesn't support HPDS, please disable CONFIG_IEE.\n");
|
||
+ #endif
|
||
+
|
||
+ // Avoid using iee code to modify pgtable before iee initialized.
|
||
+ #ifdef CONFIG_PTP
|
||
+ pgd_t *pgdp = pgd_set_fixmap_init(__pa_symbol(swapper_pg_dir));
|
||
+ #else
|
||
pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
|
||
+ #endif
|
||
+
|
||
+
|
||
extern pgd_t init_idmap_pg_dir[];
|
||
|
||
idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));
|
||
@@ -802,7 +2006,17 @@ void __init paging_init(void)
|
||
map_kernel(pgdp);
|
||
map_mem(pgdp);
|
||
|
||
+ // Map the whole physical mem into IEE, but set invalid.
|
||
+ #ifdef CONFIG_IEE
|
||
+ map_iee(pgdp);
|
||
+ #endif
|
||
+
|
||
+ // Avoid using iee code to modify pgtable before iee initialized.
|
||
+ #ifdef CONFIG_PTP
|
||
+ pgd_clear_fixmap_init();
|
||
+ #else
|
||
pgd_clear_fixmap();
|
||
+ #endif
|
||
|
||
cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
|
||
init_mm.pgd = swapper_pg_dir;
|
||
@@ -813,6 +2027,80 @@ void __init paging_init(void)
|
||
memblock_allow_resize();
|
||
|
||
create_idmap();
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ // test iee_exec_entry
|
||
+ iee_rwx_gate_entry(IEE_SI_TEST);
|
||
+ // Initialize init iee stack.
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_kernel_upage_pre_init((unsigned long)init_iee_stack_begin);
|
||
+ iee_set_kernel_upage_pre_init((unsigned long)__va(__pa_symbol(init_iee_stack_begin)));
|
||
+ #else
|
||
+ iee_set_kernel_upage((unsigned long)init_iee_stack_begin);
|
||
+ iee_set_kernel_upage((unsigned long)__va(__pa_symbol(init_iee_stack_begin)));
|
||
+ #endif
|
||
+ #endif
|
||
+
|
||
+ // Init token for init_task.
|
||
+ #ifdef CONFIG_IEE
|
||
+ // Change SP_EL0 from Image VA to Logical VA.
|
||
+ SP_EL0 = (unsigned long)__va(__pa_symbol(&init_task));
|
||
+ write_sysreg(SP_EL0, sp_el0);
|
||
+ init_task.cpus_ptr = &(((struct task_struct *)(__va(__pa_symbol(&init_task))))->cpus_mask);
|
||
+ init_task.children.prev = (__va(__pa_symbol(init_task.children.prev)));
|
||
+ init_task.children.next = (__va(__pa_symbol(init_task.children.next)));
|
||
+ // Set init_task into __entry_task before per_cpu init.
|
||
+ *(struct task_struct **)__entry_task = __va(__pa_symbol(&init_task));
|
||
+ // Alloc a page for init_token.
|
||
+ new = __va(early_pgtable_alloc(0));
|
||
+ init_token = (void *)__phys_to_iee(__pa_symbol(&init_task));
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_token_page_valid_pre_init(init_token, new);
|
||
+ #else
|
||
+ iee_set_token_page_valid(init_token, new);
|
||
+ #endif
|
||
+ // Use lm to write token before IEE initialized.
|
||
+ token = (struct task_token *)((unsigned long)new + (((unsigned long)&init_task) & ~PAGE_MASK));
|
||
+ token->mm = &init_mm;
|
||
+ token->pgd = NULL;
|
||
+ token->iee_stack = (void *)init_iee_stack_end;
|
||
+ token->valid = true;
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ // Map the existing pgtable into IEE, set valid.
|
||
+ init_iee();
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SPAN);
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ // IEE ready.
|
||
+ // Pgtable writing before uses logical memory and after uses IEE memory.
|
||
+
|
||
+ // Set the logical va of existing pgtable readonly.
|
||
+ iee_mark_all_lm_pgtable_ro();
|
||
+ #endif
|
||
+
|
||
+ // Set the init token readonly.
|
||
+ #ifdef CONFIG_IEE
|
||
+ set_iee_page_valid(__phys_to_iee(__pa(new)));
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+
|
||
+ // Set HPD1 as 1.
|
||
+ tcr = read_sysreg(tcr_el1);
|
||
+ tcr |= ((unsigned long)0x1 << 42);
|
||
+ write_sysreg(tcr, tcr_el1);
|
||
+ isb();
|
||
+
|
||
+ // Flush tlb to enable IEE.
|
||
+ flush_tlb_all();
|
||
+
|
||
+ // mark that iee is prepared.
|
||
+ iee_init_done = true;
|
||
+ #endif
|
||
}
|
||
|
||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
|
||
index 4a64089e5771..894bda11c389 100644
|
||
--- a/arch/arm64/mm/pgd.c
|
||
+++ b/arch/arm64/mm/pgd.c
|
||
@@ -15,14 +15,44 @@
|
||
#include <asm/page.h>
|
||
#include <asm/tlbflush.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
static struct kmem_cache *pgd_cache __ro_after_init;
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+pgd_t *koi_pgd_alloc(void)
|
||
+{
|
||
+ pgd_t *pgd;
|
||
+#ifdef CONFIG_PTP
|
||
+ pgd = (pgd_t *)__get_free_page(GFP_PGTABLE_KERNEL);
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(pgd));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)pgd);
|
||
+#else
|
||
+ pgd = (pgd_t *)__get_free_page(GFP_PGTABLE_KERNEL);
|
||
+#endif
|
||
+ return pgd;
|
||
+}
|
||
+#endif
|
||
+
|
||
pgd_t *pgd_alloc(struct mm_struct *mm)
|
||
{
|
||
gfp_t gfp = GFP_PGTABLE_USER;
|
||
|
||
if (PGD_SIZE == PAGE_SIZE)
|
||
+#ifdef CONFIG_PTP
|
||
+ {
|
||
+ pgd_t* new = (pgd_t *)__get_free_page(gfp);
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(new));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+ return new;
|
||
+ }
|
||
+#else
|
||
return (pgd_t *)__get_free_page(gfp);
|
||
+#endif
|
||
else
|
||
return kmem_cache_alloc(pgd_cache, gfp);
|
||
}
|
||
@@ -30,7 +60,16 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
|
||
void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
||
{
|
||
if (PGD_SIZE == PAGE_SIZE)
|
||
+#ifdef CONFIG_PTP
|
||
+ {
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(pgd));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)pgd);
|
||
+ free_page((unsigned long)pgd);
|
||
+ }
|
||
+#else
|
||
free_page((unsigned long)pgd);
|
||
+#endif
|
||
else
|
||
kmem_cache_free(pgd_cache, pgd);
|
||
}
|
||
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
|
||
index 14fdf645edc8..230b2b883a51 100644
|
||
--- a/arch/arm64/mm/proc.S
|
||
+++ b/arch/arm64/mm/proc.S
|
||
@@ -22,6 +22,8 @@
|
||
#include <asm/smp.h>
|
||
#include <asm/sysreg.h>
|
||
|
||
+
|
||
+
|
||
#ifdef CONFIG_ARM64_64K_PAGES
|
||
#define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K
|
||
#elif defined(CONFIG_ARM64_16K_PAGES)
|
||
@@ -105,6 +107,19 @@ SYM_FUNC_START(cpu_do_suspend)
|
||
ret
|
||
SYM_FUNC_END(cpu_do_suspend)
|
||
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+// SP_EL0 check failed.
|
||
+SYM_FUNC_START_LOCAL(sp_el0_check_failed)
|
||
+1:
|
||
+ nop
|
||
+ nop
|
||
+ nop
|
||
+ nop
|
||
+ b 1f
|
||
+SYM_FUNC_END(sp_el0_check_failed)
|
||
+#endif
|
||
+
|
||
/**
|
||
* cpu_do_resume - restore CPU register context
|
||
*
|
||
@@ -148,6 +163,13 @@ SYM_FUNC_START(cpu_do_resume)
|
||
msr sctlr_el1, x12
|
||
set_this_cpu_offset x13
|
||
msr sp_el0, x14
|
||
+#ifdef CONFIG_IEE
|
||
+ // tsk check.
|
||
+ ldr_this_cpu x2, __entry_task, x3
|
||
+ mrs x3, sp_el0
|
||
+ cmp x2, x3
|
||
+ b.ne sp_el0_check_failed
|
||
+#endif
|
||
/*
|
||
* Restore oslsr_el1 by writing oslar_el1
|
||
*/
|
||
@@ -190,6 +212,7 @@ SYM_TYPED_FUNC_START(idmap_cpu_replace_ttbr1)
|
||
__idmap_cpu_set_reserved_ttbr1 x1, x3
|
||
|
||
offset_ttbr1 x0, x3
|
||
+
|
||
msr ttbr1_el1, x0
|
||
isb
|
||
|
||
@@ -452,6 +475,11 @@ SYM_FUNC_START(__cpu_setup)
|
||
orr tcr, tcr, #TCR_HA // hardware Access flag update
|
||
1:
|
||
#endif /* CONFIG_ARM64_HW_AFDBM */
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+ orr tcr, tcr, #TCR_HPD1 // Hierarchical permission disables
|
||
+#endif
|
||
+
|
||
msr mair_el1, mair
|
||
msr tcr_el1, tcr
|
||
|
||
diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
|
||
index 5139a28130c0..15d2a3faa048 100644
|
||
--- a/arch/arm64/mm/trans_pgd.c
|
||
+++ b/arch/arm64/mm/trans_pgd.c
|
||
@@ -25,6 +25,9 @@
|
||
#include <linux/mm.h>
|
||
#include <linux/mmzone.h>
|
||
#include <linux/kfence.h>
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
|
||
static void *trans_alloc(struct trans_pgd_info *info)
|
||
{
|
||
@@ -65,10 +68,18 @@ static int copy_pte(struct trans_pgd_info *info, pmd_t *dst_pmdp,
|
||
pte_t *src_ptep;
|
||
pte_t *dst_ptep;
|
||
unsigned long addr = start;
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
dst_ptep = trans_alloc(info);
|
||
if (!dst_ptep)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(dst_ptep));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)dst_ptep);
|
||
+ #endif
|
||
pmd_populate_kernel(NULL, dst_pmdp, dst_ptep);
|
||
dst_ptep = pte_offset_kernel(dst_pmdp, start);
|
||
|
||
@@ -87,11 +98,19 @@ static int copy_pmd(struct trans_pgd_info *info, pud_t *dst_pudp,
|
||
pmd_t *dst_pmdp;
|
||
unsigned long next;
|
||
unsigned long addr = start;
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
if (pud_none(READ_ONCE(*dst_pudp))) {
|
||
dst_pmdp = trans_alloc(info);
|
||
if (!dst_pmdp)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(dst_pmdp));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)dst_pmdp);
|
||
+ #endif
|
||
pud_populate(NULL, dst_pudp, dst_pmdp);
|
||
}
|
||
dst_pmdp = pmd_offset(dst_pudp, start);
|
||
@@ -123,11 +142,19 @@ static int copy_pud(struct trans_pgd_info *info, p4d_t *dst_p4dp,
|
||
pud_t *src_pudp;
|
||
unsigned long next;
|
||
unsigned long addr = start;
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
if (p4d_none(READ_ONCE(*dst_p4dp))) {
|
||
dst_pudp = trans_alloc(info);
|
||
if (!dst_pudp)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(dst_pudp));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)dst_pudp);
|
||
+ #endif
|
||
p4d_populate(NULL, dst_p4dp, dst_pudp);
|
||
}
|
||
dst_pudp = pud_offset(dst_p4dp, start);
|
||
@@ -212,6 +239,12 @@ int trans_pgd_create_copy(struct trans_pgd_info *info, pgd_t **dst_pgdp,
|
||
return -ENOMEM;
|
||
}
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(trans_pgd));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)trans_pgd);
|
||
+ #endif
|
||
+
|
||
rc = copy_page_tables(info, trans_pgd, start, end);
|
||
if (!rc)
|
||
*dst_pgdp = trans_pgd;
|
||
@@ -238,6 +271,9 @@ int trans_pgd_idmap_page(struct trans_pgd_info *info, phys_addr_t *trans_ttbr0,
|
||
int bits_mapped = PAGE_SHIFT - 4;
|
||
unsigned long level_mask, prev_level_entry, *levels[4];
|
||
int this_level, index, level_lsb, level_msb;
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
dst_addr &= PAGE_MASK;
|
||
prev_level_entry = pte_val(pfn_pte(pfn, PAGE_KERNEL_ROX));
|
||
@@ -247,12 +283,22 @@ int trans_pgd_idmap_page(struct trans_pgd_info *info, phys_addr_t *trans_ttbr0,
|
||
if (!levels[this_level])
|
||
return -ENOMEM;
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(levels[this_level]));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)levels[this_level]);
|
||
+ #endif
|
||
+
|
||
level_lsb = ARM64_HW_PGTABLE_LEVEL_SHIFT(this_level);
|
||
level_msb = min(level_lsb + bits_mapped, max_msb);
|
||
level_mask = GENMASK_ULL(level_msb, level_lsb);
|
||
|
||
index = (dst_addr & level_mask) >> level_lsb;
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pte((pte_t *)(levels[this_level] + index), __pte(prev_level_entry));
|
||
+ #else
|
||
*(levels[this_level] + index) = prev_level_entry;
|
||
+ #endif
|
||
|
||
pfn = virt_to_pfn(levels[this_level]);
|
||
prev_level_entry = pte_val(pfn_pte(pfn,
|
||
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
|
||
index 83092d93f36a..fb12e7d0660a 100644
|
||
--- a/drivers/firmware/efi/arm-runtime.c
|
||
+++ b/drivers/firmware/efi/arm-runtime.c
|
||
@@ -94,7 +94,11 @@ static int __init arm_enable_runtime_services(void)
|
||
return 0;
|
||
}
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ efi_memmap_unmap_after_init();
|
||
+ #else
|
||
efi_memmap_unmap();
|
||
+ #endif
|
||
|
||
mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
|
||
|
||
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
|
||
index a1180461a445..4c64b6f15717 100644
|
||
--- a/drivers/firmware/efi/memmap.c
|
||
+++ b/drivers/firmware/efi/memmap.c
|
||
@@ -105,6 +105,26 @@ void __init efi_memmap_unmap(void)
|
||
clear_bit(EFI_MEMMAP, &efi.flags);
|
||
}
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+void __init efi_memmap_unmap_after_init(void)
|
||
+{
|
||
+ if (!efi_enabled(EFI_MEMMAP))
|
||
+ return;
|
||
+
|
||
+ if (!(efi.memmap.flags & EFI_MEMMAP_LATE)) {
|
||
+ unsigned long size;
|
||
+
|
||
+ size = efi.memmap.desc_size * efi.memmap.nr_map;
|
||
+ early_iounmap_after_init((__force void __iomem *)efi.memmap.map, size);
|
||
+ } else {
|
||
+ memunmap(efi.memmap.map);
|
||
+ }
|
||
+
|
||
+ efi.memmap.map = NULL;
|
||
+ clear_bit(EFI_MEMMAP, &efi.flags);
|
||
+}
|
||
+#endif
|
||
+
|
||
/**
|
||
* efi_memmap_init_late - Map efi.memmap with memremap()
|
||
* @phys_addr: Physical address of the new EFI memory map
|
||
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
|
||
index a5fbb6ed38ae..81428783b9da 100644
|
||
--- a/drivers/tty/serial/earlycon.c
|
||
+++ b/drivers/tty/serial/earlycon.c
|
||
@@ -40,7 +40,11 @@ static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
|
||
{
|
||
void __iomem *base;
|
||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_set_fixmap_pre_init(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK, FIXMAP_PAGE_IO);
|
||
+ #else
|
||
set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
|
||
+ #endif
|
||
base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
|
||
base += paddr & ~PAGE_MASK;
|
||
#else
|
||
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
|
||
index 45b42d8f6453..b71072d6957e 100644
|
||
--- a/drivers/usb/early/ehci-dbgp.c
|
||
+++ b/drivers/usb/early/ehci-dbgp.c
|
||
@@ -879,7 +879,11 @@ int __init early_dbgp_init(char *s)
|
||
* FIXME I don't have the bar size so just guess PAGE_SIZE is more
|
||
* than enough. 1K is the biggest I have seen.
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_set_fixmap_pre_init(FIX_DBGP_BASE, bar_val & PAGE_MASK, FIXMAP_PAGE_NOCACHE);
|
||
+ #else
|
||
set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
|
||
+ #endif
|
||
ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
|
||
ehci_bar += bar_val & ~PAGE_MASK;
|
||
dbgp_printk("ehci_bar: %p\n", ehci_bar);
|
||
diff --git a/fs/coredump.c b/fs/coredump.c
|
||
index 9d235fa14ab9..72be355903ca 100644
|
||
--- a/fs/coredump.c
|
||
+++ b/fs/coredump.c
|
||
@@ -53,6 +53,10 @@
|
||
|
||
#include <trace/events/sched.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
static bool dump_vma_snapshot(struct coredump_params *cprm);
|
||
static void free_vma_snapshot(struct coredump_params *cprm);
|
||
|
||
@@ -564,7 +568,11 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
||
*/
|
||
if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) {
|
||
/* Setuid core dump mode */
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(cred,GLOBAL_ROOT_UID);
|
||
+ #else
|
||
cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */
|
||
+ #endif
|
||
need_suid_safe = true;
|
||
}
|
||
|
||
diff --git a/fs/exec.c b/fs/exec.c
|
||
index 04fb89656cc3..3689c5f008ba 100644
|
||
--- a/fs/exec.c
|
||
+++ b/fs/exec.c
|
||
@@ -76,6 +76,14 @@
|
||
|
||
#include <trace/events/sched.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+#include <asm/iee-token.h>
|
||
+#endif
|
||
+
|
||
static int bprm_creds_from_file(struct linux_binprm *bprm);
|
||
|
||
int suid_dumpable = 0;
|
||
@@ -1005,6 +1013,10 @@ static int exec_mmap(struct mm_struct *mm)
|
||
if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
|
||
local_irq_enable();
|
||
activate_mm(active_mm, mm);
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(tsk, mm);
|
||
+ iee_set_token_pgd(tsk, mm->pgd);
|
||
+ #endif
|
||
if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
|
||
local_irq_enable();
|
||
lru_gen_add_mm(mm);
|
||
@@ -1618,12 +1630,20 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
||
|
||
if (mode & S_ISUID) {
|
||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_euid(bprm->cred, vfsuid_into_kuid(vfsuid));
|
||
+ #else
|
||
bprm->cred->euid = vfsuid_into_kuid(vfsuid);
|
||
+ #endif
|
||
}
|
||
|
||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_egid(bprm->cred, vfsgid_into_kgid(vfsgid));
|
||
+ #else
|
||
bprm->cred->egid = vfsgid_into_kgid(vfsgid);
|
||
+ #endif
|
||
}
|
||
}
|
||
|
||
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
|
||
index 3e724cb7ef01..e32e136e4271 100644
|
||
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
|
||
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
|
||
@@ -15,6 +15,10 @@
|
||
|
||
#include <linux/sunrpc/metrics.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
#include "flexfilelayout.h"
|
||
#include "../nfs4session.h"
|
||
#include "../nfs4idmap.h"
|
||
@@ -502,8 +506,13 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
|
||
rc = -ENOMEM;
|
||
if (!kcred)
|
||
goto out_err_free;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(kcred,uid);
|
||
+ iee_set_cred_fsgid(kcred,gid);
|
||
+ #else
|
||
kcred->fsuid = uid;
|
||
kcred->fsgid = gid;
|
||
+ #endif
|
||
cred = RCU_INITIALIZER(kcred);
|
||
|
||
if (lgr->range.iomode == IOMODE_READ)
|
||
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
|
||
index 25a7c771cfd8..b15ab8e33e0e 100644
|
||
--- a/fs/nfs/nfs4idmap.c
|
||
+++ b/fs/nfs/nfs4idmap.c
|
||
@@ -48,6 +48,10 @@
|
||
#include <linux/module.h>
|
||
#include <linux/user_namespace.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
#include "internal.h"
|
||
#include "netns.h"
|
||
#include "nfs4idmap.h"
|
||
@@ -226,8 +230,13 @@ int nfs_idmap_init(void)
|
||
goto failed_reg_legacy;
|
||
|
||
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(cred,keyring);
|
||
+ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
|
||
+ #else
|
||
cred->thread_keyring = keyring;
|
||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||
+ #endif
|
||
id_resolver_cache = cred;
|
||
return 0;
|
||
|
||
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
|
||
index e6beaaf4f170..e89385fd81f1 100644
|
||
--- a/fs/nfsd/auth.c
|
||
+++ b/fs/nfsd/auth.c
|
||
@@ -2,6 +2,9 @@
|
||
/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
|
||
|
||
#include <linux/sched.h>
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
#include "nfsd.h"
|
||
#include "auth.h"
|
||
|
||
@@ -32,22 +35,40 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
|
||
if (!new)
|
||
return -ENOMEM;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,rqstp->rq_cred.cr_uid);
|
||
+ iee_set_cred_fsgid(new,rqstp->rq_cred.cr_gid);
|
||
+ #else
|
||
new->fsuid = rqstp->rq_cred.cr_uid;
|
||
new->fsgid = rqstp->rq_cred.cr_gid;
|
||
+ #endif
|
||
|
||
rqgi = rqstp->rq_cred.cr_group_info;
|
||
|
||
if (flags & NFSEXP_ALLSQUASH) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,exp->ex_anon_uid);
|
||
+ iee_set_cred_fsgid(new,exp->ex_anon_gid);
|
||
+ #else
|
||
new->fsuid = exp->ex_anon_uid;
|
||
new->fsgid = exp->ex_anon_gid;
|
||
+ #endif
|
||
gi = groups_alloc(0);
|
||
if (!gi)
|
||
goto oom;
|
||
} else if (flags & NFSEXP_ROOTSQUASH) {
|
||
if (uid_eq(new->fsuid, GLOBAL_ROOT_UID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,exp->ex_anon_uid);
|
||
+ #else
|
||
new->fsuid = exp->ex_anon_uid;
|
||
+ #endif
|
||
if (gid_eq(new->fsgid, GLOBAL_ROOT_GID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsgid(new,exp->ex_anon_gid);
|
||
+ #else
|
||
new->fsgid = exp->ex_anon_gid;
|
||
+ #endif
|
||
|
||
gi = groups_alloc(rqgi->ngroups);
|
||
if (!gi)
|
||
@@ -67,18 +88,35 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
|
||
}
|
||
|
||
if (uid_eq(new->fsuid, INVALID_UID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,exp->ex_anon_uid);
|
||
+ #else
|
||
new->fsuid = exp->ex_anon_uid;
|
||
+ #endif
|
||
if (gid_eq(new->fsgid, INVALID_GID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsgid(new,exp->ex_anon_gid);
|
||
+ #else
|
||
new->fsgid = exp->ex_anon_gid;
|
||
+ #endif
|
||
|
||
set_groups(new, gi);
|
||
put_group_info(gi);
|
||
|
||
if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,cap_drop_nfsd_set(new->cap_effective));
|
||
+ #else
|
||
new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,cap_raise_nfsd_set(new->cap_effective,
|
||
+ new->cap_permitted));
|
||
+ #else
|
||
new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
|
||
new->cap_permitted);
|
||
+ #endif
|
||
put_cred(override_creds(new));
|
||
put_cred(new);
|
||
return 0;
|
||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
|
||
index 4039ffcf90ba..6e0dfa01e01e 100644
|
||
--- a/fs/nfsd/nfs4callback.c
|
||
+++ b/fs/nfsd/nfs4callback.c
|
||
@@ -41,6 +41,9 @@
|
||
#include "trace.h"
|
||
#include "xdr4cb.h"
|
||
#include "xdr4.h"
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
|
||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||
|
||
@@ -946,8 +949,13 @@ static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct r
|
||
if (!kcred)
|
||
return NULL;
|
||
|
||
- kcred->fsuid = ses->se_cb_sec.uid;
|
||
- kcred->fsgid = ses->se_cb_sec.gid;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_uid(kcred,ses->se_cb_sec.uid);
|
||
+ iee_set_cred_gid(kcred,ses->se_cb_sec.gid);
|
||
+ #else
|
||
+ kcred->uid = ses->se_cb_sec.uid;
|
||
+ kcred->gid = ses->se_cb_sec.gid;
|
||
+ #endif
|
||
return kcred;
|
||
}
|
||
}
|
||
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
|
||
index 3509e73abe1f..798fe0352841 100644
|
||
--- a/fs/nfsd/nfs4recover.c
|
||
+++ b/fs/nfsd/nfs4recover.c
|
||
@@ -44,6 +44,10 @@
|
||
#include <linux/sunrpc/clnt.h>
|
||
#include <linux/nfsd/cld.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
#include "nfsd.h"
|
||
#include "state.h"
|
||
#include "vfs.h"
|
||
@@ -78,8 +82,13 @@ nfs4_save_creds(const struct cred **original_creds)
|
||
if (!new)
|
||
return -ENOMEM;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,GLOBAL_ROOT_UID);
|
||
+ iee_set_cred_fsgid(new,GLOBAL_ROOT_GID);
|
||
+ #else
|
||
new->fsuid = GLOBAL_ROOT_UID;
|
||
new->fsgid = GLOBAL_ROOT_GID;
|
||
+ #endif
|
||
*original_creds = override_creds(new);
|
||
put_cred(new);
|
||
return 0;
|
||
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
|
||
index 355bf0db3235..6cb276dde4e9 100644
|
||
--- a/fs/nfsd/nfsfh.c
|
||
+++ b/fs/nfsd/nfsfh.c
|
||
@@ -16,6 +16,10 @@
|
||
#include "auth.h"
|
||
#include "trace.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
#define NFSDDBG_FACILITY NFSDDBG_FH
|
||
|
||
|
||
@@ -223,9 +227,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
|
||
error = nfserrno(-ENOMEM);
|
||
goto out;
|
||
}
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,cap_raise_nfsd_set(new->cap_effective,
|
||
+ new->cap_permitted));
|
||
+ #else
|
||
new->cap_effective =
|
||
cap_raise_nfsd_set(new->cap_effective,
|
||
new->cap_permitted);
|
||
+ #endif
|
||
put_cred(override_creds(new));
|
||
put_cred(new);
|
||
} else {
|
||
diff --git a/fs/open.c b/fs/open.c
|
||
index 54723fceb776..d83901dc50ff 100644
|
||
--- a/fs/open.c
|
||
+++ b/fs/open.c
|
||
@@ -35,6 +35,11 @@
|
||
#include <linux/mnt_idmapping.h>
|
||
#include <linux/filelock.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
+
|
||
#include "internal.h"
|
||
|
||
int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry,
|
||
@@ -414,17 +419,34 @@ static const struct cred *access_override_creds(void)
|
||
* routine.
|
||
*/
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(override_cred,override_cred->uid);
|
||
+ iee_set_cred_fsgid(override_cred,override_cred->gid);
|
||
+ #else
|
||
override_cred->fsuid = override_cred->uid;
|
||
override_cred->fsgid = override_cred->gid;
|
||
+ #endif
|
||
|
||
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
|
||
/* Clear the capabilities if we switch to a non-root user */
|
||
kuid_t root_uid = make_kuid(override_cred->user_ns, 0);
|
||
if (!uid_eq(override_cred->uid, root_uid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = override_cred->cap_effective;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_effective(override_cred, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(override_cred->cap_effective);
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(override_cred,override_cred->cap_permitted);
|
||
+ #else
|
||
override_cred->cap_effective =
|
||
override_cred->cap_permitted;
|
||
+ #endif
|
||
}
|
||
|
||
/*
|
||
@@ -444,7 +466,11 @@ static const struct cred *access_override_creds(void)
|
||
* expecting RCU freeing. But normal thread-synchronous
|
||
* cred accesses will keep things non-RCY.
|
||
*/
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_non_rcu(override_cred,1);
|
||
+ #else
|
||
override_cred->non_rcu = 1;
|
||
+ #endif
|
||
|
||
old_cred = override_creds(override_cred);
|
||
|
||
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
|
||
index 033fc0458a3d..2afa31ead2b5 100644
|
||
--- a/fs/overlayfs/dir.c
|
||
+++ b/fs/overlayfs/dir.c
|
||
@@ -16,6 +16,10 @@
|
||
#include <linux/ratelimit.h>
|
||
#include "overlayfs.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
static unsigned short ovl_redirect_max = 256;
|
||
module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
|
||
MODULE_PARM_DESC(redirect_max,
|
||
@@ -593,8 +597,13 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
|
||
* create a new inode, so just use the ovl mounter's
|
||
* fs{u,g}id.
|
||
*/
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(override_cred,inode->i_uid);
|
||
+ iee_set_cred_fsgid(override_cred,inode->i_gid);
|
||
+ #else
|
||
override_cred->fsuid = inode->i_uid;
|
||
override_cred->fsgid = inode->i_gid;
|
||
+ #endif
|
||
err = security_dentry_create_files_as(dentry,
|
||
attr->mode, &dentry->d_name, old_cred,
|
||
override_cred);
|
||
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
|
||
index 2c056d737c27..9ede99ddb04b 100644
|
||
--- a/fs/overlayfs/super.c
|
||
+++ b/fs/overlayfs/super.c
|
||
@@ -21,6 +21,10 @@
|
||
#include "overlayfs.h"
|
||
#include "params.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
|
||
MODULE_DESCRIPTION("Overlay filesystem");
|
||
MODULE_LICENSE("GPL");
|
||
@@ -1485,7 +1489,15 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
|
||
sb->s_export_op = &ovl_export_fid_operations;
|
||
|
||
/* Never override disk quota limits or use reserved space */
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ kernel_cap_t tmp = cred->cap_effective;
|
||
+ cap_lower(tmp, CAP_SYS_RESOURCE);
|
||
+ iee_set_cred_cap_effective(cred, tmp);
|
||
+ }
|
||
+ #else
|
||
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
|
||
+ #endif
|
||
|
||
sb->s_magic = OVERLAYFS_SUPER_MAGIC;
|
||
sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
|
||
diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c
|
||
index af7849e5974f..4ac2f0e65955 100644
|
||
--- a/fs/smb/client/cifs_spnego.c
|
||
+++ b/fs/smb/client/cifs_spnego.c
|
||
@@ -18,6 +18,10 @@
|
||
#include "cifs_spnego.h"
|
||
#include "cifs_debug.h"
|
||
#include "cifsproto.h"
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
static const struct cred *spnego_cred;
|
||
|
||
/* create a new cifs key */
|
||
@@ -212,8 +216,13 @@ init_cifs_spnego(void)
|
||
* the results it looks up
|
||
*/
|
||
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(cred,keyring);
|
||
+ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
|
||
+ #else
|
||
cred->thread_keyring = keyring;
|
||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||
+ #endif
|
||
spnego_cred = cred;
|
||
|
||
cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
|
||
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
|
||
index f5b6df82e857..9f0ff045836d 100644
|
||
--- a/fs/smb/client/cifsacl.c
|
||
+++ b/fs/smb/client/cifsacl.c
|
||
@@ -26,6 +26,10 @@
|
||
#include "cifs_fs_sb.h"
|
||
#include "cifs_unicode.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
/* security id for everyone/world system group */
|
||
static const struct cifs_sid sid_everyone = {
|
||
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
|
||
@@ -491,8 +495,13 @@ init_cifs_idmap(void)
|
||
/* instruct request_key() to use this special keyring as a cache for
|
||
* the results it looks up */
|
||
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(cred,keyring);
|
||
+ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
|
||
+ #else
|
||
cred->thread_keyring = keyring;
|
||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||
+ #endif
|
||
root_cred = cred;
|
||
|
||
cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
|
||
diff --git a/include/asm-generic/early_ioremap.h b/include/asm-generic/early_ioremap.h
|
||
index 9d0479f50f97..f501e0f965f8 100644
|
||
--- a/include/asm-generic/early_ioremap.h
|
||
+++ b/include/asm-generic/early_ioremap.h
|
||
@@ -17,6 +17,9 @@ extern void *early_memremap_ro(resource_size_t phys_addr,
|
||
extern void *early_memremap_prot(resource_size_t phys_addr,
|
||
unsigned long size, unsigned long prot_val);
|
||
extern void early_iounmap(void __iomem *addr, unsigned long size);
|
||
+#ifdef CONFIG_PTP
|
||
+extern void early_iounmap_after_init(void __iomem *addr, unsigned long size);
|
||
+#endif
|
||
extern void early_memunmap(void *addr, unsigned long size);
|
||
|
||
#if defined(CONFIG_GENERIC_EARLY_IOREMAP) && defined(CONFIG_MMU)
|
||
diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h
|
||
index 8cc7b09c1bc7..83158589a545 100644
|
||
--- a/include/asm-generic/fixmap.h
|
||
+++ b/include/asm-generic/fixmap.h
|
||
@@ -70,6 +70,24 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
|
||
__set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR)
|
||
#endif
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#ifndef clear_fixmap_init
|
||
+#define clear_fixmap_init(idx) \
|
||
+ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR)
|
||
+#endif
|
||
+
|
||
+#define __iee_set_fixmap_offset_pre_init(idx, phys, flags) \
|
||
+({ \
|
||
+ unsigned long ________addr; \
|
||
+ __iee_set_fixmap_pre_init(idx, phys, flags); \
|
||
+ ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \
|
||
+ ________addr; \
|
||
+})
|
||
+
|
||
+#define iee_set_fixmap_offset_pre_init(idx, phys) \
|
||
+ __iee_set_fixmap_offset_pre_init(idx, phys, FIXMAP_PAGE_NORMAL)
|
||
+#endif
|
||
+
|
||
/* Return a pointer with offset calculated */
|
||
#define __set_fixmap_offset(idx, phys, flags) \
|
||
({ \
|
||
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
|
||
index c75d4a753849..506ff9662e02 100644
|
||
--- a/include/asm-generic/pgalloc.h
|
||
+++ b/include/asm-generic/pgalloc.h
|
||
@@ -7,6 +7,10 @@
|
||
#define GFP_PGTABLE_KERNEL (GFP_KERNEL | __GFP_ZERO)
|
||
#define GFP_PGTABLE_USER (GFP_PGTABLE_KERNEL | __GFP_ACCOUNT)
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
/**
|
||
* __pte_alloc_one_kernel - allocate memory for a PTE-level kernel page table
|
||
* @mm: the mm_struct of the current context
|
||
@@ -23,6 +27,13 @@ static inline pte_t *__pte_alloc_one_kernel(struct mm_struct *mm)
|
||
|
||
if (!ptdesc)
|
||
return NULL;
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(ptdesc_address(ptdesc)));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)ptdesc_address(ptdesc));
|
||
+ #endif
|
||
+
|
||
return ptdesc_address(ptdesc);
|
||
}
|
||
|
||
@@ -46,6 +57,11 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
|
||
*/
|
||
static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(pte));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)pte);
|
||
+ #endif
|
||
pagetable_free(virt_to_ptdesc(pte));
|
||
}
|
||
|
||
@@ -73,6 +89,13 @@ static inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp)
|
||
return NULL;
|
||
}
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_t *pte = (pte_t *)page_address(ptdesc_page(ptdesc));
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(pte));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)pte);
|
||
+ #endif
|
||
+
|
||
return ptdesc_page(ptdesc);
|
||
}
|
||
|
||
@@ -103,9 +126,20 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
|
||
*/
|
||
static inline void pte_free(struct mm_struct *mm, struct page *pte_page)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
+
|
||
struct ptdesc *ptdesc = page_ptdesc(pte_page);
|
||
|
||
pagetable_pte_dtor(ptdesc);
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(page_address(pte_page)));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)page_address(pte_page));
|
||
+ #endif
|
||
+
|
||
pagetable_free(ptdesc);
|
||
}
|
||
|
||
@@ -145,10 +179,21 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
|
||
#ifndef __HAVE_ARCH_PMD_FREE
|
||
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
+
|
||
struct ptdesc *ptdesc = virt_to_ptdesc(pmd);
|
||
|
||
BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
|
||
pagetable_pmd_dtor(ptdesc);
|
||
+
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(pmd));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)pmd);
|
||
+ #endif
|
||
+
|
||
pagetable_free(ptdesc);
|
||
}
|
||
#endif
|
||
@@ -190,7 +235,16 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
|
||
|
||
static inline void __pud_free(struct mm_struct *mm, pud_t *pud)
|
||
{
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
+
|
||
BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(pud));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)pud);
|
||
+ #endif
|
||
pagetable_free(virt_to_ptdesc(pud));
|
||
}
|
||
|
||
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
|
||
index 200853042fc7..9d733afced53 100644
|
||
--- a/include/asm-generic/vmlinux.lds.h
|
||
+++ b/include/asm-generic/vmlinux.lds.h
|
||
@@ -346,6 +346,17 @@
|
||
KEEP(*(.dtb.init.rodata)) \
|
||
__dtb_end = .;
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+#define KOI_DATA() \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __koi_data_start = .; \
|
||
+ *(.data..koi) \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ __koi_data_end = .;
|
||
+#else
|
||
+#define KOI_DATA()
|
||
+#endif
|
||
+
|
||
/*
|
||
* .data section
|
||
*/
|
||
@@ -370,8 +381,8 @@
|
||
BRANCH_PROFILE() \
|
||
TRACE_PRINTKS() \
|
||
BPF_RAW_TP() \
|
||
- TRACEPOINT_STR()
|
||
-
|
||
+ TRACEPOINT_STR() \
|
||
+ KOI_DATA()
|
||
/*
|
||
* Data section helpers
|
||
*/
|
||
@@ -1093,6 +1104,14 @@
|
||
* They will fit only a subset of the architectures
|
||
*/
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+ #define CRED_DATA \
|
||
+ . = ALIGN(PAGE_SIZE); \
|
||
+ *(.iee.cred) \
|
||
+ . = ALIGN(PAGE_SIZE);
|
||
+#else
|
||
+ #define CRED_DATA
|
||
+#endif
|
||
|
||
/*
|
||
* Writeable data.
|
||
@@ -1110,6 +1129,7 @@
|
||
. = ALIGN(PAGE_SIZE); \
|
||
.data : AT(ADDR(.data) - LOAD_OFFSET) { \
|
||
INIT_TASK_DATA(inittask) \
|
||
+ CRED_DATA \
|
||
NOSAVE_DATA \
|
||
PAGE_ALIGNED_DATA(pagealigned) \
|
||
CACHELINE_ALIGNED_DATA(cacheline) \
|
||
diff --git a/include/linux/cred.h b/include/linux/cred.h
|
||
index e01c6d094a30..cceb4842b619 100644
|
||
--- a/include/linux/cred.h
|
||
+++ b/include/linux/cred.h
|
||
@@ -18,6 +18,10 @@
|
||
#include <linux/sched/user.h>
|
||
#include <linux/kabi.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-def.h>
|
||
+#endif
|
||
+
|
||
struct cred;
|
||
struct inode;
|
||
|
||
@@ -153,6 +157,22 @@ struct cred {
|
||
KABI_RESERVE(4)
|
||
} __randomize_layout;
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+static void iee_set_cred_non_rcu(struct cred *cred, int non_rcu)
|
||
+{
|
||
+ iee_rw_gate(IEE_OP_SET_CRED_NON_RCU,cred,non_rcu);
|
||
+ *(int *)(&(((struct rcu_head *)(cred->rcu.func))->next)) = non_rcu;
|
||
+}
|
||
+
|
||
+static bool noinline iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr)
|
||
+{
|
||
+ bool ret;
|
||
+ ret = iee_rw_gate(IEE_OP_SET_CRED_ATOP_USAGE,cred,flag,nr);
|
||
+ return ret;
|
||
+}
|
||
+#endif
|
||
+
|
||
extern void __put_cred(struct cred *);
|
||
extern void exit_creds(struct task_struct *);
|
||
extern int copy_creds(struct task_struct *, unsigned long);
|
||
@@ -189,7 +209,11 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
|
||
*/
|
||
static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
|
||
{
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_atomic_op_usage(cred, AT_ADD, nr);
|
||
+ #else
|
||
atomic_long_add(nr, &cred->usage);
|
||
+ #endif
|
||
return cred;
|
||
}
|
||
|
||
@@ -202,7 +226,7 @@ static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
|
||
*/
|
||
static inline struct cred *get_new_cred(struct cred *cred)
|
||
{
|
||
- return get_new_cred_many(cred, 1);
|
||
+ return get_new_cred_many(cred, 1); // XXXzgc atomic_inc -> get_new_cred_many
|
||
}
|
||
|
||
/**
|
||
@@ -224,7 +248,11 @@ static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
|
||
struct cred *nonconst_cred = (struct cred *) cred;
|
||
if (!cred)
|
||
return cred;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_non_rcu(nonconst_cred,0);
|
||
+ #else
|
||
nonconst_cred->non_rcu = 0;
|
||
+ #endif
|
||
return get_new_cred_many(nonconst_cred, nr);
|
||
}
|
||
|
||
@@ -247,9 +275,19 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
|
||
struct cred *nonconst_cred = (struct cred *) cred;
|
||
if (!cred)
|
||
return NULL;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ if (!iee_set_cred_atomic_op_usage(nonconst_cred,AT_INC_NOT_ZERO,0))
|
||
+ return NULL;
|
||
+ #else
|
||
if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
|
||
return NULL;
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_non_rcu(nonconst_cred,0);
|
||
+ #else
|
||
nonconst_cred->non_rcu = 0;
|
||
+ #endif
|
||
return cred;
|
||
}
|
||
|
||
@@ -270,8 +308,13 @@ static inline void put_cred_many(const struct cred *_cred, int nr)
|
||
struct cred *cred = (struct cred *) _cred;
|
||
|
||
if (cred) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ if (iee_set_cred_atomic_op_usage(cred,AT_SUB_AND_TEST,nr))
|
||
+ __put_cred(cred);
|
||
+ #else
|
||
if (atomic_long_sub_and_test(nr, &cred->usage))
|
||
__put_cred(cred);
|
||
+ #endif
|
||
}
|
||
}
|
||
|
||
diff --git a/include/linux/efi.h b/include/linux/efi.h
|
||
index 9ed79128458c..970cc4f7068b 100644
|
||
--- a/include/linux/efi.h
|
||
+++ b/include/linux/efi.h
|
||
@@ -740,6 +740,15 @@ extern int __init __efi_memmap_init(struct efi_memory_map_data *data);
|
||
extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
|
||
extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
|
||
extern void __init efi_memmap_unmap(void);
|
||
+#ifdef CONFIG_PTP
|
||
+extern void __init efi_memmap_unmap_after_init(void);
|
||
+#endif
|
||
+extern int __init efi_memmap_install(struct efi_memory_map_data *data);
|
||
+extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
|
||
+ struct range *range);
|
||
+extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
|
||
+ void *buf, struct efi_mem_range *mem);
|
||
+extern void __init efi_print_memmap(void);
|
||
|
||
#ifdef CONFIG_EFI_ESRT
|
||
extern void __init efi_esrt_init(void);
|
||
diff --git a/include/linux/iee-func.h b/include/linux/iee-func.h
|
||
new file mode 100644
|
||
index 000000000000..79171de67c2a
|
||
--- /dev/null
|
||
+++ b/include/linux/iee-func.h
|
||
@@ -0,0 +1,27 @@
|
||
+#ifndef _LINUX_IEE_FUNC_H
|
||
+#define _LINUX_IEE_FUNC_H
|
||
+
|
||
+#ifdef CONFIG_IEE
|
||
+// Declare the __entry_task.
|
||
+__attribute__((aligned(PAGE_SIZE))) DECLARE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
|
||
+
|
||
+extern unsigned long long iee_rw_gate(int flag, ...);
|
||
+extern u32 get_cpu_asid_bits(void);
|
||
+extern unsigned long arm64_mm_context_get(struct mm_struct *mm);
|
||
+extern void set_iee_page_valid(unsigned long addr);
|
||
+extern void set_iee_page_invalid(unsigned long addr);
|
||
+extern void iee_set_logical_mem_ro(unsigned long addr);
|
||
+extern void iee_set_logical_mem_rw(unsigned long addr);
|
||
+extern void iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm);
|
||
+extern void iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd);
|
||
+extern void iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack);
|
||
+extern void iee_free_token(struct task_struct *tsk);
|
||
+extern unsigned long iee_read_token_stack(struct task_struct *tsk);
|
||
+extern void iee_set_token_page_valid(void *token, void *new);
|
||
+extern void iee_set_token_page_invalid(void *token);
|
||
+extern void iee_set_kernel_ppage(unsigned long addr);
|
||
+extern void iee_set_kernel_upage(unsigned long addr);
|
||
+extern void iee_write_in_byte(void *ptr, u64 data, int length);
|
||
+#endif
|
||
+
|
||
+#endif
|
||
\ No newline at end of file
|
||
diff --git a/include/linux/module.h b/include/linux/module.h
|
||
index 4db2878d9e42..ef8d51994017 100644
|
||
--- a/include/linux/module.h
|
||
+++ b/include/linux/module.h
|
||
@@ -606,6 +606,7 @@ struct module {
|
||
KABI_RESERVE(2)
|
||
KABI_RESERVE(3)
|
||
KABI_RESERVE(4)
|
||
+
|
||
} ____cacheline_aligned __randomize_layout;
|
||
#ifndef MODULE_ARCH_INIT
|
||
#define MODULE_ARCH_INIT {}
|
||
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
||
index f40411aa7b70..297becfbc8e3 100644
|
||
--- a/include/linux/sched.h
|
||
+++ b/include/linux/sched.h
|
||
@@ -773,6 +773,24 @@ struct task_struct_resvd {
|
||
struct task_struct *task;
|
||
};
|
||
|
||
+#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
|
||
+struct task_token {
|
||
+#ifdef CONFIG_IEE
|
||
+ struct mm_struct *mm; /* VA */
|
||
+ pgd_t *pgd; /* Logical VA */
|
||
+ void *iee_stack; /* VA */
|
||
+ bool valid;
|
||
+ void *kernel_stack; /* VA */
|
||
+#endif
|
||
+#ifdef CONFIG_KOI
|
||
+ void *koi_kernel_stack; /* VA */
|
||
+ void *koi_stack; /* VA */
|
||
+ void *koi_stack_base; /* VA */
|
||
+ unsigned long current_ttbr1;
|
||
+#endif
|
||
+};
|
||
+#endif
|
||
+
|
||
struct task_struct {
|
||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||
/*
|
||
@@ -795,6 +813,7 @@ struct task_struct {
|
||
randomized_struct_fields_start
|
||
|
||
void *stack;
|
||
+
|
||
refcount_t usage;
|
||
/* Per task flags (PF_*), defined further below: */
|
||
unsigned int flags;
|
||
diff --git a/init/main.c b/init/main.c
|
||
index 803332dd3d90..0f8d6e2744c2 100644
|
||
--- a/init/main.c
|
||
+++ b/init/main.c
|
||
@@ -102,6 +102,12 @@
|
||
#include <linux/randomize_kstack.h>
|
||
#include <net/net_namespace.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#include <asm/iee-si.h>
|
||
+#include <linux/stop_machine.h>
|
||
+#endif
|
||
+
|
||
#include <asm/io.h>
|
||
#include <asm/setup.h>
|
||
#include <asm/sections.h>
|
||
@@ -112,6 +118,10 @@
|
||
|
||
#include <kunit/test.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+extern void *bm_pte_addr;
|
||
+#endif
|
||
+
|
||
static int kernel_init(void *);
|
||
|
||
/*
|
||
@@ -880,6 +890,9 @@ void start_kernel(void)
|
||
{
|
||
char *command_line;
|
||
char *after_dashes;
|
||
+ #ifdef CONFIG_IEE
|
||
+ unsigned int cpu;
|
||
+ #endif
|
||
|
||
set_task_stack_end_magic(&init_task);
|
||
smp_setup_processor_id();
|
||
@@ -904,6 +917,16 @@ void start_kernel(void)
|
||
setup_command_line(command_line);
|
||
setup_nr_cpu_ids();
|
||
setup_per_cpu_areas();
|
||
+ #ifdef CONFIG_IEE
|
||
+ for_each_possible_cpu(cpu)
|
||
+ {
|
||
+ // Map the __entry_task to IEE.
|
||
+ set_iee_page_valid((unsigned long)__phys_to_iee(__pa(SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]))));
|
||
+ // Set the __entry_task of cpu 0 readonly in lm.
|
||
+ if(cpu == smp_processor_id())
|
||
+ iee_set_logical_mem_ro((unsigned long)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]));
|
||
+ }
|
||
+ #endif
|
||
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
|
||
boot_cpu_hotplug_init();
|
||
|
||
@@ -1446,6 +1469,9 @@ static int __ref kernel_init(void *unused)
|
||
wait_for_completion(&kthreadd_done);
|
||
|
||
kernel_init_freeable();
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_set_logical_mem_ro((unsigned long)bm_pte_addr);
|
||
+ #endif
|
||
/* need to finish all async __init code before freeing the memory */
|
||
async_synchronize_full();
|
||
|
||
@@ -1462,7 +1488,7 @@ static int __ref kernel_init(void *unused)
|
||
* to finalize PTI.
|
||
*/
|
||
pti_finalize();
|
||
-
|
||
+
|
||
system_state = SYSTEM_RUNNING;
|
||
numa_default_policy();
|
||
|
||
diff --git a/kernel/cred.c b/kernel/cred.c
|
||
index c033a201c808..2e44530976d5 100644
|
||
--- a/kernel/cred.c
|
||
+++ b/kernel/cred.c
|
||
@@ -20,6 +20,11 @@
|
||
#include <linux/cn_proc.h>
|
||
#include <linux/uidgid.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
#if 0
|
||
#define kdebug(FMT, ...) \
|
||
printk("[%-5.5s%5u] " FMT "\n", \
|
||
@@ -34,6 +39,9 @@ do { \
|
||
#endif
|
||
|
||
static struct kmem_cache *cred_jar;
|
||
+#ifdef CONFIG_CREDP
|
||
+static struct kmem_cache *rcu_jar;
|
||
+#endif
|
||
|
||
/* init to 2 - one for init_task, one to ensure it is never freed */
|
||
static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
|
||
@@ -41,6 +49,32 @@ static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
|
||
/*
|
||
* The initial credentials for the initial task
|
||
*/
|
||
+#ifdef CONFIG_CREDP
|
||
+struct cred init_cred __section(".iee.cred") = {
|
||
+ .usage = ATOMIC_INIT(4),
|
||
+#ifdef CONFIG_DEBUG_CREDENTIALS
|
||
+ .subscribers = ATOMIC_INIT(2),
|
||
+ .magic = CRED_MAGIC,
|
||
+#endif
|
||
+ .uid = GLOBAL_ROOT_UID,
|
||
+ .gid = GLOBAL_ROOT_GID,
|
||
+ .suid = GLOBAL_ROOT_UID,
|
||
+ .sgid = GLOBAL_ROOT_GID,
|
||
+ .euid = GLOBAL_ROOT_UID,
|
||
+ .egid = GLOBAL_ROOT_GID,
|
||
+ .fsuid = GLOBAL_ROOT_UID,
|
||
+ .fsgid = GLOBAL_ROOT_GID,
|
||
+ .securebits = SECUREBITS_DEFAULT,
|
||
+ .cap_inheritable = CAP_EMPTY_SET,
|
||
+ .cap_permitted = CAP_FULL_SET,
|
||
+ .cap_effective = CAP_FULL_SET,
|
||
+ .cap_bset = CAP_FULL_SET,
|
||
+ .user = INIT_USER,
|
||
+ .user_ns = &init_user_ns,
|
||
+ .group_info = &init_groups,
|
||
+ .ucounts = &init_ucounts,
|
||
+};
|
||
+#else
|
||
struct cred init_cred = {
|
||
.usage = ATOMIC_INIT(4),
|
||
.uid = GLOBAL_ROOT_UID,
|
||
@@ -61,13 +95,43 @@ struct cred init_cred = {
|
||
.group_info = &init_groups,
|
||
.ucounts = &init_ucounts,
|
||
};
|
||
+#endif
|
||
+
|
||
+static inline void set_cred_subscribers(struct cred *cred, int n)
|
||
+{
|
||
+#ifdef CONFIG_DEBUG_CREDENTIALS
|
||
+ atomic_set(&cred->subscribers, n);
|
||
+#endif
|
||
+}
|
||
+
|
||
+static inline int read_cred_subscribers(const struct cred *cred)
|
||
+{
|
||
+#ifdef CONFIG_DEBUG_CREDENTIALS
|
||
+ return atomic_read(&cred->subscribers);
|
||
+#else
|
||
+ return 0;
|
||
+#endif
|
||
+}
|
||
+
|
||
+static inline void alter_cred_subscribers(const struct cred *_cred, int n)
|
||
+{
|
||
+#ifdef CONFIG_DEBUG_CREDENTIALS
|
||
+ struct cred *cred = (struct cred *) _cred;
|
||
+
|
||
+ atomic_add(n, &cred->subscribers);
|
||
+#endif
|
||
+}
|
||
|
||
/*
|
||
* The RCU callback to actually dispose of a set of credentials
|
||
*/
|
||
static void put_cred_rcu(struct rcu_head *rcu)
|
||
{
|
||
+ #ifdef CONFIG_CREDP
|
||
+ struct cred *cred = *(struct cred **)(rcu + 1);
|
||
+ #else
|
||
struct cred *cred = container_of(rcu, struct cred, rcu);
|
||
+ #endif
|
||
|
||
kdebug("put_cred_rcu(%p)", cred);
|
||
|
||
@@ -86,6 +150,9 @@ static void put_cred_rcu(struct rcu_head *rcu)
|
||
if (cred->ucounts)
|
||
put_ucounts(cred->ucounts);
|
||
put_user_ns(cred->user_ns);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ kmem_cache_free(rcu_jar, (struct rcu_head *)(cred->rcu.func));
|
||
+ #endif
|
||
kmem_cache_free(cred_jar, cred);
|
||
}
|
||
|
||
@@ -104,10 +171,22 @@ void __put_cred(struct cred *cred)
|
||
BUG_ON(cred == current->cred);
|
||
BUG_ON(cred == current->real_cred);
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ if (*(int *)(&(((struct rcu_head *)(cred->rcu.func))->next)))
|
||
+ #else
|
||
if (cred->non_rcu)
|
||
+ #endif
|
||
+ #ifdef CONFIG_CREDP
|
||
+ put_cred_rcu((struct rcu_head *)(cred->rcu.func));
|
||
+ #else
|
||
put_cred_rcu(&cred->rcu);
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ call_rcu((struct rcu_head *)(cred->rcu.func), put_cred_rcu);
|
||
+ #else
|
||
call_rcu(&cred->rcu, put_cred_rcu);
|
||
+ #endif
|
||
}
|
||
EXPORT_SYMBOL(__put_cred);
|
||
|
||
@@ -178,7 +257,18 @@ struct cred *cred_alloc_blank(void)
|
||
if (!new)
|
||
return NULL;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_rcu(new,kmem_cache_zalloc(rcu_jar, GFP_KERNEL));
|
||
+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
|
||
+ iee_set_cred_atomic_set_usage(new,1);
|
||
+ #else
|
||
atomic_long_set(&new->usage, 1);
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_DEBUG_CREDENTIALS
|
||
+ new->magic = CRED_MAGIC;
|
||
+ #endif
|
||
+
|
||
if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
|
||
goto error;
|
||
|
||
@@ -213,13 +303,25 @@ struct cred *prepare_creds(void)
|
||
if (!new)
|
||
return NULL;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_rcu(new,kmem_cache_alloc(rcu_jar, GFP_KERNEL));
|
||
+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
|
||
+ #endif
|
||
+
|
||
kdebug("prepare_creds() alloc %p", new);
|
||
|
||
old = task->cred;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_copy_cred(old,new);
|
||
+
|
||
+ iee_set_cred_non_rcu(new,0);
|
||
+ iee_set_cred_atomic_set_usage(new,1);
|
||
+ #else
|
||
memcpy(new, old, sizeof(struct cred));
|
||
|
||
new->non_rcu = 0;
|
||
atomic_long_set(&new->usage, 1);
|
||
+ #endif
|
||
get_group_info(new->group_info);
|
||
get_uid(new->user);
|
||
get_user_ns(new->user_ns);
|
||
@@ -232,10 +334,18 @@ struct cred *prepare_creds(void)
|
||
#endif
|
||
|
||
#ifdef CONFIG_SECURITY
|
||
+#ifdef CONFIG_CREDP
|
||
+ iee_set_cred_security(new,NULL);
|
||
+#else
|
||
new->security = NULL;
|
||
+#endif
|
||
#endif
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_ucounts(new, get_ucounts(new->ucounts));
|
||
+ #else
|
||
new->ucounts = get_ucounts(new->ucounts);
|
||
+ #endif
|
||
if (!new->ucounts)
|
||
goto error;
|
||
|
||
@@ -265,15 +375,30 @@ struct cred *prepare_exec_creds(void)
|
||
#ifdef CONFIG_KEYS
|
||
/* newly exec'd tasks don't get a thread keyring */
|
||
key_put(new->thread_keyring);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(new,NULL);
|
||
+ #else
|
||
new->thread_keyring = NULL;
|
||
+ #endif
|
||
|
||
/* inherit the session keyring; new process keyring */
|
||
key_put(new->process_keyring);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_process_keyring(new,NULL);
|
||
+ #else
|
||
new->process_keyring = NULL;
|
||
+ #endif
|
||
#endif
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,new->euid);
|
||
+ iee_set_cred_suid(new,new->euid);
|
||
+ iee_set_cred_fsgid(new,new->egid);
|
||
+ iee_set_cred_sgid(new,new->egid);
|
||
+ #else
|
||
new->suid = new->fsuid = new->euid;
|
||
new->sgid = new->fsgid = new->egid;
|
||
+ #endif
|
||
|
||
return new;
|
||
}
|
||
@@ -327,7 +452,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||
* had one */
|
||
if (new->thread_keyring) {
|
||
key_put(new->thread_keyring);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(new,NULL);
|
||
+ #else
|
||
new->thread_keyring = NULL;
|
||
+ #endif
|
||
if (clone_flags & CLONE_THREAD)
|
||
install_thread_keyring_to_cred(new);
|
||
}
|
||
@@ -337,7 +466,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||
*/
|
||
if (!(clone_flags & CLONE_THREAD)) {
|
||
key_put(new->process_keyring);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_process_keyring(new,NULL);
|
||
+ #else
|
||
new->process_keyring = NULL;
|
||
+ #endif
|
||
}
|
||
#endif
|
||
|
||
@@ -594,7 +727,11 @@ int set_cred_ucounts(struct cred *new)
|
||
if (!(new_ucounts = alloc_ucounts(new->user_ns, new->uid)))
|
||
return -EAGAIN;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_ucounts(new, new_ucounts);
|
||
+ #else
|
||
new->ucounts = new_ucounts;
|
||
+ #endif
|
||
put_ucounts(old_ucounts);
|
||
|
||
return 0;
|
||
@@ -606,8 +743,21 @@ int set_cred_ucounts(struct cred *new)
|
||
void __init cred_init(void)
|
||
{
|
||
/* allocate a slab in which we can store credentials */
|
||
+ #ifdef CONFIG_CREDP
|
||
cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
|
||
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE, NULL);
|
||
+ rcu_jar = kmem_cache_create("rcu_jar", sizeof(struct rcu_head) + sizeof(struct cred *), 0,
|
||
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
|
||
+ // Map init_cred
|
||
+ *((struct rcu_head **)(&(init_cred.rcu.func))) = (struct rcu_head *)kmem_cache_zalloc(rcu_jar, GFP_KERNEL);
|
||
+ *(struct cred **)(((struct rcu_head *)(init_cred.rcu.func)) + 1) = &init_cred;
|
||
+ set_iee_page_valid(__phys_to_iee(__pa_symbol(&init_cred)));
|
||
+ iee_set_logical_mem_ro((unsigned long)&init_cred);
|
||
+ iee_set_logical_mem_ro((unsigned long)__va(__pa_symbol(&init_cred)));
|
||
+ #else
|
||
+ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
|
||
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
|
||
+ #endif
|
||
}
|
||
|
||
/**
|
||
@@ -638,29 +788,56 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
|
||
if (!new)
|
||
return NULL;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_rcu(new,kmem_cache_alloc(rcu_jar, GFP_KERNEL));
|
||
+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
|
||
+ #endif
|
||
+
|
||
kdebug("prepare_kernel_cred() alloc %p", new);
|
||
|
||
old = get_task_cred(daemon);
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_copy_cred(old,new);
|
||
+ iee_set_cred_non_rcu(new,0);
|
||
+ iee_set_cred_atomic_set_usage(new,1);
|
||
+ #else
|
||
*new = *old;
|
||
new->non_rcu = 0;
|
||
atomic_long_set(&new->usage, 1);
|
||
+ #endif
|
||
get_uid(new->user);
|
||
get_user_ns(new->user_ns);
|
||
get_group_info(new->group_info);
|
||
|
||
#ifdef CONFIG_KEYS
|
||
+#ifdef CONFIG_CREDP
|
||
+ iee_set_cred_session_keyring(new,NULL);
|
||
+ iee_set_cred_process_keyring(new,NULL);
|
||
+ iee_set_cred_thread_keyring(new,NULL);
|
||
+ iee_set_cred_request_key_auth(new,NULL);
|
||
+ iee_set_cred_jit_keyring(new,KEY_REQKEY_DEFL_THREAD_KEYRING);
|
||
+#else
|
||
new->session_keyring = NULL;
|
||
new->process_keyring = NULL;
|
||
new->thread_keyring = NULL;
|
||
new->request_key_auth = NULL;
|
||
new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||
#endif
|
||
+#endif
|
||
|
||
#ifdef CONFIG_SECURITY
|
||
+#ifdef CONFIG_CREDP
|
||
+ iee_set_cred_security(new,NULL);
|
||
+#else
|
||
new->security = NULL;
|
||
#endif
|
||
+#endif
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_ucounts(new, get_ucounts(new->ucounts));
|
||
+ #else
|
||
new->ucounts = get_ucounts(new->ucounts);
|
||
+ #endif
|
||
if (!new->ucounts)
|
||
goto error;
|
||
|
||
@@ -727,8 +904,13 @@ int set_create_files_as(struct cred *new, struct inode *inode)
|
||
{
|
||
if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
|
||
return -EINVAL;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,inode->i_uid);
|
||
+ iee_set_cred_fsgid(new,inode->i_gid);
|
||
+ #else
|
||
new->fsuid = inode->i_uid;
|
||
new->fsgid = inode->i_gid;
|
||
+ #endif
|
||
return security_kernel_create_files_as(new, inode);
|
||
}
|
||
EXPORT_SYMBOL(set_create_files_as);
|
||
diff --git a/kernel/exit.c b/kernel/exit.c
|
||
index 21a59a6e1f2e..d21a109f0497 100644
|
||
--- a/kernel/exit.c
|
||
+++ b/kernel/exit.c
|
||
@@ -74,6 +74,10 @@
|
||
#include <asm/unistd.h>
|
||
#include <asm/mmu_context.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
/*
|
||
* The default value should be high enough to not crash a system that randomly
|
||
* crashes its kernel from time to time, but low enough to at least not permit
|
||
@@ -558,6 +562,10 @@ static void exit_mm(void)
|
||
smp_mb__after_spinlock();
|
||
local_irq_disable();
|
||
current->mm = NULL;
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(current, NULL);
|
||
+ iee_set_token_pgd(current, NULL);
|
||
+ #endif
|
||
membarrier_update_current_mm(NULL);
|
||
enter_lazy_tlb(mm, current);
|
||
local_irq_enable();
|
||
diff --git a/kernel/fork.c b/kernel/fork.c
|
||
index e033388b11bd..c93e18a4f0b3 100644
|
||
--- a/kernel/fork.c
|
||
+++ b/kernel/fork.c
|
||
@@ -115,6 +115,10 @@
|
||
#define CREATE_TRACE_POINTS
|
||
#include <trace/events/task.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
/*
|
||
* Minimum number of threads to boot the kernel
|
||
*/
|
||
@@ -128,14 +132,14 @@
|
||
/*
|
||
* Protected counters by write_lock_irq(&tasklist_lock)
|
||
*/
|
||
-unsigned long total_forks; /* Handle normal Linux uptimes. */
|
||
-int nr_threads; /* The idle threads do not count.. */
|
||
+unsigned long total_forks; /* Handle normal Linux uptimes. */
|
||
+int nr_threads; /* The idle threads do not count.. */
|
||
|
||
-static int max_threads; /* tunable limit on nr_threads */
|
||
+static int max_threads; /* tunable limit on nr_threads */
|
||
|
||
-#define NAMED_ARRAY_INDEX(x) [x] = __stringify(x)
|
||
+#define NAMED_ARRAY_INDEX(x) [x] = __stringify(x)
|
||
|
||
-static const char * const resident_page_types[] = {
|
||
+static const char *const resident_page_types[] = {
|
||
NAMED_ARRAY_INDEX(MM_FILEPAGES),
|
||
NAMED_ARRAY_INDEX(MM_ANONPAGES),
|
||
NAMED_ARRAY_INDEX(MM_SWAPENTS),
|
||
@@ -144,7 +148,7 @@ static const char * const resident_page_types[] = {
|
||
|
||
DEFINE_PER_CPU(unsigned long, process_counts) = 0;
|
||
|
||
-__cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */
|
||
+__cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */
|
||
|
||
#ifdef CONFIG_PROVE_RCU
|
||
int lockdep_tasklist_lock_is_held(void)
|
||
@@ -159,7 +163,7 @@ int nr_processes(void)
|
||
int cpu;
|
||
int total = 0;
|
||
|
||
- for_each_possible_cpu(cpu)
|
||
+ for_each_possible_cpu (cpu)
|
||
total += per_cpu(process_counts, cpu);
|
||
|
||
return total;
|
||
@@ -190,7 +194,7 @@ static inline void free_task_struct(struct task_struct *tsk)
|
||
* Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
|
||
* kmemcache based allocator.
|
||
*/
|
||
-# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
|
||
+#if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
|
||
|
||
# ifdef CONFIG_VMAP_STACK
|
||
/*
|
||
@@ -311,8 +315,8 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
|
||
* so memcg accounting is performed manually on assigning/releasing
|
||
* stacks to tasks. Drop __GFP_ACCOUNT.
|
||
*/
|
||
- stack = __vmalloc_node_range(THREAD_SIZE, THREAD_ALIGN,
|
||
- VMALLOC_START, VMALLOC_END,
|
||
+ stack = __vmalloc_node_range(THREAD_SIZE, THREAD_ALIGN, VMALLOC_START,
|
||
+ VMALLOC_END,
|
||
THREADINFO_GFP & ~__GFP_ACCOUNT,
|
||
PAGE_KERNEL,
|
||
0, node, __builtin_return_address(0));
|
||
@@ -410,9 +414,10 @@ static void free_thread_stack(struct task_struct *tsk)
|
||
|
||
void thread_stack_cache_init(void)
|
||
{
|
||
- thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
|
||
- THREAD_SIZE, THREAD_SIZE, 0, 0,
|
||
- THREAD_SIZE, NULL);
|
||
+ thread_stack_cache =
|
||
+ kmem_cache_create_usercopy("thread_stack", THREAD_SIZE,
|
||
+ THREAD_SIZE, 0, 0, THREAD_SIZE,
|
||
+ NULL);
|
||
BUG_ON(thread_stack_cache == NULL);
|
||
}
|
||
|
||
@@ -502,7 +507,8 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
|
||
|
||
struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
|
||
{
|
||
- struct vm_area_struct *new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
|
||
+ struct vm_area_struct *new =
|
||
+ kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
|
||
|
||
if (!new)
|
||
return NULL;
|
||
@@ -602,8 +608,15 @@ void put_task_stack(struct task_struct *tsk)
|
||
}
|
||
#endif
|
||
|
||
+#ifdef CONFIG_KOI
|
||
+extern s64 koi_offset;
|
||
+#endif
|
||
+
|
||
void free_task(struct task_struct *tsk)
|
||
{
|
||
+ #ifdef CONFIG_IEE
|
||
+ void *iee_stack;
|
||
+ #endif
|
||
#ifdef CONFIG_SECCOMP
|
||
WARN_ON_ONCE(tsk->seccomp.filter);
|
||
#endif
|
||
@@ -633,6 +646,45 @@ void free_task(struct task_struct *tsk)
|
||
if (dynamic_affinity_enabled())
|
||
sched_prefer_cpus_free(tsk);
|
||
#endif
|
||
+#ifdef CONFIG_IEE
|
||
+ // Free iee stack.
|
||
+ iee_stack = (void *)iee_read_token_stack(tsk);
|
||
+ if (iee_stack) {
|
||
+ iee_set_kernel_ppage(
|
||
+ (unsigned long)(iee_stack - PAGE_SIZE * 4));
|
||
+ free_pages((unsigned long)(iee_stack - PAGE_SIZE * 4), 3);
|
||
+ }
|
||
+ // Free task_token.
|
||
+ // Empty the token
|
||
+ iee_free_token(tsk);
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+ // Free koi stack.
|
||
+ unsigned long koi_stack = iee_rw_gate(IEE_READ_KOI_STACK_BASE, current);
|
||
+ if (koi_stack != 0)
|
||
+ free_pages(koi_stack, 2);
|
||
+#endif
|
||
+#else
|
||
+#ifdef CONFIG_KOI
|
||
+// free koi stack
|
||
+ struct task_token *token = (struct task_token *)((unsigned long)current + koi_offset);
|
||
+ unsigned long flags;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile(
|
||
+ "at s1e1r, %0\n"
|
||
+ "isb\n"
|
||
+ :
|
||
+ :"r"(token));
|
||
+ unsigned long res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+ if (!(res & 0x1)) {
|
||
+ unsigned long koi_stack = token->koi_stack_base;
|
||
+ if (koi_stack != 0)
|
||
+ free_pages(koi_stack, 2);
|
||
+ }
|
||
+#endif
|
||
+#endif
|
||
+
|
||
#ifdef CONFIG_QOS_SCHED_SMART_GRID
|
||
if (smart_grid_enabled())
|
||
sched_grid_qos_free(tsk);
|
||
@@ -657,7 +709,7 @@ static void dup_mm_exe_file(struct mm_struct *mm, struct mm_struct *oldmm)
|
||
|
||
#ifdef CONFIG_MMU
|
||
static __latent_entropy int dup_mmap(struct mm_struct *mm,
|
||
- struct mm_struct *oldmm)
|
||
+ struct mm_struct *oldmm)
|
||
{
|
||
struct vm_area_struct *mpnt, *tmp;
|
||
int retval;
|
||
@@ -773,7 +825,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
|
||
flush_dcache_mmap_lock(mapping);
|
||
/* insert tmp into the share list, just after mpnt */
|
||
vma_interval_tree_insert_after(tmp, mpnt,
|
||
- &mapping->i_mmap);
|
||
+ &mapping->i_mmap);
|
||
flush_dcache_mmap_unlock(mapping);
|
||
i_mmap_unlock_write(mapping);
|
||
}
|
||
@@ -842,7 +894,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
|
||
mmap_write_unlock(oldmm);
|
||
return 0;
|
||
}
|
||
-#define mm_alloc_pgd(mm) (0)
|
||
+#define mm_alloc_pgd(mm) (0)
|
||
#define mm_free_pgd(mm)
|
||
#endif /* CONFIG_MMU */
|
||
|
||
@@ -850,20 +902,22 @@ static void check_mm(struct mm_struct *mm)
|
||
{
|
||
int i;
|
||
|
||
- BUILD_BUG_ON_MSG(ARRAY_SIZE(resident_page_types) != NR_MM_COUNTERS,
|
||
- "Please make sure 'struct resident_page_types[]' is updated as well");
|
||
+ BUILD_BUG_ON_MSG(
|
||
+ ARRAY_SIZE(resident_page_types) != NR_MM_COUNTERS,
|
||
+ "Please make sure 'struct resident_page_types[]' is updated as well");
|
||
|
||
for (i = 0; i < NR_MM_COUNTERS; i++) {
|
||
long x = mm_counter_sum(mm, i);
|
||
|
||
if (unlikely(x))
|
||
- pr_alert("BUG: Bad rss-counter state mm:%p type:%s val:%ld\n",
|
||
- mm, resident_page_types[i], x);
|
||
+ pr_alert(
|
||
+ "BUG: Bad rss-counter state mm:%p type:%s val:%ld\n",
|
||
+ mm, resident_page_types[i], x);
|
||
}
|
||
|
||
if (mm_pgtables_bytes(mm))
|
||
pr_alert("BUG: non-zero pgtables_bytes on freeing mm: %ld\n",
|
||
- mm_pgtables_bytes(mm));
|
||
+ mm_pgtables_bytes(mm));
|
||
|
||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
|
||
VM_BUG_ON_MM(mm->pmd_huge_pte, mm);
|
||
@@ -1014,14 +1068,6 @@ void __put_task_struct(struct task_struct *tsk)
|
||
}
|
||
EXPORT_SYMBOL_GPL(__put_task_struct);
|
||
|
||
-void __put_task_struct_rcu_cb(struct rcu_head *rhp)
|
||
-{
|
||
- struct task_struct *task = container_of(rhp, struct task_struct, rcu);
|
||
-
|
||
- __put_task_struct(task);
|
||
-}
|
||
-EXPORT_SYMBOL_GPL(__put_task_struct_rcu_cb);
|
||
-
|
||
void __init __weak arch_task_cache_init(void) { }
|
||
|
||
/*
|
||
@@ -1039,8 +1085,8 @@ static void set_max_threads(unsigned int max_threads_suggested)
|
||
if (fls64(nr_pages) + fls64(PAGE_SIZE) > 64)
|
||
threads = MAX_THREADS;
|
||
else
|
||
- threads = div64_u64((u64) nr_pages * (u64) PAGE_SIZE,
|
||
- (u64) THREAD_SIZE * 8UL);
|
||
+ threads = div64_u64((u64)nr_pages * (u64)PAGE_SIZE,
|
||
+ (u64)THREAD_SIZE * 8UL);
|
||
|
||
if (threads > max_threads_suggested)
|
||
threads = max_threads_suggested;
|
||
@@ -1075,17 +1121,24 @@ void __init fork_init(void)
|
||
int i;
|
||
#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
|
||
#ifndef ARCH_MIN_TASKALIGN
|
||
-#define ARCH_MIN_TASKALIGN 0
|
||
+#define ARCH_MIN_TASKALIGN 0
|
||
#endif
|
||
int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN);
|
||
unsigned long useroffset, usersize;
|
||
|
||
/* create a slab on which task_structs can be allocated */
|
||
task_struct_whitelist(&useroffset, &usersize);
|
||
+ #ifdef CONFIG_IEE
|
||
task_struct_cachep = kmem_cache_create_usercopy("task_struct",
|
||
arch_task_struct_size, align,
|
||
- SLAB_PANIC|SLAB_ACCOUNT,
|
||
+ SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE,
|
||
useroffset, usersize, NULL);
|
||
+ #else
|
||
+ task_struct_cachep =
|
||
+ kmem_cache_create_usercopy("task_struct", arch_task_struct_size,
|
||
+ align, SLAB_PANIC | SLAB_ACCOUNT,
|
||
+ useroffset, usersize, NULL);
|
||
+ #endif
|
||
#endif
|
||
|
||
/* do the arch specific task caches init */
|
||
@@ -1093,8 +1146,8 @@ void __init fork_init(void)
|
||
|
||
set_max_threads(MAX_THREADS);
|
||
|
||
- init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
|
||
- init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
|
||
+ init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads / 2;
|
||
+ init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads / 2;
|
||
init_task.signal->rlim[RLIMIT_SIGPENDING] =
|
||
init_task.signal->rlim[RLIMIT_NPROC];
|
||
|
||
@@ -1107,8 +1160,8 @@ void __init fork_init(void)
|
||
set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, RLIM_INFINITY);
|
||
|
||
#ifdef CONFIG_VMAP_STACK
|
||
- cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
|
||
- NULL, free_vm_stack_cache);
|
||
+ cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache", NULL,
|
||
+ free_vm_stack_cache);
|
||
#endif
|
||
|
||
scs_init();
|
||
@@ -1118,7 +1171,7 @@ void __init fork_init(void)
|
||
}
|
||
|
||
int __weak arch_dup_task_struct(struct task_struct *dst,
|
||
- struct task_struct *src)
|
||
+ struct task_struct *src)
|
||
{
|
||
*dst = *src;
|
||
return 0;
|
||
@@ -1129,14 +1182,14 @@ void set_task_stack_end_magic(struct task_struct *tsk)
|
||
unsigned long *stackend;
|
||
|
||
stackend = end_of_stack(tsk);
|
||
- *stackend = STACK_END_MAGIC; /* for overflow detection */
|
||
+ *stackend = STACK_END_MAGIC; /* for overflow detection */
|
||
}
|
||
|
||
static bool dup_resvd_task_struct(struct task_struct *dst,
|
||
struct task_struct *orig, int node)
|
||
{
|
||
- dst->_resvd = kzalloc_node(sizeof(struct task_struct_resvd),
|
||
- GFP_KERNEL, node);
|
||
+ dst->_resvd = kzalloc_node(sizeof(struct task_struct_resvd), GFP_KERNEL,
|
||
+ node);
|
||
if (!dst->_resvd)
|
||
return false;
|
||
|
||
@@ -1309,7 +1362,7 @@ static void mm_init_uprobes_state(struct mm_struct *mm)
|
||
}
|
||
|
||
static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
|
||
- struct user_namespace *user_ns)
|
||
+ struct user_namespace *user_ns)
|
||
{
|
||
mt_init_flags(&mm->mm_mt, MM_MT_FLAGS);
|
||
mt_set_external_lock(&mm->mm_mt, &mm->mmap_lock);
|
||
@@ -1425,8 +1478,8 @@ EXPORT_SYMBOL_GPL(mmput);
|
||
#ifdef CONFIG_MMU
|
||
static void mmput_async_fn(struct work_struct *work)
|
||
{
|
||
- struct mm_struct *mm = container_of(work, struct mm_struct,
|
||
- async_put_work);
|
||
+ struct mm_struct *mm =
|
||
+ container_of(work, struct mm_struct, async_put_work);
|
||
|
||
__mmput(mm);
|
||
}
|
||
@@ -1602,13 +1655,12 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
|
||
struct mm_struct *mm;
|
||
int err;
|
||
|
||
- err = down_read_killable(&task->signal->exec_update_lock);
|
||
+ err = down_read_killable(&task->signal->exec_update_lock);
|
||
if (err)
|
||
return ERR_PTR(err);
|
||
|
||
mm = get_task_mm(task);
|
||
- if (mm && mm != current->mm &&
|
||
- !ptrace_may_access(task, mode)) {
|
||
+ if (mm && mm != current->mm && !ptrace_may_access(task, mode)) {
|
||
mmput(mm);
|
||
mm = ERR_PTR(-EACCES);
|
||
}
|
||
@@ -1631,7 +1683,7 @@ static void complete_vfork_done(struct task_struct *tsk)
|
||
}
|
||
|
||
static int wait_for_vfork_done(struct task_struct *child,
|
||
- struct completion *vfork)
|
||
+ struct completion *vfork)
|
||
{
|
||
unsigned int state = TASK_UNINTERRUPTIBLE|TASK_KILLABLE|TASK_FREEZABLE;
|
||
int killed;
|
||
@@ -1682,8 +1734,8 @@ static void mm_release(struct task_struct *tsk, struct mm_struct *mm)
|
||
* not set up a proper pointer then tough luck.
|
||
*/
|
||
put_user(0, tsk->clear_child_tid);
|
||
- do_futex(tsk->clear_child_tid, FUTEX_WAKE,
|
||
- 1, NULL, NULL, 0, 0);
|
||
+ do_futex(tsk->clear_child_tid, FUTEX_WAKE, 1, NULL,
|
||
+ NULL, 0, 0);
|
||
}
|
||
tsk->clear_child_tid = NULL;
|
||
}
|
||
@@ -1767,6 +1819,10 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
|
||
#endif
|
||
|
||
tsk->mm = NULL;
|
||
+#ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(tsk, NULL);
|
||
+ iee_set_token_pgd(tsk, NULL);
|
||
+#endif
|
||
tsk->active_mm = NULL;
|
||
|
||
/*
|
||
@@ -1798,6 +1854,10 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
|
||
}
|
||
|
||
tsk->mm = mm;
|
||
+#ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(tsk, mm);
|
||
+ iee_set_token_pgd(tsk, mm->pgd);
|
||
+#endif
|
||
tsk->active_mm = mm;
|
||
sched_mm_cid_fork(tsk);
|
||
return 0;
|
||
@@ -2015,8 +2075,8 @@ static inline void init_task_pid_links(struct task_struct *task)
|
||
INIT_HLIST_NODE(&task->pid_links[type]);
|
||
}
|
||
|
||
-static inline void
|
||
-init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid)
|
||
+static inline void init_task_pid(struct task_struct *task, enum pid_type type,
|
||
+ struct pid *pid)
|
||
{
|
||
if (type == PIDTYPE_PID)
|
||
task->thread_pid = pid;
|
||
@@ -2277,6 +2337,12 @@ static void copy_oom_score_adj(u64 clone_flags, struct task_struct *tsk)
|
||
mutex_unlock(&oom_adj_mutex);
|
||
}
|
||
|
||
+#if defined(CONFIG_KOI) && !defined(CONFIG_IEE)
|
||
+extern s64 koi_offset;
|
||
+extern int koi_add_page_mapping(unsigned long dst, unsigned long src);
|
||
+#endif
|
||
+
|
||
+
|
||
#ifdef CONFIG_RV
|
||
static void rv_task_fork(struct task_struct *p)
|
||
{
|
||
@@ -2309,15 +2375,21 @@ __latent_entropy struct task_struct *copy_process(
|
||
struct file *pidfile = NULL;
|
||
const u64 clone_flags = args->flags;
|
||
struct nsproxy *nsp = current->nsproxy;
|
||
+ #ifdef CONFIG_IEE
|
||
+ gfp_t gfp;
|
||
+ void *pstack;
|
||
+ #endif
|
||
|
||
/*
|
||
* Don't allow sharing the root directory with processes in a different
|
||
* namespace
|
||
*/
|
||
- if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
|
||
+ if ((clone_flags & (CLONE_NEWNS | CLONE_FS)) ==
|
||
+ (CLONE_NEWNS | CLONE_FS))
|
||
return ERR_PTR(-EINVAL);
|
||
|
||
- if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
|
||
+ if ((clone_flags & (CLONE_NEWUSER | CLONE_FS)) ==
|
||
+ (CLONE_NEWUSER | CLONE_FS))
|
||
return ERR_PTR(-EINVAL);
|
||
|
||
/*
|
||
@@ -2342,7 +2414,7 @@ __latent_entropy struct task_struct *copy_process(
|
||
* from creating siblings.
|
||
*/
|
||
if ((clone_flags & CLONE_PARENT) &&
|
||
- current->signal->flags & SIGNAL_UNKILLABLE)
|
||
+ current->signal->flags & SIGNAL_UNKILLABLE)
|
||
return ERR_PTR(-EINVAL);
|
||
|
||
/*
|
||
@@ -2387,6 +2459,15 @@ __latent_entropy struct task_struct *copy_process(
|
||
p = dup_task_struct(current, node);
|
||
if (!p)
|
||
goto fork_out;
|
||
+ #ifdef CONFIG_IEE
|
||
+ // Alloc iee stack.
|
||
+ gfp = GFP_KERNEL;
|
||
+ pstack = (void *)__get_free_pages(gfp, 3);
|
||
+ iee_set_kernel_upage((unsigned long)pstack);
|
||
+ // Init token.
|
||
+ iee_init_token(p, NULL, pstack + PAGE_SIZE * 4);
|
||
+ #endif
|
||
+
|
||
p->flags &= ~PF_KTHREAD;
|
||
if (args->kthread)
|
||
p->flags |= PF_KTHREAD;
|
||
@@ -2408,7 +2489,8 @@ __latent_entropy struct task_struct *copy_process(
|
||
/*
|
||
* Clear TID on mm_release()?
|
||
*/
|
||
- p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? args->child_tid : NULL;
|
||
+ p->clear_child_tid =
|
||
+ (clone_flags & CLONE_CHILD_CLEARTID) ? args->child_tid : NULL;
|
||
|
||
ftrace_graph_init_task(p);
|
||
|
||
@@ -2519,10 +2601,10 @@ __latent_entropy struct task_struct *copy_process(
|
||
#endif
|
||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||
memset(&p->irqtrace, 0, sizeof(p->irqtrace));
|
||
- p->irqtrace.hardirq_disable_ip = _THIS_IP_;
|
||
- p->irqtrace.softirq_enable_ip = _THIS_IP_;
|
||
- p->softirqs_enabled = 1;
|
||
- p->softirq_context = 0;
|
||
+ p->irqtrace.hardirq_disable_ip = _THIS_IP_;
|
||
+ p->irqtrace.softirq_enable_ip = _THIS_IP_;
|
||
+ p->softirqs_enabled = 1;
|
||
+ p->softirq_context = 0;
|
||
#endif
|
||
|
||
p->pagefault_disabled = 0;
|
||
@@ -2535,8 +2617,8 @@ __latent_entropy struct task_struct *copy_process(
|
||
p->blocked_on = NULL; /* not blocked yet */
|
||
#endif
|
||
#ifdef CONFIG_BCACHE
|
||
- p->sequential_io = 0;
|
||
- p->sequential_io_avg = 0;
|
||
+ p->sequential_io = 0;
|
||
+ p->sequential_io_avg = 0;
|
||
#endif
|
||
#ifdef CONFIG_BPF_SYSCALL
|
||
RCU_INIT_POINTER(p->bpf_storage, NULL);
|
||
@@ -2623,7 +2705,7 @@ __latent_entropy struct task_struct *copy_process(
|
||
/*
|
||
* sigaltstack should be cleared when sharing the same VM
|
||
*/
|
||
- if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)
|
||
+ if ((clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM)
|
||
sas_ss_reset(p);
|
||
|
||
/*
|
||
@@ -2702,7 +2784,7 @@ __latent_entropy struct task_struct *copy_process(
|
||
write_lock_irq(&tasklist_lock);
|
||
|
||
/* CLONE_PARENT re-uses the old parent */
|
||
- if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {
|
||
+ if (clone_flags & (CLONE_PARENT | CLONE_THREAD)) {
|
||
p->real_parent = current->real_parent;
|
||
p->parent_exec_id = current->parent_exec_id;
|
||
if (clone_flags & CLONE_THREAD)
|
||
@@ -2766,8 +2848,9 @@ __latent_entropy struct task_struct *copy_process(
|
||
* tasklist_lock with adding child to the process tree
|
||
* for propagate_has_child_subreaper optimization.
|
||
*/
|
||
- p->signal->has_child_subreaper = p->real_parent->signal->has_child_subreaper ||
|
||
- p->real_parent->signal->is_child_subreaper;
|
||
+ p->signal->has_child_subreaper =
|
||
+ p->real_parent->signal->has_child_subreaper ||
|
||
+ p->real_parent->signal->is_child_subreaper;
|
||
list_add_tail(&p->sibling, &p->real_parent->children);
|
||
list_add_tail_rcu(&p->tasks, &init_task.tasks);
|
||
attach_pid(p, PIDTYPE_TGID);
|
||
@@ -2918,8 +3001,8 @@ struct task_struct * __init fork_idle(int cpu)
|
||
*/
|
||
struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
|
||
{
|
||
- unsigned long flags = CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
|
||
- CLONE_IO;
|
||
+ unsigned long flags = CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
|
||
+ CLONE_THREAD | CLONE_IO;
|
||
struct kernel_clone_args args = {
|
||
.flags = ((lower_32_bits(flags) | CLONE_VM |
|
||
CLONE_UNTRACED) & ~CSIGNAL),
|
||
@@ -3083,8 +3166,8 @@ SYSCALL_DEFINE0(fork)
|
||
SYSCALL_DEFINE0(vfork)
|
||
{
|
||
struct kernel_clone_args args = {
|
||
- .flags = CLONE_VFORK | CLONE_VM,
|
||
- .exit_signal = SIGCHLD,
|
||
+ .flags = CLONE_VFORK | CLONE_VM,
|
||
+ .exit_signal = SIGCHLD,
|
||
};
|
||
|
||
return kernel_clone(&args);
|
||
@@ -3094,35 +3177,30 @@ SYSCALL_DEFINE0(vfork)
|
||
#ifdef __ARCH_WANT_SYS_CLONE
|
||
#ifdef CONFIG_CLONE_BACKWARDS
|
||
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
|
||
- int __user *, parent_tidptr,
|
||
- unsigned long, tls,
|
||
- int __user *, child_tidptr)
|
||
+ int __user *, parent_tidptr, unsigned long, tls, int __user *,
|
||
+ child_tidptr)
|
||
#elif defined(CONFIG_CLONE_BACKWARDS2)
|
||
SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
|
||
- int __user *, parent_tidptr,
|
||
- int __user *, child_tidptr,
|
||
- unsigned long, tls)
|
||
-#elif defined(CONFIG_CLONE_BACKWARDS3)
|
||
-SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
|
||
- int, stack_size,
|
||
- int __user *, parent_tidptr,
|
||
- int __user *, child_tidptr,
|
||
+ int __user *, parent_tidptr, int __user *, child_tidptr,
|
||
unsigned long, tls)
|
||
+#elif defined(CONFIG_CLONE_BACKWARDS3)
|
||
+SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp, int,
|
||
+ stack_size, int __user *, parent_tidptr, int __user *,
|
||
+ child_tidptr, unsigned long, tls)
|
||
#else
|
||
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
|
||
- int __user *, parent_tidptr,
|
||
- int __user *, child_tidptr,
|
||
- unsigned long, tls)
|
||
+ int __user *, parent_tidptr, int __user *, child_tidptr,
|
||
+ unsigned long, tls)
|
||
#endif
|
||
{
|
||
struct kernel_clone_args args = {
|
||
- .flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
|
||
- .pidfd = parent_tidptr,
|
||
- .child_tid = child_tidptr,
|
||
- .parent_tid = parent_tidptr,
|
||
- .exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
|
||
- .stack = newsp,
|
||
- .tls = tls,
|
||
+ .flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
|
||
+ .pidfd = parent_tidptr,
|
||
+ .child_tid = child_tidptr,
|
||
+ .parent_tid = parent_tidptr,
|
||
+ .exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
|
||
+ .stack = newsp,
|
||
+ .tls = tls,
|
||
};
|
||
|
||
return kernel_clone(&args);
|
||
@@ -3178,21 +3256,21 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
||
return -EINVAL;
|
||
|
||
*kargs = (struct kernel_clone_args){
|
||
- .flags = args.flags,
|
||
- .pidfd = u64_to_user_ptr(args.pidfd),
|
||
- .child_tid = u64_to_user_ptr(args.child_tid),
|
||
- .parent_tid = u64_to_user_ptr(args.parent_tid),
|
||
- .exit_signal = args.exit_signal,
|
||
- .stack = args.stack,
|
||
- .stack_size = args.stack_size,
|
||
- .tls = args.tls,
|
||
- .set_tid_size = args.set_tid_size,
|
||
- .cgroup = args.cgroup,
|
||
+ .flags = args.flags,
|
||
+ .pidfd = u64_to_user_ptr(args.pidfd),
|
||
+ .child_tid = u64_to_user_ptr(args.child_tid),
|
||
+ .parent_tid = u64_to_user_ptr(args.parent_tid),
|
||
+ .exit_signal = args.exit_signal,
|
||
+ .stack = args.stack,
|
||
+ .stack_size = args.stack_size,
|
||
+ .tls = args.tls,
|
||
+ .set_tid_size = args.set_tid_size,
|
||
+ .cgroup = args.cgroup,
|
||
};
|
||
|
||
if (args.set_tid &&
|
||
- copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
|
||
- (kargs->set_tid_size * sizeof(pid_t))))
|
||
+ copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
|
||
+ (kargs->set_tid_size * sizeof(pid_t))))
|
||
return -EFAULT;
|
||
|
||
kargs->set_tid = kset_tid;
|
||
@@ -3287,7 +3365,8 @@ SYSCALL_DEFINE2(clone3, struct clone_args __user *, uargs, size_t, size)
|
||
}
|
||
#endif
|
||
|
||
-void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data)
|
||
+void walk_process_tree(struct task_struct *top, proc_visitor visitor,
|
||
+ void *data)
|
||
{
|
||
struct task_struct *leader, *parent, *child;
|
||
int res;
|
||
@@ -3295,8 +3374,8 @@ void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data
|
||
read_lock(&tasklist_lock);
|
||
leader = top = top->group_leader;
|
||
down:
|
||
- for_each_thread(leader, parent) {
|
||
- list_for_each_entry(child, &parent->children, sibling) {
|
||
+ for_each_thread (leader, parent) {
|
||
+ list_for_each_entry (child, &parent->children, sibling) {
|
||
res = visitor(child, data);
|
||
if (res) {
|
||
if (res < 0)
|
||
@@ -3304,8 +3383,7 @@ void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data
|
||
leader = child;
|
||
goto down;
|
||
}
|
||
-up:
|
||
- ;
|
||
+ up:;
|
||
}
|
||
}
|
||
|
||
@@ -3382,11 +3460,11 @@ void __init proc_caches_init(void)
|
||
*/
|
||
static int check_unshare_flags(unsigned long unshare_flags)
|
||
{
|
||
- if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
|
||
- CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
|
||
- CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
|
||
- CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP|
|
||
- CLONE_NEWTIME))
|
||
+ if (unshare_flags &
|
||
+ ~(CLONE_THREAD | CLONE_FS | CLONE_NEWNS | CLONE_SIGHAND | CLONE_VM |
|
||
+ CLONE_FILES | CLONE_SYSVSEM | CLONE_NEWUTS | CLONE_NEWIPC |
|
||
+ CLONE_NEWNET | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWCGROUP |
|
||
+ CLONE_NEWTIME))
|
||
return -EINVAL;
|
||
/*
|
||
* Not implemented, but pretend it works if there is nothing
|
||
@@ -3497,7 +3575,7 @@ int ksys_unshare(unsigned long unshare_flags)
|
||
* to a new ipc namespace, the semaphore arrays from the old
|
||
* namespace are unreachable.
|
||
*/
|
||
- if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM))
|
||
+ if (unshare_flags & (CLONE_NEWIPC | CLONE_SYSVSEM))
|
||
do_sysvsem = 1;
|
||
err = unshare_fs(unshare_flags, &new_fs);
|
||
if (err)
|
||
@@ -3508,8 +3586,8 @@ int ksys_unshare(unsigned long unshare_flags)
|
||
err = unshare_userns(unshare_flags, &new_cred);
|
||
if (err)
|
||
goto bad_unshare_cleanup_fd;
|
||
- err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
|
||
- new_cred, new_fs);
|
||
+ err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, new_cred,
|
||
+ new_fs);
|
||
if (err)
|
||
goto bad_unshare_cleanup_cred;
|
||
|
||
@@ -3606,8 +3684,8 @@ int unshare_files(void)
|
||
return 0;
|
||
}
|
||
|
||
-int sysctl_max_threads(struct ctl_table *table, int write,
|
||
- void *buffer, size_t *lenp, loff_t *ppos)
|
||
+int sysctl_max_threads(struct ctl_table *table, int write, void *buffer,
|
||
+ size_t *lenp, loff_t *ppos)
|
||
{
|
||
struct ctl_table t;
|
||
int ret;
|
||
diff --git a/kernel/groups.c b/kernel/groups.c
|
||
index 9b43da22647d..8045812e8a3c 100644
|
||
--- a/kernel/groups.c
|
||
+++ b/kernel/groups.c
|
||
@@ -11,6 +11,9 @@
|
||
#include <linux/user_namespace.h>
|
||
#include <linux/vmalloc.h>
|
||
#include <linux/uaccess.h>
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
|
||
struct group_info *groups_alloc(int gidsetsize)
|
||
{
|
||
@@ -119,7 +122,11 @@ void set_groups(struct cred *new, struct group_info *group_info)
|
||
{
|
||
put_group_info(new->group_info);
|
||
get_group_info(group_info);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_group_info(new,group_info);
|
||
+ #else
|
||
new->group_info = group_info;
|
||
+ #endif
|
||
}
|
||
|
||
EXPORT_SYMBOL(set_groups);
|
||
diff --git a/kernel/kthread.c b/kernel/kthread.c
|
||
index 1eea53050bab..317eac6eb2f2 100644
|
||
--- a/kernel/kthread.c
|
||
+++ b/kernel/kthread.c
|
||
@@ -30,6 +30,10 @@
|
||
#include <linux/sched/isolation.h>
|
||
#include <trace/events/sched.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
|
||
static DEFINE_SPINLOCK(kthread_create_lock);
|
||
static LIST_HEAD(kthread_create_list);
|
||
@@ -1429,6 +1433,10 @@ void kthread_use_mm(struct mm_struct *mm)
|
||
tsk->active_mm = mm;
|
||
tsk->mm = mm;
|
||
membarrier_update_current_mm(mm);
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(tsk, mm);
|
||
+ iee_set_token_pgd(tsk, mm->pgd);
|
||
+ #endif
|
||
switch_mm_irqs_off(active_mm, mm, tsk);
|
||
local_irq_enable();
|
||
task_unlock(tsk);
|
||
@@ -1473,7 +1481,12 @@ void kthread_unuse_mm(struct mm_struct *mm)
|
||
local_irq_disable();
|
||
tsk->mm = NULL;
|
||
membarrier_update_current_mm(NULL);
|
||
+ #ifdef CONFIG_IEE
|
||
+ iee_set_token_mm(tsk, mm);
|
||
+ iee_set_token_pgd(tsk, NULL);
|
||
+ #endif
|
||
mmgrab_lazy_tlb(mm);
|
||
+
|
||
/* active_mm is still 'mm' */
|
||
enter_lazy_tlb(mm, tsk);
|
||
local_irq_enable();
|
||
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
|
||
index f47d8f375946..60c7d365c0e1 100644
|
||
--- a/kernel/smpboot.c
|
||
+++ b/kernel/smpboot.c
|
||
@@ -16,6 +16,10 @@
|
||
#include <linux/kthread.h>
|
||
#include <linux/smpboot.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
#include "smpboot.h"
|
||
|
||
#ifdef CONFIG_SMP
|
||
@@ -57,6 +61,11 @@ static __always_inline void idle_init(unsigned int cpu)
|
||
pr_err("SMP: fork_idle() failed for CPU %u\n", cpu);
|
||
else
|
||
per_cpu(idle_threads, cpu) = tsk;
|
||
+ #ifdef CONFIG_IEE
|
||
+ // Set the secondary __entry_task.
|
||
+ *(struct task_struct **)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]) = tsk;
|
||
+ iee_set_logical_mem_ro((unsigned long)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]));
|
||
+ #endif
|
||
}
|
||
}
|
||
|
||
diff --git a/kernel/sys.c b/kernel/sys.c
|
||
index 44b575990333..fbc47f83af50 100644
|
||
--- a/kernel/sys.c
|
||
+++ b/kernel/sys.c
|
||
@@ -75,6 +75,10 @@
|
||
#include <asm/io.h>
|
||
#include <asm/unistd.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
#include "uid16.h"
|
||
|
||
#ifndef SET_UNALIGN_CTL
|
||
@@ -395,7 +399,11 @@ long __sys_setregid(gid_t rgid, gid_t egid)
|
||
if (gid_eq(old->gid, krgid) ||
|
||
gid_eq(old->egid, krgid) ||
|
||
ns_capable_setid(old->user_ns, CAP_SETGID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_gid(new,krgid);
|
||
+ #else
|
||
new->gid = krgid;
|
||
+ #endif
|
||
else
|
||
goto error;
|
||
}
|
||
@@ -404,15 +412,27 @@ long __sys_setregid(gid_t rgid, gid_t egid)
|
||
gid_eq(old->egid, kegid) ||
|
||
gid_eq(old->sgid, kegid) ||
|
||
ns_capable_setid(old->user_ns, CAP_SETGID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_egid(new,kegid);
|
||
+ #else
|
||
new->egid = kegid;
|
||
+ #endif
|
||
else
|
||
goto error;
|
||
}
|
||
|
||
if (rgid != (gid_t) -1 ||
|
||
(egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_sgid(new,new->egid);
|
||
+ #else
|
||
new->sgid = new->egid;
|
||
+ #endif
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsgid(new,new->egid);
|
||
+ #else
|
||
new->fsgid = new->egid;
|
||
+ #endif
|
||
|
||
retval = security_task_fix_setgid(new, old, LSM_SETID_RE);
|
||
if (retval < 0)
|
||
@@ -454,9 +474,25 @@ long __sys_setgid(gid_t gid)
|
||
|
||
retval = -EPERM;
|
||
if (ns_capable_setid(old->user_ns, CAP_SETGID))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ iee_set_cred_fsgid(new,kgid);
|
||
+ iee_set_cred_sgid(new,kgid);
|
||
+ iee_set_cred_egid(new,kgid);
|
||
+ iee_set_cred_gid(new,kgid);
|
||
+ }
|
||
+ #else
|
||
new->gid = new->egid = new->sgid = new->fsgid = kgid;
|
||
+ #endif
|
||
else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ iee_set_cred_fsgid(new,kgid);
|
||
+ iee_set_cred_egid(new,kgid);
|
||
+ }
|
||
+ #else
|
||
new->egid = new->fsgid = kgid;
|
||
+ #endif
|
||
else
|
||
goto error;
|
||
|
||
@@ -488,7 +524,11 @@ static int set_user(struct cred *new)
|
||
return -EAGAIN;
|
||
|
||
free_uid(new->user);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_user(new,new_user);
|
||
+ #else
|
||
new->user = new_user;
|
||
+ #endif
|
||
return 0;
|
||
}
|
||
|
||
@@ -549,7 +589,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
|
||
|
||
retval = -EPERM;
|
||
if (ruid != (uid_t) -1) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_uid(new,kruid);
|
||
+ #else
|
||
new->uid = kruid;
|
||
+ #endif
|
||
if (!uid_eq(old->uid, kruid) &&
|
||
!uid_eq(old->euid, kruid) &&
|
||
!ns_capable_setid(old->user_ns, CAP_SETUID))
|
||
@@ -557,7 +601,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
|
||
}
|
||
|
||
if (euid != (uid_t) -1) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_euid(new,keuid);
|
||
+ #else
|
||
new->euid = keuid;
|
||
+ #endif
|
||
if (!uid_eq(old->uid, keuid) &&
|
||
!uid_eq(old->euid, keuid) &&
|
||
!uid_eq(old->suid, keuid) &&
|
||
@@ -572,8 +620,16 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
|
||
}
|
||
if (ruid != (uid_t) -1 ||
|
||
(euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_suid(new,new->euid);
|
||
+ #else
|
||
new->suid = new->euid;
|
||
+ #endif
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,new->euid);
|
||
+ #else
|
||
new->fsuid = new->euid;
|
||
+ #endif
|
||
|
||
retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
|
||
if (retval < 0)
|
||
@@ -626,7 +682,12 @@ long __sys_setuid(uid_t uid)
|
||
|
||
retval = -EPERM;
|
||
if (ns_capable_setid(old->user_ns, CAP_SETUID)) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_uid(new,kuid);
|
||
+ iee_set_cred_suid(new,kuid);
|
||
+ #else
|
||
new->suid = new->uid = kuid;
|
||
+ #endif
|
||
if (!uid_eq(kuid, old->uid)) {
|
||
retval = set_user(new);
|
||
if (retval < 0)
|
||
@@ -636,7 +697,12 @@ long __sys_setuid(uid_t uid)
|
||
goto error;
|
||
}
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_euid(new,kuid);
|
||
+ iee_set_cred_fsuid(new,kuid);
|
||
+ #else
|
||
new->fsuid = new->euid = kuid;
|
||
+ #endif
|
||
|
||
retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
|
||
if (retval < 0)
|
||
@@ -710,7 +776,11 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
||
return -ENOMEM;
|
||
|
||
if (ruid != (uid_t) -1) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_uid(new,kruid);
|
||
+ #else
|
||
new->uid = kruid;
|
||
+ #endif
|
||
if (!uid_eq(kruid, old->uid)) {
|
||
retval = set_user(new);
|
||
if (retval < 0)
|
||
@@ -718,10 +788,22 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
||
}
|
||
}
|
||
if (euid != (uid_t) -1)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_euid(new,keuid);
|
||
+ #else
|
||
new->euid = keuid;
|
||
+ #endif
|
||
if (suid != (uid_t) -1)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_suid(new,ksuid);
|
||
+ #else
|
||
new->suid = ksuid;
|
||
+ #endif
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,new->euid);
|
||
+ #else
|
||
new->fsuid = new->euid;
|
||
+ #endif
|
||
|
||
retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
|
||
if (retval < 0)
|
||
@@ -810,12 +892,29 @@ long __sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
|
||
return -ENOMEM;
|
||
|
||
if (rgid != (gid_t) -1)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_gid(new,krgid);
|
||
+ #else
|
||
new->gid = krgid;
|
||
+ #endif
|
||
if (egid != (gid_t) -1)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_egid(new,kegid);
|
||
+ #else
|
||
new->egid = kegid;
|
||
+ #endif
|
||
if (sgid != (gid_t) -1)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_sgid(new,ksgid);
|
||
+ #else
|
||
new->sgid = ksgid;
|
||
+ #endif
|
||
+
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsgid(new,new->egid);
|
||
+ #else
|
||
new->fsgid = new->egid;
|
||
+ #endif
|
||
|
||
retval = security_task_fix_setgid(new, old, LSM_SETID_RES);
|
||
if (retval < 0)
|
||
@@ -882,7 +981,11 @@ long __sys_setfsuid(uid_t uid)
|
||
uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
|
||
ns_capable_setid(old->user_ns, CAP_SETUID)) {
|
||
if (!uid_eq(kuid, old->fsuid)) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,kuid);
|
||
+ #else
|
||
new->fsuid = kuid;
|
||
+ #endif
|
||
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
||
goto change_okay;
|
||
}
|
||
@@ -926,7 +1029,11 @@ long __sys_setfsgid(gid_t gid)
|
||
gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
|
||
ns_capable_setid(old->user_ns, CAP_SETGID)) {
|
||
if (!gid_eq(kgid, old->fsgid)) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsgid(new,kgid);
|
||
+ #else
|
||
new->fsgid = kgid;
|
||
+ #endif
|
||
if (security_task_fix_setgid(new,old,LSM_SETID_FS) == 0)
|
||
goto change_okay;
|
||
}
|
||
diff --git a/kernel/umh.c b/kernel/umh.c
|
||
index 1b13c5d34624..32f5c88e10bf 100644
|
||
--- a/kernel/umh.c
|
||
+++ b/kernel/umh.c
|
||
@@ -32,6 +32,10 @@
|
||
|
||
#include <trace/events/module.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
|
||
static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
|
||
static DEFINE_SPINLOCK(umh_sysctl_lock);
|
||
@@ -91,9 +95,15 @@ static int call_usermodehelper_exec_async(void *data)
|
||
goto out;
|
||
|
||
spin_lock(&umh_sysctl_lock);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_bset(new,cap_intersect(usermodehelper_bset, new->cap_bset));
|
||
+ iee_set_cred_cap_inheritable(new,cap_intersect(usermodehelper_inheritable,
|
||
+ new->cap_inheritable));
|
||
+ #else
|
||
new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
|
||
new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
|
||
new->cap_inheritable);
|
||
+ #endif
|
||
spin_unlock(&umh_sysctl_lock);
|
||
|
||
if (sub_info->init) {
|
||
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
|
||
index 1d8e47bed3f1..9f1921025539 100644
|
||
--- a/kernel/user_namespace.c
|
||
+++ b/kernel/user_namespace.c
|
||
@@ -22,6 +22,10 @@
|
||
#include <linux/bsearch.h>
|
||
#include <linux/sort.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
static struct kmem_cache *user_ns_cachep __read_mostly;
|
||
static DEFINE_MUTEX(userns_state_mutex);
|
||
|
||
@@ -45,6 +49,19 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||
/* Start with the same capabilities as init but useless for doing
|
||
* anything as the capabilities are bound to the new user namespace.
|
||
*/
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_securebits(cred,SECUREBITS_DEFAULT);
|
||
+ iee_set_cred_cap_inheritable(cred,CAP_EMPTY_SET);
|
||
+ iee_set_cred_cap_permitted(cred,CAP_FULL_SET);
|
||
+ iee_set_cred_cap_effective(cred,CAP_FULL_SET);
|
||
+ iee_set_cred_cap_ambient(cred,CAP_EMPTY_SET);
|
||
+ iee_set_cred_cap_bset(cred,CAP_FULL_SET);
|
||
+#ifdef CONFIG_KEYS
|
||
+ key_put(cred->request_key_auth);
|
||
+ iee_set_cred_request_key_auth(cred,NULL);
|
||
+#endif
|
||
+ iee_set_cred_user_ns(cred,user_ns);
|
||
+ #else
|
||
cred->securebits = SECUREBITS_DEFAULT;
|
||
cred->cap_inheritable = CAP_EMPTY_SET;
|
||
cred->cap_permitted = CAP_FULL_SET;
|
||
@@ -57,6 +74,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
|
||
#endif
|
||
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
|
||
cred->user_ns = user_ns;
|
||
+ #endif
|
||
}
|
||
|
||
static unsigned long enforced_nproc_rlimit(void)
|
||
diff --git a/mm/Kconfig b/mm/Kconfig
|
||
index 45d4139c959c..eb9d41768c15 100644
|
||
--- a/mm/Kconfig
|
||
+++ b/mm/Kconfig
|
||
@@ -530,6 +530,18 @@ config NUMA_KEEP_MEMINFO
|
||
config MEMORY_ISOLATION
|
||
bool
|
||
|
||
+# Config for kernel module isolation
|
||
+config KOI
|
||
+ depends on ARM64
|
||
+ depends on ARM64_VA_BITS_48
|
||
+ depends on ARM64_4K_PAGES
|
||
+ def_bool n
|
||
+
|
||
+# Configs for pgtable isolation
|
||
+config PTP
|
||
+ depends on IEE
|
||
+ def_bool y
|
||
+
|
||
# IORESOURCE_SYSTEM_RAM regions in the kernel resource tree that are marked
|
||
# IORESOURCE_EXCLUSIVE cannot be mapped to user space, for example, via
|
||
# /dev/mem.
|
||
diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
|
||
index d25d99cb5f2b..2ea51f559d4e 100644
|
||
--- a/mm/damon/ops-common.c
|
||
+++ b/mm/damon/ops-common.c
|
||
@@ -44,6 +44,7 @@ void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr
|
||
if (!folio)
|
||
return;
|
||
|
||
+
|
||
if (ptep_clear_young_notify(vma, addr, pte))
|
||
folio_set_young(folio);
|
||
|
||
diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
|
||
index 13f0d1192707..60dc95c5b286 100644
|
||
--- a/mm/debug_vm_pgtable.c
|
||
+++ b/mm/debug_vm_pgtable.c
|
||
@@ -452,7 +452,11 @@ static void __init pmd_huge_tests(struct pgtable_debug_args *args)
|
||
* X86 defined pmd_set_huge() verifies that the given
|
||
* PMD is not a populated non-leaf entry.
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pmd(args->pmdp, __pmd(0));
|
||
+ #else
|
||
WRITE_ONCE(*args->pmdp, __pmd(0));
|
||
+ #endif
|
||
WARN_ON(!pmd_set_huge(args->pmdp, __pfn_to_phys(args->fixed_pmd_pfn), args->page_prot));
|
||
WARN_ON(!pmd_clear_huge(args->pmdp));
|
||
pmd = READ_ONCE(*args->pmdp);
|
||
@@ -472,7 +476,11 @@ static void __init pud_huge_tests(struct pgtable_debug_args *args)
|
||
* X86 defined pud_set_huge() verifies that the given
|
||
* PUD is not a populated non-leaf entry.
|
||
*/
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pud(args->pudp, __pud(0));
|
||
+ #else
|
||
WRITE_ONCE(*args->pudp, __pud(0));
|
||
+ #endif
|
||
WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn), args->page_prot));
|
||
WARN_ON(!pud_clear_huge(args->pudp));
|
||
pud = READ_ONCE(*args->pudp);
|
||
@@ -511,7 +519,11 @@ static void __init pud_clear_tests(struct pgtable_debug_args *args)
|
||
|
||
pr_debug("Validating PUD clear\n");
|
||
pud = __pud(pud_val(pud) | RANDOM_ORVALUE);
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pud(args->pudp, pud);
|
||
+ #else
|
||
WRITE_ONCE(*args->pudp, pud);
|
||
+ #endif
|
||
pud_clear(args->pudp);
|
||
pud = READ_ONCE(*args->pudp);
|
||
WARN_ON(!pud_none(pud));
|
||
@@ -548,7 +560,11 @@ static void __init p4d_clear_tests(struct pgtable_debug_args *args)
|
||
|
||
pr_debug("Validating P4D clear\n");
|
||
p4d = __p4d(p4d_val(p4d) | RANDOM_ORVALUE);
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_p4d(args->p4dp, p4d);
|
||
+ #else
|
||
WRITE_ONCE(*args->p4dp, p4d);
|
||
+ #endif
|
||
p4d_clear(args->p4dp);
|
||
p4d = READ_ONCE(*args->p4dp);
|
||
WARN_ON(!p4d_none(p4d));
|
||
@@ -582,7 +598,11 @@ static void __init pgd_clear_tests(struct pgtable_debug_args *args)
|
||
|
||
pr_debug("Validating PGD clear\n");
|
||
pgd = __pgd(pgd_val(pgd) | RANDOM_ORVALUE);
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pgd(args->pgdp, pgd);
|
||
+ #else
|
||
WRITE_ONCE(*args->pgdp, pgd);
|
||
+ #endif
|
||
pgd_clear(args->pgdp);
|
||
pgd = READ_ONCE(*args->pgdp);
|
||
WARN_ON(!pgd_none(pgd));
|
||
@@ -650,7 +670,11 @@ static void __init pmd_clear_tests(struct pgtable_debug_args *args)
|
||
|
||
pr_debug("Validating PMD clear\n");
|
||
pmd = __pmd(pmd_val(pmd) | RANDOM_ORVALUE);
|
||
+ #ifdef CONFIG_PTP
|
||
+ set_pmd(args->pmdp, pmd);
|
||
+ #else
|
||
WRITE_ONCE(*args->pmdp, pmd);
|
||
+ #endif
|
||
pmd_clear(args->pmdp);
|
||
pmd = READ_ONCE(*args->pmdp);
|
||
WARN_ON(!pmd_none(pmd));
|
||
diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c
|
||
index ce06b2884789..a039c7a50ec5 100644
|
||
--- a/mm/early_ioremap.c
|
||
+++ b/mm/early_ioremap.c
|
||
@@ -147,7 +147,11 @@ __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
|
||
if (after_paging_init)
|
||
__late_set_fixmap(idx, phys_addr, prot);
|
||
else
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_set_fixmap_pre_init(idx, phys_addr, prot);
|
||
+ #else
|
||
__early_set_fixmap(idx, phys_addr, prot);
|
||
+ #endif
|
||
phys_addr += PAGE_SIZE;
|
||
--idx;
|
||
--nrpages;
|
||
@@ -199,13 +203,66 @@ void __init early_iounmap(void __iomem *addr, unsigned long size)
|
||
if (after_paging_init)
|
||
__late_clear_fixmap(idx);
|
||
else
|
||
+ #ifdef CONFIG_PTP
|
||
+ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR);
|
||
+ #else
|
||
__early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR);
|
||
+ #endif
|
||
--idx;
|
||
--nrpages;
|
||
}
|
||
prev_map[slot] = NULL;
|
||
}
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+void __init early_iounmap_after_init(void __iomem *addr, unsigned long size)
|
||
+{
|
||
+ unsigned long virt_addr;
|
||
+ unsigned long offset;
|
||
+ unsigned int nrpages;
|
||
+ enum fixed_addresses idx;
|
||
+ int i, slot;
|
||
+
|
||
+ slot = -1;
|
||
+ for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
|
||
+ if (prev_map[i] == addr) {
|
||
+ slot = i;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (WARN(slot < 0, "early_iounmap(%p, %08lx) not found slot\n",
|
||
+ addr, size))
|
||
+ return;
|
||
+
|
||
+ if (WARN(prev_size[slot] != size,
|
||
+ "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
|
||
+ addr, size, slot, prev_size[slot]))
|
||
+ return;
|
||
+
|
||
+ WARN(early_ioremap_debug, "early_iounmap(%p, %08lx) [%d]\n",
|
||
+ addr, size, slot);
|
||
+
|
||
+ virt_addr = (unsigned long)addr;
|
||
+ if (WARN_ON(virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)))
|
||
+ return;
|
||
+
|
||
+ offset = offset_in_page(virt_addr);
|
||
+ nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
|
||
+
|
||
+ idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
|
||
+ while (nrpages > 0) {
|
||
+ if (after_paging_init)
|
||
+ __late_clear_fixmap(idx);
|
||
+ else
|
||
+ __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR);
|
||
+ --idx;
|
||
+ --nrpages;
|
||
+ }
|
||
+ prev_map[slot] = NULL;
|
||
+}
|
||
+#endif
|
||
+
|
||
/* Remap an IO device */
|
||
void __init __iomem *
|
||
early_ioremap(resource_size_t phys_addr, unsigned long size)
|
||
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
|
||
index 763bb25e4f99..80bb2c0abeda 100644
|
||
--- a/mm/huge_memory.c
|
||
+++ b/mm/huge_memory.c
|
||
@@ -39,6 +39,10 @@
|
||
#include <linux/memory-tiers.h>
|
||
#include <linux/compat.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
#include <asm/tlb.h>
|
||
#include <asm/pgalloc.h>
|
||
#include "internal.h"
|
||
@@ -2489,6 +2493,10 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
|
||
unsigned long addr;
|
||
pte_t *pte;
|
||
int i;
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_t *ptep;
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
/*
|
||
* Leave pmd empty until pte is filled note that it is fine to delay
|
||
@@ -2501,7 +2509,14 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
|
||
old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
|
||
|
||
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
||
- pmd_populate(mm, &_pmd, pgtable);
|
||
+ #ifdef CONFIG_PTP
|
||
+ ptep = (pte_t *)page_address(pgtable);
|
||
+ iee_addr = __phys_to_iee(__pa(ptep));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)ptep);
|
||
+ #endif
|
||
+ //pmd_populate(mm, &_pmd, pgtable);
|
||
+ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE);
|
||
|
||
pte = pte_offset_map(&_pmd, haddr);
|
||
VM_BUG_ON(!pte);
|
||
@@ -2534,6 +2549,10 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
|
||
unsigned long addr;
|
||
pte_t *pte;
|
||
int i;
|
||
+ #ifdef CONFIG_PTP
|
||
+ pte_t *ptep;
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
|
||
VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
|
||
@@ -2671,7 +2690,14 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
|
||
* This's critical for some architectures (Power).
|
||
*/
|
||
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
|
||
- pmd_populate(mm, &_pmd, pgtable);
|
||
+ #ifdef CONFIG_PTP
|
||
+ ptep = (pte_t *)page_to_virt(pgtable);
|
||
+ iee_addr = __phys_to_iee(__pa(ptep));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)ptep);
|
||
+ #endif
|
||
+ //pmd_populate(mm, &_pmd, pgtable);
|
||
+ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE);
|
||
|
||
pte = pte_offset_map(&_pmd, haddr);
|
||
VM_BUG_ON(!pte);
|
||
diff --git a/mm/init-mm.c b/mm/init-mm.c
|
||
index 24c809379274..07d060fca6f0 100644
|
||
--- a/mm/init-mm.c
|
||
+++ b/mm/init-mm.c
|
||
@@ -55,3 +55,20 @@ void setup_initial_init_mm(void *start_code, void *end_code,
|
||
init_mm.end_data = (unsigned long)end_data;
|
||
init_mm.brk = (unsigned long)brk;
|
||
}
|
||
+
|
||
+#ifdef CONFIG_KOI
|
||
+/*
|
||
+ * This is used to init ko_mm when creating pgtable for a ko to be isolated
|
||
+ * the ko_mm belongs to a specific ko, pgdp is allocated by koi_pgd_alloc
|
||
+ */
|
||
+void init_ko_mm(struct mm_struct *ko_mm, pgd_t *pgdp) {
|
||
+ ko_mm->mm_rb = RB_ROOT;
|
||
+ ko_mm->pgd = pgdp;
|
||
+ ko_mm->mm_users = (atomic_t)ATOMIC_INIT(2);
|
||
+ ko_mm->mm_count = (atomic_t)ATOMIC_INIT(1);
|
||
+ ko_mm->mmap_lock = (struct rw_semaphore)__RWSEM_INITIALIZER(ko_mm->mmap_lock);
|
||
+ ko_mm->page_table_lock = __SPIN_LOCK_UNLOCKED(ko_mm.page_table_lock);
|
||
+ ko_mm->arg_lock = __SPIN_LOCK_UNLOCKED(ko_mm->arg_lock);
|
||
+ ko_mm->mmlist = (struct list_head)LIST_HEAD_INIT(ko_mm->mmlist);
|
||
+}
|
||
+#endif
|
||
diff --git a/mm/memory.c b/mm/memory.c
|
||
index 4ef917a182f9..28da89a19e30 100644
|
||
--- a/mm/memory.c
|
||
+++ b/mm/memory.c
|
||
@@ -80,6 +80,10 @@
|
||
#include <linux/userswap.h>
|
||
#include <linux/dynamic_pool.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
#include <trace/events/kmem.h>
|
||
|
||
#include <asm/io.h>
|
||
@@ -5872,6 +5876,11 @@ int __pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address)
|
||
|
||
spin_lock(&mm->page_table_lock);
|
||
if (!p4d_present(*p4d)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(new));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+ #endif
|
||
mm_inc_nr_puds(mm);
|
||
smp_wmb(); /* See comment in pmd_install() */
|
||
p4d_populate(mm, p4d, new);
|
||
@@ -5896,6 +5905,11 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
|
||
|
||
ptl = pud_lock(mm, pud);
|
||
if (!pud_present(*pud)) {
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr = __phys_to_iee(__pa(new));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)new);
|
||
+ #endif
|
||
mm_inc_nr_pmds(mm);
|
||
smp_wmb(); /* See comment in pmd_install() */
|
||
pud_populate(mm, pud, new);
|
||
diff --git a/mm/slub.c b/mm/slub.c
|
||
index ee3e32cdb7fd..20a45a7feed5 100644
|
||
--- a/mm/slub.c
|
||
+++ b/mm/slub.c
|
||
@@ -42,6 +42,11 @@
|
||
#include <kunit/test-bug.h>
|
||
#include <linux/sort.h>
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+#include <linux/iee-func.h>
|
||
+#include <asm/iee-access.h>
|
||
+#endif
|
||
+
|
||
#include <linux/debugfs.h>
|
||
#include <trace/events/kmem.h>
|
||
|
||
@@ -317,6 +322,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
|
||
/*
|
||
* Tracking user of a slab.
|
||
*/
|
||
+#ifndef CONFIG_IEE
|
||
#define TRACK_ADDRS_COUNT 16
|
||
struct track {
|
||
unsigned long addr; /* Called from address */
|
||
@@ -329,6 +335,7 @@ struct track {
|
||
};
|
||
|
||
enum track_item { TRACK_ALLOC, TRACK_FREE };
|
||
+#endif
|
||
|
||
#ifdef SLAB_SUPPORTS_SYSFS
|
||
static int sysfs_slab_add(struct kmem_cache *);
|
||
@@ -379,7 +386,9 @@ static struct workqueue_struct *flushwq;
|
||
* freeptr_t represents a SLUB freelist pointer, which might be encoded
|
||
* and not dereferenceable if CONFIG_SLAB_FREELIST_HARDENED is enabled.
|
||
*/
|
||
+#ifndef CONFIG_IEE
|
||
typedef struct { unsigned long v; } freeptr_t;
|
||
+#endif
|
||
|
||
/*
|
||
* Returns freelist pointer (ptr). With hardening, this is obfuscated
|
||
@@ -464,7 +473,14 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
|
||
#endif
|
||
|
||
freeptr_addr = (unsigned long)kasan_reset_tag((void *)freeptr_addr);
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ iee_set_freeptr((freeptr_t *)freeptr_addr, freelist_ptr_encode(s, fp, freeptr_addr));
|
||
+ else
|
||
+ *(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
|
||
+ #else
|
||
*(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
|
||
+ #endif
|
||
}
|
||
|
||
/* Loop over all objects in a slab */
|
||
@@ -809,7 +825,34 @@ static void set_track_update(struct kmem_cache *s, void *object,
|
||
depot_stack_handle_t handle)
|
||
{
|
||
struct track *p = get_track(s, object, alloc);
|
||
+#ifdef CONFIG_IEE
|
||
+ struct track tmp;
|
||
+#endif
|
||
|
||
+#ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ {
|
||
+ tmp = *p;
|
||
+ #ifdef CONFIG_STACKDEPOT
|
||
+ tmp.handle = handle;
|
||
+ #endif
|
||
+ tmp.addr = addr;
|
||
+ tmp.cpu = smp_processor_id();
|
||
+ tmp.pid = current->pid;
|
||
+ tmp.when = jiffies;
|
||
+ iee_set_track(p,&tmp);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ #ifdef CONFIG_STACKDEPOT
|
||
+ p->handle = handle;
|
||
+ #endif
|
||
+ p->addr = addr;
|
||
+ p->cpu = smp_processor_id();
|
||
+ p->pid = current->pid;
|
||
+ p->when = jiffies;
|
||
+ }
|
||
+#else
|
||
#ifdef CONFIG_STACKDEPOT
|
||
p->handle = handle;
|
||
#endif
|
||
@@ -817,6 +860,7 @@ static void set_track_update(struct kmem_cache *s, void *object,
|
||
p->cpu = smp_processor_id();
|
||
p->pid = current->pid;
|
||
p->when = jiffies;
|
||
+#endif
|
||
}
|
||
|
||
static __always_inline void set_track(struct kmem_cache *s, void *object,
|
||
@@ -835,7 +879,14 @@ static void init_tracking(struct kmem_cache *s, void *object)
|
||
return;
|
||
|
||
p = get_track(s, object, TRACK_ALLOC);
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ iee_memset(p, 0, 2*sizeof(struct track));
|
||
+ else
|
||
+ memset(p, 0, 2*sizeof(struct track));
|
||
+ #else
|
||
memset(p, 0, 2*sizeof(struct track));
|
||
+ #endif
|
||
}
|
||
|
||
static void print_track(const char *s, struct track *t, unsigned long pr_time)
|
||
@@ -1045,7 +1096,14 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
|
||
unsigned int poison_size = s->object_size;
|
||
|
||
if (s->flags & SLAB_RED_ZONE) {
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ iee_memset(p - s->red_left_pad, val, s->red_left_pad);
|
||
+ else
|
||
+ memset(p - s->red_left_pad, val, s->red_left_pad);
|
||
+ #else
|
||
memset(p - s->red_left_pad, val, s->red_left_pad);
|
||
+ #endif
|
||
|
||
if (slub_debug_orig_size(s) && val == SLUB_RED_ACTIVE) {
|
||
/*
|
||
@@ -1058,12 +1116,34 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
|
||
}
|
||
|
||
if (s->flags & __OBJECT_POISON) {
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ {
|
||
+ iee_memset(p, POISON_FREE, poison_size - 1);
|
||
+ iee_memset(&p[poison_size - 1], POISON_END, 1);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ memset(p, POISON_FREE, poison_size - 1);
|
||
+ p[poison_size - 1] = POISON_END;
|
||
+ }
|
||
+ #else
|
||
memset(p, POISON_FREE, poison_size - 1);
|
||
p[poison_size - 1] = POISON_END;
|
||
+ #endif
|
||
}
|
||
|
||
- if (s->flags & SLAB_RED_ZONE)
|
||
+ if (s->flags & SLAB_RED_ZONE) {
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ iee_memset(p + poison_size, val, s->inuse - poison_size);
|
||
+ else
|
||
+ memset(p + poison_size, val, s->inuse - poison_size);
|
||
+ #else
|
||
memset(p + poison_size, val, s->inuse - poison_size);
|
||
+ #endif
|
||
+
|
||
+ }
|
||
}
|
||
|
||
static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
|
||
@@ -1433,7 +1513,14 @@ void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr)
|
||
return;
|
||
|
||
metadata_access_enable();
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ iee_memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
|
||
+ else
|
||
+ memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
|
||
+ #else
|
||
memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
|
||
+ #endif
|
||
metadata_access_disable();
|
||
}
|
||
|
||
@@ -2015,6 +2102,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
|
||
void *start, *p, *next;
|
||
int idx;
|
||
bool shuffle;
|
||
+ #ifdef CONFIG_IEE
|
||
+ unsigned int order;
|
||
+ #endif
|
||
|
||
flags &= gfp_allowed_mask;
|
||
|
||
@@ -2029,6 +2119,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
|
||
alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_RECLAIM;
|
||
|
||
slab = alloc_slab_page(alloc_gfp, node, oo);
|
||
+ #ifdef CONFIG_IEE
|
||
+ order = oo_order(oo);
|
||
+ #endif
|
||
if (unlikely(!slab)) {
|
||
oo = s->min;
|
||
alloc_gfp = flags;
|
||
@@ -2037,6 +2130,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
|
||
* Try a lower order alloc if possible
|
||
*/
|
||
slab = alloc_slab_page(alloc_gfp, node, oo);
|
||
+ #ifdef CONFIG_IEE
|
||
+ order = oo_order(oo);
|
||
+ #endif
|
||
if (unlikely(!slab))
|
||
return NULL;
|
||
stat(s, ORDER_FALLBACK);
|
||
@@ -2046,6 +2142,45 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
|
||
slab->inuse = 0;
|
||
slab->frozen = 0;
|
||
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < (0x1 << order); i++)
|
||
+ {
|
||
+ unsigned long iee_addr = __phys_to_iee(page_to_phys(folio_page(slab_folio(slab), i)));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)page_address(folio_page(slab_folio(slab), i)));
|
||
+ }
|
||
+ }
|
||
+
|
||
+ // If the page belongs to a task_struct, alloc token for it and set iee&lm va.
|
||
+ if(strcmp(s->name, "task_struct") == 0)
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < (0x1 << order); i++)
|
||
+ {
|
||
+ void *token_addr = (void *)__phys_to_iee(page_to_phys(folio_page(slab_folio(slab), i)));
|
||
+ // Get lm va of the page.
|
||
+ void *alloc_token = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
|
||
+ iee_set_token_page_valid(token_addr, alloc_token);
|
||
+ set_iee_page_valid(__phys_to_iee(__pa(alloc_token)));
|
||
+ iee_set_logical_mem_ro((unsigned long)alloc_token);
|
||
+ }
|
||
+ }
|
||
+ #else
|
||
+ #ifdef CONFIG_KOI
|
||
+ if (strcmp(s->name, "task_struct") == 0) {
|
||
+ int i;
|
||
+ for (i = 0; i < (0x1 << order); i++) {
|
||
+ void *token_addr = __phys_to_virt(page_to_phys(page + i)) + koi_offset;
|
||
+ void *alloc_token = __get_free_page(GFP_KERNEL | __GFP_ZERO);
|
||
+ koi_add_page_mapping(token_addr, alloc_token);
|
||
+ }
|
||
+ }
|
||
+ #endif
|
||
+ #endif
|
||
+
|
||
account_slab(slab, oo_order(oo), s, flags);
|
||
|
||
slab->slab_cache = s;
|
||
@@ -2098,6 +2233,67 @@ static void __free_slab(struct kmem_cache *s, struct slab *slab)
|
||
__folio_clear_slab(folio);
|
||
mm_account_reclaimed_pages(pages);
|
||
unaccount_slab(slab, order, s);
|
||
+
|
||
+ #ifdef CONFIG_IEE
|
||
+ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < (0x1 << order); i++)
|
||
+ {
|
||
+ unsigned long iee_addr = __phys_to_iee(page_to_phys(folio_page(folio, i)));
|
||
+ set_iee_page_invalid(iee_addr);
|
||
+ iee_set_logical_mem_rw((unsigned long)page_address(folio_page(folio, i)));
|
||
+ }
|
||
+ }
|
||
+ // If the page containing this token is empty, free it and restore iee&lm va.
|
||
+ if(strcmp(s->name, "task_struct") == 0)
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < (0x1 << order); i++)
|
||
+ {
|
||
+ void *token_addr = (void *)__phys_to_iee(page_to_phys(folio_page(folio, i)));
|
||
+ unsigned long flags;
|
||
+ unsigned long res;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile("at s1e1r, %0"::"r"(token_addr));
|
||
+ isb();
|
||
+ res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+ if(!(res & 0x1))
|
||
+ {
|
||
+ // Get lm va of the page.
|
||
+ void *token_page = __va(res & PTE_ADDR_MASK);
|
||
+ iee_set_token_page_invalid(token_addr);
|
||
+ set_iee_page_invalid(__phys_to_iee(__pa(token_page)));
|
||
+ iee_set_logical_mem_rw((unsigned long)token_page);
|
||
+ free_page((unsigned long)token_page);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ #else
|
||
+ #ifdef CONFIG_KOI
|
||
+ if(strcmp(s->name, "task_struct") == 0)
|
||
+ {
|
||
+ int i;
|
||
+ for(i = 0; i < (0x1 << order); i++)
|
||
+ {
|
||
+ void *token_addr = __phys_to_virt(page_to_phys(page + i)) + koi_offset;
|
||
+ unsigned long flags;
|
||
+ local_irq_save(flags);
|
||
+ asm volatile("at s1e1r, %0"::"r"(token_addr));
|
||
+ isb();
|
||
+ unsigned long res = read_sysreg(par_el1);
|
||
+ local_irq_restore(flags);
|
||
+ if(!(res & 0x1))
|
||
+ {
|
||
+ koi_remove_page_mapping(token_addr);
|
||
+ free_page(__va(res & PTE_ADDR_MASK));
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ #endif
|
||
+ #endif
|
||
+
|
||
__free_pages(&folio->page, order);
|
||
}
|
||
|
||
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
|
||
index a2cbe44c48e1..7cf05d293312 100644
|
||
--- a/mm/sparse-vmemmap.c
|
||
+++ b/mm/sparse-vmemmap.c
|
||
@@ -28,6 +28,10 @@
|
||
#include <linux/vmalloc.h>
|
||
#include <linux/sched.h>
|
||
|
||
+#ifdef CONFIG_PTP
|
||
+#include <linux/iee-func.h>
|
||
+#endif
|
||
+
|
||
#include <asm/dma.h>
|
||
#include <asm/pgalloc.h>
|
||
|
||
@@ -146,6 +150,9 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
|
||
struct page *reuse)
|
||
{
|
||
pte_t *pte = pte_offset_kernel(pmd, addr);
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
if (pte_none(ptep_get(pte))) {
|
||
pte_t entry;
|
||
void *p;
|
||
@@ -167,6 +174,11 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
|
||
get_page(reuse);
|
||
p = page_to_virt(reuse);
|
||
}
|
||
+#ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(p));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)p);
|
||
+#endif
|
||
entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL);
|
||
set_pte_at(&init_mm, addr, pte, entry);
|
||
}
|
||
@@ -176,11 +188,20 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
|
||
static void * __meminit vmemmap_alloc_block_zero(unsigned long size, int node)
|
||
{
|
||
void *p = vmemmap_alloc_block(size, node);
|
||
+ #ifdef CONFIG_PTP
|
||
+ unsigned long iee_addr;
|
||
+ #endif
|
||
|
||
if (!p)
|
||
return NULL;
|
||
memset(p, 0, size);
|
||
|
||
+ #ifdef CONFIG_PTP
|
||
+ iee_addr = __phys_to_iee(__pa(p));
|
||
+ set_iee_page_valid(iee_addr);
|
||
+ iee_set_logical_mem_ro((unsigned long)p);
|
||
+ #endif
|
||
+
|
||
return p;
|
||
}
|
||
|
||
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
|
||
index e6058942a084..27a006728009 100644
|
||
--- a/mm/vmalloc.c
|
||
+++ b/mm/vmalloc.c
|
||
@@ -3431,7 +3431,7 @@ static int vmap_pfn_apply(pte_t *pte, unsigned long addr, void *private)
|
||
|
||
if (WARN_ON_ONCE(pfn_valid(pfn)))
|
||
return -EINVAL;
|
||
-
|
||
+
|
||
ptent = pte_mkspecial(pfn_pte(pfn, data->prot));
|
||
set_pte_at(&init_mm, addr, pte, ptent);
|
||
|
||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
|
||
index c42ddd85ff1f..4714b4f2be08 100644
|
||
--- a/net/dns_resolver/dns_key.c
|
||
+++ b/net/dns_resolver/dns_key.c
|
||
@@ -34,6 +34,10 @@
|
||
#include <keys/user-type.h>
|
||
#include "internal.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
MODULE_DESCRIPTION("DNS Resolver");
|
||
MODULE_AUTHOR("Wang Lei");
|
||
MODULE_LICENSE("GPL");
|
||
@@ -365,8 +369,13 @@ static int __init init_dns_resolver(void)
|
||
/* instruct request_key() to use this special keyring as a cache for
|
||
* the results it looks up */
|
||
set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(cred,keyring);
|
||
+ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
|
||
+ #else
|
||
cred->thread_keyring = keyring;
|
||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||
+ #endif
|
||
dns_resolver_cache = cred;
|
||
|
||
kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
|
||
diff --git a/security/commoncap.c b/security/commoncap.c
|
||
index bc0521104197..d7d3b7cc13e8 100644
|
||
--- a/security/commoncap.c
|
||
+++ b/security/commoncap.c
|
||
@@ -26,6 +26,10 @@
|
||
#include <linux/personality.h>
|
||
#include <linux/mnt_idmapping.h>
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
/*
|
||
* If a non-root user executes a setuid-root binary in
|
||
* !secure(SECURE_NOROOT) mode, then we raise capabilities.
|
||
@@ -266,6 +270,15 @@ int cap_capset(struct cred *new,
|
||
if (!cap_issubset(*effective, *permitted))
|
||
return -EPERM;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,*effective);
|
||
+ iee_set_cred_cap_inheritable(new,*inheritable);
|
||
+ iee_set_cred_cap_permitted(new,*permitted);
|
||
+
|
||
+ iee_set_cred_cap_ambient(new,cap_intersect(new->cap_ambient,
|
||
+ cap_intersect(*permitted,
|
||
+ *inheritable)));
|
||
+ #else
|
||
new->cap_effective = *effective;
|
||
new->cap_inheritable = *inheritable;
|
||
new->cap_permitted = *permitted;
|
||
@@ -277,6 +290,7 @@ int cap_capset(struct cred *new,
|
||
new->cap_ambient = cap_intersect(new->cap_ambient,
|
||
cap_intersect(*permitted,
|
||
*inheritable));
|
||
+ #endif
|
||
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
||
return -EINVAL;
|
||
return 0;
|
||
@@ -601,9 +615,16 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||
* pP' = (X & fP) | (pI & fI)
|
||
* The addition of pA' is handled later.
|
||
*/
|
||
+#ifdef CONFIG_CREDP
|
||
+ kernel_cap_t temp = new->cap_permitted;
|
||
+ temp.val = (new->cap_bset.val & caps->permitted.val) |
|
||
+ (new->cap_inheritable.val & caps->inheritable.val);
|
||
+ iee_set_cred_cap_permitted(new,temp);
|
||
+#else
|
||
new->cap_permitted.val =
|
||
(new->cap_bset.val & caps->permitted.val) |
|
||
(new->cap_inheritable.val & caps->inheritable.val);
|
||
+#endif
|
||
|
||
if (caps->permitted.val & ~new->cap_permitted.val)
|
||
/* insufficient to execute correctly */
|
||
@@ -726,7 +747,15 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file,
|
||
int rc = 0;
|
||
struct cpu_vfs_cap_data vcaps;
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = bprm->cred->cap_permitted;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_permitted(bprm->cred, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(bprm->cred->cap_permitted);
|
||
+ #endif
|
||
|
||
if (!file_caps_enabled)
|
||
return 0;
|
||
@@ -757,7 +786,15 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file,
|
||
|
||
out:
|
||
if (rc)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = bprm->cred->cap_permitted;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_permitted(bprm->cred, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(bprm->cred->cap_permitted);
|
||
+ #endif
|
||
|
||
return rc;
|
||
}
|
||
@@ -809,8 +846,13 @@ static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
|
||
*/
|
||
if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
|
||
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_permitted(new,cap_combine(old->cap_bset,
|
||
+ old->cap_inheritable));
|
||
+ #else
|
||
new->cap_permitted = cap_combine(old->cap_bset,
|
||
old->cap_inheritable);
|
||
+ #endif
|
||
}
|
||
/*
|
||
* If only the real uid is 0, we do not set the effective bit.
|
||
@@ -919,34 +961,71 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
|
||
/* downgrade; they get no more than they had, and maybe less */
|
||
if (!ns_capable(new->user_ns, CAP_SETUID) ||
|
||
(bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_euid(new,new->uid);
|
||
+ iee_set_cred_egid(new,new->gid);
|
||
+ #else
|
||
new->euid = new->uid;
|
||
new->egid = new->gid;
|
||
+ #endif
|
||
}
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_permitted(new,cap_intersect(new->cap_permitted,
|
||
+ old->cap_permitted));
|
||
+ #else
|
||
new->cap_permitted = cap_intersect(new->cap_permitted,
|
||
old->cap_permitted);
|
||
+ #endif
|
||
}
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_fsuid(new,new->euid);
|
||
+ iee_set_cred_suid(new,new->euid);
|
||
+ iee_set_cred_fsgid(new,new->egid);
|
||
+ iee_set_cred_sgid(new,new->egid);
|
||
+ #else
|
||
new->suid = new->fsuid = new->euid;
|
||
new->sgid = new->fsgid = new->egid;
|
||
+ #endif
|
||
|
||
/* File caps or setid cancels ambient. */
|
||
if (has_fcap || is_setid)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_ambient;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_ambient(new, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(new->cap_ambient);
|
||
+ #endif
|
||
|
||
/*
|
||
* Now that we've computed pA', update pP' to give:
|
||
* pP' = (X & fP) | (pI & fI) | pA'
|
||
*/
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_permitted(new,cap_combine(new->cap_permitted, new->cap_ambient));
|
||
+ #else
|
||
new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient);
|
||
+ #endif
|
||
|
||
/*
|
||
* Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set,
|
||
* this is the same as pE' = (fE ? pP' : 0) | pA'.
|
||
*/
|
||
if (effective)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,new->cap_permitted);
|
||
+ #else
|
||
new->cap_effective = new->cap_permitted;
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,new->cap_ambient);
|
||
+ #else
|
||
new->cap_effective = new->cap_ambient;
|
||
+ #endif
|
||
|
||
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
||
return -EPERM;
|
||
@@ -957,7 +1036,11 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
|
||
return ret;
|
||
}
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_securebits(new,new->securebits & ~issecure_mask(SECURE_KEEP_CAPS));
|
||
+ #else
|
||
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
||
+ #endif
|
||
|
||
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
||
return -EPERM;
|
||
@@ -1092,8 +1175,21 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
|
||
!uid_eq(new->euid, root_uid) &&
|
||
!uid_eq(new->suid, root_uid))) {
|
||
if (!issecure(SECURE_KEEP_CAPS)) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_permitted;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_permitted(new, tmp_cap);
|
||
+ } while (0);
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_effective;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_effective(new, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(new->cap_permitted);
|
||
cap_clear(new->cap_effective);
|
||
+ #endif
|
||
}
|
||
|
||
/*
|
||
@@ -1101,12 +1197,32 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
|
||
* by exec to drop capabilities. We should make sure that
|
||
* this remains the case.
|
||
*/
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_ambient;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_ambient(new, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(new->cap_ambient);
|
||
+ #endif
|
||
}
|
||
if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_effective;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_effective(new, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(new->cap_effective);
|
||
+ #endif
|
||
if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,new->cap_permitted);
|
||
+ #else
|
||
new->cap_effective = new->cap_permitted;
|
||
+ #endif
|
||
}
|
||
|
||
/**
|
||
@@ -1142,13 +1258,22 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
|
||
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
|
||
kuid_t root_uid = make_kuid(old->user_ns, 0);
|
||
if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,cap_drop_fs_set(new->cap_effective));
|
||
+ #else
|
||
new->cap_effective =
|
||
cap_drop_fs_set(new->cap_effective);
|
||
+ #endif
|
||
|
||
if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_cap_effective(new,cap_raise_fs_set(new->cap_effective,
|
||
+ new->cap_permitted));
|
||
+ #else
|
||
new->cap_effective =
|
||
cap_raise_fs_set(new->cap_effective,
|
||
new->cap_permitted);
|
||
+ #endif
|
||
}
|
||
break;
|
||
|
||
@@ -1243,7 +1368,15 @@ static int cap_prctl_drop(unsigned long cap)
|
||
new = prepare_creds();
|
||
if (!new)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ kernel_cap_t tmp = new->cap_bset;
|
||
+ cap_lower(tmp, cap);
|
||
+ iee_set_cred_cap_bset(new, tmp);
|
||
+ }
|
||
+ #else
|
||
cap_lower(new->cap_bset, cap);
|
||
+ #endif
|
||
return commit_creds(new);
|
||
}
|
||
|
||
@@ -1319,7 +1452,11 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||
new = prepare_creds();
|
||
if (!new)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_securebits(new,arg2);
|
||
+ #else
|
||
new->securebits = arg2;
|
||
+ #endif
|
||
return commit_creds(new);
|
||
|
||
case PR_GET_SECUREBITS:
|
||
@@ -1338,9 +1475,17 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||
if (!new)
|
||
return -ENOMEM;
|
||
if (arg2)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_securebits(new,new->securebits | issecure_mask(SECURE_KEEP_CAPS));
|
||
+ #else
|
||
new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_securebits(new,new->securebits & ~issecure_mask(SECURE_KEEP_CAPS));
|
||
+ #else
|
||
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
||
+ #endif
|
||
return commit_creds(new);
|
||
|
||
case PR_CAP_AMBIENT:
|
||
@@ -1351,7 +1496,15 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||
new = prepare_creds();
|
||
if (!new)
|
||
return -ENOMEM;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ do {
|
||
+ kernel_cap_t tmp_cap = new->cap_ambient;
|
||
+ tmp_cap.val = 0;
|
||
+ iee_set_cred_cap_ambient(new, tmp_cap);
|
||
+ } while (0);
|
||
+ #else
|
||
cap_clear(new->cap_ambient);
|
||
+ #endif
|
||
return commit_creds(new);
|
||
}
|
||
|
||
@@ -1375,9 +1528,25 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||
if (!new)
|
||
return -ENOMEM;
|
||
if (arg2 == PR_CAP_AMBIENT_RAISE)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ kernel_cap_t tmp = new->cap_ambient;
|
||
+ cap_raise(tmp, arg3);
|
||
+ iee_set_cred_cap_ambient(new, tmp);
|
||
+ }
|
||
+ #else
|
||
cap_raise(new->cap_ambient, arg3);
|
||
+ #endif
|
||
else
|
||
+ #ifdef CONFIG_CREDP
|
||
+ {
|
||
+ kernel_cap_t tmp = new->cap_ambient;
|
||
+ cap_lower(tmp, arg3);
|
||
+ iee_set_cred_cap_ambient(new, tmp);
|
||
+ }
|
||
+ #else
|
||
cap_lower(new->cap_ambient, arg3);
|
||
+ #endif
|
||
return commit_creds(new);
|
||
}
|
||
|
||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
|
||
index 19be69fa4d05..6cb164dfc19b 100644
|
||
--- a/security/keys/keyctl.c
|
||
+++ b/security/keys/keyctl.c
|
||
@@ -23,6 +23,9 @@
|
||
#include <linux/uaccess.h>
|
||
#include <keys/request_key_auth-type.h>
|
||
#include "internal.h"
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
|
||
#define KEY_MAX_DESC_SIZE 4096
|
||
|
||
@@ -1155,7 +1158,11 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
||
return -ENOMEM;
|
||
|
||
key_put(new->request_key_auth);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_request_key_auth(new,key_get(key));
|
||
+ #else
|
||
new->request_key_auth = key_get(key);
|
||
+ #endif
|
||
|
||
return commit_creds(new);
|
||
}
|
||
@@ -1432,7 +1439,11 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
|
||
}
|
||
|
||
set:
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_jit_keyring(new,reqkey_defl);
|
||
+ #else
|
||
new->jit_keyring = reqkey_defl;
|
||
+ #endif
|
||
commit_creds(new);
|
||
return old_setting;
|
||
error:
|
||
@@ -1644,9 +1655,17 @@ long keyctl_session_to_parent(void)
|
||
cred = cred_alloc_blank();
|
||
if (!cred)
|
||
goto error_keyring;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ newwork = (struct rcu_head *)(cred->rcu.func);
|
||
+ #else
|
||
newwork = &cred->rcu;
|
||
+ #endif
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_session_keyring(cred,key_ref_to_ptr(keyring_r));
|
||
+ #else
|
||
cred->session_keyring = key_ref_to_ptr(keyring_r);
|
||
+ #endif
|
||
keyring_r = NULL;
|
||
init_task_work(newwork, key_change_session_keyring);
|
||
|
||
@@ -1705,7 +1724,11 @@ long keyctl_session_to_parent(void)
|
||
write_unlock_irq(&tasklist_lock);
|
||
rcu_read_unlock();
|
||
if (oldwork)
|
||
+ #ifdef CONFIG_CREDP
|
||
+ put_cred(*(struct cred **)(oldwork + 1));
|
||
+ #else
|
||
put_cred(container_of(oldwork, struct cred, rcu));
|
||
+ #endif
|
||
if (newwork)
|
||
put_cred(cred);
|
||
return ret;
|
||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
|
||
index b5d5333ab330..aaa2a2347d84 100644
|
||
--- a/security/keys/process_keys.c
|
||
+++ b/security/keys/process_keys.c
|
||
@@ -19,6 +19,10 @@
|
||
#include <keys/request_key_auth-type.h>
|
||
#include "internal.h"
|
||
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
+
|
||
/* Session keyring create vs join semaphore */
|
||
static DEFINE_MUTEX(key_session_mutex);
|
||
|
||
@@ -232,7 +236,11 @@ int install_thread_keyring_to_cred(struct cred *new)
|
||
if (IS_ERR(keyring))
|
||
return PTR_ERR(keyring);
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_thread_keyring(new,keyring);
|
||
+ #else
|
||
new->thread_keyring = keyring;
|
||
+ #endif
|
||
return 0;
|
||
}
|
||
|
||
@@ -279,7 +287,11 @@ int install_process_keyring_to_cred(struct cred *new)
|
||
if (IS_ERR(keyring))
|
||
return PTR_ERR(keyring);
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_process_keyring(new,keyring);
|
||
+ #else
|
||
new->process_keyring = keyring;
|
||
+ #endif
|
||
return 0;
|
||
}
|
||
|
||
@@ -338,7 +350,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
||
|
||
/* install the keyring */
|
||
old = cred->session_keyring;
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_session_keyring(cred,keyring);
|
||
+ #else
|
||
cred->session_keyring = keyring;
|
||
+ #endif
|
||
|
||
if (old)
|
||
key_put(old);
|
||
@@ -911,7 +927,11 @@ long join_session_keyring(const char *name)
|
||
void key_change_session_keyring(struct callback_head *twork)
|
||
{
|
||
const struct cred *old = current_cred();
|
||
+ #ifdef CONFIG_CREDP
|
||
+ struct cred *new = *(struct cred **)(twork + 1);
|
||
+ #else
|
||
struct cred *new = container_of(twork, struct cred, rcu);
|
||
+ #endif
|
||
|
||
if (unlikely(current->flags & PF_EXITING)) {
|
||
put_cred(new);
|
||
@@ -925,6 +945,38 @@ void key_change_session_keyring(struct callback_head *twork)
|
||
return;
|
||
}
|
||
|
||
+ /* If get_ucounts fails more bits are needed in the refcount */
|
||
+ if (unlikely(!get_ucounts(old->ucounts))) {
|
||
+ WARN_ONCE(1, "In %s get_ucounts failed\n", __func__);
|
||
+ put_cred(new);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_uid(new,old-> uid);
|
||
+ iee_set_cred_euid(new,old-> euid);
|
||
+ iee_set_cred_suid(new,old-> suid);
|
||
+ iee_set_cred_fsuid(new,old->fsuid);
|
||
+ iee_set_cred_gid(new,old-> gid);
|
||
+ iee_set_cred_egid(new,old-> egid);
|
||
+ iee_set_cred_sgid(new,old-> sgid);
|
||
+ iee_set_cred_fsgid(new,old->fsgid);
|
||
+ iee_set_cred_user(new,get_uid(old->user));
|
||
+ iee_set_cred_ucounts(new, old->ucounts);
|
||
+ iee_set_cred_user_ns(new,get_user_ns(old->user_ns));
|
||
+ iee_set_cred_group_info(new,get_group_info(old->group_info));
|
||
+
|
||
+ iee_set_cred_securebits(new,old->securebits);
|
||
+ iee_set_cred_cap_inheritable(new,old->cap_inheritable);
|
||
+ iee_set_cred_cap_permitted(new,old->cap_permitted);
|
||
+ iee_set_cred_cap_effective(new,old->cap_effective);
|
||
+ iee_set_cred_cap_ambient(new,old->cap_ambient);
|
||
+ iee_set_cred_cap_bset(new,old->cap_bset);
|
||
+
|
||
+ iee_set_cred_jit_keyring(new,old->jit_keyring);
|
||
+ iee_set_cred_thread_keyring(new,key_get(old->thread_keyring));
|
||
+ iee_set_cred_process_keyring(new,key_get(old->process_keyring));
|
||
+ #else
|
||
new-> uid = old-> uid;
|
||
new-> euid = old-> euid;
|
||
new-> suid = old-> suid;
|
||
@@ -948,6 +1000,7 @@ void key_change_session_keyring(struct callback_head *twork)
|
||
new->jit_keyring = old->jit_keyring;
|
||
new->thread_keyring = key_get(old->thread_keyring);
|
||
new->process_keyring = key_get(old->process_keyring);
|
||
+ #endif
|
||
|
||
security_transfer_creds(new, old);
|
||
|
||
diff --git a/security/security.c b/security/security.c
|
||
index 407b51719f79..74ffd7ea3f37 100644
|
||
--- a/security/security.c
|
||
+++ b/security/security.c
|
||
@@ -30,6 +30,9 @@
|
||
#include <linux/string.h>
|
||
#include <linux/msg.h>
|
||
#include <net/flow.h>
|
||
+#ifdef CONFIG_CREDP
|
||
+#include <asm/iee-cred.h>
|
||
+#endif
|
||
|
||
/* How many LSMs were built into the kernel? */
|
||
#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
|
||
@@ -570,11 +573,19 @@ EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
|
||
static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
|
||
{
|
||
if (blob_sizes.lbs_cred == 0) {
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_security(cred,NULL);
|
||
+ #else
|
||
cred->security = NULL;
|
||
+ #endif
|
||
return 0;
|
||
}
|
||
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_security(cred,kzalloc(blob_sizes.lbs_cred, gfp));
|
||
+ #else
|
||
cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
|
||
+ #endif
|
||
if (cred->security == NULL)
|
||
return -ENOMEM;
|
||
return 0;
|
||
@@ -2950,7 +2961,11 @@ void security_cred_free(struct cred *cred)
|
||
call_void_hook(cred_free, cred);
|
||
|
||
kfree(cred->security);
|
||
+ #ifdef CONFIG_CREDP
|
||
+ iee_set_cred_security(cred,NULL);
|
||
+ #else
|
||
cred->security = NULL;
|
||
+ #endif
|
||
}
|
||
|
||
/**
|
||
--
|
||
2.34.1
|
||
|