Skip to main content

islet_rmm/rmi/
constraint.rs

1use crate::config::SMCCC_1_3_SVE_HINT;
2use crate::event::{Command, Context};
3use crate::rmi;
4
5#[allow(dead_code)]
6#[derive(Default, Copy, Clone)]
7pub struct Constraint {
8    pub cmd: Command,
9    pub arg_num: usize, // number of args including fid
10    pub ret_num: usize,
11    // TODO: add validate function for each RMI command (validate type or value inside registers)
12}
13
14impl Constraint {
15    pub fn new(cmd: Command, arg_num: usize, ret_num: usize) -> Constraint {
16        Constraint {
17            cmd,
18            arg_num,
19            ret_num,
20        }
21    }
22}
23
24fn pick(cmd: Command) -> Option<Constraint> {
25    let constraint = match cmd {
26        rmi::VERSION => Constraint::new(rmi::VERSION, 2, 3),
27        rmi::GRANULE_DELEGATE => Constraint::new(rmi::GRANULE_DELEGATE, 2, 1),
28        rmi::GRANULE_UNDELEGATE => Constraint::new(rmi::GRANULE_UNDELEGATE, 2, 1),
29        rmi::DATA_CREATE => Constraint::new(rmi::DATA_CREATE, 6, 1),
30        rmi::DATA_CREATE_UNKNOWN => Constraint::new(rmi::DATA_CREATE_UNKNOWN, 4, 1),
31        rmi::DATA_DESTROY => Constraint::new(rmi::DATA_DESTROY, 3, 3),
32        rmi::REALM_ACTIVATE => Constraint::new(rmi::REALM_ACTIVATE, 2, 1),
33        // NOTE: REALM_CREATE has 3 of arg_num and 1 of ret_num according to the specification,
34        //       but we're using one more return value for our own purpose.
35        rmi::REALM_CREATE => Constraint::new(rmi::REALM_CREATE, 3, 2),
36        rmi::REALM_DESTROY => Constraint::new(rmi::REALM_DESTROY, 2, 1),
37        // NOTE: REC_CREATE has 4 of arg_num and 1 of ret_num according to the specification,
38        //       but we're using one more return value for our own purpose.
39        rmi::REC_CREATE => Constraint::new(rmi::REC_CREATE, 4, 2),
40        rmi::REC_DESTROY => Constraint::new(rmi::REC_DESTROY, 2, 1),
41        rmi::REC_ENTER => Constraint::new(rmi::REC_ENTER, 3, 1),
42        rmi::RTT_MAP_UNPROTECTED => Constraint::new(rmi::RTT_MAP_UNPROTECTED, 5, 1),
43        rmi::RTT_UNMAP_UNPROTECTED => Constraint::new(rmi::RTT_UNMAP_UNPROTECTED, 4, 2),
44        rmi::RTT_READ_ENTRY => Constraint::new(rmi::RTT_READ_ENTRY, 4, 5),
45        rmi::FEATURES => Constraint::new(rmi::FEATURES, 2, 2),
46        rmi::REC_AUX_COUNT => Constraint::new(rmi::REC_AUX_COUNT, 2, 2),
47        rmi::RTT_CREATE => Constraint::new(rmi::RTT_CREATE, 5, 1),
48        rmi::RTT_DESTROY => Constraint::new(rmi::RTT_DESTROY, 4, 3),
49        rmi::RTT_INIT_RIPAS => Constraint::new(rmi::RTT_INIT_RIPAS, 4, 2),
50        rmi::RTT_SET_RIPAS => Constraint::new(rmi::RTT_SET_RIPAS, 5, 2),
51        rmi::RTT_FOLD => Constraint::new(rmi::RTT_FOLD, 4, 2),
52        // XXX: REQ_COMPLETE do not exist in the spec
53        rmi::REQ_COMPLETE => Constraint::new(rmi::REQ_COMPLETE, 4, 2),
54        rmi::PSCI_COMPLETE => Constraint::new(rmi::PSCI_COMPLETE, 4, 1),
55        rmi::ISLET_REALM_SET_METADATA => Constraint::new(rmi::ISLET_REALM_SET_METADATA, 4, 1),
56        _ => return None,
57    };
58    Some(constraint)
59}
60
61pub fn validate(cmd: Command, arg: &[usize]) -> Context {
62    let fid = cmd & !SMCCC_1_3_SVE_HINT;
63    if let Some(c) = pick(fid) {
64        let mut ctx = Context::new(fid);
65        // SMC calling convention requires x4-x7 to be preserved unless used.
66        // Since the rmmd in EL3 takes care of preserving x5-x7,
67        // we only store x4.
68        ctx.x4 = arg[3] as u64;
69        ctx.init_arg(&arg[..(c.arg_num - 1)]);
70        ctx.resize_ret(c.ret_num);
71        if cmd & SMCCC_1_3_SVE_HINT != 0 {
72            ctx.sve_hint = true;
73        }
74        ctx
75    } else {
76        error!("Coudlnt find constraint for command: {:X}", cmd);
77        Context::new(rmi::NOT_SUPPORTED_YET)
78    }
79}