1use consortium_macros_helpers::{
18 get_output_type, is_context_ref, is_mut_tee_param_ref, is_primitive, is_result_returning,
19 is_slice_ref, is_tee_param_path, is_tuple_u32_u32, is_vec_u8, mut_scalar_inner,
20};
21use heck::ToPascalCase;
22use proc_macro2::{Span, TokenStream as TokenStream2};
23use quote::quote;
24use syn::{Ident, ItemFn, LitInt, PatType, Token};
25
26struct TeeArgs {
28 pub codec: Option<syn::Path>,
29 pub ctx: Option<CtxArg>,
30}
31
32enum CtxArg {
33 First(Ident),
34 Ident(Ident),
35 Index(LitInt),
36}
37
38impl syn::parse::Parse for TeeArgs {
39 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
40 let mut codec = None;
41 let mut ctx = None;
42
43 while !input.is_empty() {
44 let ident: Ident = input.parse()?;
45 if ident == "codec" {
46 if codec.is_some() {
47 return Err(syn::Error::new(ident.span(), "duplicate `codec` argument"));
48 }
49 let _eq: Token![=] = input.parse()?;
50 codec = Some(input.parse()?);
51 } else if ident == "ctx" {
52 if ctx.is_some() {
53 return Err(syn::Error::new(ident.span(), "duplicate `ctx` argument"));
54 }
55 ctx = if input.peek(Token![=]) {
56 let _eq: Token![=] = input.parse()?;
57 if input.peek(LitInt) {
58 Some(CtxArg::Index(input.parse()?))
59 } else {
60 Some(CtxArg::Ident(input.parse()?))
61 }
62 } else {
63 Some(CtxArg::First(ident))
64 };
65 } else {
66 return Err(syn::Error::new(ident.span(), "expected `codec` or `ctx`"));
67 }
68
69 if input.is_empty() {
70 break;
71 }
72 input.parse::<Token![,]>()?;
73 }
74
75 Ok(TeeArgs { codec, ctx })
76 }
77}
78
79pub fn tee_command(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
124 let TeeArgs { codec, ctx } = match syn::parse2::<TeeArgs>(attr) {
125 Ok(args) => args,
126 Err(err) => return err.into_compile_error(),
127 };
128
129 let codec_ty: TokenStream2 = match &codec {
131 Some(c) => quote! { #c },
132 None => quote! { ::consortium_tee::NoCodec },
133 };
134
135 let input = match syn::parse2::<ItemFn>(item) {
136 Ok(input) => input,
137 Err(err) => return err.into_compile_error(),
138 };
139 let fn_name = &input.sig.ident;
140 let dispatched_name = Ident::new(&format!("{}_dispatched", fn_name), fn_name.span());
141 let call_name = Ident::new(&format!("call_{}", fn_name), fn_name.span());
142
143 let parameters: Vec<&PatType> = input
144 .sig
145 .inputs
146 .iter()
147 .filter_map(|arg| {
148 if let syn::FnArg::Typed(pt) = arg {
149 Some(pt)
150 } else {
151 None
152 }
153 })
154 .collect();
155
156 let (ctx_index, ctx_warning) = match resolve_context_index(ctx.as_ref(), ¶meters) {
157 Ok(resolved) => resolved,
158 Err(err) => return err.into_compile_error(),
159 };
160 let ctx_param = ctx_index.map(|index| parameters[index]);
161 let tee_params: Vec<&PatType> = parameters
162 .iter()
163 .enumerate()
164 .filter_map(|(index, param)| (Some(index) != ctx_index).then_some(*param))
165 .collect();
166
167 let output_ty: Option<&syn::Type> = get_output_type(&input.sig.output);
169 let has_output = output_ty.is_some();
170 let ret_is_result = is_result_returning(&input.sig.output);
171
172 let mut slot_index = 0usize;
174 let mut unpack_stmts = vec![];
175 let mut post_call_stmts = vec![];
176 let mut dispatch_call_args = vec![];
177
178 for (param_index, param) in parameters.iter().enumerate() {
179 let pat = ¶m.pat;
180 let ty = ¶m.ty;
181 if Some(param_index) == ctx_index {
182 dispatch_call_args.push(quote! { #pat });
183 continue;
184 }
185 let (unpack, post, next) = gen_unpack(pat, ty, slot_index, &codec_ty);
186 unpack_stmts.push(unpack);
187 if let Some(p) = post {
188 post_call_stmts.push(p);
189 }
190 dispatch_call_args.push(quote! { #pat });
191 slot_index = next;
192 }
193
194 let output_slot = slot_index;
196
197 let call_and_flush = if let Some(out_ty) = output_ty {
199 let flush = gen_flush_ta(output_slot, out_ty, &codec_ty);
200 if ret_is_result {
201 quote! {
202 let __ret_val = #fn_name(#(#dispatch_call_args),*)?;
203 #(#post_call_stmts)*
204 #flush
205 Ok(())
206 }
207 } else {
208 quote! {
209 let __ret_val = #fn_name(#(#dispatch_call_args),*);
210 #(#post_call_stmts)*
211 #flush
212 Ok(())
213 }
214 }
215 } else if !post_call_stmts.is_empty() {
216 if ret_is_result {
217 quote! {
218 #fn_name(#(#dispatch_call_args),*)?;
219 #(#post_call_stmts)*
220 Ok(())
221 }
222 } else {
223 quote! {
224 #fn_name(#(#dispatch_call_args),*);
225 #(#post_call_stmts)*
226 Ok(())
227 }
228 }
229 } else {
230 quote! { #fn_name(#(#dispatch_call_args),*) }
231 };
232
233 let param_binding = if !tee_params.is_empty() || has_output {
234 quote! { params }
235 } else {
236 quote! { _params }
237 };
238
239 let dispatched_fn = if let Some(ctx) = ctx_param {
243 let ctx_pat = &ctx.pat;
244 let ctx_ty = &ctx.ty;
245 quote! {
246 #[cfg(feature = "ta")]
247 fn #dispatched_name(#ctx_pat: #ctx_ty, #param_binding: &mut ::optee_utee::Parameters) -> ::optee_utee::Result<()> {
248 #(#unpack_stmts)*
249 #call_and_flush
250 }
251 }
252 } else {
253 quote! {
254 #[cfg(feature = "ta")]
255 fn #dispatched_name(#param_binding: &mut ::optee_utee::Parameters) -> ::optee_utee::Result<()> {
256 #(#unpack_stmts)*
257 #call_and_flush
258 }
259 }
260 };
261
262 let mut pack_stmts = vec![];
264 let mut post_invoke_stmts = vec![];
265 let mut ca_sig_args = vec![];
266 let mut new_params_args = vec![];
267
268 for (i, param) in tee_params.iter().enumerate() {
269 let pat = ¶m.pat;
270 let ty = ¶m.ty;
271 let slot_ident = Ident::new(&format!("_p{}", i), Span::call_site());
272 ca_sig_args.push(quote! { #pat: #ty });
273 let (pack, post) = gen_pack_ca(&slot_ident, pat, ty, i, &codec_ty);
274 pack_stmts.push(pack);
275 if let Some(p) = post {
276 post_invoke_stmts.push(p);
277 }
278 new_params_args.push(quote! { #slot_ident });
279 }
280
281 if has_output {
282 let out_ty = output_ty.unwrap();
283 let out_slot = tee_params.len();
284 let slot_ident = Ident::new(&format!("_p{}", out_slot), Span::call_site());
285 pack_stmts.push(gen_output_pack_ca(&slot_ident, out_ty, out_slot, &codec_ty));
286 new_params_args.push(quote! { #slot_ident });
287 }
288
289 while new_params_args.len() < 4 {
290 new_params_args.push(quote! { ::optee_teec::ParamNone });
291 }
292
293 let command_variant = Ident::new(&fn_name.to_string().to_pascal_case(), fn_name.span());
294
295 let ca_fn = if has_output {
297 let out_ty = output_ty.unwrap();
298 let read_back = gen_output_read_ca(tee_params.len(), out_ty, &codec_ty);
299 quote! {
300 #[cfg(feature = "ca")]
301 pub fn #call_name(session: &mut ::optee_teec::Session, #(#ca_sig_args),*) -> ::consortium_tee::TeeResult<#out_ty> {
302 #(#pack_stmts)*
303 let mut _operation = ::optee_teec::Operation::new(0, #(#new_params_args),*);
304 session.invoke_command(Command::#command_variant as u32, &mut _operation)?;
305 #(#post_invoke_stmts)*
306 Ok(#read_back)
307 }
308 }
309 } else if !post_invoke_stmts.is_empty() {
310 quote! {
311 #[cfg(feature = "ca")]
312 pub fn #call_name(session: &mut ::optee_teec::Session, #(#ca_sig_args),*) -> ::consortium_tee::TeeResult<()> {
313 #(#pack_stmts)*
314 let mut _operation = ::optee_teec::Operation::new(0, #(#new_params_args),*);
315 session.invoke_command(Command::#command_variant as u32, &mut _operation)?;
316 #(#post_invoke_stmts)*
317 Ok(())
318 }
319 }
320 } else {
321 quote! {
322 #[cfg(feature = "ca")]
323 pub fn #call_name(session: &mut ::optee_teec::Session, #(#ca_sig_args),*) -> ::consortium_tee::TeeResult<()> {
324 #(#pack_stmts)*
325 let mut _operation = ::optee_teec::Operation::new(0, #(#new_params_args),*);
326 session.invoke_command(Command::#command_variant as u32, &mut _operation)?;
327 Ok(())
328 }
329 }
330 };
331
332 quote! {
333 #input
334 #ctx_warning
335 #dispatched_fn
336 #ca_fn
337 }
338}
339
340fn resolve_context_index(
341 ctx: Option<&CtxArg>,
342 parameters: &[&PatType],
343) -> syn::Result<(Option<usize>, TokenStream2)> {
344 let Some(ctx) = ctx else {
345 return Ok((None, quote! {}));
346 };
347
348 let (index, warning) = match ctx {
349 CtxArg::First(ident) => {
350 if parameters.is_empty() {
351 return Err(syn::Error::new(
352 ident.span(),
353 "`ctx` requires a first parameter to use as context",
354 ));
355 }
356 (0, quote! {})
357 }
358 CtxArg::Ident(ident) => {
359 let index = parameters
360 .iter()
361 .position(|param| {
362 if let syn::Pat::Ident(pat_ident) = param.pat.as_ref() {
363 pat_ident.ident == *ident
364 } else {
365 false
366 }
367 })
368 .ok_or_else(|| {
369 syn::Error::new(
370 ident.span(),
371 format!("could not find context parameter `{ident}`"),
372 )
373 })?;
374 (index, gen_deprecated_ctx_value_warning(index))
375 }
376 CtxArg::Index(lit) => {
377 let index = lit.base10_parse::<usize>()?;
378 if index >= parameters.len() {
379 return Err(syn::Error::new(
380 lit.span(),
381 format!("context parameter index {index} is out of range"),
382 ));
383 }
384 (index, gen_deprecated_ctx_value_warning(index))
385 }
386 };
387
388 let param = parameters[index];
389 if !is_context_ref(¶m.ty) {
390 return Err(syn::Error::new_spanned(
391 ¶m.ty,
392 "`ctx` parameter must have type `&mut SomePath`",
393 ));
394 }
395
396 Ok((Some(index), warning))
397}
398
399fn gen_deprecated_ctx_value_warning(index: usize) -> TokenStream2 {
400 if index == 0 {
401 quote! {
402 const _: () = {
403 #[deprecated(
404 note = "`#[tee_command(ctx = ...)]` is accepted for compatibility; prefer bare `ctx`"
405 )]
406 const __TEE_COMMAND_CTX_VALUE_WARNING: () = ();
407 __TEE_COMMAND_CTX_VALUE_WARNING
408 };
409 }
410 } else {
411 quote! {
412 const _: () = {
413 #[deprecated(
414 note = "`#[tee_command(ctx = ...)]` is accepted for compatibility; move the context to the first parameter and use bare `ctx`"
415 )]
416 const __TEE_COMMAND_CTX_VALUE_WARNING: () = ();
417 __TEE_COMMAND_CTX_VALUE_WARNING
418 };
419 }
420 }
421}
422
423fn gen_unpack(
427 pat: &syn::Pat,
428 ty: &syn::Type,
429 slot: usize,
430 codec: &TokenStream2,
431) -> (TokenStream2, Option<TokenStream2>, usize) {
432 if slot >= 4 {
433 return (
434 quote! { compile_error!("Too many parameters: TEE only supports up to 4"); },
435 None,
436 slot,
437 );
438 }
439 let idx = syn::Index::from(slot);
440 let tmp = Ident::new(&format!("__p_{}", slot), Span::call_site());
441
442 if is_slice_ref(ty, false) {
444 let stmt = quote! {
445 let mut #tmp = unsafe { params.#idx.as_memref()? };
447 let #pat: &[u8] = #tmp.buffer();
448 };
449 return (stmt, None, slot + 1);
450 }
451
452 if is_slice_ref(ty, true) {
454 let stmt = quote! {
455 let mut #tmp = unsafe { params.#idx.as_memref()? };
457 let #pat: &mut [u8] = #tmp.buffer();
458 };
459 return (stmt, None, slot + 1);
460 }
461
462 if let Some(scalar) = mut_scalar_inner(ty) {
464 let val_tmp = Ident::new(&format!("__val_{}", slot), Span::call_site());
465 let (unpack_stmt, flush_stmt) = match scalar {
466 "u32" => {
467 let u = quote! {
468 let mut #tmp = unsafe { params.#idx.as_value()? };
470 let mut #val_tmp: u32 = #tmp.a();
471 let #pat: &mut u32 = &mut #val_tmp;
472 };
473 let f = quote! {
474 #tmp.set_a(*#pat);
476 };
477 (u, f)
478 }
479 "i32" => {
480 let u = quote! {
481 let mut #tmp = unsafe { params.#idx.as_value()? };
483 let mut #val_tmp: i32 = #tmp.a() as i32;
484 let #pat: &mut i32 = &mut #val_tmp;
485 };
486 let f = quote! {
487 #tmp.set_a(*#pat as u32);
489 };
490 (u, f)
491 }
492 "u64" => {
493 let u = quote! {
494 let mut #tmp = unsafe { params.#idx.as_value()? };
496 let mut #val_tmp: u64 = (#tmp.b() as u64) << 32 | #tmp.a() as u64;
497 let #pat: &mut u64 = &mut #val_tmp;
498 };
499 let f = quote! {
500 #tmp.set_a(*#pat as u32);
502 #tmp.set_b((*#pat >> 32) as u32);
503 };
504 (u, f)
505 }
506 _ => unreachable!(),
507 };
508 return (unpack_stmt, Some(flush_stmt), slot + 1);
509 }
510
511 if is_mut_tee_param_ref(ty) {
513 let inner_ty = if let syn::Type::Reference(r) = ty {
514 r.elem.as_ref()
515 } else {
516 unreachable!()
517 };
518 let val_tmp = Ident::new(&format!("__val_{}", slot), Span::call_site());
519 let repr_flush = Ident::new(&format!("__repr_flush_{}", slot), Span::call_site());
520 let flush_bytes = Ident::new(&format!("__flush_bytes_{}", slot), Span::call_site());
521 let unpack = quote! {
522 let mut #tmp = unsafe { params.#idx.as_memref()? };
524 let mut #val_tmp: #inner_ty =
525 <#inner_ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
526 ::consortium_tee::TeeParamSlot::Serialized(#tmp.buffer())
527 ).map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
528 let #pat: &mut #inner_ty = &mut #val_tmp;
529 };
530 let flush = quote! {
531 let #repr_flush =
533 <#inner_ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(&#val_tmp)
534 .map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
535 let ::consortium_tee::TeeParamSlot::Serialized(ref #flush_bytes) = #repr_flush
536 else { unreachable!() };
537 #tmp.buffer()[..#flush_bytes.len()].copy_from_slice(#flush_bytes.as_slice());
538 };
539 return (unpack, Some(flush), slot + 1);
540 }
541
542 let is_value_slot = is_primitive(ty, "u8")
546 || is_primitive(ty, "u16")
547 || is_primitive(ty, "u32")
548 || is_primitive(ty, "u64")
549 || is_primitive(ty, "i8")
550 || is_primitive(ty, "i16")
551 || is_primitive(ty, "i32")
552 || is_primitive(ty, "i64")
553 || is_primitive(ty, "bool")
554 || is_tuple_u32_u32(ty);
555
556 if is_value_slot {
557 let stmt = quote! {
558 let mut #tmp = unsafe { params.#idx.as_value()? };
560 let #pat = <#ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
561 ::consortium_tee::TeeParamSlot::Primitive { a: #tmp.a(), b: #tmp.b() }
562 ).map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
563 };
564 return (stmt, None, slot + 1);
565 }
566
567 if is_vec_u8(ty) || is_tee_param_path(ty) {
569 let stmt = quote! {
570 let mut #tmp = unsafe { params.#idx.as_memref()? };
572 let #pat = <#ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
573 ::consortium_tee::TeeParamSlot::Serialized(#tmp.buffer())
574 ).map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
575 };
576 return (stmt, None, slot + 1);
577 }
578
579 (
580 quote! { compile_error!("Unsupported TEE parameter type"); },
581 None,
582 slot,
583 )
584}
585
586fn gen_flush_ta(slot: usize, ty: &syn::Type, codec: &TokenStream2) -> TokenStream2 {
588 if slot >= 4 {
589 return quote! { compile_error!("Too many parameters: no room for the output slot (TEE max 4)"); };
590 }
591 let idx = syn::Index::from(slot);
592
593 let is_value_slot = is_primitive(ty, "u8")
594 || is_primitive(ty, "u16")
595 || is_primitive(ty, "u32")
596 || is_primitive(ty, "u64")
597 || is_primitive(ty, "i8")
598 || is_primitive(ty, "i16")
599 || is_primitive(ty, "i32")
600 || is_primitive(ty, "i64")
601 || is_primitive(ty, "bool")
602 || is_tuple_u32_u32(ty);
603
604 if is_value_slot {
605 return quote! {
606 let mut __p_out = unsafe { params.#idx.as_value()? };
608 let __repr_out = <#ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(&__ret_val)
609 .map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
610 let ::consortium_tee::TeeParamSlot::Primitive { a: __pa_out, b: __pb_out } = __repr_out
611 else { unreachable!() };
612 __p_out.set_a(__pa_out);
613 __p_out.set_b(__pb_out);
614 };
615 }
616
617 if is_vec_u8(ty) || is_tee_param_path(ty) {
619 return quote! {
620 let mut __p_out = unsafe { params.#idx.as_memref()? };
622 let __repr_out = <#ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(&__ret_val)
623 .map_err(|_| ::optee_utee::Error::new(::optee_utee::ErrorKind::BadParameters))?;
624 let ::consortium_tee::TeeParamSlot::Serialized(ref __out_bytes) = __repr_out
625 else { unreachable!() };
626 __p_out.buffer()[..__out_bytes.len()].copy_from_slice(__out_bytes.as_slice());
627 };
628 }
629
630 quote! { compile_error!("Unsupported TEE return type"); }
631}
632
633fn gen_pack_ca(
637 slot_ident: &Ident,
638 pat: &syn::Pat,
639 ty: &syn::Type,
640 slot: usize,
641 codec: &TokenStream2,
642) -> (TokenStream2, Option<TokenStream2>) {
643 if is_slice_ref(ty, false) {
645 return (
646 quote! { let #slot_ident = ::optee_teec::ParamTmpRef::new_input(#pat); },
647 None,
648 );
649 }
650
651 if is_slice_ref(ty, true) {
653 return (
654 quote! { let #slot_ident = ::optee_teec::ParamTmpRef::new_inout(#pat); },
655 None,
656 );
657 }
658
659 if let Some(scalar) = mut_scalar_inner(ty) {
661 let slot_idx = syn::Index::from(slot);
662 let (pack, read_back) = match scalar {
663 "u32" => (
664 quote! { let #slot_ident = ::optee_teec::ParamValue::new(*#pat, 0, ::optee_teec::ParamType::ValueInout); },
665 quote! { *#pat = _operation.parameters().#slot_idx.a(); },
666 ),
667 "i32" => (
668 quote! { let #slot_ident = ::optee_teec::ParamValue::new(*#pat as u32, 0, ::optee_teec::ParamType::ValueInout); },
669 quote! { *#pat = _operation.parameters().#slot_idx.a() as i32; },
670 ),
671 "u64" => (
672 quote! { let #slot_ident = ::optee_teec::ParamValue::new(*#pat as u32, (*#pat >> 32) as u32, ::optee_teec::ParamType::ValueInout); },
673 quote! {
674 *#pat = (_operation.parameters().#slot_idx.b() as u64) << 32
675 | _operation.parameters().#slot_idx.a() as u64;
676 },
677 ),
678 _ => unreachable!(),
679 };
680 return (pack, Some(read_back));
681 }
682
683 if is_mut_tee_param_ref(ty) {
685 let inner_ty = if let syn::Type::Reference(r) = ty {
686 r.elem.as_ref()
687 } else {
688 unreachable!()
689 };
690 let buf_ident = Ident::new(&format!("__inout_buf_{}", slot), Span::call_site());
691 let repr_ident = Ident::new(&format!("__repr_inout_{}", slot), Span::call_site());
692 let src_ident = Ident::new(&format!("__src_inout_{}", slot), Span::call_site());
693 let slot_idx = syn::Index::from(slot);
694 let pack = quote! {
695 let mut #buf_ident = vec![0u8; <#inner_ty as ::consortium_tee::TeeParam<#codec>>::MAX_SIZE];
696 let #repr_ident = <#inner_ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(#pat)
697 .map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?;
698 let ::consortium_tee::TeeParamSlot::Serialized(ref #src_ident) = #repr_ident
699 else { unreachable!() };
700 #buf_ident[..#src_ident.len()].copy_from_slice(#src_ident.as_slice());
701 let #slot_ident = ::optee_teec::ParamTmpRef::new_inout(&mut #buf_ident);
702 };
703 let read_back = quote! {
704 *#pat = {
705 let __updated_size = _operation.parameters().#slot_idx.updated_size();
706 <#inner_ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
707 ::consortium_tee::TeeParamSlot::Serialized(&#buf_ident[..__updated_size])
708 ).map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?
709 };
710 };
711 return (pack, Some(read_back));
712 }
713
714 let is_value_slot = is_primitive(ty, "u8")
716 || is_primitive(ty, "u16")
717 || is_primitive(ty, "u32")
718 || is_primitive(ty, "u64")
719 || is_primitive(ty, "i8")
720 || is_primitive(ty, "i16")
721 || is_primitive(ty, "i32")
722 || is_primitive(ty, "i64")
723 || is_primitive(ty, "bool")
724 || is_tuple_u32_u32(ty);
725
726 if is_value_slot {
727 let repr_ident = Ident::new(&format!("__repr_{}", slot), Span::call_site());
728 let pa_ident = Ident::new(&format!("__pa_{}", slot), Span::call_site());
729 let pb_ident = Ident::new(&format!("__pb_{}", slot), Span::call_site());
730 let pack = quote! {
731 let #repr_ident = <#ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(&#pat)
732 .map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?;
733 let ::consortium_tee::TeeParamSlot::Primitive { a: #pa_ident, b: #pb_ident } = #repr_ident
734 else { unreachable!() };
735 let #slot_ident = ::optee_teec::ParamValue::new(#pa_ident, #pb_ident, ::optee_teec::ParamType::ValueInput);
736 };
737 return (pack, None);
738 }
739
740 if is_vec_u8(ty) || is_tee_param_path(ty) {
742 let repr_ident = Ident::new(&format!("__repr_{}", slot), Span::call_site());
743 let bytes_ident = Ident::new(&format!("__bytes_{}", slot), Span::call_site());
744 let pack = quote! {
745 let #repr_ident = <#ty as ::consortium_tee::TeeParam<#codec>>::into_tee_param(&#pat)
746 .map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?;
747 let ::consortium_tee::TeeParamSlot::Serialized(ref #bytes_ident) = #repr_ident
748 else { unreachable!() };
749 let #slot_ident = ::optee_teec::ParamTmpRef::new_input(#bytes_ident.as_slice());
750 };
751 return (pack, None);
752 }
753
754 (
755 quote! {
756 let #slot_ident = ::optee_teec::ParamNone;
757 compile_error!("Unsupported TEE parameter type");
758 },
759 None,
760 )
761}
762
763fn gen_output_pack_ca(
765 slot_ident: &Ident,
766 ty: &syn::Type,
767 slot: usize,
768 codec: &TokenStream2,
769) -> TokenStream2 {
770 let is_value_slot = is_primitive(ty, "u8")
771 || is_primitive(ty, "u16")
772 || is_primitive(ty, "u32")
773 || is_primitive(ty, "u64")
774 || is_primitive(ty, "i8")
775 || is_primitive(ty, "i16")
776 || is_primitive(ty, "i32")
777 || is_primitive(ty, "i64")
778 || is_primitive(ty, "bool")
779 || is_tuple_u32_u32(ty);
780
781 if is_value_slot {
782 return quote! { let #slot_ident = ::optee_teec::ParamValue::new(0, 0, ::optee_teec::ParamType::ValueOutput); };
783 }
784
785 if is_vec_u8(ty) || is_tee_param_path(ty) {
786 let buf_ident = Ident::new(&format!("__out_buf_{}", slot), Span::call_site());
787 return quote! {
788 let mut #buf_ident = vec![0u8; <#ty as ::consortium_tee::TeeParam<#codec>>::MAX_SIZE];
789 let #slot_ident = ::optee_teec::ParamTmpRef::new_output(&mut #buf_ident);
790 };
791 }
792
793 quote! { compile_error!("Unsupported TEE return type for output parameter"); }
794}
795
796fn gen_output_read_ca(slot: usize, ty: &syn::Type, codec: &TokenStream2) -> TokenStream2 {
798 let slot_idx = syn::Index::from(slot);
799 let buf_ident = Ident::new(&format!("__out_buf_{}", slot), Span::call_site());
800
801 let is_value_slot = is_primitive(ty, "u8")
802 || is_primitive(ty, "u16")
803 || is_primitive(ty, "u32")
804 || is_primitive(ty, "u64")
805 || is_primitive(ty, "i8")
806 || is_primitive(ty, "i16")
807 || is_primitive(ty, "i32")
808 || is_primitive(ty, "i64")
809 || is_primitive(ty, "bool")
810 || is_tuple_u32_u32(ty);
811
812 if is_value_slot {
813 return quote! {
814 {
815 let __v = _operation.parameters().#slot_idx;
816 <#ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
817 ::consortium_tee::TeeParamSlot::Primitive { a: __v.a(), b: __v.b() }
818 ).map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?
819 }
820 };
821 }
822
823 if is_vec_u8(ty) || is_tee_param_path(ty) {
824 return quote! {
828 {
829 let __updated_size = _operation.parameters().#slot_idx.updated_size();
830 <#ty as ::consortium_tee::TeeParam<#codec>>::from_tee_param(
831 ::consortium_tee::TeeParamSlot::Serialized(&#buf_ident[..__updated_size])
832 ).map_err(|_| ::consortium_tee::TeeError::ParamMismatch)?
833 }
834 };
835 }
836
837 quote! { compile_error!("Unsupported TEE return type") }
838}