#include <asm/sections.h>
 #include <asm/machdep.h>
 #include <asm/asm-prototypes.h>
+#include <asm/ultravisor-api.h>
 
 #include <linux/linux_logo.h>
 
 static bool __prombss prom_xive_disable;
 #endif
 
+#ifdef CONFIG_PPC_SVM
+static bool __prombss prom_svm_enable;
+#endif
+
 struct platform_support {
        bool hash_mmu;
        bool radix_mmu;
                prom_debug("XIVE disabled from cmdline\n");
        }
 #endif /* CONFIG_PPC_PSERIES */
+
+#ifdef CONFIG_PPC_SVM
+       opt = prom_strstr(prom_cmd_line, "svm=");
+       if (opt) {
+               bool val;
+
+               opt += sizeof("svm=") - 1;
+               if (!prom_strtobool(opt, &val))
+                       prom_svm_enable = val;
+       }
+#endif /* CONFIG_PPC_SVM */
 }
 
 #ifdef CONFIG_PPC_PSERIES
        }
 }
 
+#ifdef CONFIG_PPC_SVM
+static int prom_rtas_hcall(uint64_t args)
+{
+       register uint64_t arg1 asm("r3") = H_RTAS;
+       register uint64_t arg2 asm("r4") = args;
+
+       asm volatile("sc 1\n" : "=r" (arg1) :
+                       "r" (arg1),
+                       "r" (arg2) :);
+       return arg1;
+}
+
+static struct rtas_args __prombss os_term_args;
+
+static void __init prom_rtas_os_term(char *str)
+{
+       phandle rtas_node;
+       __be32 val;
+       u32 token;
+
+       prom_debug("%s: start...\n", __func__);
+       rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+       prom_debug("rtas_node: %x\n", rtas_node);
+       if (!PHANDLE_VALID(rtas_node))
+               return;
+
+       val = 0;
+       prom_getprop(rtas_node, "ibm,os-term", &val, sizeof(val));
+       token = be32_to_cpu(val);
+       prom_debug("ibm,os-term: %x\n", token);
+       if (token == 0)
+               prom_panic("Could not get token for ibm,os-term\n");
+       os_term_args.token = cpu_to_be32(token);
+       prom_rtas_hcall((uint64_t)&os_term_args);
+}
+#endif /* CONFIG_PPC_SVM */
+
 /*
  * Allocate room for and instantiate RTAS
  */
 #endif
 #endif
 
+#ifdef CONFIG_PPC_SVM
+/*
+ * Perform the Enter Secure Mode ultracall.
+ */
+static int enter_secure_mode(unsigned long kbase, unsigned long fdt)
+{
+       register unsigned long r3 asm("r3") = UV_ESM;
+       register unsigned long r4 asm("r4") = kbase;
+       register unsigned long r5 asm("r5") = fdt;
+
+       asm volatile("sc 2" : "+r"(r3) : "r"(r4), "r"(r5));
+
+       return r3;
+}
+
+/*
+ * Call the Ultravisor to transfer us to secure memory if we have an ESM blob.
+ */
+static void setup_secure_guest(unsigned long kbase, unsigned long fdt)
+{
+       int ret;
+
+       if (!prom_svm_enable)
+               return;
+
+       /* Switch to secure mode. */
+       prom_printf("Switching to secure mode.\n");
+
+       ret = enter_secure_mode(kbase, fdt);
+       if (ret != U_SUCCESS) {
+               prom_printf("Returned %d from switching to secure mode.\n", ret);
+               prom_rtas_os_term("Switch to secure mode failed.\n");
+       }
+}
+#else
+static void setup_secure_guest(unsigned long kbase, unsigned long fdt)
+{
+}
+#endif /* CONFIG_PPC_SVM */
+
 /*
  * We enter here early on, when the Open Firmware prom is still
  * handling exceptions and the MMU hash table for us.
        unreloc_toc();
 #endif
 
+       /* Move to secure memory if we're supposed to be secure guests. */
+       setup_secure_guest(kbase, hdr);
+
        __start(hdr, kbase, 0, 0, 0, 0, 0);
 
        return 0;