|
25 | 25 | #include <linux/psp-sev.h>
|
26 | 26 | #include <linux/dmi.h>
|
27 | 27 | #include <uapi/linux/sev-guest.h>
|
| 28 | +#include <crypto/gcm.h> |
28 | 29 |
|
29 | 30 | #include <asm/init.h>
|
30 | 31 | #include <asm/cpu_entry_area.h>
|
@@ -2580,15 +2581,9 @@ static struct platform_device sev_guest_device = {
|
2580 | 2581 |
|
2581 | 2582 | static int __init snp_init_platform_device(void)
|
2582 | 2583 | {
|
2583 |
| - struct sev_guest_platform_data data; |
2584 |
| - |
2585 | 2584 | if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
|
2586 | 2585 | return -ENODEV;
|
2587 | 2586 |
|
2588 |
| - data.secrets_gpa = secrets_pa; |
2589 |
| - if (platform_device_add_data(&sev_guest_device, &data, sizeof(data))) |
2590 |
| - return -ENODEV; |
2591 |
| - |
2592 | 2587 | if (platform_device_register(&sev_guest_device))
|
2593 | 2588 | return -ENODEV;
|
2594 | 2589 |
|
@@ -2667,3 +2662,179 @@ static int __init sev_sysfs_init(void)
|
2667 | 2662 | }
|
2668 | 2663 | arch_initcall(sev_sysfs_init);
|
2669 | 2664 | #endif // CONFIG_SYSFS
|
| 2665 | + |
| 2666 | +static void free_shared_pages(void *buf, size_t sz) |
| 2667 | +{ |
| 2668 | + unsigned int npages = PAGE_ALIGN(sz) >> PAGE_SHIFT; |
| 2669 | + int ret; |
| 2670 | + |
| 2671 | + if (!buf) |
| 2672 | + return; |
| 2673 | + |
| 2674 | + ret = set_memory_encrypted((unsigned long)buf, npages); |
| 2675 | + if (ret) { |
| 2676 | + WARN_ONCE(ret, "failed to restore encryption mask (leak it)\n"); |
| 2677 | + return; |
| 2678 | + } |
| 2679 | + |
| 2680 | + __free_pages(virt_to_page(buf), get_order(sz)); |
| 2681 | +} |
| 2682 | + |
| 2683 | +static void *alloc_shared_pages(size_t sz) |
| 2684 | +{ |
| 2685 | + unsigned int npages = PAGE_ALIGN(sz) >> PAGE_SHIFT; |
| 2686 | + struct page *page; |
| 2687 | + int ret; |
| 2688 | + |
| 2689 | + page = alloc_pages(GFP_KERNEL_ACCOUNT, get_order(sz)); |
| 2690 | + if (!page) |
| 2691 | + return NULL; |
| 2692 | + |
| 2693 | + ret = set_memory_decrypted((unsigned long)page_address(page), npages); |
| 2694 | + if (ret) { |
| 2695 | + pr_err("failed to mark page shared, ret=%d\n", ret); |
| 2696 | + __free_pages(page, get_order(sz)); |
| 2697 | + return NULL; |
| 2698 | + } |
| 2699 | + |
| 2700 | + return page_address(page); |
| 2701 | +} |
| 2702 | + |
| 2703 | +static u8 *get_vmpck(int id, struct snp_secrets_page *secrets, u32 **seqno) |
| 2704 | +{ |
| 2705 | + u8 *key = NULL; |
| 2706 | + |
| 2707 | + switch (id) { |
| 2708 | + case 0: |
| 2709 | + *seqno = &secrets->os_area.msg_seqno_0; |
| 2710 | + key = secrets->vmpck0; |
| 2711 | + break; |
| 2712 | + case 1: |
| 2713 | + *seqno = &secrets->os_area.msg_seqno_1; |
| 2714 | + key = secrets->vmpck1; |
| 2715 | + break; |
| 2716 | + case 2: |
| 2717 | + *seqno = &secrets->os_area.msg_seqno_2; |
| 2718 | + key = secrets->vmpck2; |
| 2719 | + break; |
| 2720 | + case 3: |
| 2721 | + *seqno = &secrets->os_area.msg_seqno_3; |
| 2722 | + key = secrets->vmpck3; |
| 2723 | + break; |
| 2724 | + default: |
| 2725 | + break; |
| 2726 | + } |
| 2727 | + |
| 2728 | + return key; |
| 2729 | +} |
| 2730 | + |
| 2731 | +static struct aesgcm_ctx *snp_init_crypto(u8 *key, size_t keylen) |
| 2732 | +{ |
| 2733 | + struct aesgcm_ctx *ctx; |
| 2734 | + |
| 2735 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
| 2736 | + if (!ctx) |
| 2737 | + return NULL; |
| 2738 | + |
| 2739 | + if (aesgcm_expandkey(ctx, key, keylen, AUTHTAG_LEN)) { |
| 2740 | + pr_err("Crypto context initialization failed\n"); |
| 2741 | + kfree(ctx); |
| 2742 | + return NULL; |
| 2743 | + } |
| 2744 | + |
| 2745 | + return ctx; |
| 2746 | +} |
| 2747 | + |
| 2748 | +int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id) |
| 2749 | +{ |
| 2750 | + /* Adjust the default VMPCK key based on the executing VMPL level */ |
| 2751 | + if (vmpck_id == -1) |
| 2752 | + vmpck_id = snp_vmpl; |
| 2753 | + |
| 2754 | + mdesc->vmpck = get_vmpck(vmpck_id, mdesc->secrets, &mdesc->os_area_msg_seqno); |
| 2755 | + if (!mdesc->vmpck) { |
| 2756 | + pr_err("Invalid VMPCK%d communication key\n", vmpck_id); |
| 2757 | + return -EINVAL; |
| 2758 | + } |
| 2759 | + |
| 2760 | + /* Verify that VMPCK is not zero. */ |
| 2761 | + if (!memchr_inv(mdesc->vmpck, 0, VMPCK_KEY_LEN)) { |
| 2762 | + pr_err("Empty VMPCK%d communication key\n", vmpck_id); |
| 2763 | + return -EINVAL; |
| 2764 | + } |
| 2765 | + |
| 2766 | + mdesc->vmpck_id = vmpck_id; |
| 2767 | + |
| 2768 | + mdesc->ctx = snp_init_crypto(mdesc->vmpck, VMPCK_KEY_LEN); |
| 2769 | + if (!mdesc->ctx) |
| 2770 | + return -ENOMEM; |
| 2771 | + |
| 2772 | + return 0; |
| 2773 | +} |
| 2774 | +EXPORT_SYMBOL_GPL(snp_msg_init); |
| 2775 | + |
| 2776 | +struct snp_msg_desc *snp_msg_alloc(void) |
| 2777 | +{ |
| 2778 | + struct snp_msg_desc *mdesc; |
| 2779 | + void __iomem *mem; |
| 2780 | + |
| 2781 | + BUILD_BUG_ON(sizeof(struct snp_guest_msg) > PAGE_SIZE); |
| 2782 | + |
| 2783 | + mdesc = kzalloc(sizeof(struct snp_msg_desc), GFP_KERNEL); |
| 2784 | + if (!mdesc) |
| 2785 | + return ERR_PTR(-ENOMEM); |
| 2786 | + |
| 2787 | + mem = ioremap_encrypted(secrets_pa, PAGE_SIZE); |
| 2788 | + if (!mem) |
| 2789 | + goto e_free_mdesc; |
| 2790 | + |
| 2791 | + mdesc->secrets = (__force struct snp_secrets_page *)mem; |
| 2792 | + |
| 2793 | + /* Allocate the shared page used for the request and response message. */ |
| 2794 | + mdesc->request = alloc_shared_pages(sizeof(struct snp_guest_msg)); |
| 2795 | + if (!mdesc->request) |
| 2796 | + goto e_unmap; |
| 2797 | + |
| 2798 | + mdesc->response = alloc_shared_pages(sizeof(struct snp_guest_msg)); |
| 2799 | + if (!mdesc->response) |
| 2800 | + goto e_free_request; |
| 2801 | + |
| 2802 | + mdesc->certs_data = alloc_shared_pages(SEV_FW_BLOB_MAX_SIZE); |
| 2803 | + if (!mdesc->certs_data) |
| 2804 | + goto e_free_response; |
| 2805 | + |
| 2806 | + /* initial the input address for guest request */ |
| 2807 | + mdesc->input.req_gpa = __pa(mdesc->request); |
| 2808 | + mdesc->input.resp_gpa = __pa(mdesc->response); |
| 2809 | + mdesc->input.data_gpa = __pa(mdesc->certs_data); |
| 2810 | + |
| 2811 | + return mdesc; |
| 2812 | + |
| 2813 | +e_free_response: |
| 2814 | + free_shared_pages(mdesc->response, sizeof(struct snp_guest_msg)); |
| 2815 | +e_free_request: |
| 2816 | + free_shared_pages(mdesc->request, sizeof(struct snp_guest_msg)); |
| 2817 | +e_unmap: |
| 2818 | + iounmap(mem); |
| 2819 | +e_free_mdesc: |
| 2820 | + kfree(mdesc); |
| 2821 | + |
| 2822 | + return ERR_PTR(-ENOMEM); |
| 2823 | +} |
| 2824 | +EXPORT_SYMBOL_GPL(snp_msg_alloc); |
| 2825 | + |
| 2826 | +void snp_msg_free(struct snp_msg_desc *mdesc) |
| 2827 | +{ |
| 2828 | + if (!mdesc) |
| 2829 | + return; |
| 2830 | + |
| 2831 | + kfree(mdesc->ctx); |
| 2832 | + free_shared_pages(mdesc->response, sizeof(struct snp_guest_msg)); |
| 2833 | + free_shared_pages(mdesc->request, sizeof(struct snp_guest_msg)); |
| 2834 | + free_shared_pages(mdesc->certs_data, SEV_FW_BLOB_MAX_SIZE); |
| 2835 | + iounmap((__force void __iomem *)mdesc->secrets); |
| 2836 | + |
| 2837 | + memset(mdesc, 0, sizeof(*mdesc)); |
| 2838 | + kfree(mdesc); |
| 2839 | +} |
| 2840 | +EXPORT_SYMBOL_GPL(snp_msg_free); |
0 commit comments