Commit 964bbdfd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_sev_for_v6.10_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 SEV updates from Borislav Petkov:

 - Small cleanups and improvements

* tag 'x86_sev_for_v6.10_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/sev: Make the VMPL0 checking more straight forward
  x86/sev: Rename snp_init() in boot/compressed/sev.c
  x86/sev: Shorten struct name snp_secrets_page_layout to snp_secrets_page
parents a1907ccd e2f4c8c3
...@@ -335,26 +335,6 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code) ...@@ -335,26 +335,6 @@ void do_boot_stage2_vc(struct pt_regs *regs, unsigned long exit_code)
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
} }
static void enforce_vmpl0(void)
{
u64 attrs;
int err;
/*
* RMPADJUST modifies RMP permissions of a lesser-privileged (numerically
* higher) privilege level. Here, clear the VMPL1 permission mask of the
* GHCB page. If the guest is not running at VMPL0, this will fail.
*
* If the guest is running at VMPL0, it will succeed. Even if that operation
* modifies permission bits, it is still ok to do so currently because Linux
* SNP guests are supported only on VMPL0 so VMPL1 or higher permission masks
* changing is a don't-care.
*/
attrs = 1;
if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, attrs))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
}
/* /*
* SNP_FEATURES_IMPL_REQ is the mask of SNP features that will need * SNP_FEATURES_IMPL_REQ is the mask of SNP features that will need
* guest side implementation for proper functioning of the guest. If any * guest side implementation for proper functioning of the guest. If any
...@@ -413,6 +393,85 @@ void snp_check_features(void) ...@@ -413,6 +393,85 @@ void snp_check_features(void)
} }
} }
/* Search for Confidential Computing blob in the EFI config table. */
static struct cc_blob_sev_info *find_cc_blob_efi(struct boot_params *bp)
{
unsigned long cfg_table_pa;
unsigned int cfg_table_len;
int ret;
ret = efi_get_conf_table(bp, &cfg_table_pa, &cfg_table_len);
if (ret)
return NULL;
return (struct cc_blob_sev_info *)efi_find_vendor_table(bp, cfg_table_pa,
cfg_table_len,
EFI_CC_BLOB_GUID);
}
/*
* Initial set up of SNP relies on information provided by the
* Confidential Computing blob, which can be passed to the boot kernel
* by firmware/bootloader in the following ways:
*
* - via an entry in the EFI config table
* - via a setup_data structure, as defined by the Linux Boot Protocol
*
* Scan for the blob in that order.
*/
static struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
{
struct cc_blob_sev_info *cc_info;
cc_info = find_cc_blob_efi(bp);
if (cc_info)
goto found_cc_info;
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)
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
return cc_info;
}
/*
* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks
* will verify the SNP CPUID/MSR bits.
*/
static bool early_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 a SNP-specific Confidential Computing blob is present, then
* firmware/bootloader have indicated SNP support. Verifying this
* involves CPUID checks which will be more reliable if the SNP
* CPUID table is used. See comments over snp_setup_cpuid_table() for
* more details.
*/
setup_cpuid_table(cc_info);
/*
* Pass run-time kernel a pointer to CC info via boot_params so EFI
* config table doesn't need to be searched again during early startup
* phase.
*/
bp->cc_blob_address = (u32)(unsigned long)cc_info;
return true;
}
/* /*
* sev_check_cpu_support - Check for SEV support in the CPU capabilities * sev_check_cpu_support - Check for SEV support in the CPU capabilities
* *
...@@ -463,7 +522,7 @@ void sev_enable(struct boot_params *bp) ...@@ -463,7 +522,7 @@ void sev_enable(struct boot_params *bp)
bp->cc_blob_address = 0; bp->cc_blob_address = 0;
/* /*
* Do an initial SEV capability check before snp_init() which * Do an initial SEV capability check before early_snp_init() which
* loads the CPUID page and the same checks afterwards are done * loads the CPUID page and the same checks afterwards are done
* without the hypervisor and are trustworthy. * without the hypervisor and are trustworthy.
* *
...@@ -478,7 +537,7 @@ void sev_enable(struct boot_params *bp) ...@@ -478,7 +537,7 @@ void sev_enable(struct boot_params *bp)
* Setup/preliminary detection of SNP. This will be sanity-checked * Setup/preliminary detection of SNP. This will be sanity-checked
* against CPUID/MSR values later. * against CPUID/MSR values later.
*/ */
snp = snp_init(bp); snp = early_snp_init(bp);
/* Now repeat the checks with the SNP CPUID table. */ /* Now repeat the checks with the SNP CPUID table. */
...@@ -509,7 +568,20 @@ void sev_enable(struct boot_params *bp) ...@@ -509,7 +568,20 @@ void sev_enable(struct boot_params *bp)
if (!(get_hv_features() & GHCB_HV_FT_SNP)) if (!(get_hv_features() & GHCB_HV_FT_SNP))
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED); sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
enforce_vmpl0(); /*
* Enforce running at VMPL0.
*
* RMPADJUST modifies RMP permissions of a lesser-privileged (numerically
* higher) privilege level. Here, clear the VMPL1 permission mask of the
* GHCB page. If the guest is not running at VMPL0, this will fail.
*
* If the guest is running at VMPL0, it will succeed. Even if that operation
* modifies permission bits, it is still ok to do so currently because Linux
* SNP guests running at VMPL0 only run at VMPL0, so VMPL1 or higher
* permission mask changes are a don't-care.
*/
if (rmpadjust((unsigned long)&boot_ghcb_page, RMP_PG_SIZE_4K, 1))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
} }
if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED)) if (snp && !(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
...@@ -535,85 +607,6 @@ u64 sev_get_status(void) ...@@ -535,85 +607,6 @@ u64 sev_get_status(void)
return m.q; return m.q;
} }
/* Search for Confidential Computing blob in the EFI config table. */
static struct cc_blob_sev_info *find_cc_blob_efi(struct boot_params *bp)
{
unsigned long cfg_table_pa;
unsigned int cfg_table_len;
int ret;
ret = efi_get_conf_table(bp, &cfg_table_pa, &cfg_table_len);
if (ret)
return NULL;
return (struct cc_blob_sev_info *)efi_find_vendor_table(bp, cfg_table_pa,
cfg_table_len,
EFI_CC_BLOB_GUID);
}
/*
* Initial set up of SNP relies on information provided by the
* Confidential Computing blob, which can be passed to the boot kernel
* by firmware/bootloader in the following ways:
*
* - via an entry in the EFI config table
* - via a setup_data structure, as defined by the Linux Boot Protocol
*
* Scan for the blob in that order.
*/
static struct cc_blob_sev_info *find_cc_blob(struct boot_params *bp)
{
struct cc_blob_sev_info *cc_info;
cc_info = find_cc_blob_efi(bp);
if (cc_info)
goto found_cc_info;
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)
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
return cc_info;
}
/*
* Indicate SNP based on presence of SNP-specific CC blob. Subsequent checks
* will verify the SNP CPUID/MSR bits.
*/
bool 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 a SNP-specific Confidential Computing blob is present, then
* firmware/bootloader have indicated SNP support. Verifying this
* involves CPUID checks which will be more reliable if the SNP
* CPUID table is used. See comments over snp_setup_cpuid_table() for
* more details.
*/
setup_cpuid_table(cc_info);
/*
* Pass run-time kernel a pointer to CC info via boot_params so EFI
* config table doesn't need to be searched again during early startup
* phase.
*/
bp->cc_blob_address = (u32)(unsigned long)cc_info;
return true;
}
void sev_prep_identity_maps(unsigned long top_level_pgt) void sev_prep_identity_maps(unsigned long top_level_pgt)
{ {
/* /*
......
...@@ -140,7 +140,7 @@ struct secrets_os_area { ...@@ -140,7 +140,7 @@ struct secrets_os_area {
#define VMPCK_KEY_LEN 32 #define VMPCK_KEY_LEN 32
/* See the SNP spec version 0.9 for secrets page format */ /* See the SNP spec version 0.9 for secrets page format */
struct snp_secrets_page_layout { struct snp_secrets_page {
u32 version; u32 version;
u32 imien : 1, u32 imien : 1,
rsvd1 : 31; rsvd1 : 31;
......
...@@ -648,7 +648,7 @@ static u64 __init get_secrets_page(void) ...@@ -648,7 +648,7 @@ static u64 __init get_secrets_page(void)
static u64 __init get_snp_jump_table_addr(void) static u64 __init get_snp_jump_table_addr(void)
{ {
struct snp_secrets_page_layout *layout; struct snp_secrets_page *secrets;
void __iomem *mem; void __iomem *mem;
u64 pa, addr; u64 pa, addr;
...@@ -662,9 +662,9 @@ static u64 __init get_snp_jump_table_addr(void) ...@@ -662,9 +662,9 @@ static u64 __init get_snp_jump_table_addr(void)
return 0; return 0;
} }
layout = (__force struct snp_secrets_page_layout *)mem; secrets = (__force struct snp_secrets_page *)mem;
addr = layout->os_area.ap_jump_table_pa; addr = secrets->os_area.ap_jump_table_pa;
iounmap(mem); iounmap(mem);
return addr; return addr;
......
...@@ -59,7 +59,7 @@ struct snp_guest_dev { ...@@ -59,7 +59,7 @@ struct snp_guest_dev {
*/ */
struct snp_guest_msg secret_request, secret_response; struct snp_guest_msg secret_request, secret_response;
struct snp_secrets_page_layout *layout; struct snp_secrets_page *secrets;
struct snp_req_data input; struct snp_req_data input;
union { union {
struct snp_report_req report; struct snp_report_req report;
...@@ -743,26 +743,26 @@ static const struct file_operations snp_guest_fops = { ...@@ -743,26 +743,26 @@ static const struct file_operations snp_guest_fops = {
.unlocked_ioctl = snp_guest_ioctl, .unlocked_ioctl = snp_guest_ioctl,
}; };
static u8 *get_vmpck(int id, struct snp_secrets_page_layout *layout, u32 **seqno) static u8 *get_vmpck(int id, struct snp_secrets_page *secrets, u32 **seqno)
{ {
u8 *key = NULL; u8 *key = NULL;
switch (id) { switch (id) {
case 0: case 0:
*seqno = &layout->os_area.msg_seqno_0; *seqno = &secrets->os_area.msg_seqno_0;
key = layout->vmpck0; key = secrets->vmpck0;
break; break;
case 1: case 1:
*seqno = &layout->os_area.msg_seqno_1; *seqno = &secrets->os_area.msg_seqno_1;
key = layout->vmpck1; key = secrets->vmpck1;
break; break;
case 2: case 2:
*seqno = &layout->os_area.msg_seqno_2; *seqno = &secrets->os_area.msg_seqno_2;
key = layout->vmpck2; key = secrets->vmpck2;
break; break;
case 3: case 3:
*seqno = &layout->os_area.msg_seqno_3; *seqno = &secrets->os_area.msg_seqno_3;
key = layout->vmpck3; key = secrets->vmpck3;
break; break;
default: default:
break; break;
...@@ -897,8 +897,8 @@ static void unregister_sev_tsm(void *data) ...@@ -897,8 +897,8 @@ static void unregister_sev_tsm(void *data)
static int __init sev_guest_probe(struct platform_device *pdev) static int __init sev_guest_probe(struct platform_device *pdev)
{ {
struct snp_secrets_page_layout *layout;
struct sev_guest_platform_data *data; struct sev_guest_platform_data *data;
struct snp_secrets_page *secrets;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct snp_guest_dev *snp_dev; struct snp_guest_dev *snp_dev;
struct miscdevice *misc; struct miscdevice *misc;
...@@ -916,7 +916,7 @@ static int __init sev_guest_probe(struct platform_device *pdev) ...@@ -916,7 +916,7 @@ static int __init sev_guest_probe(struct platform_device *pdev)
if (!mapping) if (!mapping)
return -ENODEV; return -ENODEV;
layout = (__force void *)mapping; secrets = (__force void *)mapping;
ret = -ENOMEM; ret = -ENOMEM;
snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL); snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL);
...@@ -924,7 +924,7 @@ static int __init sev_guest_probe(struct platform_device *pdev) ...@@ -924,7 +924,7 @@ static int __init sev_guest_probe(struct platform_device *pdev)
goto e_unmap; goto e_unmap;
ret = -EINVAL; ret = -EINVAL;
snp_dev->vmpck = get_vmpck(vmpck_id, layout, &snp_dev->os_area_msg_seqno); snp_dev->vmpck = get_vmpck(vmpck_id, secrets, &snp_dev->os_area_msg_seqno);
if (!snp_dev->vmpck) { if (!snp_dev->vmpck) {
dev_err(dev, "invalid vmpck id %d\n", vmpck_id); dev_err(dev, "invalid vmpck id %d\n", vmpck_id);
goto e_unmap; goto e_unmap;
...@@ -938,7 +938,7 @@ static int __init sev_guest_probe(struct platform_device *pdev) ...@@ -938,7 +938,7 @@ static int __init sev_guest_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, snp_dev); platform_set_drvdata(pdev, snp_dev);
snp_dev->dev = dev; snp_dev->dev = dev;
snp_dev->layout = layout; snp_dev->secrets = secrets;
/* Allocate the shared page used for the request and response message. */ /* Allocate the shared page used for the request and response message. */
snp_dev->request = alloc_shared_pages(dev, sizeof(struct snp_guest_msg)); snp_dev->request = alloc_shared_pages(dev, sizeof(struct snp_guest_msg));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment