powerpc updates for 6.3

- Support for configuring secure boot with user-defined keys on PowerVM LPARs.
 
  - Simplify the replay of soft-masked IRQs by making it non-recursive.
 
  - Add support for KCSAN on 64-bit Book3S.
 
  - Improvements to the API & code which interacts with RTAS (pseries firmware).
 
  - Change 32-bit powermac to assign PCI bus numbers per domain by default.
 
  - Some improvements to the 32-bit BPF JIT.
 
  - Various other small features and fixes.
 
 Thanks to: Anders Roxell, Andrew Donnellan, Andrew Jeffery, Benjamin Gray, Christophe
 Leroy, Frederic Barrat, Ganesh Goudar, Geoff Levand, Greg Kroah-Hartman, Jan-Benedict
 Glaw, Josh Poimboeuf, Kajol Jain, Laurent Dufour, Mahesh Salgaonkar, Mathieu Desnoyers,
 Mimi Zohar, Murphy Zhou, Nathan Chancellor, Nathan Lynch, Nayna Jain, Nicholas Piggin,
 Pali Rohár, Petr Mladek, Rohan McLure, Russell Currey, Sachin Sant, Sathvika Vasireddy,
 Sourabh Jain, Stefan Berger, Stephen Rothwell, Sudhakar Kuppusamy.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAmP4GnkTHG1wZUBlbGxl
 cm1hbi5pZC5hdQAKCRBR6+o8yOGlgEnlEAC9UoE9JM853o9ZzpOJDrbYknHsRQad
 ztQJ9xu5qjkFHHryTmWKYdiAtNDFbcfn7+1aoc5FXrIb6BOfvBo/uRFw6P501Qwv
 Fg0MQyWUnT5WrI7+rBE2q+1+FaHBNKLycLNRSh5JpXtuKe2ubQfiFD80tarBnEnU
 6I4bqXd+xjDtnqtpfiYnil/kdZTu/MzntdkmCne6fMkflgEQFU9EVQEnnE+imqFa
 6BuCwITvZ+NyaaU+cYMeGZT7aoz9PAwkksgTxXW2gQbTIApX9WX4kYU/vbW4aHts
 0bpzMmIbSbAklYIu2PQQhSU0bLfKJ+xly8E8tozHgRX6hrFlqvtmD/T5LHTBD11f
 FFzKb0NUCD8qTIy6Hn0M1tj5egLpxxzATPe/kVTkxxqTlZrzdSEaqzft6syyJHJd
 ueo0QN53AUyBaVMtxLbnB/U/8Vnz6rLqY+8dLKzXhjYjoPJqOZh/Qlc1Tk3syPwf
 E2j4H6wFqGMTOGi453Pijkpj3qpNkNT79FG5DmClcQLJxD/EXDyffLZITrkzQa0S
 FEkcMzz/Hn9Hkf7ZuNo4DN6ss6IF0vlxoi7GNr+MRR53/aVQJUDc8z24c4ICl/3w
 20ETk57XMVJzP++Hb+yn16JyAawfQOOlckBRZ2O8W5YYVoes45hxDQxVoh8EII69
 hb3KOGYEqF5wyA==
 =ECNb
 -----END PGP SIGNATURE-----

Merge tag 'powerpc-6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc updates from Michael Ellerman:

 - Support for configuring secure boot with user-defined keys on PowerVM
   LPARs

 - Simplify the replay of soft-masked IRQs by making it non-recursive

 - Add support for KCSAN on 64-bit Book3S

 - Improvements to the API & code which interacts with RTAS (pseries
   firmware)

 - Change 32-bit powermac to assign PCI bus numbers per domain by
   default

 - Some improvements to the 32-bit BPF JIT

 - Various other small features and fixes

Thanks to Anders Roxell, Andrew Donnellan, Andrew Jeffery, Benjamin
Gray, Christophe Leroy, Frederic Barrat, Ganesh Goudar, Geoff Levand,
Greg Kroah-Hartman, Jan-Benedict Glaw, Josh Poimboeuf, Kajol Jain,
Laurent Dufour, Mahesh Salgaonkar, Mathieu Desnoyers, Mimi Zohar, Murphy
Zhou, Nathan Chancellor, Nathan Lynch, Nayna Jain, Nicholas Piggin, Pali
Rohár, Petr Mladek, Rohan McLure, Russell Currey, Sachin Sant, Sathvika
Vasireddy, Sourabh Jain, Stefan Berger, Stephen Rothwell, and Sudhakar
Kuppusamy.

* tag 'powerpc-6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (114 commits)
  powerpc/pseries: Avoid hcall in plpks_is_available() on non-pseries
  powerpc: dts: turris1x.dts: Set lower priority for CPLD syscon-reboot
  powerpc/e500: Add missing prototype for 'relocate_init'
  powerpc/64: Fix unannotated intra-function call warning
  powerpc/epapr: Don't use wrteei on non booke
  powerpc: Pass correct CPU reference to assembler
  powerpc/mm: Rearrange if-else block to avoid clang warning
  powerpc/nohash: Fix build with llvm-as
  powerpc/nohash: Fix build error with binutils >= 2.38
  powerpc/pseries: Fix endianness issue when parsing PLPKS secvar flags
  macintosh: windfarm: Use unsigned type for 1-bit bitfields
  powerpc/kexec_file: print error string on usable memory property update failure
  powerpc/machdep: warn when machine_is() used too early
  powerpc/64: Replace -mcpu=e500mc64 by -mcpu=e5500
  powerpc/eeh: Set channel state after notifying the drivers
  selftests/powerpc: Fix incorrect kernel headers search path
  powerpc/rtas: arch-wide function token lookup conversions
  powerpc/rtas: introduce rtas_function_token() API
  powerpc/pseries/lpar: convert to papr_sysparm API
  powerpc/pseries/hv-24x7: convert to papr_sysparm API
  ...
This commit is contained in:
Linus Torvalds 2023-02-25 11:00:06 -08:00
commit d0a32f5520
113 changed files with 3856 additions and 1588 deletions

View File

@ -18,6 +18,14 @@ Description: A string indicating which backend is in use by the firmware.
This determines the format of the variable and the accepted
format of variable updates.
On powernv/OPAL, this value is provided by the OPAL firmware
and is expected to be "ibm,edk2-compat-v1".
On pseries/PLPKS, this is generated by the kernel based on the
version number in the SB_VERSION variable in the keystore, and
has the form "ibm,plpks-sb-v<version>", or
"ibm,plpks-sb-unknown" if there is no SB_VERSION variable.
What: /sys/firmware/secvar/vars/<variable name>
Date: August 2019
Contact: Nayna Jain <nayna@linux.ibm.com>
@ -34,7 +42,7 @@ Description: An integer representation of the size of the content of the
What: /sys/firmware/secvar/vars/<variable_name>/data
Date: August 2019
Contact: Nayna Jain h<nayna@linux.ibm.com>
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: A read-only file containing the value of the variable. The size
of the file represents the maximum size of the variable data.
@ -44,3 +52,68 @@ Contact: Nayna Jain <nayna@linux.ibm.com>
Description: A write-only file that is used to submit the new value for the
variable. The size of the file represents the maximum size of
the variable data that can be written.
What: /sys/firmware/secvar/config
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: This optional directory contains read-only config attributes as
defined by the secure variable implementation. All data is in
ASCII format. The directory is only created if the backing
implementation provides variables to populate it, which at
present is only PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/version
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Config version as reported by the hypervisor in ASCII decimal
format.
Currently only provided by PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/max_object_size
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Maximum allowed size of objects in the keystore in bytes,
represented in ASCII decimal format.
This is not necessarily the same as the max size that can be
written to an update file as writes can contain more than
object data, you should use the size of the update file for
that purpose.
Currently only provided by PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/total_size
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Total size of the PLPKS in bytes, represented in ASCII decimal
format.
Currently only provided by PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/used_space
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Current space consumed by the key store, in bytes, represented
in ASCII decimal format.
Currently only provided by PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/supported_policies
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Bitmask of supported policy flags by the hypervisor,
represented as an 8 byte hexadecimal ASCII string. Consult the
hypervisor documentation for what these flags are.
Currently only provided by PLPKS on the pseries platform.
What: /sys/firmware/secvar/config/signed_update_algorithms
Date: February 2023
Contact: Nayna Jain <nayna@linux.ibm.com>
Description: Bitmask of flags indicating which algorithms the hypervisor
supports for signed update of objects, represented as a 16 byte
hexadecimal ASCII string. Consult the hypervisor documentation
for what these flags mean.
Currently only provided by PLPKS on the pseries platform.

View File

@ -197,6 +197,7 @@ config PPC
select HAVE_ARCH_KASAN if PPC_RADIX_MMU
select HAVE_ARCH_KASAN if PPC_BOOK3E_64
select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN
select HAVE_ARCH_KCSAN if PPC_BOOK3S_64
select HAVE_ARCH_KFENCE if ARCH_SUPPORTS_DEBUG_PAGEALLOC
select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
select HAVE_ARCH_KGDB
@ -206,7 +207,7 @@ config PPC
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_ASM_MODVERSIONS
select HAVE_CONTEXT_TRACKING_USER if PPC64
select HAVE_CONTEXT_TRACKING_USER
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_KMEMLEAK
select HAVE_DEBUG_STACKOVERFLOW
@ -256,6 +257,7 @@ config PPC
select HAVE_STATIC_CALL if PPC32
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_VIRT_CPU_ACCOUNTING_GEN
select HUGETLB_PAGE_SIZE_VARIABLE if PPC_BOOK3S_64 && HUGETLB_PAGE
select IOMMU_HELPER if PPC64
select IRQ_DOMAIN
@ -387,10 +389,22 @@ config PPC_DCR
depends on PPC_DCR_NATIVE || PPC_DCR_MMIO
default y
config PPC_PCI_OF_BUS_MAP
bool "Use pci_to_OF_bus_map (deprecated)"
depends on PPC32
depends on PPC_PMAC || PPC_CHRP
help
This option uses pci_to_OF_bus_map to map OF nodes to PCI devices, which
restricts the system to only having 256 PCI buses. On CHRP it also causes
the "pci-OF-bus-map" property to be created in the device tree.
If unsure, say "N".
config PPC_PCI_BUS_NUM_DOMAIN_DEPENDENT
depends on PPC32
depends on !PPC_PMAC && !PPC_CHRP
depends on !PPC_PCI_OF_BUS_MAP
bool "Assign PCI bus numbers from zero individually for each PCI domain"
default y
help
By default on PPC32 were PCI bus numbers unique across all PCI domains.
So system could have only 256 PCI buses independently of available
@ -1028,6 +1042,7 @@ config PPC_SECURE_BOOT
depends on PPC_POWERNV || PPC_PSERIES
depends on IMA_ARCH_POLICY
imply IMA_SECURE_AND_OR_TRUSTED_BOOT
select PSERIES_PLPKS if PPC_PSERIES
help
Systems with firmware secure boot enabled need to define security
policies to extend secure boot to the OS. This config allows a user

View File

@ -146,19 +146,6 @@ CFLAGS-$(CONFIG_PPC32) += $(call cc-option, $(MULTIPLEWORD))
CFLAGS-$(CONFIG_PPC32) += $(call cc-option,-mno-readonly-in-sdata)
ifdef CONFIG_PPC_BOOK3S_64
ifdef CONFIG_CPU_LITTLE_ENDIAN
CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=power8
else
CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=power4
endif
CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power10, \
$(call cc-option,-mtune=power9, \
$(call cc-option,-mtune=power8)))
else ifdef CONFIG_PPC_BOOK3E_64
CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64
endif
ifdef CONFIG_FUNCTION_TRACER
CC_FLAGS_FTRACE := -pg
ifdef CONFIG_MPROFILE_KERNEL
@ -166,11 +153,12 @@ CC_FLAGS_FTRACE += -mprofile-kernel
endif
endif
CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU))
AFLAGS-$(CONFIG_TARGET_CPU_BOOL) += $(call cc-option,-mcpu=$(CONFIG_TARGET_CPU))
CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += -mcpu=$(CONFIG_TARGET_CPU)
AFLAGS-$(CONFIG_TARGET_CPU_BOOL) += -mcpu=$(CONFIG_TARGET_CPU)
CFLAGS-$(CONFIG_E5500_CPU) += $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
CFLAGS-$(CONFIG_POWERPC64_CPU) += $(call cc-option,-mtune=power10, \
$(call cc-option,-mtune=power9, \
$(call cc-option,-mtune=power8)))
asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1)
@ -213,10 +201,7 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
# often slow when they are implemented at all
KBUILD_CFLAGS += $(call cc-option,-mno-string)
cpu-as-$(CONFIG_40x) += -Wa,-m405
cpu-as-$(CONFIG_44x) += -Wa,-m440
cpu-as-$(CONFIG_ALTIVEC) += $(call as-option,-Wa$(comma)-maltivec)
cpu-as-$(CONFIG_PPC_E500) += -Wa,-me500
# When using '-many -mpower4' gas will first try and find a matching power4
# mnemonic and failing that it will allow any valid mnemonic that GAS knows
@ -224,7 +209,6 @@ cpu-as-$(CONFIG_PPC_E500) += -Wa,-me500
# LLVM IAS doesn't understand either flag: https://github.com/ClangBuiltLinux/linux/issues/675
# but LLVM IAS only supports ISA >= 2.06 for Book3S 64 anyway...
cpu-as-$(CONFIG_PPC_BOOK3S_64) += $(call as-option,-Wa$(comma)-mpower4) $(call as-option,-Wa$(comma)-many)
cpu-as-$(CONFIG_PPC_E500MC) += $(call as-option,-Wa$(comma)-me500mc)
KBUILD_AFLAGS += $(cpu-as-y)
KBUILD_CFLAGS += $(cpu-as-y)

View File

@ -39,13 +39,19 @@ BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
$(LINUXINCLUDE)
ifdef CONFIG_PPC64_BOOT_WRAPPER
ifdef CONFIG_CPU_LITTLE_ENDIAN
BOOTCFLAGS += -m64 -mcpu=powerpc64le
BOOTCFLAGS += -m64
else
BOOTCFLAGS += -m64 -mcpu=powerpc64
BOOTCFLAGS += -m32
endif
ifdef CONFIG_TARGET_CPU_BOOL
BOOTCFLAGS += -mcpu=$(CONFIG_TARGET_CPU)
else ifdef CONFIG_PPC64_BOOT_WRAPPER
ifdef CONFIG_CPU_LITTLE_ENDIAN
BOOTCFLAGS += -mcpu=powerpc64le
else
BOOTCFLAGS += -m32 -mcpu=powerpc
BOOTCFLAGS += -mcpu=powerpc64
endif
endif
BOOTCFLAGS += -isystem $(shell $(BOOTCC) -print-file-name=include)

View File

@ -367,11 +367,34 @@
};
reboot@d {
/*
* CPLD firmware which manages system reset and
* watchdog registers has bugs. It does not
* autoclear system reset register after change
* and watchdog ignores reset line on immediate
* succeeding reset cycle triggered by watchdog.
* These bugs have to be workarounded in U-Boot
* bootloader. So use system reset via syscon as
* a last resort because older U-Boot versions
* do not have workaround for watchdog.
*
* Reset method via rstcr's global-utilities
* (the preferred one) has priority level 128,
* watchdog has priority level 0 and default
* syscon-reboot priority level is 192.
*
* So define syscon-reboot with custom priority
* level 64 (between rstcr and watchdog) because
* rstcr should stay as default preferred reset
* method and reset via watchdog is more broken
* than system reset via syscon.
*/
compatible = "syscon-reboot";
reg = <0x0d 0x01>;
offset = <0x0d>;
mask = <0x01>;
value = <0x01>;
priority = <64>;
};
led-controller@13 {

View File

@ -1,8 +1,3 @@
CONFIG_PPC64=y
CONFIG_CELL_CPU=y
CONFIG_ALTIVEC=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_HIGH_RES_TIMERS=y
@ -10,11 +5,12 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
# CONFIG_PERF_EVENTS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PPC64=y
CONFIG_CELL_CPU=y
CONFIG_ALTIVEC=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
# CONFIG_PPC_POWERNV is not set
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_PMAC is not set
@ -27,17 +23,20 @@ CONFIG_PS3_FLASH=y
CONFIG_PS3_VRAM=m
CONFIG_PS3_LPM=m
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=y
CONFIG_KEXEC=y
CONFIG_PPC_4K_PAGES=y
# CONFIG_SPARSEMEM_VMEMMAP is not set
# CONFIG_COMPACTION is not set
CONFIG_SCHED_SMT=y
CONFIG_PM=y
CONFIG_PM_DEBUG=y
# CONFIG_SECCOMP is not set
# CONFIG_PCI is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_BINFMT_MISC=y
CONFIG_SLAB=y
# CONFIG_COMPAT_BRK is not set
# CONFIG_SPARSEMEM_VMEMMAP is not set
# CONFIG_COMPACTION is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@ -87,7 +86,6 @@ CONFIG_USB_USBNET=m
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
CONFIG_INPUT_FF_MEMLESS=m
CONFIG_INPUT_JOYDEV=m
CONFIG_INPUT_EVDEV=m
# CONFIG_INPUT_KEYBOARD is not set
@ -110,13 +108,10 @@ CONFIG_SND=m
# CONFIG_SND_DRIVERS is not set
CONFIG_SND_USB_AUDIO=m
CONFIG_HIDRAW=y
CONFIG_HID_APPLE=m
CONFIG_HID_BELKIN=m
CONFIG_HID_CHERRY=m
CONFIG_HID_EZKEY=m
CONFIG_HID_TWINHAN=m
CONFIG_HID_LOGITECH=m
CONFIG_HID_LOGITECH_DJ=m
CONFIG_HID_MICROSOFT=m
CONFIG_HID_SUNPLUS=m
CONFIG_HID_SMARTJOYPLUS=m
@ -151,8 +146,12 @@ CONFIG_CIFS=m
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRC_CCITT=m
CONFIG_CRC_T10DIF=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_MEMORY_INIT=y
@ -163,7 +162,3 @@ CONFIG_DEBUG_LOCKDEP=y
CONFIG_DEBUG_LIST=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_LZO=m
CONFIG_PRINTK_TIME=y

View File

@ -113,9 +113,7 @@ FUNC_START(CRC_FUNCTION_NAME)
#endif
#ifdef BYTESWAP_DATA
addis r3,r2,.byteswap_constant@toc@ha
addi r3,r3,.byteswap_constant@toc@l
LOAD_REG_ADDR(r3, .byteswap_constant)
lvx byteswap,0,r3
addi r3,r3,16
#endif
@ -150,8 +148,7 @@ FUNC_START(CRC_FUNCTION_NAME)
addi r7,r7,-1
mtctr r7
addis r3,r2,.constants@toc@ha
addi r3,r3,.constants@toc@l
LOAD_REG_ADDR(r3, .constants)
/* Find the start of our constants */
add r3,r3,r8
@ -506,8 +503,7 @@ FUNC_START(CRC_FUNCTION_NAME)
.Lbarrett_reduction:
/* Barrett constants */
addis r3,r2,.barrett_constants@toc@ha
addi r3,r3,.barrett_constants@toc@l
LOAD_REG_ADDR(r3, .barrett_constants)
lvx const1,0,r3
lvx const2,off16,r3
@ -610,8 +606,7 @@ FUNC_START(CRC_FUNCTION_NAME)
cmpdi r5,0
beq .Lzero
addis r3,r2,.short_constants@toc@ha
addi r3,r3,.short_constants@toc@l
LOAD_REG_ADDR(r3, .short_constants)
/* Calculate where in the constant table we need to start */
subfic r6,r5,256

View File

@ -35,9 +35,9 @@
* However, on CPUs that don't support lwsync, lwsync actually maps to a
* heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
*/
#define mb() __asm__ __volatile__ ("sync" : : : "memory")
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
#define __mb() __asm__ __volatile__ ("sync" : : : "memory")
#define __rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define __wmb() __asm__ __volatile__ ("sync" : : : "memory")
/* The sub-arch has lwsync */
#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_E500MC)
@ -51,12 +51,12 @@
/* clang defines this macro for a builtin, which will not work with runtime patching */
#undef __lwsync
#define __lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
#define dma_rmb() __lwsync()
#define dma_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
#define __dma_rmb() __lwsync()
#define __dma_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
#define __smp_lwsync() __lwsync()
#define __smp_mb() mb()
#define __smp_mb() __mb()
#define __smp_rmb() __lwsync()
#define __smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")

View File

@ -335,6 +335,7 @@
#define H_RPT_INVALIDATE 0x448
#define H_SCM_FLUSH 0x44C
#define H_GET_ENERGY_SCALE_INFO 0x450
#define H_PKS_SIGNED_UPDATE 0x454
#define H_WATCHDOG 0x45C
#define MAX_HCALL_OPCODE H_WATCHDOG

View File

@ -36,15 +36,17 @@
#define PACA_IRQ_DEC 0x08 /* Or FIT */
#define PACA_IRQ_HMI 0x10
#define PACA_IRQ_PMI 0x20
#define PACA_IRQ_REPLAYING 0x40
/*
* Some soft-masked interrupts must be hard masked until they are replayed
* (e.g., because the soft-masked handler does not clear the exception).
* Interrupt replay itself must remain hard masked too.
*/
#ifdef CONFIG_PPC_BOOK3S
#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE|PACA_IRQ_PMI)
#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE|PACA_IRQ_PMI|PACA_IRQ_REPLAYING)
#else
#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE)
#define PACA_IRQ_MUST_HARD_MASK (PACA_IRQ_EE|PACA_IRQ_REPLAYING)
#endif
#endif /* CONFIG_PPC64 */

View File

@ -74,17 +74,18 @@
#include <asm/kprobes.h>
#include <asm/runlatch.h>
#ifdef CONFIG_PPC64
#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
/*
* WARN/BUG is handled with a program interrupt so minimise checks here to
* avoid recursion and maximise the chance of getting the first oops handled.
*/
#define INT_SOFT_MASK_BUG_ON(regs, cond) \
do { \
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG) && \
(user_mode(regs) || (TRAP(regs) != INTERRUPT_PROGRAM))) \
if ((user_mode(regs) || (TRAP(regs) != INTERRUPT_PROGRAM))) \
BUG_ON(cond); \
} while (0)
#else
#define INT_SOFT_MASK_BUG_ON(regs, cond)
#endif
#ifdef CONFIG_PPC_BOOK3S_64
@ -151,28 +152,8 @@ static inline void booke_restore_dbcr0(void)
static inline void interrupt_enter_prepare(struct pt_regs *regs)
{
#ifdef CONFIG_PPC32
if (!arch_irq_disabled_regs(regs))
trace_hardirqs_off();
if (user_mode(regs))
kuap_lock();
else
kuap_save_and_lock(regs);
if (user_mode(regs))
account_cpu_user_entry();
#endif
#ifdef CONFIG_PPC64
bool trace_enable = false;
if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS)) {
if (irq_soft_mask_set_return(IRQS_ALL_DISABLED) == IRQS_ENABLED)
trace_enable = true;
} else {
irq_soft_mask_set(IRQS_ALL_DISABLED);
}
irq_soft_mask_set(IRQS_ALL_DISABLED);
/*
* If the interrupt was taken with HARD_DIS clear, then enable MSR[EE].
@ -188,9 +169,10 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs)
} else {
__hard_RI_enable();
}
/* Enable MSR[RI] early, to support kernel SLB and hash faults */
#endif
/* Do this when RI=1 because it can cause SLB faults */
if (trace_enable)
if (!arch_irq_disabled_regs(regs))
trace_hardirqs_off();
if (user_mode(regs)) {
@ -215,7 +197,6 @@ static inline void interrupt_enter_prepare(struct pt_regs *regs)
}
INT_SOFT_MASK_BUG_ON(regs, !arch_irq_disabled_regs(regs) &&
!(regs->msr & MSR_EE));
#endif
booke_restore_dbcr0();
}

View File

@ -16,9 +16,6 @@
extern atomic_t ppc_n_lost_interrupts;
/* This number is used when no interrupt has been assigned */
#define NO_IRQ (0)
/* Total number of virq in the platform */
#define NR_IRQS CONFIG_NR_IRQS

View File

@ -3,6 +3,7 @@
#define _ASM_POWERPC_MACHDEP_H
#ifdef __KERNEL__
#include <linux/compiler.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
@ -220,11 +221,16 @@ extern struct machdep_calls *machine_id;
EXPORT_SYMBOL(mach_##name); \
struct machdep_calls mach_##name __machine_desc =
#define machine_is(name) \
({ \
extern struct machdep_calls mach_##name \
__attribute__((weak)); \
machine_id == &mach_##name; \
static inline bool __machine_is(const struct machdep_calls *md)
{
WARN_ON(!machine_id); // complain if used before probe_machine()
return machine_id == md;
}
#define machine_is(name) \
({ \
extern struct machdep_calls mach_##name __weak; \
__machine_is(&mach_##name); \
})
static inline void log_error(char *buf, unsigned int err_type, int fatal)

View File

@ -295,7 +295,6 @@ extern void free_unused_pacas(void);
#else /* CONFIG_PPC64 */
static inline void allocate_paca_ptrs(void) { }
static inline void allocate_paca(int cpu) { }
static inline void free_unused_pacas(void) { }

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_POWERPC_PAPR_SYSPARM_H
#define _ASM_POWERPC_PAPR_SYSPARM_H
typedef struct {
const u32 token;
} papr_sysparm_t;
#define mk_papr_sysparm(x_) ((papr_sysparm_t){ .token = x_, })
/*
* Derived from the "Defined Parameters" table in PAPR 7.3.16 System
* Parameters Option. Where the spec says "characteristics", we use
* "attrs" in the symbolic names to keep them from getting too
* unwieldy.
*/
#define PAPR_SYSPARM_SHARED_PROC_LPAR_ATTRS mk_papr_sysparm(20)
#define PAPR_SYSPARM_PROC_MODULE_INFO mk_papr_sysparm(43)
#define PAPR_SYSPARM_COOP_MEM_OVERCOMMIT_ATTRS mk_papr_sysparm(44)
#define PAPR_SYSPARM_TLB_BLOCK_INVALIDATE_ATTRS mk_papr_sysparm(50)
#define PAPR_SYSPARM_LPAR_NAME mk_papr_sysparm(55)
enum {
PAPR_SYSPARM_MAX_INPUT = 1024,
PAPR_SYSPARM_MAX_OUTPUT = 4000,
};
struct papr_sysparm_buf {
__be16 len;
char val[PAPR_SYSPARM_MAX_OUTPUT];
};
struct papr_sysparm_buf *papr_sysparm_buf_alloc(void);
void papr_sysparm_buf_free(struct papr_sysparm_buf *buf);
int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf);
int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf);
#endif /* _ASM_POWERPC_PAPR_SYSPARM_H */

View File

@ -176,8 +176,10 @@ extern int pci_device_from_OF_node(struct device_node *node,
#endif
#ifndef CONFIG_PPC64
#ifdef CONFIG_PPC_CHRP
#ifdef CONFIG_PPC_PCI_OF_BUS_MAP
extern void pci_create_OF_bus_map(void);
#else
static inline void pci_create_OF_bus_map(void) {}
#endif
#else /* CONFIG_PPC64 */

View File

@ -0,0 +1,195 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 IBM Corporation
* Author: Nayna Jain <nayna@linux.ibm.com>
*
* Platform keystore for pseries LPAR(PLPKS).
*/
#ifndef _ASM_POWERPC_PLPKS_H
#define _ASM_POWERPC_PLPKS_H
#ifdef CONFIG_PSERIES_PLPKS
#include <linux/types.h>
#include <linux/list.h>
// Object policy flags from supported_policies
#define PLPKS_OSSECBOOTAUDIT PPC_BIT32(1) // OS secure boot must be audit/enforce
#define PLPKS_OSSECBOOTENFORCE PPC_BIT32(2) // OS secure boot must be enforce
#define PLPKS_PWSET PPC_BIT32(3) // No access without password set
#define PLPKS_WORLDREADABLE PPC_BIT32(4) // Readable without authentication
#define PLPKS_IMMUTABLE PPC_BIT32(5) // Once written, object cannot be removed
#define PLPKS_TRANSIENT PPC_BIT32(6) // Object does not persist through reboot
#define PLPKS_SIGNEDUPDATE PPC_BIT32(7) // Object can only be modified by signed updates
#define PLPKS_HVPROVISIONED PPC_BIT32(28) // Hypervisor has provisioned this object
// Signature algorithm flags from signed_update_algorithms
#define PLPKS_ALG_RSA2048 PPC_BIT(0)
#define PLPKS_ALG_RSA4096 PPC_BIT(1)
// Object label OS metadata flags
#define PLPKS_VAR_LINUX 0x02
#define PLPKS_VAR_COMMON 0x04
// Flags for which consumer owns an object is owned by
#define PLPKS_FW_OWNER 0x1
#define PLPKS_BOOTLOADER_OWNER 0x2
#define PLPKS_OS_OWNER 0x3
// Flags for label metadata fields
#define PLPKS_LABEL_VERSION 0
#define PLPKS_MAX_LABEL_ATTR_SIZE 16
#define PLPKS_MAX_NAME_SIZE 239
#define PLPKS_MAX_DATA_SIZE 4000
// Timeouts for PLPKS operations
#define PLPKS_MAX_TIMEOUT 5000 // msec
#define PLPKS_FLUSH_SLEEP 10 // msec
#define PLPKS_FLUSH_SLEEP_RANGE 400
struct plpks_var {
char *component;
u8 *name;
u8 *data;
u32 policy;
u16 namelen;
u16 datalen;
u8 os;
};
struct plpks_var_name {
u8 *name;
u16 namelen;
};
struct plpks_var_name_list {
u32 varcount;
struct plpks_var_name varlist[];
};
/**
* Updates the authenticated variable. It expects NULL as the component.
*/
int plpks_signed_update_var(struct plpks_var *var, u64 flags);
/**
* Writes the specified var and its data to PKS.
* Any caller of PKS driver should present a valid component type for
* their variable.
*/
int plpks_write_var(struct plpks_var var);
/**
* Removes the specified var and its data from PKS.
*/
int plpks_remove_var(char *component, u8 varos,
struct plpks_var_name vname);
/**
* Returns the data for the specified os variable.
*
* Caller must allocate a buffer in var->data with length in var->datalen.
* If no buffer is provided, var->datalen will be populated with the object's
* size.
*/
int plpks_read_os_var(struct plpks_var *var);
/**
* Returns the data for the specified firmware variable.
*
* Caller must allocate a buffer in var->data with length in var->datalen.
* If no buffer is provided, var->datalen will be populated with the object's
* size.
*/
int plpks_read_fw_var(struct plpks_var *var);
/**
* Returns the data for the specified bootloader variable.
*
* Caller must allocate a buffer in var->data with length in var->datalen.
* If no buffer is provided, var->datalen will be populated with the object's
* size.
*/
int plpks_read_bootloader_var(struct plpks_var *var);
/**
* Returns if PKS is available on this LPAR.
*/
bool plpks_is_available(void);
/**
* Returns version of the Platform KeyStore.
*/
u8 plpks_get_version(void);
/**
* Returns hypervisor storage overhead per object, not including the size of
* the object or label. Only valid for config version >= 2
*/
u16 plpks_get_objoverhead(void);
/**
* Returns maximum password size. Must be >= 32 bytes
*/
u16 plpks_get_maxpwsize(void);
/**
* Returns maximum object size supported by Platform KeyStore.
*/
u16 plpks_get_maxobjectsize(void);
/**
* Returns maximum object label size supported by Platform KeyStore.
*/
u16 plpks_get_maxobjectlabelsize(void);
/**
* Returns total size of the configured Platform KeyStore.
*/
u32 plpks_get_totalsize(void);
/**
* Returns used space from the total size of the Platform KeyStore.
*/
u32 plpks_get_usedspace(void);
/**
* Returns bitmask of policies supported by the hypervisor.
*/
u32 plpks_get_supportedpolicies(void);
/**
* Returns maximum byte size of a single object supported by the hypervisor.
* Only valid for config version >= 3
*/
u32 plpks_get_maxlargeobjectsize(void);
/**
* Returns bitmask of signature algorithms supported for signed updates.
* Only valid for config version >= 3
*/
u64 plpks_get_signedupdatealgorithms(void);
/**
* Returns the length of the PLPKS password in bytes.
*/
u16 plpks_get_passwordlen(void);
/**
* Called in early init to retrieve and clear the PLPKS password from the DT.
*/
void plpks_early_init_devtree(void);
/**
* Populates the FDT with the PLPKS password to prepare for kexec.
*/
int plpks_populate_fdt(void *fdt);
#else // CONFIG_PSERIES_PLPKS
static inline bool plpks_is_available(void) { return false; }
static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); }
static inline void plpks_early_init_devtree(void) { }
static inline int plpks_populate_fdt(void *fdt) { BUILD_BUG(); }
#endif // CONFIG_PSERIES_PLPKS
#endif // _ASM_POWERPC_PLPKS_H

View File

@ -18,8 +18,6 @@ struct rtas_t {
unsigned long entry; /* physical address pointer */
unsigned long base; /* physical address pointer */
unsigned long size;
arch_spinlock_t lock;
struct rtas_args args;
struct device_node *dev; /* virtual address pointer */
};

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _ASM_POWERPC_RTAS_WORK_AREA_H
#define _ASM_POWERPC_RTAS_WORK_AREA_H
#include <linux/build_bug.h>
#include <linux/sizes.h>
#include <linux/types.h>
#include <asm/page.h>
/**
* struct rtas_work_area - RTAS work area descriptor.
*
* Descriptor for a "work area" in PAPR terminology that satisfies
* RTAS addressing requirements.
*/
struct rtas_work_area {
/* private: Use the APIs provided below. */
char *buf;
size_t size;
};
enum {
/* Maximum allocation size, enforced at build time. */
RTAS_WORK_AREA_MAX_ALLOC_SZ = SZ_128K,
};
/**
* rtas_work_area_alloc() - Acquire a work area of the requested size.
* @size_: Allocation size. Must be compile-time constant and not more
* than %RTAS_WORK_AREA_MAX_ALLOC_SZ.
*
* Allocate a buffer suitable for passing to RTAS functions that have
* a memory address parameter, often (but not always) referred to as a
* "work area" in PAPR. Although callers are allowed to block while
* holding a work area, the amount of memory reserved for this purpose
* is limited, and allocations should be short-lived. A good guideline
* is to release any allocated work area before returning from a
* system call.
*
* This function does not fail. It blocks until the allocation
* succeeds. To prevent deadlocks, callers are discouraged from
* allocating more than one work area simultaneously in a single task
* context.
*
* Context: This function may sleep.
* Return: A &struct rtas_work_area descriptor for the allocated work area.
*/
#define rtas_work_area_alloc(size_) ({ \
static_assert(__builtin_constant_p(size_)); \
static_assert((size_) > 0); \
static_assert((size_) <= RTAS_WORK_AREA_MAX_ALLOC_SZ); \
__rtas_work_area_alloc(size_); \
})
/*
* Do not call __rtas_work_area_alloc() directly. Use
* rtas_work_area_alloc().
*/
struct rtas_work_area *__rtas_work_area_alloc(size_t size);
/**
* rtas_work_area_free() - Release a work area.
* @area: Work area descriptor as returned from rtas_work_area_alloc().
*
* Return a work area buffer to the pool.
*/
void rtas_work_area_free(struct rtas_work_area *area);
static inline char *rtas_work_area_raw_buf(const struct rtas_work_area *area)
{
return area->buf;
}
static inline size_t rtas_work_area_size(const struct rtas_work_area *area)
{
return area->size;
}
static inline phys_addr_t rtas_work_area_phys(const struct rtas_work_area *area)
{
return __pa(area->buf);
}
/*
* Early setup for the work area allocator. Call from
* rtas_initialize() only.
*/
#ifdef CONFIG_PPC_PSERIES
void rtas_work_area_reserve_arena(phys_addr_t limit);
#else /* CONFIG_PPC_PSERIES */
static inline void rtas_work_area_reserve_arena(phys_addr_t limit) {}
#endif /* CONFIG_PPC_PSERIES */
#endif /* _ASM_POWERPC_RTAS_WORK_AREA_H */

View File

@ -16,6 +16,185 @@
* Copyright (C) 2001 PPC 64 Team, IBM Corp
*/
enum rtas_function_index {
RTAS_FNIDX__CHECK_EXCEPTION,
RTAS_FNIDX__DISPLAY_CHARACTER,
RTAS_FNIDX__EVENT_SCAN,
RTAS_FNIDX__FREEZE_TIME_BASE,
RTAS_FNIDX__GET_POWER_LEVEL,
RTAS_FNIDX__GET_SENSOR_STATE,
RTAS_FNIDX__GET_TERM_CHAR,
RTAS_FNIDX__GET_TIME_OF_DAY,
RTAS_FNIDX__IBM_ACTIVATE_FIRMWARE,
RTAS_FNIDX__IBM_CBE_START_PTCAL,
RTAS_FNIDX__IBM_CBE_STOP_PTCAL,
RTAS_FNIDX__IBM_CHANGE_MSI,
RTAS_FNIDX__IBM_CLOSE_ERRINJCT,
RTAS_FNIDX__IBM_CONFIGURE_BRIDGE,
RTAS_FNIDX__IBM_CONFIGURE_CONNECTOR,
RTAS_FNIDX__IBM_CONFIGURE_KERNEL_DUMP,
RTAS_FNIDX__IBM_CONFIGURE_PE,
RTAS_FNIDX__IBM_CREATE_PE_DMA_WINDOW,
RTAS_FNIDX__IBM_DISPLAY_MESSAGE,
RTAS_FNIDX__IBM_ERRINJCT,
RTAS_FNIDX__IBM_EXTI2C,
RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO,
RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO2,
RTAS_FNIDX__IBM_GET_DYNAMIC_SENSOR_STATE,
RTAS_FNIDX__IBM_GET_INDICES,
RTAS_FNIDX__IBM_GET_RIO_TOPOLOGY,
RTAS_FNIDX__IBM_GET_SYSTEM_PARAMETER,
RTAS_FNIDX__IBM_GET_VPD,
RTAS_FNIDX__IBM_GET_XIVE,
RTAS_FNIDX__IBM_INT_OFF,
RTAS_FNIDX__IBM_INT_ON,
RTAS_FNIDX__IBM_IO_QUIESCE_ACK,
RTAS_FNIDX__IBM_LPAR_PERFTOOLS,
RTAS_FNIDX__IBM_MANAGE_FLASH_IMAGE,
RTAS_FNIDX__IBM_MANAGE_STORAGE_PRESERVATION,
RTAS_FNIDX__IBM_NMI_INTERLOCK,
RTAS_FNIDX__IBM_NMI_REGISTER,
RTAS_FNIDX__IBM_OPEN_ERRINJCT,
RTAS_FNIDX__IBM_OPEN_SRIOV_ALLOW_UNFREEZE,
RTAS_FNIDX__IBM_OPEN_SRIOV_MAP_PE_NUMBER,
RTAS_FNIDX__IBM_OS_TERM,
RTAS_FNIDX__IBM_PARTNER_CONTROL,
RTAS_FNIDX__IBM_PHYSICAL_ATTESTATION,
RTAS_FNIDX__IBM_PLATFORM_DUMP,
RTAS_FNIDX__IBM_POWER_OFF_UPS,
RTAS_FNIDX__IBM_QUERY_INTERRUPT_SOURCE_NUMBER,
RTAS_FNIDX__IBM_QUERY_PE_DMA_WINDOW,
RTAS_FNIDX__IBM_READ_PCI_CONFIG,
RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE,
RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2,
RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW,
RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS,
RTAS_FNIDX__IBM_SCAN_LOG_DUMP,
RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR,
RTAS_FNIDX__IBM_SET_EEH_OPTION,
RTAS_FNIDX__IBM_SET_SLOT_RESET,
RTAS_FNIDX__IBM_SET_SYSTEM_PARAMETER,
RTAS_FNIDX__IBM_SET_XIVE,
RTAS_FNIDX__IBM_SLOT_ERROR_DETAIL,
RTAS_FNIDX__IBM_SUSPEND_ME,
RTAS_FNIDX__IBM_TUNE_DMA_PARMS,
RTAS_FNIDX__IBM_UPDATE_FLASH_64_AND_REBOOT,
RTAS_FNIDX__IBM_UPDATE_NODES,
RTAS_FNIDX__IBM_UPDATE_PROPERTIES,
RTAS_FNIDX__IBM_VALIDATE_FLASH_IMAGE,
RTAS_FNIDX__IBM_WRITE_PCI_CONFIG,
RTAS_FNIDX__NVRAM_FETCH,
RTAS_FNIDX__NVRAM_STORE,
RTAS_FNIDX__POWER_OFF,
RTAS_FNIDX__PUT_TERM_CHAR,
RTAS_FNIDX__QUERY_CPU_STOPPED_STATE,
RTAS_FNIDX__READ_PCI_CONFIG,
RTAS_FNIDX__RTAS_LAST_ERROR,
RTAS_FNIDX__SET_INDICATOR,
RTAS_FNIDX__SET_POWER_LEVEL,
RTAS_FNIDX__SET_TIME_FOR_POWER_ON,
RTAS_FNIDX__SET_TIME_OF_DAY,
RTAS_FNIDX__START_CPU,
RTAS_FNIDX__STOP_SELF,
RTAS_FNIDX__SYSTEM_REBOOT,
RTAS_FNIDX__THAW_TIME_BASE,
RTAS_FNIDX__WRITE_PCI_CONFIG,
};
/*
* Opaque handle for client code to refer to RTAS functions. All valid
* function handles are build-time constants prefixed with RTAS_FN_.
*/
typedef struct {
const enum rtas_function_index index;
} rtas_fn_handle_t;
#define rtas_fn_handle(x_) ((const rtas_fn_handle_t) { .index = x_, })
#define RTAS_FN_CHECK_EXCEPTION rtas_fn_handle(RTAS_FNIDX__CHECK_EXCEPTION)
#define RTAS_FN_DISPLAY_CHARACTER rtas_fn_handle(RTAS_FNIDX__DISPLAY_CHARACTER)
#define RTAS_FN_EVENT_SCAN rtas_fn_handle(RTAS_FNIDX__EVENT_SCAN)
#define RTAS_FN_FREEZE_TIME_BASE rtas_fn_handle(RTAS_FNIDX__FREEZE_TIME_BASE)
#define RTAS_FN_GET_POWER_LEVEL rtas_fn_handle(RTAS_FNIDX__GET_POWER_LEVEL)
#define RTAS_FN_GET_SENSOR_STATE rtas_fn_handle(RTAS_FNIDX__GET_SENSOR_STATE)
#define RTAS_FN_GET_TERM_CHAR rtas_fn_handle(RTAS_FNIDX__GET_TERM_CHAR)
#define RTAS_FN_GET_TIME_OF_DAY rtas_fn_handle(RTAS_FNIDX__GET_TIME_OF_DAY)
#define RTAS_FN_IBM_ACTIVATE_FIRMWARE rtas_fn_handle(RTAS_FNIDX__IBM_ACTIVATE_FIRMWARE)
#define RTAS_FN_IBM_CBE_START_PTCAL rtas_fn_handle(RTAS_FNIDX__IBM_CBE_START_PTCAL)
#define RTAS_FN_IBM_CBE_STOP_PTCAL rtas_fn_handle(RTAS_FNIDX__IBM_CBE_STOP_PTCAL)
#define RTAS_FN_IBM_CHANGE_MSI rtas_fn_handle(RTAS_FNIDX__IBM_CHANGE_MSI)
#define RTAS_FN_IBM_CLOSE_ERRINJCT rtas_fn_handle(RTAS_FNIDX__IBM_CLOSE_ERRINJCT)
#define RTAS_FN_IBM_CONFIGURE_BRIDGE rtas_fn_handle(RTAS_FNIDX__IBM_CONFIGURE_BRIDGE)
#define RTAS_FN_IBM_CONFIGURE_CONNECTOR rtas_fn_handle(RTAS_FNIDX__IBM_CONFIGURE_CONNECTOR)
#define RTAS_FN_IBM_CONFIGURE_KERNEL_DUMP rtas_fn_handle(RTAS_FNIDX__IBM_CONFIGURE_KERNEL_DUMP)
#define RTAS_FN_IBM_CONFIGURE_PE rtas_fn_handle(RTAS_FNIDX__IBM_CONFIGURE_PE)
#define RTAS_FN_IBM_CREATE_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_CREATE_PE_DMA_WINDOW)
#define RTAS_FN_IBM_DISPLAY_MESSAGE rtas_fn_handle(RTAS_FNIDX__IBM_DISPLAY_MESSAGE)
#define RTAS_FN_IBM_ERRINJCT rtas_fn_handle(RTAS_FNIDX__IBM_ERRINJCT)
#define RTAS_FN_IBM_EXTI2C rtas_fn_handle(RTAS_FNIDX__IBM_EXTI2C)
#define RTAS_FN_IBM_GET_CONFIG_ADDR_INFO rtas_fn_handle(RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO)
#define RTAS_FN_IBM_GET_CONFIG_ADDR_INFO2 rtas_fn_handle(RTAS_FNIDX__IBM_GET_CONFIG_ADDR_INFO2)
#define RTAS_FN_IBM_GET_DYNAMIC_SENSOR_STATE rtas_fn_handle(RTAS_FNIDX__IBM_GET_DYNAMIC_SENSOR_STATE)
#define RTAS_FN_IBM_GET_INDICES rtas_fn_handle(RTAS_FNIDX__IBM_GET_INDICES)
#define RTAS_FN_IBM_GET_RIO_TOPOLOGY rtas_fn_handle(RTAS_FNIDX__IBM_GET_RIO_TOPOLOGY)
#define RTAS_FN_IBM_GET_SYSTEM_PARAMETER rtas_fn_handle(RTAS_FNIDX__IBM_GET_SYSTEM_PARAMETER)
#define RTAS_FN_IBM_GET_VPD rtas_fn_handle(RTAS_FNIDX__IBM_GET_VPD)
#define RTAS_FN_IBM_GET_XIVE rtas_fn_handle(RTAS_FNIDX__IBM_GET_XIVE)
#define RTAS_FN_IBM_INT_OFF rtas_fn_handle(RTAS_FNIDX__IBM_INT_OFF)
#define RTAS_FN_IBM_INT_ON rtas_fn_handle(RTAS_FNIDX__IBM_INT_ON)
#define RTAS_FN_IBM_IO_QUIESCE_ACK rtas_fn_handle(RTAS_FNIDX__IBM_IO_QUIESCE_ACK)
#define RTAS_FN_IBM_LPAR_PERFTOOLS rtas_fn_handle(RTAS_FNIDX__IBM_LPAR_PERFTOOLS)
#define RTAS_FN_IBM_MANAGE_FLASH_IMAGE rtas_fn_handle(RTAS_FNIDX__IBM_MANAGE_FLASH_IMAGE)
#define RTAS_FN_IBM_MANAGE_STORAGE_PRESERVATION rtas_fn_handle(RTAS_FNIDX__IBM_MANAGE_STORAGE_PRESERVATION)
#define RTAS_FN_IBM_NMI_INTERLOCK rtas_fn_handle(RTAS_FNIDX__IBM_NMI_INTERLOCK)
#define RTAS_FN_IBM_NMI_REGISTER rtas_fn_handle(RTAS_FNIDX__IBM_NMI_REGISTER)
#define RTAS_FN_IBM_OPEN_ERRINJCT rtas_fn_handle(RTAS_FNIDX__IBM_OPEN_ERRINJCT)
#define RTAS_FN_IBM_OPEN_SRIOV_ALLOW_UNFREEZE rtas_fn_handle(RTAS_FNIDX__IBM_OPEN_SRIOV_ALLOW_UNFREEZE)
#define RTAS_FN_IBM_OPEN_SRIOV_MAP_PE_NUMBER rtas_fn_handle(RTAS_FNIDX__IBM_OPEN_SRIOV_MAP_PE_NUMBER)
#define RTAS_FN_IBM_OS_TERM rtas_fn_handle(RTAS_FNIDX__IBM_OS_TERM)
#define RTAS_FN_IBM_PARTNER_CONTROL rtas_fn_handle(RTAS_FNIDX__IBM_PARTNER_CONTROL)
#define RTAS_FN_IBM_PHYSICAL_ATTESTATION rtas_fn_handle(RTAS_FNIDX__IBM_PHYSICAL_ATTESTATION)
#define RTAS_FN_IBM_PLATFORM_DUMP rtas_fn_handle(RTAS_FNIDX__IBM_PLATFORM_DUMP)
#define RTAS_FN_IBM_POWER_OFF_UPS rtas_fn_handle(RTAS_FNIDX__IBM_POWER_OFF_UPS)
#define RTAS_FN_IBM_QUERY_INTERRUPT_SOURCE_NUMBER rtas_fn_handle(RTAS_FNIDX__IBM_QUERY_INTERRUPT_SOURCE_NUMBER)
#define RTAS_FN_IBM_QUERY_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_QUERY_PE_DMA_WINDOW)
#define RTAS_FN_IBM_READ_PCI_CONFIG rtas_fn_handle(RTAS_FNIDX__IBM_READ_PCI_CONFIG)
#define RTAS_FN_IBM_READ_SLOT_RESET_STATE rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE)
#define RTAS_FN_IBM_READ_SLOT_RESET_STATE2 rtas_fn_handle(RTAS_FNIDX__IBM_READ_SLOT_RESET_STATE2)
#define RTAS_FN_IBM_REMOVE_PE_DMA_WINDOW rtas_fn_handle(RTAS_FNIDX__IBM_REMOVE_PE_DMA_WINDOW)
#define RTAS_FN_IBM_RESET_PE_DMA_WINDOWS rtas_fn_handle(RTAS_FNIDX__IBM_RESET_PE_DMA_WINDOWS)
#define RTAS_FN_IBM_SCAN_LOG_DUMP rtas_fn_handle(RTAS_FNIDX__IBM_SCAN_LOG_DUMP)
#define RTAS_FN_IBM_SET_DYNAMIC_INDICATOR rtas_fn_handle(RTAS_FNIDX__IBM_SET_DYNAMIC_INDICATOR)
#define RTAS_FN_IBM_SET_EEH_OPTION rtas_fn_handle(RTAS_FNIDX__IBM_SET_EEH_OPTION)
#define RTAS_FN_IBM_SET_SLOT_RESET rtas_fn_handle(RTAS_FNIDX__IBM_SET_SLOT_RESET)
#define RTAS_FN_IBM_SET_SYSTEM_PARAMETER rtas_fn_handle(RTAS_FNIDX__IBM_SET_SYSTEM_PARAMETER)
#define RTAS_FN_IBM_SET_XIVE rtas_fn_handle(RTAS_FNIDX__IBM_SET_XIVE)
#define RTAS_FN_IBM_SLOT_ERROR_DETAIL rtas_fn_handle(RTAS_FNIDX__IBM_SLOT_ERROR_DETAIL)
#define RTAS_FN_IBM_SUSPEND_ME rtas_fn_handle(RTAS_FNIDX__IBM_SUSPEND_ME)
#define RTAS_FN_IBM_TUNE_DMA_PARMS rtas_fn_handle(RTAS_FNIDX__IBM_TUNE_DMA_PARMS)
#define RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT rtas_fn_handle(RTAS_FNIDX__IBM_UPDATE_FLASH_64_AND_REBOOT)
#define RTAS_FN_IBM_UPDATE_NODES rtas_fn_handle(RTAS_FNIDX__IBM_UPDATE_NODES)
#define RTAS_FN_IBM_UPDATE_PROPERTIES rtas_fn_handle(RTAS_FNIDX__IBM_UPDATE_PROPERTIES)
#define RTAS_FN_IBM_VALIDATE_FLASH_IMAGE rtas_fn_handle(RTAS_FNIDX__IBM_VALIDATE_FLASH_IMAGE)
#define RTAS_FN_IBM_WRITE_PCI_CONFIG rtas_fn_handle(RTAS_FNIDX__IBM_WRITE_PCI_CONFIG)
#define RTAS_FN_NVRAM_FETCH rtas_fn_handle(RTAS_FNIDX__NVRAM_FETCH)
#define RTAS_FN_NVRAM_STORE rtas_fn_handle(RTAS_FNIDX__NVRAM_STORE)
#define RTAS_FN_POWER_OFF rtas_fn_handle(RTAS_FNIDX__POWER_OFF)
#define RTAS_FN_PUT_TERM_CHAR rtas_fn_handle(RTAS_FNIDX__PUT_TERM_CHAR)
#define RTAS_FN_QUERY_CPU_STOPPED_STATE rtas_fn_handle(RTAS_FNIDX__QUERY_CPU_STOPPED_STATE)
#define RTAS_FN_READ_PCI_CONFIG rtas_fn_handle(RTAS_FNIDX__READ_PCI_CONFIG)
#define RTAS_FN_RTAS_LAST_ERROR rtas_fn_handle(RTAS_FNIDX__RTAS_LAST_ERROR)
#define RTAS_FN_SET_INDICATOR rtas_fn_handle(RTAS_FNIDX__SET_INDICATOR)
#define RTAS_FN_SET_POWER_LEVEL rtas_fn_handle(RTAS_FNIDX__SET_POWER_LEVEL)
#define RTAS_FN_SET_TIME_FOR_POWER_ON rtas_fn_handle(RTAS_FNIDX__SET_TIME_FOR_POWER_ON)
#define RTAS_FN_SET_TIME_OF_DAY rtas_fn_handle(RTAS_FNIDX__SET_TIME_OF_DAY)
#define RTAS_FN_START_CPU rtas_fn_handle(RTAS_FNIDX__START_CPU)
#define RTAS_FN_STOP_SELF rtas_fn_handle(RTAS_FNIDX__STOP_SELF)
#define RTAS_FN_SYSTEM_REBOOT rtas_fn_handle(RTAS_FNIDX__SYSTEM_REBOOT)
#define RTAS_FN_THAW_TIME_BASE rtas_fn_handle(RTAS_FNIDX__THAW_TIME_BASE)
#define RTAS_FN_WRITE_PCI_CONFIG rtas_fn_handle(RTAS_FNIDX__WRITE_PCI_CONFIG)
#define RTAS_UNKNOWN_SERVICE (-1)
#define RTAS_INSTANTIATE_MAX (1ULL<<30) /* Don't instantiate rtas at/above this value */
@ -222,6 +401,11 @@ extern void (*rtas_flash_term_hook)(int);
extern struct rtas_t rtas;
s32 rtas_function_token(const rtas_fn_handle_t handle);
static inline bool rtas_function_implemented(const rtas_fn_handle_t handle)
{
return rtas_function_token(handle) != RTAS_UNKNOWN_SERVICE;
}
extern int rtas_token(const char *service);
extern int rtas_service_present(const char *service);
extern int rtas_call(int token, int, int, int *, ...);

View File

@ -10,25 +10,30 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sysfs.h>
extern const struct secvar_operations *secvar_ops;
struct secvar_operations {
int (*get)(const char *key, uint64_t key_len, u8 *data,
uint64_t *data_size);
int (*get_next)(const char *key, uint64_t *key_len,
uint64_t keybufsize);
int (*set)(const char *key, uint64_t key_len, u8 *data,
uint64_t data_size);
int (*get)(const char *key, u64 key_len, u8 *data, u64 *data_size);
int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
ssize_t (*format)(char *buf, size_t bufsize);
int (*max_size)(u64 *max_size);
const struct attribute **config_attrs;
// NULL-terminated array of fixed variable names
// Only used if get_next() isn't provided
const char * const *var_names;
};
#ifdef CONFIG_PPC_SECURE_BOOT
extern void set_secvar_ops(const struct secvar_operations *ops);
int set_secvar_ops(const struct secvar_operations *ops);
#else
static inline void set_secvar_ops(const struct secvar_operations *ops) { }
static inline int set_secvar_ops(const struct secvar_operations *ops) { return 0; }
#endif

View File

@ -26,6 +26,7 @@
#include <asm/percpu.h>
extern int boot_cpuid;
extern int boot_cpu_hwid; /* PPC64 only */
extern int spinning_secondaries;
extern u32 *cpu_to_phys_id;
extern bool coregroup_enabled;

View File

@ -119,6 +119,109 @@ TRACE_EVENT_FN_COND(hcall_exit,
);
#endif
#ifdef CONFIG_PPC_RTAS
#include <asm/rtas-types.h>
TRACE_EVENT(rtas_input,
TP_PROTO(struct rtas_args *rtas_args, const char *name),
TP_ARGS(rtas_args, name),
TP_STRUCT__entry(
__field(__u32, nargs)
__string(name, name)
__dynamic_array(__u32, inputs, be32_to_cpu(rtas_args->nargs))
),
TP_fast_assign(
__entry->nargs = be32_to_cpu(rtas_args->nargs);
__assign_str(name, name);
be32_to_cpu_array(__get_dynamic_array(inputs), rtas_args->args, __entry->nargs);
),
TP_printk("%s arguments: %s", __get_str(name),
__print_array(__get_dynamic_array(inputs), __entry->nargs, 4)
)
);
TRACE_EVENT(rtas_output,
TP_PROTO(struct rtas_args *rtas_args, const char *name),
TP_ARGS(rtas_args, name),
TP_STRUCT__entry(
__field(__u32, nr_other)
__field(__s32, status)
__string(name, name)
__dynamic_array(__u32, other_outputs, be32_to_cpu(rtas_args->nret) - 1)
),
TP_fast_assign(
__entry->nr_other = be32_to_cpu(rtas_args->nret) - 1;
__entry->status = be32_to_cpu(rtas_args->rets[0]);
__assign_str(name, name);
be32_to_cpu_array(__get_dynamic_array(other_outputs),
&rtas_args->rets[1], __entry->nr_other);
),
TP_printk("%s status: %d, other outputs: %s", __get_str(name), __entry->status,
__print_array(__get_dynamic_array(other_outputs),
__entry->nr_other, 4)
)
);
DECLARE_EVENT_CLASS(rtas_parameter_block,
TP_PROTO(struct rtas_args *rtas_args),
TP_ARGS(rtas_args),
TP_STRUCT__entry(
__field(u32, token)
__field(u32, nargs)
__field(u32, nret)
__array(__u32, params, 16)
),
TP_fast_assign(
__entry->token = be32_to_cpu(rtas_args->token);
__entry->nargs = be32_to_cpu(rtas_args->nargs);
__entry->nret = be32_to_cpu(rtas_args->nret);
be32_to_cpu_array(__entry->params, rtas_args->args, ARRAY_SIZE(rtas_args->args));
),
TP_printk("token=%u nargs=%u nret=%u params:"
" [0]=0x%08x [1]=0x%08x [2]=0x%08x [3]=0x%08x"
" [4]=0x%08x [5]=0x%08x [6]=0x%08x [7]=0x%08x"
" [8]=0x%08x [9]=0x%08x [10]=0x%08x [11]=0x%08x"
" [12]=0x%08x [13]=0x%08x [14]=0x%08x [15]=0x%08x",
__entry->token, __entry->nargs, __entry->nret,
__entry->params[0], __entry->params[1], __entry->params[2], __entry->params[3],
__entry->params[4], __entry->params[5], __entry->params[6], __entry->params[7],
__entry->params[8], __entry->params[9], __entry->params[10], __entry->params[11],
__entry->params[12], __entry->params[13], __entry->params[14], __entry->params[15]
)
);
DEFINE_EVENT(rtas_parameter_block, rtas_ll_entry,
TP_PROTO(struct rtas_args *rtas_args),
TP_ARGS(rtas_args)
);
DEFINE_EVENT(rtas_parameter_block, rtas_ll_exit,
TP_PROTO(struct rtas_args *rtas_args),
TP_ARGS(rtas_args)
);
#endif /* CONFIG_PPC_RTAS */
#ifdef CONFIG_PPC_POWERNV
extern int opal_tracepoint_regfunc(void);
extern void opal_tracepoint_unregfunc(void);

View File

@ -54,6 +54,13 @@ CFLAGS_cputable.o += -DDISABLE_BRANCH_PROFILING
CFLAGS_btext.o += -DDISABLE_BRANCH_PROFILING
endif
KCSAN_SANITIZE_early_32.o := n
KCSAN_SANITIZE_early_64.o := n
KCSAN_SANITIZE_cputable.o := n
KCSAN_SANITIZE_btext.o := n
KCSAN_SANITIZE_paca.o := n
KCSAN_SANITIZE_setup_64.o := n
#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
# Remove stack protector to avoid triggering unneeded stack canary
# checks due to randomize_kstack_offset.
@ -177,12 +184,15 @@ obj-$(CONFIG_PPC_SECVAR_SYSFS) += secvar-sysfs.o
# Disable GCOV, KCOV & sanitizers in odd or sensitive code
GCOV_PROFILE_prom_init.o := n
KCOV_INSTRUMENT_prom_init.o := n
KCSAN_SANITIZE_prom_init.o := n
UBSAN_SANITIZE_prom_init.o := n
GCOV_PROFILE_kprobes.o := n
KCOV_INSTRUMENT_kprobes.o := n
KCSAN_SANITIZE_kprobes.o := n
UBSAN_SANITIZE_kprobes.o := n
GCOV_PROFILE_kprobes-ftrace.o := n
KCOV_INSTRUMENT_kprobes-ftrace.o := n
KCSAN_SANITIZE_kprobes-ftrace.o := n
UBSAN_SANITIZE_kprobes-ftrace.o := n
GCOV_PROFILE_syscall_64.o := n
KCOV_INSTRUMENT_syscall_64.o := n

View File

@ -1065,10 +1065,10 @@ recover_failed:
eeh_slot_error_detail(pe, EEH_LOG_PERM);
/* Notify all devices that they're about to go down. */
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
eeh_set_irq_state(pe, false);
eeh_pe_report("error_detected(permanent failure)", pe,
eeh_report_failure, NULL);
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
/* Mark the PE to be removed permanently */
eeh_pe_state_mark(pe, EEH_PE_REMOVED);
@ -1185,10 +1185,10 @@ void eeh_handle_special_event(void)
/* Notify all devices to be down */
eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
eeh_pe_report(
"error_detected(permanent failure)", pe,
eeh_report_failure, NULL);
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
pci_lock_rescan_remove();
list_for_each_entry(hose, &hose_list, list_node) {

View File

@ -21,7 +21,13 @@ _GLOBAL(epapr_ev_idle)
ori r4, r4,_TLF_NAPPING /* so when we take an exception */
PPC_STL r4, TI_LOCAL_FLAGS(r2) /* it will return to our caller */
#ifdef CONFIG_BOOKE_OR_40x
wrteei 1
#else
mfmsr r4
ori r4, r4, MSR_EE
mtmsr r4
#endif
idle_loop:
LOAD_REG_IMMEDIATE(r11, EV_HCALL_TOKEN(EV_IDLE))

View File

@ -160,12 +160,8 @@ __secondary_hold:
std r24,(ABS_ADDR(__secondary_hold_acknowledge, first_256B))(0)
sync
li r26,0
#ifdef CONFIG_PPC_BOOK3E_64
tovirt(r26,r26)
#endif
/* All secondary cpus wait here until told to start. */
100: ld r12,(ABS_ADDR(__secondary_hold_spinloop, first_256B))(r26)
100: ld r12,(ABS_ADDR(__secondary_hold_spinloop, first_256B))(0)
cmpdi 0,r12,0
beq 100b
@ -475,8 +471,31 @@ SYM_FUNC_START_LOCAL(__mmu_off)
rfid
b . /* prevent speculative execution */
SYM_FUNC_END(__mmu_off)
#endif
SYM_FUNC_START_LOCAL(start_initialization_book3s)
mflr r25
/* Setup some critical 970 SPRs before switching MMU off */
mfspr r0,SPRN_PVR
srwi r0,r0,16
cmpwi r0,0x39 /* 970 */
beq 1f
cmpwi r0,0x3c /* 970FX */
beq 1f
cmpwi r0,0x44 /* 970MP */
beq 1f
cmpwi r0,0x45 /* 970GX */
bne 2f
1: bl __cpu_preinit_ppc970
2:
/* Switch off MMU if not already off */
bl __mmu_off
mtlr r25
blr
SYM_FUNC_END(start_initialization_book3s)
#endif
/*
* Here is our main kernel entry point. We support currently 2 kind of entries
@ -523,26 +542,10 @@ __start_initialization_multiplatform:
#ifdef CONFIG_PPC_BOOK3E_64
bl start_initialization_book3e
b __after_prom_start
#else
/* Setup some critical 970 SPRs before switching MMU off */
mfspr r0,SPRN_PVR
srwi r0,r0,16
cmpwi r0,0x39 /* 970 */
beq 1f
cmpwi r0,0x3c /* 970FX */
beq 1f
cmpwi r0,0x44 /* 970MP */
beq 1f
cmpwi r0,0x45 /* 970GX */
bne 2f
1: bl __cpu_preinit_ppc970
2:
/* Switch off MMU if not already off */
bl __mmu_off
b __after_prom_start
bl start_initialization_book3s
#endif /* CONFIG_PPC_BOOK3E_64 */
b __after_prom_start
__REF
__boot_from_prom:

View File

@ -67,11 +67,9 @@ static void iommu_debugfs_add(struct iommu_table *tbl)
static void iommu_debugfs_del(struct iommu_table *tbl)
{
char name[10];
struct dentry *liobn_entry;
sprintf(name, "%08lx", tbl->it_index);
liobn_entry = debugfs_lookup(name, iommu_debugfs_dir);
debugfs_remove(liobn_entry);
debugfs_lookup_and_remove(name, iommu_debugfs_dir);
}
#else
static void iommu_debugfs_add(struct iommu_table *tbl){}

View File

@ -70,22 +70,19 @@ int distribute_irqs = 1;
static inline void next_interrupt(struct pt_regs *regs)
{
/*
* Softirq processing can enable/disable irqs, which will leave
* MSR[EE] enabled and the soft mask set to IRQS_DISABLED. Fix
* this up.
*/
if (!(local_paca->irq_happened & PACA_IRQ_HARD_DIS))
hard_irq_disable();
else
irq_soft_mask_set(IRQS_ALL_DISABLED);
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
WARN_ON(!(local_paca->irq_happened & PACA_IRQ_HARD_DIS));
WARN_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED);
}
/*
* We are responding to the next interrupt, so interrupt-off
* latencies should be reset here.
*/
lockdep_hardirq_exit();
trace_hardirqs_on();
trace_hardirqs_off();
lockdep_hardirq_enter();
}
static inline bool irq_happened_test_and_clear(u8 irq)
@ -97,22 +94,11 @@ static inline bool irq_happened_test_and_clear(u8 irq)
return false;
}
void replay_soft_interrupts(void)
static __no_kcsan void __replay_soft_interrupts(void)
{
struct pt_regs regs;
/*
* Be careful here, calling these interrupt handlers can cause
* softirqs to be raised, which they may run when calling irq_exit,
* which will cause local_irq_enable() to be run, which can then
* recurse into this function. Don't keep any state across
* interrupt handler calls which may change underneath us.
*
* Softirqs can not be disabled over replay to stop this recursion
* because interrupts taken in idle code may require RCU softirq
* to run in the irq RCU tracking context. This is a hard problem
* to fix without changes to the softirq or idle layer.
*
* We use local_paca rather than get_paca() to avoid all the
* debug_smp_processor_id() business in this low level function.
*/
@ -120,13 +106,20 @@ void replay_soft_interrupts(void)
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
WARN_ON_ONCE(mfmsr() & MSR_EE);
WARN_ON(!(local_paca->irq_happened & PACA_IRQ_HARD_DIS));
WARN_ON(local_paca->irq_happened & PACA_IRQ_REPLAYING);
}
/*
* PACA_IRQ_REPLAYING prevents interrupt handlers from enabling
* MSR[EE] to get PMIs, which can result in more IRQs becoming
* pending.
*/
local_paca->irq_happened |= PACA_IRQ_REPLAYING;
ppc_save_regs(&regs);
regs.softe = IRQS_ENABLED;
regs.msr |= MSR_EE;
again:
/*
* Force the delivery of pending soft-disabled interrupts on PS3.
* Any HV call will have this side effect.
@ -175,17 +168,18 @@ again:
next_interrupt(&regs);
}
/*
* Softirq processing can enable and disable interrupts, which can
* result in new irqs becoming pending. Must keep looping until we
* have cleared out all pending interrupts.
*/
if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS)
goto again;
local_paca->irq_happened &= ~PACA_IRQ_REPLAYING;
}
__no_kcsan void replay_soft_interrupts(void)
{
irq_enter(); /* See comment in arch_local_irq_restore */
__replay_soft_interrupts();
irq_exit();
}
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_KUAP)
static inline void replay_soft_interrupts_irqrestore(void)
static inline __no_kcsan void replay_soft_interrupts_irqrestore(void)
{
unsigned long kuap_state = get_kuap();
@ -200,16 +194,16 @@ static inline void replay_soft_interrupts_irqrestore(void)
if (kuap_state != AMR_KUAP_BLOCKED)
set_kuap(AMR_KUAP_BLOCKED);
replay_soft_interrupts();
__replay_soft_interrupts();
if (kuap_state != AMR_KUAP_BLOCKED)
set_kuap(kuap_state);
}
#else
#define replay_soft_interrupts_irqrestore() replay_soft_interrupts()
#define replay_soft_interrupts_irqrestore() __replay_soft_interrupts()
#endif
notrace void arch_local_irq_restore(unsigned long mask)
notrace __no_kcsan void arch_local_irq_restore(unsigned long mask)
{
unsigned char irq_happened;
@ -219,9 +213,13 @@ notrace void arch_local_irq_restore(unsigned long mask)
return;
}
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
WARN_ON_ONCE(in_nmi() || in_hardirq());
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
WARN_ON_ONCE(in_nmi());
WARN_ON_ONCE(in_hardirq());
WARN_ON_ONCE(local_paca->irq_happened & PACA_IRQ_REPLAYING);
}
again:
/*
* After the stb, interrupts are unmasked and there are no interrupts
* pending replay. The restart sequence makes this atomic with
@ -248,6 +246,12 @@ notrace void arch_local_irq_restore(unsigned long mask)
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
WARN_ON_ONCE(!(mfmsr() & MSR_EE));
/*
* If we came here from the replay below, we might have a preempt
* pending (due to preempt_enable_no_resched()). Have to check now.
*/
preempt_check_resched();
return;
happened:
@ -261,6 +265,7 @@ happened:
irq_soft_mask_set(IRQS_ENABLED);
local_paca->irq_happened = 0;
__hard_irq_enable();
preempt_check_resched();
return;
}
@ -296,12 +301,38 @@ happened:
irq_soft_mask_set(IRQS_ALL_DISABLED);
trace_hardirqs_off();
/*
* Now enter interrupt context. The interrupt handlers themselves
* also call irq_enter/exit (which is okay, they can nest). But call
* it here now to hold off softirqs until the below irq_exit(). If
* we allowed replayed handlers to run softirqs, that enables irqs,
* which must replay interrupts, which recurses in here and makes
* things more complicated. The recursion is limited to 2, and it can
* be made to work, but it's complicated.
*
* local_bh_disable can not be used here because interrupts taken in
* idle are not in the right context (RCU, tick, etc) to run softirqs
* so irq_enter must be called.
*/
irq_enter();
replay_soft_interrupts_irqrestore();
irq_exit();
if (unlikely(local_paca->irq_happened != PACA_IRQ_HARD_DIS)) {
/*
* The softirq processing in irq_exit() may enable interrupts
* temporarily, which can result in MSR[EE] being enabled and
* more irqs becoming pending. Go around again if that happens.
*/
trace_hardirqs_on();
preempt_enable_no_resched();
goto again;
}
trace_hardirqs_on();
irq_soft_mask_set(IRQS_ENABLED);
if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG))
WARN_ON(local_paca->irq_happened != PACA_IRQ_HARD_DIS);
local_paca->irq_happened = 0;
__hard_irq_enable();
preempt_enable();

View File

@ -131,6 +131,13 @@ void save_mce_event(struct pt_regs *regs, long handled,
if (mce->error_type == MCE_ERROR_TYPE_UE)
mce->u.ue_error.ignore_event = mce_err->ignore_event;
/*
* Raise irq work, So that we don't miss to log the error for
* unrecoverable errors.
*/
if (mce->disposition == MCE_DISPOSITION_NOT_RECOVERED)
mce_irq_work_queue();
if (!addr)
return;
@ -233,9 +240,6 @@ static void machine_check_ue_event(struct machine_check_event *evt)
}
memcpy(&local_paca->mce_info->mce_ue_event_queue[index],
evt, sizeof(*evt));
/* Queue work to process this event later. */
mce_irq_work_queue();
}
/*

View File

@ -502,9 +502,10 @@ static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs,
static int restore_r2(const char *name, u32 *instruction, struct module *me)
{
u32 *prev_insn = instruction - 1;
u32 insn_val = *instruction;
if (is_mprofile_ftrace_call(name))
return 1;
return 0;
/*
* Make sure the branch isn't a sibling call. Sibling calls aren't
@ -512,19 +513,25 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me)
* restore afterwards.
*/
if (!instr_is_relative_link_branch(ppc_inst(*prev_insn)))
return 1;
if (*instruction != PPC_RAW_NOP()) {
pr_err("%s: Expected nop after call, got %08x at %pS\n",
me->name, *instruction, instruction);
return 0;
/*
* For livepatch, the restore r2 instruction might have already been
* written previously, if the referenced symbol is in a previously
* unloaded module which is now being loaded again. In that case, skip
* the warning and the instruction write.
*/
if (insn_val == PPC_INST_LD_TOC)
return 0;
if (insn_val != PPC_RAW_NOP()) {
pr_err("%s: Expected nop after call, got %08x at %pS\n",
me->name, insn_val, instruction);
return -ENOEXEC;
}
/* ld r2,R2_STACK_OFFSET(r1) */
if (patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC)))
return 0;
return 1;
return patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC));
}
int apply_relocate_add(Elf64_Shdr *sechdrs,
@ -648,8 +655,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
strtab + sym->st_name);
if (!value)
return -ENOENT;
if (!restore_r2(strtab + sym->st_name,
(u32 *)location + 1, me))
if (restore_r2(strtab + sym->st_name,
(u32 *)location + 1, me))
return -ENOEXEC;
} else
value += local_entry_offset(sym);

View File

@ -62,7 +62,7 @@ fixup_cpc710_pci64(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_CHRP)
#ifdef CONFIG_PPC_PCI_OF_BUS_MAP
static u8* pci_to_OF_bus_map;
static int pci_bus_count;
@ -152,6 +152,7 @@ pcibios_make_OF_bus_map(void)
}
#endif
}
#endif // CONFIG_PPC_PCI_OF_BUS_MAP
#ifdef CONFIG_PPC_PMAC
@ -160,7 +161,9 @@ pcibios_make_OF_bus_map(void)
*/
int pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
{
#ifdef CONFIG_PPC_PCI_OF_BUS_MAP
struct pci_dev *dev = NULL;
#endif
const __be32 *reg;
int size;
@ -175,6 +178,9 @@ int pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
*bus = (be32_to_cpup(&reg[0]) >> 16) & 0xff;
*devfn = (be32_to_cpup(&reg[0]) >> 8) & 0xff;
#ifndef CONFIG_PPC_PCI_OF_BUS_MAP
return 0;
#else
/* Ok, here we need some tweak. If we have already renumbered
* all busses, we can't rely on the OF bus number any more.
* the pci_to_OF_bus_map is not enough as several PCI busses
@ -192,11 +198,12 @@ int pci_device_from_OF_node(struct device_node *node, u8 *bus, u8 *devfn)
}
return -ENODEV;
#endif // CONFIG_PPC_PCI_OF_BUS_MAP
}
EXPORT_SYMBOL(pci_device_from_OF_node);
#endif
#ifdef CONFIG_PPC_CHRP
#ifdef CONFIG_PPC_PCI_OF_BUS_MAP
/* We create the "pci-OF-bus-map" property now so it appears in the
* /proc device tree
*/
@ -221,9 +228,7 @@ pci_create_OF_bus_map(void)
of_node_put(dn);
}
}
#endif
#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_CHRP) */
#endif // CONFIG_PPC_PCI_OF_BUS_MAP
void pcibios_setup_phb_io_space(struct pci_controller *hose)
{
@ -273,6 +278,7 @@ static int __init pcibios_init(void)
}
#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_CHRP)
#ifdef CONFIG_PPC_PCI_OF_BUS_MAP
pci_bus_count = next_busno;
/* OpenFirmware based machines need a map of OF bus
@ -281,6 +287,7 @@ static int __init pcibios_init(void)
*/
if (pci_assign_all_buses)
pcibios_make_OF_bus_map();
#endif
#endif
/* Call common code to handle resource allocation */

View File

@ -1405,8 +1405,7 @@ static void show_instructions(struct pt_regs *regs)
for (i = 0; i < NR_INSN_TO_PRINT; i++) {
int instr;
if (!__kernel_text_address(pc) ||
get_kernel_nofault(instr, (const void *)pc)) {
if (get_kernel_nofault(instr, (const void *)pc)) {
pr_cont("XXXXXXXX ");
} else {
if (nip == pc)
@ -2118,6 +2117,9 @@ static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
unsigned long stack_page;
unsigned long cpu = task_cpu(p);
if (!hardirq_ctx[cpu] || !softirq_ctx[cpu])
return 0;
stack_page = (unsigned long)hardirq_ctx[cpu];
if (sp >= stack_page && sp <= stack_page + THREAD_SIZE - nbytes)
return 1;
@ -2139,6 +2141,14 @@ static inline int valid_emergency_stack(unsigned long sp, struct task_struct *p,
if (!paca_ptrs)
return 0;
if (!paca_ptrs[cpu]->emergency_sp)
return 0;
# ifdef CONFIG_PPC_BOOK3S_64
if (!paca_ptrs[cpu]->nmi_emergency_sp || !paca_ptrs[cpu]->mc_emergency_sp)
return 0;
#endif
stack_page = (unsigned long)paca_ptrs[cpu]->emergency_sp - THREAD_SIZE;
if (sp >= stack_page && sp <= stack_page + THREAD_SIZE - nbytes)
return 1;

View File

@ -56,6 +56,7 @@
#include <asm/drmem.h>
#include <asm/ultravisor.h>
#include <asm/prom.h>
#include <asm/plpks.h>
#include <mm/mmu_decl.h>
@ -370,8 +371,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
be32_to_cpu(intserv[found_thread]));
boot_cpuid = found;
// Pass the boot CPU's hard CPU id back to our caller
*((u32 *)data) = be32_to_cpu(intserv[found_thread]);
if (IS_ENABLED(CONFIG_PPC64))
boot_cpu_hwid = be32_to_cpu(intserv[found_thread]);
/*
* PAPR defines "logical" PVR values for cpus that
@ -755,7 +756,6 @@ static inline void save_fscr_to_task(void) {}
void __init early_init_devtree(void *params)
{
u32 boot_cpu_hwid;
phys_addr_t limit;
DBG(" -> early_init_devtree(%px)\n", params);
@ -851,7 +851,7 @@ void __init early_init_devtree(void *params)
/* Retrieve CPU related informations from the flat tree
* (altivec support, boot CPU ID, ...)
*/
of_scan_flat_dt(early_init_dt_scan_cpus, &boot_cpu_hwid);
of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
if (boot_cpuid < 0) {
printk("Failed to identify boot CPU !\n");
BUG();
@ -868,11 +868,6 @@ void __init early_init_devtree(void *params)
mmu_early_init_devtree();
// NB. paca is not installed until later in early_setup()
allocate_paca_ptrs();
allocate_paca(boot_cpuid);
set_hard_smp_processor_id(boot_cpuid, boot_cpu_hwid);
#ifdef CONFIG_PPC_POWERNV
/* Scan and build the list of machine check recoverable ranges */
of_scan_flat_dt(early_init_dt_scan_recoverable_ranges, NULL);
@ -893,6 +888,9 @@ void __init early_init_devtree(void *params)
powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE;
#endif
/* If kexec left a PLPKS password in the DT, get it and clear it */
plpks_early_init_devtree();
tm_init();
DBG(" <- early_init_devtree()\n");

View File

@ -287,9 +287,9 @@ static ssize_t ppc_rtas_poweron_write(struct file *file,
rtc_time64_to_tm(nowtime, &tm);
error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_FOR_POWER_ON), 7, 1, NULL,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
if (error)
printk(KERN_WARNING "error: setting poweron time returned: %s\n",
ppc_rtas_process_error(error));
@ -350,9 +350,9 @@ static ssize_t ppc_rtas_clock_write(struct file *file,
return error;
rtc_time64_to_tm(nowtime, &tm);
error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
if (error)
printk(KERN_WARNING "error: setting the clock returned: %s\n",
ppc_rtas_process_error(error));
@ -362,7 +362,7 @@ static ssize_t ppc_rtas_clock_write(struct file *file,
static int ppc_rtas_clock_show(struct seq_file *m, void *v)
{
int ret[8];
int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
int error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);
if (error) {
printk(KERN_WARNING "error: reading the clock returned: %s\n",
@ -385,7 +385,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
{
int i,j;
int state, error;
int get_sensor_state = rtas_token("get-sensor-state");
int get_sensor_state = rtas_function_token(RTAS_FN_GET_SENSOR_STATE);
seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n");
seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n");
@ -708,8 +708,8 @@ static ssize_t ppc_rtas_tone_freq_write(struct file *file,
return error;
rtas_tone_frequency = freq; /* save it for later */
error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
TONE_FREQUENCY, 0, freq);
error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
TONE_FREQUENCY, 0, freq);
if (error)
printk(KERN_WARNING "error: setting tone frequency returned: %s\n",
ppc_rtas_process_error(error));
@ -736,8 +736,8 @@ static ssize_t ppc_rtas_tone_volume_write(struct file *file,
volume = 100;
rtas_tone_volume = volume; /* save it for later */
error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
TONE_VOLUME, 0, volume);
error = rtas_call(rtas_function_token(RTAS_FN_SET_INDICATOR), 3, 1, NULL,
TONE_VOLUME, 0, volume);
if (error)
printk(KERN_WARNING "error: setting tone volume returned: %s\n",
ppc_rtas_process_error(error));

View File

@ -21,7 +21,7 @@ time64_t __init rtas_get_boot_time(void)
max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
do {
error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);
wait_time = rtas_busy_delay_time(error);
if (wait_time) {
@ -53,7 +53,7 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)
max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
do {
error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
error = rtas_call(rtas_function_token(RTAS_FN_GET_TIME_OF_DAY), 0, 8, ret);
wait_time = rtas_busy_delay_time(error);
if (wait_time) {
@ -90,7 +90,7 @@ int rtas_set_rtc_time(struct rtc_time *tm)
max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
do {
error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
error = rtas_call(rtas_function_token(RTAS_FN_SET_TIME_OF_DAY), 7, 1, NULL,
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec, 0);

File diff suppressed because it is too large Load Diff

View File

@ -376,7 +376,7 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf, unsigned int op)
s32 rc;
do {
rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1,
rc = rtas_call(rtas_function_token(RTAS_FN_IBM_MANAGE_FLASH_IMAGE), 1, 1,
NULL, op);
} while (rtas_busy_delay(rc));
@ -444,7 +444,7 @@ error:
*/
static void validate_flash(struct rtas_validate_flash_t *args_buf)
{
int token = rtas_token("ibm,validate-flash-image");
int token = rtas_function_token(RTAS_FN_IBM_VALIDATE_FLASH_IMAGE);
int update_results;
s32 rc;
@ -570,7 +570,7 @@ static void rtas_flash_firmware(int reboot_type)
return;
}
update_token = rtas_token("ibm,update-flash-64-and-reboot");
update_token = rtas_function_token(RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT);
if (update_token == RTAS_UNKNOWN_SERVICE) {
printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot "
"is not available -- not a service partition?\n");
@ -653,7 +653,7 @@ static void rtas_flash_firmware(int reboot_type)
*/
struct rtas_flash_file {
const char *filename;
const char *rtas_call_name;
const rtas_fn_handle_t handle;
int *status;
const struct proc_ops ops;
};
@ -661,7 +661,7 @@ struct rtas_flash_file {
static const struct rtas_flash_file rtas_flash_files[] = {
{
.filename = "powerpc/rtas/" FIRMWARE_FLASH_NAME,
.rtas_call_name = "ibm,update-flash-64-and-reboot",
.handle = RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT,
.status = &rtas_update_flash_data.status,
.ops.proc_read = rtas_flash_read_msg,
.ops.proc_write = rtas_flash_write,
@ -670,7 +670,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
},
{
.filename = "powerpc/rtas/" FIRMWARE_UPDATE_NAME,
.rtas_call_name = "ibm,update-flash-64-and-reboot",
.handle = RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT,
.status = &rtas_update_flash_data.status,
.ops.proc_read = rtas_flash_read_num,
.ops.proc_write = rtas_flash_write,
@ -679,7 +679,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
},
{
.filename = "powerpc/rtas/" VALIDATE_FLASH_NAME,
.rtas_call_name = "ibm,validate-flash-image",
.handle = RTAS_FN_IBM_VALIDATE_FLASH_IMAGE,
.status = &rtas_validate_flash_data.status,
.ops.proc_read = validate_flash_read,
.ops.proc_write = validate_flash_write,
@ -688,7 +688,7 @@ static const struct rtas_flash_file rtas_flash_files[] = {
},
{
.filename = "powerpc/rtas/" MANAGE_FLASH_NAME,
.rtas_call_name = "ibm,manage-flash-image",
.handle = RTAS_FN_IBM_MANAGE_FLASH_IMAGE,
.status = &rtas_manage_flash_data.status,
.ops.proc_read = manage_flash_read,
.ops.proc_write = manage_flash_write,
@ -700,8 +700,7 @@ static int __init rtas_flash_init(void)
{
int i;
if (rtas_token("ibm,update-flash-64-and-reboot") ==
RTAS_UNKNOWN_SERVICE) {
if (rtas_function_token(RTAS_FN_IBM_UPDATE_FLASH_64_AND_REBOOT) == RTAS_UNKNOWN_SERVICE) {
pr_info("rtas_flash: no firmware flash support\n");
return -EINVAL;
}
@ -730,7 +729,7 @@ static int __init rtas_flash_init(void)
* This code assumes that the status int is the first member of the
* struct
*/
token = rtas_token(f->rtas_call_name);
token = rtas_function_token(f->handle);
if (token == RTAS_UNKNOWN_SERVICE)
*f->status = FLASH_AUTH;
else

View File

@ -191,10 +191,10 @@ static void python_countermeasures(struct device_node *dev)
void __init init_pci_config_tokens(void)
{
read_pci_config = rtas_token("read-pci-config");
write_pci_config = rtas_token("write-pci-config");
ibm_read_pci_config = rtas_token("ibm,read-pci-config");
ibm_write_pci_config = rtas_token("ibm,write-pci-config");
read_pci_config = rtas_function_token(RTAS_FN_READ_PCI_CONFIG);
write_pci_config = rtas_function_token(RTAS_FN_WRITE_PCI_CONFIG);
ibm_read_pci_config = rtas_function_token(RTAS_FN_IBM_READ_PCI_CONFIG);
ibm_write_pci_config = rtas_function_token(RTAS_FN_IBM_WRITE_PCI_CONFIG);
}
unsigned long get_phb_buid(struct device_node *phb)

View File

@ -506,7 +506,7 @@ static int __init rtas_event_scan_init(void)
return 0;
/* No RTAS */
event_scan = rtas_token("event-scan");
event_scan = rtas_function_token(RTAS_FN_EVENT_SCAN);
if (event_scan == RTAS_UNKNOWN_SERVICE) {
printk(KERN_INFO "rtasd: No event-scan on system\n");
return -ENODEV;

View File

@ -8,10 +8,16 @@
#include <linux/cache.h>
#include <asm/secvar.h>
#include <asm/bug.h>
const struct secvar_operations *secvar_ops __ro_after_init;
const struct secvar_operations *secvar_ops __ro_after_init = NULL;
void set_secvar_ops(const struct secvar_operations *ops)
int set_secvar_ops(const struct secvar_operations *ops)
{
if (WARN_ON_ONCE(secvar_ops))
return -EBUSY;
secvar_ops = ops;
return 0;
}

View File

@ -21,56 +21,48 @@ static struct kset *secvar_kset;
static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
ssize_t rc = 0;
struct device_node *node;
const char *format;
char tmp[32];
ssize_t len = secvar_ops->format(tmp, sizeof(tmp));
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
if (!of_device_is_available(node)) {
rc = -ENODEV;
goto out;
}
if (len > 0)
return sysfs_emit(buf, "%s\n", tmp);
else if (len < 0)
pr_err("Error %zd reading format string\n", len);
else
pr_err("Got empty format string from backend\n");
rc = of_property_read_string(node, "format", &format);
if (rc)
goto out;
rc = sprintf(buf, "%s\n", format);
out:
of_node_put(node);
return rc;
return -EIO;
}
static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
uint64_t dsize;
u64 dsize;
int rc;
rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
if (rc) {
pr_err("Error retrieving %s variable size %d\n", kobj->name,
rc);
if (rc != -ENOENT)
pr_err("Error retrieving %s variable size %d\n", kobj->name, rc);
return rc;
}
return sprintf(buf, "%llu\n", dsize);
return sysfs_emit(buf, "%llu\n", dsize);
}
static ssize_t data_read(struct file *filep, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off,
size_t count)
{
uint64_t dsize;
char *data;
u64 dsize;
int rc;
rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
if (rc) {
pr_err("Error getting %s variable size %d\n", kobj->name, rc);
if (rc != -ENOENT)
pr_err("Error getting %s variable size %d\n", kobj->name, rc);
return rc;
}
pr_debug("dsize is %llu\n", dsize);
@ -141,34 +133,58 @@ static struct kobj_type secvar_ktype = {
static int update_kobj_size(void)
{
struct device_node *node;
u64 varsize;
int rc = 0;
int rc = secvar_ops->max_size(&varsize);
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
if (!of_device_is_available(node)) {
rc = -ENODEV;
goto out;
}
rc = of_property_read_u64(node, "max-var-size", &varsize);
if (rc)
goto out;
return rc;
data_attr.size = varsize;
update_attr.size = varsize;
out:
of_node_put(node);
return 0;
}
return rc;
static int secvar_sysfs_config(struct kobject *kobj)
{
struct attribute_group config_group = {
.name = "config",
.attrs = (struct attribute **)secvar_ops->config_attrs,
};
if (secvar_ops->config_attrs)
return sysfs_create_group(kobj, &config_group);
return 0;
}
static int add_var(const char *name)
{
struct kobject *kobj;
int rc;
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return -ENOMEM;
kobject_init(kobj, &secvar_ktype);
rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
if (rc) {
pr_warn("kobject_add error %d for attribute: %s\n", rc,
name);
kobject_put(kobj);
return rc;
}
kobject_uevent(kobj, KOBJ_ADD);
return 0;
}
static int secvar_sysfs_load(void)
{
u64 namesize = 0;
char *name;
uint64_t namesize = 0;
struct kobject *kobj;
int rc;
name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
@ -179,73 +195,99 @@ static int secvar_sysfs_load(void)
rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
if (rc) {
if (rc != -ENOENT)
pr_err("error getting secvar from firmware %d\n",
rc);
pr_err("error getting secvar from firmware %d\n", rc);
else
rc = 0;
break;
}
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj) {
rc = -ENOMEM;
break;
}
kobject_init(kobj, &secvar_ktype);
rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
if (rc) {
pr_warn("kobject_add error %d for attribute: %s\n", rc,
name);
kobject_put(kobj);
kobj = NULL;
}
if (kobj)
kobject_uevent(kobj, KOBJ_ADD);
rc = add_var(name);
} while (!rc);
kfree(name);
return rc;
}
static int secvar_sysfs_load_static(void)
{
const char * const *name_ptr = secvar_ops->var_names;
int rc;
while (*name_ptr) {
rc = add_var(*name_ptr);
if (rc)
return rc;
name_ptr++;
}
return 0;
}
static int secvar_sysfs_init(void)
{
u64 max_size;
int rc;
if (!secvar_ops) {
pr_warn("secvar: failed to retrieve secvar operations.\n");
pr_warn("Failed to retrieve secvar operations\n");
return -ENODEV;
}
secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
if (!secvar_kobj) {
pr_err("secvar: Failed to create firmware kobj\n");
pr_err("Failed to create firmware kobj\n");
return -ENOMEM;
}
rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
if (rc) {
kobject_put(secvar_kobj);
return -ENOMEM;
pr_err("Failed to create format object\n");
rc = -ENOMEM;
goto err;
}
secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
if (!secvar_kset) {
pr_err("secvar: sysfs kobject registration failed.\n");
kobject_put(secvar_kobj);
return -ENOMEM;
pr_err("sysfs kobject registration failed\n");
rc = -ENOMEM;
goto err;
}
rc = update_kobj_size();
if (rc) {
pr_err("Cannot read the size of the attribute\n");
return rc;
goto err;
}
secvar_sysfs_load();
rc = secvar_sysfs_config(secvar_kobj);
if (rc) {
pr_err("Failed to create config directory\n");
goto err;
}
if (secvar_ops->get_next)
rc = secvar_sysfs_load();
else
rc = secvar_sysfs_load_static();
if (rc) {
pr_err("Failed to create variable attributes\n");
goto err;
}
// Due to sysfs limitations, we will only ever get a write buffer of
// up to 1 page in size. Print a warning if this is potentially going
// to cause problems, so that the user is aware.
secvar_ops->max_size(&max_size);
if (max_size > PAGE_SIZE)
pr_warn_ratelimited("PAGE_SIZE (%lu) is smaller than maximum object size (%llu), writes are limited to PAGE_SIZE\n",
PAGE_SIZE, max_size);
return 0;
err:
kobject_put(secvar_kobj);
return rc;
}
late_initcall(secvar_sysfs_init);

View File

@ -87,6 +87,10 @@ EXPORT_SYMBOL(machine_id);
int boot_cpuid = -1;
EXPORT_SYMBOL_GPL(boot_cpuid);
#ifdef CONFIG_PPC64
int boot_cpu_hwid = -1;
#endif
/*
* These are used in binfmt_elf.c to put aux entries on the stack
* for each elf executable being started.

View File

@ -385,17 +385,21 @@ void __init early_setup(unsigned long dt_ptr)
/*
* Do early initialization using the flattened device
* tree, such as retrieving the physical memory map or
* calculating/retrieving the hash table size.
* calculating/retrieving the hash table size, discover
* boot_cpuid and boot_cpu_hwid.
*/
early_init_devtree(__va(dt_ptr));
/* Now we know the logical id of our boot cpu, setup the paca. */
if (boot_cpuid != 0) {
/* Poison paca_ptrs[0] again if it's not the boot cpu */
memset(&paca_ptrs[0], 0x88, sizeof(paca_ptrs[0]));
}
allocate_paca_ptrs();
allocate_paca(boot_cpuid);
set_hard_smp_processor_id(boot_cpuid, boot_cpu_hwid);
fixup_boot_paca(paca_ptrs[boot_cpuid]);
setup_paca(paca_ptrs[boot_cpuid]); /* install the paca into registers */
// smp_processor_id() now reports boot_cpuid
#ifdef CONFIG_SMP
task_thread_info(current)->cpu = boot_cpuid; // fix task_cpu(current)
#endif
/*
* Configure exception handlers. This include setting up trampolines

View File

@ -356,7 +356,7 @@ void vtime_flush(struct task_struct *tsk)
}
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
void __delay(unsigned long loops)
void __no_kcsan __delay(unsigned long loops)
{
unsigned long start;
@ -377,7 +377,7 @@ void __delay(unsigned long loops)
}
EXPORT_SYMBOL(__delay);
void udelay(unsigned long usecs)
void __no_kcsan udelay(unsigned long usecs)
{
__delay(tb_ticks_per_usec * usecs);
}

View File

@ -23,4 +23,5 @@ obj-$(CONFIG_PPC32) += $(obj32-y)
# Disable GCOV, KCOV & sanitizers in odd or sensitive code
GCOV_PROFILE_ftrace.o := n
KCOV_INSTRUMENT_ftrace.o := n
KCSAN_SANITIZE_ftrace.o := n
UBSAN_SANITIZE_ftrace.o := n

View File

@ -46,6 +46,7 @@ GCOV_PROFILE := n
KCOV_INSTRUMENT := n
UBSAN_SANITIZE := n
KASAN_SANITIZE := n
KCSAN_SANITIZE := n
ccflags-y := -shared -fno-common -fno-builtin -nostdlib -Wl,--hash-style=both
ccflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld)

View File

@ -28,6 +28,7 @@
#include <asm/crashdump-ppc64.h>
#include <asm/mmzone.h>
#include <asm/prom.h>
#include <asm/plpks.h>
struct umem_info {
u64 *buf; /* data buffer for usable-memory property */
@ -689,7 +690,8 @@ static int update_usable_mem_fdt(void *fdt, struct crash_mem *usable_mem)
ret = fdt_setprop(fdt, node, "linux,drconf-usable-memory",
um_info.buf, (um_info.idx * sizeof(u64)));
if (ret) {
pr_err("Failed to update fdt with linux,drconf-usable-memory property");
pr_err("Failed to update fdt with linux,drconf-usable-memory property: %s",
fdt_strerror(ret));
goto out;
}
}
@ -978,12 +980,17 @@ static unsigned int cpu_node_size(void)
*/
unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
{
unsigned int cpu_nodes, extra_size;
unsigned int cpu_nodes, extra_size = 0;
struct device_node *dn;
u64 usm_entries;
// Budget some space for the password blob. There's already extra space
// for the key name
if (plpks_is_available())
extra_size += (unsigned int)plpks_get_passwordlen();
if (image->type != KEXEC_TYPE_CRASH)
return 0;
return extra_size;
/*
* For kdump kernel, account for linux,usable-memory and
@ -993,9 +1000,7 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
if (drmem_lmb_size()) {
usm_entries = ((memory_hotplug_max() / drmem_lmb_size()) +
(2 * (resource_size(&crashk_res) / drmem_lmb_size())));
extra_size = (unsigned int)(usm_entries * sizeof(u64));
} else {
extra_size = 0;
extra_size += (unsigned int)(usm_entries * sizeof(u64));
}
/*
@ -1234,6 +1239,10 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
}
}
// If we have PLPKS active, we need to provide the password to the new kernel
if (plpks_is_available())
ret = plpks_populate_fdt(fdt);
out:
kfree(rmem);
kfree(umem);

View File

@ -16,6 +16,8 @@ KASAN_SANITIZE_feature-fixups.o := n
# restart_table.o contains functions called in the NMI interrupt path
# which can be in real mode. Disable KASAN.
KASAN_SANITIZE_restart_table.o := n
KCSAN_SANITIZE_code-patching.o := n
KCSAN_SANITIZE_feature-fixups.o := n
ifdef CONFIG_KASAN
CFLAGS_code-patching.o += -DDISABLE_BRANCH_PROFILING

View File

@ -1051,7 +1051,8 @@ static void __init htab_initialize(void)
static_branch_enable(&stress_hpt_key);
// Too early to use nr_cpu_ids, so use NR_CPUS
tmp = memblock_phys_alloc_range(sizeof(struct stress_hpt_struct) * NR_CPUS,
0, 0, MEMBLOCK_ALLOC_ANYWHERE);
__alignof__(struct stress_hpt_struct),
0, MEMBLOCK_ALLOC_ANYWHERE);
memset((void *)tmp, 0xff, sizeof(struct stress_hpt_struct) * NR_CPUS);
stress_hpt_struct = __va(tmp);

View File

@ -700,12 +700,13 @@ static inline void _tlbiel_va_range_multicast(struct mm_struct *mm,
*/
void radix__local_flush_tlb_mm(struct mm_struct *mm)
{
unsigned long pid;
unsigned long pid = mm->context.id;
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
pid = mm->context.id;
if (pid != MMU_NO_CONTEXT)
_tlbiel_pid(pid, RIC_FLUSH_TLB);
_tlbiel_pid(pid, RIC_FLUSH_TLB);
preempt_enable();
}
EXPORT_SYMBOL(radix__local_flush_tlb_mm);
@ -713,12 +714,13 @@ EXPORT_SYMBOL(radix__local_flush_tlb_mm);
#ifndef CONFIG_SMP
void radix__local_flush_all_mm(struct mm_struct *mm)
{
unsigned long pid;
unsigned long pid = mm->context.id;
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
pid = mm->context.id;
if (pid != MMU_NO_CONTEXT)
_tlbiel_pid(pid, RIC_FLUSH_ALL);
_tlbiel_pid(pid, RIC_FLUSH_ALL);
preempt_enable();
}
EXPORT_SYMBOL(radix__local_flush_all_mm);
@ -732,12 +734,13 @@ static void __flush_all_mm(struct mm_struct *mm, bool fullmm)
void radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
int psize)
{
unsigned long pid;
unsigned long pid = mm->context.id;
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
pid = mm->context.id;
if (pid != MMU_NO_CONTEXT)
_tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB);
_tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB);
preempt_enable();
}
@ -945,7 +948,7 @@ void radix__flush_tlb_mm(struct mm_struct *mm)
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
@ -985,7 +988,7 @@ static void __flush_all_mm(struct mm_struct *mm, bool fullmm)
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
@ -1024,7 +1027,7 @@ void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr,
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
preempt_disable();
@ -1104,6 +1107,9 @@ void radix__flush_tlb_kernel_range(unsigned long start, unsigned long end)
}
EXPORT_SYMBOL(radix__flush_tlb_kernel_range);
/*
* Doesn't appear to be used anywhere. Remove.
*/
#define TLB_FLUSH_ALL -1UL
/*
@ -1125,23 +1131,22 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm,
unsigned int page_shift = mmu_psize_defs[mmu_virtual_psize].shift;
unsigned long page_size = 1UL << page_shift;
unsigned long nr_pages = (end - start) >> page_shift;
bool fullmm = (end == TLB_FLUSH_ALL);
bool flush_pid, flush_pwc = false;
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
WARN_ON_ONCE(end == TLB_FLUSH_ALL);
preempt_disable();
smp_mb(); /* see radix__flush_tlb_mm */
type = flush_type_needed(mm, fullmm);
type = flush_type_needed(mm, false);
if (type == FLUSH_TYPE_NONE)
goto out;
if (fullmm)
flush_pid = true;
else if (type == FLUSH_TYPE_GLOBAL)
if (type == FLUSH_TYPE_GLOBAL)
flush_pid = nr_pages > tlb_single_page_flush_ceiling;
else
flush_pid = nr_pages > tlb_local_single_page_flush_ceiling;
@ -1179,15 +1184,12 @@ static inline void __radix__flush_tlb_range(struct mm_struct *mm,
}
}
} else {
bool hflush = false;
bool hflush;
unsigned long hstart, hend;
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
hstart = (start + PMD_SIZE - 1) & PMD_MASK;
hend = end & PMD_MASK;
if (hstart < hend)
hflush = true;
}
hstart = (start + PMD_SIZE - 1) & PMD_MASK;
hend = end & PMD_MASK;
hflush = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && hstart < hend;
if (type == FLUSH_TYPE_LOCAL) {
asm volatile("ptesync": : :"memory");
@ -1302,7 +1304,7 @@ void radix__tlb_flush(struct mmu_gather *tlb)
* that flushes the process table entry cache upon process teardown.
* See the comment for radix in arch_exit_mmap().
*/
if (tlb->fullmm || tlb->need_flush_all) {
if (tlb->fullmm) {
__flush_all_mm(mm, true);
} else if ( (psize = radix_get_mmu_psize(page_size)) == -1) {
if (!tlb->freed_tables)
@ -1325,25 +1327,22 @@ static void __radix__flush_tlb_range_psize(struct mm_struct *mm,
unsigned int page_shift = mmu_psize_defs[psize].shift;
unsigned long page_size = 1UL << page_shift;
unsigned long nr_pages = (end - start) >> page_shift;
bool fullmm = (end == TLB_FLUSH_ALL);
bool flush_pid;
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
fullmm = (end == TLB_FLUSH_ALL);
WARN_ON_ONCE(end == TLB_FLUSH_ALL);
preempt_disable();
smp_mb(); /* see radix__flush_tlb_mm */
type = flush_type_needed(mm, fullmm);
type = flush_type_needed(mm, false);
if (type == FLUSH_TYPE_NONE)
goto out;
if (fullmm)
flush_pid = true;
else if (type == FLUSH_TYPE_GLOBAL)
if (type == FLUSH_TYPE_GLOBAL)
flush_pid = nr_pages > tlb_single_page_flush_ceiling;
else
flush_pid = nr_pages > tlb_local_single_page_flush_ceiling;
@ -1406,7 +1405,7 @@ void radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr)
enum tlb_flush_type type;
pid = mm->context.id;
if (unlikely(pid == MMU_NO_CONTEXT))
if (WARN_ON_ONCE(pid == MMU_NO_CONTEXT))
return;
/* 4k page size, just blow the world */

View File

@ -120,6 +120,7 @@ extern int switch_to_as1(void);
extern void restore_to_as0(int esel, int offset, void *dt_ptr, int bootcpu);
void create_kaslr_tlb_entry(int entry, unsigned long virt, phys_addr_t phys);
void reloc_kernel_entry(void *fdt, int addr);
void relocate_init(u64 dt_ptr, phys_addr_t start);
extern int is_second_reloc;
#endif
extern void loadcam_entry(unsigned int index);

View File

@ -45,7 +45,9 @@ static inline void book3e_tlb_lock(void)
if (!cpu_has_feature(CPU_FTR_SMT))
return;
asm volatile("1: lbarx %0, 0, %1;"
asm volatile(".machine push;"
".machine e6500;"
"1: lbarx %0, 0, %1;"
"cmpwi %0, 0;"
"bne 2f;"
"stbcx. %2, 0, %1;"
@ -56,6 +58,7 @@ static inline void book3e_tlb_lock(void)
"bne 2b;"
"b 1b;"
"3:"
".machine pop;"
: "=&r" (tmp)
: "r" (&paca->tcd_ptr->lock), "r" (token)
: "memory");

View File

@ -351,7 +351,7 @@ END_FTR_SECTION_NESTED(CPU_FTR_EMB_HV,CPU_FTR_EMB_HV,532)
mfspr r15,SPRN_MAS2
isync
tlbilxva 0,r15
PPC_TLBILX_VA(0,R15)
isync
mtspr SPRN_MAS6,r10

View File

@ -169,7 +169,7 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
void bpf_jit_init_reg_mapping(struct codegen_context *ctx);
int bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
u32 *addrs, int pass);
u32 *addrs, int pass, bool extra_pass);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx);
void bpf_jit_realloc_regs(struct codegen_context *ctx);

View File

@ -23,74 +23,6 @@ static void bpf_jit_fill_ill_insns(void *area, unsigned int size)
memset32(area, BREAKPOINT_INSTRUCTION, size / 4);
}
/* Fix updated addresses (for subprog calls, ldimm64, et al) during extra pass */
static int bpf_jit_fixup_addresses(struct bpf_prog *fp, u32 *image,
struct codegen_context *ctx, u32 *addrs)
{
const struct bpf_insn *insn = fp->insnsi;
bool func_addr_fixed;
u64 func_addr;
u32 tmp_idx;
int i, j, ret;
for (i = 0; i < fp->len; i++) {
/*
* During the extra pass, only the branch target addresses for
* the subprog calls need to be fixed. All other instructions
* can left untouched.
*
* The JITed image length does not change because we already
* ensure that the JITed instruction sequence for these calls
* are of fixed length by padding them with NOPs.
*/
if (insn[i].code == (BPF_JMP | BPF_CALL) &&
insn[i].src_reg == BPF_PSEUDO_CALL) {
ret = bpf_jit_get_func_addr(fp, &insn[i], true,
&func_addr,
&func_addr_fixed);
if (ret < 0)
return ret;
/*
* Save ctx->idx as this would currently point to the
* end of the JITed image and set it to the offset of
* the instruction sequence corresponding to the
* subprog call temporarily.
*/
tmp_idx = ctx->idx;
ctx->idx = addrs[i] / 4;
ret = bpf_jit_emit_func_call_rel(image, ctx, func_addr);
if (ret)
return ret;
/*
* Restore ctx->idx here. This is safe as the length
* of the JITed sequence remains unchanged.
*/
ctx->idx = tmp_idx;
} else if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) {
tmp_idx = ctx->idx;
ctx->idx = addrs[i] / 4;
#ifdef CONFIG_PPC32
PPC_LI32(bpf_to_ppc(insn[i].dst_reg) - 1, (u32)insn[i + 1].imm);
PPC_LI32(bpf_to_ppc(insn[i].dst_reg), (u32)insn[i].imm);
for (j = ctx->idx - addrs[i] / 4; j < 4; j++)
EMIT(PPC_RAW_NOP());
#else
func_addr = ((u64)(u32)insn[i].imm) | (((u64)(u32)insn[i + 1].imm) << 32);
PPC_LI64(bpf_to_ppc(insn[i].dst_reg), func_addr);
/* overwrite rest with nops */
for (j = ctx->idx - addrs[i] / 4; j < 5; j++)
EMIT(PPC_RAW_NOP());
#endif
ctx->idx = tmp_idx;
i++;
}
}
return 0;
}
int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr)
{
if (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx->idx * 4))) {
@ -185,7 +117,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
cgctx.stack_size = round_up(fp->aux->stack_depth, 16);
/* Scouting faux-generate pass 0 */
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0, false)) {
/* We hit something illegal or unsupported. */
fp = org_fp;
goto out_addrs;
@ -200,7 +132,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
*/
if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
cgctx.idx = 0;
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0)) {
if (bpf_jit_build_body(fp, 0, &cgctx, addrs, 0, false)) {
fp = org_fp;
goto out_addrs;
}
@ -234,29 +166,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
skip_init_ctx:
code_base = (u32 *)(image + FUNCTION_DESCR_SIZE);
if (extra_pass) {
/*
* Do not touch the prologue and epilogue as they will remain
* unchanged. Only fix the branch target address for subprog
* calls in the body, and ldimm64 instructions.
*
* This does not change the offsets and lengths of the subprog
* call instruction sequences and hence, the size of the JITed
* image as well.
*/
bpf_jit_fixup_addresses(fp, code_base, &cgctx, addrs);
/* There is no need to perform the usual passes. */
goto skip_codegen_passes;
}
/* Code generation passes 1-2 */
for (pass = 1; pass < 3; pass++) {
/* Now build the prologue, body code & epilogue for real. */
cgctx.idx = 0;
cgctx.alt_exit_addr = 0;
bpf_jit_build_prologue(code_base, &cgctx);
if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass)) {
if (bpf_jit_build_body(fp, code_base, &cgctx, addrs, pass, extra_pass)) {
bpf_jit_binary_free(bpf_hdr);
fp = org_fp;
goto out_addrs;
@ -268,7 +184,6 @@ skip_init_ctx:
proglen - (cgctx.idx * 4), cgctx.seen);
}
skip_codegen_passes:
if (bpf_jit_enable > 1)
/*
* Note that we output the base address of the code_base

View File

@ -79,6 +79,20 @@ static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
#define SEEN_NVREG_FULL_MASK 0x0003ffff /* Non volatile registers r14-r31 */
#define SEEN_NVREG_TEMP_MASK 0x00001e01 /* BPF_REG_5, BPF_REG_AX, TMP_REG */
static inline bool bpf_has_stack_frame(struct codegen_context *ctx)
{
/*
* We only need a stack frame if:
* - we call other functions (kernel helpers), or
* - we use non volatile registers, or
* - we use tail call counter
* - the bpf program uses its stack area
* The latter condition is deduced from the usage of BPF_REG_FP
*/
return ctx->seen & (SEEN_FUNC | SEEN_TAILCALL | SEEN_NVREG_FULL_MASK) ||
bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_FP));
}
void bpf_jit_realloc_regs(struct codegen_context *ctx)
{
unsigned int nvreg_mask;
@ -114,11 +128,15 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
int i;
/* Initialize tail_call_cnt, to be skipped if we do tail calls. */
EMIT(PPC_RAW_LI(_R4, 0));
if (ctx->seen & SEEN_TAILCALL)
EMIT(PPC_RAW_LI(_R4, 0));
else
EMIT(PPC_RAW_NOP());
#define BPF_TAILCALL_PROLOGUE_SIZE 4
EMIT(PPC_RAW_STWU(_R1, _R1, -BPF_PPC_STACKFRAME(ctx)));
if (bpf_has_stack_frame(ctx))
EMIT(PPC_RAW_STWU(_R1, _R1, -BPF_PPC_STACKFRAME(ctx)));
if (ctx->seen & SEEN_TAILCALL)
EMIT(PPC_RAW_STW(_R4, _R1, bpf_jit_stack_offsetof(ctx, BPF_PPC_TC)));
@ -141,12 +159,6 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
if (bpf_is_seen_register(ctx, i))
EMIT(PPC_RAW_STW(i, _R1, bpf_jit_stack_offsetof(ctx, i)));
/* If needed retrieve arguments 9 and 10, ie 5th 64 bits arg.*/
if (bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_5))) {
EMIT(PPC_RAW_LWZ(bpf_to_ppc(BPF_REG_5) - 1, _R1, BPF_PPC_STACKFRAME(ctx)) + 8);
EMIT(PPC_RAW_LWZ(bpf_to_ppc(BPF_REG_5), _R1, BPF_PPC_STACKFRAME(ctx)) + 12);
}
/* Setup frame pointer to point to the bpf stack area */
if (bpf_is_seen_register(ctx, bpf_to_ppc(BPF_REG_FP))) {
EMIT(PPC_RAW_LI(bpf_to_ppc(BPF_REG_FP) - 1, 0));
@ -171,7 +183,8 @@ static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx
EMIT(PPC_RAW_LWZ(_R0, _R1, BPF_PPC_STACKFRAME(ctx) + PPC_LR_STKOFF));
/* Tear down our stack frame */
EMIT(PPC_RAW_ADDI(_R1, _R1, BPF_PPC_STACKFRAME(ctx)));
if (bpf_has_stack_frame(ctx))
EMIT(PPC_RAW_ADDI(_R1, _R1, BPF_PPC_STACKFRAME(ctx)));
if (ctx->seen & SEEN_FUNC)
EMIT(PPC_RAW_MTLR(_R0));
@ -193,9 +206,6 @@ int bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func
if (image && rel < 0x2000000 && rel >= -0x2000000) {
PPC_BL(func);
EMIT(PPC_RAW_NOP());
EMIT(PPC_RAW_NOP());
EMIT(PPC_RAW_NOP());
} else {
/* Load function address into r0 */
EMIT(PPC_RAW_LIS(_R0, IMM_H(func)));
@ -269,7 +279,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
u32 *addrs, int pass)
u32 *addrs, int pass, bool extra_pass)
{
const struct bpf_insn *insn = fp->insnsi;
int flen = fp->len;
@ -280,10 +290,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
for (i = 0; i < flen; i++) {
u32 code = insn[i].code;
u32 prevcode = i ? insn[i - 1].code : 0;
u32 dst_reg = bpf_to_ppc(insn[i].dst_reg);
u32 dst_reg_h = dst_reg - 1;
u32 src_reg = bpf_to_ppc(insn[i].src_reg);
u32 src_reg_h = src_reg - 1;
u32 src2_reg = dst_reg;
u32 src2_reg_h = dst_reg_h;
u32 ax_reg = bpf_to_ppc(BPF_REG_AX);
u32 tmp_reg = bpf_to_ppc(TMP_REG);
u32 size = BPF_SIZE(code);
@ -296,6 +309,15 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
u32 tmp_idx;
int j;
if (i && (BPF_CLASS(code) == BPF_ALU64 || BPF_CLASS(code) == BPF_ALU) &&
(BPF_CLASS(prevcode) == BPF_ALU64 || BPF_CLASS(prevcode) == BPF_ALU) &&
BPF_OP(prevcode) == BPF_MOV && BPF_SRC(prevcode) == BPF_X &&
insn[i - 1].dst_reg == insn[i].dst_reg && insn[i - 1].imm != 1) {
src2_reg = bpf_to_ppc(insn[i - 1].src_reg);
src2_reg_h = src2_reg - 1;
ctx->idx = addrs[i - 1] / 4;
}
/*
* addrs[] maps a BPF bytecode address into a real offset from
* the start of the body code.
@ -328,95 +350,111 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* Arithmetic operations: ADD/SUB/MUL/DIV/MOD/NEG
*/
case BPF_ALU | BPF_ADD | BPF_X: /* (u32) dst += (u32) src */
EMIT(PPC_RAW_ADD(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_ADD(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_ADD | BPF_X: /* dst += src */
EMIT(PPC_RAW_ADDC(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_ADDE(dst_reg_h, dst_reg_h, src_reg_h));
EMIT(PPC_RAW_ADDC(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_ADDE(dst_reg_h, src2_reg_h, src_reg_h));
break;
case BPF_ALU | BPF_SUB | BPF_X: /* (u32) dst -= (u32) src */
EMIT(PPC_RAW_SUB(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SUB(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_SUB | BPF_X: /* dst -= src */
EMIT(PPC_RAW_SUBFC(dst_reg, src_reg, dst_reg));
EMIT(PPC_RAW_SUBFE(dst_reg_h, src_reg_h, dst_reg_h));
EMIT(PPC_RAW_SUBFC(dst_reg, src_reg, src2_reg));
EMIT(PPC_RAW_SUBFE(dst_reg_h, src_reg_h, src2_reg_h));
break;
case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */
imm = -imm;
fallthrough;
case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */
if (IMM_HA(imm) & 0xffff)
EMIT(PPC_RAW_ADDIS(dst_reg, dst_reg, IMM_HA(imm)));
if (!imm) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
} else if (IMM_HA(imm) & 0xffff) {
EMIT(PPC_RAW_ADDIS(dst_reg, src2_reg, IMM_HA(imm)));
src2_reg = dst_reg;
}
if (IMM_L(imm))
EMIT(PPC_RAW_ADDI(dst_reg, dst_reg, IMM_L(imm)));
EMIT(PPC_RAW_ADDI(dst_reg, src2_reg, IMM_L(imm)));
break;
case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */
imm = -imm;
fallthrough;
case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */
if (!imm)
if (!imm) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
EMIT(PPC_RAW_MR(dst_reg_h, src2_reg_h));
break;
}
if (imm >= -32768 && imm < 32768) {
EMIT(PPC_RAW_ADDIC(dst_reg, dst_reg, imm));
EMIT(PPC_RAW_ADDIC(dst_reg, src2_reg, imm));
} else {
PPC_LI32(_R0, imm);
EMIT(PPC_RAW_ADDC(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_ADDC(dst_reg, src2_reg, _R0));
}
if (imm >= 0 || (BPF_OP(code) == BPF_SUB && imm == 0x80000000))
EMIT(PPC_RAW_ADDZE(dst_reg_h, dst_reg_h));
EMIT(PPC_RAW_ADDZE(dst_reg_h, src2_reg_h));
else
EMIT(PPC_RAW_ADDME(dst_reg_h, dst_reg_h));
EMIT(PPC_RAW_ADDME(dst_reg_h, src2_reg_h));
break;
case BPF_ALU64 | BPF_MUL | BPF_X: /* dst *= src */
bpf_set_seen_register(ctx, tmp_reg);
EMIT(PPC_RAW_MULW(_R0, dst_reg, src_reg_h));
EMIT(PPC_RAW_MULW(dst_reg_h, dst_reg_h, src_reg));
EMIT(PPC_RAW_MULHWU(tmp_reg, dst_reg, src_reg));
EMIT(PPC_RAW_MULW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_MULW(_R0, src2_reg, src_reg_h));
EMIT(PPC_RAW_MULW(dst_reg_h, src2_reg_h, src_reg));
EMIT(PPC_RAW_MULHWU(tmp_reg, src2_reg, src_reg));
EMIT(PPC_RAW_MULW(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_ADD(dst_reg_h, dst_reg_h, _R0));
EMIT(PPC_RAW_ADD(dst_reg_h, dst_reg_h, tmp_reg));
break;
case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */
EMIT(PPC_RAW_MULW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_MULW(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU | BPF_MUL | BPF_K: /* (u32) dst *= (u32) imm */
if (imm >= -32768 && imm < 32768) {
EMIT(PPC_RAW_MULI(dst_reg, dst_reg, imm));
if (imm == 1) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
} else if (imm == -1) {
EMIT(PPC_RAW_SUBFIC(dst_reg, src2_reg, 0));
} else if (is_power_of_2((u32)imm)) {
EMIT(PPC_RAW_SLWI(dst_reg, src2_reg, ilog2(imm)));
} else if (imm >= -32768 && imm < 32768) {
EMIT(PPC_RAW_MULI(dst_reg, src2_reg, imm));
} else {
PPC_LI32(_R0, imm);
EMIT(PPC_RAW_MULW(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_MULW(dst_reg, src2_reg, _R0));
}
break;
case BPF_ALU64 | BPF_MUL | BPF_K: /* dst *= imm */
if (!imm) {
PPC_LI32(dst_reg, 0);
PPC_LI32(dst_reg_h, 0);
break;
} else if (imm == 1) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
EMIT(PPC_RAW_MR(dst_reg_h, src2_reg_h));
} else if (imm == -1) {
EMIT(PPC_RAW_SUBFIC(dst_reg, src2_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, src2_reg_h));
} else if (imm > 0 && is_power_of_2(imm)) {
imm = ilog2(imm);
EMIT(PPC_RAW_RLWINM(dst_reg_h, src2_reg_h, imm, 0, 31 - imm));
EMIT(PPC_RAW_RLWIMI(dst_reg_h, dst_reg, imm, 32 - imm, 31));
EMIT(PPC_RAW_SLWI(dst_reg, src2_reg, imm));
} else {
bpf_set_seen_register(ctx, tmp_reg);
PPC_LI32(tmp_reg, imm);
EMIT(PPC_RAW_MULW(dst_reg_h, src2_reg_h, tmp_reg));
if (imm < 0)
EMIT(PPC_RAW_SUB(dst_reg_h, dst_reg_h, src2_reg));
EMIT(PPC_RAW_MULHWU(_R0, src2_reg, tmp_reg));
EMIT(PPC_RAW_MULW(dst_reg, src2_reg, tmp_reg));
EMIT(PPC_RAW_ADD(dst_reg_h, dst_reg_h, _R0));
}
if (imm == 1)
break;
if (imm == -1) {
EMIT(PPC_RAW_SUBFIC(dst_reg, dst_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, dst_reg_h));
break;
}
bpf_set_seen_register(ctx, tmp_reg);
PPC_LI32(tmp_reg, imm);
EMIT(PPC_RAW_MULW(dst_reg_h, dst_reg_h, tmp_reg));
if (imm < 0)
EMIT(PPC_RAW_SUB(dst_reg_h, dst_reg_h, dst_reg));
EMIT(PPC_RAW_MULHWU(_R0, dst_reg, tmp_reg));
EMIT(PPC_RAW_MULW(dst_reg, dst_reg, tmp_reg));
EMIT(PPC_RAW_ADD(dst_reg_h, dst_reg_h, _R0));
break;
case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */
EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_DIVWU(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */
EMIT(PPC_RAW_DIVWU(_R0, dst_reg, src_reg));
EMIT(PPC_RAW_DIVWU(_R0, src2_reg, src_reg));
EMIT(PPC_RAW_MULW(_R0, src_reg, _R0));
EMIT(PPC_RAW_SUB(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_SUB(dst_reg, src2_reg, _R0));
break;
case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */
return -EOPNOTSUPP;
@ -425,11 +463,14 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */
if (!imm)
return -EINVAL;
if (imm == 1)
break;
PPC_LI32(_R0, imm);
EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, _R0));
if (imm == 1) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
} else if (is_power_of_2((u32)imm)) {
EMIT(PPC_RAW_SRWI(dst_reg, src2_reg, ilog2(imm)));
} else {
PPC_LI32(_R0, imm);
EMIT(PPC_RAW_DIVWU(dst_reg, src2_reg, _R0));
}
break;
case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */
if (!imm)
@ -438,16 +479,15 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (!is_power_of_2((u32)imm)) {
bpf_set_seen_register(ctx, tmp_reg);
PPC_LI32(tmp_reg, imm);
EMIT(PPC_RAW_DIVWU(_R0, dst_reg, tmp_reg));
EMIT(PPC_RAW_DIVWU(_R0, src2_reg, tmp_reg));
EMIT(PPC_RAW_MULW(_R0, tmp_reg, _R0));
EMIT(PPC_RAW_SUB(dst_reg, dst_reg, _R0));
break;
}
if (imm == 1)
EMIT(PPC_RAW_SUB(dst_reg, src2_reg, _R0));
} else if (imm == 1) {
EMIT(PPC_RAW_LI(dst_reg, 0));
else
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 32 - ilog2((u32)imm), 31));
} else {
imm = ilog2((u32)imm);
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 0, 32 - imm, 31));
}
break;
case BPF_ALU64 | BPF_MOD | BPF_K: /* dst %= imm */
if (!imm)
@ -459,7 +499,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
if (imm == 1)
EMIT(PPC_RAW_LI(dst_reg, 0));
else
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 32 - ilog2(imm), 31));
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 0, 32 - ilog2(imm), 31));
EMIT(PPC_RAW_LI(dst_reg_h, 0));
break;
case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */
@ -469,34 +509,38 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
return -EOPNOTSUPP;
if (imm < 0) {
EMIT(PPC_RAW_SUBFIC(dst_reg, dst_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, dst_reg_h));
EMIT(PPC_RAW_SUBFIC(dst_reg, src2_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, src2_reg_h));
imm = -imm;
src2_reg = dst_reg;
}
if (imm == 1) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
EMIT(PPC_RAW_MR(dst_reg_h, src2_reg_h));
} else {
imm = ilog2(imm);
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, src2_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_SRAWI(dst_reg_h, src2_reg_h, imm));
}
if (imm == 1)
break;
imm = ilog2(imm);
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, dst_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_SRAWI(dst_reg_h, dst_reg_h, imm));
break;
case BPF_ALU | BPF_NEG: /* (u32) dst = -dst */
EMIT(PPC_RAW_NEG(dst_reg, dst_reg));
EMIT(PPC_RAW_NEG(dst_reg, src2_reg));
break;
case BPF_ALU64 | BPF_NEG: /* dst = -dst */
EMIT(PPC_RAW_SUBFIC(dst_reg, dst_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, dst_reg_h));
EMIT(PPC_RAW_SUBFIC(dst_reg, src2_reg, 0));
EMIT(PPC_RAW_SUBFZE(dst_reg_h, src2_reg_h));
break;
/*
* Logical operations: AND/OR/XOR/[A]LSH/[A]RSH
*/
case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */
EMIT(PPC_RAW_AND(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_AND(dst_reg_h, dst_reg_h, src_reg_h));
EMIT(PPC_RAW_AND(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_AND(dst_reg_h, src2_reg_h, src_reg_h));
break;
case BPF_ALU | BPF_AND | BPF_X: /* (u32) dst = dst & src */
EMIT(PPC_RAW_AND(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_AND(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */
if (imm >= 0)
@ -504,23 +548,23 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
fallthrough;
case BPF_ALU | BPF_AND | BPF_K: /* (u32) dst = dst & imm */
if (!IMM_H(imm)) {
EMIT(PPC_RAW_ANDI(dst_reg, dst_reg, IMM_L(imm)));
EMIT(PPC_RAW_ANDI(dst_reg, src2_reg, IMM_L(imm)));
} else if (!IMM_L(imm)) {
EMIT(PPC_RAW_ANDIS(dst_reg, dst_reg, IMM_H(imm)));
EMIT(PPC_RAW_ANDIS(dst_reg, src2_reg, IMM_H(imm)));
} else if (imm == (((1 << fls(imm)) - 1) ^ ((1 << (ffs(i) - 1)) - 1))) {
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0,
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 0,
32 - fls(imm), 32 - ffs(imm)));
} else {
PPC_LI32(_R0, imm);
EMIT(PPC_RAW_AND(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_AND(dst_reg, src2_reg, _R0));
}
break;
case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */
EMIT(PPC_RAW_OR(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_OR(dst_reg_h, dst_reg_h, src_reg_h));
EMIT(PPC_RAW_OR(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_OR(dst_reg_h, src2_reg_h, src_reg_h));
break;
case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */
EMIT(PPC_RAW_OR(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_OR(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_OR | BPF_K:/* dst = dst | imm */
/* Sign-extended */
@ -528,145 +572,154 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
EMIT(PPC_RAW_LI(dst_reg_h, -1));
fallthrough;
case BPF_ALU | BPF_OR | BPF_K:/* dst = (u32) dst | (u32) imm */
if (IMM_L(imm))
EMIT(PPC_RAW_ORI(dst_reg, dst_reg, IMM_L(imm)));
if (IMM_L(imm)) {
EMIT(PPC_RAW_ORI(dst_reg, src2_reg, IMM_L(imm)));
src2_reg = dst_reg;
}
if (IMM_H(imm))
EMIT(PPC_RAW_ORIS(dst_reg, dst_reg, IMM_H(imm)));
EMIT(PPC_RAW_ORIS(dst_reg, src2_reg, IMM_H(imm)));
break;
case BPF_ALU64 | BPF_XOR | BPF_X: /* dst ^= src */
if (dst_reg == src_reg) {
EMIT(PPC_RAW_LI(dst_reg, 0));
EMIT(PPC_RAW_LI(dst_reg_h, 0));
} else {
EMIT(PPC_RAW_XOR(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_XOR(dst_reg_h, dst_reg_h, src_reg_h));
EMIT(PPC_RAW_XOR(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_XOR(dst_reg_h, src2_reg_h, src_reg_h));
}
break;
case BPF_ALU | BPF_XOR | BPF_X: /* (u32) dst ^= src */
if (dst_reg == src_reg)
EMIT(PPC_RAW_LI(dst_reg, 0));
else
EMIT(PPC_RAW_XOR(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_XOR(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_XOR | BPF_K: /* dst ^= imm */
if (imm < 0)
EMIT(PPC_RAW_NOR(dst_reg_h, dst_reg_h, dst_reg_h));
EMIT(PPC_RAW_NOR(dst_reg_h, src2_reg_h, src2_reg_h));
fallthrough;
case BPF_ALU | BPF_XOR | BPF_K: /* (u32) dst ^= (u32) imm */
if (IMM_L(imm))
EMIT(PPC_RAW_XORI(dst_reg, dst_reg, IMM_L(imm)));
if (IMM_L(imm)) {
EMIT(PPC_RAW_XORI(dst_reg, src2_reg, IMM_L(imm)));
src2_reg = dst_reg;
}
if (IMM_H(imm))
EMIT(PPC_RAW_XORIS(dst_reg, dst_reg, IMM_H(imm)));
EMIT(PPC_RAW_XORIS(dst_reg, src2_reg, IMM_H(imm)));
break;
case BPF_ALU | BPF_LSH | BPF_X: /* (u32) dst <<= (u32) src */
EMIT(PPC_RAW_SLW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SLW(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_LSH | BPF_X: /* dst <<= src; */
bpf_set_seen_register(ctx, tmp_reg);
EMIT(PPC_RAW_SUBFIC(_R0, src_reg, 32));
EMIT(PPC_RAW_SLW(dst_reg_h, dst_reg_h, src_reg));
EMIT(PPC_RAW_SLW(dst_reg_h, src2_reg_h, src_reg));
EMIT(PPC_RAW_ADDI(tmp_reg, src_reg, 32));
EMIT(PPC_RAW_SRW(_R0, dst_reg, _R0));
EMIT(PPC_RAW_SLW(tmp_reg, dst_reg, tmp_reg));
EMIT(PPC_RAW_SRW(_R0, src2_reg, _R0));
EMIT(PPC_RAW_SLW(tmp_reg, src2_reg, tmp_reg));
EMIT(PPC_RAW_OR(dst_reg_h, dst_reg_h, _R0));
EMIT(PPC_RAW_SLW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SLW(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_OR(dst_reg_h, dst_reg_h, tmp_reg));
break;
case BPF_ALU | BPF_LSH | BPF_K: /* (u32) dst <<= (u32) imm */
if (!imm)
break;
EMIT(PPC_RAW_SLWI(dst_reg, dst_reg, imm));
if (imm)
EMIT(PPC_RAW_SLWI(dst_reg, src2_reg, imm));
else
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
break;
case BPF_ALU64 | BPF_LSH | BPF_K: /* dst <<= imm */
if (imm < 0)
return -EINVAL;
if (!imm)
break;
if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg_h, dst_reg_h, imm, 0, 31 - imm));
EMIT(PPC_RAW_RLWIMI(dst_reg_h, dst_reg, imm, 32 - imm, 31));
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, imm, 0, 31 - imm));
break;
}
if (imm < 64)
EMIT(PPC_RAW_RLWINM(dst_reg_h, dst_reg, imm, 0, 31 - imm));
else
if (!imm) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
} else if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg_h, src2_reg_h, imm, 0, 31 - imm));
EMIT(PPC_RAW_RLWIMI(dst_reg_h, src2_reg, imm, 32 - imm, 31));
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, imm, 0, 31 - imm));
} else if (imm < 64) {
EMIT(PPC_RAW_RLWINM(dst_reg_h, src2_reg, imm, 0, 31 - imm));
EMIT(PPC_RAW_LI(dst_reg, 0));
} else {
EMIT(PPC_RAW_LI(dst_reg_h, 0));
EMIT(PPC_RAW_LI(dst_reg, 0));
EMIT(PPC_RAW_LI(dst_reg, 0));
}
break;
case BPF_ALU | BPF_RSH | BPF_X: /* (u32) dst >>= (u32) src */
EMIT(PPC_RAW_SRW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SRW(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_RSH | BPF_X: /* dst >>= src */
bpf_set_seen_register(ctx, tmp_reg);
EMIT(PPC_RAW_SUBFIC(_R0, src_reg, 32));
EMIT(PPC_RAW_SRW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SRW(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_ADDI(tmp_reg, src_reg, 32));
EMIT(PPC_RAW_SLW(_R0, dst_reg_h, _R0));
EMIT(PPC_RAW_SLW(_R0, src2_reg_h, _R0));
EMIT(PPC_RAW_SRW(tmp_reg, dst_reg_h, tmp_reg));
EMIT(PPC_RAW_OR(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_SRW(dst_reg_h, dst_reg_h, src_reg));
EMIT(PPC_RAW_SRW(dst_reg_h, src2_reg_h, src_reg));
EMIT(PPC_RAW_OR(dst_reg, dst_reg, tmp_reg));
break;
case BPF_ALU | BPF_RSH | BPF_K: /* (u32) dst >>= (u32) imm */
if (!imm)
break;
EMIT(PPC_RAW_SRWI(dst_reg, dst_reg, imm));
if (imm)
EMIT(PPC_RAW_SRWI(dst_reg, src2_reg, imm));
else
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
break;
case BPF_ALU64 | BPF_RSH | BPF_K: /* dst >>= imm */
if (imm < 0)
return -EINVAL;
if (!imm)
break;
if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, dst_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_RLWINM(dst_reg_h, dst_reg_h, 32 - imm, imm, 31));
break;
}
if (imm < 64)
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg_h, 64 - imm, imm - 32, 31));
else
if (!imm) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
EMIT(PPC_RAW_MR(dst_reg_h, src2_reg_h));
} else if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, src2_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_RLWINM(dst_reg_h, src2_reg_h, 32 - imm, imm, 31));
} else if (imm < 64) {
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg_h, 64 - imm, imm - 32, 31));
EMIT(PPC_RAW_LI(dst_reg_h, 0));
} else {
EMIT(PPC_RAW_LI(dst_reg, 0));
EMIT(PPC_RAW_LI(dst_reg_h, 0));
EMIT(PPC_RAW_LI(dst_reg_h, 0));
}
break;
case BPF_ALU | BPF_ARSH | BPF_X: /* (s32) dst >>= src */
EMIT(PPC_RAW_SRAW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SRAW(dst_reg, src2_reg, src_reg));
break;
case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */
bpf_set_seen_register(ctx, tmp_reg);
EMIT(PPC_RAW_SUBFIC(_R0, src_reg, 32));
EMIT(PPC_RAW_SRW(dst_reg, dst_reg, src_reg));
EMIT(PPC_RAW_SLW(_R0, dst_reg_h, _R0));
EMIT(PPC_RAW_SRW(dst_reg, src2_reg, src_reg));
EMIT(PPC_RAW_SLW(_R0, src2_reg_h, _R0));
EMIT(PPC_RAW_ADDI(tmp_reg, src_reg, 32));
EMIT(PPC_RAW_OR(dst_reg, dst_reg, _R0));
EMIT(PPC_RAW_RLWINM(_R0, tmp_reg, 0, 26, 26));
EMIT(PPC_RAW_SRAW(tmp_reg, dst_reg_h, tmp_reg));
EMIT(PPC_RAW_SRAW(dst_reg_h, dst_reg_h, src_reg));
EMIT(PPC_RAW_SRAW(tmp_reg, src2_reg_h, tmp_reg));
EMIT(PPC_RAW_SRAW(dst_reg_h, src2_reg_h, src_reg));
EMIT(PPC_RAW_SLW(tmp_reg, tmp_reg, _R0));
EMIT(PPC_RAW_OR(dst_reg, dst_reg, tmp_reg));
break;
case BPF_ALU | BPF_ARSH | BPF_K: /* (s32) dst >>= imm */
if (!imm)
break;
EMIT(PPC_RAW_SRAWI(dst_reg, dst_reg, imm));
if (imm)
EMIT(PPC_RAW_SRAWI(dst_reg, src2_reg, imm));
else
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
break;
case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */
if (imm < 0)
return -EINVAL;
if (!imm)
break;
if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, dst_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_SRAWI(dst_reg_h, dst_reg_h, imm));
break;
if (!imm) {
EMIT(PPC_RAW_MR(dst_reg, src2_reg));
EMIT(PPC_RAW_MR(dst_reg_h, src2_reg_h));
} else if (imm < 32) {
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 32 - imm, imm, 31));
EMIT(PPC_RAW_RLWIMI(dst_reg, src2_reg_h, 32 - imm, 0, imm - 1));
EMIT(PPC_RAW_SRAWI(dst_reg_h, src2_reg_h, imm));
} else if (imm < 64) {
EMIT(PPC_RAW_SRAWI(dst_reg, src2_reg_h, imm - 32));
EMIT(PPC_RAW_SRAWI(dst_reg_h, src2_reg_h, 31));
} else {
EMIT(PPC_RAW_SRAWI(dst_reg, src2_reg_h, 31));
EMIT(PPC_RAW_SRAWI(dst_reg_h, src2_reg_h, 31));
}
if (imm < 64)
EMIT(PPC_RAW_SRAWI(dst_reg, dst_reg_h, imm - 32));
else
EMIT(PPC_RAW_SRAWI(dst_reg, dst_reg_h, 31));
EMIT(PPC_RAW_SRAWI(dst_reg_h, dst_reg_h, 31));
break;
/*
@ -700,7 +753,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
switch (imm) {
case 16:
/* Copy 16 bits to upper part */
EMIT(PPC_RAW_RLWIMI(dst_reg, dst_reg, 16, 0, 15));
EMIT(PPC_RAW_RLWIMI(dst_reg, src2_reg, 16, 0, 15));
/* Rotate 8 bits right & mask */
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 24, 16, 31));
break;
@ -710,23 +763,23 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
* 2 bytes are already in their final position
* -- byte 2 and 4 (of bytes 1, 2, 3 and 4)
*/
EMIT(PPC_RAW_RLWINM(_R0, dst_reg, 8, 0, 31));
EMIT(PPC_RAW_RLWINM(_R0, src2_reg, 8, 0, 31));
/* Rotate 24 bits and insert byte 1 */
EMIT(PPC_RAW_RLWIMI(_R0, dst_reg, 24, 0, 7));
EMIT(PPC_RAW_RLWIMI(_R0, src2_reg, 24, 0, 7));
/* Rotate 24 bits and insert byte 3 */
EMIT(PPC_RAW_RLWIMI(_R0, dst_reg, 24, 16, 23));
EMIT(PPC_RAW_RLWIMI(_R0, src2_reg, 24, 16, 23));
EMIT(PPC_RAW_MR(dst_reg, _R0));
break;
case 64:
bpf_set_seen_register(ctx, tmp_reg);
EMIT(PPC_RAW_RLWINM(tmp_reg, dst_reg, 8, 0, 31));
EMIT(PPC_RAW_RLWINM(_R0, dst_reg_h, 8, 0, 31));
EMIT(PPC_RAW_RLWINM(tmp_reg, src2_reg, 8, 0, 31));
EMIT(PPC_RAW_RLWINM(_R0, src2_reg_h, 8, 0, 31));
/* Rotate 24 bits and insert byte 1 */
EMIT(PPC_RAW_RLWIMI(tmp_reg, dst_reg, 24, 0, 7));
EMIT(PPC_RAW_RLWIMI(_R0, dst_reg_h, 24, 0, 7));
EMIT(PPC_RAW_RLWIMI(tmp_reg, src2_reg, 24, 0, 7));
EMIT(PPC_RAW_RLWIMI(_R0, src2_reg_h, 24, 0, 7));
/* Rotate 24 bits and insert byte 3 */
EMIT(PPC_RAW_RLWIMI(tmp_reg, dst_reg, 24, 16, 23));
EMIT(PPC_RAW_RLWIMI(_R0, dst_reg_h, 24, 16, 23));
EMIT(PPC_RAW_RLWIMI(tmp_reg, src2_reg, 24, 16, 23));
EMIT(PPC_RAW_RLWIMI(_R0, src2_reg_h, 24, 16, 23));
EMIT(PPC_RAW_MR(dst_reg, _R0));
EMIT(PPC_RAW_MR(dst_reg_h, tmp_reg));
break;
@ -736,7 +789,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
switch (imm) {
case 16:
/* zero-extend 16 bits into 32 bits */
EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 16, 31));
EMIT(PPC_RAW_RLWINM(dst_reg, src2_reg, 0, 16, 31));
break;
case 32:
case 64:
@ -960,8 +1013,9 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
PPC_LI32(dst_reg_h, (u32)insn[i + 1].imm);
PPC_LI32(dst_reg, (u32)insn[i].imm);
/* padding to allow full 4 instructions for later patching */
for (j = ctx->idx - tmp_idx; j < 4; j++)
EMIT(PPC_RAW_NOP());
if (!image)
for (j = ctx->idx - tmp_idx; j < 4; j++)
EMIT(PPC_RAW_NOP());
/* Adjust for two bpf instructions */
addrs[++i] = ctx->idx * 4;
break;
@ -989,7 +1043,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
ret = bpf_jit_get_func_addr(fp, &insn[i], false,
ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;

View File

@ -240,13 +240,14 @@ int bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 func
* load the callee's address, but this may optimize the number of
* instructions required based on the nature of the address.
*
* Since we don't want the number of instructions emitted to change,
* Since we don't want the number of instructions emitted to increase,
* we pad the optimized PPC_LI64() call with NOPs to guarantee that
* we always have a five-instruction sequence, which is the maximum
* that PPC_LI64() can emit.
*/
for (i = ctx->idx - ctx_idx; i < 5; i++)
EMIT(PPC_RAW_NOP());
if (!image)
for (i = ctx->idx - ctx_idx; i < 5; i++)
EMIT(PPC_RAW_NOP());
EMIT(PPC_RAW_MTCTR(_R12));
EMIT(PPC_RAW_BCTRL());
@ -343,7 +344,7 @@ asm (
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx,
u32 *addrs, int pass)
u32 *addrs, int pass, bool extra_pass)
{
enum stf_barrier_type stf_barrier = stf_barrier_type_get();
const struct bpf_insn *insn = fp->insnsi;
@ -938,8 +939,9 @@ emit_clear:
tmp_idx = ctx->idx;
PPC_LI64(dst_reg, imm64);
/* padding to allow full 5 instructions for later patching */
for (j = ctx->idx - tmp_idx; j < 5; j++)
EMIT(PPC_RAW_NOP());
if (!image)
for (j = ctx->idx - tmp_idx; j < 5; j++)
EMIT(PPC_RAW_NOP());
/* Adjust for two bpf instructions */
addrs[++i] = ctx->idx * 4;
break;
@ -967,7 +969,7 @@ emit_clear:
case BPF_JMP | BPF_CALL:
ctx->seen |= SEEN_FUNC;
ret = bpf_jit_get_func_addr(fp, &insn[i], false,
ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass,
&func_addr, &func_addr_fixed);
if (ret < 0)
return ret;

View File

@ -18,6 +18,7 @@
#include <asm/firmware.h>
#include <asm/hvcall.h>
#include <asm/io.h>
#include <asm/papr-sysparm.h>
#include <linux/byteorder/generic.h>
#include <asm/rtas.h>
@ -66,8 +67,6 @@ static bool is_physical_domain(unsigned int domain)
* Refer PAPR+ document to get parameter token value as '43'.
*/
#define PROCESSOR_MODULE_INFO 43
static u32 phys_sockets; /* Physical sockets */
static u32 phys_chipspersocket; /* Physical chips per socket*/
static u32 phys_coresperchip; /* Physical cores per chip */
@ -79,9 +78,7 @@ static u32 phys_coresperchip; /* Physical cores per chip */
*/
void read_24x7_sys_info(void)
{
int call_status, len, ntypes;
spin_lock(&rtas_data_buf_lock);
struct papr_sysparm_buf *buf;
/*
* Making system parameter: chips and sockets and cores per chip
@ -91,32 +88,22 @@ void read_24x7_sys_info(void)
phys_chipspersocket = 1;
phys_coresperchip = 1;
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
NULL,
PROCESSOR_MODULE_INFO,
__pa(rtas_data_buf),
RTAS_DATA_BUF_SIZE);
buf = papr_sysparm_buf_alloc();
if (!buf)
return;
if (call_status != 0) {
pr_err("Error calling get-system-parameter %d\n",
call_status);
} else {
len = be16_to_cpup((__be16 *)&rtas_data_buf[0]);
if (len < 8)
goto out;
if (!papr_sysparm_get(PAPR_SYSPARM_PROC_MODULE_INFO, buf)) {
int ntypes = be16_to_cpup((__be16 *)&buf->val[0]);
int len = be16_to_cpu(buf->len);
ntypes = be16_to_cpup((__be16 *)&rtas_data_buf[2]);
if (!ntypes)
goto out;
phys_sockets = be16_to_cpup((__be16 *)&rtas_data_buf[4]);
phys_chipspersocket = be16_to_cpup((__be16 *)&rtas_data_buf[6]);
phys_coresperchip = be16_to_cpup((__be16 *)&rtas_data_buf[8]);
if (len >= 8 && ntypes != 0) {
phys_sockets = be16_to_cpup((__be16 *)&buf->val[2]);
phys_chipspersocket = be16_to_cpup((__be16 *)&buf->val[4]);
phys_coresperchip = be16_to_cpup((__be16 *)&buf->val[6]);
}
}
out:
spin_unlock(&rtas_data_buf_lock);
papr_sysparm_buf_free(buf);
}
/* Domains for which more than one result element are returned for each event. */
@ -1727,7 +1714,8 @@ static int hv_24x7_init(void)
}
/* POWER8 only supports v1, while POWER9 only supports v2. */
if (PVR_VER(pvr) == PVR_POWER8)
if (PVR_VER(pvr) == PVR_POWER8 || PVR_VER(pvr) == PVR_POWER8E ||
PVR_VER(pvr) == PVR_POWER8NVL)
interface_version = 1;
else {
interface_version = 2;

View File

@ -205,7 +205,7 @@ static void __init node_irq_request(const char *compat, irq_handler_t errirq_han
for_each_compatible_node(np, NULL, compat) {
irq = irq_of_parse_and_map(np, 0);
if (irq == NO_IRQ) {
if (!irq) {
pr_err("device tree node %pOFn is missing a interrupt",
np);
of_node_put(np);

View File

@ -41,7 +41,7 @@ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int ret = -1;
int rval;
rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
rval = rtas_call(rtas_function_token(RTAS_FN_READ_PCI_CONFIG), 2, 2, &ret, addr, len);
*val = ret;
return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
@ -55,7 +55,7 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
| (hose->global_number << 24);
int rval;
rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
rval = rtas_call(rtas_function_token(RTAS_FN_WRITE_PCI_CONFIG), 3, 1, NULL,
addr, len, val);
return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}

View File

@ -118,19 +118,18 @@ endchoice
choice
prompt "CPU selection"
default GENERIC_CPU
help
This will create a kernel which is optimised for a particular CPU.
The resulting kernel may not run on other CPUs, so use this with care.
If unsure, select Generic.
config GENERIC_CPU
config POWERPC64_CPU
bool "Generic (POWER5 and PowerPC 970 and above)"
depends on PPC_BOOK3S_64 && !CPU_LITTLE_ENDIAN
select PPC_64S_HASH_MMU
config GENERIC_CPU
config POWERPC64_CPU
bool "Generic (POWER8 and above)"
depends on PPC_BOOK3S_64 && CPU_LITTLE_ENDIAN
select ARCH_HAS_FAST_MULTIPLIER
@ -144,6 +143,7 @@ config POWERPC_CPU
config CELL_CPU
bool "Cell Broadband Engine"
depends on PPC_BOOK3S_64 && !CPU_LITTLE_ENDIAN
depends on !CC_IS_CLANG
select PPC_64S_HASH_MMU
config PPC_970_CPU
@ -188,11 +188,13 @@ config E5500_CPU
config E6500_CPU
bool "Freescale e6500"
depends on PPC64 && PPC_E500
depends on !CC_IS_CLANG
select PPC_HAS_LBARX_LHARX
config 405_CPU
bool "40x family"
depends on 40x
depends on !CC_IS_CLANG
config 440_CPU
bool "440 (44x family)"
@ -201,22 +203,27 @@ config 440_CPU
config 464_CPU
bool "464 (44x family)"
depends on 44x
depends on !CC_IS_CLANG
config 476_CPU
bool "476 (47x family)"
depends on PPC_47x
depends on !CC_IS_CLANG
config 860_CPU
bool "8xx family"
depends on PPC_8xx
depends on !CC_IS_CLANG
config E300C2_CPU
bool "e300c2 (832x)"
depends on PPC_BOOK3S_32
depends on !CC_IS_CLANG
config E300C3_CPU
bool "e300c3 (831x)"
depends on PPC_BOOK3S_32
depends on !CC_IS_CLANG
config G4_CPU
bool "G4 (74xx)"
@ -233,13 +240,12 @@ config E500MC_CPU
config TOOLCHAIN_DEFAULT_CPU
bool "Rely on the toolchain's implicit default CPU"
depends on PPC32
endchoice
config TARGET_CPU_BOOL
bool
default !GENERIC_CPU && !TOOLCHAIN_DEFAULT_CPU
default !TOOLCHAIN_DEFAULT_CPU
config TARGET_CPU
string
@ -251,6 +257,10 @@ config TARGET_CPU
default "power8" if POWER8_CPU
default "power9" if POWER9_CPU
default "power10" if POWER10_CPU
default "e5500" if E5500_CPU
default "e6500" if E6500_CPU
default "power4" if POWERPC64_CPU && !CPU_LITTLE_ENDIAN
default "power8" if POWERPC64_CPU && CPU_LITTLE_ENDIAN
default "405" if 405_CPU
default "440" if 440_CPU
default "464" if 464_CPU

View File

@ -297,8 +297,8 @@ int cbe_sysreset_hack(void)
static int __init cbe_ptcal_init(void)
{
int ret;
ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
ptcal_start_tok = rtas_function_token(RTAS_FN_IBM_CBE_START_PTCAL);
ptcal_stop_tok = rtas_function_token(RTAS_FN_IBM_CBE_STOP_PTCAL);
if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
|| ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)

View File

@ -81,7 +81,7 @@ static inline int smp_startup_cpu(unsigned int lcpu)
* If the RTAS start-cpu token does not exist then presume the
* cpu is already spinning.
*/
start_cpu = rtas_token("start-cpu");
start_cpu = rtas_function_token(RTAS_FN_START_CPU);
if (start_cpu == RTAS_UNKNOWN_SERVICE)
return 1;
@ -152,7 +152,7 @@ void __init smp_init_cell(void)
cpumask_clear_cpu(boot_cpuid, &of_spin_map);
/* Non-lpar has additional take/give timebase */
if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
if (rtas_function_token(RTAS_FN_FREEZE_TIME_BASE) != RTAS_UNKNOWN_SERVICE) {
smp_ops->give_timebase = rtas_give_timebase;
smp_ops->take_timebase = rtas_take_timebase;
}

View File

@ -31,7 +31,7 @@ static unsigned char chrp_nvram_read_val(int addr)
return 0xff;
}
spin_lock_irqsave(&nvram_lock, flags);
if ((rtas_call(rtas_token("nvram-fetch"), 3, 2, &done, addr,
if ((rtas_call(rtas_function_token(RTAS_FN_NVRAM_FETCH), 3, 2, &done, addr,
__pa(nvram_buf), 1) != 0) || 1 != done)
ret = 0xff;
else
@ -53,7 +53,7 @@ static void chrp_nvram_write_val(int addr, unsigned char val)
}
spin_lock_irqsave(&nvram_lock, flags);
nvram_buf[0] = val;
if ((rtas_call(rtas_token("nvram-store"), 3, 2, &done, addr,
if ((rtas_call(rtas_function_token(RTAS_FN_NVRAM_STORE), 3, 2, &done, addr,
__pa(nvram_buf), 1) != 0) || 1 != done)
printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr);
spin_unlock_irqrestore(&nvram_lock, flags);

View File

@ -104,7 +104,7 @@ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int ret = -1;
int rval;
rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
rval = rtas_call(rtas_function_token(RTAS_FN_READ_PCI_CONFIG), 2, 2, &ret, addr, len);
*val = ret;
return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
}
@ -118,7 +118,7 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset
| (hose->global_number << 24);
int rval;
rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
rval = rtas_call(rtas_function_token(RTAS_FN_WRITE_PCI_CONFIG), 3, 1, NULL,
addr, len, val);
return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL;
}

View File

@ -323,11 +323,11 @@ static void __init chrp_setup_arch(void)
printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
rtas_initialize();
if (rtas_token("display-character") >= 0)
if (rtas_function_token(RTAS_FN_DISPLAY_CHARACTER) >= 0)
ppc_md.progress = rtas_progress;
/* use RTAS time-of-day routines if available */
if (rtas_token("get-time-of-day") != RTAS_UNKNOWN_SERVICE) {
if (rtas_function_token(RTAS_FN_GET_TIME_OF_DAY) != RTAS_UNKNOWN_SERVICE) {
ppc_md.get_boot_time = rtas_get_boot_time;
ppc_md.get_rtc_time = rtas_get_rtc_time;
ppc_md.set_rtc_time = rtas_set_rtc_time;

View File

@ -162,8 +162,8 @@ static struct smp_ops_t maple_smp_ops = {
static void __init maple_use_rtas_reboot_and_halt_if_present(void)
{
if (rtas_service_present("system-reboot") &&
rtas_service_present("power-off")) {
if (rtas_function_implemented(RTAS_FN_SYSTEM_REBOOT) &&
rtas_function_implemented(RTAS_FN_POWER_OFF)) {
ppc_md.restart = rtas_restart;
pm_power_off = rtas_power_off;
ppc_md.halt = rtas_halt;

View File

@ -54,8 +54,7 @@ static int opal_status_to_err(int rc)
return err;
}
static int opal_get_variable(const char *key, uint64_t ksize,
u8 *data, uint64_t *dsize)
static int opal_get_variable(const char *key, u64 ksize, u8 *data, u64 *dsize)
{
int rc;
@ -71,8 +70,7 @@ static int opal_get_variable(const char *key, uint64_t ksize,
return opal_status_to_err(rc);
}
static int opal_get_next_variable(const char *key, uint64_t *keylen,
uint64_t keybufsize)
static int opal_get_next_variable(const char *key, u64 *keylen, u64 keybufsize)
{
int rc;
@ -88,8 +86,7 @@ static int opal_get_next_variable(const char *key, uint64_t *keylen,
return opal_status_to_err(rc);
}
static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
uint64_t dsize)
static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
{
int rc;
@ -101,10 +98,57 @@ static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
return opal_status_to_err(rc);
}
static ssize_t opal_secvar_format(char *buf, size_t bufsize)
{
ssize_t rc = 0;
struct device_node *node;
const char *format;
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
if (!of_device_is_available(node)) {
rc = -ENODEV;
goto out;
}
rc = of_property_read_string(node, "format", &format);
if (rc)
goto out;
rc = snprintf(buf, bufsize, "%s", format);
out:
of_node_put(node);
return rc;
}
static int opal_secvar_max_size(u64 *max_size)
{
int rc;
struct device_node *node;
node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
if (!node)
return -ENODEV;
if (!of_device_is_available(node)) {
rc = -ENODEV;
goto out;
}
rc = of_property_read_u64(node, "max-var-size", max_size);
out:
of_node_put(node);
return rc;
}
static const struct secvar_operations opal_secvar_ops = {
.get = opal_get_variable,
.get_next = opal_get_next_variable,
.set = opal_set_variable,
.format = opal_secvar_format,
.max_size = opal_secvar_max_size,
};
static int opal_secvar_probe(struct platform_device *pdev)
@ -116,9 +160,7 @@ static int opal_secvar_probe(struct platform_device *pdev)
return -ENODEV;
}
set_secvar_ops(&opal_secvar_ops);
return 0;
return set_secvar_ops(&opal_secvar_ops);
}
static const struct of_device_id opal_secvar_match[] = {

View File

@ -2325,7 +2325,8 @@ static void pnv_ioda_setup_pe_res(struct pnv_ioda_pe *pe,
int index;
int64_t rc;
if (!res || !res->flags || res->start > res->end)
if (!res || !res->flags || res->start > res->end ||
res->flags & IORESOURCE_UNSET)
return;
if (res->flags & IORESOURCE_IO) {

View File

@ -146,7 +146,7 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
int psize, int ssize)
{
panic("ps3_hpte_updateboltedpp() not implemented");
pr_info("ps3_hpte_updateboltedpp() not implemented");
}
static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,

View File

@ -151,16 +151,16 @@ config IBMEBUS
config PSERIES_PLPKS
depends on PPC_PSERIES
bool "Support for the Platform Key Storage"
help
PowerVM provides an isolated Platform Keystore(PKS) storage
allocation for each LPAR with individually managed access
controls to store sensitive information securely. It can be
used to store asymmetric public keys or secrets as required
by different usecases. Select this config to enable
operating system interface to hypervisor to access this space.
If unsure, select N.
select NLS
bool
# PowerVM provides an isolated Platform Keystore (PKS) storage
# allocation for each LPAR with individually managed access
# controls to store sensitive information securely. It can be
# used to store asymmetric public keys or secrets as required
# by different usecases.
#
# This option is selected by in-kernel consumers that require
# access to the PKS.
config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM

View File

@ -3,7 +3,7 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
of_helpers.o \
of_helpers.o rtas-work-area.o papr-sysparm.o \
setup.o iommu.o event_sources.o ras.o \
firmware.o power.o dlpar.o mobility.o rng.o \
pci.o pci_dlpar.o eeh_pseries.o msi.o \
@ -27,8 +27,8 @@ obj-$(CONFIG_PAPR_SCM) += papr_scm.o
obj-$(CONFIG_PPC_SPLPAR) += vphn.o
obj-$(CONFIG_PPC_SVM) += svm.o
obj-$(CONFIG_FA_DUMP) += rtas-fadump.o
obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
obj-$(CONFIG_PPC_SECURE_BOOT) += plpks-secvar.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-sysfs.o

View File

@ -22,6 +22,7 @@
#include <asm/machdep.h>
#include <linux/uaccess.h>
#include <asm/rtas.h>
#include <asm/rtas-work-area.h>
static struct workqueue_struct *pseries_hp_wq;
@ -137,37 +138,27 @@ struct device_node *dlpar_configure_connector(__be32 drc_index,
struct property *property;
struct property *last_property = NULL;
struct cc_workarea *ccwa;
struct rtas_work_area *work_area;
char *data_buf;
int cc_token;
int rc = -1;
cc_token = rtas_token("ibm,configure-connector");
cc_token = rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR);
if (cc_token == RTAS_UNKNOWN_SERVICE)
return NULL;
data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
if (!data_buf)
return NULL;
work_area = rtas_work_area_alloc(SZ_4K);
data_buf = rtas_work_area_raw_buf(work_area);
ccwa = (struct cc_workarea *)&data_buf[0];
ccwa->drc_index = drc_index;
ccwa->zero = 0;
do {
/* Since we release the rtas_data_buf lock between configure
* connector calls we want to re-populate the rtas_data_buffer
* with the contents of the previous call.
*/
spin_lock(&rtas_data_buf_lock);
memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE);
rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL);
memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
spin_unlock(&rtas_data_buf_lock);
if (rtas_busy_delay(rc))
continue;
do {
rc = rtas_call(cc_token, 2, 1, NULL,
rtas_work_area_phys(work_area), NULL);
} while (rtas_busy_delay(rc));
switch (rc) {
case COMPLETE:
@ -227,7 +218,7 @@ struct device_node *dlpar_configure_connector(__be32 drc_index,
} while (rc);
cc_error:
kfree(data_buf);
rtas_work_area_free(work_area);
if (rc) {
if (first_dn)

View File

@ -699,7 +699,7 @@ static int pseries_eeh_write_config(struct eeh_dev *edev, int where, int size, u
static int pseries_send_allow_unfreeze(struct pci_dn *pdn, u16 *vf_pe_array, int cur_vfs)
{
int rc;
int ibm_allow_unfreeze = rtas_token("ibm,open-sriov-allow-unfreeze");
int ibm_allow_unfreeze = rtas_function_token(RTAS_FN_IBM_OPEN_SRIOV_ALLOW_UNFREEZE);
unsigned long buid, addr;
addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
@ -774,7 +774,7 @@ static int pseries_notify_resume(struct eeh_dev *edev)
if (!edev)
return -EEXIST;
if (rtas_token("ibm,open-sriov-allow-unfreeze") == RTAS_UNKNOWN_SERVICE)
if (rtas_function_token(RTAS_FN_IBM_OPEN_SRIOV_ALLOW_UNFREEZE) == RTAS_UNKNOWN_SERVICE)
return -EINVAL;
if (edev->pdev->is_physfn || edev->pdev->is_virtfn)
@ -815,14 +815,14 @@ static int __init eeh_pseries_init(void)
int ret, config_addr;
/* figure out EEH RTAS function call tokens */
ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2");
ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
ibm_configure_pe = rtas_token("ibm,configure-pe");
ibm_set_eeh_option = rtas_function_token(RTAS_FN_IBM_SET_EEH_OPTION);
ibm_set_slot_reset = rtas_function_token(RTAS_FN_IBM_SET_SLOT_RESET);
ibm_read_slot_reset_state2 = rtas_function_token(RTAS_FN_IBM_READ_SLOT_RESET_STATE2);
ibm_read_slot_reset_state = rtas_function_token(RTAS_FN_IBM_READ_SLOT_RESET_STATE);
ibm_slot_error_detail = rtas_function_token(RTAS_FN_IBM_SLOT_ERROR_DETAIL);
ibm_get_config_addr_info2 = rtas_function_token(RTAS_FN_IBM_GET_CONFIG_ADDR_INFO2);
ibm_get_config_addr_info = rtas_function_token(RTAS_FN_IBM_GET_CONFIG_ADDR_INFO);
ibm_configure_pe = rtas_function_token(RTAS_FN_IBM_CONFIGURE_PE);
/*
* ibm,configure-pe and ibm,configure-bridge have the same semantics,
@ -830,7 +830,7 @@ static int __init eeh_pseries_init(void)
* ibm,configure-pe then fall back to using ibm,configure-bridge.
*/
if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE)
ibm_configure_pe = rtas_token("ibm,configure-bridge");
ibm_configure_pe = rtas_function_token(RTAS_FN_IBM_CONFIGURE_BRIDGE);
/*
* Necessary sanity check. We needn't check "get-config-addr-info"

View File

@ -855,8 +855,8 @@ static int __init pseries_cpu_hotplug_init(void)
ppc_md.cpu_release = dlpar_cpu_release;
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
rtas_stop_self_token = rtas_token("stop-self");
qcss_tok = rtas_token("query-cpu-stopped-state");
rtas_stop_self_token = rtas_function_token(RTAS_FN_STOP_SELF);
qcss_tok = rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE);
if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE ||
qcss_tok == RTAS_UNKNOWN_SERVICE) {

View File

@ -143,7 +143,7 @@ static int __init ioei_init(void)
{
struct device_node *np;
ioei_check_exception_token = rtas_token("check-exception");
ioei_check_exception_token = rtas_function_token(RTAS_FN_CHECK_EXCEPTION);
if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE)
return -ENODEV;

View File

@ -32,6 +32,7 @@
#include <asm/iommu.h>
#include <asm/tlb.h>
#include <asm/cputable.h>
#include <asm/papr-sysparm.h>
#include <asm/udbg.h>
#include <asm/smp.h>
#include <asm/trace.h>
@ -1469,8 +1470,6 @@ static inline void __init check_lp_set_hblkrm(unsigned int lp,
}
}
#define SPLPAR_TLB_BIC_TOKEN 50
/*
* The size of the TLB Block Invalidate Characteristics is variable. But at the
* maximum it will be the number of possible page sizes *2 + 10 bytes.
@ -1481,42 +1480,24 @@ static inline void __init check_lp_set_hblkrm(unsigned int lp,
void __init pseries_lpar_read_hblkrm_characteristics(void)
{
unsigned char local_buffer[SPLPAR_TLB_BIC_MAXLENGTH];
int call_status, len, idx, bpsize;
static struct papr_sysparm_buf buf __initdata;
int len, idx, bpsize;
if (!firmware_has_feature(FW_FEATURE_BLOCK_REMOVE))
return;
spin_lock(&rtas_data_buf_lock);
memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
NULL,
SPLPAR_TLB_BIC_TOKEN,
__pa(rtas_data_buf),
RTAS_DATA_BUF_SIZE);
memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH);
local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0';
spin_unlock(&rtas_data_buf_lock);
if (call_status != 0) {
pr_warn("%s %s Error calling get-system-parameter (0x%x)\n",
__FILE__, __func__, call_status);
if (papr_sysparm_get(PAPR_SYSPARM_TLB_BLOCK_INVALIDATE_ATTRS, &buf))
return;
}
/*
* The first two (2) bytes of the data in the buffer are the length of
* the returned data, not counting these first two (2) bytes.
*/
len = be16_to_cpu(*((u16 *)local_buffer)) + 2;
len = be16_to_cpu(buf.len);
if (len > SPLPAR_TLB_BIC_MAXLENGTH) {
pr_warn("%s too large returned buffer %d", __func__, len);
return;
}
idx = 2;
idx = 0;
while (idx < len) {
u8 block_shift = local_buffer[idx++];
u8 block_shift = buf.val[idx++];
u32 block_size;
unsigned int npsize;
@ -1525,9 +1506,9 @@ void __init pseries_lpar_read_hblkrm_characteristics(void)
block_size = 1 << block_shift;
for (npsize = local_buffer[idx++];
for (npsize = buf.val[idx++];
npsize > 0 && idx < len; npsize--)
check_lp_set_hblkrm((unsigned int) local_buffer[idx++],
check_lp_set_hblkrm((unsigned int)buf.val[idx++],
block_size);
}

View File

@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <asm/papr-sysparm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@ -311,16 +312,6 @@ static void parse_mpp_x_data(struct seq_file *m)
seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
}
/*
* PAPR defines, in section "7.3.16 System Parameters Option", the token 55 to
* read the LPAR name, and the largest output data to 4000 + 2 bytes length.
*/
#define SPLPAR_LPAR_NAME_TOKEN 55
#define GET_SYS_PARM_BUF_SIZE 4002
#if GET_SYS_PARM_BUF_SIZE > RTAS_DATA_BUF_SIZE
#error "GET_SYS_PARM_BUF_SIZE is larger than RTAS_DATA_BUF_SIZE"
#endif
/*
* Read the lpar name using the RTAS ibm,get-system-parameter call.
*
@ -332,46 +323,19 @@ static void parse_mpp_x_data(struct seq_file *m)
*/
static int read_rtas_lpar_name(struct seq_file *m)
{
int rc, len, token;
union {
char raw_buffer[GET_SYS_PARM_BUF_SIZE];
struct {
__be16 len;
char name[GET_SYS_PARM_BUF_SIZE-2];
};
} *local_buffer;
struct papr_sysparm_buf *buf;
int err;
token = rtas_token("ibm,get-system-parameter");
if (token == RTAS_UNKNOWN_SERVICE)
return -EINVAL;
local_buffer = kmalloc(sizeof(*local_buffer), GFP_KERNEL);
if (!local_buffer)
buf = papr_sysparm_buf_alloc();
if (!buf)
return -ENOMEM;
do {
spin_lock(&rtas_data_buf_lock);
memset(rtas_data_buf, 0, sizeof(*local_buffer));
rc = rtas_call(token, 3, 1, NULL, SPLPAR_LPAR_NAME_TOKEN,
__pa(rtas_data_buf), sizeof(*local_buffer));
if (!rc)
memcpy(local_buffer->raw_buffer, rtas_data_buf,
sizeof(local_buffer->raw_buffer));
spin_unlock(&rtas_data_buf_lock);
} while (rtas_busy_delay(rc));
err = papr_sysparm_get(PAPR_SYSPARM_LPAR_NAME, buf);
if (!err)
seq_printf(m, "partition_name=%s\n", buf->val);
if (!rc) {
/* Force end of string */
len = min((int) be16_to_cpu(local_buffer->len),
(int) sizeof(local_buffer->name)-1);
local_buffer->name[len] = '\0';
seq_printf(m, "partition_name=%s\n", local_buffer->name);
} else
rc = -ENODATA;
kfree(local_buffer);
return rc;
papr_sysparm_buf_free(buf);
return err;
}
/*
@ -397,7 +361,6 @@ static void read_lpar_name(struct seq_file *m)
pr_err_once("Error can't get the LPAR name");
}
#define SPLPAR_CHARACTERISTICS_TOKEN 20
#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
/*
@ -408,45 +371,25 @@ static void read_lpar_name(struct seq_file *m)
*/
static void parse_system_parameter_string(struct seq_file *m)
{
int call_status;
struct papr_sysparm_buf *buf;
unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
if (!local_buffer) {
printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
__FILE__, __func__, __LINE__);
buf = papr_sysparm_buf_alloc();
if (!buf)
return;
}
spin_lock(&rtas_data_buf_lock);
memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
NULL,
SPLPAR_CHARACTERISTICS_TOKEN,
__pa(rtas_data_buf),
RTAS_DATA_BUF_SIZE);
memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
spin_unlock(&rtas_data_buf_lock);
if (call_status != 0) {
printk(KERN_INFO
"%s %s Error calling get-system-parameter (0x%x)\n",
__FILE__, __func__, call_status);
if (papr_sysparm_get(PAPR_SYSPARM_SHARED_PROC_LPAR_ATTRS, buf)) {
goto out_free;
} else {
const char *local_buffer;
int splpar_strlen;
int idx, w_idx;
char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
if (!workbuffer) {
printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
__FILE__, __func__, __LINE__);
kfree(local_buffer);
return;
}
#ifdef LPARCFG_DEBUG
printk(KERN_INFO "success calling get-system-parameter\n");
#endif
splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
local_buffer += 2; /* step over strlen value */
if (!workbuffer)
goto out_free;
splpar_strlen = be16_to_cpu(buf->len);
local_buffer = buf->val;
w_idx = 0;
idx = 0;
@ -480,7 +423,8 @@ static void parse_system_parameter_string(struct seq_file *m)
kfree(workbuffer);
local_buffer -= 2; /* back up over strlen value */
}
kfree(local_buffer);
out_free:
papr_sysparm_buf_free(buf);
}
/* Return the number of processors in the system.

View File

@ -195,7 +195,7 @@ static int update_dt_node(struct device_node *dn, s32 scope)
u32 nprops;
u32 vd;
update_properties_token = rtas_token("ibm,update-properties");
update_properties_token = rtas_function_token(RTAS_FN_IBM_UPDATE_PROPERTIES);
if (update_properties_token == RTAS_UNKNOWN_SERVICE)
return -EINVAL;
@ -306,7 +306,7 @@ static int pseries_devicetree_update(s32 scope)
int update_nodes_token;
int rc;
update_nodes_token = rtas_token("ibm,update-nodes");
update_nodes_token = rtas_function_token(RTAS_FN_IBM_UPDATE_NODES);
if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
return 0;

View File

@ -679,8 +679,8 @@ static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
static int rtas_msi_init(void)
{
query_token = rtas_token("ibm,query-interrupt-source-number");
change_token = rtas_token("ibm,change-msi");
query_token = rtas_function_token(RTAS_FN_IBM_QUERY_INTERRUPT_SOURCE_NUMBER);
change_token = rtas_function_token(RTAS_FN_IBM_CHANGE_MSI);
if ((query_token == RTAS_UNKNOWN_SERVICE) ||
(change_token == RTAS_UNKNOWN_SERVICE)) {

View File

@ -227,8 +227,8 @@ int __init pSeries_nvram_init(void)
nvram_size = be32_to_cpup(nbytes_p);
nvram_fetch = rtas_token("nvram-fetch");
nvram_store = rtas_token("nvram-store");
nvram_fetch = rtas_function_token(RTAS_FN_NVRAM_FETCH);
nvram_store = rtas_function_token(RTAS_FN_NVRAM_STORE);
printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
of_node_put(nvram);

View File

@ -0,0 +1,151 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "papr-sysparm: " fmt
#include <linux/bug.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <asm/rtas.h>
#include <asm/papr-sysparm.h>
#include <asm/rtas-work-area.h>
struct papr_sysparm_buf *papr_sysparm_buf_alloc(void)
{
struct papr_sysparm_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
return buf;
}
void papr_sysparm_buf_free(struct papr_sysparm_buf *buf)
{
kfree(buf);
}
/**
* papr_sysparm_get() - Retrieve the value of a PAPR system parameter.
* @param: PAPR system parameter token as described in
* 7.3.16 "System Parameters Option".
* @buf: A &struct papr_sysparm_buf as returned from papr_sysparm_buf_alloc().
*
* Place the result of querying the specified parameter, if available,
* in @buf. The result includes a be16 length header followed by the
* value, which may be a string or binary data. See &struct papr_sysparm_buf.
*
* Since there is at least one parameter (60, OS Service Entitlement
* Status) where the results depend on the incoming contents of the
* work area, the caller-supplied buffer is copied unmodified into the
* work area before calling ibm,get-system-parameter.
*
* A defined parameter may not be implemented on a given system, and
* some implemented parameters may not be available to all partitions
* on a system. A parameter's disposition may change at any time due
* to system configuration changes or partition migration.
*
* Context: This function may sleep.
*
* Return: 0 on success, -errno otherwise. @buf is unmodified on error.
*/
int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf)
{
const s32 token = rtas_function_token(RTAS_FN_IBM_GET_SYSTEM_PARAMETER);
struct rtas_work_area *work_area;
s32 fwrc;
int ret;
might_sleep();
if (WARN_ON(!buf))
return -EFAULT;
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
work_area = rtas_work_area_alloc(sizeof(*buf));
memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf));
do {
fwrc = rtas_call(token, 3, 1, NULL, param.token,
rtas_work_area_phys(work_area),
rtas_work_area_size(work_area));
} while (rtas_busy_delay(fwrc));
switch (fwrc) {
case 0:
ret = 0;
memcpy(buf, rtas_work_area_raw_buf(work_area), sizeof(*buf));
break;
case -3: /* parameter not implemented */
ret = -EOPNOTSUPP;
break;
case -9002: /* this partition not authorized to retrieve this parameter */
ret = -EPERM;
break;
case -9999: /* "parameter error" e.g. the buffer is too small */
ret = -EINVAL;
break;
default:
pr_err("unexpected ibm,get-system-parameter result %d\n", fwrc);
fallthrough;
case -1: /* Hardware/platform error */
ret = -EIO;
break;
}
rtas_work_area_free(work_area);
return ret;
}
int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf)
{
const s32 token = rtas_function_token(RTAS_FN_IBM_SET_SYSTEM_PARAMETER);
struct rtas_work_area *work_area;
s32 fwrc;
int ret;
might_sleep();
if (WARN_ON(!buf))
return -EFAULT;
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
work_area = rtas_work_area_alloc(sizeof(*buf));
memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf));
do {
fwrc = rtas_call(token, 2, 1, NULL, param.token,
rtas_work_area_phys(work_area));
} while (rtas_busy_delay(fwrc));
switch (fwrc) {
case 0:
ret = 0;
break;
case -3: /* parameter not supported */
ret = -EOPNOTSUPP;
break;
case -9002: /* this partition not authorized to modify this parameter */
ret = -EPERM;
break;
case -9999: /* "parameter error" e.g. invalid input data */
ret = -EINVAL;
break;
default:
pr_err("unexpected ibm,set-system-parameter result %d\n", fwrc);
fallthrough;
case -1: /* Hardware/platform error */
ret = -EIO;
break;
}
rtas_work_area_free(work_area);
return ret;
}

View File

@ -60,7 +60,7 @@ static int pseries_send_map_pe(struct pci_dev *pdev, u16 num_vfs,
struct pci_dn *pdn;
int rc;
unsigned long buid, addr;
int ibm_map_pes = rtas_token("ibm,open-sriov-map-pe-number");
int ibm_map_pes = rtas_function_token(RTAS_FN_IBM_OPEN_SRIOV_MAP_PE_NUMBER);
if (ibm_map_pes == RTAS_UNKNOWN_SERVICE)
return -EINVAL;

View File

@ -0,0 +1,217 @@
// SPDX-License-Identifier: GPL-2.0-only
// Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
//
// Copyright 2022, 2023 IBM Corporation
// Authors: Russell Currey
// Andrew Donnellan
// Nayna Jain
#define pr_fmt(fmt) "secvar: "fmt
#include <linux/printk.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kobject.h>
#include <linux/nls.h>
#include <asm/machdep.h>
#include <asm/secvar.h>
#include <asm/plpks.h>
// Config attributes for sysfs
#define PLPKS_CONFIG_ATTR(name, fmt, func) \
static ssize_t name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, \
char *buf) \
{ \
return sysfs_emit(buf, fmt, func()); \
} \
static struct kobj_attribute attr_##name = __ATTR_RO(name)
PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
static const struct attribute *config_attrs[] = {
&attr_version.attr,
&attr_max_object_size.attr,
&attr_total_size.attr,
&attr_used_space.attr,
&attr_supported_policies.attr,
&attr_signed_update_algorithms.attr,
NULL,
};
static u32 get_policy(const char *name)
{
if ((strcmp(name, "db") == 0) ||
(strcmp(name, "dbx") == 0) ||
(strcmp(name, "grubdb") == 0) ||
(strcmp(name, "grubdbx") == 0) ||
(strcmp(name, "sbat") == 0))
return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
else
return PLPKS_SIGNEDUPDATE;
}
static const char * const plpks_var_names[] = {
"PK",
"KEK",
"db",
"dbx",
"grubdb",
"grubdbx",
"sbat",
"moduledb",
"trustedcadb",
NULL,
};
static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
u64 *data_size)
{
struct plpks_var var = {0};
int rc = 0;
// We subtract 1 from key_len because we don't need to include the
// null terminator at the end of the string
var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
if (!var.name)
return -ENOMEM;
rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
key_len - 1);
if (rc < 0)
goto err;
var.namelen = rc * 2;
var.os = PLPKS_VAR_LINUX;
if (data) {
var.data = data;
var.datalen = *data_size;
}
rc = plpks_read_os_var(&var);
if (rc)
goto err;
*data_size = var.datalen;
err:
kfree(var.name);
if (rc && rc != -ENOENT) {
pr_err("Failed to read variable '%s': %d\n", key, rc);
// Return -EIO since userspace probably doesn't care about the
// specific error
rc = -EIO;
}
return rc;
}
static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
u64 data_size)
{
struct plpks_var var = {0};
int rc = 0;
u64 flags;
// Secure variables need to be prefixed with 8 bytes of flags.
// We only want to perform the write if we have at least one byte of data.
if (data_size <= sizeof(flags))
return -EINVAL;
// We subtract 1 from key_len because we don't need to include the
// null terminator at the end of the string
var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
if (!var.name)
return -ENOMEM;
rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
key_len - 1);
if (rc < 0)
goto err;
var.namelen = rc * 2;
// Flags are contained in the first 8 bytes of the buffer, and are always big-endian
flags = be64_to_cpup((__be64 *)data);
var.datalen = data_size - sizeof(flags);
var.data = data + sizeof(flags);
var.os = PLPKS_VAR_LINUX;
var.policy = get_policy(key);
// Unlike in the read case, the plpks error code can be useful to
// userspace on write, so we return it rather than just -EIO
rc = plpks_signed_update_var(&var, flags);
err:
kfree(var.name);
return rc;
}
// PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
// Instead, report the format using the SB_VERSION variable in the keystore.
// The string is made up by us, and takes the form "ibm,plpks-sb-v<n>" (or "ibm,plpks-sb-unknown"
// if the SB_VERSION variable doesn't exist). Hypervisor defines the SB_VERSION variable as a
// "1 byte unsigned integer value".
static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
{
struct plpks_var var = {0};
ssize_t ret;
u8 version;
var.component = NULL;
// Only the signed variables have null bytes in their names, this one doesn't
var.name = "SB_VERSION";
var.namelen = strlen(var.name);
var.datalen = 1;
var.data = &version;
// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
ret = plpks_read_fw_var(&var);
if (ret) {
if (ret == -ENOENT) {
ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
} else {
pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
ret = -EIO;
}
goto err;
}
ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", version);
err:
return ret;
}
static int plpks_max_size(u64 *max_size)
{
// The max object size reported by the hypervisor is accurate for the
// object itself, but we use the first 8 bytes of data on write as the
// signed update flags, so the max size a user can write is larger.
*max_size = (u64)plpks_get_maxobjectsize() + sizeof(u64);
return 0;
}
static const struct secvar_operations plpks_secvar_ops = {
.get = plpks_get_variable,
.set = plpks_set_variable,
.format = plpks_secvar_format,
.max_size = plpks_max_size,
.config_attrs = config_attrs,
.var_names = plpks_var_names,
};
static int plpks_secvar_init(void)
{
if (!plpks_is_available())
return -ENODEV;
return set_secvar_ops(&plpks_secvar_ops);
}
machine_device_initcall(pseries, plpks_secvar_init);

View File

@ -16,30 +16,28 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/memblock.h>
#include <asm/hvcall.h>
#include <asm/machdep.h>
#include "plpks.h"
#define PKS_FW_OWNER 0x1
#define PKS_BOOTLOADER_OWNER 0x2
#define PKS_OS_OWNER 0x3
#define LABEL_VERSION 0
#define MAX_LABEL_ATTR_SIZE 16
#define MAX_NAME_SIZE 239
#define MAX_DATA_SIZE 4000
#define PKS_FLUSH_MAX_TIMEOUT 5000 //msec
#define PKS_FLUSH_SLEEP 10 //msec
#define PKS_FLUSH_SLEEP_RANGE 400
#include <asm/plpks.h>
#include <asm/firmware.h>
static u8 *ospassword;
static u16 ospasswordlength;
// Retrieved with H_PKS_GET_CONFIG
static u8 version;
static u16 objoverhead;
static u16 maxpwsize;
static u16 maxobjsize;
static s16 maxobjlabelsize;
static u32 totalsize;
static u32 usedspace;
static u32 supportedpolicies;
static u32 maxlargeobjectsize;
static u64 signedupdatealgorithms;
struct plpks_auth {
u8 version;
@ -60,7 +58,7 @@ struct label_attr {
struct label {
struct label_attr attr;
u8 name[MAX_NAME_SIZE];
u8 name[PLPKS_MAX_NAME_SIZE];
size_t size;
};
@ -87,6 +85,12 @@ static int pseries_status_to_err(int rc)
err = -ENOENT;
break;
case H_BUSY:
case H_LONG_BUSY_ORDER_1_MSEC:
case H_LONG_BUSY_ORDER_10_MSEC:
case H_LONG_BUSY_ORDER_100_MSEC:
case H_LONG_BUSY_ORDER_1_SEC:
case H_LONG_BUSY_ORDER_10_SEC:
case H_LONG_BUSY_ORDER_100_SEC:
err = -EBUSY;
break;
case H_AUTHORITY:
@ -117,16 +121,25 @@ static int pseries_status_to_err(int rc)
err = -EINVAL;
}
pr_debug("Converted hypervisor code %d to Linux %d\n", rc, err);
return err;
}
static int plpks_gen_password(void)
{
unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
u8 *password, consumer = PKS_OS_OWNER;
u8 *password, consumer = PLPKS_OS_OWNER;
int rc;
password = kzalloc(maxpwsize, GFP_KERNEL);
// If we booted from kexec, we could be reusing an existing password already
if (ospassword) {
pr_debug("Password of length %u already in use\n", ospasswordlength);
return 0;
}
// The password must not cross a page boundary, so we align to the next power of 2
password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
if (!password)
return -ENOMEM;
@ -143,7 +156,7 @@ static int plpks_gen_password(void)
memcpy(ospassword, password, ospasswordlength);
} else {
if (rc == H_IN_USE) {
pr_warn("Password is already set for POWER LPAR Platform KeyStore\n");
pr_warn("Password already set - authenticated operations will fail\n");
rc = 0;
} else {
goto out;
@ -159,17 +172,19 @@ static struct plpks_auth *construct_auth(u8 consumer)
{
struct plpks_auth *auth;
if (consumer > PKS_OS_OWNER)
if (consumer > PLPKS_OS_OWNER)
return ERR_PTR(-EINVAL);
auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
// The auth structure must not cross a page boundary and must be
// 16 byte aligned. We align to the next largest power of 2
auth = kzalloc(roundup_pow_of_two(struct_size(auth, password, maxpwsize)), GFP_KERNEL);
if (!auth)
return ERR_PTR(-ENOMEM);
auth->version = 1;
auth->consumer = consumer;
if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER)
if (consumer == PLPKS_FW_OWNER || consumer == PLPKS_BOOTLOADER_OWNER)
return auth;
memcpy(auth->password, ospassword, ospasswordlength);
@ -187,25 +202,29 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
u16 namelen)
{
struct label *label;
size_t slen;
size_t slen = 0;
if (!name || namelen > MAX_NAME_SIZE)
if (!name || namelen > PLPKS_MAX_NAME_SIZE)
return ERR_PTR(-EINVAL);
slen = strlen(component);
if (component && slen > sizeof(label->attr.prefix))
return ERR_PTR(-EINVAL);
// Support NULL component for signed updates
if (component) {
slen = strlen(component);
if (slen > sizeof(label->attr.prefix))
return ERR_PTR(-EINVAL);
}
label = kzalloc(sizeof(*label), GFP_KERNEL);
// The label structure must not cross a page boundary, so we align to the next power of 2
label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
if (!label)
return ERR_PTR(-ENOMEM);
if (component)
memcpy(&label->attr.prefix, component, slen);
label->attr.version = LABEL_VERSION;
label->attr.version = PLPKS_LABEL_VERSION;
label->attr.os = varos;
label->attr.length = MAX_LABEL_ATTR_SIZE;
label->attr.length = PLPKS_MAX_LABEL_ATTR_SIZE;
memcpy(&label->name, name, namelen);
label->size = sizeof(struct label_attr) + namelen;
@ -216,38 +235,164 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
static int _plpks_get_config(void)
{
unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
struct {
struct config {
u8 version;
u8 flags;
__be32 rsvd0;
__be16 rsvd0;
__be16 objoverhead;
__be16 maxpwsize;
__be16 maxobjlabelsize;
__be16 maxobjsize;
__be32 totalsize;
__be32 usedspace;
__be32 supportedpolicies;
__be64 rsvd1;
} __packed config;
__be32 maxlargeobjectsize;
__be64 signedupdatealgorithms;
u8 rsvd1[476];
} __packed * config;
size_t size;
int rc = 0;
size = sizeof(*config);
// Config struct must not cross a page boundary. So long as the struct
// size is a power of 2, this should be fine as alignment is guaranteed
config = kzalloc(size, GFP_KERNEL);
if (!config) {
rc = -ENOMEM;
goto err;
}
rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(config), size);
if (rc != H_SUCCESS) {
rc = pseries_status_to_err(rc);
goto err;
}
version = config->version;
objoverhead = be16_to_cpu(config->objoverhead);
maxpwsize = be16_to_cpu(config->maxpwsize);
maxobjsize = be16_to_cpu(config->maxobjsize);
maxobjlabelsize = be16_to_cpu(config->maxobjlabelsize);
totalsize = be32_to_cpu(config->totalsize);
usedspace = be32_to_cpu(config->usedspace);
supportedpolicies = be32_to_cpu(config->supportedpolicies);
maxlargeobjectsize = be32_to_cpu(config->maxlargeobjectsize);
signedupdatealgorithms = be64_to_cpu(config->signedupdatealgorithms);
// Validate that the numbers we get back match the requirements of the spec
if (maxpwsize < 32) {
pr_err("Invalid Max Password Size received from hypervisor (%d < 32)\n", maxpwsize);
rc = -EIO;
goto err;
}
if (maxobjlabelsize < 255) {
pr_err("Invalid Max Object Label Size received from hypervisor (%d < 255)\n",
maxobjlabelsize);
rc = -EIO;
goto err;
}
if (totalsize < 4096) {
pr_err("Invalid Total Size received from hypervisor (%d < 4096)\n", totalsize);
rc = -EIO;
goto err;
}
if (version >= 3 && maxlargeobjectsize >= 65536 && maxobjsize != 0xFFFF) {
pr_err("Invalid Max Object Size (0x%x != 0xFFFF)\n", maxobjsize);
rc = -EIO;
goto err;
}
err:
kfree(config);
return rc;
}
u8 plpks_get_version(void)
{
return version;
}
u16 plpks_get_objoverhead(void)
{
return objoverhead;
}
u16 plpks_get_maxpwsize(void)
{
return maxpwsize;
}
u16 plpks_get_maxobjectsize(void)
{
return maxobjsize;
}
u16 plpks_get_maxobjectlabelsize(void)
{
return maxobjlabelsize;
}
u32 plpks_get_totalsize(void)
{
return totalsize;
}
u32 plpks_get_usedspace(void)
{
// Unlike other config values, usedspace regularly changes as objects
// are updated, so we need to refresh.
int rc = _plpks_get_config();
if (rc) {
pr_err("Couldn't get config, rc: %d\n", rc);
return 0;
}
return usedspace;
}
u32 plpks_get_supportedpolicies(void)
{
return supportedpolicies;
}
u32 plpks_get_maxlargeobjectsize(void)
{
return maxlargeobjectsize;
}
u64 plpks_get_signedupdatealgorithms(void)
{
return signedupdatealgorithms;
}
u16 plpks_get_passwordlen(void)
{
return ospasswordlength;
}
bool plpks_is_available(void)
{
int rc;
size = sizeof(config);
if (!firmware_has_feature(FW_FEATURE_LPAR))
return false;
rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(&config), size);
rc = _plpks_get_config();
if (rc)
return false;
if (rc != H_SUCCESS)
return pseries_status_to_err(rc);
maxpwsize = be16_to_cpu(config.maxpwsize);
maxobjsize = be16_to_cpu(config.maxobjsize);
return 0;
return true;
}
static int plpks_confirm_object_flushed(struct label *label,
struct plpks_auth *auth)
{
unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
bool timed_out = true;
u64 timeout = 0;
u8 status;
int rc;
@ -259,20 +404,79 @@ static int plpks_confirm_object_flushed(struct label *label,
status = retbuf[0];
if (rc) {
timed_out = false;
if (rc == H_NOT_FOUND && status == 1)
rc = 0;
break;
}
if (!rc && status == 1)
if (!rc && status == 1) {
timed_out = false;
break;
}
usleep_range(PKS_FLUSH_SLEEP,
PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
timeout = timeout + PKS_FLUSH_SLEEP;
} while (timeout < PKS_FLUSH_MAX_TIMEOUT);
usleep_range(PLPKS_FLUSH_SLEEP,
PLPKS_FLUSH_SLEEP + PLPKS_FLUSH_SLEEP_RANGE);
timeout = timeout + PLPKS_FLUSH_SLEEP;
} while (timeout < PLPKS_MAX_TIMEOUT);
rc = pseries_status_to_err(rc);
if (timed_out)
return -ETIMEDOUT;
return pseries_status_to_err(rc);
}
int plpks_signed_update_var(struct plpks_var *var, u64 flags)
{
unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
int rc;
struct label *label;
struct plpks_auth *auth;
u64 continuetoken = 0;
u64 timeout = 0;
if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE)
return -EINVAL;
if (!(var->policy & PLPKS_SIGNEDUPDATE))
return -EINVAL;
// Signed updates need the component to be NULL.
if (var->component)
return -EINVAL;
auth = construct_auth(PLPKS_OS_OWNER);
if (IS_ERR(auth))
return PTR_ERR(auth);
label = construct_label(var->component, var->os, var->name, var->namelen);
if (IS_ERR(label)) {
rc = PTR_ERR(label);
goto out;
}
do {
rc = plpar_hcall9(H_PKS_SIGNED_UPDATE, retbuf,
virt_to_phys(auth), virt_to_phys(label),
label->size, var->policy, flags,
virt_to_phys(var->data), var->datalen,
continuetoken);
continuetoken = retbuf[0];
if (pseries_status_to_err(rc) == -EBUSY) {
int delay_ms = get_longbusy_msecs(rc);
mdelay(delay_ms);
timeout += delay_ms;
}
rc = pseries_status_to_err(rc);
} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
if (!rc)
rc = plpks_confirm_object_flushed(label, auth);
kfree(label);
out:
kfree(auth);
return rc;
}
@ -285,13 +489,13 @@ int plpks_write_var(struct plpks_var var)
int rc;
if (!var.component || !var.data || var.datalen <= 0 ||
var.namelen > MAX_NAME_SIZE || var.datalen > MAX_DATA_SIZE)
var.namelen > PLPKS_MAX_NAME_SIZE || var.datalen > PLPKS_MAX_DATA_SIZE)
return -EINVAL;
if (var.policy & SIGNEDUPDATE)
if (var.policy & PLPKS_SIGNEDUPDATE)
return -EINVAL;
auth = construct_auth(PKS_OS_OWNER);
auth = construct_auth(PLPKS_OS_OWNER);
if (IS_ERR(auth))
return PTR_ERR(auth);
@ -323,10 +527,10 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
struct label *label;
int rc;
if (!component || vname.namelen > MAX_NAME_SIZE)
if (vname.namelen > PLPKS_MAX_NAME_SIZE)
return -EINVAL;
auth = construct_auth(PKS_OS_OWNER);
auth = construct_auth(PLPKS_OS_OWNER);
if (IS_ERR(auth))
return PTR_ERR(auth);
@ -358,14 +562,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
u8 *output;
int rc;
if (var->namelen > MAX_NAME_SIZE)
if (var->namelen > PLPKS_MAX_NAME_SIZE)
return -EINVAL;
auth = construct_auth(consumer);
if (IS_ERR(auth))
return PTR_ERR(auth);
if (consumer == PKS_OS_OWNER) {
if (consumer == PLPKS_OS_OWNER) {
label = construct_label(var->component, var->os, var->name,
var->namelen);
if (IS_ERR(label)) {
@ -380,7 +584,7 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
goto out_free_label;
}
if (consumer == PKS_OS_OWNER)
if (consumer == PLPKS_OS_OWNER)
rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth),
virt_to_phys(label), label->size, virt_to_phys(output),
maxobjsize);
@ -395,17 +599,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
goto out_free_output;
}
if (var->datalen == 0 || var->datalen > retbuf[0])
if (!var->data || var->datalen > retbuf[0])
var->datalen = retbuf[0];
var->data = kzalloc(var->datalen, GFP_KERNEL);
if (!var->data) {
rc = -ENOMEM;
goto out_free_output;
}
var->policy = retbuf[1];
memcpy(var->data, output, var->datalen);
if (var->data)
memcpy(var->data, output, var->datalen);
rc = 0;
out_free_output:
@ -420,17 +621,69 @@ out_free_auth:
int plpks_read_os_var(struct plpks_var *var)
{
return plpks_read_var(PKS_OS_OWNER, var);
return plpks_read_var(PLPKS_OS_OWNER, var);
}
int plpks_read_fw_var(struct plpks_var *var)
{
return plpks_read_var(PKS_FW_OWNER, var);
return plpks_read_var(PLPKS_FW_OWNER, var);
}
int plpks_read_bootloader_var(struct plpks_var *var)
{
return plpks_read_var(PKS_BOOTLOADER_OWNER, var);
return plpks_read_var(PLPKS_BOOTLOADER_OWNER, var);
}
int plpks_populate_fdt(void *fdt)
{
int chosen_offset = fdt_path_offset(fdt, "/chosen");
if (chosen_offset < 0) {
pr_err("Can't find chosen node: %s\n",
fdt_strerror(chosen_offset));
return chosen_offset;
}
return fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw", ospassword, ospasswordlength);
}
// Once a password is registered with the hypervisor it cannot be cleared without
// rebooting the LPAR, so to keep using the PLPKS across kexec boots we need to
// recover the previous password from the FDT.
//
// There are a few challenges here. We don't want the password to be visible to
// users, so we need to clear it from the FDT. This has to be done in early boot.
// Clearing it from the FDT would make the FDT's checksum invalid, so we have to
// manually cause the checksum to be recalculated.
void __init plpks_early_init_devtree(void)
{
void *fdt = initial_boot_params;
int chosen_node = fdt_path_offset(fdt, "/chosen");
const u8 *password;
int len;
if (chosen_node < 0)
return;
password = fdt_getprop(fdt, chosen_node, "ibm,plpks-pw", &len);
if (len <= 0) {
pr_debug("Couldn't find ibm,plpks-pw node.\n");
return;
}
ospassword = memblock_alloc_raw(len, SMP_CACHE_BYTES);
if (!ospassword) {
pr_err("Error allocating memory for password.\n");
goto out;
}
memcpy(ospassword, password, len);
ospasswordlength = (u16)len;
out:
fdt_nop_property(fdt, chosen_node, "ibm,plpks-pw");
// Since we've cleared the password, we must update the FDT checksum
early_init_dt_verify(fdt);
}
static __init int pseries_plpks_init(void)

View File

@ -1,71 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 IBM Corporation
* Author: Nayna Jain <nayna@linux.ibm.com>
*
* Platform keystore for pseries LPAR(PLPKS).
*/
#ifndef _PSERIES_PLPKS_H
#define _PSERIES_PLPKS_H
#include <linux/types.h>
#include <linux/list.h>
#define OSSECBOOTAUDIT 0x40000000
#define OSSECBOOTENFORCE 0x20000000
#define WORLDREADABLE 0x08000000
#define SIGNEDUPDATE 0x01000000
#define PLPKS_VAR_LINUX 0x02
#define PLPKS_VAR_COMMON 0x04
struct plpks_var {
char *component;
u8 *name;
u8 *data;
u32 policy;
u16 namelen;
u16 datalen;
u8 os;
};
struct plpks_var_name {
u8 *name;
u16 namelen;
};
struct plpks_var_name_list {
u32 varcount;
struct plpks_var_name varlist[];
};
/**
* Writes the specified var and its data to PKS.
* Any caller of PKS driver should present a valid component type for
* their variable.
*/
int plpks_write_var(struct plpks_var var);
/**
* Removes the specified var and its data from PKS.
*/
int plpks_remove_var(char *component, u8 varos,
struct plpks_var_name vname);
/**
* Returns the data for the specified os variable.
*/
int plpks_read_os_var(struct plpks_var *var);
/**
* Returns the data for the specified firmware variable.
*/
int plpks_read_fw_var(struct plpks_var *var);
/**
* Returns the data for the specified bootloader variable.
*/
int plpks_read_bootloader_var(struct plpks_var *var);
#endif

View File

@ -155,7 +155,7 @@ static int __init init_ras_IRQ(void)
{
struct device_node *np;
ras_check_exception_token = rtas_token("check-exception");
ras_check_exception_token = rtas_function_token(RTAS_FN_CHECK_EXCEPTION);
/* Internal Errors */
np = of_find_node_by_path("/event-sources/internal-errors");

View File

@ -0,0 +1,209 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "rtas-work-area: " fmt
#include <linux/genalloc.h>
#include <linux/log2.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/mempool.h>
#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/numa.h>
#include <linux/sizes.h>
#include <linux/wait.h>
#include <asm/machdep.h>
#include <asm/rtas-work-area.h>
#include <asm/rtas.h>
enum {
/*
* Ensure the pool is page-aligned.
*/
RTAS_WORK_AREA_ARENA_ALIGN = PAGE_SIZE,
/*
* Don't let a single allocation claim the whole arena.
*/
RTAS_WORK_AREA_ARENA_SZ = RTAS_WORK_AREA_MAX_ALLOC_SZ * 2,
/*
* The smallest known work area size is for ibm,get-vpd's
* location code argument, which is limited to 79 characters
* plus 1 nul terminator.
*
* PAPR+ 7.3.20 ibm,get-vpd RTAS Call
* PAPR+ 12.3.2.4 Converged Location Code Rules - Length Restrictions
*/
RTAS_WORK_AREA_MIN_ALLOC_SZ = roundup_pow_of_two(80),
};
static struct {
struct gen_pool *gen_pool;
char *arena;
struct mutex mutex; /* serializes allocations */
struct wait_queue_head wqh;
mempool_t descriptor_pool;
bool available;
} rwa_state = {
.mutex = __MUTEX_INITIALIZER(rwa_state.mutex),
.wqh = __WAIT_QUEUE_HEAD_INITIALIZER(rwa_state.wqh),
};
/*
* A single work area buffer and descriptor to serve requests early in
* boot before the allocator is fully initialized. We know 4KB is the
* most any boot time user needs (they all call ibm,get-system-parameter).
*/
static bool early_work_area_in_use __initdata;
static char early_work_area_buf[SZ_4K] __initdata __aligned(SZ_4K);
static struct rtas_work_area early_work_area __initdata = {
.buf = early_work_area_buf,
.size = sizeof(early_work_area_buf),
};
static struct rtas_work_area * __init rtas_work_area_alloc_early(size_t size)
{
WARN_ON(size > early_work_area.size);
WARN_ON(early_work_area_in_use);
early_work_area_in_use = true;
memset(early_work_area.buf, 0, early_work_area.size);
return &early_work_area;
}
static void __init rtas_work_area_free_early(struct rtas_work_area *work_area)
{
WARN_ON(work_area != &early_work_area);
WARN_ON(!early_work_area_in_use);
early_work_area_in_use = false;
}
struct rtas_work_area * __ref __rtas_work_area_alloc(size_t size)
{
struct rtas_work_area *area;
unsigned long addr;
might_sleep();
/*
* The rtas_work_area_alloc() wrapper enforces this at build
* time. Requests that exceed the arena size will block
* indefinitely.
*/
WARN_ON(size > RTAS_WORK_AREA_MAX_ALLOC_SZ);
if (!rwa_state.available)
return rtas_work_area_alloc_early(size);
/*
* To ensure FCFS behavior and prevent a high rate of smaller
* requests from starving larger ones, use the mutex to queue
* allocations.
*/
mutex_lock(&rwa_state.mutex);
wait_event(rwa_state.wqh,
(addr = gen_pool_alloc(rwa_state.gen_pool, size)) != 0);
mutex_unlock(&rwa_state.mutex);
area = mempool_alloc(&rwa_state.descriptor_pool, GFP_KERNEL);
area->buf = (char *)addr;
area->size = size;
return area;
}
void __ref rtas_work_area_free(struct rtas_work_area *area)
{
if (!rwa_state.available) {
rtas_work_area_free_early(area);
return;
}
gen_pool_free(rwa_state.gen_pool, (unsigned long)area->buf, area->size);
mempool_free(area, &rwa_state.descriptor_pool);
wake_up(&rwa_state.wqh);
}
/*
* Initialization of the work area allocator happens in two parts. To
* reliably reserve an arena that satisfies RTAS addressing
* requirements, we must perform a memblock allocation early,
* immmediately after RTAS instantiation. Then we have to wait until
* the slab allocator is up before setting up the descriptor mempool
* and adding the arena to a gen_pool.
*/
static __init int rtas_work_area_allocator_init(void)
{
const unsigned int order = ilog2(RTAS_WORK_AREA_MIN_ALLOC_SZ);
const phys_addr_t pa_start = __pa(rwa_state.arena);
const phys_addr_t pa_end = pa_start + RTAS_WORK_AREA_ARENA_SZ - 1;
struct gen_pool *pool;
const int nid = NUMA_NO_NODE;
int err;
err = -ENOMEM;
if (!rwa_state.arena)
goto err_out;
pool = gen_pool_create(order, nid);
if (!pool)
goto err_out;
/*
* All RTAS functions that consume work areas are OK with
* natural alignment, when they have alignment requirements at
* all.
*/
gen_pool_set_algo(pool, gen_pool_first_fit_order_align, NULL);
err = gen_pool_add(pool, (unsigned long)rwa_state.arena,
RTAS_WORK_AREA_ARENA_SZ, nid);
if (err)
goto err_destroy;
err = mempool_init_kmalloc_pool(&rwa_state.descriptor_pool, 1,
sizeof(struct rtas_work_area));
if (err)
goto err_destroy;
rwa_state.gen_pool = pool;
rwa_state.available = true;
pr_debug("arena [%pa-%pa] (%uK), min/max alloc sizes %u/%u\n",
&pa_start, &pa_end,
RTAS_WORK_AREA_ARENA_SZ / SZ_1K,
RTAS_WORK_AREA_MIN_ALLOC_SZ,
RTAS_WORK_AREA_MAX_ALLOC_SZ);
return 0;
err_destroy:
gen_pool_destroy(pool);
err_out:
return err;
}
machine_arch_initcall(pseries, rtas_work_area_allocator_init);
/**
* rtas_work_area_reserve_arena() - Reserve memory suitable for RTAS work areas.
*/
void __init rtas_work_area_reserve_arena(const phys_addr_t limit)
{
const phys_addr_t align = RTAS_WORK_AREA_ARENA_ALIGN;
const phys_addr_t size = RTAS_WORK_AREA_ARENA_SZ;
const phys_addr_t min = MEMBLOCK_LOW_LIMIT;
const int nid = NUMA_NO_NODE;
/*
* Too early for a machine_is(pseries) check. But PAPR
* effectively mandates that ibm,get-system-parameter is
* present:
*
* R17.3.161. All platforms must support the System
* Parameters option.
*
* So set up the arena if we find that, with a fallback to
* ibm,configure-connector, just in case.
*/
if (rtas_function_implemented(RTAS_FN_IBM_GET_SYSTEM_PARAMETER) ||
rtas_function_implemented(RTAS_FN_IBM_CONFIGURE_CONNECTOR))
rwa_state.arena = memblock_alloc_try_nid(size, align, min, limit, nid);
}

View File

@ -57,6 +57,7 @@
#include <asm/pmc.h>
#include <asm/xics.h>
#include <asm/xive.h>
#include <asm/papr-sysparm.h>
#include <asm/ppc-pci.h>
#include <asm/i8259.h>
#include <asm/udbg.h>
@ -135,11 +136,11 @@ static void __init fwnmi_init(void)
#endif
int ibm_nmi_register_token;
ibm_nmi_register_token = rtas_token("ibm,nmi-register");
ibm_nmi_register_token = rtas_function_token(RTAS_FN_IBM_NMI_REGISTER);
if (ibm_nmi_register_token == RTAS_UNKNOWN_SERVICE)
return;
ibm_nmi_interlock_token = rtas_token("ibm,nmi-interlock");
ibm_nmi_interlock_token = rtas_function_token(RTAS_FN_IBM_NMI_INTERLOCK);
if (WARN_ON(ibm_nmi_interlock_token == RTAS_UNKNOWN_SERVICE))
return;
@ -941,28 +942,21 @@ void pSeries_coalesce_init(void)
*/
static void __init pSeries_cmo_feature_init(void)
{
static struct papr_sysparm_buf buf __initdata;
static_assert(sizeof(buf.val) >= CMO_MAXLENGTH);
char *ptr, *key, *value, *end;
int call_status;
int page_order = IOMMU_PAGE_SHIFT_4K;
pr_debug(" -> fw_cmo_feature_init()\n");
spin_lock(&rtas_data_buf_lock);
memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
NULL,
CMO_CHARACTERISTICS_TOKEN,
__pa(rtas_data_buf),
RTAS_DATA_BUF_SIZE);
if (call_status != 0) {
spin_unlock(&rtas_data_buf_lock);
if (papr_sysparm_get(PAPR_SYSPARM_COOP_MEM_OVERCOMMIT_ATTRS, &buf)) {
pr_debug("CMO not available\n");
pr_debug(" <- fw_cmo_feature_init()\n");
return;
}
end = rtas_data_buf + CMO_MAXLENGTH - 2;
ptr = rtas_data_buf + 2; /* step over strlen value */
end = &buf.val[CMO_MAXLENGTH];
ptr = &buf.val[0];
key = value = ptr;
while (*ptr && (ptr <= end)) {
@ -1008,7 +1002,6 @@ static void __init pSeries_cmo_feature_init(void)
} else
pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
CMO_SecPSP);
spin_unlock(&rtas_data_buf_lock);
pr_debug(" <- fw_cmo_feature_init()\n");
}
@ -1078,14 +1071,14 @@ static void __init pseries_init(void)
static void pseries_power_off(void)
{
int rc;
int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups");
int rtas_poweroff_ups_token = rtas_function_token(RTAS_FN_IBM_POWER_OFF_UPS);
if (rtas_flash_term_hook)
rtas_flash_term_hook(SYS_POWER_OFF);
if (rtas_poweron_auto == 0 ||
rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) {
rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1);
rc = rtas_call(rtas_function_token(RTAS_FN_POWER_OFF), 2, 1, NULL, -1, -1);
printk(KERN_INFO "RTAS power-off returned %d\n", rc);
} else {
rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL);

View File

@ -55,7 +55,7 @@ static cpumask_var_t of_spin_mask;
int smp_query_cpu_stopped(unsigned int pcpu)
{
int cpu_status, status;
int qcss_tok = rtas_token("query-cpu-stopped-state");
int qcss_tok = rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE);
if (qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk_once(KERN_INFO
@ -108,7 +108,7 @@ static inline int smp_startup_cpu(unsigned int lcpu)
* If the RTAS start-cpu token does not exist then presume the
* cpu is already spinning.
*/
start_cpu = rtas_token("start-cpu");
start_cpu = rtas_function_token(RTAS_FN_START_CPU);
if (start_cpu == RTAS_UNKNOWN_SERVICE)
return 1;
@ -266,7 +266,7 @@ void __init smp_init_pseries(void)
* We know prom_init will not have started them if RTAS supports
* query-cpu-stopped-state.
*/
if (rtas_token("query-cpu-stopped-state") == RTAS_UNKNOWN_SERVICE) {
if (rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE) == RTAS_UNKNOWN_SERVICE) {
if (cpu_has_feature(CPU_FTR_SMT)) {
for_each_present_cpu(i) {
if (cpu_thread_in_core(i) == 0)
@ -278,11 +278,5 @@ void __init smp_init_pseries(void)
cpumask_clear_cpu(boot_cpuid, of_spin_mask);
}
/* Non-lpar has additional take/give timebase */
if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
smp_ops->give_timebase = rtas_give_timebase;
smp_ops->take_timebase = rtas_take_timebase;
}
pr_debug(" <- smp_init_pSeries()\n");
}

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
KASAN_SANITIZE := n
KCSAN_SANITIZE := n
targets += trampoline_$(BITS).o purgatory.ro

View File

@ -200,10 +200,10 @@ static struct ics ics_rtas = {
__init int ics_rtas_init(void)
{
ibm_get_xive = rtas_token("ibm,get-xive");
ibm_set_xive = rtas_token("ibm,set-xive");
ibm_int_on = rtas_token("ibm,int-on");
ibm_int_off = rtas_token("ibm,int-off");
ibm_get_xive = rtas_function_token(RTAS_FN_IBM_GET_XIVE);
ibm_set_xive = rtas_function_token(RTAS_FN_IBM_SET_XIVE);
ibm_int_on = rtas_function_token(RTAS_FN_IBM_INT_ON);
ibm_int_off = rtas_function_token(RTAS_FN_IBM_INT_OFF);
/* We enable the RTAS "ICS" if RTAS is present with the
* appropriate tokens

View File

@ -5,6 +5,7 @@ GCOV_PROFILE := n
KCOV_INSTRUMENT := n
UBSAN_SANITIZE := n
KASAN_SANITIZE := n
KCSAN_SANITIZE := n
# Disable ftrace for the entire directory
ccflags-remove-$(CONFIG_FUNCTION_TRACER) += $(CC_FLAGS_FTRACE)

View File

@ -76,9 +76,6 @@ static cpumask_t xmon_batch_cpus = CPU_MASK_NONE;
#define xmon_owner 0
#endif /* CONFIG_SMP */
#ifdef CONFIG_PPC_PSERIES
static int set_indicator_token = RTAS_UNKNOWN_SERVICE;
#endif
static unsigned long in_xmon __read_mostly = 0;
static int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
static bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE);
@ -398,6 +395,7 @@ static inline void disable_surveillance(void)
#ifdef CONFIG_PPC_PSERIES
/* Since this can't be a module, args should end up below 4GB. */
static struct rtas_args args;
const s32 token = rtas_function_token(RTAS_FN_SET_INDICATOR);
/*
* At this point we have got all the cpus we can into
@ -406,10 +404,10 @@ static inline void disable_surveillance(void)
* If we did try to take rtas.lock there would be a
* real possibility of deadlock.
*/
if (set_indicator_token == RTAS_UNKNOWN_SERVICE)
if (token == RTAS_UNKNOWN_SERVICE)
return;
rtas_call_unlocked(&args, set_indicator_token, 3, 1, NULL,
rtas_call_unlocked(&args, token, 3, 1, NULL,
SURVEILLANCE_TOKEN, 0, 0);
#endif /* CONFIG_PPC_PSERIES */
@ -3976,14 +3974,6 @@ static void xmon_init(int enable)
__debugger_iabr_match = xmon_iabr_match;
__debugger_break_match = xmon_break_match;
__debugger_fault_handler = xmon_fault_handler;
#ifdef CONFIG_PPC_PSERIES
/*
* Get the token here to avoid trying to get a lock
* during the crash, causing a deadlock.
*/
set_indicator_token = rtas_token("set-indicator");
#endif
} else {
__debugger = NULL;
__debugger_ipi = NULL;

View File

@ -33,8 +33,8 @@
#endif
struct wf_lm75_sensor {
int ds1775 : 1;
int inited : 1;
unsigned int ds1775 : 1;
unsigned int inited : 1;
struct i2c_client *i2c;
struct wf_sensor sens;
};

View File

@ -274,8 +274,8 @@ struct smu_cpu_power_sensor {
struct list_head link;
struct wf_sensor *volts;
struct wf_sensor *amps;
int fake_volts : 1;
int quadratic : 1;
unsigned int fake_volts : 1;
unsigned int quadratic : 1;
struct wf_sensor sens;
};
#define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens)

View File

@ -10,34 +10,39 @@
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <asm/secure_boot.h>
#include <asm/secvar.h>
#include "keyring_handler.h"
#include "../integrity.h"
/*
* Get a certificate list blob from the named secure variable.
*
* Returns:
* - a pointer to a kmalloc'd buffer containing the cert list on success
* - NULL if the key does not exist
* - an ERR_PTR on error
*/
static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
{
int rc;
void *db;
rc = secvar_ops->get(key, keylen, NULL, size);
if (rc) {
pr_err("Couldn't get size: %d\n", rc);
return NULL;
if (rc == -ENOENT)
return NULL;
return ERR_PTR(rc);
}
db = kmalloc(*size, GFP_KERNEL);
if (!db)
return NULL;
return ERR_PTR(-ENOMEM);
rc = secvar_ops->get(key, keylen, db, size);
if (rc) {
kfree(db);
pr_err("Error reading %s var: %d\n", key, rc);
return NULL;
return ERR_PTR(rc);
}
return db;
@ -51,25 +56,35 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
static int __init load_powerpc_certs(void)
{
void *db = NULL, *dbx = NULL;
uint64_t dbsize = 0, dbxsize = 0;
u64 dbsize = 0, dbxsize = 0;
int rc = 0;
struct device_node *node;
ssize_t len;
char buf[32];
if (!secvar_ops)
return -ENODEV;
/* The following only applies for the edk2-compat backend. */
node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
if (!node)
len = secvar_ops->format(buf, sizeof(buf));
if (len <= 0)
return -ENODEV;
// Check for known secure boot implementations from OPAL or PLPKS
if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
return -ENODEV;
}
/*
* Get db, and dbx. They might not exist, so it isn't an error if we
* can't get them.
*/
db = get_cert_list("db", 3, &dbsize);
if (!db) {
pr_err("Couldn't get db list from firmware\n");
pr_info("Couldn't get db list from firmware\n");
} else if (IS_ERR(db)) {
rc = PTR_ERR(db);
pr_err("Error reading db from firmware: %d\n", rc);
return rc;
} else {
rc = parse_efi_signature_list("powerpc:db", db, dbsize,
get_handler_for_db);
@ -81,6 +96,10 @@ static int __init load_powerpc_certs(void)
dbx = get_cert_list("dbx", 4, &dbxsize);
if (!dbx) {
pr_info("Couldn't get dbx list from firmware\n");
} else if (IS_ERR(dbx)) {
rc = PTR_ERR(dbx);
pr_err("Error reading dbx from firmware: %d\n", rc);
return rc;
} else {
rc = parse_efi_signature_list("powerpc:dbx", dbx, dbxsize,
get_handler_for_dbx);
@ -89,8 +108,6 @@ static int __init load_powerpc_certs(void)
kfree(dbx);
}
of_node_put(node);
return rc;
}
late_initcall(load_powerpc_certs);

View File

@ -64,48 +64,26 @@ inline void set_dscr_usr(unsigned long val)
/* Default DSCR access */
unsigned long get_default_dscr(void)
{
int fd = -1, ret;
char buf[16];
int err;
unsigned long val;
if (fd == -1) {
fd = open(DSCR_DEFAULT, O_RDONLY);
if (fd == -1) {
perror("open() failed");
exit(1);
}
}
memset(buf, 0, sizeof(buf));
lseek(fd, 0, SEEK_SET);
ret = read(fd, buf, sizeof(buf));
if (ret == -1) {
err = read_ulong(DSCR_DEFAULT, &val, 16);
if (err) {
perror("read() failed");
exit(1);
}
sscanf(buf, "%lx", &val);
close(fd);
return val;
}
void set_default_dscr(unsigned long val)
{
int fd = -1, ret;
char buf[16];
int err;
if (fd == -1) {
fd = open(DSCR_DEFAULT, O_RDWR);
if (fd == -1) {
perror("open() failed");
exit(1);
}
}
sprintf(buf, "%lx\n", val);
ret = write(fd, buf, strlen(buf));
if (ret == -1) {
err = write_ulong(DSCR_DEFAULT, val, 16);
if (err) {
perror("write() failed");
exit(1);
}
close(fd);
}
double uniform_deviate(int seed)

View File

@ -12,27 +12,16 @@
static int check_cpu_dscr_default(char *file, unsigned long val)
{
char buf[10];
int fd, rc;
unsigned long cpu_dscr;
int err;
fd = open(file, O_RDWR);
if (fd == -1) {
perror("open() failed");
return 1;
}
err = read_ulong(file, &cpu_dscr, 16);
if (err)
return err;
rc = read(fd, buf, sizeof(buf));
if (rc == -1) {
perror("read() failed");
close(fd);
return 1;
}
close(fd);
buf[rc] = '\0';
if (strtol(buf, NULL, 16) != val) {
if (cpu_dscr != val) {
printf("DSCR match failed: %ld (system) %ld (cpu)\n",
val, strtol(buf, NULL, 16));
val, cpu_dscr);
return 1;
}
return 0;

Some files were not shown because too many files have changed in this diff Show More