|
| 1 | +// Licensed to the Apache Software Foundation (ASF) under one |
| 2 | +// or more contributor license agreements. See the NOTICE file |
| 3 | +// distributed with this work for additional information |
| 4 | +// regarding copyright ownership. The ASF licenses this file |
| 5 | +// to you under the Apache License, Version 2.0 (the |
| 6 | +// "License"); you may not use this file except in compliance |
| 7 | +// with the License. You may obtain a copy of the License at |
| 8 | +// |
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +// |
| 11 | +// Unless required by applicable law or agreed to in writing, |
| 12 | +// software distributed under the License is distributed on an |
| 13 | +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 14 | +// KIND, either express or implied. See the License for the |
| 15 | +// specific language governing permissions and limitations |
| 16 | +// under the License. |
| 17 | + |
| 18 | +use std::path::PathBuf; |
| 19 | + |
| 20 | +pub struct Config { |
| 21 | + name: String, |
| 22 | + uuid: uuid::Uuid, |
| 23 | + init_fn_name: String, |
| 24 | + invoke_fn_name: String, |
| 25 | + dest: Option<PathBuf>, |
| 26 | +} |
| 27 | + |
| 28 | +impl Config { |
| 29 | + pub fn new(name: &str, uuid: uuid::Uuid, init_fn_name: &str, invoke_fn_name: &str) -> Self { |
| 30 | + Self { |
| 31 | + name: name.to_owned(), |
| 32 | + uuid, |
| 33 | + init_fn_name: init_fn_name.to_owned(), |
| 34 | + invoke_fn_name: invoke_fn_name.to_owned(), |
| 35 | + dest: None, |
| 36 | + } |
| 37 | + } |
| 38 | + pub fn build(&self) -> std::io::Result<()> { |
| 39 | + let codes = generate_binding( |
| 40 | + &self.name, |
| 41 | + &self.uuid, |
| 42 | + &self.init_fn_name, |
| 43 | + &self.invoke_fn_name, |
| 44 | + ) |
| 45 | + .to_string(); |
| 46 | + let out_path = self.get_out_path(); |
| 47 | + if let Ok(v) = std::fs::read(&out_path) |
| 48 | + && v.eq(codes.as_bytes()) |
| 49 | + { |
| 50 | + return Ok(()); |
| 51 | + } |
| 52 | + |
| 53 | + if let Some(parent_dir) = out_path.parent() { |
| 54 | + std::fs::create_dir_all(parent_dir)?; |
| 55 | + } |
| 56 | + std::fs::write(out_path, codes.as_bytes()) |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +impl Config { |
| 61 | + fn get_out_path(&self) -> PathBuf { |
| 62 | + match self.dest.as_ref() { |
| 63 | + Some(v) => v.clone(), |
| 64 | + None => { |
| 65 | + let out_dir = PathBuf::from( |
| 66 | + std::env::var("OUT_DIR").expect("Infallible when using in build.rs"), |
| 67 | + ); |
| 68 | + out_dir.join("plugin_static.rs") |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +pub fn generate_binding( |
| 75 | + name: &str, |
| 76 | + uuid: &uuid::Uuid, |
| 77 | + init_fn_name: &str, |
| 78 | + invoke_fn_name: &str, |
| 79 | +) -> proc_macro2::TokenStream { |
| 80 | + let (uuid_f1, uuid_f2, uuid_f3, uuid_f4) = uuid.as_fields(); |
| 81 | + let name_bytes_with_null = format!("{}\0", name); |
| 82 | + let init_fn_name = quote::format_ident!("{}", init_fn_name); |
| 83 | + let invoke_fn_name = quote::format_ident!("{}", invoke_fn_name); |
| 84 | + quote::quote! { |
| 85 | + const _: () = { |
| 86 | + use core::ffi::{c_char, c_void}; |
| 87 | + use optee_teec::raw::{PluginMethod, TEEC_Result, TEEC_SUCCESS, TEEC_UUID, size_t}; |
| 88 | + const _: fn() -> optee_teec::Result<()> = #init_fn_name; |
| 89 | + const _: fn(_: &mut optee_teec::PluginParameters) -> optee_teec::Result<()> = #invoke_fn_name; |
| 90 | + |
| 91 | + unsafe extern "C" fn __plugin_init() -> TEEC_Result { |
| 92 | + match #init_fn_name() { |
| 93 | + Ok(()) => TEEC_SUCCESS, |
| 94 | + Err(err) => err.raw_code(), |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + unsafe extern "C" fn __plugin_invoke( |
| 99 | + cmd: u32, |
| 100 | + sub_cmd: u32, |
| 101 | + data: *mut c_void, |
| 102 | + in_len: size_t, |
| 103 | + out_len: *mut size_t, |
| 104 | + ) -> TEEC_Result { |
| 105 | + let mut parameter = match unsafe { |
| 106 | + optee_teec::PluginParameters::from_raw( |
| 107 | + cmd, |
| 108 | + sub_cmd, |
| 109 | + data as *mut c_char, |
| 110 | + in_len, |
| 111 | + out_len, |
| 112 | + ) |
| 113 | + } { |
| 114 | + Ok(v) => v, |
| 115 | + Err(err) => return err.raw_code(), |
| 116 | + }; |
| 117 | + |
| 118 | + match #invoke_fn_name(&mut parameter) { |
| 119 | + Ok(()) => TEEC_SUCCESS, |
| 120 | + Err(err) => err.raw_code(), |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + static PLUGIN_NAME: &str = #name_bytes_with_null; |
| 125 | + |
| 126 | + #[unsafe(no_mangle)] |
| 127 | + pub static mut plugin_method: PluginMethod = PluginMethod { |
| 128 | + name: PLUGIN_NAME.as_ptr() as *const _, |
| 129 | + uuid: TEEC_UUID { |
| 130 | + timeLow: #uuid_f1, |
| 131 | + timeMid: #uuid_f2, |
| 132 | + timeHiAndVersion: #uuid_f3, |
| 133 | + clockSeqAndNode: [#(#uuid_f4),*], |
| 134 | + }, |
| 135 | + init: __plugin_init, |
| 136 | + invoke: __plugin_invoke, |
| 137 | + }; |
| 138 | + }; |
| 139 | + } |
| 140 | +} |
0 commit comments