From 1a5614e971cf44e08342c2b1639fa3be544b0202 Mon Sep 17 00:00:00 2001
From: Anup Patel <anup.patel@wdc.com>
Date: Fri, 5 Apr 2019 14:08:57 +0530
Subject: lib: Extend sbi_hart_switch_mode() to support hypervisor extension

This patch extends sbi_hart_switch_mode() to support entering
VS/VU modes when hypervisor extension is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 include/sbi/riscv_encoding.h | 14 ++++++++++++++
 include/sbi/sbi_hart.h       |  3 ++-
 lib/sbi/sbi_hart.c           | 27 +++++++++++++++++++++++++--
 lib/sbi/sbi_init.c           |  5 +++--
 4 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
index 5a5086a..dace9e6 100644
--- a/include/sbi/riscv_encoding.h
+++ b/include/sbi/riscv_encoding.h
@@ -38,8 +38,21 @@
 #define MSTATUS_TW			0x00200000
 #define MSTATUS_TSR			0x00400000
 #define MSTATUS32_SD			0x80000000
+#if __riscv_xlen == 64
 #define MSTATUS_UXL			0x0000000300000000
 #define MSTATUS_SXL			0x0000000C00000000
+#define MSTATUS_MTL			0x0000004000000000
+#define MSTATUS_MTL_SHIFT		38
+#define MSTATUS_MPV			0x0000008000000000
+#define MSTATUS_MPV_HIFT		39
+#else
+#define MSTATUSH_UXL			0x00000003
+#define MSTATUSH_SXL			0x0000000C
+#define MSTATUSH_MTL			0x00000040
+#define MSTATUSH_MTL_SHIFT		6
+#define MSTATUSH_MPV			0x00000080
+#define MSTATUSH_MPV_HIFT		7
+#endif
 #define MSTATUS64_SD			0x8000000000000000
 
 #define SSTATUS_UIE			0x00000001
@@ -256,6 +269,7 @@
 #define CSR_MIE				0x304
 #define CSR_MTVEC			0x305
 #define CSR_MCOUNTEREN			0x306
+#define CSR_MSTATUSH			0x310
 #define CSR_MSCRATCH			0x340
 #define CSR_MEPC			0x341
 #define CSR_MCAUSE			0x342
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 4aa4a5c..0762f95 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -26,7 +26,8 @@ void __attribute__((noreturn)) sbi_hart_hang(void);
 
 void __attribute__((noreturn))
 sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
-		     unsigned long next_addr, unsigned long next_mode);
+		     unsigned long next_addr, unsigned long next_mode,
+		     bool next_virt);
 
 void sbi_hart_mark_available(u32 hartid);
 
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 6dac84b..b0c087a 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -241,9 +241,14 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
 
 void __attribute__((noreturn))
 sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
-		     unsigned long next_addr, unsigned long next_mode)
+		     unsigned long next_addr, unsigned long next_mode,
+		     bool next_virt)
 {
+#if __riscv_xlen == 32
+	unsigned long val, valH;
+#else
 	unsigned long val;
+#endif
 
 	switch (next_mode) {
 	case PRV_M:
@@ -263,7 +268,25 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
 	val = csr_read(CSR_MSTATUS);
 	val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
 	val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
-
+#if __riscv_xlen == 32
+	if (misa_extension('H')) {
+		valH = csr_read(CSR_MSTATUSH);
+		valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
+		if (next_virt)
+			valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
+		else
+			valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
+		csr_write(CSR_MSTATUSH, valH);
+	}
+#else
+	if (misa_extension('H')) {
+		val = INSERT_FIELD(val, MSTATUS_MTL, 0);
+		if (next_virt)
+			val = INSERT_FIELD(val, MSTATUS_MPV, 1);
+		else
+			val = INSERT_FIELD(val, MSTATUS_MPV, 0);
+	}
+#endif
 	csr_write(CSR_MSTATUS, val);
 	csr_write(CSR_MEPC, next_addr);
 
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 4663a30..e1acb57 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -102,7 +102,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
 		sbi_hart_wake_coldboot_harts(scratch, hartid);
 	sbi_hart_mark_available(hartid);
 	sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
-			     scratch->next_mode);
+			     scratch->next_mode, FALSE);
 }
 
 static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
@@ -147,7 +147,8 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
 		sbi_hart_hang();
 	else
 		sbi_hart_switch_mode(hartid, scratch->next_arg1,
-				     scratch->next_addr, scratch->next_mode);
+				     scratch->next_addr,
+				     scratch->next_mode, FALSE);
 }
 
 static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);
-- 
cgit v1.2.3