blob: 33e8ece3b24ef7ca5ef268ba4520e6f01955c2d0 [file]
// Copyright 2021 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use super::{PageCache, PageList};
use core::ffi::c_int;
use core::mem::MaybeUninit;
use core::pin::Pin;
use zx_types::zx_status_t;
unsafe extern "C" {
pub(super) fn cpp_global_prng_draw(buffer: *mut u8, len: usize);
pub(super) fn rand_r(seed: *mut usize) -> c_int;
}
// C++ FFI entry points for `page_cache::PageCache` in `<lib/page_cache.h>`.
/// Initializes a `PageCache` in-place at `out_cache`.
#[unsafe(no_mangle)]
pub extern "C" fn rust_page_cache_create(
reserve_pages: usize,
out_cache: &mut MaybeUninit<PageCache>,
) -> zx_status_t {
match PageCache::new(reserve_pages) {
Ok(cache) => {
out_cache.write(cache);
zx_status::sys::ZX_OK
}
Err(status) => status.into_raw(),
}
}
/// Drops a `PageCache` in-place at `cache`.
///
/// # Safety
///
/// `cache` must point to a valid, initialized `PageCache` that has not yet been dropped.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_page_cache_destroy(cache: *mut PageCache) {
debug_assert!(!cache.is_null());
// SAFETY: Caller guarantees `cache` is a valid initialized `PageCache`.
unsafe {
core::ptr::drop_in_place(cache);
}
}
/// Seeds the random should-wait state for all per-CPU caches in `cache`.
#[unsafe(no_mangle)]
pub extern "C" fn rust_page_cache_seed_random_should_wait(cache: &PageCache) {
cache.seed_random_should_wait();
}
/// Allocates `page_count` pages from `cache` into `out_pages` and writes the
/// remaining available pages to `out_available_pages`.
///
/// # Safety
///
/// `out_pages` must be pinned in memory.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_page_cache_allocate(
cache: &PageCache,
page_count: usize,
alloc_flags: u32,
out_pages: &mut PageList,
out_available_pages: &mut usize,
) -> zx_status_t {
// SAFETY: Caller guarantees `out_pages` is pinned.
let out_pages = unsafe { Pin::new_unchecked(out_pages) };
match cache.allocate(page_count, alloc_flags, out_pages) {
Ok(available_pages) => {
*out_available_pages = available_pages;
zx_status::sys::ZX_OK
}
Err(status) => status.into_raw(),
}
}
/// Frees `page_list` into `cache`, returning any excess pages to the PMM.
///
/// # Safety
///
/// `page_list` must be pinned in memory.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust_page_cache_free(cache: &PageCache, page_list: &mut PageList) {
// SAFETY: Caller guarantees `page_list` is pinned.
let page_list = unsafe { Pin::new_unchecked(page_list) };
cache.free(page_list);
}