162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <asm/uv.h>
362306a36Sopenharmony_ci#include <asm/boot_data.h>
462306a36Sopenharmony_ci#include <asm/facility.h>
562306a36Sopenharmony_ci#include <asm/sections.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "boot.h"
862306a36Sopenharmony_ci#include "uv.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/* will be used in arch/s390/kernel/uv.c */
1162306a36Sopenharmony_ci#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
1262306a36Sopenharmony_ciint __bootdata_preserved(prot_virt_guest);
1362306a36Sopenharmony_ci#endif
1462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_KVM)
1562306a36Sopenharmony_ciint __bootdata_preserved(prot_virt_host);
1662306a36Sopenharmony_ci#endif
1762306a36Sopenharmony_cistruct uv_info __bootdata_preserved(uv_info);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_civoid uv_query_info(void)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct uv_cb_qui uvcb = {
2262306a36Sopenharmony_ci		.header.cmd = UVC_CMD_QUI,
2362306a36Sopenharmony_ci		.header.len = sizeof(uvcb)
2462306a36Sopenharmony_ci	};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if (!test_facility(158))
2762306a36Sopenharmony_ci		return;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	/* rc==0x100 means that there is additional data we do not process */
3062306a36Sopenharmony_ci	if (uv_call(0, (uint64_t)&uvcb) && uvcb.header.rc != 0x100)
3162306a36Sopenharmony_ci		return;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KVM)) {
3462306a36Sopenharmony_ci		memcpy(uv_info.inst_calls_list, uvcb.inst_calls_list, sizeof(uv_info.inst_calls_list));
3562306a36Sopenharmony_ci		uv_info.uv_base_stor_len = uvcb.uv_base_stor_len;
3662306a36Sopenharmony_ci		uv_info.guest_base_stor_len = uvcb.conf_base_phys_stor_len;
3762306a36Sopenharmony_ci		uv_info.guest_virt_base_stor_len = uvcb.conf_base_virt_stor_len;
3862306a36Sopenharmony_ci		uv_info.guest_virt_var_stor_len = uvcb.conf_virt_var_stor_len;
3962306a36Sopenharmony_ci		uv_info.guest_cpu_stor_len = uvcb.cpu_stor_len;
4062306a36Sopenharmony_ci		uv_info.max_sec_stor_addr = ALIGN(uvcb.max_guest_stor_addr, PAGE_SIZE);
4162306a36Sopenharmony_ci		uv_info.max_num_sec_conf = uvcb.max_num_sec_conf;
4262306a36Sopenharmony_ci		uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id;
4362306a36Sopenharmony_ci		uv_info.uv_feature_indications = uvcb.uv_feature_indications;
4462306a36Sopenharmony_ci		uv_info.supp_se_hdr_ver = uvcb.supp_se_hdr_versions;
4562306a36Sopenharmony_ci		uv_info.supp_se_hdr_pcf = uvcb.supp_se_hdr_pcf;
4662306a36Sopenharmony_ci		uv_info.conf_dump_storage_state_len = uvcb.conf_dump_storage_state_len;
4762306a36Sopenharmony_ci		uv_info.conf_dump_finalize_len = uvcb.conf_dump_finalize_len;
4862306a36Sopenharmony_ci		uv_info.supp_att_req_hdr_ver = uvcb.supp_att_req_hdr_ver;
4962306a36Sopenharmony_ci		uv_info.supp_att_pflags = uvcb.supp_att_pflags;
5062306a36Sopenharmony_ci		uv_info.supp_add_secret_req_ver = uvcb.supp_add_secret_req_ver;
5162306a36Sopenharmony_ci		uv_info.supp_add_secret_pcf = uvcb.supp_add_secret_pcf;
5262306a36Sopenharmony_ci		uv_info.supp_secret_types = uvcb.supp_secret_types;
5362306a36Sopenharmony_ci		uv_info.max_secrets = uvcb.max_secrets;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
5762306a36Sopenharmony_ci	if (test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list) &&
5862306a36Sopenharmony_ci	    test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list))
5962306a36Sopenharmony_ci		prot_virt_guest = 1;
6062306a36Sopenharmony_ci#endif
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_KVM)
6462306a36Sopenharmony_ciunsigned long adjust_to_uv_max(unsigned long limit)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	if (is_prot_virt_host() && uv_info.max_sec_stor_addr)
6762306a36Sopenharmony_ci		limit = min_t(unsigned long, limit, uv_info.max_sec_stor_addr);
6862306a36Sopenharmony_ci	return limit;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int is_prot_virt_host_capable(void)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	/* disable if no prot_virt=1 given on command-line */
7462306a36Sopenharmony_ci	if (!is_prot_virt_host())
7562306a36Sopenharmony_ci		return 0;
7662306a36Sopenharmony_ci	/* disable if protected guest virtualization is enabled */
7762306a36Sopenharmony_ci	if (is_prot_virt_guest())
7862306a36Sopenharmony_ci		return 0;
7962306a36Sopenharmony_ci	/* disable if no hardware support */
8062306a36Sopenharmony_ci	if (!test_facility(158))
8162306a36Sopenharmony_ci		return 0;
8262306a36Sopenharmony_ci	/* disable if kdump */
8362306a36Sopenharmony_ci	if (oldmem_data.start)
8462306a36Sopenharmony_ci		return 0;
8562306a36Sopenharmony_ci	/* disable if stand-alone dump */
8662306a36Sopenharmony_ci	if (ipl_block_valid && is_ipl_block_dump())
8762306a36Sopenharmony_ci		return 0;
8862306a36Sopenharmony_ci	return 1;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid sanitize_prot_virt_host(void)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	prot_virt_host = is_prot_virt_host_capable();
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci#endif
96