blob: 1ea95bc18cb211d80e7cbff9752e5bea4b7bc139 [file] [log] [blame]
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +01001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Low-level entry and exit points of pvmfw.
16
Pierre-Clément Tosia1d3ea32022-11-01 15:05:11 +000017use crate::helpers;
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +010018use crate::mmio_guard;
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010019use core::arch::asm;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010020use core::slice;
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +010021use log::{debug, error, LevelFilter};
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +010022use vmbase::{console, logger, main, power::reboot};
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010023
24#[derive(Debug, Clone)]
25enum RebootReason {
26 /// An unexpected internal error happened.
27 InternalError,
28}
29
30main!(start);
31
32/// Entry point for pVM firmware.
33pub fn start(fdt_address: u64, payload_start: u64, payload_size: u64, _arg3: u64) {
34 // Limitations in this function:
35 // - can't access non-pvmfw memory (only statically-mapped memory)
36 // - can't access MMIO (therefore, no logging)
37
38 match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
39 Ok(_) => jump_to_payload(fdt_address, payload_start),
40 Err(_) => reboot(),
41 }
42
43 // if we reach this point and return, vmbase::entry::rust_entry() will call power::shutdown().
44}
45
46/// Sets up the environment for main() and wraps its result for start().
47///
48/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
49/// the assumption that its environment has been properly configured.
50fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), RebootReason> {
51 // Limitations in this function:
52 // - only access MMIO once (and while) it has been mapped and configured
53 // - only perform logging once the logger has been initialized
54 // - only access non-pvmfw memory once (and while) it has been mapped
Pierre-Clément Tosidbd72862022-10-21 14:31:02 +010055 logger::init(LevelFilter::Info).map_err(|_| RebootReason::InternalError)?;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010056
Pierre-Clément Tosia1d3ea32022-11-01 15:05:11 +000057 const FDT_MAX_SIZE: usize = helpers::SIZE_2MB;
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010058 // TODO: Check that the FDT is fully contained in RAM.
59 // SAFETY - We trust the VMM, for now.
60 let fdt = unsafe { slice::from_raw_parts_mut(fdt as *mut u8, FDT_MAX_SIZE) };
61 // TODO: Check that the payload is fully contained in RAM and doesn't overlap with the FDT.
62 // SAFETY - We trust the VMM, for now.
63 let payload = unsafe { slice::from_raw_parts(payload as *const u8, payload_size) };
64
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +010065 // Use debug!() to avoid printing to the UART if we failed to configure it as only local
66 // builds that have tweaked the logger::init() call will actually attempt to log the message.
67
68 mmio_guard::init().map_err(|e| {
69 debug!("{e}");
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010070 RebootReason::InternalError
71 })?;
72
Pierre-Clément Tosi072969b2022-10-19 17:32:24 +010073 mmio_guard::map(console::BASE_ADDRESS).map_err(|e| {
74 debug!("Failed to configure the UART: {e}");
75 RebootReason::InternalError
76 })?;
77
78 // This wrapper allows main() to be blissfully ignorant of platform details.
79 crate::main(fdt, payload);
80
Pierre-Clément Tosia99bfa62022-10-06 13:30:52 +010081 mmio_guard::unmap(console::BASE_ADDRESS).map_err(|e| {
82 error!("Failed to unshare the UART: {e}");
83 RebootReason::InternalError
84 })?;
85
Pierre-Clément Tosi5bbfca52022-10-21 12:14:35 +010086 Ok(())
87}
Pierre-Clément Tosi645e90e2022-10-21 13:27:19 +010088
89fn jump_to_payload(fdt_address: u64, payload_start: u64) -> ! {
90 const SCTLR_EL1_RES1: usize = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
91 // Stage 1 instruction access cacheability is unaffected.
92 const SCTLR_EL1_I: usize = 0b1 << 12;
93 // SETEND instruction disabled at EL0 in aarch32 mode.
94 const SCTLR_EL1_SED: usize = 0b1 << 8;
95 // Various IT instructions are disabled at EL0 in aarch32 mode.
96 const SCTLR_EL1_ITD: usize = 0b1 << 7;
97
98 const SCTLR_EL1_VAL: usize = SCTLR_EL1_RES1 | SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_I;
99
100 // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
101 unsafe {
102 asm!(
103 "msr sctlr_el1, {sctlr_el1_val}",
104 "isb",
105 "mov x1, xzr",
106 "mov x2, xzr",
107 "mov x3, xzr",
108 "mov x4, xzr",
109 "mov x5, xzr",
110 "mov x6, xzr",
111 "mov x7, xzr",
112 "mov x8, xzr",
113 "mov x9, xzr",
114 "mov x10, xzr",
115 "mov x11, xzr",
116 "mov x12, xzr",
117 "mov x13, xzr",
118 "mov x14, xzr",
119 "mov x15, xzr",
120 "mov x16, xzr",
121 "mov x17, xzr",
122 "mov x18, xzr",
123 "mov x19, xzr",
124 "mov x20, xzr",
125 "mov x21, xzr",
126 "mov x22, xzr",
127 "mov x23, xzr",
128 "mov x24, xzr",
129 "mov x25, xzr",
130 "mov x26, xzr",
131 "mov x27, xzr",
132 "mov x28, xzr",
133 "mov x29, xzr",
134 "msr ttbr0_el1, xzr",
135 "isb",
136 "dsb nsh",
137 "br x30",
138 sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
139 in("x0") fdt_address,
140 in("x30") payload_start,
141 options(nomem, noreturn, nostack),
142 );
143 };
144}