diff --git a/Documentation/x86/hygon-secure-virtualization.rst b/Documentation/x86/hygon-secure-virtualization.rst new file mode 100644 index 0000000000000000000000000000000000000000..d7e32e0ab29a75575b6c565ab4f875abaa7e2891 --- /dev/null +++ b/Documentation/x86/hygon-secure-virtualization.rst @@ -0,0 +1,86 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================== +HYGON Secure Virtualization +=========================== + +China Secure Virtualization (CSV) is a key virtualization feature on Hygon +processors. + +CSV feature integrates secure processor, memory encryption and memory isolation +to provide the ability to protect guest's private data. The CSV guest's context +like CPU registers, control block and nested page table is accessed only by the +guest itself and the secure processor. Neither other guests nor the host can +tamper with the guest's context. + +The secure processor is a separate processor inside Hygon hardware. The firmware +running inside the secure processor performs activities in a secure way, such as +OVMF encryption, VM launch, secure memory management and nested page table +management etc. For more information, please see CSV spec from Hygon. + +A CSV guest is running in the memory that is encrypted with a dedicated encrypt +key which is set by the secure processor. And CSV guest's memory encrypt key is +unique from the others. A low latency crypto engine resides on Hygon hardware +to minimize the negative effect on memory bandwidth. In CSV guest, a guest private +page will be automatically decrypted when read from memory and encrypted when +written to memory. + +CSV feature provides an enhancement technology named memory isolation to improve +the security. A dedicated memory isolation hardware is built in Hygon hardware. +Only the secure processor has privilege to configure the isolation hardware. At +the BIOS stage, host will reserve several memory regions as secure which are +protected by the isolation hardware. The secure processor allocates the reserved +secure memory for CSV guest and marks the memory as dedicated for the current CSV +guest. Any memory access (read or write) to CSV guest's private memory outside +the guest will be blocked by isolation hardware. + +A CSV guest may declare some memory regions as shared to share data with the host. +When a page is set as shared, read/write on the page will bypass the isolation +hardware and the guest's shared memory can be accessed by the host. A method named +CSV secure call command is designed and CSV guest sends the secure call command +to the secure processor to change private memory to shared memory. In the method, +2 dedicated pages are reserved at early stage of the guest. Any read/write on the +dedicated pages will trigger nested page fault. When NPF happens, the host helps +to issue an external command to the secure processor but cannot tamper with the +data in the guest's private memory. Then the secure processor checks the fault +address and handles the command if the address is exactly the dedicated pages. + +Support for CSV can be determined through the CPUID instruction. The CPUID function +0x8000001f reports information to CSV:: + + 0x8000001f[eax]: + Bit[30] indicates support for CSV + +If CSV is support, MSR 0xc0010131 can be used to determine if CSV is active:: + + 0xc0010131: + Bit[30] 0 = CSV is not active + 1 = CSV is active + +All CSV/CSV2's configurations must be enabled in CSV3. Linux can activate CSV3 by +default (CONFIG_HYGON_CSV=y, CONFIG_CMA=y). CSV3 guest's memory is managed by +CMA (Contiguous Memory Allocation). User must specify CSV3 total secure memory on +the linux kernel command line with csv_mem_size or csv_mem_percentage:: + + csv_mem_size=nn[MG] + [KNL,CSV] + Reserve specified CSV3 memory size in CMA. CSV3's memory will be + allocated from these CMAs. + For instance, csv_mem_size=40G, 40G memory is reserved for CSV3. + + csv_mem_percentage=nn + [KNL,CSV] + Reserve specified memory size which is prorated according to the + whole system memory size. CSV3 guest's memory will be allocated + from these CMAs. + For instance, csv_mem_percentage=60, means 60% system memory is + reserved for CSV3. + The maximum percentage is 80. And the default percentage is 0. + +Limitations +The reserved CSV3 memory within CMA cannot be used by kernel or any application that +may pin memory using long term gup during the application's life time. +For instance, if the whole system memory is 64G and 32G is reserved for CSV3 with +kernel command line csv_mem_percentage=50, only 32G memory is available for CSV/CSV2. +As a result, user will fail to run a CSV/CSV2 guest with memory size which exceeds +32G. diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1bae7dd8d3db446b853cb44358f8274dc3cce053..2f310729fac136a071e744a14ff9703f606bfb5a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2064,6 +2064,21 @@ config EFI_MIXED If unsure, say N. +config HYGON_CSV + bool "Hygon secure virtualization CSV support" + default n + depends on CPU_SUP_HYGON && AMD_MEM_ENCRYPT && CMA + help + CSV feature integrates secure processor, memory encryption and + memory isolation to provide the ability to protect guest's private + data. The CSV guest's context like CPU registers, control block + and nested page table is accessed only by the guest itself and + the secure processor. Neither other guests nor the host can tamper + with the guest's context. + + Say yes to enable support for the Hygon secure virtualization + on hygon processor. + source "kernel/Kconfig.hz" config KEXEC diff --git a/arch/x86/include/asm/csv.h b/arch/x86/include/asm/csv.h new file mode 100644 index 0000000000000000000000000000000000000000..d4fd4532d1eaea1d652ed4dbc8450b7ca4c0a7e7 --- /dev/null +++ b/arch/x86/include/asm/csv.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Hygon China Secure Virtualization (CSV) + * + * Copyright (C) Hygon Info Technologies Ltd. + * + * Author: Jiang Xin + */ + +#ifndef _ASM_X86_CSV_H +#define _ASM_X86_CSV_H + +#ifdef CONFIG_HYGON_CSV + +#define CSV_MR_ALIGN_BITS (28) + +struct csv_mem { + uint64_t start; + uint64_t size; +}; + +extern struct csv_mem *csv_smr; +extern unsigned int csv_smr_num; + +void __init early_csv_reserve_mem(void); +phys_addr_t csv_alloc_from_contiguous(size_t size, nodemask_t *nodes_allowed, + unsigned int align); +void csv_release_to_contiguous(phys_addr_t pa, size_t size); +uint32_t csv_get_smr_entry_shift(void); + +#endif + +#endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9ac50ce23633d66df8689bf46ec643ba9e7a3917..901fb725210c2104cb19e719af9e8a5eb5a7152e 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -50,6 +50,9 @@ #include #include #include +#ifdef CONFIG_HYGON_CSV +#include +#endif /* * max_low_pfn_mapped: highest directly mapped pfn < 4 GB @@ -1218,6 +1221,9 @@ void __init setup_arch(char **cmdline_p) early_acpi_boot_init(); initmem_init(); +#ifdef CONFIG_HYGON_CSV + early_csv_reserve_mem(); +#endif dma_contiguous_reserve(max_pfn_mapped << PAGE_SHIFT); if (boot_cpu_has(X86_FEATURE_GBPAGES)) diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index fe3d3061fc116a7780e28e3f604aef4aa0ea185d..08c4dbe1e12bd87f7af3a06f32adcc28f3ef99a4 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -60,3 +60,5 @@ obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_amd.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_identity.o obj-$(CONFIG_AMD_MEM_ENCRYPT) += mem_encrypt_boot.o + +obj-$(CONFIG_HYGON_CSV) += csv.o diff --git a/arch/x86/mm/csv.c b/arch/x86/mm/csv.c new file mode 100644 index 0000000000000000000000000000000000000000..83bd6b7f819ca81d132f5ce1c7f1b3fb2811a49c --- /dev/null +++ b/arch/x86/mm/csv.c @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Hygon China Secure Virtualization (CSV) + * + * Copyright (C) Hygon Info Technologies Ltd. + * + * Author: Jiang Xin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "CSV-CMA: " fmt + +#define NUM_SMR_ENTRIES (8 * 1024) +#define CSV_CMA_SHIFT PUD_SHIFT +#define CSV_CMA_SIZE (1 << CSV_CMA_SHIFT) +#define MIN_SMR_ENTRY_SHIFT 23 +#define CSV_SMR_INFO_SIZE (nr_node_ids * sizeof(struct csv_mem)) + +struct used_hugetlb_migration_control { + spinlock_t lock; + int enabled_counts; + int last_value; +}; + +static struct used_hugetlb_migration_control control; + +/* 0 percent of total memory by default*/ +static unsigned char csv_mem_percentage; +static unsigned long csv_mem_size; + +static int __init cmdline_parse_csv_mem_size(char *str) +{ + unsigned long size; + char *endp; + + if (str) { + size = memparse(str, &endp); + csv_mem_size = size; + if (!csv_mem_size) + csv_mem_percentage = 0; + } + + return 0; +} +early_param("csv_mem_size", cmdline_parse_csv_mem_size); + +static int __init cmdline_parse_csv_mem_percentage(char *str) +{ + unsigned char percentage; + int ret; + + if (!str) + return 0; + + ret = kstrtou8(str, 10, &percentage); + if (!ret) { + csv_mem_percentage = min_t(unsigned char, percentage, 80); + if (csv_mem_percentage != percentage) + pr_warn("csv_mem_percentage is limited to 80.\n"); + } else { + /* Disable CSV CMA. */ + csv_mem_percentage = 0; + pr_err("csv_mem_percentage is invalid. (0 - 80) is expected.\n"); + } + + return ret; +} +early_param("csv_mem_percentage", cmdline_parse_csv_mem_percentage); + +struct csv_mem *csv_smr; +EXPORT_SYMBOL_GPL(csv_smr); + +unsigned int csv_smr_num; +EXPORT_SYMBOL_GPL(csv_smr_num); + +struct csv_cma { + int fast; + struct cma *cma; +}; + +struct cma_array { + unsigned long count; + struct csv_cma csv_cma[]; +}; + +static unsigned int smr_entry_shift; +static struct cma_array *csv_contiguous_pernuma_area[MAX_NUMNODES]; + +static void csv_set_smr_entry_shift(unsigned int shift) +{ + smr_entry_shift = max_t(unsigned int, shift, MIN_SMR_ENTRY_SHIFT); + pr_info("SMR entry size is 0x%x\n", 1 << smr_entry_shift); +} + +unsigned int csv_get_smr_entry_shift(void) +{ + return smr_entry_shift; +} +EXPORT_SYMBOL_GPL(csv_get_smr_entry_shift); + +static unsigned long __init present_pages_in_node(int nid) +{ + unsigned long range_start_pfn, range_end_pfn; + unsigned long nr_present = 0; + int i; + + for_each_mem_pfn_range(i, nid, &range_start_pfn, &range_end_pfn, NULL) + nr_present += range_end_pfn - range_start_pfn; + + return nr_present; +} + +static phys_addr_t __init csv_early_percent_memory_on_node(int nid) +{ + return (present_pages_in_node(nid) * csv_mem_percentage / 100) << PAGE_SHIFT; +} + +void __init csv_cma_reserve_mem(void) +{ + int node, i; + unsigned long size; + int idx = 0; + int count; + int cma_array_size; + unsigned long max_spanned_size = 0; + + csv_smr = memblock_alloc_node(CSV_SMR_INFO_SIZE, SMP_CACHE_BYTES, NUMA_NO_NODE); + if (!csv_smr) { + pr_err("Fail to allocate csv_smr\n"); + return; + } + + for_each_node_state(node, N_ONLINE) { + int ret; + char name[CMA_MAX_NAME]; + struct cma_array *array; + unsigned long spanned_size; + unsigned long start = 0, end = 0; + struct csv_cma *csv_cma; + + size = csv_early_percent_memory_on_node(node); + count = DIV_ROUND_UP(size, 1 << CSV_CMA_SHIFT); + if (!count) + continue; + + cma_array_size = count * sizeof(*csv_cma) + sizeof(*array); + array = memblock_alloc_node(cma_array_size, SMP_CACHE_BYTES, NUMA_NO_NODE); + if (!array) { + pr_err("Fail to allocate cma_array\n"); + continue; + } + + array->count = 0; + csv_contiguous_pernuma_area[node] = array; + + for (i = 0; i < count; i++) { + csv_cma = &array->csv_cma[i]; + csv_cma->fast = 1; + snprintf(name, sizeof(name), "csv-n%dc%d", node, i); + ret = cma_declare_contiguous_nid(0, CSV_CMA_SIZE, 0, + 1 << CSV_MR_ALIGN_BITS, PMD_SHIFT - PAGE_SHIFT, + false, name, &(csv_cma->cma), node); + if (ret) { + pr_warn("Fail to reserve memory size 0x%x node %d\n", + 1 << CSV_CMA_SHIFT, node); + break; + } + + if (start > cma_get_base(csv_cma->cma) || !start) + start = cma_get_base(csv_cma->cma); + + if (end < cma_get_base(csv_cma->cma) + cma_get_size(csv_cma->cma)) + end = cma_get_base(csv_cma->cma) + cma_get_size(csv_cma->cma); + } + + if (!i) + continue; + + array->count = i; + spanned_size = end - start; + if (spanned_size > max_spanned_size) + max_spanned_size = spanned_size; + + csv_smr[idx].start = start; + csv_smr[idx].size = end - start; + idx++; + + pr_info("Node %d - reserve size 0x%016lx, (expected size 0x%016lx)\n", + node, (unsigned long)i * CSV_CMA_SIZE, size); + } + + csv_smr_num = idx; + WARN_ON((max_spanned_size / NUM_SMR_ENTRIES) < 1); + if (likely((max_spanned_size / NUM_SMR_ENTRIES) >= 1)) + csv_set_smr_entry_shift(ilog2(max_spanned_size / NUM_SMR_ENTRIES - 1) + 1); +} + +#define CSV_CMA_AREAS 2458 +void __init early_csv_reserve_mem(void) +{ + unsigned long total_pages; + + if (!(boot_cpu_data.x86_vendor == X86_VENDOR_HYGON && + boot_cpu_data.x86_model >= 0x4)) + return; + + if (cma_alloc_areas(CSV_CMA_AREAS)) + return; + + total_pages = PHYS_PFN(memblock_phys_mem_size()); + if (csv_mem_size) { + if (csv_mem_size < (total_pages << PAGE_SHIFT)) { + csv_mem_percentage = csv_mem_size * 100 / (total_pages << PAGE_SHIFT); + if (csv_mem_percentage > 80) + csv_mem_percentage = 80; /* Maximum percentage */ + } else + csv_mem_percentage = 80; /* Maximum percentage */ + } + + if (!csv_mem_percentage) { + pr_warn("Don't reserve any memory\n"); + return; + } + + csv_cma_reserve_mem(); +} + +static void enable_used_hugtlb_migration(void) +{ + spin_lock(&control.lock); + if (!control.enabled_counts) { + control.last_value = sysctl_enable_used_hugtlb_migration; + sysctl_enable_used_hugtlb_migration = 1; + } + control.enabled_counts++; + spin_unlock(&control.lock); +} + +static void disable_used_hugtlb_migration(void) +{ + spin_lock(&control.lock); + control.enabled_counts--; + if (!control.enabled_counts) + sysctl_enable_used_hugtlb_migration = control.last_value; + spin_unlock(&control.lock); +} + +phys_addr_t csv_alloc_from_contiguous(size_t size, nodemask_t *nodes_allowed, + unsigned int align) +{ + int nid; + int nr_nodes; + struct page *page = NULL; + phys_addr_t phys_addr; + int count; + struct csv_cma *csv_cma; + int fast = 1; + + if (!nodes_allowed || size > CSV_CMA_SIZE) { + pr_err("Invalid params, size = 0x%lx, nodes_allowed = %p\n", + size, nodes_allowed); + return 0; + } + + align = min_t(unsigned int, align, get_order(CSV_CMA_SIZE)); +retry: + nr_nodes = nodes_weight(*nodes_allowed); + + /* Traverse from current node */ + nid = numa_node_id(); + if (!node_isset(nid, *nodes_allowed)) + nid = next_node_in(nid, *nodes_allowed); + + for (; nr_nodes > 0; nid = next_node_in(nid, *nodes_allowed), nr_nodes--) { + struct cma_array *array = csv_contiguous_pernuma_area[nid]; + + if (!array) + continue; + + count = array->count; + while (count) { + csv_cma = &array->csv_cma[count - 1]; + + /* + * The value check of csv_cma->fast is lockless, but + * that's ok as this don't affect functional correntness + * whatever the value of csv_cma->fast. + */ + if (fast && !csv_cma->fast) { + count--; + continue; + } + enable_used_hugtlb_migration(); + page = cma_alloc(csv_cma->cma, PAGE_ALIGN(size) >> PAGE_SHIFT, + align, true); + disable_used_hugtlb_migration(); + if (page) { + page->private = (unsigned long)csv_cma; + if (!csv_cma->fast) + csv_cma->fast = 1; + goto success; + } else + csv_cma->fast = 0; + + count--; + } + } + + if (fast) { + fast = 0; + goto retry; + } else { + pr_err("Fail to alloc secure memory(size = 0x%lx)\n", size); + return 0; + } + +success: + phys_addr = page_to_phys(page); + clflush_cache_range(__va(phys_addr), size); + + return phys_addr; +} +EXPORT_SYMBOL_GPL(csv_alloc_from_contiguous); + +void csv_release_to_contiguous(phys_addr_t pa, size_t size) +{ + struct csv_cma *csv_cma; + struct page *page = pfn_to_page(pa >> PAGE_SHIFT); + + WARN_ON(!page); + if (likely(page)) { + csv_cma = (struct csv_cma *)page->private; + WARN_ON(!csv_cma); + if (likely(csv_cma)) { + page->private = 0; + csv_cma->fast = 1; + cma_release(csv_cma->cma, page, PAGE_ALIGN(size) >> PAGE_SHIFT); + } + } +} +EXPORT_SYMBOL_GPL(csv_release_to_contiguous); + +static int __init csv_mm_init(void) +{ + spin_lock_init(&control.lock); + control.enabled_counts = 0; + return 0; +} + +static void __exit csv_mm_exit(void) +{ +} + +module_init(csv_mm_init); +module_exit(csv_mm_exit); diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index c63309ff5f0de2a2f74f94d683667f18ca3a45d4..80aab8cb0d5cc0e3951e740dbd48a92bcd9573c8 100644 --- a/drivers/crypto/ccp/psp-dev.c +++ b/drivers/crypto/ccp/psp-dev.c @@ -283,7 +283,8 @@ static int psp_init(struct psp_device *psp, unsigned int capability) return ret; } - if (!psp_check_tee_support(psp, capability)) { + if ((boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) && + !psp_check_tee_support(psp, capability)) { ret = tee_dev_init(psp); if (ret) return ret; diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 59a9c766bcff8c9d0ecf4f866abe26a13c5e4d7c..cf8537ba2c443d8ad87cf3d9c057b65c3dfc4885 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -22,7 +22,10 @@ #include #include #include - +#include +#ifdef CONFIG_HYGON_CSV +#include +#endif #include #include "psp-dev.h" @@ -150,6 +153,22 @@ static int sev_cmd_buffer_len(int cmd) return sizeof(struct csv_data_hgsc_cert_import); case CSV_CMD_RING_BUFFER: return sizeof(struct csv_data_ring_buffer); + case CSV_CMD_LAUNCH_ENCRYPT_DATA: + return sizeof(struct csv_data_launch_encrypt_data); + case CSV_CMD_LAUNCH_ENCRYPT_VMCB: + return sizeof(struct csv_data_launch_encrypt_vmcb); + case CSV_CMD_UPDATE_NPT: + return sizeof(struct csv_data_update_npt); + case CSV_CMD_SET_SMR: + return sizeof(struct csv_data_set_smr); + case CSV_CMD_SET_SMCR: + return sizeof(struct csv_data_set_smcr); + case CSV_CMD_SET_GUEST_PRIVATE_MEMORY: + return sizeof(struct csv_data_set_guest_private_memory); + case CSV_CMD_DBG_READ_VMSA: + return sizeof(struct csv_data_dbg_read_vmsa); + case CSV_CMD_DBG_READ_MEM: + return sizeof(struct csv_data_dbg_read_mem); default: break; } @@ -1696,6 +1715,80 @@ int csv_issue_ringbuf_cmds_external_user(struct file *filep, int *psp_ret) } EXPORT_SYMBOL_GPL(csv_issue_ringbuf_cmds_external_user); +#ifdef CONFIG_HYGON_CSV +static int csv_platform_cmd_set_secure_memory_region(int *error) +{ + int ret = 0; + unsigned int i = 0; + struct csv_data_set_smr *cmd_set_smr; + struct csv_data_set_smcr *cmd_set_smcr; + struct csv_data_memory_region *smr_regions; + + if (!csv_smr || !csv_smr_num) + return -EINVAL; + + cmd_set_smr = kzalloc(sizeof(*cmd_set_smr), GFP_KERNEL); + if (!cmd_set_smr) + return -ENOMEM; + + smr_regions = kcalloc(csv_smr_num, sizeof(*smr_regions), GFP_KERNEL); + if (!smr_regions) { + ret = -ENOMEM; + goto e_free_cmd_set_smr; + } + + for (i = 0; i < csv_smr_num; i++) { + smr_regions[i].base_address = csv_smr[i].start; + smr_regions[i].size = csv_smr[i].size; + } + + cmd_set_smr->smr_entry_size = 1 << csv_get_smr_entry_shift(); + cmd_set_smr->regions_paddr = __psp_pa(smr_regions); + cmd_set_smr->nregions = csv_smr_num; + + ret = sev_do_cmd(CSV_CMD_SET_SMR, cmd_set_smr, error); + if (ret) { + pr_err("Fail to set SMR, ret %#x, error %#x\n", ret, *error); + goto e_free_smr_area; + } + + cmd_set_smcr = kzalloc(sizeof(*cmd_set_smcr), GFP_KERNEL); + if (!cmd_set_smcr) { + ret = -ENOMEM; + goto e_free_smr_area; + } + + cmd_set_smcr->base_address = csv_alloc_from_contiguous(1UL << CSV_MR_ALIGN_BITS, + &node_online_map, + get_order(1 << CSV_MR_ALIGN_BITS)); + if (!cmd_set_smcr->base_address) { + pr_err("Fail to alloc SMCR memory\n"); + ret = -ENOMEM; + goto e_free_cmd_set_smcr; + } + + cmd_set_smcr->size = 1UL << CSV_MR_ALIGN_BITS; + ret = sev_do_cmd(CSV_CMD_SET_SMCR, cmd_set_smcr, error); + if (ret) { + if (*error == SEV_RET_INVALID_COMMAND) + ret = 0; + else + pr_err("set smcr ret %#x, error %#x\n", ret, *error); + + csv_release_to_contiguous(cmd_set_smcr->base_address, + 1UL << CSV_MR_ALIGN_BITS); + } + +e_free_cmd_set_smcr: + kfree((void *)cmd_set_smcr); +e_free_smr_area: + kfree((void *)smr_regions); +e_free_cmd_set_smr: + kfree((void *)cmd_set_smr); + return ret; +} +#endif + void sev_pci_init(void) { struct sev_device *sev = psp_master->sev_data; @@ -1726,6 +1819,14 @@ void sev_pci_init(void) "SEV: TMR allocation failed, SEV-ES support unavailable\n"); } +#ifdef CONFIG_HYGON_CSV + /* Set SMR for CSV */ + rc = csv_platform_cmd_set_secure_memory_region(&error); + if (rc) + dev_warn(sev->dev, + "CSV3: fail to set secure memory region, CSV3 support unavailable\n"); +#endif + /* Initialize the platform */ rc = sev_platform_init(&error); if (rc && (error == SEV_RET_SECURE_DATA_INVALID)) { diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index ee7d26e4a747d6891eeb91ad0ea59af3f9d84c67..7a01be34902a9144f8da82ffd970f9cd408e50a0 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -300,6 +300,12 @@ static const struct tee_vdata teev1 = { .ring_rptr_reg = 0x10554, }; +static const struct sev_vdata csvv1 = { + .cmdresp_reg = 0x10580, + .cmdbuff_addr_lo_reg = 0x105e0, + .cmdbuff_addr_hi_reg = 0x105e4, +}; + static const struct psp_vdata pspv1 = { .sev = &sevv1, .feature_reg = 0x105fc, @@ -330,6 +336,13 @@ static const struct psp_vdata pspv3 = { .inten_reg = 0x10690, .intsts_reg = 0x10694, }; + +static const struct psp_vdata psp_csvv1 = { + .sev = &csvv1, + .feature_reg = 0x105fc, + .inten_reg = 0x10670, + .intsts_reg = 0x10674, +}; #endif static const struct sp_dev_vdata dev_vdata[] = { @@ -376,6 +389,15 @@ static const struct sp_dev_vdata dev_vdata[] = { .bar = 2, #ifdef CONFIG_CRYPTO_DEV_SP_PSP .psp_vdata = &pspv2, +#endif + }, + { /* 6 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_CCP + .ccp_vdata = &ccpv5a, +#endif +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &psp_csvv1, #endif }, }; @@ -389,6 +411,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, { PCI_VDEVICE(HYGON, 0x1456), (kernel_ulong_t)&dev_vdata[1] }, { PCI_VDEVICE(HYGON, 0x1468), (kernel_ulong_t)&dev_vdata[2] }, + { PCI_VDEVICE(HYGON, 0x1486), (kernel_ulong_t)&dev_vdata[6] }, /* Last entry must be zero */ { 0, } }; diff --git a/include/linux/cma.h b/include/linux/cma.h index 217999c8a7621968f9c11f66198649ade9eefa54..2af4ade5e0ce48ceaaf8bda8d9042896333a9204 100644 --- a/include/linux/cma.h +++ b/include/linux/cma.h @@ -49,4 +49,5 @@ extern struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align, extern bool cma_release(struct cma *cma, const struct page *pages, unsigned int count); extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data); +extern int __init cma_alloc_areas(unsigned int max_cma_size); #endif diff --git a/include/linux/psp-csv.h b/include/linux/psp-csv.h new file mode 100644 index 0000000000000000000000000000000000000000..20c0658c1927aa864af57e8cd5f46e010cc50dcd --- /dev/null +++ b/include/linux/psp-csv.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Hygon Secure Virtualization feature CSV driver interface + * + * Copyright (C) Hygon Info Technologies Ltd. + */ + +#ifndef __PSP_CSV_H__ +#define __PSP_CSV_H__ + +#include + +/** + * Guest/platform management commands + */ +enum csv3_cmd { + /* Guest launch commands */ + CSV_CMD_SET_GUEST_PRIVATE_MEMORY = 0x200, + CSV_CMD_LAUNCH_ENCRYPT_DATA = 0x201, + CSV_CMD_LAUNCH_ENCRYPT_VMCB = 0x202, + /* Guest NPT(Nested Page Table) management commands */ + CSV_CMD_UPDATE_NPT = 0x203, + + /* Guest migration commands */ + CSV_CMD_SEND_ENCRYPT_DATA = 0x210, + CSV_CMD_SEND_ENCRYPT_CONTEXT = 0x211, + CSV_CMD_RECEIVE_ENCRYPT_DATA = 0x212, + CSV_CMD_RECEIVE_ENCRYPT_CONTEXT = 0x213, + + /* Guest debug commands */ + CSV_CMD_DBG_READ_VMSA = 0x220, + CSV_CMD_DBG_READ_MEM = 0x221, + + /* Platform secure memory management commands */ + CSV_CMD_SET_SMR = 0x230, + CSV_CMD_SET_SMCR = 0x231, + + CSV3_CMD_MAX, +}; + +/** + * struct csv_data_launch_encrypt_data - CSV_CMD_LAUNCH_ENCRYPT_DATA command + * + * @handle: handle of the VM to update + * @gpa: guest address where data is copied + * @length: len of memory to be encrypted + * @data_blocks: memory regions to hold data page address + */ +struct csv_data_launch_encrypt_data { + u32 handle; /* In */ + u32 reserved; /* In */ + u64 gpa; /* In */ + u32 length; /* In */ + u32 reserved1; /* In */ + u64 data_blocks[8]; /* In */ +} __packed; + +/** + * struct csv_data_launch_encrypt_vmcb - CSV_CMD_LAUNCH_ENCRYPT_VMCB command + * + * @handle: handle of the VM + * @vcpu_id: id of vcpu per vmsa/vmcb + * @vmsa_addr: memory address of initial vmsa data + * @vmsa_len: len of initial vmsa data + * @shadow_vmcb_addr: memory address of shadow vmcb data + * @shadow_vmcb_len: len of shadow vmcb data + * @secure_vmcb_addr: memory address of secure vmcb data + * @secure_vmcb_len: len of secure vmcb data + */ +struct csv_data_launch_encrypt_vmcb { + u32 handle; /* In */ + u32 reserved; /* In */ + u32 vcpu_id; /* In */ + u32 reserved1; /* In */ + u64 vmsa_addr; /* In */ + u32 vmsa_len; /* In */ + u32 reserved2; /* In */ + u64 shadow_vmcb_addr; /* In */ + u32 shadow_vmcb_len; /* In */ + u32 reserved3; /* In */ + u64 secure_vmcb_addr; /* Out */ + u32 secure_vmcb_len; /* Out */ +} __packed; + +/** + * struct csv_data_update_npt - CSV_CMD_UPDATE_NPT command + * + * @handle: handle assigned to the VM + * @error_code: nested page fault error code + * @gpa: guest page address where npf happens + * @spa: physical address which maps to gpa in host page table + * @level: page level which can be mapped in nested page table + * @page_attr: page attribute for gpa + * @page_attr_mask: which page attribute bit should be set + * @npages: number of pages from gpa is handled. + */ +struct csv_data_update_npt { + u32 handle; /* In */ + u32 reserved; /* In */ + u32 error_code; /* In */ + u32 reserved1; /* In */ + u64 gpa; /* In */ + u64 spa; /* In */ + u64 level; /* In */ + u64 page_attr; /* In */ + u64 page_attr_mask; /* In */ + u32 npages; /* In/Out */ +} __packed; + +/** + * struct csv_data_mem_region - define a memory region + * + * @base_address: base address of a memory region + * @size: size of memory region + */ +struct csv_data_memory_region { + u64 base_address; /* In */ + u64 size; /* In */ +} __packed; + +/** + * struct csv_data_set_guest_private_memory - CSV_CMD_SET_GUEST_PRIVATE_MEMORY + * command parameters + * + * @handle: handle assigned to the VM + * @nregions: number of memory regions + * @regions_paddr: address of memory containing multiple memory regions + */ +struct csv_data_set_guest_private_memory { + u32 handle; /* In */ + u32 nregions; /* In */ + u64 regions_paddr; /* In */ +} __packed; + +/** + * struct csv_data_set_smr - CSV_CMD_SET_SMR command parameters + * + * @smr_entry_size: size of SMR entry + * @nregions: number of memory regions + * @regions_paddr: address of memory containing multiple memory regions + */ +struct csv_data_set_smr { + u32 smr_entry_size; /* In */ + u32 nregions; /* In */ + u64 regions_paddr; /* In */ +} __packed; + +/** + * struct csv_data_set_smcr - CSV_CMD_SET_SMCR command parameters + * + * @base_address: start address of SMCR memory + * @size: size of SMCR memory + */ +struct csv_data_set_smcr { + u64 base_address; /* In */ + u64 size; /* In */ +} __packed; + +/** + * struct csv_data_dbg_read_vmsa - CSV_CMD_DBG_READ_VMSA command parameters + * + * @handle: handle assigned to the VM + * @spa: system physical address of memory to get vmsa of the specific vcpu + * @size: size of the host memory + * @vcpu_id: the specific vcpu + */ +struct csv_data_dbg_read_vmsa { + u32 handle; /* In */ + u32 reserved; /* In */ + u64 spa; /* In */ + u32 size; /* In */ + u32 vcpu_id; /* In */ +} __packed; + +/** + * struct csv_data_dbg_read_mem - CSV_CMD_DBG_READ_MEM command parameters + * + * @handle: handle assigned to the VM + * @gpa: guest physical address of the memory to access + * @spa: system physical address of memory to get data from gpa + * @size: size of guest memory to access + */ +struct csv_data_dbg_read_mem { + u32 handle; /* In */ + u32 reserved; /* In */ + u64 gpa; /* In */ + u64 spa; /* In */ + u32 size; /* In */ +} __packed; + +#endif diff --git a/mm/cma.c b/mm/cma.c index 94e732d54bac7e0e7682ac033a9d8e4989857246..bd3984f49186bf8961f2f459315e526ce3fb66e3 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -35,7 +35,10 @@ #include "cma.h" -struct cma cma_areas[MAX_CMA_AREAS]; +static struct cma cma_areas_data[MAX_CMA_AREAS]; +static unsigned int cma_areas_size = MAX_CMA_AREAS; +struct cma *cma_areas = cma_areas_data; + unsigned cma_area_count; static DEFINE_MUTEX(cma_mutex); @@ -152,6 +155,25 @@ static int __init cma_init_reserved_areas(void) } core_initcall(cma_init_reserved_areas); +int __init cma_alloc_areas(unsigned int max_cma_size) +{ + struct cma *data; + + if (max_cma_size <= MAX_CMA_AREAS) + return 0; + + if (cma_area_count || cma_areas != cma_areas_data) + return -EPERM; + + data = memblock_alloc(max_cma_size * sizeof(*cma_areas), SMP_CACHE_BYTES); + if (!data) + return -ENOMEM; + + cma_areas = data; + cma_areas_size = max_cma_size; + return 0; +} + /** * cma_init_reserved_mem() - create custom contiguous area from reserved memory * @base: Base address of the reserved area @@ -173,7 +195,7 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, phys_addr_t alignment; /* Sanity checks */ - if (cma_area_count == ARRAY_SIZE(cma_areas)) { + if (cma_area_count == cma_areas_size) { pr_err("Not enough slots for CMA reserved regions!\n"); return -ENOSPC; } @@ -253,7 +275,7 @@ int __init cma_declare_contiguous_nid(phys_addr_t base, pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n", __func__, &size, &base, &limit, &alignment); - if (cma_area_count == ARRAY_SIZE(cma_areas)) { + if (cma_area_count == cma_areas_size) { pr_err("Not enough slots for CMA reserved regions!\n"); return -ENOSPC; } diff --git a/mm/cma.h b/mm/cma.h index c46c5050aaa90f70576766a2e8b22cc106ca4abe..1ad9afe5c5e8692b24aca362758ecfcf5506c1ef 100644 --- a/mm/cma.h +++ b/mm/cma.h @@ -18,7 +18,7 @@ struct cma { char name[CMA_MAX_NAME]; }; -extern struct cma cma_areas[MAX_CMA_AREAS]; +extern struct cma *cma_areas; extern unsigned cma_area_count; static inline unsigned long cma_bitmap_maxno(struct cma *cma)