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">
<program_image path="microkit-ipc-server.elf" />
</protection_domain>
<channel>
<end pd="client" id="13" pp="true" />
<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, channels: ChannelSet) -> Result<(), Self::Error> {
debug_println!("client: notified by {}", channels.display());
if channels.contains(SERVER) {
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.