/ src / arch / riscv / payload.c
payload.c
 1  /* SPDX-License-Identifier: GPL-2.0-only */
 2  
 3  #include <program_loading.h>
 4  #include <stdint.h>
 5  #include <arch/boot.h>
 6  #include <arch/encoding.h>
 7  #include <arch/pmp.h>
 8  #include <arch/smp/atomic.h>
 9  #include <console/console.h>
10  #include <mcall.h>
11  #include <vm.h>
12  
13  /* Run OpenSBI and let OpenSBI hand over control to the payload */
14  void run_payload_opensbi(struct prog *prog, void *fdt, struct prog *opensbi, int payload_mode)
15  {
16  	int hart_id = read_csr(mhartid);
17  	uintptr_t status = read_csr(mstatus);
18  	status = INSERT_FIELD(status, MSTATUS_MPIE, 0);
19  
20  	/*
21  	 * In case of OpenSBI we always run it in M-Mode.
22  	 * OpenSBI will switch to payload_mode when done.
23  	 */
24  
25  	status = INSERT_FIELD(status, MSTATUS_MPP, PRV_M);
26  	/* Trap vector base address point to the payload */
27  	write_csr(mtvec, prog_entry(opensbi));
28  	/* disable M-Mode interrupt */
29  	write_csr(mie, 0);
30  	write_csr(mstatus, status);
31  
32  	run_opensbi(hart_id, fdt, prog_entry(opensbi), prog_entry(prog), payload_mode);
33  }
34  
35  /* Runs the payload without OpenSBI integration */
36  void run_payload(struct prog *prog, void *fdt, int payload_mode)
37  {
38  	void (*doit)(int hart_id, void *fdt) = prog_entry(prog);
39  	int hart_id = read_csr(mhartid);
40  	uintptr_t status = read_csr(mstatus);
41  	extern void *_text, *_estack;
42  	status = INSERT_FIELD(status, MSTATUS_MPIE, 0);
43  
44  	switch (payload_mode) {
45  	case RISCV_PAYLOAD_MODE_S:
46  		/*
47  		 * Set up a PMP to protect coreboot, then close the PMPs.
48  		 * If a mainboard or SoC needs other ranges
49  		 * set up, they should do so before this point,
50  		 * as close_pmp puts in a "match all" entry, and
51  		 * PMPs are processed in linear order.
52  		 */
53  
54  		/*
55  		 * On this code path, coreboot is providing the coreboot SBI, and must
56  		 * protect the ramstage, from _text to _estack, from S and U
57  		 * modes. Because the number of PMP registers may be very
58  		 * small, make this an NAPOT area. The linker scripts
59  		 * should round _text and _estack to 4K.
60  		 */
61  		setup_pmp((u64)(uintptr_t) _text,
62  				(u64)(uintptr_t) _estack - (u64)(uintptr_t) _text, 0);
63  
64  		/*
65  		 * All pmp operations should be finished when close_pmp is called.
66  		 * Presently, this requirement is not enforced.
67  		 */
68  		close_pmp();
69  
70  		status = INSERT_FIELD(status, MSTATUS_MPP, PRV_S);
71  		/* Trap vector base address point to the payload */
72  		write_csr(stvec, doit);
73  		/* disable S-Mode interrupt */
74  		write_csr(sie, 0);
75  		/* disable MMU */
76  		write_csr(satp, 0);
77  		/* save stack to mscratch so trap_entry can use that as exception stack */
78  		write_csr(mscratch, MACHINE_STACK_TOP());
79  		break;
80  	case RISCV_PAYLOAD_MODE_M:
81  		status = INSERT_FIELD(status, MSTATUS_MPP, PRV_M);
82  		/* Trap vector base address point to the payload */
83  		write_csr(mtvec, doit);
84  		/* disable M-Mode interrupt */
85  		write_csr(mie, 0);
86  		break;
87  	default:
88  		die("wrong privilege level for payload");
89  		break;
90  	}
91  	write_csr(mstatus, status);
92  	write_csr(mepc, doit);
93  	asm volatile(
94  		"mv a0, %0\n\t"
95  		"mv a1, %1\n\t"
96  		"mret" ::"r"(hart_id),
97  		"r"(fdt)
98  		: "a0", "a1");
99  }