2019-10-23 19:56:36 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Common Ultravisor functions and initialization
|
|
|
|
*
|
|
|
|
* Copyright IBM Corp. 2019, 2020
|
|
|
|
*/
|
|
|
|
#define KMSG_COMPONENT "prot_virt"
|
|
|
|
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/sizes.h>
|
|
|
|
#include <linux/bitmap.h>
|
|
|
|
#include <linux/memblock.h>
|
|
|
|
#include <asm/facility.h>
|
|
|
|
#include <asm/sections.h>
|
|
|
|
#include <asm/uv.h>
|
|
|
|
|
|
|
|
/* the bootdata_preserved fields come from ones in arch/s390/boot/uv.c */
|
|
|
|
#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
|
|
|
|
int __bootdata_preserved(prot_virt_guest);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_KVM)
|
|
|
|
int prot_virt_host;
|
|
|
|
EXPORT_SYMBOL(prot_virt_host);
|
|
|
|
struct uv_info __bootdata_preserved(uv_info);
|
|
|
|
EXPORT_SYMBOL(uv_info);
|
|
|
|
|
|
|
|
static int __init prot_virt_setup(char *val)
|
|
|
|
{
|
|
|
|
bool enabled;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = kstrtobool(val, &enabled);
|
|
|
|
if (!rc && enabled)
|
|
|
|
prot_virt_host = 1;
|
|
|
|
|
|
|
|
if (is_prot_virt_guest() && prot_virt_host) {
|
|
|
|
prot_virt_host = 0;
|
|
|
|
pr_warn("Protected virtualization not available in protected guests.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prot_virt_host && !test_facility(158)) {
|
|
|
|
prot_virt_host = 0;
|
|
|
|
pr_warn("Protected virtualization not supported by the hardware.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
early_param("prot_virt", prot_virt_setup);
|
2019-10-23 19:56:39 +08:00
|
|
|
|
|
|
|
static int __init uv_init(unsigned long stor_base, unsigned long stor_len)
|
|
|
|
{
|
|
|
|
struct uv_cb_init uvcb = {
|
|
|
|
.header.cmd = UVC_CMD_INIT_UV,
|
|
|
|
.header.len = sizeof(uvcb),
|
|
|
|
.stor_origin = stor_base,
|
|
|
|
.stor_len = stor_len,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (uv_call(0, (uint64_t)&uvcb)) {
|
|
|
|
pr_err("Ultravisor init failed with rc: 0x%x rrc: 0%x\n",
|
|
|
|
uvcb.header.rc, uvcb.header.rrc);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init setup_uv(void)
|
|
|
|
{
|
|
|
|
unsigned long uv_stor_base;
|
|
|
|
|
|
|
|
uv_stor_base = (unsigned long)memblock_alloc_try_nid(
|
|
|
|
uv_info.uv_base_stor_len, SZ_1M, SZ_2G,
|
|
|
|
MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE);
|
|
|
|
if (!uv_stor_base) {
|
|
|
|
pr_warn("Failed to reserve %lu bytes for ultravisor base storage\n",
|
|
|
|
uv_info.uv_base_stor_len);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) {
|
|
|
|
memblock_free(uv_stor_base, uv_info.uv_base_stor_len);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Reserving %luMB as ultravisor base storage\n",
|
|
|
|
uv_info.uv_base_stor_len >> 20);
|
|
|
|
return;
|
|
|
|
fail:
|
|
|
|
pr_info("Disabling support for protected virtualization");
|
|
|
|
prot_virt_host = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void adjust_to_uv_max(unsigned long *vmax)
|
|
|
|
{
|
|
|
|
*vmax = min_t(unsigned long, *vmax, uv_info.max_sec_stor_addr);
|
|
|
|
}
|
2019-10-23 19:56:36 +08:00
|
|
|
#endif
|