1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Partition side of the ARINC 653 Linux hypervisor
//!
//! This crate is a library, implementing and providing the ARINC 653 API meant
//! to be used from within a partition running on the Linux hypervisor.

#![deny(dead_code)]

#[macro_use]
extern crate log;

#[cfg(feature = "socket")]
use std::net::{TcpStream, UdpSocket};
#[cfg(feature = "socket")]
use std::os::fd::FromRawFd;

#[cfg(feature = "socket")]
use a653rs_linux_core::ipc::IoReceiver;

use std::os::fd::{AsRawFd, OwnedFd};
use std::sync::Arc;
use std::time::{Duration, Instant};

use a653rs::prelude::OperatingMode;
use a653rs_linux_core::file::{get_memfd, TempFile};
use a653rs_linux_core::health_event::PartitionCall;
use a653rs_linux_core::ipc::{self, IpcSender};
use a653rs_linux_core::partition::*;
use a653rs_linux_core::syscall::SYSCALL_SOCKET_PATH;
use nix::sys::socket::{self, connect, AddressFamily, SockFlag, SockType, UnixAddr};
use once_cell::sync::{Lazy, OnceCell};
use process::Process;
use tinyvec::ArrayVec;

pub mod apex;
pub mod partition;
pub mod syscall;
//mod scheduler;
pub(crate) mod process;

const SAMPLING_PORTS_FILE: &str = "sampling_channels";
// const MAX_SAMPLING_PORTS: usize = 32;
const QUEUING_PORTS_FILE: &str = "queuing_channels";

pub(crate) static CONSTANTS: Lazy<PartitionConstants> =
    Lazy::new(|| PartitionConstants::open().unwrap());

pub(crate) static SYSTEM_TIME: Lazy<Instant> = Lazy::new(|| {
    TempFile::<Instant>::try_from(CONSTANTS.start_time_fd)
        .unwrap()
        .read()
        .unwrap()
});

pub(crate) static PARTITION_MODE: Lazy<TempFile<OperatingMode>> =
    Lazy::new(|| TempFile::<OperatingMode>::try_from(CONSTANTS.partition_mode_fd).unwrap());

pub(crate) static PERIODIC_PROCESS: OnceCell<Arc<Process>> = OnceCell::new();
pub(crate) static APERIODIC_PROCESS: OnceCell<Arc<Process>> = OnceCell::new();

pub(crate) type SamplingPortsType = (usize, Duration);
pub(crate) static SAMPLING_PORTS: Lazy<TempFile<ArrayVec<[SamplingPortsType; 32]>>> =
    Lazy::new(|| {
        if let Ok(fd) = get_memfd(SAMPLING_PORTS_FILE) {
            TempFile::try_from(fd).unwrap()
        } else {
            let file = TempFile::create(SAMPLING_PORTS_FILE).unwrap();
            file.write(&Default::default()).unwrap();
            file
        }
    });

pub(crate) type QueuingPortsType = usize;
pub(crate) static QUEUING_PORTS: Lazy<TempFile<ArrayVec<[QueuingPortsType; 32]>>> =
    Lazy::new(|| {
        if let Ok(fd) = get_memfd(QUEUING_PORTS_FILE) {
            TempFile::try_from(fd).unwrap()
        } else {
            let file = TempFile::create(QUEUING_PORTS_FILE).unwrap();
            file.write(&Default::default()).unwrap();
            file
        }
    });

pub(crate) static SENDER: Lazy<IpcSender<PartitionCall>> =
    Lazy::new(|| ipc::connect_sender(PartitionConstants::IPC_SENDER.as_ref()).unwrap());

#[cfg(feature = "socket")]
pub(crate) static UDP_IO_RX: Lazy<IoReceiver<UdpSocket>> =
    Lazy::new(|| unsafe { IoReceiver::<UdpSocket>::from_raw_fd(CONSTANTS.io_fd) });

#[cfg(feature = "socket")]
pub(crate) static TCP_IO_RX: Lazy<IoReceiver<TcpStream>> =
    Lazy::new(|| unsafe { IoReceiver::<TcpStream>::from_raw_fd(CONSTANTS.io_fd) });

pub(crate) static SYSCALL: Lazy<OwnedFd> = Lazy::new(|| {
    let syscall_socket = socket::socket(
        AddressFamily::Unix,
        SockType::Datagram,
        SockFlag::empty(),
        None,
    )
    .unwrap();

    connect(
        syscall_socket.as_raw_fd(),
        &UnixAddr::new(SYSCALL_SOCKET_PATH).unwrap(),
    )
    .unwrap();

    syscall_socket
});

#[cfg(feature = "socket")]
pub(crate) static UDP_SOCKETS: Lazy<Vec<UdpSocket>> = Lazy::new(|| receive_sockets(&UDP_IO_RX));

#[cfg(feature = "socket")]
pub(crate) static TCP_SOCKETS: Lazy<Vec<TcpStream>> = Lazy::new(|| receive_sockets(&TCP_IO_RX));

/// Receives sockets from the hypervisor.
/// Will panic if an error occurs while receiving the file descriptors of the
/// sockets.
#[cfg(feature = "socket")]
fn receive_sockets<T: FromRawFd>(receiver: &IoReceiver<T>) -> Vec<T> {
    let mut sockets: Vec<T> = Vec::default();
    loop {
        match unsafe { receiver.try_receive() } {
            Ok(i) => {
                if let Some(i) = i {
                    sockets.push(i);
                } else {
                    return sockets;
                }
            }
            Err(e) => panic!("Could not receive sockets from hypervisor: {e:?}"),
        }
    }
}