riscv: compat: Add hw capability check for elf
[linux-2.6-microblaze.git] / arch / riscv / kernel / process.c
index 03ac3aa..1c7be86 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/string.h>
 #include <asm/switch_to.h>
 #include <asm/thread_info.h>
+#include <asm/cpuidle.h>
 
 register unsigned long gp_in_global __asm__("gp");
 
@@ -37,7 +38,7 @@ extern asmlinkage void ret_from_kernel_thread(void);
 
 void arch_cpu_idle(void)
 {
-       wait_for_interrupt();
+       cpu_do_idle();
        raw_local_irq_enable();
 }
 
@@ -83,6 +84,34 @@ void show_regs(struct pt_regs *regs)
                dump_backtrace(regs, NULL, KERN_DEFAULT);
 }
 
+#ifdef CONFIG_COMPAT
+static bool compat_mode_supported __read_mostly;
+
+bool compat_elf_check_arch(Elf32_Ehdr *hdr)
+{
+       return compat_mode_supported &&
+              hdr->e_machine == EM_RISCV &&
+              hdr->e_ident[EI_CLASS] == ELFCLASS32;
+}
+
+static int __init compat_mode_detect(void)
+{
+       unsigned long tmp = csr_read(CSR_STATUS);
+
+       csr_write(CSR_STATUS, (tmp & ~SR_UXL) | SR_UXL_32);
+       compat_mode_supported =
+                       (csr_read(CSR_STATUS) & SR_UXL) == SR_UXL_32;
+
+       csr_write(CSR_STATUS, tmp);
+
+       pr_info("riscv: ELF compat mode %s",
+                       compat_mode_supported ? "supported" : "failed");
+
+       return 0;
+}
+early_initcall(compat_mode_detect);
+#endif
+
 void start_thread(struct pt_regs *regs, unsigned long pc,
        unsigned long sp)
 {
@@ -97,6 +126,15 @@ void start_thread(struct pt_regs *regs, unsigned long pc,
        }
        regs->epc = pc;
        regs->sp = sp;
+
+#ifdef CONFIG_64BIT
+       regs->status &= ~SR_UXL;
+
+       if (is_compat_task())
+               regs->status |= SR_UXL_32;
+       else
+               regs->status |= SR_UXL_64;
+#endif
 }
 
 void flush_thread(void)