a653rs_linux/
lib.rs

1//! Partition side of the ARINC 653 Linux hypervisor
2//!
3//! This crate is a library, implementing and providing the ARINC 653 API meant
4//! to be used from within a partition running on the Linux hypervisor.
5
6#![deny(dead_code)]
7
8#[macro_use]
9extern crate log;
10
11#[cfg(feature = "socket")]
12use std::net::{TcpStream, UdpSocket};
13#[cfg(feature = "socket")]
14use std::os::fd::FromRawFd;
15
16#[cfg(feature = "socket")]
17use a653rs_linux_core::ipc::IoReceiver;
18
19use std::os::fd::{AsRawFd, OwnedFd};
20use std::sync::Arc;
21use std::time::{Duration, Instant};
22
23use a653rs::prelude::OperatingMode;
24use a653rs_linux_core::file::{get_memfd, TempFile};
25use a653rs_linux_core::health_event::PartitionCall;
26use a653rs_linux_core::ipc::{self, IpcSender};
27use a653rs_linux_core::partition::*;
28use a653rs_linux_core::syscall::SYSCALL_SOCKET_PATH;
29use nix::sys::socket::{self, connect, AddressFamily, SockFlag, SockType, UnixAddr};
30use once_cell::sync::{Lazy, OnceCell};
31use process::Process;
32use tinyvec::ArrayVec;
33
34pub mod apex;
35pub mod partition;
36pub mod syscall;
37//mod scheduler;
38pub(crate) mod process;
39
40const SAMPLING_PORTS_FILE: &str = "sampling_channels";
41// const MAX_SAMPLING_PORTS: usize = 32;
42const QUEUING_PORTS_FILE: &str = "queuing_channels";
43
44pub(crate) static CONSTANTS: Lazy<PartitionConstants> =
45    Lazy::new(|| PartitionConstants::open().unwrap());
46
47pub(crate) static SYSTEM_TIME: Lazy<Instant> = Lazy::new(|| {
48    TempFile::<Instant>::try_from(CONSTANTS.start_time_fd)
49        .unwrap()
50        .read()
51        .unwrap()
52});
53
54pub(crate) static PARTITION_MODE: Lazy<TempFile<OperatingMode>> =
55    Lazy::new(|| TempFile::<OperatingMode>::try_from(CONSTANTS.partition_mode_fd).unwrap());
56
57pub(crate) static PERIODIC_PROCESS: OnceCell<Arc<Process>> = OnceCell::new();
58pub(crate) static APERIODIC_PROCESS: OnceCell<Arc<Process>> = OnceCell::new();
59
60pub(crate) type SamplingPortsType = (usize, Duration);
61pub(crate) static SAMPLING_PORTS: Lazy<TempFile<ArrayVec<[SamplingPortsType; 32]>>> =
62    Lazy::new(|| {
63        if let Ok(fd) = get_memfd(SAMPLING_PORTS_FILE) {
64            TempFile::try_from(fd).unwrap()
65        } else {
66            let file = TempFile::create(SAMPLING_PORTS_FILE).unwrap();
67            file.write(&Default::default()).unwrap();
68            file
69        }
70    });
71
72pub(crate) type QueuingPortsType = usize;
73pub(crate) static QUEUING_PORTS: Lazy<TempFile<ArrayVec<[QueuingPortsType; 32]>>> =
74    Lazy::new(|| {
75        if let Ok(fd) = get_memfd(QUEUING_PORTS_FILE) {
76            TempFile::try_from(fd).unwrap()
77        } else {
78            let file = TempFile::create(QUEUING_PORTS_FILE).unwrap();
79            file.write(&Default::default()).unwrap();
80            file
81        }
82    });
83
84pub(crate) static SENDER: Lazy<IpcSender<PartitionCall>> =
85    Lazy::new(|| ipc::connect_sender(PartitionConstants::IPC_SENDER.as_ref()).unwrap());
86
87#[cfg(feature = "socket")]
88pub(crate) static UDP_IO_RX: Lazy<IoReceiver<UdpSocket>> =
89    Lazy::new(|| unsafe { IoReceiver::<UdpSocket>::from_raw_fd(CONSTANTS.udp_io_fd) });
90
91#[cfg(feature = "socket")]
92pub(crate) static TCP_IO_RX: Lazy<IoReceiver<TcpStream>> =
93    Lazy::new(|| unsafe { IoReceiver::<TcpStream>::from_raw_fd(CONSTANTS.tcp_io_fd) });
94
95pub(crate) static SYSCALL: Lazy<OwnedFd> = Lazy::new(|| {
96    let syscall_socket = socket::socket(
97        AddressFamily::Unix,
98        SockType::Datagram,
99        SockFlag::empty(),
100        None,
101    )
102    .unwrap();
103
104    connect(
105        syscall_socket.as_raw_fd(),
106        &UnixAddr::new(SYSCALL_SOCKET_PATH).unwrap(),
107    )
108    .unwrap();
109
110    syscall_socket
111});
112
113#[cfg(feature = "socket")]
114pub(crate) static UDP_SOCKETS: Lazy<Vec<UdpSocket>> = Lazy::new(|| receive_sockets(&UDP_IO_RX));
115
116#[cfg(feature = "socket")]
117pub(crate) static TCP_SOCKETS: Lazy<Vec<TcpStream>> = Lazy::new(|| receive_sockets(&TCP_IO_RX));
118
119/// Receives sockets from the hypervisor.
120/// Will panic if an error occurs while receiving the file descriptors of the
121/// sockets.
122#[cfg(feature = "socket")]
123fn receive_sockets<T: FromRawFd>(receiver: &IoReceiver<T>) -> Vec<T> {
124    let mut sockets: Vec<T> = Vec::default();
125    loop {
126        match unsafe { receiver.try_receive() } {
127            Ok(i) => {
128                if let Some(i) = i {
129                    sockets.push(i);
130                } else {
131                    return sockets;
132                }
133            }
134            Err(e) => panic!("Could not receive sockets from hypervisor: {e:?}"),
135        }
136    }
137}