Standardise and require safety comments in vmbase.

Bug: 290018030
Test: m vmbase_example_bin
Change-Id: Ic5704d6cd9b2a4090fa9758d7a65a56e83c4286c
diff --git a/vmbase/src/arch.rs b/vmbase/src/arch.rs
index d7b63b3..d8bb8b2 100644
--- a/vmbase/src/arch.rs
+++ b/vmbase/src/arch.rs
@@ -19,8 +19,8 @@
 macro_rules! read_sysreg {
     ($sysreg:literal) => {{
         let mut r: usize;
-        // Safe because it reads a system register and does not affect Rust.
         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
+        // SAFETY: Reading a system register does not affect memory.
         unsafe {
             core::arch::asm!(
                 concat!("mrs {}, ", $sysreg),
@@ -53,8 +53,8 @@
 #[macro_export]
 macro_rules! isb {
     () => {{
-        // Safe because this is just a memory barrier and does not affect Rust.
         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
+        // SAFETY: memory barriers do not affect Rust's memory model.
         unsafe {
             core::arch::asm!("isb", options(nomem, nostack, preserves_flags));
         }
@@ -65,8 +65,8 @@
 #[macro_export]
 macro_rules! dsb {
     ($option:literal) => {{
-        // Safe because this is just a memory barrier and does not affect Rust.
         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
+        // SAFETY: memory barriers do not affect Rust's memory model.
         unsafe {
             core::arch::asm!(concat!("dsb ", $option), options(nomem, nostack, preserves_flags));
         }
@@ -79,9 +79,9 @@
     ($option:literal, $asid:expr, $addr:expr) => {{
         let asid: usize = $asid;
         let addr: usize = $addr;
-        // Safe because it invalidates TLB and doesn't affect Rust. When the address matches a
-        // block entry larger than the page size, all translations for the block are invalidated.
         #[allow(unused_unsafe)] // In case the macro is used within an unsafe block.
+        // SAFETY: Invalidating the TLB doesn't affect Rust. When the address matches a
+        // block entry larger than the page size, all translations for the block are invalidated.
         unsafe {
             core::arch::asm!(
                 concat!("tlbi ", $option, ", {x}"),
diff --git a/vmbase/src/bionic.rs b/vmbase/src/bionic.rs
index 937105e..5af9ebc 100644
--- a/vmbase/src/bionic.rs
+++ b/vmbase/src/bionic.rs
@@ -42,11 +42,13 @@
 
 #[no_mangle]
 unsafe extern "C" fn __errno() -> *mut c_int {
-    &mut ERRNO as *mut _
+    // SAFETY: C functions which call this are only called from the main thread, not from exception
+    // handlers.
+    unsafe { &mut ERRNO as *mut _ }
 }
 
 fn set_errno(value: c_int) {
-    // SAFETY - vmbase is currently single-threaded.
+    // SAFETY: vmbase is currently single-threaded.
     unsafe { ERRNO = value };
 }
 
@@ -54,15 +56,15 @@
 ///
 /// # Safety
 ///
-/// Input strings `prefix` and `format` must be properly NULL-terminated.
+/// Input strings `prefix` and `format` must be valid and properly NUL-terminated.
 ///
 /// # Note
 ///
 /// This Rust functions is missing the last argument of its C/C++ counterpart, a va_list.
 #[no_mangle]
 unsafe extern "C" fn async_safe_fatal_va_list(prefix: *const c_char, format: *const c_char) {
-    let prefix = CStr::from_ptr(prefix);
-    let format = CStr::from_ptr(format);
+    // SAFETY: The caller guaranteed that both strings were valid and NUL-terminated.
+    let (prefix, format) = unsafe { (CStr::from_ptr(prefix), CStr::from_ptr(format)) };
 
     if let (Ok(prefix), Ok(format)) = (prefix.to_str(), format.to_str()) {
         // We don't bother with printf formatting.
@@ -96,7 +98,7 @@
 
 #[no_mangle]
 extern "C" fn fputs(c_str: *const c_char, stream: usize) -> c_int {
-    // SAFETY - Just like libc, we need to assume that `s` is a valid NULL-terminated string.
+    // SAFETY: Just like libc, we need to assume that `s` is a valid NULL-terminated string.
     let c_str = unsafe { CStr::from_ptr(c_str) };
 
     if let (Ok(s), Ok(_)) = (c_str.to_str(), File::try_from(stream)) {
@@ -112,7 +114,7 @@
 extern "C" fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: usize) -> usize {
     let length = size.saturating_mul(nmemb);
 
-    // SAFETY - Just like libc, we need to assume that `ptr` is valid.
+    // SAFETY: Just like libc, we need to assume that `ptr` is valid.
     let bytes = unsafe { slice::from_raw_parts(ptr as *const u8, length) };
 
     if let (Ok(s), Ok(_)) = (str::from_utf8(bytes), File::try_from(stream)) {
diff --git a/vmbase/src/console.rs b/vmbase/src/console.rs
index 7c8ddf6..f94feba 100644
--- a/vmbase/src/console.rs
+++ b/vmbase/src/console.rs
@@ -25,7 +25,7 @@
 
 /// 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
+    // SAFETY: BASE_ADDRESS is the base of the MMIO region for a UART and is mapped as device
     // memory.
     unsafe { Uart::new(BASE_ADDRESS) }
 }
diff --git a/vmbase/src/entry.rs b/vmbase/src/entry.rs
index df0bb7c..0a96d86 100644
--- a/vmbase/src/entry.rs
+++ b/vmbase/src/entry.rs
@@ -19,9 +19,11 @@
 /// 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(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
-    // SAFETY - Only called once, from here, and inaccessible to client code.
+    // SAFETY: Only called once, from here, and inaccessible to client code.
     unsafe { heap::init() };
     console::init();
+    // SAFETY: `main` is provided by the application using the `main!` macro, and we make sure it
+    // has the right type.
     unsafe {
         main(x0, x1, x2, x3);
     }
diff --git a/vmbase/src/heap.rs b/vmbase/src/heap.rs
index b00ca6f..c8b76ac 100644
--- a/vmbase/src/heap.rs
+++ b/vmbase/src/heap.rs
@@ -33,7 +33,7 @@
     ($len:expr) => {
         static mut __HEAP_ARRAY: [u8; $len] = [0; $len];
         #[export_name = "HEAP"]
-        // SAFETY - HEAP will only be accessed once as mut, from init().
+        // SAFETY: HEAP will only be accessed once as mut, from init().
         static mut __HEAP: &'static mut [u8] = unsafe { &mut __HEAP_ARRAY };
     };
 }
@@ -65,12 +65,12 @@
 pub fn aligned_boxed_slice(size: usize, align: usize) -> Option<Box<[u8]>> {
     let size = NonZeroUsize::new(size)?.get();
     let layout = Layout::from_size_align(size, align).ok()?;
-    // SAFETY - We verify that `size` and the returned `ptr` are non-null.
+    // SAFETY: We verify that `size` and the returned `ptr` are non-null.
     let ptr = unsafe { alloc(layout) };
     let ptr = NonNull::new(ptr)?.as_ptr();
     let slice_ptr = ptr::slice_from_raw_parts_mut(ptr, size);
 
-    // SAFETY - The memory was allocated using the proper layout by our global_allocator.
+    // SAFETY: The memory was allocated using the proper layout by our global_allocator.
     Some(unsafe { Box::from_raw(slice_ptr) })
 }
 
@@ -100,9 +100,9 @@
         heap_range.contains(&(ptr.as_ptr() as *const u8)),
         "free() called on a pointer that is not part of the HEAP: {ptr:?}"
     );
+    // SAFETY: ptr is non-null and was allocated by allocate, which prepends a correctly aligned
+    // usize.
     let (ptr, size) = unsafe {
-        // SAFETY: ptr is non-null and was allocated by allocate, which prepends a correctly aligned
-        // usize.
         let ptr = ptr.cast::<usize>().as_ptr().offset(-1);
         (ptr, *ptr)
     };
diff --git a/vmbase/src/layout/mod.rs b/vmbase/src/layout/mod.rs
index 00d7f9a..b8021b7 100644
--- a/vmbase/src/layout/mod.rs
+++ b/vmbase/src/layout/mod.rs
@@ -28,6 +28,8 @@
 #[macro_export]
 macro_rules! linker_addr {
     ($symbol:ident) => {{
+        // SAFETY: We're just getting the address of an extern static symbol provided by the linker,
+        // not dereferencing it.
         unsafe { addr_of!($crate::linker::$symbol) as usize }
     }};
 }
diff --git a/vmbase/src/lib.rs b/vmbase/src/lib.rs
index 7e47968..e490faa 100644
--- a/vmbase/src/lib.rs
+++ b/vmbase/src/lib.rs
@@ -15,6 +15,8 @@
 //! Basic functionality for bare-metal binaries to run in a VM under crosvm.
 
 #![no_std]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![deny(clippy::undocumented_unsafe_blocks)]
 
 extern crate alloc;
 
diff --git a/vmbase/src/memory/dbm.rs b/vmbase/src/memory/dbm.rs
index d429b30..401022e 100644
--- a/vmbase/src/memory/dbm.rs
+++ b/vmbase/src/memory/dbm.rs
@@ -34,7 +34,7 @@
     } else {
         tcr &= !TCR_EL1_HA_HD_BITS
     };
-    // Safe because it writes to a system register and does not affect Rust.
+    // SAFETY: Changing this bit in TCR doesn't affect Rust's view of memory.
     unsafe { write_sysreg!("tcr_el1", tcr) }
     isb!();
 }
diff --git a/vmbase/src/memory/shared.rs b/vmbase/src/memory/shared.rs
index 61cbeb0..4a75b97 100644
--- a/vmbase/src/memory/shared.rs
+++ b/vmbase/src/memory/shared.rs
@@ -69,6 +69,8 @@
     payload_range: Option<MemoryRange>,
 }
 
+// TODO: Remove this once aarch64-paging crate is updated.
+// SAFETY: Only `PageTable` doesn't implement Send, but it should.
 unsafe impl Send for MemoryTracker {}
 
 impl MemoryTracker {
@@ -93,7 +95,7 @@
         set_dbm_enabled(true);
 
         debug!("Activating dynamic page table...");
-        // SAFETY - page_table duplicates the static mappings for everything that the Rust code is
+        // SAFETY: page_table duplicates the static mappings for everything that the Rust code is
         // aware of so activating it shouldn't have any visible effect.
         unsafe { page_table.activate() }
         debug!("... Success!");
@@ -368,7 +370,7 @@
     fn refill(&mut self, pool: &mut FrameAllocator<32>, hint: Layout) {
         let layout = hint.align_to(self.granule).unwrap().pad_to_align();
         assert_ne!(layout.size(), 0);
-        // SAFETY - layout has non-zero size.
+        // SAFETY: layout has non-zero size.
         let Some(shared) = NonNull::new(unsafe { alloc_zeroed(layout) }) else {
             handle_alloc_error(layout);
         };
@@ -396,7 +398,7 @@
                 get_hypervisor().mem_unshare(virt_to_phys(vaddr).try_into().unwrap()).unwrap();
             }
 
-            // SAFETY - The region was obtained from alloc_zeroed() with the recorded layout.
+            // SAFETY: The region was obtained from alloc_zeroed() with the recorded layout.
             unsafe { dealloc(base as *mut _, layout) };
         }
     }
diff --git a/vmbase/src/memory/util.rs b/vmbase/src/memory/util.rs
index b9ef5c9..48d4c55 100644
--- a/vmbase/src/memory/util.rs
+++ b/vmbase/src/memory/util.rs
@@ -55,7 +55,7 @@
     let start = unchecked_align_down(start, line_size);
 
     for line in (start..end).step_by(line_size) {
-        // SAFETY - Clearing cache lines shouldn't have Rust-visible side effects.
+        // SAFETY: Clearing cache lines shouldn't have Rust-visible side effects.
         unsafe {
             asm!(
                 "dc cvau, {x}",
diff --git a/vmbase/src/rand.rs b/vmbase/src/rand.rs
index 00567b8..26fb51a 100644
--- a/vmbase/src/rand.rs
+++ b/vmbase/src/rand.rs
@@ -114,7 +114,7 @@
 
 #[no_mangle]
 extern "C" fn CRYPTO_sysrand(out: *mut u8, req: usize) {
-    // SAFETY - We need to assume that out points to valid memory of size req.
+    // SAFETY: We need to assume that out points to valid memory of size req.
     let s = unsafe { core::slice::from_raw_parts_mut(out, req) };
     fill_with_entropy(s).unwrap()
 }
diff --git a/vmbase/src/uart.rs b/vmbase/src/uart.rs
index 0fc2494..09d747f 100644
--- a/vmbase/src/uart.rs
+++ b/vmbase/src/uart.rs
@@ -38,8 +38,8 @@
 
     /// 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.
+        // SAFETY: We know that the base address points to the control registers of a UART device
+        // which is appropriately mapped.
         unsafe {
             write_volatile(self.base_address, byte);
         }
@@ -55,5 +55,5 @@
     }
 }
 
-// Safe because it just contains a pointer to device memory, which can be accessed from any context.
+// SAFETY: `Uart` just contains a pointer to device memory, which can be accessed from any context.
 unsafe impl Send for Uart {}
diff --git a/vmbase/src/virtio/hal.rs b/vmbase/src/virtio/hal.rs
index 36f9e56..51ac6ba 100644
--- a/vmbase/src/virtio/hal.rs
+++ b/vmbase/src/virtio/hal.rs
@@ -32,10 +32,8 @@
 /// HAL implementation for the virtio_drivers crate.
 pub struct HalImpl;
 
-/// # Safety
-///
-/// See the 'Implementation Safety' comments on methods below for how they fulfill the safety
-/// requirements of the unsafe `Hal` trait.
+/// SAFETY: See the 'Implementation Safety' comments on methods below for how they fulfill the
+/// safety requirements of the unsafe `Hal` trait.
 unsafe impl Hal for HalImpl {
     /// # Implementation Safety
     ///
@@ -48,14 +46,14 @@
         let layout = dma_layout(pages);
         let vaddr =
             alloc_shared(layout).expect("Failed to allocate and share VirtIO DMA range with host");
-        // SAFETY - vaddr points to a region allocated for the caller so is safe to access.
+        // SAFETY: vaddr points to a region allocated for the caller so is safe to access.
         unsafe { core::ptr::write_bytes(vaddr.as_ptr(), 0, layout.size()) };
         let paddr = virt_to_phys(vaddr);
         (paddr, vaddr)
     }
 
     unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull<u8>, pages: usize) -> i32 {
-        // SAFETY - Memory was allocated by `dma_alloc` using `alloc_shared` with the same layout.
+        // SAFETY: Memory was allocated by `dma_alloc` using `alloc_shared` with the same layout.
         unsafe { dealloc_shared(vaddr, dma_layout(pages)) }
             .expect("Failed to unshare VirtIO DMA range with host");
         0
@@ -96,7 +94,7 @@
         if direction == BufferDirection::DriverToDevice {
             let src = buffer.cast::<u8>().as_ptr().cast_const();
             trace!("VirtIO bounce buffer at {bounce:?} (PA:{paddr:#x}) initialized from {src:?}");
-            // SAFETY - Both regions are valid, properly aligned, and don't overlap.
+            // SAFETY: Both regions are valid, properly aligned, and don't overlap.
             unsafe { copy_nonoverlapping(src, bounce.as_ptr(), size) };
         }
 
@@ -109,11 +107,11 @@
         if direction == BufferDirection::DeviceToDriver {
             let dest = buffer.cast::<u8>().as_ptr();
             trace!("VirtIO bounce buffer at {bounce:?} (PA:{paddr:#x}) copied back to {dest:?}");
-            // SAFETY - Both regions are valid, properly aligned, and don't overlap.
+            // SAFETY: Both regions are valid, properly aligned, and don't overlap.
             unsafe { copy_nonoverlapping(bounce.as_ptr(), dest, size) };
         }
 
-        // SAFETY - Memory was allocated by `share` using `alloc_shared` with the same layout.
+        // SAFETY: Memory was allocated by `share` using `alloc_shared` with the same layout.
         unsafe { dealloc_shared(bounce, bb_layout(size)) }
             .expect("Failed to unshare and deallocate VirtIO bounce buffer");
     }