Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  lib.rs

  Sprache: Rust
 

/*
 * Copyright (c) 2025 Google Inc. All rights reserved
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#![no_std]

use crate::sys::sm_vm_notifier_register;
use crate::sys::sm_vm_notifier_unregister;
use alloc::boxed::Box;
use core::cell::UnsafeCell;
use core::fmt;
use core::fmt::Debug;
use core::fmt::Formatter;
use core::mem::zeroed;
use core::mem::ManuallyDrop;
use core::ptr::null_mut;
use extmem::ext_mem_obj_id_t;
use rust_support::container_of;
use rust_support::list_node;
use rust_support::obj_ref;
use rust_support::status_t;
use rust_support::Error;

pub use crate::sys::sm_vm;
pub use crate::sys::sm_vm_del_ref;
pub use crate::sys::sm_vm_get;
pub use crate::sys::sm_vm_notifier;

mod sys {
    #![allow(unused)]
    #![allow(non_camel_case_types)]
    use extmem::ext_mem_obj_id_t;
    use rust_support::list_node;
    use rust_support::obj_ref;
    use rust_support::status_t;
    include!(env!("BINDGEN_INC_FILE"));
}

pub fn intc_raise_doorbell_irq() {
    // SAFETY: This function has no safety requirements and may be called from any context.
    unsafe {
        sys::sm_intc_raise_doorbell_irq();
    }
}

// Use repr(C) to ensure its layout is consistent between compilations to allow using
// container_of to cast from sm_vm_notifier pointers to VmNotifierInner pointers.
#[repr(C)]
struct VmNotifierInner {
    notif: sm_vm_notifier,
    // A rust-specific callback for VM destruction notification. The callback field in
    // sm_vm_notifier just reads the client ID and calls this function with it.
    destroy: VmDestroyCallback,
}

// Implement Debug manually since sm_vm_notifier contains a list_node which does not implement it.
// This impl omits the callback field in sm_vm_notifier since the rust bindings ensure it will
// always be the invoke_rust_callback function.
impl Debug for VmNotifierInner {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        f.debug_struct("VmNotifierInner")
            .field("client_id", &self.notif.client_id)
            .field("destroy", &self.destroy)
            .finish()
    }
}

// A notifier for invoking a callback when a VM is destroyed. This is boxed since sm_vm_notifier
// has a list_node field which must not move.
#[derive(Debug)]
pub struct VmNotifier(Box<VmNotifierInner>);

// SAFETY: VmNotifier provides no way to mutate it through a shared reference
unsafe impl Sync for VmNotifier {}

// SAFETY: VmNotifier only has a heap allocated field so it may be freely sent across threads
// without invalidating it.
unsafe impl Send for VmNotifier {}

// TODO: add Unpin as a negative trait bound once the rustc feature is stabilized.
// impl !Unpin for VmNotifier {}

pub type VmDestroyCallback = fn(ext_mem_obj_id_t) -> Result<(), Error>;

impl VmNotifier {
    /// Creates a destruction notifier for a VM with the given client ID.
    ///
    /// Unlike the C sm_vm_notifier interface, the destroy callback takes the client ID as its only
    /// argument and must be a safe function. Callers must also register and avoid dropping the
    /// VmNotifier to ensure Trusty will invoke it when the VM is destroyed.
    pub fn new(client_id: ext_mem_obj_id_t, destroy: VmDestroyCallback) -> Result<Self, Error> {
        // SAFETY: The c_notif argument must point to a sm_vm_notifier embedded in a VmNotifierInner
        // struct. The caller must ensure that the `notif.client_id` and `destroy` fields will not change
        // for the duration of this function.
        unsafe extern "C" fn invoke_rust_callback(c_notif: *mut sm_vm_notifier) -> status_t {
            // SAFETY: Safety delegated to caller.
            let client_id = unsafe { (*c_notif).client_id };
            // This cast is valid due to the layout of VmNotifierInner.
            // SAFETY: invoke_rust_callback's safety requirements ensure `c_notif` points to the
            // `notif` field in VmNotifierInner.
            let rust_notif = unsafe { container_of!(c_notif, VmNotifierInner, notif) };
            // SAFETY: Safety delegated to caller.
            let rust_callback = unsafe { (*rust_notif).destroy };
            let rc = rust_callback(client_id);
            match rc {
                Ok(()) => 0,
                Err(e) => status_t::from(e),
            }
        }
        let notif = sm_vm_notifier {
            node: list_node::default(),
            client_id,
            destroy: Some(invoke_rust_callback),
        };
        let rust_notif = Box::new(VmNotifierInner { notif, destroy });
        // TODO: Call sm_vm_notifier_init and assert it returns 0. That function currently only sets
        // fields and validates arguments like VmNotifier::new but we should use it instead of
        // relying on setting fields explicitly to avoid having to keep these two code paths in
        // sync. Using it currently triggers a linker error since it relies on bindgen's
        // --wrap-static-fns and we need to ensure the .o produced from that source file gets linked
        // into lk-crates.a
        // let rc = sm_vm_notifier_init(rust_notif.notif.get(), client_id, Some(invoke_rust_callback));
        // assert!(rc == 0);
        let mut res = Self(rust_notif);
        res.register()?;
        Ok(res)
    }

    fn register(&mut self) -> Result<(), Error> {
        // SAFETY: This makes Trusty call the C callback `invoke_rust_callback` when a VM is
        // destroyed. The safety requirements on it are that the argument is an sm_vm_notifier
        // embedded within a VmNotifierInner and that the `client_id` and `destroy` (rust
        // callback) fields do not change for the duration of that function. The former holds
        // because of the definition of the VmNotifier type. The latter two hold because VmNotifier
        // provides no way to change these fields after its initialized. The constructor also
        // ensures that `invoke_rust_callback` is always the unsafe function that will get called
        // when the VM is destroyed.
        let rc = unsafe { sm_vm_notifier_register(&raw mut self.0.notif) };
        Error::from_lk(rc)
    }

    pub fn unregister(self) -> Result<(), (Self, Error)> {
        // Skip dropping self to avoid calling sm_vm_notifier_unregister multiple times
        let mut rust_notif = ManuallyDrop::new(self);
        // SAFETY: This function removes the notifier its argument points to from the bst of VMs
        // preventing the C callback from being called. `unregister` takes `self` by value so only a
        // single thread may attempt to remove the notifier from the bst and there cannot be a race
        // condition. If the callback is already in progress this function will just wait for it to
        // finish and return NO_ERROR. If the callback has already been called it will just return
        // ERR_NOT_FOUND.
        let rc = unsafe { sm_vm_notifier_unregister(&raw mut rust_notif.0.notif) };
        if rc != 0 {
            return Error::from_lk(rc).map_err(|e| (ManuallyDrop::into_inner(rust_notif), e));
        }
        Ok(())
    }
}

impl Drop for VmNotifier {
    fn drop(&mut self) {
        // SAFETY: This function removes the notifier its argument points to from the bst of VMs
        // preventing the C callback from being called. Only a single thread may drop the notifier
        // so only a single thread may attempt to remove the notifier from the bst and there cannot
        // be a race condition. If the callback is already in progress it will just wait for it to
        // finish and return NO_ERROR. If the callback has already been called it will return
        // ERR_NOT_FOUND. Any other error code is unexpected so we panic since Drop doesn't allow
        // bubbling up an error to the caller.
        let rc = unsafe { sm_vm_notifier_unregister(&raw mut self.0.notif) };
        if rc != Error::NO_ERROR.0 && rc != Error::ERR_NOT_FOUND.0 {
            panic!("Failed to unregister VmNotifier");
        }
    }
}

#[derive(Debug)]
pub struct VmRef {
    vm_ptr: *mut sm_vm,
    // TODO: Remove the UnsafeCell when the box_as_ptr feature is stabilized
    // https://github.com/rust-lang/rust/issues/129090
    obj_ref_ptr: Box<UnsafeCell<obj_ref>>,
}

impl VmRef {
    pub fn new(client_id: ext_mem_obj_id_t) -> Result<Self, Error> {
        // sm_vm_get expects the caller to allocate memory for the struct obj_ref so we place it on
        // the heap to ensure it remains valid after VmRef::new returns
        // SAFETY: obj_ref is a C type with two pointers which can be zeroed.
        let obj_ref_init: obj_ref = unsafe { zeroed() };
        let boxed_obj_ref = Box::new(UnsafeCell::new(obj_ref_init));
        let mut vm_ptr: *mut sm_vm = null_mut();
        // Grab a reference to the VM by calling sm_vm_get
        // SAFETY: This function takes a non-null pointer to a struct obj_ref which may be
        // uninitialized and a pointer for the VM object. The struct obj_ref pointee has a fixed
        // address so the value it's initialized to remains valid after this function returns. The
        // pointer to the obj_ref that sm_vm_get stores also remains valid since it's boxed and
        // owned by the returned Self
        let rc = unsafe { sm_vm_get(client_id, boxed_obj_ref.get(), &raw mut vm_ptr) };
        Error::from_lk(rc)?;
        // If it succeeded store the out-parameters for when we want to release the VM reference
        Ok(Self { vm_ptr, obj_ref_ptr: boxed_obj_ref })
    }
}

impl Drop for VmRef {
    fn drop(&mut self) {
        // Release the reference
        // SAFETY: These pointers were initialized to valid values in VmRef::new and their pointees
        // remain valid for the lifetime of the VmRef since obj_ref is owned by the VmRef and libsm
        // will not deallocate the backing sm_vm struct while there are references to the VM.
        unsafe { sm_vm_del_ref(self.vm_ptr, self.obj_ref_ptr.get()) }
    }
}

// SAFETY: Both pointers in VmRef are heap allocated so it may freely be sent between threads. The
// thread which releases a refcount does not necessarily need to be same that grabbed it so its Drop
// impl is allowed to run in a different thread than the one that created it.
unsafe impl Send for VmRef {}

Messung V0.5 in Prozent
C=91 H=93 G=91

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik