clear-pkgs-linux-iot-lts2018/0923-trusty-detect-vmm-when...

288 lines
8.7 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Qi, Yadong" <yadong.qi@intel.com>
Date: Fri, 2 Feb 2018 13:12:40 +0800
Subject: [PATCH] trusty: detect vmm when load trusty driver
Use hypervisor_cpuid_base() to detect VMM which support Trusty.
Currently, there are 2 hypervisors support trusty: CWP and EVMM.
Use different hypercall to implement SMC for EVMM and CWP.
Change-Id: I45a9c69862c785aba3d2911ca439b5e3d8cf0cf6
Signed-off-by: Qi, Yadong <yadong.qi@intel.com>
Tracked-On: OAM-56970
---
drivers/trusty/trusty-ipc.c | 4 +--
drivers/trusty/trusty-irq.c | 4 +--
drivers/trusty/trusty-log.c | 10 +++----
drivers/trusty/trusty-timer.c | 4 +--
drivers/trusty/trusty-virtio.c | 4 +--
drivers/trusty/trusty-wall.c | 4 +--
drivers/trusty/trusty.c | 52 +++++++++++++++++++++++++++-------
include/linux/trusty/trusty.h | 33 +++++++++++----------
8 files changed, 74 insertions(+), 41 deletions(-)
diff --git a/drivers/trusty/trusty-ipc.c b/drivers/trusty/trusty-ipc.c
index 93003b45eb32..a2bc3fcba29a 100644
--- a/drivers/trusty/trusty-ipc.c
+++ b/drivers/trusty/trusty-ipc.c
@@ -1525,9 +1525,9 @@ static int tipc_virtio_probe(struct virtio_device *vdev)
vq_callback_t *vq_cbs[] = {_rxvq_cb, _txvq_cb};
const char *vq_names[] = { "rx", "tx" };
- err = trusty_check_cpuid(NULL);
+ err = trusty_detect_vmm();
if (err < 0) {
- dev_err(&vdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&vdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
diff --git a/drivers/trusty/trusty-irq.c b/drivers/trusty/trusty-irq.c
index 04df531bf9d0..af2af6ee37ba 100644
--- a/drivers/trusty/trusty-irq.c
+++ b/drivers/trusty/trusty-irq.c
@@ -539,9 +539,9 @@ static int trusty_irq_probe(struct platform_device *pdev)
unsigned long irq_flags;
struct trusty_irq_state *is;
- ret = trusty_check_cpuid(NULL);
+ ret = trusty_detect_vmm();
if (ret < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c
index b58715cc2ef3..d2446a1f34c9 100755
--- a/drivers/trusty/trusty-log.c
+++ b/drivers/trusty/trusty-log.c
@@ -259,13 +259,13 @@ static int trusty_log_probe(struct platform_device *pdev)
{
struct trusty_log_state *s;
int result;
- u32 vmm_signature;
+ int vmm_id;
phys_addr_t pa;
struct deadloop_dump *dump;
- result = trusty_check_cpuid(&vmm_signature);
- if (result < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ vmm_id = trusty_detect_vmm();
+ if (vmm_id < 0) {
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
@@ -321,7 +321,7 @@ static int trusty_log_probe(struct platform_device *pdev)
goto error_panic_notifier;
}
- if(vmm_signature == EVMM_SIGNATURE_VMM) {
+ if(vmm_id == VMM_ID_EVMM) {
/* allocate debug buffer for vmm panic dump */
g_vmm_debug_buf = __get_free_pages(GFP_KERNEL | __GFP_ZERO, 2);
if (!g_vmm_debug_buf) {
diff --git a/drivers/trusty/trusty-timer.c b/drivers/trusty/trusty-timer.c
index 43e43265c3c6..5d4466d4e157 100644
--- a/drivers/trusty/trusty-timer.c
+++ b/drivers/trusty/trusty-timer.c
@@ -100,9 +100,9 @@ static int trusty_timer_probe(struct platform_device *pdev)
struct trusty_timer_dev_state *s;
struct trusty_timer *tt;
- ret = trusty_check_cpuid(NULL);
+ ret = trusty_detect_vmm();
if (ret < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
diff --git a/drivers/trusty/trusty-virtio.c b/drivers/trusty/trusty-virtio.c
index b2418d7da5e1..743a4789772f 100644
--- a/drivers/trusty/trusty-virtio.c
+++ b/drivers/trusty/trusty-virtio.c
@@ -641,9 +641,9 @@ static int trusty_virtio_probe(struct platform_device *pdev)
int ret;
struct trusty_ctx *tctx;
- ret = trusty_check_cpuid(NULL);
+ ret = trusty_detect_vmm();
if (ret < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
diff --git a/drivers/trusty/trusty-wall.c b/drivers/trusty/trusty-wall.c
index 64368480c309..2345f56a6405 100644
--- a/drivers/trusty/trusty-wall.c
+++ b/drivers/trusty/trusty-wall.c
@@ -147,9 +147,9 @@ static int trusty_wall_probe(struct platform_device *pdev)
int ret;
struct trusty_wall_dev_state *s;
- ret = trusty_check_cpuid(NULL);
+ ret = trusty_detect_vmm();
if (ret < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index d4eeb40e2b60..98c866487a3e 100755
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -26,7 +26,8 @@
#include <linux/trusty/sm_err.h>
#include <linux/trusty/trusty.h>
-#define TRUSTY_VMCALL_SMC 0x74727500
+#define EVMM_SMC_HC_ID 0x74727500
+#define CWP_SMC_HC_ID 0x80000071
struct trusty_state;
@@ -53,13 +54,28 @@ struct trusty_smc_interface {
ulong args[5];
};
-static inline ulong smc(ulong r0, ulong r1, ulong r2, ulong r3)
+static ulong (*smc)(ulong, ulong, ulong, ulong);
+
+#define asm_smc_vmcall(smc_id, rdi, rsi, rdx, rbx) \
+do { \
+ __asm__ __volatile__( \
+ "vmcall; \n" \
+ : "=D"(rdi) \
+ : "r"(smc_id), "D"(rdi), "S"(rsi), "d"(rdx), "b"(rbx) \
+ ); \
+} while (0)
+
+static inline ulong smc_evmm(ulong r0, ulong r1, ulong r2, ulong r3)
{
- __asm__ __volatile__(
- "vmcall; \n"
- : "=D"(r0)
- : "a"(TRUSTY_VMCALL_SMC), "D"(r0), "S"(r1), "d"(r2), "b"(r3)
- );
+ register unsigned long smc_id asm("rax") = EVMM_SMC_HC_ID;
+ asm_smc_vmcall(smc_id, r0, r1, r2, r3);
+ return r0;
+}
+
+static inline ulong smc_cwp(ulong r0, ulong r1, ulong r2, ulong r3)
+{
+ register unsigned long smc_id asm("r8") = CWP_SMC_HC_ID;
+ asm_smc_vmcall(smc_id, r0, r1, r2, r3);
return r0;
}
@@ -443,6 +459,19 @@ static void nop_work_func(struct work_struct *work)
dev_dbg(s->dev, "%s: done\n", __func__);
}
+static void trusty_init_smc(int vmm_id)
+{
+ if (vmm_id == VMM_ID_EVMM) {
+ smc = smc_evmm;
+ } else if (vmm_id == VMM_ID_CWP) {
+ smc = smc_cwp;
+ } else {
+ pr_err("%s: No smc supports VMM[%d](sig:%s)!",
+ __func__, vmm_id, vmm_signature[vmm_id]);
+ BUG();
+ }
+}
+
void trusty_enqueue_nop(struct device *dev, struct trusty_nop *nop)
{
unsigned long flags;
@@ -479,8 +508,6 @@ void trusty_dequeue_nop(struct device *dev, struct trusty_nop *nop)
}
EXPORT_SYMBOL(trusty_dequeue_nop);
-
-
static int trusty_probe(struct platform_device *pdev)
{
int ret;
@@ -489,11 +516,14 @@ static int trusty_probe(struct platform_device *pdev)
struct trusty_state *s;
struct device_node *node = pdev->dev.of_node;
- ret = trusty_check_cpuid(NULL);
+ ret = trusty_detect_vmm();
if (ret < 0) {
- dev_err(&pdev->dev, "CPUID Error: Cannot find eVmm in trusty driver initialization!");
+ dev_err(&pdev->dev, "Cannot detect VMM which supports trusty!");
return -EINVAL;
}
+ dev_dbg(&pdev->dev, "Detected VMM: sig=%s\n", vmm_signature[ret]);
+
+ trusty_init_smc(ret);
if (!node) {
dev_err(&pdev->dev, "of_node required\n");
diff --git a/include/linux/trusty/trusty.h b/include/linux/trusty/trusty.h
index 3189c7ec967c..48e1ea716889 100644
--- a/include/linux/trusty/trusty.h
+++ b/include/linux/trusty/trusty.h
@@ -18,6 +18,7 @@
#include <linux/trusty/sm_err.h>
#include <linux/device.h>
#include <linux/pagemap.h>
+#include <asm/hypervisor.h>
#if IS_ENABLED(CONFIG_TRUSTY)
@@ -90,25 +91,27 @@ void *trusty_wall_base(struct device *dev);
void *trusty_wall_per_cpu_item_ptr(struct device *dev, unsigned int cpu,
u32 item_id, size_t exp_sz);
-/* CPUID leaf 0x3 is used because eVMM will trap this leaf.*/
-#define EVMM_SIGNATURE_CORP 0x43544E49 /* "INTC", edx */
-#define EVMM_SIGNATURE_VMM 0x4D4D5645 /* "EVMM", ecx */
-
-static inline int trusty_check_cpuid(u32 *vmm_signature)
-{
- u32 eax, ebx, ecx, edx;
+enum {
+ VMM_ID_EVMM = 0,
+ VMM_ID_CWP,
+ VMM_SUPPORTED_NUM
+};
- cpuid(3, &eax, &ebx, &ecx, &edx);
- if ((ecx != EVMM_SIGNATURE_VMM) ||
- (edx != EVMM_SIGNATURE_CORP)) {
- return -EINVAL;
- }
+static const char *vmm_signature[] = {
+ [VMM_ID_EVMM] = "EVMMEVMMEVMM",
+ [VMM_ID_CWP] = "CWPCWPCWP\0\0"
+};
- if(vmm_signature) {
- *vmm_signature = ecx;
+/* Detect VMM and return vmm_id */
+static inline int trusty_detect_vmm(void)
+{
+ int i;
+ for (i = 0; i < VMM_SUPPORTED_NUM; i++) {
+ if (hypervisor_cpuid_base(vmm_signature[i], 0))
+ return i;
}
- return 0;
+ return -EINVAL;
}
/* High 32 bits of unsigned 64-bit integer*/
--
https://clearlinux.org