-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathserver.rs
285 lines (258 loc) · 9.67 KB
/
server.rs
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
//! IPC Server primitives
//!
//! The creation of an IPC server requires a WaitableManager and a PortHandler.
//! The WaitableManager will manage the event loop: it will wait for a request
//! to arrive on one of the waiters (or for any other event to happen), and call
//! that waiter's `handle_signal` function.
//!
//! A PortHandler is a type of Waiter which listens for incoming connections on
//! a port, creates a new Object from it, wrap it in a SessionWrapper (a kind of
//! waiter), and adds it to the WaitableManager's wait list.
//!
//! When a request comes to the Session, the SessionWrapper's handle_signaled
//! will call the dispatch function of its underlying object.
//!
//! Here's a very simple example server:
//!
//! ```
//! struct IExample;
//! object! {
//! impl IExample {
//! #[cmdid(0)]
//! fn hello(&mut self, ) -> Result<([u8; 5]), Error> {
//! Ok(b"hello")
//! }
//! }
//! }
//!
//! fn main() {
//! let man = WaitableManager::new();
//! let handler = Box::new(PortHandler::<IExample>::new("hello\0").unwrap());
//! man.add_waitable(handler as Box<dyn IWaitable>);
//! man.run()
//! }
//! ```
use crate::syscalls;
use crate::types::{HandleRef, ServerPort, ServerSession};
use core::marker::PhantomData;
use alloc::prelude::*;
use spin::Mutex;
use core::ops::{Deref, DerefMut, Index};
use core::fmt::{self, Debug};
use crate::error::Error;
use crate::ipc::Message;
/// A handle to a waitable object.
pub trait IWaitable: Debug {
/// Gets the handleref for use in the `wait_synchronization` call.
fn get_handle(&self) -> HandleRef<'_>;
/// Function the manager calls when this object gets signaled.
///
/// Takes the manager as a parameter, allowing the handler to add new handles
/// to the wait queue.
///
/// If the function returns false, remove it from the WaitableManager. If it
/// returns an error, log the error somewhere, and remove the handle from the
/// waitable manager.
fn handle_signaled(&mut self, manager: &WaitableManager) -> Result<bool, Error>;
}
/// The event loop manager. Waits on the waitable objects added to it.
#[derive(Debug, Default)]
pub struct WaitableManager {
/// Vector of items to add to the waitable list on the next loop.
to_add_waitables: Mutex<Vec<Box<dyn IWaitable>>>
}
impl WaitableManager {
/// Creates an empty waitable manager.
pub fn new() -> WaitableManager {
WaitableManager {
to_add_waitables: Mutex::new(Vec::new())
}
}
/// Add a new handle for the waitable manager to wait on.
pub fn add_waitable(&self, waitable: Box<dyn IWaitable>) {
self.to_add_waitables.lock().push(waitable);
}
/// Run the event loop. This will call wait_synchronization on all the
/// pending handles, and call handle_signaled on the handle that gets
/// signaled.
pub fn run(&self) -> ! {
let mut waitables = Vec::new();
loop {
{
let mut guard = self.to_add_waitables.lock();
for waitable in guard.drain(..) {
waitables.push(waitable);
}
}
let idx = {
let handles = waitables.iter().map(|v| v.get_handle()).collect::<Vec<HandleRef<'_>>>();
// TODO: new_waitable_event
syscalls::wait_synchronization(&*handles, None).unwrap()
};
match waitables[idx].handle_signaled(self) {
Ok(false) => (),
Ok(true) => { waitables.remove(idx); },
Err(err) => {
let _ = syscalls::output_debug_string(&format!("Error: {}", err));
waitables.remove(idx);
}
}
}
}
}
/// An IPC object.
///
/// Deriving this function manually is not recommended. Instead, users should use
/// the [object] macro to derive the Object implementation
/// from its external interface.
pub trait Object {
/// Handle a request with the given cmdid.
fn dispatch(&mut self, manager: &WaitableManager, cmdid: u32, buf: &mut [u8]) -> Result<(), Error>;
}
/// Wrapper struct that forces the alignment to 0x10. Somewhat necessary for the
/// IPC command buffer.
#[repr(C, align(16))]
#[derive(Debug)]
struct Align16<T>(T);
impl<T> Deref for Align16<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Align16<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T, Idx> Index<Idx> for Align16<T> where T: Index<Idx> {
type Output = T::Output;
fn index(&self, index: Idx) -> &T::Output {
&self.0[index]
}
}
/// A wrapper around an Object backed by an IPC Session that implements the
/// IWaitable trait.
pub struct SessionWrapper<T: Object> {
/// Kernel Handle backing this object.
handle: ServerSession,
/// Object instance.
object: T,
/// Command buffer for this session.
/// Ensure 16 bytes of alignment so the raw data is properly aligned.
buf: Align16<[u8; 0x100]>,
/// Buffer used for receiving type-X buffers and answering to type-C buffers.
// TODO: Pointer Buf should take its size as a generic parameter.
// BODY: The Pointer Buffer size should be configurable by the sysmodule.
// BODY: We'll wait for const generics to do it however, as otherwise we'd
// BODY: have to bend over backwards with typenum.
pointer_buf: [u8; 0x300]
}
impl<T: Object + Debug> Debug for SessionWrapper<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SessionWrapper")
.field("handle", &self.handle)
.field("object", &self.object)
.field("buf", &&self.buf[..])
.field("pointer_buf", &&self.pointer_buf[..])
.finish()
}
}
impl<T: Object> SessionWrapper<T> {
/// Create a new SessionWrapper from an open ServerSession and a backing
/// Object.
pub fn new(handle: ServerSession, object: T) -> SessionWrapper<T> {
SessionWrapper {
handle,
object,
buf: Align16([0; 0x100]),
pointer_buf: [0; 0x300],
}
}
}
impl<T: Object + Debug> IWaitable for SessionWrapper<T> {
fn get_handle(&self) -> HandleRef<'_> {
self.handle.0.as_ref()
}
fn handle_signaled(&mut self, manager: &WaitableManager) -> Result<bool, Error> {
// Push a C Buffer before receiving.
let mut req = Message::<(), [_; 1], [_; 0], [_; 0]>::new_request(None, 0);
req.push_in_pointer(&mut self.pointer_buf, false);
req.pack(&mut self.buf[..]);
self.handle.receive(&mut self.buf[..], Some(0))?;
match super::find_ty_cmdid(&self.buf[..]) {
// TODO: Handle other types.
Some((4, cmdid)) | Some((6, cmdid)) => {
self.object.dispatch(manager, cmdid, &mut self.buf[..])?;
self.handle.reply(&mut self.buf[..])?;
Ok(false)
},
Some((2, _)) => Ok(true),
_ => Ok(true)
}
}
}
/// A wrapper around a Server Port that implements the IWaitable trait. Waits for
/// connection requests, and creates a new SessionWrapper around the incoming
/// connections, which gets registered on the WaitableManager.
pub struct PortHandler<T: Object + Default + Debug> {
/// The kernel object backing this Port Handler.
handle: ServerPort,
/// Type of the Object this port creates.
phantom: PhantomData<T>
}
impl<T: Object + Default + Debug> Debug for PortHandler<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("PortHandler")
.field("handle", &self.handle)
.field("phantom", &self.phantom)
.finish()
}
}
impl<T: Object + Default + Debug + 'static> IWaitable for PortHandler<T> {
fn get_handle(&self) -> HandleRef<'_> {
self.handle.0.as_ref()
}
fn handle_signaled(&mut self, manager: &WaitableManager) -> Result<bool, Error> {
let session = Box::new(SessionWrapper {
object: T::default(),
handle: self.handle.accept()?,
buf: Align16([0; 0x100]),
pointer_buf: [0; 0x300]
});
manager.add_waitable(session);
Ok(false)
}
}
/// Encode an 8-character service string into an u64
fn encode_bytes(s: &str) -> u64 {
assert!(s.len() < 8);
let s = s.as_bytes();
0
| (u64::from(*s.get(0).unwrap_or(&0))) << 00 | (u64::from(*s.get(1).unwrap_or(&0))) << 8
| (u64::from(*s.get(2).unwrap_or(&0))) << 16 | (u64::from(*s.get(3).unwrap_or(&0))) << 24
| (u64::from(*s.get(4).unwrap_or(&0))) << 32 | (u64::from(*s.get(5).unwrap_or(&0))) << 40
| (u64::from(*s.get(6).unwrap_or(&0))) << 48 | (u64::from(*s.get(7).unwrap_or(&0))) << 56
}
impl<T: Object + Default + Debug> PortHandler<T> {
/// Registers a new PortHandler of the given name to the sm: service.
pub fn new(server_name: &str) -> Result<PortHandler<T>, Error> {
use crate::sm::IUserInterface;
let port = IUserInterface::raw_new()?.register_service(encode_bytes(server_name), false, 0)?;
Ok(PortHandler {
handle: port,
phantom: PhantomData
})
}
/// Registers a new PortHandler of the given name to the kernel. Note that
/// this interface should not be used by most services. Only the service
/// manager should register itself through this interface, as kernel managed
/// services do not implement any access controls.
pub fn new_managed(server_name: &str) -> Result<PortHandler<T>, Error> {
let port = syscalls::manage_named_port(server_name, 0)?;
Ok(PortHandler {
handle: port,
phantom: PhantomData
})
}
}