mailbox_hal: revise mailbox protocol

Pages attached to a mailbox msg were used to send+recv large msg data but
that's not where they are needed. Instead treat them as an attachment
to the msg that is available for bulk data transfer in addition to the
rpc msg.

To that end the first word sent through the FIFO is still the message
size (bytes). If that word is tagged with HEADER_FLAG_LONG_MESSAGE
then a second word is read from the FIFO with the physical address of
the associated page. The page information is available through a new
get_message_page() method.

While here fix a bug in send_message_sync() whereby a partial last word
was not sent. This bug exists in get_message_sync() too, but will defer
the fix as the SecurityCoordinator currently always send word-aligned data.

Bug: 294433731

Change-Id: I4b89faecc999c2dbc3a1d4beafba0b3411b039ad
diff --git a/hal/src/mailbox_hal.rs b/hal/src/mailbox_hal.rs
index f28a76f..07fa29a 100644
--- a/hal/src/mailbox_hal.rs
+++ b/hal/src/mailbox_hal.rs
@@ -67,6 +67,7 @@
 //------------------------------------------------------------------------------
 
 pub trait MailboxHAL {
+    fn get_message_page(&self) -> Option<u32>;
     fn get_message_sync(&self, buf: &mut [u8]) -> Result<usize, usize>;
     fn send_message_sync(&self, message_size: usize, buf: &[u8]) -> Result<usize, usize>;
     fn get_message_slice_sync(&self, slice: &AppSlice<Shared, u8>) -> Result<usize, usize>;
@@ -94,9 +95,8 @@
     // Client interrupt callback
     client_isr: Cell<Option<&'static dyn MailboxISR>>,
 
-    // Physical address of the memory page used to send the last message, if it
-    // was a long message.
-    message_page: Cell<u32>,
+    // Physical address of any page associated with the last message.
+    message_page: Cell<Option<u32>>,
 }
 
 //------------------------------------------------------------------------------
@@ -109,7 +109,7 @@
             rtirq: rtirq,
             eirq: eirq,
             client_isr: Cell::new(None),
-            message_page: Cell::new(0),
+            message_page: Cell::new(None),
         };
 
         // Clear any old interrupts and enable receive and error interrupts.
@@ -180,57 +180,52 @@
 //------------------------------------------------------------------------------
 
 impl MailboxHAL for MailboxImpl {
+    fn get_message_page(&self) -> Option<u32> {
+        self.message_page.get()
+    }
+
     fn get_message_sync(&self, buf: &mut [u8]) -> Result<usize, usize> {
         let header = self.dequeue_u32();
-        let message_size = header & !HEADER_FLAG_LONG_MESSAGE;
-
         if (header & HEADER_FLAG_LONG_MESSAGE) != 0 {
-            // Long message, copy from message page to result buffer.
-            let message_page = self.dequeue_u32();
-            self.message_page.set(message_page);
-            unsafe {
-                let src: *const u8 = transmute(message_page);
-                let dst: *mut u8 = transmute(buf.as_ptr());
-                core::ptr::copy_nonoverlapping(src, dst, message_size as usize);
-            }
-        } else {
-            // Short message, copy from mailbox to result buffer.
-            unsafe {
-                let dst: *mut u32 = transmute(buf.as_ptr());
-                let message_dwords = message_size / 4;
-                for i in 0..message_dwords {
-                    dst.offset(i as isize).write(self.dequeue_u32());
-                }
+            let page = self.dequeue_u32();
+            self.message_page.set(Some(page));
+        }
+        // Copy from the FIFO to the result buffer.
+        let message_size = header & !HEADER_FLAG_LONG_MESSAGE;
+        unsafe {
+            let dst: *mut u32 = transmute(buf.as_ptr());
+            let message_dwords = message_size / 4;
+            for i in 0..message_dwords {
+                dst.add(i as usize).write(self.dequeue_u32());
             }
         }
         return Ok(message_size as usize);
     }
 
     fn send_message_sync(&self, message_size: usize, buf: &[u8]) -> Result<usize, usize> {
+        self.message_page.set(None);
         unsafe {
-            let message_page = self.message_page.get();
-            if message_page != 0 {
-                // Long message, reply using the same physical page as the request.
-                let src: *const u8 = transmute(buf.as_ptr());
-                let dst: *mut u8 = transmute(message_page);
-                core::ptr::copy_nonoverlapping(src, dst, message_size);
+            self.enqueue_u32(message_size as u32);
 
-                self.enqueue_u32(0x80000000 | message_size as u32);
-                self.enqueue_u32(message_page);
-
-                // Response sent, clear cached page address
-                self.message_page.set(0);
-            } else {
-                // Short message, respond via the mailbox.
-                let src: *const u32 = transmute(buf.as_ptr());
-                let message_dwords = message_size / 4;
-                self.enqueue_u32(message_size as u32);
-                for i in 0..message_dwords {
-                    self.enqueue_u32(src.offset(i as isize).read());
+            // Copy the reply to the FIFO.
+            let src: *const u32 = transmute(buf.as_ptr());
+            let message_dwords = message_size / 4;
+            for i in 0..message_dwords {
+                self.enqueue_u32(src.add(i).read());
+            }
+            let remainder = message_size - (4 * message_dwords);
+            if remainder > 0 {
+                // XXX check native byte order
+                let mut word: u32 = buf[message_size - 1] as u32;
+                if remainder > 1 {
+                    word = (word << 8) | (buf[message_size - 2] as u32);
                 }
+                if remainder > 2 {
+                    word = (word << 8) | (buf[message_size - 3] as u32);
+                }
+                self.enqueue_u32(word);
             }
         }
-
         return Ok(message_size);
     }