162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014 Oracle Co., Daniel Kiper
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bitops.h>
762306a36Sopenharmony_ci#include <linux/efi.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/string.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <xen/xen.h>
1262306a36Sopenharmony_ci#include <xen/xen-ops.h>
1362306a36Sopenharmony_ci#include <xen/interface/platform.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/page.h>
1662306a36Sopenharmony_ci#include <asm/setup.h>
1762306a36Sopenharmony_ci#include <asm/xen/hypercall.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "xen-ops.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic efi_char16_t vendor[100] __initdata;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic efi_system_table_t efi_systab_xen __initdata = {
2462306a36Sopenharmony_ci	.hdr = {
2562306a36Sopenharmony_ci		.signature	= EFI_SYSTEM_TABLE_SIGNATURE,
2662306a36Sopenharmony_ci		.revision	= 0, /* Initialized later. */
2762306a36Sopenharmony_ci		.headersize	= 0, /* Ignored by Linux Kernel. */
2862306a36Sopenharmony_ci		.crc32		= 0, /* Ignored by Linux Kernel. */
2962306a36Sopenharmony_ci		.reserved	= 0
3062306a36Sopenharmony_ci	},
3162306a36Sopenharmony_ci	.fw_vendor	= EFI_INVALID_TABLE_ADDR, /* Initialized later. */
3262306a36Sopenharmony_ci	.fw_revision	= 0,			  /* Initialized later. */
3362306a36Sopenharmony_ci	.con_in_handle	= EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
3462306a36Sopenharmony_ci	.con_in		= NULL,			  /* Not used under Xen. */
3562306a36Sopenharmony_ci	.con_out_handle	= EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
3662306a36Sopenharmony_ci	.con_out	= NULL, 		  /* Not used under Xen. */
3762306a36Sopenharmony_ci	.stderr_handle	= EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
3862306a36Sopenharmony_ci	.stderr		= EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
3962306a36Sopenharmony_ci	.runtime	= (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR,
4062306a36Sopenharmony_ci						  /* Not used under Xen. */
4162306a36Sopenharmony_ci	.boottime	= (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR,
4262306a36Sopenharmony_ci						  /* Not used under Xen. */
4362306a36Sopenharmony_ci	.nr_tables	= 0,			  /* Initialized later. */
4462306a36Sopenharmony_ci	.tables		= EFI_INVALID_TABLE_ADDR  /* Initialized later. */
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic efi_system_table_t __init *xen_efi_probe(void)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct xen_platform_op op = {
5062306a36Sopenharmony_ci		.cmd = XENPF_firmware_info,
5162306a36Sopenharmony_ci		.u.firmware_info = {
5262306a36Sopenharmony_ci			.type = XEN_FW_EFI_INFO,
5362306a36Sopenharmony_ci			.index = XEN_FW_EFI_CONFIG_TABLE
5462306a36Sopenharmony_ci		}
5562306a36Sopenharmony_ci	};
5662306a36Sopenharmony_ci	union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!xen_initial_domain() || HYPERVISOR_platform_op(&op) < 0)
5962306a36Sopenharmony_ci		return NULL;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Here we know that Xen runs on EFI platform. */
6262306a36Sopenharmony_ci	xen_efi_runtime_setup();
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	efi_systab_xen.tables = info->cfg.addr;
6562306a36Sopenharmony_ci	efi_systab_xen.nr_tables = info->cfg.nent;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	op.cmd = XENPF_firmware_info;
6862306a36Sopenharmony_ci	op.u.firmware_info.type = XEN_FW_EFI_INFO;
6962306a36Sopenharmony_ci	op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
7062306a36Sopenharmony_ci	info->vendor.bufsz = sizeof(vendor);
7162306a36Sopenharmony_ci	set_xen_guest_handle(info->vendor.name, vendor);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (HYPERVISOR_platform_op(&op) == 0) {
7462306a36Sopenharmony_ci		efi_systab_xen.fw_vendor = __pa_symbol(vendor);
7562306a36Sopenharmony_ci		efi_systab_xen.fw_revision = info->vendor.revision;
7662306a36Sopenharmony_ci	} else
7762306a36Sopenharmony_ci		efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	op.cmd = XENPF_firmware_info;
8062306a36Sopenharmony_ci	op.u.firmware_info.type = XEN_FW_EFI_INFO;
8162306a36Sopenharmony_ci	op.u.firmware_info.index = XEN_FW_EFI_VERSION;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (HYPERVISOR_platform_op(&op) == 0)
8462306a36Sopenharmony_ci		efi_systab_xen.hdr.revision = info->version;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	op.cmd = XENPF_firmware_info;
8762306a36Sopenharmony_ci	op.u.firmware_info.type = XEN_FW_EFI_INFO;
8862306a36Sopenharmony_ci	op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (HYPERVISOR_platform_op(&op) == 0)
9162306a36Sopenharmony_ci		efi.runtime_version = info->version;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return &efi_systab_xen;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Determine whether we're in secure boot mode.
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistatic enum efi_secureboot_mode xen_efi_get_secureboot(void)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	static efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
10262306a36Sopenharmony_ci	enum efi_secureboot_mode mode;
10362306a36Sopenharmony_ci	efi_status_t status;
10462306a36Sopenharmony_ci	u8 moksbstate;
10562306a36Sopenharmony_ci	unsigned long size;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	mode = efi_get_secureboot_mode(efi.get_variable);
10862306a36Sopenharmony_ci	if (mode == efi_secureboot_mode_unknown) {
10962306a36Sopenharmony_ci		pr_err("Could not determine UEFI Secure Boot status.\n");
11062306a36Sopenharmony_ci		return efi_secureboot_mode_unknown;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	if (mode != efi_secureboot_mode_enabled)
11362306a36Sopenharmony_ci		return mode;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* See if a user has put the shim into insecure mode. */
11662306a36Sopenharmony_ci	size = sizeof(moksbstate);
11762306a36Sopenharmony_ci	status = efi.get_variable(L"MokSBStateRT", &shim_guid,
11862306a36Sopenharmony_ci				  NULL, &size, &moksbstate);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* If it fails, we don't care why. Default to secure. */
12162306a36Sopenharmony_ci	if (status != EFI_SUCCESS)
12262306a36Sopenharmony_ci		goto secure_boot_enabled;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (moksbstate == 1)
12562306a36Sopenharmony_ci		return efi_secureboot_mode_disabled;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci secure_boot_enabled:
12862306a36Sopenharmony_ci	pr_info("UEFI Secure Boot is enabled.\n");
12962306a36Sopenharmony_ci	return efi_secureboot_mode_enabled;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_civoid __init xen_efi_init(struct boot_params *boot_params)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	efi_system_table_t *efi_systab_xen;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	efi_systab_xen = xen_efi_probe();
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (efi_systab_xen == NULL)
13962306a36Sopenharmony_ci		return;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	strscpy((char *)&boot_params->efi_info.efi_loader_signature, "Xen",
14262306a36Sopenharmony_ci			sizeof(boot_params->efi_info.efi_loader_signature));
14362306a36Sopenharmony_ci	boot_params->efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
14462306a36Sopenharmony_ci	boot_params->efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	boot_params->secure_boot = xen_efi_get_secureboot();
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	set_bit(EFI_BOOT, &efi.flags);
14962306a36Sopenharmony_ci	set_bit(EFI_PARAVIRT, &efi.flags);
15062306a36Sopenharmony_ci	set_bit(EFI_64BIT, &efi.flags);
15162306a36Sopenharmony_ci}
152