
Before being able to host protected virtual machines, donate some of the memory to the ultravisor. Besides that the ultravisor might impose addressing limitations for memory used to back protected VM storage. Treat that limit as protected virtualization host's virtual memory limit. Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: David Hildenbrand <david@redhat.com> [borntraeger@de.ibm.com: patch merging, splitting, fixing] Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
101 lines
2.3 KiB
C
101 lines
2.3 KiB
C
// 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);
|
|
|
|
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);
|
|
}
|
|
#endif
|