Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        /// <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);
        }
Exemplo n.º 4
0
        /// <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()
Exemplo n.º 5
0
        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()
Exemplo n.º 6
0
        } // 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()
Exemplo n.º 7
0
        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!");
        }
Exemplo n.º 8
0
        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("}");
        }
Exemplo n.º 9
0
        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()
Exemplo n.º 10
0
        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()
Exemplo n.º 11
0
        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!");
        }