powerpc updates for 7.0

- Implement masked user access
  - Add support for internal only per-CPU instructions and inline the bpf_get_smp_processor_id() and bpf_get_current_task()
  - Fix pSeries MSI-X allocation failure when quota is exceeded
  - Fix recursive pci_lock_rescan_remove locking in EEH event handling
  - Support tailcalls with subprogs & BPF exceptions on 64bit
  - Extend "trusted" keys to support the PowerVM Key Wrapping Module (PKWM)
 
 Thanks to: Abhishek Dubey, Christophe Leroy, Gaurav Batra, Guangshuo Li, Jarkko
 Sakkinen, Mahesh Salgaonkar, Mimi Zohar, Miquel Sabaté Solà, Nam Cao, Narayana
 Murty N, Nayna Jain, Nilay Shroff, Puranjay Mohan, Saket Kumar Bhaskar, Sourabh
 Jain, Srish Srinivasan, Venkat Rao Bagalkote,
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqX2DNAOgU8sBX3pRpnEsdPSHZJQFAmmL7S0ACgkQpnEsdPSH
 ZJR2xA/9G+tZp9+2TidbLSyPT5o063uC5H5+j5QcvvHWi/ImGUNtixlDm5HcZLCR
 yKywE1piKYBU8HoISjzAt0+JCVd3ZjJ8chTpKgCHLXPRSBTgdR1MG+SXQysDJSWb
 yA4pwDikmwoLlfi+pf500F0nX2DRCRdU2Yi28ZFeaF/khJ7ebwj41QJ7LjN22+Q1
 G8Kq543obZluzSoVvfG4xUK4ByWER+Zdd2F6699iMP68yw5PJ8PPc0SUGt8nuD4i
 FUs0Lw7XV7i/K3+zm/ZgH5+Cvn7wOIcMNkXgFlxJXkFit97KXUDijifYPoXQyKLL
 ksD7SPFdV0++Sc+3mWcgW4j+hQZC0Pn864unmh8C6ug3SagQ+3pE1JYWKwCmoyXd
 49ROH0y+npArJ4NAc79eweunhafGcRYTSG+zV7swQvpRocMujEqa4CDz4uk1ll5W
 1yAac08AN6PnfcXl2VMrcDboziTlQVFcnNQbK/ieYMC7KpgA+udw1hd2rOWNZCPd
 u0byXxR1ak5YaAEuyMztd/39hrExx8306Jtkh5FIRZKWGAO+3np5bi3vxk11rDni
 c9BGh2JIMtuPUGys3wcFPGMRTKwF2bDFW/pB+5hMHeLUdlkni9WGCX8eLe2klYsy
 T7fBVb4d99IVrJGYv3J1lwELgjrgXvv35XOaUiyJyZhcbng15cc=
 =zJoL
 -----END PGP SIGNATURE-----

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

Pull powerpc updates for 7.0

 - Implement masked user access

 - Add bpf support for internal only per-CPU instructions and inline the
   bpf_get_smp_processor_id() and bpf_get_current_task() functions

 - Fix pSeries MSI-X allocation failure when quota is exceeded

 - Fix recursive pci_lock_rescan_remove locking in EEH event handling

 - Support tailcalls with subprogs & BPF exceptions on 64bit

 - Extend "trusted" keys to support the PowerVM Key Wrapping Module
   (PKWM)

Thanks to Abhishek Dubey, Christophe Leroy, Gaurav Batra, Guangshuo Li,
Jarkko Sakkinen, Mahesh Salgaonkar, Mimi Zohar, Miquel Sabaté Solà, Nam
Cao, Narayana Murty N, Nayna Jain, Nilay Shroff, Puranjay Mohan, Saket
Kumar Bhaskar, Sourabh Jain, Srish Srinivasan, and Venkat Rao Bagalkote.

* tag 'powerpc-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (27 commits)
  powerpc/pseries: plpks: export plpks_wrapping_is_supported
  docs: trusted-encryped: add PKWM as a new trust source
  keys/trusted_keys: establish PKWM as a trusted source
  pseries/plpks: add HCALLs for PowerVM Key Wrapping Module
  pseries/plpks: expose PowerVM wrapping features via the sysfs
  powerpc/pseries: move the PLPKS config inside its own sysfs directory
  pseries/plpks: fix kernel-doc comment inconsistencies
  powerpc/smp: Add check for kcalloc() failure in parse_thread_groups()
  powerpc: kgdb: Remove OUTBUFMAX constant
  powerpc64/bpf: Additional NVR handling for bpf_throw
  powerpc64/bpf: Support exceptions
  powerpc64/bpf: Add arch_bpf_stack_walk() for BPF JIT
  powerpc64/bpf: Avoid tailcall restore from trampoline
  powerpc64/bpf: Support tailcalls with subprogs
  powerpc64/bpf: Moving tail_call_cnt to bottom of frame
  powerpc/eeh: fix recursive pci_lock_rescan_remove locking in EEH event handling
  powerpc/pseries: Fix MSI-X allocation failure when quota is exceeded
  powerpc/iommu: bypass DMA APIs for coherent allocations for pre-mapped memory
  powerpc64/bpf: Inline bpf_get_smp_processor_id() and bpf_get_current_task/_btf()
  powerpc64/bpf: Support internal-only MOV instruction to resolve per-CPU addrs
  ...
This commit is contained in:
Linus Torvalds 2026-02-10 21:46:12 -08:00
commit 192c015940
51 changed files with 1857 additions and 421 deletions

View file

@ -46,6 +46,14 @@ config TRUSTED_KEYS_DCP
help
Enable use of NXP's DCP (Data Co-Processor) as trusted key backend.
config TRUSTED_KEYS_PKWM
bool "PKWM-based trusted keys"
depends on PSERIES_PLPKS >= TRUSTED_KEYS
default y
select HAVE_TRUSTED_KEYS
help
Enable use of IBM PowerVM Key Wrapping Module (PKWM) as a trusted key backend.
if !HAVE_TRUSTED_KEYS
comment "No trust source selected!"
endif

View file

@ -16,3 +16,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o
trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o
trusted-$(CONFIG_TRUSTED_KEYS_DCP) += trusted_dcp.o
trusted-$(CONFIG_TRUSTED_KEYS_PKWM) += trusted_pkwm.o

View file

@ -12,6 +12,7 @@
#include <keys/trusted_caam.h>
#include <keys/trusted_dcp.h>
#include <keys/trusted_tpm.h>
#include <keys/trusted_pkwm.h>
#include <linux/capability.h>
#include <linux/err.h>
#include <linux/init.h>
@ -31,7 +32,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG");
static char *trusted_key_source;
module_param_named(source, trusted_key_source, charp, 0);
MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dcp)");
MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam, dcp or pkwm)");
static const struct trusted_key_source trusted_key_sources[] = {
#if defined(CONFIG_TRUSTED_KEYS_TPM)
@ -46,6 +47,9 @@ static const struct trusted_key_source trusted_key_sources[] = {
#if defined(CONFIG_TRUSTED_KEYS_DCP)
{ "dcp", &dcp_trusted_key_ops },
#endif
#if defined(CONFIG_TRUSTED_KEYS_PKWM)
{ "pkwm", &pkwm_trusted_key_ops },
#endif
};
DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal);

View file

@ -0,0 +1,190 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025 IBM Corporation, Srish Srinivasan <ssrish@linux.ibm.com>
*/
#include <keys/trusted_pkwm.h>
#include <keys/trusted-type.h>
#include <linux/build_bug.h>
#include <linux/key-type.h>
#include <linux/parser.h>
#include <asm/plpks.h>
enum {
Opt_err,
Opt_wrap_flags,
};
static const match_table_t key_tokens = {
{Opt_wrap_flags, "wrap_flags=%s"},
{Opt_err, NULL}
};
static int getoptions(char *datablob, struct trusted_key_options *opt)
{
substring_t args[MAX_OPT_ARGS];
char *p = datablob;
int token;
int res;
u16 wrap_flags;
unsigned long token_mask = 0;
struct trusted_pkwm_options *pkwm;
if (!datablob)
return 0;
pkwm = opt->private;
while ((p = strsep(&datablob, " \t"))) {
if (*p == '\0' || *p == ' ' || *p == '\t')
continue;
token = match_token(p, key_tokens, args);
if (test_and_set_bit(token, &token_mask))
return -EINVAL;
switch (token) {
case Opt_wrap_flags:
res = kstrtou16(args[0].from, 16, &wrap_flags);
if (res < 0 || wrap_flags > 2)
return -EINVAL;
pkwm->wrap_flags = wrap_flags;
break;
default:
return -EINVAL;
}
}
return 0;
}
static struct trusted_key_options *trusted_options_alloc(void)
{
struct trusted_key_options *options;
struct trusted_pkwm_options *pkwm;
options = kzalloc(sizeof(*options), GFP_KERNEL);
if (options) {
pkwm = kzalloc(sizeof(*pkwm), GFP_KERNEL);
if (!pkwm) {
kfree_sensitive(options);
options = NULL;
} else {
options->private = pkwm;
}
}
return options;
}
static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
{
struct trusted_key_options *options = NULL;
struct trusted_pkwm_options *pkwm = NULL;
u8 *input_buf, *output_buf;
u32 output_len, input_len;
int rc;
options = trusted_options_alloc();
if (!options)
return -ENOMEM;
rc = getoptions(datablob, options);
if (rc < 0)
goto out;
dump_options(options);
input_len = p->key_len;
input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
if (!input_buf) {
pr_err("Input buffer allocation failed. Returning -ENOMEM.");
rc = -ENOMEM;
goto out;
}
memcpy(input_buf, p->key, p->key_len);
pkwm = options->private;
rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags,
&output_buf, &output_len);
if (!rc) {
memcpy(p->blob, output_buf, output_len);
p->blob_len = output_len;
dump_payload(p);
} else {
pr_err("Wrapping of payload key failed: %d\n", rc);
}
kfree(input_buf);
kfree(output_buf);
out:
kfree_sensitive(options->private);
kfree_sensitive(options);
return rc;
}
static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
{
u8 *input_buf, *output_buf;
u32 input_len, output_len;
int rc;
input_len = p->blob_len;
input_buf = kmalloc(ALIGN(input_len, 4096), GFP_KERNEL);
if (!input_buf) {
pr_err("Input buffer allocation failed. Returning -ENOMEM.");
return -ENOMEM;
}
memcpy(input_buf, p->blob, p->blob_len);
rc = plpks_unwrap_object(&input_buf, input_len, &output_buf,
&output_len);
if (!rc) {
memcpy(p->key, output_buf, output_len);
p->key_len = output_len;
dump_payload(p);
} else {
pr_err("Unwrapping of payload failed: %d\n", rc);
}
kfree(input_buf);
kfree(output_buf);
return rc;
}
static int trusted_pkwm_init(void)
{
int ret;
if (!plpks_wrapping_is_supported()) {
pr_err("H_PKS_WRAP_OBJECT interface not supported\n");
return -ENODEV;
}
ret = plpks_gen_wrapping_key();
if (ret) {
pr_err("Failed to generate default wrapping key\n");
return -EINVAL;
}
return register_key_type(&key_type_trusted);
}
static void trusted_pkwm_exit(void)
{
unregister_key_type(&key_type_trusted);
}
struct trusted_key_ops pkwm_trusted_key_ops = {
.migratable = 0, /* non-migratable */
.init = trusted_pkwm_init,
.seal = trusted_pkwm_seal,
.unseal = trusted_pkwm_unseal,
.exit = trusted_pkwm_exit,
};