tfhe_hpu_backend/ffi/sim/
ipc.rs

1//! IPC interface and associated Commands
2
3use ipc_channel::ipc::{self, IpcOneShotServer, IpcReceiver, IpcSender};
4use std::fs::OpenOptions;
5use std::io::{BufRead, BufReader, Write};
6use std::path::Path;
7use std::sync::{Arc, Mutex};
8
9use serde::{Deserialize, Serialize};
10
11use crate::entities::HpuPBSParameters;
12use crate::ffi::{self, SyncMode};
13
14/// Register request
15#[derive(Debug, Serialize, Deserialize)]
16pub enum RegisterReq {
17    Read { addr: u64 },
18    Write { addr: u64, value: u32 },
19    PbsParams,
20}
21
22/// Register acknowledgment
23#[derive(Debug, Serialize, Deserialize)]
24pub enum RegisterAck {
25    Read(u32),
26    Write,
27    PbsParams(HpuPBSParameters),
28}
29
30/// FFI side of IPC channel used for Register xfer
31#[derive(Debug, Serialize, Deserialize)]
32pub(crate) struct RegisterFfi {
33    pub(crate) req: IpcSender<RegisterReq>,
34    pub(crate) ack: IpcReceiver<RegisterAck>,
35}
36/// Sim side of IPC channel used for Register xfer
37#[derive(Debug, Serialize, Deserialize)]
38pub struct RegisterSim {
39    pub req: IpcReceiver<RegisterReq>,
40    pub ack: IpcSender<RegisterAck>,
41}
42
43pub(crate) fn register_channel() -> (RegisterFfi, RegisterSim) {
44    let (req_tx, req_rx) = ipc::channel().unwrap();
45    let (ack_tx, ack_rx) = ipc::channel().unwrap();
46
47    (
48        RegisterFfi {
49            req: req_tx,
50            ack: ack_rx,
51        },
52        RegisterSim {
53            req: req_rx,
54            ack: ack_tx,
55        },
56    )
57}
58
59/// Memory request
60#[derive(Debug, Serialize, Deserialize)]
61pub enum MemoryReq {
62    Allocate {
63        mem_kind: ffi::MemKind,
64        size_b: usize,
65    },
66    Sync {
67        mem_kind: ffi::MemKind,
68        addr: u64,
69        mode: SyncMode,
70        data: Option<ipc::IpcSharedMemory>,
71    },
72    Release {
73        mem_kind: ffi::MemKind,
74        addr: u64,
75    },
76}
77
78/// Memory acknowledgment
79#[derive(Debug, Serialize, Deserialize)]
80pub enum MemoryAck {
81    Allocate { addr: u64 },
82    Sync { data: Option<ipc::IpcSharedMemory> },
83    Release,
84}
85
86/// FFI side of IPC channel used for Memory xfer
87#[derive(Debug, Serialize, Deserialize)]
88pub(crate) struct MemoryFfi {
89    pub(crate) req: IpcSender<MemoryReq>,
90    pub(crate) ack: IpcReceiver<MemoryAck>,
91}
92/// FFI memory wrapped in an Arc<Mutex<_>>
93/// Indeed, this object must be shared with all MemZone to enable proper sync
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub(crate) struct MemoryFfiWrapped(pub(crate) Arc<Mutex<MemoryFfi>>);
96
97impl From<MemoryFfi> for MemoryFfiWrapped {
98    fn from(value: MemoryFfi) -> Self {
99        Self(Arc::new(Mutex::new(value)))
100    }
101}
102
103/// Sim side of IPC channel used for Memory xfer
104#[derive(Debug, Serialize, Deserialize)]
105pub struct MemorySim {
106    pub req: IpcReceiver<MemoryReq>,
107    pub ack: IpcSender<MemoryAck>,
108}
109
110pub(crate) fn memory_channel() -> (MemoryFfi, MemorySim) {
111    let (req_tx, req_rx) = ipc::channel().unwrap();
112    let (ack_tx, ack_rx) = ipc::channel().unwrap();
113
114    (
115        MemoryFfi {
116            req: req_tx,
117            ack: ack_rx,
118        },
119        MemorySim {
120            req: req_rx,
121            ack: ack_tx,
122        },
123    )
124}
125
126/// FFI side of IPC channel used for Memory xfer
127/// Gather Register/Memory interface together to easily exchange them across OneShot server
128#[derive(Debug, Serialize, Deserialize)]
129pub(crate) struct IpcFfi {
130    pub(crate) register: RegisterFfi,
131    pub(crate) memory: MemoryFfiWrapped,
132}
133
134impl IpcFfi {
135    /// Create IPC binding for Register and Memory interface
136    /// Use a named file to retrieved the OneShot IPC channel that enable to exchange
137    /// typed ipc_channels
138    pub fn new_bind_on(ipc_name: &str) -> IpcFfi {
139        // Open file
140        let mut rd_f = BufReader::new(
141            OpenOptions::new()
142                .create(false)
143                .read(true)
144                .open(ipc_name)
145                .unwrap(),
146        );
147        // Read name of the targeted oneshot channel
148        let oneshot_name = {
149            let mut name = String::new();
150            rd_f.read_line(&mut name).unwrap();
151            name
152        };
153        tracing::debug!("Will bind through {oneshot_name}");
154
155        // Connect to the oneshot channel
156        let bind_tx = IpcSender::connect(oneshot_name).unwrap();
157
158        // Generate ipc channel and send Sim side through oneshot
159        let (ffi, sim) = ipc_channel();
160        bind_tx.send(sim).unwrap();
161
162        ffi
163    }
164}
165
166#[derive(Debug, Serialize, Deserialize)]
167pub struct IpcSim {
168    pub register: RegisterSim,
169    pub memory: MemorySim,
170}
171impl IpcSim {
172    /// Create IPC Oneshot server and wait for endpoint
173    pub fn new_bind_on(ipc_name: &str) -> IpcSim {
174        // Create one shot channel
175        let (oneshot_server, oneshot_name) = IpcOneShotServer::new().unwrap();
176        // Register it into {ipc_name} file
177        // Create folder if needed
178        let path = Path::new(ipc_name);
179        if let Some(dir_p) = path.parent() {
180            std::fs::create_dir_all(dir_p).unwrap();
181        }
182        // Open file
183        let mut wr_f = OpenOptions::new()
184            .create(true)
185            .write(true)
186            .truncate(true)
187            .open(ipc_name)
188            .unwrap();
189        write!(wr_f, "{oneshot_name}").unwrap();
190
191        tracing::info!("Mockup waiting on IPC `{oneshot_name}`");
192        let (_, ipc_sim): (_, IpcSim) = oneshot_server.accept().unwrap();
193
194        ipc_sim
195    }
196}
197
198pub(crate) fn ipc_channel() -> (IpcFfi, IpcSim) {
199    let (register_ffi, register_sim) = register_channel();
200    let (memory_ffi, memory_sim) = memory_channel();
201
202    (
203        IpcFfi {
204            register: register_ffi,
205            memory: MemoryFfiWrapped::from(memory_ffi),
206        },
207        IpcSim {
208            register: register_sim,
209            memory: memory_sim,
210        },
211    )
212}