host_bindings/
graphics.rs1use std::{
2 cell::OnceCell,
3 collections::{BTreeMap, btree_map::Entry},
4 os::raw::c_void,
5};
6
7use futures::block_on;
8pub use graphics::lvgl;
9
10use task::TaskIdentifier;
11use virtual_machine::{
12 Environment, EnvironmentPointer, FunctionDescriptor, Registrable, WasmPointer, WasmUsize,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Error {
17 InvalidArgumentsCount,
18 InvalidPointer,
19 NativePointerNotFound,
20 WasmPointerNotFound,
21 PointerTableFull,
22 EnvironmentRetrievalFailed,
23}
24
25pub type Result<T> = core::result::Result<T, Error>;
26
27mod generated_bindings {
28 use super::{Error, PointerTable, Result, TaskIdentifier, lvgl::*};
29 use virtual_machine::{Environment, WasmPointer, WasmUsize};
30
31 unsafe fn convert_to_native_pointer<T>(
32 environment: &Environment,
33 pointer: WasmPointer,
34 ) -> Result<*mut T> {
35 unsafe {
36 environment
37 .convert_to_native_pointer(pointer)
38 .ok_or(Error::InvalidPointer)
39 }
40 }
41
42 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
43}
44
45pub struct GraphicsBindings;
46
47impl Registrable for GraphicsBindings {
48 fn get_functions(&self) -> &[FunctionDescriptor] {
49 &GRAPHICS_BINDINGS_FUNCTIONS
50 }
51
52 #[cfg(not(target_arch = "x86_64"))]
53 fn is_XIP(&self) -> bool {
54 true
55 }
56
57 fn get_name(&self) -> &'static str {
58 "Xila_graphics\0"
59 }
60}
61
62pub(crate) struct PointerTable {
63 to_native_pointer: BTreeMap<usize, *mut c_void>,
64 to_wasm_pointer: BTreeMap<*mut c_void, u16>,
65}
66
67impl PointerTable {
68 pub fn new() -> Self {
69 Self {
70 to_native_pointer: BTreeMap::new(),
71 to_wasm_pointer: BTreeMap::new(),
72 }
73 }
74
75 const fn get_identifier(task: TaskIdentifier, identifier: u16) -> usize {
76 (task.into_inner() as usize) << 32 | identifier as usize
77 }
78
79 pub fn insert(&mut self, task: TaskIdentifier, pointer: *mut c_void) -> Result<u16> {
80 for i in u16::MIN..u16::MAX {
81 let identifier = Self::get_identifier(task, i);
82
83 match self.to_native_pointer.entry(identifier) {
84 Entry::Vacant(entry) => {
85 entry.insert(pointer);
86 self.to_wasm_pointer.insert(pointer, i);
87 return Ok(i);
88 }
89 Entry::Occupied(entry_pointer) => {
90 if *entry_pointer.get() == pointer {
91 return Ok(i);
92 }
93 }
94 }
95 }
96
97 Err(Error::PointerTableFull)
98 }
99
100 pub fn get_native_pointer<T>(&self, task: TaskIdentifier, identifier: u16) -> Result<*mut T> {
101 let identifier = Self::get_identifier(task, identifier);
102
103 self.to_native_pointer
104 .get(&identifier)
105 .map(|pointer| *pointer as *mut T)
106 .ok_or(Error::NativePointerNotFound)
107 }
108
109 pub fn get_wasm_pointer<T>(&self, pointer: *mut T) -> Result<u16> {
110 self.to_wasm_pointer
111 .get(&(pointer as *mut c_void))
112 .cloned()
113 .ok_or(Error::WasmPointerNotFound)
114 }
115
116 pub fn remove<T>(&mut self, task: TaskIdentifier, identifier: u16) -> Result<*mut T> {
117 let identifier = Self::get_identifier(task, identifier);
118
119 let pointer = self
120 .to_native_pointer
121 .remove(&identifier)
122 .map(|pointer| pointer as *mut T)
123 .ok_or(Error::NativePointerNotFound)?;
124
125 self.to_wasm_pointer.remove(&(pointer as *mut _));
126
127 Ok(pointer)
128 }
129}
130
131static mut POINTER_TABLE: OnceCell<PointerTable> = OnceCell::new();
132
133#[allow(clippy::too_many_arguments)]
140pub unsafe fn call(
141 environment: EnvironmentPointer,
142 function: generated_bindings::FunctionCall,
143 argument_0: WasmUsize,
144 argument_1: WasmUsize,
145 argument_2: WasmUsize,
146 argument_3: WasmUsize,
147 argument_4: WasmUsize,
148 argument_5: WasmUsize,
149 argument_6: WasmUsize,
150 arguments_count: u8,
151 result: WasmPointer,
152) {
153 unsafe {
154 let environment = Environment::from_raw_pointer(environment).unwrap();
155
156 let instance = graphics::get_instance();
157
158 let _lock = block_on(instance.lock());
159
160 let pointer_table_reference = &raw mut POINTER_TABLE;
161
162 let _ = (*pointer_table_reference).get_or_init(PointerTable::new);
163
164 let pointer_table_reference = (*pointer_table_reference).get_mut().unwrap();
165
166 if let Err(error) = generated_bindings::call_function(
167 environment,
168 pointer_table_reference,
169 function,
170 argument_0,
171 argument_1,
172 argument_2,
173 argument_3,
174 argument_4,
175 argument_5,
176 argument_6,
177 arguments_count,
178 result,
179 ) {
180 log::Error!(
181 "Error {error:?} durring graphics call: {function:?} with arguments: {argument_0:x}, {argument_1:x}, {argument_2:x}, {argument_3:x}, {argument_4:x}, {argument_5:x}, {argument_6:x}",
182 );
183 }
184
185 }
187}
188
189const GRAPHICS_BINDINGS_FUNCTIONS: [FunctionDescriptor; 1] = [FunctionDescriptor {
190 name: "Xila_graphics_call",
191 pointer: call as *mut _,
192}];