Commit 6ae1290a authored by yangxiangkai's avatar yangxiangkai
Browse files

virtcca feature: vfio driver dma map

virtcca inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAQON6



--------------------------------

VirtCCA Coda Feature:
Vfio driver want to map or unmap ram memory and mmio space, which need
to use tmi interface, complete the secure memory map and secure world
stage2 map.
Msi space map also need to use tmi interface complete stage2 map

Signed-off-by: default avatarXiangkai Yang <yangxiangkai@huawei.com>
Signed-off-by: default avatarJunbin Li <lijunbin4@huawei.com>
---
parent a8078c65
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -247,6 +247,7 @@ struct tmi_tec_run {
#define TMI_FNUM_SMMU_WRITE             U(0x282)
#define TMI_FNUM_SMMU_READ              U(0x283)
#define TMI_FNUM_SMMU_PCIE_CORE_CHECK   U(0x284)
#define TMI_FNUM_DEV_TTT_CREATE         U(0x285)

/* TMI SMC64 PIDs handled by the SPMD */
#define TMI_TMM_VERSION_REQ             TMI_FID(SMC_64, TMI_FNUM_VERSION_REQ)
@@ -280,6 +281,7 @@ struct tmi_tec_run {
#define TMI_TMM_SMMU_WRITE              TMI_FID(SMC_64, TMI_FNUM_SMMU_WRITE)
#define TMI_TMM_SMMU_READ               TMI_FID(SMC_64, TMI_FNUM_SMMU_READ)
#define TMI_TMM_SMMU_PCIE_CORE_CHECK    TMI_FID(SMC_64, TMI_FNUM_SMMU_PCIE_CORE_CHECK)
#define TMI_TMM_DEV_TTT_CREATE          TMI_FID(SMC_64, TMI_FNUM_DEV_TTT_CREATE)

#define TMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
#define TMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
@@ -381,6 +383,7 @@ u64 tmi_ttt_map_range(u64 rd, u64 map_addr, u64 size, u64 cur_node, u64 target_n
u64 tmi_ttt_unmap_range(u64 rd, u64 map_addr, u64 size, u64 node_id);
u64 tmi_mem_info_show(u64 mem_info_addr);

u64 tmi_dev_ttt_create(u64 numa_set, u64 rd, u64 map_addr, u64 level);
u64 tmi_smmu_queue_create(u64 params_ptr);
u64 tmi_smmu_queue_write(uint64_t cmd0, uint64_t cmd1, u64 smmu_id);
u64 tmi_smmu_ste_create(u64 params_ptr);
+5 −0
Original line number Diff line number Diff line
@@ -100,9 +100,14 @@ int kvm_cvm_map_range(struct kvm *kvm);
int cvm_arm_smmu_domain_set_kvm(void *group);
int kvm_cvm_map_unmap_ipa_range(struct kvm *kvm, phys_addr_t ipa_base, phys_addr_t pa,
	unsigned long map_size, uint32_t is_map);
int cvm_map_unmap_ipa_range(struct kvm *kvm, phys_addr_t ipa_base, phys_addr_t pa,
	unsigned long map_size, uint32_t is_map);
int kvm_cvm_map_ipa_mmio(struct kvm *kvm, phys_addr_t ipa_base,
	phys_addr_t pa, unsigned long map_size);

bool check_virtcca_cvm_ram_range(struct kvm *kvm, uint64_t iova);
bool check_virtcca_cvm_vfio_map_dma(struct kvm *kvm, uint64_t iova);

#define CVM_TTT_BLOCK_LEVEL	2
#define CVM_TTT_MAX_LEVEL	3

+9 −0
Original line number Diff line number Diff line
@@ -309,3 +309,12 @@ u64 tmi_smmu_read(u64 smmu_base, u64 reg_offset, u64 bits)
}
EXPORT_SYMBOL(tmi_smmu_read);

/* Create device ttt */
u64 tmi_dev_ttt_create(u64 numa_set, u64 rd, u64 map_addr, u64 level)
{
	struct arm_smccc_res res;

	arm_smccc_1_1_smc(TMI_TMM_DEV_TTT_CREATE, numa_set, rd, map_addr, level, &res);
	return res.a1;
}
+146 −3
Original line number Diff line number Diff line
@@ -196,6 +196,7 @@ void kvm_destroy_cvm(struct kvm *kvm)
	if (!tmi_cvm_destroy(cvm->rd))
		kvm_info("KVM has destroyed cVM: %d\n", cvm->cvm_vmid);

	cvm->is_mapped = false;
	kfree(cvm);
	kvm->arch.virtcca_cvm = NULL;
}
@@ -517,7 +518,11 @@ int kvm_cvm_map_range(struct kvm *kvm)
			}
		}
	}

	/* Vfio driver will pin memory in advance,
	 * if the ram already mapped, activate cvm
	 * does not need to map twice
	 */
	cvm->is_mapped = true;
	return ret;
}

@@ -528,7 +533,7 @@ static int kvm_activate_cvm(struct kvm *kvm)
	if (virtcca_cvm_state(kvm) != CVM_STATE_NEW)
		return -EINVAL;

	if (kvm_cvm_map_range(kvm))
	if (!cvm->is_mapped && kvm_cvm_map_range(kvm))
		return -EFAULT;

	if (tmi_cvm_activate(cvm->rd)) {
@@ -862,7 +867,53 @@ int kvm_init_cvm_vm(struct kvm *kvm)
 */

/**
 * cvm_arm_smmu_domain_set_kvm - Associate SMMU domain with CVM
 * check_virtcca_cvm_ram_range - Check if the iova belongs
 * to the cvm ram range
 * @kvm: The handle of kvm
 * @iova: Ipa address
 *
 * Returns:
 * %true if the iova belongs to cvm ram
 * %false if the iova is not within the scope of cvm ram
 */
bool check_virtcca_cvm_ram_range(struct kvm *kvm, uint64_t iova)
{
	struct virtcca_cvm *virtcca_cvm = kvm->arch.virtcca_cvm;

	if (iova >= virtcca_cvm->loader_start &&
		iova < virtcca_cvm->loader_start + virtcca_cvm->ram_size)
		return true;

	return false;
}
EXPORT_SYMBOL_GPL(check_virtcca_cvm_ram_range);

/**
 * check_virtcca_cvm_vfio_map_dma - Whether the vfio need
 * to map the dma address
 * @kvm: The handle of kvm
 * @iova: Ipa address
 *
 * Returns:
 * %true if virtcca cvm ram is nort mapped or
 * virtcca_cvm_ram is mapped and the iova does not
 * belong to cvm ram range
 * %false if virtcca_cvm_ram is mapped and the iova belong
 * to cvm ram range
 */
bool check_virtcca_cvm_vfio_map_dma(struct kvm *kvm, uint64_t iova)
{
	struct virtcca_cvm *virtcca_cvm = kvm->arch.virtcca_cvm;

	if (!virtcca_cvm->is_mapped)
		return true;

	return !check_virtcca_cvm_ram_range(kvm, iova);
}
EXPORT_SYMBOL_GPL(check_virtcca_cvm_vfio_map_dma);

/**
 * cvm_arm_smmu_domain_set_kvm - Associate SMMU domain with CV
 * @group: Iommu group
 *
 * Returns:
@@ -890,3 +941,95 @@ int cvm_arm_smmu_domain_set_kvm(void *group)
	return 0;
}

static int kvm_cvm_dev_ttt_create(struct virtcca_cvm *cvm,
			unsigned long addr,
			int level,
			u64 numa_set)
{
	addr = ALIGN_DOWN(addr, cvm_ttt_level_mapsize(level - 1));
	return tmi_dev_ttt_create(numa_set, cvm->rd, addr, level);
}

/* CVM create ttt level information about device */
int kvm_cvm_create_dev_ttt_levels(struct kvm *kvm, struct virtcca_cvm *cvm,
			unsigned long ipa,
			int level,
			int max_level,
			struct kvm_mmu_memory_cache *mc)
{
	int ret = 0;

	if (WARN_ON(level == max_level))
		return 0;

	while (level++ < max_level) {
		u64 numa_set = kvm_get_first_binded_numa_set(kvm);

		ret = kvm_cvm_dev_ttt_create(cvm, ipa, level, numa_set);
		if (ret)
			return -ENXIO;
	}

	return 0;
}

/**
 * cvm_map_unmap_ipa_range - Vfio driver map or
 * unmap cvm ipa
 * @kvm: The handle of kvm
 * @ipa_base: Ipa address
 * @pa: Physical address
 * @map_size: Map range
 * @is_map: Map type
 *
 * Returns:
 * %0 if cvm map/unmap address successfully
 * %-ENXIO if map/unmap failed
 */
int cvm_map_unmap_ipa_range(struct kvm *kvm, phys_addr_t ipa_base,
	phys_addr_t pa, unsigned long map_size, uint32_t is_map)
{
	unsigned long size;
	struct virtcca_cvm *virtcca_cvm = (struct virtcca_cvm *)kvm->arch.virtcca_cvm;
	phys_addr_t rd = virtcca_cvm->rd;
	unsigned long ipa = ipa_base;
	unsigned long phys = pa;
	int ret = 0;

	for (size = 0; size < map_size; size += PAGE_SIZE) {
		if (is_map)
			ret = tmi_mmio_map(rd, ipa, CVM_TTT_MAX_LEVEL, phys);
		else
			ret = tmi_mmio_unmap(rd, ipa, CVM_TTT_MAX_LEVEL);

		if (TMI_RETURN_STATUS(ret) == TMI_ERROR_TTT_WALK) {
			/* Create missing TTTs and retry */
			int level_fault = TMI_RETURN_INDEX(ret);

			if (is_map) {
				ret = kvm_cvm_create_dev_ttt_levels(kvm, virtcca_cvm, ipa,
					level_fault, CVM_TTT_MAX_LEVEL, NULL);
				if (ret)
					goto err;
				ret = tmi_mmio_map(rd, ipa, CVM_TTT_MAX_LEVEL, phys);
			} else {
				ret = tmi_mmio_unmap(rd, ipa, level_fault);
			}
		}

		if (ret)
			goto err;

		if (size + PAGE_SIZE >= map_size)
			break;
		ipa += PAGE_SIZE;
		phys += PAGE_SIZE;
	}

	return 0;

err:
	if (!tmi_cvm_destroy(rd))
		kvm_info("Vfio map failed, kvm has destroyed cVM: %d\n", virtcca_cvm->cvm_vmid);
	return -ENXIO;
}
+56 −0
Original line number Diff line number Diff line
@@ -1114,6 +1114,62 @@ static bool arm_s_smmu_idr1_support_secure(struct arm_smmu_device *smmu)
	return true;
}

/**
 * virtcca_smmu_map_pages - Iommu driver calls to this point,
 * and then calls the map function in the
 * io-pgtable to perform mapping
 * @domain: Iommu domain
 * @iova: Ipa address
 * @paddr: Physical address
 * @pgsize: Page size
 * @pgcount: Page count
 * @prot: Iommu attribute
 * @mapped: Maped size
 *
 * Returns:
 * %0 if map success
 * %-ENODEV if ops is null
 */
int virtcca_smmu_map_pages(struct iommu_domain *domain, unsigned long iova,
	phys_addr_t paddr, size_t pgsize, size_t pgcount,
	int prot, size_t *mapped)
{
	struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;

	if (!ops)
		return -ENODEV;

	return virtcca_map_pages(ops, iova, paddr, pgsize, pgcount, prot, mapped);
}
EXPORT_SYMBOL_GPL(virtcca_smmu_map_pages);

/**
 * virtcca_smmu_unmap_pages - Iommu driver calls to this point,
 * and then calls the unmap function in the
 * io-pgtable to perform unmapping
 * @domain: Iommu domain
 * @iova: Ipa address
 * @pgsize: Page size
 * @pgcount: Page count
 *
 * Returns:
 * %0 if map success
 * %-ENODEV if ops is null
 */

size_t virtcca_smmu_unmap_pages(struct iommu_domain *domain, unsigned long iova,
	size_t pgsize, size_t pgcount)
{
	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;

	if (!ops)
		return 0;

	return virtcca_unmap_pages(ops, iova, pgsize, pgcount);
}
EXPORT_SYMBOL_GPL(virtcca_smmu_unmap_pages);

/**
 * virtcca_smmu_secure_dev_operator - Implement security settings for corresponding devices
 * targeting the secure smmu domain
Loading