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