diff options
Diffstat (limited to 'arch/riscv/kernel/process.c')
| -rw-r--r-- | arch/riscv/kernel/process.c | 37 | 
1 files changed, 37 insertions, 0 deletions
| diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 504b496787aa..1c7be865ab31 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -84,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)  { @@ -98,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) | 
