Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/arch/x86/boot/startup/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  sev-startup.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * AMD Memory Encryption Support
 *
 * Copyright (C) 2019 SUSE
 *
 * Author: Joerg Roedel <jroedel@suse.de>
 */


#define pr_fmt(fmt) "SEV: " fmt

#include <linux/percpu-defs.h>
#include <linux/cc_platform.h>
#include <linux/printk.h>
#include <linux/mm_types.h>
#include <linux/set_memory.h>
#include <linux/memblock.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/cpumask.h>
#include <linux/efi.h>
#include <linux/io.h>
#include <linux/psp-sev.h>
#include <uapi/linux/sev-guest.h>

#include <asm/init.h>
#include <asm/cpu_entry_area.h>
#include <asm/stacktrace.h>
#include <asm/sev.h>
#include <asm/sev-internal.h>
#include <asm/insn-eval.h>
#include <asm/fpu/xcr.h>
#include <asm/processor.h>
#include <asm/realmode.h>
#include <asm/setup.h>
#include <asm/traps.h>
#include <asm/svm.h>
#include <asm/smp.h>
#include <asm/cpu.h>
#include <asm/apic.h>
#include <asm/cpuid/api.h>
#include <asm/cmdline.h>

/* For early boot hypervisor communication in SEV-ES enabled guests */
struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);

/*
 * Needs to be in the .data section because we need it NULL before bss is
 * cleared
 */

struct ghcb *boot_ghcb __section(".data");

/* Bitmap of SEV features supported by the hypervisor */
u64 sev_hv_features __ro_after_init;

/* Secrets page physical address from the CC blob */
u64 sev_secrets_pa __ro_after_init;

/* For early boot SVSM communication */
struct svsm_ca boot_svsm_ca_page __aligned(PAGE_SIZE);

DEFINE_PER_CPU(struct svsm_ca *, svsm_caa);
DEFINE_PER_CPU(u64, svsm_caa_pa);

/*
 * Nothing shall interrupt this code path while holding the per-CPU
 * GHCB. The backup GHCB is only for NMIs interrupting this path.
 *
 * Callers must disable local interrupts around it.
 */

noinstr struct ghcb *__sev_get_ghcb(struct ghcb_state *state)
{
 struct sev_es_runtime_data *data;
 struct ghcb *ghcb;

 WARN_ON(!irqs_disabled());

 data = this_cpu_read(runtime_data);
 ghcb = &data->ghcb_page;

 if (unlikely(data->ghcb_active)) {
  /* GHCB is already in use - save its contents */

  if (unlikely(data->backup_ghcb_active)) {
   /*
 * Backup-GHCB is also already in use. There is no way
 * to continue here so just kill the machine. To make
 * panic() work, mark GHCBs inactive so that messages
 * can be printed out.
 */

   data->ghcb_active        = false;
   data->backup_ghcb_active = false;

   instrumentation_begin();
   panic("Unable to handle #VC exception! GHCB and Backup GHCB are already in use");
   instrumentation_end();
  }

  /* Mark backup_ghcb active before writing to it */
  data->backup_ghcb_active = true;

  state->ghcb = &data->backup_ghcb;

  /* Backup GHCB content */
  *state->ghcb = *ghcb;
 } else {
  state->ghcb = NULL;
  data->ghcb_active = true;
 }

 return ghcb;
}

/* Include code shared with pre-decompression boot stage */
#include "sev-shared.c"

noinstr void __sev_put_ghcb(struct ghcb_state *state)
{
 struct sev_es_runtime_data *data;
 struct ghcb *ghcb;

 WARN_ON(!irqs_disabled());

 data = this_cpu_read(runtime_data);
 ghcb = &data->ghcb_page;

 if (state->ghcb) {
  /* Restore GHCB from Backup */
  *ghcb = *state->ghcb;
  data->backup_ghcb_active = false;
  state->ghcb = NULL;
 } else {
  /*
 * Invalidate the GHCB so a VMGEXIT instruction issued
 * from userspace won't appear to be valid.
 */

  vc_ghcb_invalidate(ghcb);
  data->ghcb_active = false;
 }
}

int svsm_perform_call_protocol(struct svsm_call *call)
{
 struct ghcb_state state;
 unsigned long flags;
 struct ghcb *ghcb;
 int ret;

 /*
 * This can be called very early in the boot, use native functions in
 * order to avoid paravirt issues.
 */

 flags = native_local_irq_save();

 if (sev_cfg.ghcbs_initialized)
  ghcb = __sev_get_ghcb(&state);
 else if (boot_ghcb)
  ghcb = boot_ghcb;
 else
  ghcb = NULL;

 do {
  ret = ghcb ? svsm_perform_ghcb_protocol(ghcb, call)
      : svsm_perform_msr_protocol(call);
 } while (ret == -EAGAIN);

 if (sev_cfg.ghcbs_initialized)
  __sev_put_ghcb(&state);

 native_local_irq_restore(flags);

 return ret;
}

void __head
early_set_pages_state(unsigned long vaddr, unsigned long paddr,
        unsigned long npages, enum psc_op op)
{
 unsigned long paddr_end;
 u64 val;

 vaddr = vaddr & PAGE_MASK;

 paddr = paddr & PAGE_MASK;
 paddr_end = paddr + (npages << PAGE_SHIFT);

 while (paddr < paddr_end) {
  /* Page validation must be rescinded before changing to shared */
  if (op == SNP_PAGE_STATE_SHARED)
   pvalidate_4k_page(vaddr, paddr, false);

  /*
 * Use the MSR protocol because this function can be called before
 * the GHCB is established.
 */

  sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
  VMGEXIT();

  val = sev_es_rd_ghcb_msr();

  if (GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP)
   goto e_term;

  if (GHCB_MSR_PSC_RESP_VAL(val))
   goto e_term;

  /* Page validation must be performed after changing to private */
  if (op == SNP_PAGE_STATE_PRIVATE)
   pvalidate_4k_page(vaddr, paddr, true);

  vaddr += PAGE_SIZE;
  paddr += PAGE_SIZE;
 }

 return;

e_term:
 sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
}

void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,
      unsigned long npages)
{
 /*
 * This can be invoked in early boot while running identity mapped, so
 * use an open coded check for SNP instead of using cc_platform_has().
 * This eliminates worries about jump tables or checking boot_cpu_data
 * in the cc_platform_has() function.
 */

 if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
  return;

  /*
  * Ask the hypervisor to mark the memory pages as private in the RMP
  * table.
  */

 early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_PRIVATE);
}

void __head early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
     unsigned long npages)
{
 /*
 * This can be invoked in early boot while running identity mapped, so
 * use an open coded check for SNP instead of using cc_platform_has().
 * This eliminates worries about jump tables or checking boot_cpu_data
 * in the cc_platform_has() function.
 */

 if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
  return;

  /* Ask hypervisor to mark the memory pages shared in the RMP table. */
 early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_SHARED);
}

/*
 * Initial set up of SNP relies on information provided by the
 * Confidential Computing blob, which can be passed to the kernel
 * in the following ways, depending on how it is booted:
 *
 * - when booted via the boot/decompress kernel:
 *   - via boot_params
 *
 * - when booted directly by firmware/bootloader (e.g. CONFIG_PVH):
 *   - via a setup_data entry, as defined by the Linux Boot Protocol
 *
 * Scan for the blob in that order.
 */

static __head struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
{
 struct cc_blob_sev_info *cc_info;

 /* Boot kernel would have passed the CC blob via boot_params. */
 if (bp->cc_blob_address) {
  cc_info = (struct cc_blob_sev_info *)(unsigned long)bp->cc_blob_address;
  goto found_cc_info;
 }

 /*
 * If kernel was booted directly, without the use of the
 * boot/decompression kernel, the CC blob may have been passed via
 * setup_data instead.
 */

 cc_info = find_cc_blob_setup_data(bp);
 if (!cc_info)
  return NULL;

found_cc_info:
 if (cc_info->magic != CC_BLOB_SEV_HDR_MAGIC)
  snp_abort();

 return cc_info;
}

static __head void svsm_setup(struct cc_blob_sev_info *cc_info)
{
 struct svsm_call call = {};
 int ret;
 u64 pa;

 /*
 * Record the SVSM Calling Area address (CAA) if the guest is not
 * running at VMPL0. The CA will be used to communicate with the
 * SVSM to perform the SVSM services.
 */

 if (!svsm_setup_ca(cc_info))
  return;

 /*
 * It is very early in the boot and the kernel is running identity
 * mapped but without having adjusted the pagetables to where the
 * kernel was loaded (physbase), so the get the CA address using
 * RIP-relative addressing.
 */

 pa = (u64)rip_rel_ptr(&boot_svsm_ca_page);

 /*
 * Switch over to the boot SVSM CA while the current CA is still
 * addressable. There is no GHCB at this point so use the MSR protocol.
 *
 * SVSM_CORE_REMAP_CA call:
 *   RAX = 0 (Protocol=0, CallID=0)
 *   RCX = New CA GPA
 */

 call.caa = svsm_get_caa();
 call.rax = SVSM_CORE_CALL(SVSM_CORE_REMAP_CA);
 call.rcx = pa;
 ret = svsm_perform_call_protocol(&call);
 if (ret)
  sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SVSM_CA_REMAP_FAIL);

 boot_svsm_caa = (struct svsm_ca *)pa;
 boot_svsm_caa_pa = pa;
}

bool __head snp_init(struct boot_params *bp)
{
 struct cc_blob_sev_info *cc_info;

 if (!bp)
  return false;

 cc_info = find_cc_blob(bp);
 if (!cc_info)
  return false;

 if (cc_info->secrets_phys && cc_info->secrets_len == PAGE_SIZE)
  sev_secrets_pa = cc_info->secrets_phys;
 else
  return false;

 setup_cpuid_table(cc_info);

 svsm_setup(cc_info);

 /*
 * The CC blob will be used later to access the secrets page. Cache
 * it here like the boot kernel does.
 */

 bp->cc_blob_address = (u32)(unsigned long)cc_info;

 return true;
}

void __head __noreturn snp_abort(void)
{
 sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
}

Messung V0.5
C=96 H=93 G=94

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.