Merge changes I4e779ab0,I9105f200
* changes:
Add minimal UART driver for console.
Move writable data to a higher block of memory.
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 8af40e2..fbdd8d7 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -12,6 +12,9 @@
"libcompiler_builtins.rust_sysroot",
"libcore.rust_sysroot",
],
+ rustlibs: [
+ "libspin_nostd",
+ ],
enabled: false,
target: {
android_arm64: {
diff --git a/pvmfw/entry.S b/pvmfw/entry.S
index 787b4ff..e5c6045 100644
--- a/pvmfw/entry.S
+++ b/pvmfw/entry.S
@@ -63,13 +63,16 @@
.set .L_SCTLR_ELx_M, 0x1 << 0
/* Privileged Access Never is unchanged on taking an exception to EL1. */
.set .L_SCTLR_EL1_SPAN, 0x1 << 23
+/* All writable memory regions are treated as XN. */
+.set .L_SCTLR_EL1_WXN, 0x1 << 19
/* 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_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
-.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1
+.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1 | .L_SCTLR_EL1_WXN
+
/**
* This is a generic entry point for an image. It carries out the operations
* required to prepare the loaded image to be run. Specifically, it zeroes the
@@ -128,13 +131,23 @@
stp xzr, xzr, [x29], #16
b 0b
-1: /* Prepare the stack. */
- adr x30, boot_stack_end
+1: /* Copy the data section. */
+ adr_l x28, data_begin
+ adr_l x29, data_end
+ adr_l x30, data_lma
+2: cmp x28, x29
+ b.ge 3f
+ ldp q0, q1, [x30], #32
+ stp q0, q1, [x28], #32
+ b 2b
+
+3: /* Prepare the stack. */
+ adr_l x30, boot_stack_end
mov sp, x30
/* Call into Rust code. */
bl main
/* Loop forever waiting for interrupts. */
-2: wfi
- b 2b
+4: wfi
+ b 4b
diff --git a/pvmfw/idmap.S b/pvmfw/idmap.S
index f5050af..f1df6cc 100644
--- a/pvmfw/idmap.S
+++ b/pvmfw/idmap.S
@@ -30,7 +30,8 @@
.set .L_BLOCK_RO, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_RO | .L_TT_XN
.set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN
-.set .L_BLOCK_MEM_XIP, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG
+.set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_XN | .L_TT_NG
+.set .L_BLOCK_MEM_XIP, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG | .L_TT_RO
.section ".rodata.idmap", "a", %progbits
.global idmap
@@ -45,4 +46,5 @@
/* level 2 */
0: .quad .L_BLOCK_RO | 0x80000000 // DT provided by VMM
.quad .L_BLOCK_MEM_XIP | 0x80200000 // 2 MB of DRAM containing image
- .fill 510, 8, 0x0
+ .quad .L_BLOCK_MEM | 0x80400000 // 2 MB of writable DRAM
+ .fill 509, 8, 0x0
diff --git a/pvmfw/image.ld b/pvmfw/image.ld
index e08fbe2..4655f68 100644
--- a/pvmfw/image.ld
+++ b/pvmfw/image.ld
@@ -18,6 +18,7 @@
{
dtb_region : ORIGIN = 0x80000000, LENGTH = 2M
image : ORIGIN = 0x80200000, LENGTH = 2M
+ writable_data : ORIGIN = 0x80400000, LENGTH = 2M
}
/*
@@ -82,7 +83,9 @@
*/
. = ALIGN(32);
data_end = .;
- } >image
+ } >writable_data AT>image
+ data_lma = LOADADDR(.data);
+
/* Everything beyond this point will not be included in the binary. */
bin_end = .;
@@ -93,14 +96,14 @@
*(COMMON)
. = ALIGN(16);
bss_end = .;
- } >image
+ } >writable_data
.stack (NOLOAD) : ALIGN(4096) {
boot_stack_begin = .;
. += 40 * 4096;
. = ALIGN(4096);
boot_stack_end = .;
- } >image
+ } >writable_data
/*
* Remove unused sections from the image.
diff --git a/pvmfw/src/console.rs b/pvmfw/src/console.rs
new file mode 100644
index 0000000..d44eb92
--- /dev/null
+++ b/pvmfw/src/console.rs
@@ -0,0 +1,61 @@
+// 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
+//
+// http://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.
+
+//! Console driver for 8250 UART.
+
+use crate::uart::Uart;
+use core::fmt::{write, Arguments, Write};
+use spin::mutex::SpinMutex;
+
+const BASE_ADDRESS: usize = 0x3f8;
+
+static CONSOLE: SpinMutex<Option<Uart>> = SpinMutex::new(None);
+
+/// Initialises a new instance of the UART driver and returns it.
+fn create() -> Uart {
+ // Safe because BASE_ADDRESS is the base of the MMIO region for a UART and is mapped as device
+ // memory.
+ unsafe { Uart::new(BASE_ADDRESS) }
+}
+
+/// Initialises the global instance of the UART driver. This must be called before using
+/// the `print!` and `println!` macros.
+pub fn init() {
+ let uart = create();
+ CONSOLE.lock().replace(uart);
+}
+
+/// Writes a string to the console.
+///
+/// Panics if [`init`] was not called first.
+pub fn write_str(s: &str) {
+ CONSOLE.lock().as_mut().unwrap().write_str(s).unwrap();
+}
+
+/// Writes a formatted string to the console.
+///
+/// Panics if [`init`] was not called first.
+#[allow(unused)]
+pub fn write_args(format_args: Arguments) {
+ write(CONSOLE.lock().as_mut().unwrap(), format_args).unwrap();
+}
+
+/// Reinitialises the UART driver and writes a string to it.
+///
+/// This is intended for use in situations where the UART may be in an unknown state or the global
+/// instance may be locked, such as in an exception handler or panic handler.
+pub fn emergency_write_str(s: &str) {
+ let mut uart = create();
+ let _ = uart.write_str(s);
+}
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 0a359f6..7156213 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -17,14 +17,20 @@
#![no_main]
#![no_std]
+mod console;
mod psci;
+mod uart;
+use console::emergency_write_str;
use core::panic::PanicInfo;
use psci::{system_off, system_reset};
/// Entry point for pVM firmware.
#[no_mangle]
pub extern "C" fn main() -> ! {
+ console::init();
+ console::write_str("Hello world\n");
+
system_off();
#[allow(clippy::empty_loop)]
loop {}
@@ -32,6 +38,7 @@
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
+ emergency_write_str("panic\n");
system_reset();
loop {}
}
diff --git a/pvmfw/src/uart.rs b/pvmfw/src/uart.rs
new file mode 100644
index 0000000..0fc2494
--- /dev/null
+++ b/pvmfw/src/uart.rs
@@ -0,0 +1,59 @@
+// 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
+//
+// http://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.
+
+//! Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
+//! provided by crosvm, and won't work with real hardware.
+
+use core::fmt::{self, Write};
+use core::ptr::write_volatile;
+
+/// Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
+/// provided by crosvm, and won't work with real hardware.
+pub struct Uart {
+ base_address: *mut u8,
+}
+
+impl Uart {
+ /// Constructs a new instance of the UART driver for a device at the given base address.
+ ///
+ /// # Safety
+ ///
+ /// The given base address must point to the 8 MMIO control registers of an appropriate UART
+ /// device, which must be mapped into the address space of the process as device memory and not
+ /// have any other aliases.
+ pub unsafe fn new(base_address: usize) -> Self {
+ Self { base_address: base_address as *mut u8 }
+ }
+
+ /// Writes a single byte to the UART.
+ pub fn write_byte(&self, byte: u8) {
+ // Safe because we know that the base address points to the control registers of an UART
+ // device which is appropriately mapped.
+ unsafe {
+ write_volatile(self.base_address, byte);
+ }
+ }
+}
+
+impl Write for Uart {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ for c in s.as_bytes() {
+ self.write_byte(*c);
+ }
+ Ok(())
+ }
+}
+
+// Safe because it just contains a pointer to device memory, which can be accessed from any context.
+unsafe impl Send for Uart {}