1use std::fs;
6use std::iter;
7use std::path::PathBuf;
8
9use crate::cbor;
10use crate::codegen::Codegen;
11use anyhow::{Context, Result, bail};
12use heck::{ToShoutySnakeCase, ToUpperCamelCase};
13use indexmap::IndexMap;
14use itertools::Itertools;
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
18#[serde(deny_unknown_fields)]
19pub struct CwtTemplate {
20 pub name: String,
22 pub variables: IndexMap<String, TemplateVariable>,
24 pub constants: IndexMap<String, TemplateConstant>,
26 pub structure: TemplateStructure,
28}
29
30#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
31#[serde(rename_all = "kebab-case")]
32pub enum VariableSize {
33 MaxSize(u64),
35 ExactSize(u64),
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
40#[serde(rename_all = "kebab-case")]
41pub enum VariableType {
42 ByteArray,
44 String,
46 Integer,
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
52#[serde(tag = "type", rename_all = "kebab-case")]
53pub enum TemplateVariable {
54 ByteArray {
56 #[serde(flatten)]
57 size: VariableSize,
58 },
59 String {
61 #[serde(flatten)]
62 size: VariableSize,
63 },
64 Integer,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
70#[serde(tag = "type", rename_all = "kebab-case")]
71pub enum TemplateConstant {
72 ByteArray {
74 #[serde(with = "hex::serde")]
76 value: Vec<u8>,
77 },
78 String { value: String },
80 Integer { value: i64 },
82}
83
84#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
86#[serde(untagged)]
87pub enum TemplateStructure {
88 #[serde(rename_all = "kebab-case")]
90 CborByteArray {
91 cbor_byte_array: Box<TemplateStructure>,
92 },
93 Item(String),
95 Map(IndexMap<String, TemplateStructure>),
97 Array(Vec<TemplateStructure>),
99}
100
101#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
103struct CodegenVar {
104 name: String,
105 size: VariableSize,
106 value: CodegenVarValue,
107}
108
109type CodegenVarTable = IndexMap<String, CodegenVar>;
110
111#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
112enum CodegenVarValue {
113 ByteArray(Option<Vec<u8>>),
114 String(Option<String>),
115 Integer(Option<i64>),
116}
117
118impl CodegenVar {
119 fn from_template_variable(name: &str, var: &TemplateVariable) -> Result<Self> {
120 let name = name.to_owned();
121 let (size, value) = match var {
122 TemplateVariable::ByteArray { size } => (*size, CodegenVarValue::ByteArray(None)),
123 TemplateVariable::String { size } => (*size, CodegenVarValue::String(None)),
124 TemplateVariable::Integer => (VariableSize::MaxSize(8), CodegenVarValue::Integer(None)),
125 };
126
127 Ok(Self { name, size, value })
128 }
129
130 fn from_template_constant(name: &str, var: &TemplateConstant) -> Result<Self> {
131 let name = name.to_owned();
132 let (value, size) = match var {
133 TemplateConstant::ByteArray { value } => (
134 CodegenVarValue::ByteArray(Some(value.clone())),
135 VariableSize::ExactSize(value.len().try_into().with_context(|| {
136 format!("the size of {name} is too large for u64: {}", value.len())
137 })?),
138 ),
139 TemplateConstant::String { value } => (
140 CodegenVarValue::String(Some(value.clone())),
141 VariableSize::ExactSize(value.len().try_into().with_context(|| {
142 format!("the size of {name} is too large for u64: {}", value.len())
143 })?),
144 ),
145 TemplateConstant::Integer { value } => {
146 let arg = if *value >= 0 { *value } else { -(*value + 1) } as u64;
147 (
148 CodegenVarValue::Integer(Some(*value)),
149 VariableSize::ExactSize(cbor::arg_size(arg).0),
150 )
151 }
152 };
153
154 Ok(Self { name, size, value })
155 }
156
157 fn is_constant(&self) -> bool {
158 match &self.value {
159 CodegenVarValue::ByteArray(v) => v.is_some(),
160 CodegenVarValue::String(v) => v.is_some(),
161 CodegenVarValue::Integer(v) => v.is_some(),
162 }
163 }
164
165 fn variable_type(&self) -> VariableType {
166 match &self.value {
167 CodegenVarValue::ByteArray(_) => VariableType::ByteArray,
168 CodegenVarValue::String(_) => VariableType::String,
169 CodegenVarValue::Integer(_) => VariableType::Integer,
170 }
171 }
172
173 fn declarations(&self, prefix: &str) -> String {
175 assert!(!self.is_constant());
176
177 match self.value {
178 CodegenVarValue::ByteArray(_) => {
179 indoc::formatdoc! { r#"
180 {prefix}uint8_t *{name};
181 {prefix}size_t {name}_size;
182 "#,
183 name = self.name
184 }
185 }
186 CodegenVarValue::String(_) => {
187 indoc::formatdoc! { r#"
188 {prefix}char *{name};
189 {prefix}size_t {name}_size;
190 "#,
191 name = self.name
192 }
193 }
194 CodegenVarValue::Integer(_) => indoc::formatdoc! { r#"
195 {prefix}int64_t {name};
196 "#,
197 name = self.name
198 },
199 }
200 }
201
202 fn value_expression(&self) -> String {
204 assert!(!self.is_constant());
205 format!("values->{}", self.name)
206 }
207
208 fn size_expression(&self) -> String {
210 assert!(!self.is_constant());
211 if self.variable_type() != VariableType::Integer {
212 format!("values->{}_size", self.name)
213 } else {
214 format!("cbor_calc_int_size(values->{})", self.name)
215 }
216 }
217}
218
219#[derive(Clone, Debug, PartialEq, Eq)]
222enum CodegenStructure<'a> {
223 Var(&'a CodegenVar),
224 CborByteArray(usize),
225 Map(Vec<(usize, usize)>),
226 Array(Vec<usize>),
227}
228
229impl CodegenStructure<'_> {
230 fn from_template<'a>(
231 template: &CwtTemplate,
232 vars: &'a CodegenVarTable,
233 ) -> Result<Vec<CodegenStructure<'a>>> {
234 let mut nodes = Vec::<CodegenStructure>::new();
235 let mut id_mapping = IndexMap::<String, usize>::new();
236 Self::build_codegen_structure(&template.structure, vars, &mut nodes, &mut id_mapping)
237 .context("build_codegen_structure failed")?;
238 Ok(nodes)
239 }
240
241 fn build_codegen_structure<'a>(
245 cur: &TemplateStructure,
246 vars: &'a CodegenVarTable,
247 nodes: &mut Vec<CodegenStructure<'a>>,
248 var_ids: &mut IndexMap<String, usize>,
249 ) -> Result<usize> {
250 let node = match cur {
251 TemplateStructure::Item(name) => {
252 let var = vars
253 .get(name)
254 .with_context(|| format!("cannot find item {name} in template"))?;
255 CodegenStructure::Var(var)
256 }
257 TemplateStructure::CborByteArray { cbor_byte_array } => {
258 let inner = Self::build_codegen_structure(cbor_byte_array, vars, nodes, var_ids)?;
259 CodegenStructure::CborByteArray(inner)
260 }
261 TemplateStructure::Map(items) => {
262 let mut pairs = Vec::new();
263 for (k, v) in items {
264 let item = TemplateStructure::Item(k.clone());
265 let first = Self::build_codegen_structure(&item, vars, nodes, var_ids)?;
266 let second = Self::build_codegen_structure(v, vars, nodes, var_ids)?;
267 pairs.push((first, second));
268 }
269 CodegenStructure::Map(pairs)
270 }
271 TemplateStructure::Array(items) => {
272 let mut values = Vec::new();
273 for item in items {
274 let value = Self::build_codegen_structure(item, vars, nodes, var_ids)?;
275 values.push(value);
276 }
277 CodegenStructure::Array(values)
278 }
279 };
280
281 if let CodegenStructure::Var(var) = node {
282 if var_ids.contains_key(&var.name) {
284 Ok(var_ids[&var.name])
288 } else {
289 let idx = nodes.len();
291 nodes.push(node);
292 var_ids.insert(var.name.clone(), idx);
293 Ok(idx)
294 }
295 } else {
296 let idx = nodes.len();
298 nodes.push(node);
299 Ok(idx)
300 }
301 }
302}
303
304#[derive(Clone, Debug, PartialEq, Eq)]
351struct SizeExpression<'a> {
352 index: usize,
353 arg_size: ArgSize,
354 constant: u64,
355 dependencies: SizeDependency<'a>,
356}
357
358#[derive(Clone, Debug, PartialEq, Eq)]
359enum ArgSize {
360 Constant(u64),
362 LengthOfContentSize,
364}
365
366#[derive(Clone, Debug, PartialEq, Eq)]
367enum SizeDependency<'a> {
368 Var(&'a CodegenVar),
369 SubItemSize(Vec<usize>),
370}
371
372impl SizeExpression<'_> {
373 fn from_codegenvar(index: usize, arg_size: ArgSize, var: &CodegenVar) -> SizeExpression<'_> {
375 SizeExpression {
376 index,
377 arg_size,
378 constant: 0,
379 dependencies: SizeDependency::Var(var),
380 }
381 }
382
383 fn empty_dependency(index: usize, arg_size: ArgSize, constant: u64) -> Self {
385 SizeExpression {
386 index,
387 arg_size,
388 constant,
389 dependencies: SizeDependency::SubItemSize(vec![]),
390 }
391 }
392
393 fn add_constant(&mut self, constant: u64) {
394 self.constant += constant;
395 }
396
397 fn add_dependency(&mut self, index: usize) {
398 if let SizeDependency::SubItemSize(deps) = &mut self.dependencies {
399 deps.push(index);
400 } else {
401 panic!(
402 "add_dependency should be only called on SizeExpression with SubItemSize dependency."
403 )
404 }
405 }
406
407 fn is_constant(&self) -> bool {
408 match &self.dependencies {
409 SizeDependency::Var(_) => false,
410 SizeDependency::SubItemSize(items) => items.is_empty(),
411 }
412 }
413
414 fn content_size(&self) -> u64 {
415 assert!(self.is_constant());
416 self.constant
417 }
418
419 fn item_size(&self) -> u64 {
420 assert!(self.is_constant());
421 match self.arg_size {
422 ArgSize::Constant(arg) => 1 + arg + self.constant,
423 ArgSize::LengthOfContentSize => 1 + cbor::arg_size(self.constant).0 + self.constant,
424 }
425 }
426
427 fn content_size_expression(&self) -> String {
429 let mut terms = Vec::new();
430
431 if self.constant > 0 {
432 terms.push(self.constant.to_string());
433 }
434
435 match &self.dependencies {
436 SizeDependency::Var(var) => terms.push(var.size_expression()),
437 SizeDependency::SubItemSize(items) => {
438 terms.extend(items.iter().map(|idx| format!("item_size_{idx}")))
439 }
440 };
441
442 terms.join(" + ")
443 }
444
445 fn item_size_expression(&self) -> String {
448 if self.is_constant() {
449 self.item_size().to_string()
450 } else {
451 match &self.arg_size {
452 ArgSize::Constant(arg) => {
453 format!("{k} + content_size_{idx}", k = 1 + arg, idx = self.index)
454 }
455 ArgSize::LengthOfContentSize => format!(
456 "1 + cbor_calc_arg_size(content_size_{idx}) + content_size_{idx}",
457 idx = self.index
458 ),
459 }
460 }
461 }
462}
463
464fn derive_size_expressions<'a>(
479 nodes: &'a [CodegenStructure],
480 get_var_size: &impl Fn(&CodegenVar) -> Option<u64>,
481) -> Result<Vec<SizeExpression<'a>>> {
482 let mut exps = Vec::<SizeExpression>::new();
483
484 for (idx, node) in nodes.iter().enumerate() {
486 let from_var = |arg_size, var| {
488 if let Some(size) = get_var_size(var) {
489 SizeExpression::empty_dependency(idx, arg_size, size)
490 } else {
491 SizeExpression::from_codegenvar(idx, arg_size, var)
492 }
493 };
494
495 let from_deps = |arg_size, idxs: &mut dyn Iterator<Item = &usize>| {
497 let mut exp = SizeExpression::empty_dependency(idx, arg_size, 0);
498 for idx in idxs {
499 let dep = &exps[*idx];
500 if dep.is_constant() {
501 exp.add_constant(dep.item_size());
502 } else {
503 exp.add_dependency(*idx);
504 }
505 }
506 exp
507 };
508
509 let exp = match node {
510 CodegenStructure::Var(var) => match var.variable_type() {
511 VariableType::ByteArray => from_var(ArgSize::LengthOfContentSize, var),
512 VariableType::String => from_var(ArgSize::LengthOfContentSize, var),
513 VariableType::Integer => from_var(ArgSize::Constant(0), var),
514 },
515 CodegenStructure::CborByteArray(inner) => {
516 from_deps(ArgSize::LengthOfContentSize, &mut iter::once(inner))
517 }
518 CodegenStructure::Map(items) => {
519 let len = items.len().try_into().with_context(|| {
520 format!("the size of the map is too large for u64: {}", items.len())
521 })?;
522 from_deps(
523 ArgSize::Constant(cbor::arg_size(len).0),
524 &mut items.iter().flat_map(|(a, b)| [a, b]),
525 )
526 }
527 CodegenStructure::Array(items) => {
528 let len = items.len().try_into().with_context(|| {
529 format!(
530 "the size of the array is too large for u64: {}",
531 items.len()
532 )
533 })?;
534 from_deps(ArgSize::Constant(cbor::arg_size(len).0), &mut items.iter())
535 }
536 };
537
538 exps.push(exp);
539 }
540
541 Ok(exps)
542}
543
544fn collect_codegenvar(template: &CwtTemplate) -> Result<CodegenVarTable> {
545 let mut vars = IndexMap::<String, CodegenVar>::new();
546
547 for (name, var) in &template.variables {
548 let ret = vars.insert(name.clone(), CodegenVar::from_template_variable(name, var)?);
549 if ret.is_some() {
550 bail!("A variable name {} already exists", name);
551 }
552 }
553
554 for (name, var) in &template.constants {
555 let ret = vars.insert(name.clone(), CodegenVar::from_template_constant(name, var)?);
556 if ret.is_some() {
557 bail!("A constant name {} already exists", name);
558 }
559 }
560
561 Ok(vars)
562}
563
564fn generate_input_fields(vars: &CodegenVarTable, indent: &str) -> String {
566 vars.iter()
567 .filter(|(_, var)| !var.is_constant())
568 .map(|(_, var)| var.declarations(indent))
569 .collect()
570}
571
572fn generate_size_computations(size_exps: &[SizeExpression], prefix: &str) -> Result<String> {
574 assert!(!size_exps.is_empty());
575
576 let mut code = String::new();
577 for size_exp in size_exps.iter().filter(|exp| !exp.is_constant()) {
578 code += &format!(
579 "{prefix}const size_t content_size_{} = {};\n",
580 size_exp.index,
581 size_exp.content_size_expression()
582 );
583 code += &format!(
584 "{prefix}const size_t item_size_{} = {};\n",
585 size_exp.index,
586 size_exp.item_size_expression()
587 );
588 }
589
590 Ok(code)
591}
592
593fn generate_size_checks(
597 vars: &CodegenVarTable,
598 whole_struct_size: &SizeExpression,
599 prefix: &str,
600) -> Result<(String, String)> {
601 let mut input_checks = String::new();
602
603 for (_, var) in vars
605 .iter()
606 .filter(|(_, var)| !var.is_constant() && var.variable_type() != VariableType::Integer)
607 {
608 let size_exp = var.size_expression();
609 let cond = match var.size {
610 VariableSize::ExactSize(size) => format!("!= {size}"),
611 VariableSize::MaxSize(size) => format!("> {size}"),
612 };
613
614 input_checks +=
615 &format!("{prefix}if ({size_exp} {cond}) return kErrorCertInvalidArgument;\n");
616 }
617
618 let size_bound = if whole_struct_size.is_constant() {
619 whole_struct_size.item_size().to_string()
620 } else {
621 format!("item_size_{idx}", idx = whole_struct_size.index)
622 };
623
624 input_checks +=
626 &format!("{prefix}if (*inout_size < {size_bound}) return kErrorCertInvalidSize;\n");
627
628 let output_checks =
630 format!("{prefix}if (*inout_size != {size_bound}) return kErrorCertInternal;\n");
631
632 Ok((input_checks, output_checks))
633}
634
635fn collect_preorder_indicies_helper(nodes: &[CodegenStructure], root: usize, res: &mut Vec<usize>) {
636 res.push(root);
637 match &nodes[root] {
638 CodegenStructure::Var(_) => {}
639 CodegenStructure::CborByteArray(inner) => {
640 collect_preorder_indicies_helper(nodes, *inner, res);
641 }
642 CodegenStructure::Map(items) => {
643 for (k, v) in items {
644 collect_preorder_indicies_helper(nodes, *k, res);
645 collect_preorder_indicies_helper(nodes, *v, res);
646 }
647 }
648 CodegenStructure::Array(items) => {
649 for item in items {
650 collect_preorder_indicies_helper(nodes, *item, res);
651 }
652 }
653 }
654}
655
656fn collect_preorder_indicies(nodes: &[CodegenStructure]) -> Vec<usize> {
657 let mut res = Vec::new();
658 collect_preorder_indicies_helper(nodes, nodes.len() - 1, &mut res);
659 res
660}
661
662type CodeBlock = Vec<GeneratedCode>;
664
665#[derive(Clone, Debug, PartialEq, Eq)]
666enum GeneratedCode {
667 FunctionCall(String),
669 CborBytes(Vec<u8>),
671}
672
673struct GeneratedCborInstructions {
674 constant_definitions: String,
675 cbor_instructions: String,
676}
677
678fn generate_cbor_instructions(
679 nodes: &[CodegenStructure],
680 size_exps: &[SizeExpression],
681 prefix: &str,
682) -> Result<GeneratedCborInstructions> {
683 assert!(nodes.len() == size_exps.len());
684
685 let call_wrapper = |func_call: String| {
686 indoc::formatdoc! { r#"
687 {prefix}{func_call};
688 "#
689 }
690 };
691
692 let gen_inst = |inst: String| GeneratedCode::FunctionCall(call_wrapper(inst));
693
694 let mut code_blocks = Vec::<CodeBlock>::new();
696 for (idx, (node, size_exp)) in nodes.iter().zip(size_exps.iter()).enumerate() {
697 let code_block = match node {
698 CodegenStructure::Var(var) => match &var.value {
699 CodegenVarValue::ByteArray(val) => {
700 let header = if let VariableSize::ExactSize(size) = var.size {
701 GeneratedCode::CborBytes(cbor::byte_array_header(size))
702 } else {
703 gen_inst(format!("cbor_write_bstr_header(&cbor, content_size_{idx})"))
704 };
705
706 let content = if let Some(constant) = val {
707 GeneratedCode::CborBytes(constant.clone())
708 } else {
709 let val = var.value_expression();
710 let size = var.size_expression();
711 gen_inst(format!("cbor_write_raw_bytes(&cbor, {val}, {size})"))
712 };
713
714 vec![header, content]
715 }
716 CodegenVarValue::String(val) => {
717 let header = if let VariableSize::ExactSize(size) = var.size {
718 GeneratedCode::CborBytes(cbor::string_header(size))
719 } else {
720 gen_inst(format!("cbor_write_tstr_header(&cbor, content_size_{idx})"))
721 };
722
723 let content = if let Some(constant) = val {
724 GeneratedCode::CborBytes(constant.as_bytes().to_vec())
725 } else {
726 let val = var.value_expression();
727 let size = var.size_expression();
728 gen_inst(format!(
729 "cbor_write_raw_bytes(&cbor, (uint8_t *){val}, {size})"
730 ))
731 };
732
733 vec![header, content]
734 }
735 CodegenVarValue::Integer(val) => match val {
736 Some(constant) => {
737 vec![GeneratedCode::CborBytes(cbor::int(*constant))]
738 }
739 None => {
740 let val = var.value_expression();
741 vec![gen_inst(format!("cbor_write_int(&cbor, {val})"))]
742 }
743 },
744 },
745 CodegenStructure::CborByteArray(_) => {
746 if size_exp.is_constant() {
747 let size = size_exp.content_size();
748 vec![GeneratedCode::CborBytes(cbor::byte_array_header(size))]
749 } else {
750 vec![gen_inst(format!(
751 "cbor_write_bstr_header(&cbor, content_size_{idx})"
752 ))]
753 }
754 }
755 CodegenStructure::Map(items) => {
756 let len = items.len().try_into().with_context(|| {
757 format!("the size of the map is too large for u64: {}", items.len())
758 })?;
759 vec![GeneratedCode::CborBytes(cbor::map_header(len))]
760 }
761 CodegenStructure::Array(items) => {
762 let len = items.len().try_into().with_context(|| {
763 format!(
764 "the size of the array is too large for u64: {}",
765 items.len()
766 )
767 })?;
768 vec![GeneratedCode::CborBytes(cbor::array_header(len))]
769 }
770 };
771
772 code_blocks.push(code_block);
773 }
774
775 let order = collect_preorder_indicies(nodes);
777 let insts = order.iter().flat_map(|&idx| code_blocks[idx].clone());
778
779 let mut constant_definitions = String::new();
780 let mut cbor_instructions = String::new();
781
782 let mut idx = 0usize;
784 for (is_constant, chunk) in &insts.chunk_by(|inst| matches!(inst, GeneratedCode::CborBytes(_)))
785 {
786 if is_constant {
787 let buf = chunk.flat_map(|inst| match inst {
788 GeneratedCode::CborBytes(inner) => inner,
789 _ => panic!("Shouldn't have any non GeneratedCode::CborBytes variant."),
790 });
791
792 let bytes = buf.map(|ch| format!("{}", ch));
793 let initializer: String =
794 itertools::Itertools::intersperse(bytes, ", ".to_owned()).collect();
795
796 constant_definitions += &indoc::formatdoc! { r#"
797 {prefix}const static uint8_t binary_{idx}[] = {{{initializer}}};
798 "#};
799 cbor_instructions += &call_wrapper(format!(
800 "cbor_write_raw_bytes(&cbor, binary_{idx}, sizeof(binary_{idx}))"
801 ));
802
803 idx += 1;
804 } else {
805 for block in chunk {
806 match block {
807 GeneratedCode::FunctionCall(inner) => cbor_instructions += &inner,
808 _ => panic!("Shouldn't have any non GeneratedCode::FunctionCall variant."),
809 }
810 }
811 }
812 }
813
814 Ok(GeneratedCborInstructions {
815 constant_definitions,
816 cbor_instructions,
817 })
818}
819
820fn generate_header(from_file: &str, template_name: &str, max_size: u64, decls: String) -> String {
821 let preproc_guard_include = template_name.to_shouty_snake_case();
822 let enum_name = template_name.to_upper_camel_case();
823
824 indoc::formatdoc! { r#"
825 // Copyright lowRISC contributors (OpenTitan project).
826 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
827 // SPDX-License-Identifier: Apache-2.0
828
829 // This file was automatically generated using opentitantool from:
830 // {from_file}
831 #ifndef __{preproc_guard_include}__
832 #define __{preproc_guard_include}__
833
834 #include "sw/device/lib/base/status.h"
835
836 typedef struct {template_name}_values {{
837 {decls}}} {template_name}_values_t;
838
839 enum {{
840 k{enum_name}MaxVariableSizeBytes = {max_size},
841 }};
842
843 rom_error_t {template_name}_build({template_name}_values_t *values, uint8_t *output, size_t *inout_size);
844
845 #endif
846 "#}
847}
848
849fn generate_source(
850 from_file: &str,
851 template_name: &str,
852 constant_definitions: &str,
853 size_computations: &str,
854 input_size_checks: &str,
855 output_size_checks: &str,
856 cbor_instructions: &str,
857) -> String {
858 let source_template = indoc::formatdoc! { r#"
859 // Copyright lowRISC contributors (OpenTitan project).
860 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
861 // SPDX-License-Identifier: Apache-2.0
862
863 // This file was automatically generated using opentitantool from:
864 // {from_file}
865
866 #include "{template_name}.h"
867 #include "sw/device/silicon_creator/lib/cert/cbor.h"
868
869 {constant_definitions}
870 rom_error_t {template_name}_build({template_name}_values_t *values, uint8_t *buffer, size_t *inout_size) {{
871 {size_computations}
872 {input_size_checks}
873 cbor_out_t cbor;
874 cbor_out_init(&cbor, buffer);
875
876 {cbor_instructions}
877 *inout_size = cbor_out_size(&cbor);
878 {output_size_checks}
879 return kErrorOk;
880 }}
881 "#};
882
883 source_template
884}
885
886impl CwtTemplate {
887 pub fn from_hjson_str(content: &str) -> Result<CwtTemplate> {
888 deser_hjson::from_str(content).context("CwtTemplate::from_hjson_str failed")
889 }
890}
891
892pub fn load_cwt_template(path: &PathBuf) -> Result<CwtTemplate> {
893 let template_content = fs::read_to_string(path)
894 .with_context(|| format!("could not load the template file {}", path.display()))?;
895
896 CwtTemplate::from_hjson_str(&template_content).with_context(|| {
897 format!(
898 "failed to parse CwtTemplate from the template file {}",
899 path.display()
900 )
901 })
902}
903
904pub fn generate_cert(from_file: &str, template: &CwtTemplate) -> Result<Codegen> {
905 let vars = collect_codegenvar(template).context("collect_codegenvar failed")?;
906
907 let structures = CodegenStructure::from_template(template, &vars)
908 .context("CodegenStructure::from_template failed")?;
909
910 let max_size = {
911 let exp = derive_size_expressions(&structures, &|var| match var.size {
912 VariableSize::ExactSize(size) => Some(size),
913 VariableSize::MaxSize(size) => Some(size),
914 })
915 .context("derive_size_expressions for maximum size failed")?;
916
917 exp.last()
918 .context("there isn't any item in the structure")?
919 .item_size()
920 };
921
922 let decls = generate_input_fields(&vars, " ");
923
924 let source_h = generate_header(from_file, &template.name, max_size, decls);
925
926 let exact_sizes = derive_size_expressions(&structures, &|var| match var.size {
927 VariableSize::ExactSize(size) => Some(size),
928 _ => None,
929 })
930 .context("derive_size_expressions for exact size failed")?;
931
932 let size_computations = generate_size_computations(&exact_sizes, " ")
933 .context("generate_size_computations failed")?;
934
935 let (input_size_checks, output_size_checks) = generate_size_checks(
936 &vars,
937 exact_sizes
938 .last()
939 .context("there isn't any item in the structure")?,
940 " ",
941 )
942 .context("generate_size_checks failed")?;
943
944 let GeneratedCborInstructions {
945 constant_definitions,
946 cbor_instructions,
947 } = generate_cbor_instructions(&structures, &exact_sizes, " ")
948 .context("generate_cbor_instructions failed")?;
949
950 let source_c = generate_source(
951 from_file,
952 &template.name,
953 &constant_definitions,
954 &size_computations,
955 &input_size_checks,
956 &output_size_checks,
957 &cbor_instructions,
958 );
959
960 let source_unittest = String::new();
962
963 Ok(Codegen {
964 source_h,
965 source_c,
966 source_unittest,
967 })
968}