Wrap main function, to set up console before and shutdown after.

Bug: 223166344
Test: Ran unprotected VM under crosvm.
Change-Id: Idf1f9d30a5118737134a31c65375cdc293ede117
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 3fe3435..d98ea8e 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -19,13 +19,11 @@
 
 mod exceptions;
 
-use vmbase::{console, power::shutdown, println};
+use vmbase::{main, println};
+
+main!(main);
 
 /// Entry point for pVM firmware.
-#[no_mangle]
-pub extern "C" fn main() -> ! {
-    console::init();
+pub fn main() {
     println!("Hello world");
-
-    shutdown();
 }
diff --git a/vmbase/entry.S b/vmbase/entry.S
index f0021be..a12e1aa 100644
--- a/vmbase/entry.S
+++ b/vmbase/entry.S
@@ -150,7 +150,7 @@
 	msr vbar_el1, x30
 
 	/* Call into Rust code. */
-	bl main
+	bl rust_entry
 
 	/* Loop forever waiting for interrupts. */
 4:	wfi
diff --git a/vmbase/src/entry.rs b/vmbase/src/entry.rs
new file mode 100644
index 0000000..dd7f6db
--- /dev/null
+++ b/vmbase/src/entry.rs
@@ -0,0 +1,57 @@
+// 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.
+
+//! Rust entry point.
+
+use crate::{console, power::shutdown};
+
+/// This is the entry point to the Rust code, called from the binary entry point in `entry.S`.
+#[no_mangle]
+extern "C" fn rust_entry() -> ! {
+    console::init();
+    unsafe {
+        main();
+    }
+    shutdown();
+}
+
+extern "Rust" {
+    /// Main function provided by the application using the `main!` macro.
+    fn main();
+}
+
+/// Marks the main function of the binary.
+///
+/// Example:
+///
+/// ```rust
+/// use vmbase::main;
+///
+/// main!(my_main);
+///
+/// fn my_main() {
+///     println!("Hello world");
+/// }
+/// ```
+#[macro_export]
+macro_rules! main {
+    ($name:path) => {
+        // Export a symbol with a name matching the extern declaration above.
+        #[export_name = "main"]
+        fn __main() {
+            // Ensure that the main function provided by the application has the correct type.
+            $name()
+        }
+    };
+}
diff --git a/vmbase/src/lib.rs b/vmbase/src/lib.rs
index 0901e04..90d6fc2 100644
--- a/vmbase/src/lib.rs
+++ b/vmbase/src/lib.rs
@@ -17,6 +17,7 @@
 #![no_std]
 
 pub mod console;
+mod entry;
 pub mod power;
 pub mod uart;