[pvmfw] Move utility functions/consts relating to memory to vmbase
This cl moves some utility functions and constants relating to
memory aligment computation from pvmfw to vmbase for reuse in
rialto in the future.
No behavior change in this cl.
Bug: 284462758
Test: m pvmfw_img
Change-Id: I0ac7350c884ff00dd9379f736e9245aa39ed0b7a
diff --git a/vmbase/src/lib.rs b/vmbase/src/lib.rs
index 2541b8a..80cdf4e 100644
--- a/vmbase/src/lib.rs
+++ b/vmbase/src/lib.rs
@@ -28,6 +28,7 @@
pub mod memory;
pub mod power;
pub mod uart;
+pub mod util;
pub use bionic::STACK_CHK_GUARD;
diff --git a/vmbase/src/memory/mod.rs b/vmbase/src/memory/mod.rs
index 5e1065a..3b1b384 100644
--- a/vmbase/src/memory/mod.rs
+++ b/vmbase/src/memory/mod.rs
@@ -22,4 +22,4 @@
pub use dbm::set_dbm_enabled;
pub use page_table::{PageTable, MMIO_LAZY_MAP_FLAG};
pub use shared::MemorySharer;
-pub use util::{phys_to_virt, virt_to_phys};
+pub use util::{page_4kb_of, phys_to_virt, virt_to_phys, SIZE_2MB, SIZE_4KB, SIZE_4MB};
diff --git a/vmbase/src/memory/util.rs b/vmbase/src/memory/util.rs
index 5b89cd1..3186409 100644
--- a/vmbase/src/memory/util.rs
+++ b/vmbase/src/memory/util.rs
@@ -14,8 +14,21 @@
//! Utility functions for memory management.
+use crate::util::unchecked_align_down;
use core::ptr::NonNull;
+/// The size of a 4KB memory in bytes.
+pub const SIZE_4KB: usize = 4 << 10;
+/// The size of a 2MB memory in bytes.
+pub const SIZE_2MB: usize = 2 << 20;
+/// The size of a 4MB memory in bytes.
+pub const SIZE_4MB: usize = 4 << 20;
+
+/// Computes the address of the 4KiB page containing a given address.
+pub const fn page_4kb_of(addr: usize) -> usize {
+ unchecked_align_down(addr, SIZE_4KB)
+}
+
/// Returns the intermediate physical address corresponding to the given virtual address.
///
/// As we use identity mapping for everything, this is just a cast, but it's useful to use it to be
diff --git a/vmbase/src/util.rs b/vmbase/src/util.rs
new file mode 100644
index 0000000..7396edc
--- /dev/null
+++ b/vmbase/src/util.rs
@@ -0,0 +1,72 @@
+// Copyright 2023, 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.
+
+//! Utility functions.
+
+/// Flatten [[T; N]] into &[T]
+/// TODO: use slice::flatten when it graduates from experimental
+pub fn flatten<T, const N: usize>(original: &[[T; N]]) -> &[T] {
+ // SAFETY: no overflow because original (whose size is len()*N) is already in memory
+ let len = original.len() * N;
+ // SAFETY: [T] has the same layout as [T;N]
+ unsafe { core::slice::from_raw_parts(original.as_ptr().cast(), len) }
+}
+
+/// Computes the largest multiple of the provided alignment smaller or equal to the address.
+///
+/// Note: the result is undefined if alignment isn't a power of two.
+pub const fn unchecked_align_down(addr: usize, alignment: usize) -> usize {
+ addr & !(alignment - 1)
+}
+
+/// Computes the smallest multiple of the provided alignment larger or equal to the address.
+///
+/// Note: the result is undefined if alignment isn't a power of two and may wrap to 0.
+pub const fn unchecked_align_up(addr: usize, alignment: usize) -> usize {
+ unchecked_align_down(addr + alignment - 1, alignment)
+}
+
+/// Safe wrapper around unchecked_align_up() that validates its assumptions and doesn't wrap.
+pub const fn align_up(addr: usize, alignment: usize) -> Option<usize> {
+ if !alignment.is_power_of_two() {
+ None
+ } else if let Some(s) = addr.checked_add(alignment - 1) {
+ Some(unchecked_align_down(s, alignment))
+ } else {
+ None
+ }
+}
+
+/// Aligns the given address to the given alignment, if it is a power of two.
+///
+/// Returns `None` if the alignment isn't a power of two.
+#[allow(dead_code)] // Currently unused but might be needed again.
+const fn align_down(addr: usize, alignment: usize) -> Option<usize> {
+ if !alignment.is_power_of_two() {
+ None
+ } else {
+ Some(unchecked_align_down(addr, alignment))
+ }
+}
+
+/// Performs an integer division rounding up.
+///
+/// Note: Returns None if den isn't a power of two.
+pub const fn ceiling_div(num: usize, den: usize) -> Option<usize> {
+ let Some(r) = align_up(num, den) else {
+ return None;
+ };
+
+ r.checked_div(den)
+}