From 4884ca42a3f71596e11cf168060a4440b1bbebfe Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 10 Aug 2023 13:49:52 +0800 Subject: [PATCH 1/5] anolis: crypto: ccp: Add CCP/PSP PCI interface on Hygon hardware ANBZ: #773 Add CCP/PSP PCI interface on Hygon hardware. Signed-off-by: Xin Jiang --- drivers/crypto/ccp/sp-pci.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index ee7d26e4a747..7a01be34902a 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, } }; -- Gitee From 64c1ad647a7c86a36dc6928851630b121e24d31c Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 10 Aug 2023 13:56:01 +0800 Subject: [PATCH 2/5] anolis: crypto: ccp: No tee init on Hygon platform ANBZ: #773 The TEE capability flag in Hygon conflicts with other vendor. No tee init on Hygon platform even TEE capability is on. The TEE capability should be redefined later. Signed-off-by: Xin Jiang --- drivers/crypto/ccp/psp-dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/psp-dev.c b/drivers/crypto/ccp/psp-dev.c index c63309ff5f0d..80aab8cb0d5c 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; -- Gitee From 523add01824a2182e6b7a47347decfba5ac9e0db Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 10 Aug 2023 14:05:47 +0800 Subject: [PATCH 3/5] anolis: crypto: Define CSV key management command id ANBZ: #773 Define Hygon CSV key management command id and structure. CSV is Hygon's new feature to improve security of guest with secure isolated memory technology in hardware. The command definition is available in CSV spec. Signed-off-by: Xin Jiang --- .../x86/hygon-secure-virtualization.rst | 86 ++++++++ drivers/crypto/ccp/sev-dev.c | 17 ++ include/linux/psp-csv.h | 191 ++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 Documentation/x86/hygon-secure-virtualization.rst create mode 100644 include/linux/psp-csv.h diff --git a/Documentation/x86/hygon-secure-virtualization.rst b/Documentation/x86/hygon-secure-virtualization.rst new file mode 100644 index 000000000000..d7e32e0ab29a --- /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/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 59a9c766bcff..b000b5775114 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -150,6 +151,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; } diff --git a/include/linux/psp-csv.h b/include/linux/psp-csv.h new file mode 100644 index 000000000000..20c0658c1927 --- /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 -- Gitee From 5345a04c5da5c2d7f5a285f33330df48b5547c7c Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 10 Aug 2023 14:21:16 +0800 Subject: [PATCH 4/5] anolis: x86/csv: Manage CSV guest's private memory by CMA ANBZ: #773 The private memory of a CSV guest is isolated from VMM and has to be physically contiguous. CMA(Contiguous Memory Allocator) is a memory allocator within the kernel for contiguous physical memory. Use the CMA for the CSV private memory management. Signed-off-by: Xin Jiang --- arch/x86/Kconfig | 15 ++ arch/x86/include/asm/csv.h | 33 ++++ arch/x86/kernel/setup.c | 6 + arch/x86/mm/Makefile | 2 + arch/x86/mm/csv.c | 367 +++++++++++++++++++++++++++++++++++++ include/linux/cma.h | 1 + mm/cma.c | 28 ++- mm/cma.h | 2 +- 8 files changed, 450 insertions(+), 4 deletions(-) create mode 100644 arch/x86/include/asm/csv.h create mode 100644 arch/x86/mm/csv.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1bae7dd8d3db..2f310729fac1 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 000000000000..d4fd4532d1ea --- /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 9ac50ce23633..901fb725210c 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 fe3d3061fc11..08c4dbe1e12b 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 000000000000..83bd6b7f819c --- /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/include/linux/cma.h b/include/linux/cma.h index 217999c8a762..2af4ade5e0ce 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/mm/cma.c b/mm/cma.c index 94e732d54bac..bd3984f49186 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 c46c5050aaa9..1ad9afe5c5e8 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) -- Gitee From a4c786a4dd4a580caaa736b95a7b732d07291fbb Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 10 Aug 2023 14:27:21 +0800 Subject: [PATCH 5/5] anolis: crypto: ccp: Add SET_SMR/SET_SMCR commands for CSV ANBZ: #773 Set guest memory regions in hygon hardware with SET_SMR command. Secure memory control region(SMCR) is a special memory region which is dedicated for CSV guest's meta data. SET_SMCR command is used to set SMCR memory in hygon hardware. Both SET_SMR and SET_SMCR should be issued early during platform initialization. Signed-off-by: Xin Jiang --- drivers/crypto/ccp/sev-dev.c | 86 +++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index b000b5775114..cf8537ba2c44 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -23,7 +23,9 @@ #include #include #include - +#ifdef CONFIG_HYGON_CSV +#include +#endif #include #include "psp-dev.h" @@ -1713,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; @@ -1743,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)) { -- Gitee