Skip to content

Commit c56ba46

Browse files
Add support for ARM SMC calls
Signed-off-by: Ivan Velickovic <[email protected]>
1 parent f43f042 commit c56ba46

File tree

6 files changed

+96
-0
lines changed

6 files changed

+96
-0
lines changed

docs/manual.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ If the protection domain has children it must also implement:
438438
void microkit_vcpu_arm_ack_vppi(microkit_child vcpu, seL4_Word irq);
439439
seL4_Word microkit_vcpu_arm_read_reg(microkit_child vcpu, seL4_Word reg);
440440
void microkit_vcpu_arm_write_reg(microkit_child vcpu, seL4_Word reg, seL4_Word value);
441+
void microkit_arm_smc_call(seL4_ARM_SMCContext *args, seL4_ARM_SMCContext *response);
441442

442443

443444
## `void init(void)`
@@ -605,6 +606,16 @@ Write to a register for a given virtual CPU with ID `vcpu`. The `reg` argument i
605606
register that is written to. The `value` argument is what the register will be set to.
606607
The list of registers is defined by the enum `seL4_VCPUReg` in the seL4 source code.
607608

609+
## `void microkit_arm_smc_call(seL4_ARM_SMCContext *args, seL4_ARM_SMCContext *response)`
610+
611+
This API is available only on ARM and only when seL4 has been configured to enable the
612+
`KernelAllowSMCCalls` option.
613+
614+
The API takes in arguments for a Secure Monitor Call which will be performed by seL4. Any
615+
response values will be placed into the `response` structure.
616+
617+
The `seL4_ARM_SMCContext` structure contains fields for registers x0 to x7.
618+
608619
# System Description File {#sysdesc}
609620

610621
This section describes the format of the System Description File (SDF).
@@ -634,6 +645,7 @@ It supports the following attributes:
634645
* `passive`: (optional) Indicates that the protection domain will be passive and thus have its scheduling context removed after initialisation; defaults to false.
635646
* `stack_size`: (optional) Number of bytes that will be used for the PD's stack.
636647
Must be be between 4KiB and 16MiB and be 4K page-aligned. Defaults to 4KiB.
648+
* `smc`: (optional, only on ARM) Allow the PD to give an SMC call for the kernel to perform. Only available when the kernel has been configured with `KernelAllowSMCCalls`. Defaults to false.
637649

638650
Additionally, it supports the following child elements:
639651

libmicrokit/include/microkit.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ typedef seL4_MessageInfo_t microkit_msginfo;
1818
#define MONITOR_EP 5
1919
/* Only valid in the 'benchmark' configuration */
2020
#define TCB_CAP 6
21+
/* Only valid when the PD has been configured to make SMC calls */
22+
#define ARM_SMC_CAP 7
2123
#define BASE_OUTPUT_NOTIFICATION_CAP 10
2224
#define BASE_ENDPOINT_CAP 74
2325
#define BASE_IRQ_CAP 138
@@ -206,6 +208,18 @@ static inline void microkit_vcpu_arm_write_reg(microkit_child vcpu, seL4_Word re
206208
}
207209
#endif
208210

211+
#if defined(CONFIG_ALLOW_SMC_CALLS)
212+
static inline void microkit_arm_smc_call(seL4_ARM_SMCContext *args, seL4_ARM_SMCContext *response)
213+
{
214+
seL4_Error err;
215+
err = seL4_ARM_SMC_Call(ARM_SMC_CAP, args, response);
216+
if (err != seL4_NoError) {
217+
microkit_dbg_puts("microkit_arm_smc_call: error making SMC call\n");
218+
microkit_internal_crash(err);
219+
}
220+
}
221+
#endif
222+
209223
static inline void microkit_deferred_notify(microkit_channel ch)
210224
{
211225
microkit_have_signal = seL4_True;

tool/microkit/src/main.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const VSPACE_CAP_IDX: u64 = 3;
4747
const REPLY_CAP_IDX: u64 = 4;
4848
const MONITOR_EP_CAP_IDX: u64 = 5;
4949
const TCB_CAP_IDX: u64 = 6;
50+
const SMC_CAP_IDX: u64 = 7;
5051

5152
const BASE_OUTPUT_NOTIFICATION_CAP: u64 = 10;
5253
const BASE_OUTPUT_ENDPOINT_CAP: u64 = BASE_OUTPUT_NOTIFICATION_CAP + 64;
@@ -70,6 +71,7 @@ const INIT_CNODE_CAP_ADDRESS: u64 = 2;
7071
const INIT_VSPACE_CAP_ADDRESS: u64 = 3;
7172
const IRQ_CONTROL_CAP_ADDRESS: u64 = 4; // Singleton
7273
const INIT_ASID_POOL_CAP_ADDRESS: u64 = 6;
74+
const SMC_CAP_ADDRESS: u64 = 15;
7375

7476
// const ASID_CONTROL_CAP_ADDRESS: u64 = 5; // Singleton
7577
// const IO_PORT_CONTROL_CAP_ADDRESS: u64 = 7; // Null on this platform
@@ -892,6 +894,7 @@ fn build_system(
892894
cap_address_names.insert(INIT_VSPACE_CAP_ADDRESS, "VSpace: init".to_string());
893895
cap_address_names.insert(INIT_ASID_POOL_CAP_ADDRESS, "ASID Pool: init".to_string());
894896
cap_address_names.insert(IRQ_CONTROL_CAP_ADDRESS, "IRQ Control".to_string());
897+
cap_address_names.insert(SMC_CAP_IDX, "SMC".to_string());
895898

896899
let system_cnode_bits = system_cnode_size.ilog2() as u64;
897900

@@ -2448,6 +2451,26 @@ fn build_system(
24482451
}
24492452
}
24502453

2454+
for (pd_idx, pd) in system.protection_domains.iter().enumerate() {
2455+
if pd.smc {
2456+
assert!(config.arm_smc.is_some() && config.arm_smc.unwrap());
2457+
let cnode_obj = &cnode_objs[pd_idx];
2458+
system_invocations.push(Invocation::new(
2459+
config,
2460+
InvocationArgs::CnodeMint {
2461+
cnode: cnode_obj.cap_addr,
2462+
dest_index: SMC_CAP_IDX,
2463+
dest_depth: PD_CAP_BITS,
2464+
src_root: root_cnode_cap,
2465+
src_obj: SMC_CAP_ADDRESS,
2466+
src_depth: config.cap_address_bits,
2467+
rights: Rights::All as u64, // FIXME: Check rights
2468+
badge: 0,
2469+
},
2470+
));
2471+
}
2472+
}
2473+
24512474
// All minting is complete at this point
24522475

24532476
// Associate badges
@@ -3297,6 +3320,11 @@ fn main() -> Result<(), String> {
32973320
Arch::Riscv64 => None,
32983321
};
32993322

3323+
let arm_smc = match arch {
3324+
Arch::Aarch64 => Some(json_str_as_bool(&kernel_config_json, "ALLOW_SMC_CALLS")?),
3325+
_ => None,
3326+
};
3327+
33003328
let kernel_frame_size = match arch {
33013329
Arch::Aarch64 => 1 << 12,
33023330
Arch::Riscv64 => 1 << 21,
@@ -3315,6 +3343,7 @@ fn main() -> Result<(), String> {
33153343
benchmark: args.config == "benchmark",
33163344
fpu: json_str_as_bool(&kernel_config_json, "HAVE_FPU")?,
33173345
arm_pa_size_bits,
3346+
arm_smc,
33183347
riscv_pt_levels: Some(RiscvVirtualMemory::Sv39),
33193348
};
33203349

tool/microkit/src/sdf.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ pub struct ProtectionDomain {
144144
pub pp: bool,
145145
pub passive: bool,
146146
pub stack_size: u64,
147+
pub smc: bool,
147148
pub program_image: PathBuf,
148149
pub maps: Vec<SysMap>,
149150
pub irqs: Vec<SysIrq>,
@@ -285,6 +286,9 @@ impl ProtectionDomain {
285286
"period",
286287
"passive",
287288
"stack_size",
289+
// The SMC field is only available in certain configurations
290+
// but we do the error-checking further down.
291+
"smc",
288292
];
289293
if is_child {
290294
attrs.push("id");
@@ -360,6 +364,37 @@ impl ProtectionDomain {
360364
PD_DEFAULT_STACK_SIZE
361365
};
362366

367+
let smc = if let Some(xml_smc) = node.attribute("smc") {
368+
match str_to_bool(xml_smc) {
369+
Some(val) => val,
370+
None => {
371+
return Err(value_error(
372+
xml_sdf,
373+
node,
374+
"smc must be 'true' or 'false'".to_string(),
375+
))
376+
}
377+
}
378+
} else {
379+
false
380+
};
381+
382+
if smc {
383+
match config.arm_smc {
384+
Some(smc_allowed) => {
385+
if !smc_allowed {
386+
return Err(value_error(xml_sdf, node, "Using SMC support without ARM SMC forwarding support enabled for this platform".to_string()));
387+
}
388+
}
389+
None => {
390+
return Err(
391+
"ARM SMC forwarding support is not available for this architecture"
392+
.to_string(),
393+
)
394+
}
395+
}
396+
}
397+
363398
#[allow(clippy::manual_range_contains)]
364399
if stack_size < PD_MIN_STACK_SIZE || stack_size > PD_MAX_STACK_SIZE {
365400
return Err(value_error(
@@ -559,6 +594,7 @@ impl ProtectionDomain {
559594
pp,
560595
passive,
561596
stack_size,
597+
smc,
562598
program_image: program_image.unwrap(),
563599
maps,
564600
irqs,

tool/microkit/src/sel4.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ pub struct Config {
5050
pub fpu: bool,
5151
/// ARM-specific, number of physical address bits
5252
pub arm_pa_size_bits: Option<usize>,
53+
/// ARM-specific, where or not SMC forwarding is allowed
54+
/// False if the kernel config option has not been enabled.
55+
/// None on any non-ARM architecture.
56+
pub arm_smc: Option<bool>,
5357
/// RISC-V specific, what kind of virtual memory system (e.g Sv39)
5458
pub riscv_pt_levels: Option<RiscvVirtualMemory>,
5559
}

tool/microkit/tests/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const DEFAULT_KERNEL_CONFIG: sel4::Config = sel4::Config {
1919
benchmark: false,
2020
fpu: true,
2121
arm_pa_size_bits: Some(40),
22+
arm_smc: None,
2223
riscv_pt_levels: None,
2324
};
2425

0 commit comments

Comments
 (0)