public static string TranslateTypeName(TpmType t) { var underType = t.StripTypedefs(); if (underType is TpmValueType) { return(TargetLang.NameFor(underType.SpecName)); } return(TargetLang.DotNet ? (underType is TpmUnion ? "I" : "") + TypeToDotNet(underType.SpecName) : underType.SpecName); }
public static List <TpmNamedConstant> GetBifieldElements(TpmBitfield bf) { var elements = new List <TpmNamedConstant>(); foreach (var b in bf.Elements) { if (b.StartBit == b.EndBit) { AddBitfieldElt(elements, b.TranslatedName, 1 << b.StartBit, b.Comment, b.OldStyleName); } else // multibit members of a bitfield { string typeName = b.Name; if (TpmTypes.Contains(typeName)) { // Type typeName defines allowed values for this multi-bit field var e = TpmTypes.Lookup(typeName) as TpmEnum; if (e != null) { foreach (var v in e.Members) { AddBitfieldElt(elements, v.Name, v.NumericValue << b.EndBit, v.Comment); } } } // Multi-bit bitfield 'name' is additionally represented by several enumerators: // name_BIT_MASK - bit mask selecting all bits of the field // name_BIT_OFFSET - offset of the field's low order bit // name_BIT_LENGTH - number of bits in the field string nameBase = b.Name.Contains("_") ? TargetLang.NameToDotNet(b.Name) : b.Name; int len = b.StartBit - b.EndBit + 1; var suff = TargetLang.DotNet ? new string[] { "BitMask", "BitOffset", "BitLength" } : new string[] { "_BIT_MASK", "_BIT_OFFSET", "_BIT_LENGTH" }; AddBitfieldElt(elements, nameBase + suff[0], ((1 << len) - 1) << b.EndBit, b.Comment, null, true); AddBitfieldElt(elements, nameBase + suff[1], b.EndBit, null, null, true); AddBitfieldElt(elements, nameBase + suff[2], len, null, null, true); if (TargetLang.DotNet && bf.Name == "LocalityAttr") { // For backward compatibility for (int i = 0; i < len; ++i) { AddBitfieldElt(elements, $"{nameBase}Bit{i}", 1 << (b.EndBit + i), "", null, true); } } } // multibit members of a bitfield } return(elements); }
/// <summary> Adds fundamental type definitions and a couple of custom classes </summary> internal static void Init() { foreach (var et in TargetLang.GetElementaryTypes()) { Add(et); } TpmStruct s = new TpmStruct("TPM_HANDLE", "Handle of a loaded TPM key or other object [TSS]", null, null, true); s.Add(new StructField("UINT32", "handle", "Handle value")); s.UnderlyingType = Lookup("UINT32"); Add(s); // Create and register empty structs for unions string descr = "Base class for empty union elements.\n" + "An empty union element does not contain any data to marshal.\n" + "This data structure can be used in place of any other union\n" + "initialized with its own empty element."; EmptyUnionBase = new TpmStruct(EmptyUnionBaseName, descr); Add(EmptyUnionBase); }
/// <summary> Makes constant values specified as arithmetic expressions comply with the current /// langauge syntax (adds enum type name qualifiers and type casts when necessary, eliminates /// sizeof() operators when unsupported, etc.) </summary> public static string TranslateConstExpr(TpmConstExpr ce, TpmEnum enclosingEnum = null) { var nameDelimiters = new char[] { ' ', ',', '{', '}', '(', ')', '+', '-', '<', '*', '/', '`' }; string suffix = TargetLang.Java ? ".toInt()" : ""; string expr = ce.Expr; string[] tokens = expr.Split(nameDelimiters); bool sizeofOccurred = false, commentNeeded = false; foreach (string token in tokens) { if (token.Length == 0) { continue; } if (token == "sizeof") { Debug.Assert(!sizeofOccurred); sizeofOccurred = true; continue; } if (Expression.IsNumber(token)) { if (token == "00") { Debug.Assert(expr == token); expr = "0"; } Debug.Assert(!sizeofOccurred); continue; } TpmNamedConstant nc = TpmTypes.LookupConstant(token); if (enclosingEnum != null && nc?.EnclosingEnum == enclosingEnum) { // Members of the enum being processed do not need to be qualified Debug.Assert(token == nc.SpecName); expr = expr.Replace(token, nc.Name + suffix); continue; } if (!TpmTypes.ContainsConstant(token)) { // This must be a type name operand of sizeof() Debug.Assert(sizeofOccurred); sizeofOccurred = false; TpmType t = TpmTypes.Lookup(token); if (t is TpmStruct || TargetLang.IsOneOf(Lang.Java, Lang.JS, Lang.Py)) { string sizeofExpr = "sizeof(" + token + ")"; Debug.Assert(expr.Contains(sizeofExpr)); commentNeeded = TargetLang.Py; string origExpr = TargetLang.Py ? "" : $"/*{sizeofExpr}*/"; expr = expr.Replace(sizeofExpr, $"0x{t.GetSize():X}{origExpr}"); } else if (TargetLang.DotNet) { expr = expr.Replace(token, t.StripTypedefs().Name); } } else { nc = TpmTypes.LookupConstant(token); var translated = nc.QualifiedName + suffix; if (!TargetLang.IsGenerated(nc.EnclosingEnum)) { translated = nc.NumericValue.ToString(); if (!TargetLang.Py) { translated += "/*" + token + "*/"; } else { commentNeeded = true; } } expr = expr.Replace(token, translated); } } // foreach token if (TargetLang.DotNet && expr.Contains("<<")) { // Shift operator in .Net requires right operand of type 'int' and unsigned left one. int curPos = 0; expr = expr.Replace(" << ", "<<"); do { int pos = expr.IndexOf("<<", curPos); if (pos == -1) { break; } curPos = pos + 2 + 6; // Add sizes of "<<" and "(uint)" while (char.IsLetterOrDigit(expr[--pos]) || expr[pos] == '.') { continue; } expr = expr.Insert(pos + 1, "(uint)"); } while (true); expr = expr.Replace("<<", " << (int)"); } if (commentNeeded) { expr += $" # {ce.Expr}"; } return(expr); } // TranslateConstExpr()
public static List <string> GetToTpmFieldsMarshalOps(StructField[] fields) { var marshalOps = new List <string>(); foreach (StructField f in fields) { int size = f.Type.GetSize(); string fieldName = ThisMember + f.Name; switch (f.MarshalType) { case MarshalType.Normal: if (f.IsValueType()) { marshalOps.Add($"buf.write{WireNameForInt(size)}({fieldName})"); } else { marshalOps.Add($"{fieldName}.toTpm(buf)"); } if (f.Attrs.HasFlag(StructFieldAttr.TermOnNull)) { marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + " return"); } break; case MarshalType.ConstantValue: marshalOps.Add($"buf.write{WireNameForInt(size)}({ConstTag(f)})"); break; case MarshalType.SizedStruct: Debug.Assert(f.SizeTagField != null); marshalOps.Add($"buf.writeSizedObj({fieldName})"); break; case MarshalType.EncryptedVariableLengthArray: case MarshalType.SpecialVariableLengthArray: // TPMT_HA size is tagged by its hash alg (the first field) marshalOps.Add($"buf.writeByteBuf({fieldName})"); break; case MarshalType.VariableLengthArray: var sizeTagLen = f.SizeTagField.Type.GetSize(); if (f.IsByteBuffer()) { marshalOps.Add($"buf.writeSizedByteBuf({fieldName}" + (sizeTagLen == 2 ? ")" : $", {sizeTagLen})")); } else if (f.IsValueType()) { marshalOps.Add($"buf.writeValArr({fieldName}, {size})"); } else { marshalOps.Add($"buf.writeObjArr({fieldName})"); } break; case MarshalType.UnionSelector: // A trick to allow using default-constructed TPMT_SENSITIVE as an empty (non-marshaling) object string unionField = ThisMember + f.RelatedUnion.Name; if (f == fields.First()) { marshalOps.Add(TargetLang.If($"{unionField} == {TargetLang.Null}") + " return"); } marshalOps.Add($"buf.write{WireNameForInt(size)}({unionField}{TargetLang.Member}GetUnionSelector())"); break; case MarshalType.UnionObject: marshalOps.Add($"{fieldName}{TargetLang.Member}toTpm(buf)"); break; default: Debug.Assert(false); break; } } return(marshalOps); } // GetToTpmFieldsMarshalOps()
} // GetToTpmFieldsMarshalOps() public static List <string> GetFromTpmFieldsMarshalOps(StructField[] fields) { var marshalOps = new List <string>(); foreach (StructField f in fields) { int size = f.Type.GetSize(); string fieldName = ThisMember + f.Name; switch (f.MarshalType) { case MarshalType.Normal: if (f.IsValueType()) { marshalOps.Add($"{fieldName} = buf.read{WireNameForInt(size)}()"); } else { marshalOps.Add(TargetLang.Cpp ? $"{fieldName}.initFromTpm(buf)" : $"{fieldName} = {f.TypeName}.fromTpm(buf)"); } if (f.Attrs.HasFlag(StructFieldAttr.TermOnNull)) { marshalOps.Add(TargetLang.If($"{fieldName} == {TpmTypes.AlgNull}") + " return"); } break; case MarshalType.ConstantValue: // TODO: Add assertion by comparing with the expected constant marshalOps.Add($"buf.read{WireNameForInt(size)}()"); break; case MarshalType.SizedStruct: Debug.Assert(f.SizeTagField != null); marshalOps.Add(TargetLang.Cpp ? $"buf.readSizedObj({fieldName})" : $"{fieldName} = buf.createSizedObj({TargetLang.TypeInfo(f.TypeName)})"); break; case MarshalType.EncryptedVariableLengthArray: marshalOps.Add($"{fieldName} = buf.readByteBuf(buf.getCurStuctRemainingSize())"); break; case MarshalType.SpecialVariableLengthArray: // TPMT_HA size is inferred from the hash algorithm Debug.Assert(f.IsByteBuffer() && f.SizeTagField.Type.GetSize() == 2); marshalOps.Add($"{fieldName} = buf.readByteBuf({TargetLang.DigestSize(f.SizeTagField.Name)})"); break; case MarshalType.VariableLengthArray: var sizeTagLen = f.SizeTagField.Type.GetSize(); if (f.IsByteBuffer()) { marshalOps.Add($"{fieldName} = buf.readSizedByteBuf(" + (sizeTagLen == 2 ? ")" : $"{sizeTagLen})")); } else if (f.IsValueType()) { marshalOps.Add(TargetLang.Cpp ? $"buf.readValArr({fieldName}, {f.Type.GetSize()})" : $"{fieldName} = buf.readValArr({f.Type.GetSize()})"); } else { marshalOps.Add(TargetLang.Cpp ? $"buf.readObjArr({fieldName})" : $"{fieldName} = buf.readObjArr({TargetLang.TypeInfo(f.TypeName.TrimEnd('[', ']'))})"); } break; case MarshalType.UnionSelector: var localVar = TargetLang.LocalVar(f.Name, f.TypeName); marshalOps.Add($"{localVar} = " + (f.IsValueType() ? $"buf.read{WireNameForInt(size)}()" : $"{f.TypeName}.fromTpm(buf)")); break; case MarshalType.UnionObject: var selector = (f as UnionField).UnionSelector.Name; marshalOps.Add(TargetLang.Cpp ? $"UnionFactory::Create({fieldName}, {selector})" : $"{fieldName} = UnionFactory.create({TargetLang.Quote(f.TypeName)}, {selector})"); marshalOps.Add($"{fieldName}{TargetLang.Member}initFromTpm(buf)"); break; default: break; } } return(marshalOps); } // GetFromTpmFieldsMarshalOps()
static void Main(string[] args) { bool help = false, abort = false; string specPath = null; string tssRootPath = null; var actions = Action.None; Func <Lang, string> langName = l => Enum.GetName(typeof(Lang), l); var allLangs = ((Lang[])Enum.GetValues(typeof(Lang))).ToList(); var langs = new List <Lang>(); for (int i = 0; i < args.Length; ++i) { string opt = args[i]; if (opt[0] != '-' && opt[0] != '/') { help = abort = true; PrintError($"Invalid format for option {i}: {opt}"); break; } opt = opt.Substring(1); var res = ProcessPathOption(opt, "spec", args, ref i, ref specPath); if (res == Option.ParsingError) { return; } if (res == Option.Matched) { continue; } res = ProcessPathOption(opt, "dest", args, ref i, ref tssRootPath); if (res == Option.ParsingError) { return; } if (res == Option.Matched) { continue; } if (opt == "h" || opt == "help" || opt == "?") { help = true; } else if (0 == string.Compare(opt, "extract", true)) { actions |= Action.ExtractFromDoc; } else if (0 == string.Compare(opt, "noextract", true)) { actions &= ~Action.ExtractFromDoc; } else { Lang lang = allLangs.FirstOrDefault(l => 0 == string.Compare(opt, langName(l), true)); if (lang != Lang.None) { if (!langs.Contains(lang)) { langs.Add(lang); } } else { lang = allLangs.FirstOrDefault(l => 0 == string.Compare(opt, "no" + langName(l), true)); if (lang != Lang.None) { langs = allLangs.Where(l => l != lang).ToList(); } else { help = abort = true; PrintError($"Unrecognized option '{opt}'"); } } } } if (help) { Console.WriteLine("\nAll command line parameters are case-insensitive and optional.\n" + "Option names are prepended with either dash ('-') or slash ('/') marks.\n" + " They include:\n" + " spec <path> - a path to the root folder that contains the TPM 2.0 spec Word\n" + " documents and/or intermediate XML representation\n" + " dest <path> - a path to the root folder that contains the TPM 2.0 spec Word\n" + " documents and/or intermediate XML representation\n" + " noExtract, dotNet, cpp, java, noDotnet, noCpp, noJava, h|help|?" + "Options are case-insensitive, and must be prepended by characters '-' or '/'\n"); if (abort) { return; } } // The TPM 2.0 spec Word docs Part 2 and 3 are parsed to produce an XML representation. // This operation is slow. By default (i.e. if no '-extract' option is specified) // CodeGen bypasses the spec parsing stage and proceeds directly off the existing XML. if (specPath == null) { string pwd = Directory.GetCurrentDirectory(); specPath = Path.GetFullPath(Path.Combine(pwd, @"..\..\..\TpmSpec")); } string rawTables = Path.GetFullPath(Path.Combine(specPath, "RawTables.xml")); if (actions.HasFlag(Action.ExtractFromDoc) || !File.Exists(rawTables)) { // Kill Word processes Process[] wordProcesses = Process.GetProcessesByName("WINWORD"); if (wordProcesses.Length != 0) { DialogResult res = MessageBox.Show("There are word processes running. Kill them?", "Kill Word Processes?", MessageBoxButtons.YesNo); if (res == DialogResult.Yes) { foreach (Process p in wordProcesses) { try { p.Kill(); } catch (Exception) {} } Thread.Sleep(2000); } } TableExtractor extractor = new TableExtractor(specPath); XmlSerializeToFile(rawTables, RawTables.Tables); } // Load the XML description of the tables, and extract into in-memory data structures List <RawTable> tables = XmlDeserializeFromFile <List <RawTable> >(rawTables); TypeExtractor tpe = new TypeExtractor(tables); tpe.Extract(); TpmTypeTranslations.DoFixups(); if (tssRootPath == null) { tssRootPath = @"..\..\..\..\"; } if (langs.Count == 0) { langs = allLangs.Skip(1).ToList(); } foreach (var lang in langs) { if (lang == Lang.DotNet) { continue; } var tssName = "TSS." + langName(lang).Replace("DotNet", "Net"); Console.WriteLine($"\nGenerating {tssName}..."); var cg = TargetLang.NewCodeGen(lang, tssRootPath + tssName + '\\'); TargetLang.SetTargetLang(lang); cg.Generate(); } if (langs.Contains(Lang.DotNet)) { Console.WriteLine("\nGenerating TSS.Net..."); CGenDotNet dotNetGen = new CGenDotNet(tssRootPath + @"TSS.NET\"); TargetLang.SetTargetLang(Lang.DotNet); dotNetGen.Generate(); } Console.WriteLine("All done!"); }
void GenHandleTable() { Write("//-----------------------------------------------------------------------------"); Write("//------------------------- COMMAND INFO -----------------------------------"); Write("//-----------------------------------------------------------------------------"); Write("public static class CommandInformation"); TabIn("{"); Write("public static CommandInfo[] Info = new CommandInfo[]"); TabIn("{"); bool printComma = false; foreach (var req in TpmTypes.Get <TpmStruct>().Where(s => s.Info.IsRequest())) { TpmStruct resp = GetRespStruct(req); string cmdName = GetCommandName(req); string transCmdName = TargetLang.TypeToDotNet(cmdName); string reqStructName = "Tpm2" + transCmdName + "Request"; // encryptable parms? ParmCryptInfo cryptInfo = 0; if (req.Fields.Count > req.NumHandles) { // find the first field that is not a handle StructField parm0 = req.Fields[req.NumHandles]; if (parm0.MarshalType.IsOneOf(MarshalType.LengthOfStruct, MarshalType.ArrayCount)) { string typeName = parm0.Type.StripTypedefs().Name; if (typeName == "uint") { cryptInfo |= ParmCryptInfo.EncIn4; } else if (typeName == "ushort") { cryptInfo |= ParmCryptInfo.Enc2In2; } } } if (resp.Fields.Count > resp.NumHandles) { // find the first field that is not a handle StructField parm0 = resp.Fields[resp.NumHandles]; if (parm0.MarshalType.IsOneOf(MarshalType.LengthOfStruct, MarshalType.ArrayCount)) { string typeName = parm0.Type.StripTypedefs().Name; if (typeName == "uint") { cryptInfo |= ParmCryptInfo.DecOut4; } else if (typeName == "ushort") { cryptInfo |= ParmCryptInfo.DecOut2; } } } string handleTypeNames = ""; // types of input handles if (req.NumHandles > 0) { for (int j = 0; j < req.NumHandles; j++) { StructField hField = req.Fields[j]; string origHandleType = hField.Type.SpecName; handleTypeNames += origHandleType + " "; TpmType tpx = TpmTypes.Lookup(origHandleType); } } handleTypeNames = handleTypeNames.TrimEnd(new char[] { ' ' }); handleTypeNames = "\"" + handleTypeNames + "\""; string respTypeId = !resp.Implement ? "EmptyResponse" : resp.Name; WriteComma(ref printComma); Write($"new CommandInfo(TpmCc.{transCmdName}, {req.NumHandles}, {resp.NumHandles}, {req.NumAuthHandles}, " + $"typeof({reqStructName}), typeof({respTypeId}), {(uint)cryptInfo}, {handleTypeNames})", false); } TabOut("};"); TabOut("}"); }
void GenCommands() { Write("//-----------------------------------------------------------------------------"); Write("//------------------------- COMMANDS -----------------------------------------"); Write("//-----------------------------------------------------------------------------"); Write(""); Write("public partial class Tpm2"); TabIn("{"); foreach (var req in TpmTypes.Get <TpmStruct>().Where(s => s.Info.IsRequest())) { string cmdName = GetCommandName(req); var resp = GetRespStruct(req); var reqFields = req.NonTagFields; var respFields = resp.NonTagFields; string outputType = "void"; int numRespParams = respFields.Count(); if (respFields.Count() != 0) { if (respFields.Last().Name == "name") { --numRespParams; } outputType = respFields[0].TypeName; } string annotation = req.Comment + "\n\n"; foreach (var f in reqFields) { annotation += GetParamComment(f) + "\n"; } annotation += GetReturnComment(respFields); WriteComment(annotation, false); // commmand prototype + parameters string transCmdName = TargetLang.NameToDotNet(cmdName); Write("[TpmCommand]"); TabIn($"public {outputType} {transCmdName}("); bool printComma = false; foreach (StructField f in reqFields) { WriteComma(ref printComma); Write($"{f.TypeName} {f.Name}", false); } for (int i = 1; i < numRespParams; ++i) { var f = respFields[i]; WriteComma(ref printComma); Write($"out {f.TypeName} {f.Name}", false); } TabOut(")"); TabIn("{"); // Create input struct string reqStructInitList = string.Join(", ", reqFields.Select(f => f.Name)); Write($"var req = new {req.Name}({reqStructInitList});"); // Dispatch the command string respType = !resp.Implement ? "EmptyResponse" : resp.Name; Write($"var resp = new {respType}();"); Write($"DispatchMethod(TpmCc.{transCmdName}, req, resp, {req.NumHandles}, {resp.NumHandles});"); if (numRespParams > 0) { if (numRespParams == 1) { Write($"return resp.{respFields[0].Name};"); } else { // Set the return parameters for (int i = 1; i < numRespParams; ++i) { string rfName = respFields[i].Name; Write($"{rfName} = resp.{rfName};"); } Write($"return resp.{respFields[0].Name};"); } } TabOut("}"); continue; } TabOut("}"); } // GenCommands()
void GenStructure(TpmStruct s) { bool hasBase = s.DerivedFrom != null; // Has a non-trivial base class? string className = s.Name; string classBases = hasBase ? s.DerivedFrom.Name : "TpmStructureBase"; // Here "implements" is as opposed to "inherits and overrides" bool implementsUnionInterfaces = !s.IsCmdStruct() && !hasBase && s.ContainingUnions.Count > 0; Debug.Assert(s.DerivedFrom == null || s.DerivedFrom.ContainingUnions.Count >= s.ContainingUnions.Count); if (implementsUnionInterfaces) { foreach (TpmUnion u in s.ContainingUnions) { classBases += ", " + u.Name; } } WriteComment(s); Write("[DataContract]"); var knownTypes = GetKnownTypes(s); foreach (TpmType kt in knownTypes) { Write($"[KnownType(typeof({kt.Name}))]"); } string specName = s.Info.IsRequest() ? s.SpecName.Substring(5).Replace("_REQUEST", "_In") : s.Info.IsResponse() ? s.SpecName.Replace("Response", "_Out") : s.SpecName; Write($"[SpecTypeName(\"{specName}\")]"); Write($"public partial class {className}: {classBases}"); TabIn("{"); if (s.DerivedFrom != null) { Debug.Assert(!s.IsCmdStruct()); //--------------------------------------- // Constructors var fields = new List <StructField>(); TpmStruct b = s; do { fields.AddRange(b.NonTagFields); b = b.DerivedFrom; } while (b != null); // Default constructor Write($"public {className}() {{}}"); Write(""); if (fields.Count != 0) { // Copy-constructor WriteLine("public {0}({0} _{0}) : base(_{0}) {{}}", className); Write(""); // Member-wise constructor GenMemeberwiseCtorPrototype(className, fields); if (fields.Count == 1) { Write($" : base(_{fields.First().Name}) {{}}"); } else { string baseInitList = string.Join(", ", fields.ConvertAll(f => "_" + f.Name)); Write(""); Write($" : base({baseInitList})"); Write("{}"); } Write(""); } GenGetUnionSelector(s, implementsUnionInterfaces); GenCloningMethods(s.Name); // end of class TabOut("}"); return; } // if (s.DerivedFrom != null) // // Member fields // bool onlyStaticFields = true; int idx = 0; foreach (StructField f in s.Fields) { var tag = f.SizeTagField; if (f.SizedField == null) { WriteComment(f); WriteConstraints(f); } onlyStaticFields = false; switch (f.MarshalType) { case MarshalType.ArrayCount: case MarshalType.LengthOfStruct: --idx; break; case MarshalType.UnionSelector: { Debug.Assert(f.RelatedUnion.MarshalType == MarshalType.UnionObject); Debug.Assert(f.RelatedUnion.UnionSelector == f); var unionField = f.RelatedUnion; var u = (TpmUnion)unionField.Type; Write($"[MarshalAs({idx}, MarshalType.UnionSelector)]"); TabIn($"public {f.TypeName} {f.Name} {{"); if (u.NullSelector == null) { Write($"get {{ return {unionField.Name}.GetUnionSelector(); }}"); } else { Write($"get {{ return {unionField.Name} != null ? {unionField.Name}.GetUnionSelector() : {u.NullSelector.QualifiedName}; }}"); } TabOut("}"); // property break; } case MarshalType.Normal: case MarshalType.SizedStruct: { if (tag == null) { Write($"[MarshalAs({idx})]"); } else { Write($"[MarshalAs({idx}, MarshalType.SizedStruct, \"{tag.Name}\", {tag.Type.GetSize()})]"); } WriteFieldDef(f, " { get; set; }"); break; } case MarshalType.UnionObject: { UnionField fx = (UnionField)f; Write($"[MarshalAs({idx}, MarshalType.Union, \"{fx.UnionSelector.Name}\")]"); WriteFieldDef(f, " { get; set; }"); break; } case MarshalType.VariableLengthArray: case MarshalType.SpecialVariableLengthArray: { string marshalType = Enum.GetName(typeof(MarshalType), f.MarshalType); Write($"[MarshalAs({idx}, MarshalType.{marshalType}, \"{tag.Name}\", {tag.Type.GetSize()})]"); WriteFieldDef(f); break; } case MarshalType.EncryptedVariableLengthArray: { Write($"[MarshalAs({idx}, MarshalType.EncryptedVariableLengthArray)]"); WriteFieldDef(f); break; } case MarshalType.ConstantValue: { string val = TargetLang.TranslateConstExpr(f.Domain[0, Constraint.Type.Single]); Write($"[MarshalAs({idx})]"); WriteFieldDef(f, $" = {val};"); break; } default: throw new Exception(); } ++idx; } // foreach field if (onlyStaticFields && s.Fields.Count > 0) { // end of class TabOut("}"); return; } // Default constructor var fieldsToInit = s.NonDefaultInitFields; Write(""); Write($"public {className}()", false); if (fieldsToInit.Count() == 0) { Write(" {}"); } else if (fieldsToInit.Count() == 1) { var f = fieldsToInit[0]; Write($" {{ {f.Name} = {f.GetInitVal()}; }}"); } else { TabIn("{"); foreach (StructField f in fieldsToInit) { Write($"{f.Name} = {f.GetInitVal()};"); } TabOut("}"); } // Copy constructor if (!s.Info.IsRequest()) { var fields = s.NonTagFields; if (fields.Count() != 0) { Write(""); Write($"public {className}({className} src)", false); if (fields.Count() == 1 && s.SpecName != "TPM_HANDLE") { string field = fields.First().Name; Write($" {{ {field} = src.{field}; }}"); } else { Write(""); TabIn("{"); foreach (StructField f in fields) { Write($"{f.Name} = src.{f.Name};"); } // special case if (s.SpecName == "TPM_HANDLE") { Write("Auth = src.Auth;"); TabIn("if (src.Name != null)"); Write("Name = Globs.CopyData(src.Name);"); TabOut(); } TabOut("}"); } } } // Member-wise constructor if (!s.Info.IsResponse()) { var fields = s.NonTagFields; if (fields.Count() != 0) { GenMemeberwiseCtorPrototype(className, fields); if (fields.Count() == 1) { string fName = fields.First().Name; Write($" {{ {fName} = _{fName}; }}"); } else { TabIn("{"); foreach (StructField f in fields) { Write($"{f.Name} = _{f.Name};"); } TabOut("}"); } } } GenGetUnionSelector(s); GenCloningMethods(s.Name); TabOut("}"); // end of class } // GenStructure()
static void Main(string[] args) { bool help = false; string specPath = null; string tssRootPath = null; Action actions = Action.None; Func <Lang, string> langName = l => Enum.GetName(typeof(Lang), l); var allLangs = ((Lang[])Enum.GetValues(typeof(Lang))).ToList(); var langs = new List <Lang>(); for (int i = 0; i < args.Length; ++i) { string opt = args[i]; if (opt[0] != '-' && opt[0] != '/') { help = true; PrintError($"Invalid format for option {i}: {opt}"); break; } opt = opt.Substring(1); var res = ProcessPathOption(opt, "spec", args, ref i, ref specPath); if (res == Option.ParsingError) { return; } if (res == Option.Matched) { continue; } res = ProcessPathOption(opt, "dest", args, ref i, ref tssRootPath); if (res == Option.ParsingError) { return; } if (res == Option.Matched) { continue; } if (opt == "h" || opt == "help" || opt == "?") { help = true; } else if (0 == string.Compare(opt, "extract", true)) { actions |= Action.ExtractFromDoc; } else if (0 == string.Compare(opt, "noextract", true)) { actions &= ~Action.ExtractFromDoc; } else { Lang lang = allLangs.FirstOrDefault(l => 0 == string.Compare(opt, langName(l), true)); if (lang != Lang.None) { if (!langs.Contains(lang)) { langs.Add(lang); } } else { lang = allLangs.FirstOrDefault(l => 0 == string.Compare(opt, "no" + langName(l), true)); if (lang != Lang.None) { langs = allLangs.Where(l => l != lang).ToList(); } else { help = true; PrintError($"Unrecognized option '{opt}'"); } } } } if (help) { Console.WriteLine("TSS Code Generator tool.\n" + "Copyright (c) Microsoft Corporation. All rights reserved.\n" + "\n" + "This tool (re)generates the interface part of the TPM Software Stack (TSS)\n" + "implementations for all supported programming languages/frameworks (TSS.Net,\n" + "TSS.CPP, TSS.Java, TSS.JS, TSS.Py)\n" + "\n" + "All command line parameters are case-insensitive and optional.\n" + "Option names are prepended with either dash ('-') or slash ('/') marks.\n" + "\n" + "The following options are supported:\n" + " h|help|? - Display this message\n" + " spec <path> - Path to the folder containing the TPM 2.0 specification Word\n" + " documents and/or intermediate XML representation (RawTables.xml).\n" + " By default the TssCodeGen/TpmSpec folder is used.\n" + " dest <path> - Path to the root folder containing individual TSSes to be updated.\n" + " By default the TSS implementations in this repo clone (in the\n" + " folders adjasent to the TssCodeGen folder) are updated.\n" + " extract - Force parsing the TPM 2.0 spec documents even if the intermediate\n" + " XML representation file (RawTables.xml) is available. By default\n" + " the tool will always use RawTables.xml if it is present.\n" + " dotNet, cpp, java, node, py - Any combination of these options can be used\n" + " to select TSS implementations to be updated. By default (when\n" + " none of them is present) all supported languages are updated.\n" + "\n" + "Note that the default path values used by the tool are selected in expectation\n" + "that it is run from the Visual Studio after being built from its github repo clone.\n" + "If however the binary location or folder structure is different, options 'spec'\n" + "and 'dest' will be required." + "\n" ); return; } // The TPM 2.0 spec Word docs Part 2 and 3 are parsed to produce an XML representation. // This operation is slow. By default (i.e. if no '-extract' option is specified) // CodeGen bypasses the spec parsing stage and proceeds directly off the existing XML. if (specPath == null) { string pwd = Directory.GetCurrentDirectory(); specPath = Path.GetFullPath(Path.Combine(pwd, @"..\..\..\TpmSpec")); } string rawTables = Path.GetFullPath(Path.Combine(specPath, "RawTables.xml")); if (actions.HasFlag(Action.ExtractFromDoc) || !File.Exists(rawTables)) { // Kill Word processes Process[] wordProcesses = Process.GetProcessesByName("WINWORD"); if (wordProcesses.Length != 0) { DialogResult res = MessageBox.Show("There are word processes running. Kill them?", "Kill Word Processes?", MessageBoxButtons.YesNo); if (res == DialogResult.Yes) { foreach (Process p in wordProcesses) { try { p.Kill(); } catch (Exception) {} } Thread.Sleep(2000); } } TableExtractor extractor = new TableExtractor(specPath); XmlSerializeToFile(rawTables, RawTables.Tables); } // Load the XML description of the tables, and extract into in-memory data structures List <RawTable> tables = XmlDeserializeFromFile <List <RawTable> >(rawTables); TypeExtractor tpe = new TypeExtractor(tables); tpe.Extract(); if (tssRootPath == null) { tssRootPath = @"..\..\..\..\"; } if (langs.Count == 0) { langs = allLangs.Skip(1).ToList(); } foreach (var lang in langs) { if (lang == Lang.DotNet) { continue; } var tssName = "TSS." + langName(lang).Replace("DotNet", "Net"); Console.WriteLine($"\nGenerating {tssName}..."); var cg = TargetLang.NewCodeGen(lang, tssRootPath + tssName + '\\'); TargetLang.SetTargetLang(lang); cg.Generate(); } if (langs.Contains(Lang.DotNet)) { Console.WriteLine("\nGenerating TSS.Net..."); CGenDotNet dotNetGen = new CGenDotNet(tssRootPath + @"TSS.NET\"); TargetLang.SetTargetLang(Lang.DotNet); dotNetGen.Generate(); } Console.WriteLine("\nAll done!"); }