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:
commit
d0a32f5520
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) { }
|
||||
|
||||
|
38
arch/powerpc/include/asm/papr-sysparm.h
Normal file
38
arch/powerpc/include/asm/papr-sysparm.h
Normal 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 */
|
@ -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 */
|
||||
|
195
arch/powerpc/include/asm/plpks.h
Normal file
195
arch/powerpc/include/asm/plpks.h
Normal 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
|
@ -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 */
|
||||
};
|
||||
|
||||
|
96
arch/powerpc/include/asm/rtas-work-area.h
Normal file
96
arch/powerpc/include/asm/rtas-work-area.h
Normal 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 */
|
@ -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 *, ...);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -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){}
|
||||
|
@ -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(®s);
|
||||
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(®s);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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(®[0]) >> 16) & 0xff;
|
||||
*devfn = (be32_to_cpup(®[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 */
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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));
|
||||
|
@ -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
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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[] = {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
|
151
arch/powerpc/platforms/pseries/papr-sysparm.c
Normal file
151
arch/powerpc/platforms/pseries/papr-sysparm.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
217
arch/powerpc/platforms/pseries/plpks-secvar.c
Normal file
217
arch/powerpc/platforms/pseries/plpks-secvar.c
Normal 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);
|
@ -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)
|
||||
|
@ -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
|
@ -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");
|
||||
|
209
arch/powerpc/platforms/pseries/rtas-work-area.c
Normal file
209
arch/powerpc/platforms/pseries/rtas-work-area.c
Normal 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:
|
||||
*
|
||||
* R1–7.3.16–1. 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);
|
||||
}
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
KASAN_SANITIZE := n
|
||||
KCSAN_SANITIZE := n
|
||||
|
||||
targets += trampoline_$(BITS).o purgatory.ro
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user