Skip to content

Commit ff31b38

Browse files
committed
tool: create IPC buffer in the tool, not the ELF
This removes the need for the linker script to define the IPC buffer. Signed-off-by: Julia Vassiliki <julia.vassiliki@unsw.edu.au>
1 parent b5cd889 commit ff31b38

6 files changed

Lines changed: 117 additions & 74 deletions

File tree

libmicrokit/microkit.ld

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,4 @@ SECTIONS
6666
. = ALIGN(4);
6767
_bss_end = .;
6868
} :data
69-
70-
. = ALIGN(0x1000);
71-
.ipc_buffer (NOLOAD): {
72-
__sel4_ipc_buffer_obj = .;
73-
} :NONE
7469
}

libmicrokit/src/main.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* SPDX-License-Identifier: BSD-2-Clause
55
*/
6+
#include <assert.h>
67
#include <stdbool.h>
78
#include <stddef.h>
89
#include <stdint.h>
@@ -39,9 +40,19 @@ seL4_Word microkit_notifications;
3940
seL4_Word microkit_pps;
4041
seL4_Word microkit_ioports;
4142

42-
extern seL4_IPCBuffer __sel4_ipc_buffer_obj;
43+
// Workaround: https://github.com/seL4/seL4/issues/1693
44+
#if seL4_UserTop == 0x00ffffffffff || seL4_UserTop == 0x0fffffffffff || seL4_UserTop == 0x7fffffffffff
45+
#define user_top_aligned (seL4_UserTop + 1)
46+
#elif (seL4_UserTop & ((1ULL << seL4_PageBits) - 1)) != 0
47+
#error "Expects seL4_UserTop to be aligned"
48+
#else
49+
#define user_top_aligned (seL4_UserTop)
50+
#endif
4351

44-
seL4_IPCBuffer *__sel4_ipc_buffer = &__sel4_ipc_buffer_obj;
52+
/* The tool assumes the IPC buffer in the top page of user memory */
53+
seL4_IPCBuffer *__sel4_ipc_buffer = (seL4_IPCBuffer *)(user_top_aligned - (1ULL << seL4_PageBits));
54+
static_assert(sizeof(seL4_IPCBuffer) <= (1ULL << seL4_PageBits),
55+
"IPC Buffer is expected to need less than one page in size");
4556

4657
extern const void (*const __init_array_start [])(void);
4758
extern const void (*const __init_array_end [])(void);

monitor/src/main.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
* Acting as the fault handler for protection domains.
1313
*/
14-
14+
#include <assert.h>
1515
#include <stdbool.h>
1616
#include <stdint.h>
1717
#include <sel4/sel4.h>
@@ -29,8 +29,19 @@
2929
#define BASE_SCHED_CONTEXT_CAP 138
3030
#define BASE_NOTIFICATION_CAP 202
3131

32-
extern seL4_IPCBuffer __sel4_ipc_buffer_obj;
33-
seL4_IPCBuffer *__sel4_ipc_buffer = &__sel4_ipc_buffer_obj;
32+
// Workaround: https://github.com/seL4/seL4/issues/1693
33+
#if seL4_UserTop == 0x00ffffffffff || seL4_UserTop == 0x0fffffffffff || seL4_UserTop == 0x7fffffffffff
34+
#define user_top_aligned (seL4_UserTop + 1)
35+
#elif (seL4_UserTop & ((1ULL << seL4_PageBits) - 1)) != 0
36+
#error "Expects seL4_UserTop to be aligned"
37+
#else
38+
#define user_top_aligned (seL4_UserTop)
39+
#endif
40+
41+
/* The tool assumes the IPC buffer in the top page of user memory */
42+
seL4_IPCBuffer *__sel4_ipc_buffer = (seL4_IPCBuffer *)(user_top_aligned - (1ULL << seL4_PageBits));
43+
static_assert(sizeof(seL4_IPCBuffer) <= (1ULL << seL4_PageBits),
44+
"IPC Buffer is expected to need less than one page in size");
3445

3546
char pd_names[MAX_PDS][MAX_NAME_LEN];
3647
seL4_Word pd_names_len;

tool/microkit/src/capdl/builder.rs

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ use crate::{
3131
util::{ranges_overlap, round_down, round_up},
3232
};
3333

34-
// Corresponds to the IPC buffer symbol in libmicrokit and the monitor
35-
const SYMBOL_IPC_BUFFER: &str = "__sel4_ipc_buffer_obj";
36-
3734
const FAULT_BADGE: u64 = 1 << 62;
3835
const PPC_BADGE: u64 = 1 << 63;
3936

@@ -295,47 +292,11 @@ impl CapDLSpecContainer {
295292
}
296293
}
297294

298-
// Create and map the IPC buffer for this ELF
299-
let ipcbuf_frame_obj_id = capdl_util_make_frame_obj(
300-
self,
301-
Fill {
302-
entries: [].to_vec(),
303-
},
304-
&format!("ipcbuf_{pd_name}"),
305-
None,
306-
PageSize::Small.fixed_size_bits(sel4_config) as u8,
307-
);
308-
let ipcbuf_frame_cap =
309-
capdl_util_make_frame_cap(ipcbuf_frame_obj_id, true, true, false, true);
310-
// We need to clone the IPC buf cap because in addition to mapping the frame into the VSpace, we need to bind
311-
// this frame to the TCB as well.
312-
let ipcbuf_frame_cap_for_tcb = ipcbuf_frame_cap.clone();
313-
let ipcbuf_vaddr = elf
314-
.find_symbol(SYMBOL_IPC_BUFFER)
315-
.unwrap_or_else(|_| panic!("Could not find {SYMBOL_IPC_BUFFER}"))
316-
.0;
317-
match map_page(
318-
self,
319-
sel4_config,
320-
pd_name,
321-
vspace_obj_id,
322-
ipcbuf_frame_cap,
323-
PageSize::Small as u64,
324-
ipcbuf_vaddr,
325-
) {
326-
Ok(_) => {}
327-
Err(map_err_reason) => {
328-
return Err(format!(
329-
"build_capdl_spec(): failed to map ipc buffer frame to {pd_name} because: {map_err_reason}"
330-
))
331-
}
332-
};
333-
334295
let tcb_name = format!("tcb_{pd_name}");
335296
let entry_point = elf.entry;
336297

337298
let tcb_extra_info = object::TcbExtraInfo {
338-
ipc_buffer_addr: ipcbuf_vaddr.into(),
299+
ipc_buffer_addr: 0.into(),
339300
affinity: Word(pd_cpu.0.into()),
340301
prio: 0,
341302
max_prio: 0,
@@ -350,11 +311,7 @@ impl CapDLSpecContainer {
350311

351312
let tcb_inner_obj = object::Tcb {
352313
// Bind the VSpace into the TCB
353-
slots: [
354-
capdl_util_make_cte(TcbBoundSlot::VSpace as u32, vspace_cap),
355-
capdl_util_make_cte(TcbBoundSlot::IpcBuffer as u32, ipcbuf_frame_cap_for_tcb),
356-
]
357-
.to_vec(),
314+
slots: vec![capdl_util_make_cte(TcbBoundSlot::VSpace as u32, vspace_cap)],
358315
extra: Box::new(tcb_extra_info),
359316
};
360317

@@ -488,6 +445,27 @@ pub fn build_capdl_spec(
488445
)
489446
.unwrap();
490447

448+
// Create monitor IPC Bufffer
449+
let mon_ipcbuf_frame_obj_id = capdl_util_make_frame_obj(
450+
&mut spec_container,
451+
Fill { entries: vec![] },
452+
&format!("ipcbuf_{MONITOR_PD_NAME}"),
453+
None,
454+
PageSize::Small.fixed_size_bits(kernel_config) as u8,
455+
);
456+
let mon_ipcbuf_frame_cap =
457+
capdl_util_make_frame_cap(mon_ipcbuf_frame_obj_id, true, true, false, true);
458+
map_page(
459+
&mut spec_container,
460+
kernel_config,
461+
MONITOR_PD_NAME,
462+
mon_vspace_obj_id,
463+
mon_ipcbuf_frame_cap.clone(),
464+
PageSize::Small as u64,
465+
kernel_config.pd_ipc_buffer(),
466+
)
467+
.expect("should be able to map the IPC buffer as we checked overlaps");
468+
491469
// At this point, all of the required objects for the monitor have been created and its caps inserted into
492470
// the correct slot in the CSpace. We need to bind those objects into the TCB for the monitor to use them.
493471
// In addition, `add_elf_to_spec()` doesn't fill most the details in the TCB.
@@ -497,6 +475,7 @@ pub fn build_capdl_spec(
497475
.unwrap()
498476
.object
499477
{
478+
monitor_tcb.extra.ipc_buffer_addr = Word(kernel_config.pd_ipc_buffer());
500479
// Special case, monitor has its stack statically allocated.
501480
monitor_tcb.extra.sp = Word(kernel_config.pd_stack_top());
502481
// While there is nothing stopping us from running the monitor at the highest priority alongside the
@@ -505,6 +484,11 @@ pub fn build_capdl_spec(
505484
monitor_tcb.extra.max_prio = MONITOR_PRIORITY;
506485
monitor_tcb.extra.resume = true;
507486

487+
monitor_tcb.slots.push(capdl_util_make_cte(
488+
TcbBoundSlot::IpcBuffer as u32,
489+
mon_ipcbuf_frame_cap,
490+
));
491+
508492
monitor_tcb.slots.push(capdl_util_make_cte(
509493
TcbBoundSlot::CSpace as u32,
510494
mon_cnode_cap,
@@ -638,17 +622,27 @@ pub fn build_capdl_spec(
638622
// We perform this check here, otherwise the tool will panic with quite cryptic page-table related errors.
639623
let mr_vaddr_range = map.vaddr..(map.vaddr + (page_size_bytes * frames.len() as u64));
640624

641-
let pd_stack_range =
642-
kernel_config.pd_stack_bottom(pd.stack_size)..kernel_config.pd_stack_top();
643-
if ranges_overlap(&mr_vaddr_range, &pd_stack_range) {
644-
return Err(format!("ERROR: mapping MR '{}' to PD '{}' with vaddr [0x{:x}..0x{:x}) will overlap with the stack at [0x{:x}..0x{:x})", map.mr, pd.name, mr_vaddr_range.start, mr_vaddr_range.end, pd_stack_range.start, pd_stack_range.end));
625+
let pd_reserved_range =
626+
kernel_config.pd_map_max_vaddr(pd.stack_size)..kernel_config.user_top();
627+
if ranges_overlap(&mr_vaddr_range, &pd_reserved_range) {
628+
return Err(
629+
format!(
630+
"ERROR: mapping MR '{}' to PD '{}' with vaddr [0x{:x}..0x{:x}) will overlap with the PD reserved range at [0x{:x}..0x{:x})",
631+
map.mr, pd.name, mr_vaddr_range.start, mr_vaddr_range.end, pd_reserved_range.start, pd_reserved_range.end,
632+
)
633+
);
645634
}
646635

647636
for elf_seg in elf_obj.loadable_segments().iter() {
648637
let elf_seg_vaddr_range = elf_seg.virt_addr
649638
..elf_seg.virt_addr + round_up(elf_seg.mem_size(), PageSize::Small as u64);
650639
if ranges_overlap(&mr_vaddr_range, &elf_seg_vaddr_range) {
651-
return Err(format!("ERROR: mapping MR '{}' to PD '{}' with vaddr [0x{:x}..0x{:x}) will overlap with an ELF segment at [0x{:x}..0x{:x})", map.mr, pd.name, mr_vaddr_range.start, mr_vaddr_range.end, elf_seg_vaddr_range.start, elf_seg_vaddr_range.end));
640+
return Err(
641+
format!(
642+
"ERROR: mapping MR '{}' to PD '{}' with vaddr [0x{:x}..0x{:x}) will overlap with an ELF segment at [0x{:x}..0x{:x})",
643+
map.mr, pd.name, mr_vaddr_range.start, mr_vaddr_range.end, elf_seg_vaddr_range.start, elf_seg_vaddr_range.end,
644+
)
645+
);
652646
}
653647
}
654648

@@ -663,7 +657,32 @@ pub fn build_capdl_spec(
663657
);
664658
}
665659

666-
// Step 3-3: Create and map in the stack (bottom up)
660+
// Step 3-3a: Create and map in the IPC buffer
661+
let ipcbuf_frame_obj_id = capdl_util_make_frame_obj(
662+
&mut spec_container,
663+
Fill { entries: vec![] },
664+
&format!("ipcbuf_{}", pd.name),
665+
None,
666+
PageSize::Small.fixed_size_bits(kernel_config) as u8,
667+
);
668+
let ipcbuf_frame_cap =
669+
capdl_util_make_frame_cap(ipcbuf_frame_obj_id, true, true, false, true);
670+
map_page(
671+
&mut spec_container,
672+
kernel_config,
673+
&pd.name,
674+
pd_vspace_obj_id,
675+
ipcbuf_frame_cap.clone(),
676+
PageSize::Small as u64,
677+
kernel_config.pd_ipc_buffer(),
678+
)
679+
.expect("should be able to map the IPC buffer as we checked overlaps");
680+
caps_to_bind_to_tcb.push(capdl_util_make_cte(
681+
TcbBoundSlot::IpcBuffer as u32,
682+
ipcbuf_frame_cap,
683+
));
684+
685+
// Step 3-3b: Create and map in the stack (bottom up)
667686
let mut cur_stack_vaddr = kernel_config.pd_stack_bottom(pd.stack_size);
668687
pd_stack_bottoms.push(cur_stack_vaddr);
669688
let num_stack_frames = pd.stack_size / PageSize::Small as u64;
@@ -1027,6 +1046,7 @@ pub fn build_capdl_spec(
10271046
.unwrap()
10281047
.object
10291048
{
1049+
pd_tcb.extra.ipc_buffer_addr = Word(kernel_config.pd_ipc_buffer());
10301050
pd_tcb.extra.sp = Word(kernel_config.pd_stack_top());
10311051
pd_tcb.extra.master_fault_ep = None; // Not used on MCS kernel.
10321052
pd_tcb.extra.prio = pd.priority;

tool/microkit/src/sel4.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,18 @@ pub struct Config {
310310
}
311311

312312
impl Config {
313-
/// Refers to 'seL4_UserTop'
313+
/// Refers to 'seL4_UserTop'. Is exclusive.
314314
pub fn user_top(&self) -> u64 {
315315
match self.arch {
316+
// Almost the same as the true definition, but for an inconsistency
317+
// TODO: Resolve https://github.com/seL4/seL4/issues/1693
316318
Arch::Aarch64 => match self.hypervisor {
317319
true => match self.arm_pa_size_bits.unwrap() {
318-
40 => 0x10000000000,
319-
44 => 0x100000000000,
320+
40 => 0x00ffffffffff + 1,
321+
44 => 0x0fffffffffff + 1,
320322
_ => panic!("Unknown ARM physical address size bits"),
321323
},
322-
false => 0x800000000000,
324+
false => 0x7fffffffffff + 1,
323325
},
324326
Arch::Riscv64 => 0x0000003ffffff000,
325327
Arch::X86_64 => 0x7ffffffff000,
@@ -346,22 +348,26 @@ impl Config {
346348
}
347349
}
348350

351+
/// IPC Buffer is located at the highest possible virtual memory page
352+
pub fn pd_ipc_buffer(&self) -> u64 {
353+
self.user_top() - PageSize::Small as u64
354+
}
355+
356+
/// The stack is located in the third highest possible virtual memory pages,
357+
/// as the IPC buffer lives in the top, and we add a guard page inbetween.
349358
pub fn pd_stack_top(&self) -> u64 {
350-
self.user_top()
359+
// Subtract off the guard page.
360+
self.pd_ipc_buffer() - PageSize::Small as u64
351361
}
352362

353363
pub fn pd_stack_bottom(&self, stack_size: u64) -> u64 {
354364
self.pd_stack_top() - stack_size
355365
}
356366

357-
/// For simplicity and consistency, the stack of each PD occupies the highest
358-
/// possible virtual memory region. That means that the highest possible address
359-
/// for a user to be able to create a mapping at is below the stack region.
367+
/// For simplicity and consistency, the stack & IPC buffers of each PD
368+
/// occupy the highest memory regions near seL4_UserTop.
369+
/// So the maximum vaddr allowed for mapping is the stack bottom.
360370
pub fn pd_map_max_vaddr(&self, stack_size: u64) -> u64 {
361-
// This function depends on the invariant that the stack of a PD
362-
// consumes the highest possible address of the virtual address space.
363-
assert!(self.pd_stack_top() == self.user_top());
364-
365371
self.pd_stack_bottom(stack_size)
366372
}
367373

tool/microkit/tests/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ mod system {
10071007
check_error(
10081008
&DEFAULT_AARCH64_KERNEL_CONFIG,
10091009
"sys_map_too_high.system",
1010-
"Error: vaddr (0x1000000000000000) must be less than 0xffffffe000 on element 'map'",
1010+
"Error: vaddr (0x1000000000000000) must be less than 0xffffffc000 on element 'map'",
10111011
)
10121012
}
10131013

0 commit comments

Comments
 (0)