IPC
This chapter covers making and handling protected procedure calls in protection domains written in Rust. Navigate to and run the example:
cd workspaces/microkit/ipc
make simulate
The example system description specifies two protection domains, with a channel between them:
<system>
<protection_domain name="client" priority="100">
<program_image path="microkit-ipc-client.elf" />
</protection_domain>
<protection_domain name="server" priority="200" pp="true">
<program_image path="microkit-ipc-server.elf" />
</protection_domain>
<channel>
<end pd="client" id="13" />
<end pd="server" id="37" />
</channel>
</system>
const SERVER: Channel = Channel::new(13);
#[protection_domain]
fn init() -> impl Handler {
debug_println!("client: initializing");
HandlerImpl
}
struct HandlerImpl;
impl Handler for HandlerImpl {
type Error = Infallible;
fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
debug_println!("client: notified by {:?}", channel);
debug_println!("client: TEST_PASS");
Ok(())
}
}
const CLIENT: Channel = Channel::new(37);
#[protection_domain]
fn init() -> impl Handler {
debug_println!("server: initializing");
debug_println!("server: notifying client");
CLIENT.notify();
HandlerImpl
}
struct HandlerImpl;
impl Handler for HandlerImpl {
type Error = Infallible;
fn protected(
&mut self,
channel: Channel,
msg_info: MessageInfo,
) -> Result<MessageInfo, Self::Error> {
debug_println!("server: called by {:?}", channel);
todo!()
}
}
The
Channel
type is the Rust equivalent of the
microkit_channel
type alias in libmicrokit
.
Note how the functionality corresponding to libmicrokit
's microkit_notify
, microkit_irq_ack
, and microkit_ppcall
is implemented in methods for Channel
.
The
MessageInfo
type is the Rust equivalent of the
microkit_msginfo
type alias in libmicrokit
.
Just as microkit_msginfo
is an alias for seL4_MessageInfo_t
, sel4_microkit::MessageInfo
is just a thin wrapper around MessageInfo
.
libmicrokit
has microkit_mr_set()
and microkit_mr_get()
for interacting with the IPC buffer.
In the sel4_microkit
crate, we have
get_mr()
and
set_mr()
,
but we also have
with_msg_regs()
,
with_msg_regs_mut()
,
with_msg_bytes()
, and
with_msg_bytes_mut()
,
which use
sel4::with_ipc_buffer()
and
sel4::with_ipc_buffer_mut()
under the hood.
Step 10.A (exercise)
Exercise:
In the client's notified()
handler, make a protected procedure call to the server using SERVER.pp_call()
.
Handle the call in the server's protected()
handler.
Include data in the message using sel4_microkit::with_msg_regs{,_mut}
.
Exercise (optional):
Send something more interesting over IPC using
msg_bytes
and
msg_bytes_mut
.
For example, the zerocopy
crate can be used to view certain types as bytes and vice versa, and the lightweight postcard
crate can be used to serialize and deserialize a wider range of types using serde
.