pvmfw: Implement jump_to_payload with asm!()
Move the start_payload routine to Rust as at the point where we might
call it, the system is in a state where Rust code can run and there is
then no reason to avoid the Rust compiler, unlike vmbase/entry.S. By
using asm!(), the compiler is made aware of the routine and will handle
ABI compatibility and more.
Test: atest MicrodroidTestApp
Change-Id: If9867d0142c1254e370f6c97d4f3ef749771afe2
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 296644a..d0fc9a9 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -20,7 +20,6 @@
defaults: ["vmbase_elf_defaults"],
srcs: [
"idmap.S",
- "payload.S",
],
static_libs: [
"libpvmfw",
diff --git a/pvmfw/payload.S b/pvmfw/payload.S
deleted file mode 100644
index cbda448..0000000
--- a/pvmfw/payload.S
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-.macro mov_i, reg:req, imm:req
- movz \reg, :abs_g3:\imm
- movk \reg, :abs_g2_nc:\imm
- movk \reg, :abs_g1_nc:\imm
- movk \reg, :abs_g0_nc:\imm
-.endm
-
-/* Stage 1 instruction access cacheability is unaffected. */
-.set .L_SCTLR_ELx_I, 0x1 << 12
-/* SETEND instruction disabled at EL0 in aarch32 mode. */
-.set .L_SCTLR_EL1_SED, 0x1 << 8
-/* Various IT instructions are disabled at EL0 in aarch32 mode. */
-.set .L_SCTLR_EL1_ITD, 0x1 << 7
-.set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << 28) | (0x1 << 29)
-.set .Lsctlrval, .L_SCTLR_ELx_I | .L_SCTLR_EL1_SED | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_RES1
-
-/**
- * Disable the exception vector, caches and page talbe and then jump to the payload at the given
- * address, passing it the given FDT pointer.
- *
- * x0: FDT address to pass to payload
- * x1: Payload address
- */
-.global start_payload
-start_payload:
- /* Move payload address to a higher register and zero out parameters other than x0. */
- mov x30, x1
- mov x1, #0
- mov x2, #0
- mov x3, #0
-
- /* Zero out remaining registers to avoid leaking data. */
- mov x4, #0
- mov x5, #0
- mov x6, #0
- mov x7, #0
- mov x8, #0
- mov x9, #0
- mov x10, #0
- mov x11, #0
- mov x12, #0
- mov x13, #0
- mov x14, #0
- mov x15, #0
- mov x16, #0
- mov x17, #0
- mov x18, #0
- mov x19, #0
- mov x20, #0
- mov x21, #0
- mov x22, #0
- mov x23, #0
- mov x24, #0
- mov x25, #0
- mov x26, #0
- mov x27, #0
- mov x28, #0
-
- /* Disable the MMU and cache, and set other settings to valid warm reset values. */
- mov_i x29, .Lsctlrval
- msr sctlr_el1, x29
- isb
- msr ttbr0_el1, xzr
-
- isb
- dsb nsh
-
- /* Jump into the payload. */
- br x30
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 95dc0b0..a606462 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -15,8 +15,8 @@
//! Low-level entry and exit points of pvmfw.
use crate::helpers::FDT_MAX_SIZE;
-use crate::jump_to_payload;
use crate::mmio_guard;
+use core::arch::asm;
use core::slice;
use log::{debug, LevelFilter};
use vmbase::{console, logger, main, power::reboot};
@@ -79,3 +79,60 @@
Ok(())
}
+
+fn jump_to_payload(fdt_address: u64, payload_start: u64) -> ! {
+ const SCTLR_EL1_RES1: usize = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
+ // Stage 1 instruction access cacheability is unaffected.
+ const SCTLR_EL1_I: usize = 0b1 << 12;
+ // SETEND instruction disabled at EL0 in aarch32 mode.
+ const SCTLR_EL1_SED: usize = 0b1 << 8;
+ // Various IT instructions are disabled at EL0 in aarch32 mode.
+ const SCTLR_EL1_ITD: usize = 0b1 << 7;
+
+ const SCTLR_EL1_VAL: usize = SCTLR_EL1_RES1 | SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_I;
+
+ // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
+ unsafe {
+ asm!(
+ "msr sctlr_el1, {sctlr_el1_val}",
+ "isb",
+ "mov x1, xzr",
+ "mov x2, xzr",
+ "mov x3, xzr",
+ "mov x4, xzr",
+ "mov x5, xzr",
+ "mov x6, xzr",
+ "mov x7, xzr",
+ "mov x8, xzr",
+ "mov x9, xzr",
+ "mov x10, xzr",
+ "mov x11, xzr",
+ "mov x12, xzr",
+ "mov x13, xzr",
+ "mov x14, xzr",
+ "mov x15, xzr",
+ "mov x16, xzr",
+ "mov x17, xzr",
+ "mov x18, xzr",
+ "mov x19, xzr",
+ "mov x20, xzr",
+ "mov x21, xzr",
+ "mov x22, xzr",
+ "mov x23, xzr",
+ "mov x24, xzr",
+ "mov x25, xzr",
+ "mov x26, xzr",
+ "mov x27, xzr",
+ "mov x28, xzr",
+ "mov x29, xzr",
+ "msr ttbr0_el1, xzr",
+ "isb",
+ "dsb nsh",
+ "br x30",
+ sctlr_el1_val = in(reg) SCTLR_EL1_VAL,
+ in("x0") fdt_address,
+ in("x30") payload_start,
+ options(nomem, noreturn, nostack),
+ );
+ };
+}
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index d1951b3..9f8cbd2 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -36,15 +36,3 @@
info!("Starting payload...");
}
-
-fn jump_to_payload(fdt_address: u64, payload_start: u64) {
- // Safe because this is a function we have implemented in assembly that matches its signature
- // here.
- unsafe {
- start_payload(fdt_address, payload_start);
- }
-}
-
-extern "C" {
- fn start_payload(fdt_address: u64, payload_start: u64) -> !;
-}