mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 22:02:28 +00:00
9155e2341a
The X.509 certificates trusted by the platform and required to secure boot the OS kernel are wrapped in secure variables, which are controlled by OPAL. This patch adds firmware/kernel interface to read and write OPAL secure variables based on the unique key. This support can be enabled using CONFIG_OPAL_SECVAR. Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com> Signed-off-by: Nayna Jain <nayna@linux.ibm.com> Signed-off-by: Eric Richter <erichte@linux.ibm.com> [mpe: Make secvar_ops __ro_after_init, only build opal-secvar.c if PPC_SECURE_BOOT=y] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/1573441836-3632-2-git-send-email-nayna@linux.ibm.com
141 lines
2.6 KiB
C
141 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* PowerNV code for secure variables
|
|
*
|
|
* Copyright (C) 2019 IBM Corporation
|
|
* Author: Claudio Carvalho
|
|
* Nayna Jain
|
|
*
|
|
* APIs to access secure variables managed by OPAL.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "secvar: "fmt
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_platform.h>
|
|
#include <asm/opal.h>
|
|
#include <asm/secvar.h>
|
|
#include <asm/secure_boot.h>
|
|
|
|
static int opal_status_to_err(int rc)
|
|
{
|
|
int err;
|
|
|
|
switch (rc) {
|
|
case OPAL_SUCCESS:
|
|
err = 0;
|
|
break;
|
|
case OPAL_UNSUPPORTED:
|
|
err = -ENXIO;
|
|
break;
|
|
case OPAL_PARAMETER:
|
|
err = -EINVAL;
|
|
break;
|
|
case OPAL_RESOURCE:
|
|
err = -ENOSPC;
|
|
break;
|
|
case OPAL_HARDWARE:
|
|
err = -EIO;
|
|
break;
|
|
case OPAL_NO_MEM:
|
|
err = -ENOMEM;
|
|
break;
|
|
case OPAL_EMPTY:
|
|
err = -ENOENT;
|
|
break;
|
|
case OPAL_PARTIAL:
|
|
err = -EFBIG;
|
|
break;
|
|
default:
|
|
err = -EINVAL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int opal_get_variable(const char *key, uint64_t ksize,
|
|
u8 *data, uint64_t *dsize)
|
|
{
|
|
int rc;
|
|
|
|
if (!key || !dsize)
|
|
return -EINVAL;
|
|
|
|
*dsize = cpu_to_be64(*dsize);
|
|
|
|
rc = opal_secvar_get(key, ksize, data, dsize);
|
|
|
|
*dsize = be64_to_cpu(*dsize);
|
|
|
|
return opal_status_to_err(rc);
|
|
}
|
|
|
|
static int opal_get_next_variable(const char *key, uint64_t *keylen,
|
|
uint64_t keybufsize)
|
|
{
|
|
int rc;
|
|
|
|
if (!key || !keylen)
|
|
return -EINVAL;
|
|
|
|
*keylen = cpu_to_be64(*keylen);
|
|
|
|
rc = opal_secvar_get_next(key, keylen, keybufsize);
|
|
|
|
*keylen = be64_to_cpu(*keylen);
|
|
|
|
return opal_status_to_err(rc);
|
|
}
|
|
|
|
static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
|
|
uint64_t dsize)
|
|
{
|
|
int rc;
|
|
|
|
if (!key || !data)
|
|
return -EINVAL;
|
|
|
|
rc = opal_secvar_enqueue_update(key, ksize, data, dsize);
|
|
|
|
return opal_status_to_err(rc);
|
|
}
|
|
|
|
static const struct secvar_operations opal_secvar_ops = {
|
|
.get = opal_get_variable,
|
|
.get_next = opal_get_next_variable,
|
|
.set = opal_set_variable,
|
|
};
|
|
|
|
static int opal_secvar_probe(struct platform_device *pdev)
|
|
{
|
|
if (!opal_check_token(OPAL_SECVAR_GET)
|
|
|| !opal_check_token(OPAL_SECVAR_GET_NEXT)
|
|
|| !opal_check_token(OPAL_SECVAR_ENQUEUE_UPDATE)) {
|
|
pr_err("OPAL doesn't support secure variables\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
set_secvar_ops(&opal_secvar_ops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id opal_secvar_match[] = {
|
|
{ .compatible = "ibm,secvar-backend",},
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver opal_secvar_driver = {
|
|
.driver = {
|
|
.name = "secvar",
|
|
.of_match_table = opal_secvar_match,
|
|
},
|
|
};
|
|
|
|
static int __init opal_secvar_init(void)
|
|
{
|
|
return platform_driver_probe(&opal_secvar_driver, opal_secvar_probe);
|
|
}
|
|
device_initcall(opal_secvar_init);
|