hrx/execution/
contract.rs1use crate::{Error, Result};
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
6pub enum Access {
7 Read,
9 Write,
11 ReadWrite,
13}
14impl Access {
15 pub(super) fn writes(self) -> bool {
16 self != Self::Read
17 }
18}
19#[derive(Clone, Debug, Serialize, Deserialize)]
21#[serde(deny_unknown_fields)]
22pub struct BindingContract {
23 pub bytes: usize,
25 pub alignment: usize,
27 pub access: Access,
29 pub layout: String,
31}
32#[derive(Clone, Debug, Serialize, Deserialize)]
36#[serde(deny_unknown_fields)]
37pub struct KernelContract {
38 pub bindings: Vec<BindingContract>,
40 pub constants: Vec<u8>,
42}
43impl KernelContract {
44 pub fn validate(&self) -> Result<()> {
46 for binding in &self.bindings {
47 if binding.bytes == 0
48 || binding.bytes > isize::MAX as usize
49 || !binding.alignment.is_power_of_two()
50 {
51 return Err(Error::Message(
52 "invalid kernel binding extent or alignment".into(),
53 ));
54 }
55 }
56 Ok(())
57 }
58 pub(super) fn check(&self, bindings: &[super::BufferView]) -> Result<()> {
59 self.check_extents(bindings)?;
60 self.check_aliases(bindings)
61 }
62 pub(super) fn check_extents(&self, bindings: &[super::BufferView]) -> Result<()> {
63 self.validate()?;
64 if bindings.len() != self.bindings.len() {
65 return Err(Error::Message("kernel binding count mismatch".into()));
66 }
67 for (view, contract) in bindings.iter().zip(&self.bindings) {
68 if view.len() < contract.bytes || view.offset() % contract.alignment != 0 {
69 return Err(Error::Message(format!(
70 "binding does not satisfy {}: {} bytes aligned to {} required",
71 contract.layout, contract.bytes, contract.alignment
72 )));
73 }
74 }
75 Ok(())
76 }
77 pub(super) fn check_aliases(&self, bindings: &[super::BufferView]) -> Result<()> {
78 for (index, a) in bindings.iter().enumerate() {
80 for (other, b) in bindings[..index].iter().enumerate() {
81 if a.overlaps(b)
82 && (self.bindings[index].access.writes()
83 || self.bindings[other].access.writes())
84 {
85 return Err(Error::Message(
86 "overlapping writable kernel arguments require an unsafe dispatch".into(),
87 ));
88 }
89 }
90 }
91 Ok(())
92 }
93}