/// <summary> /// genAIS command. Always use section-by-section CRC checks /// </summary> /// <param name="coffFileName"></param> /// <param name="bootMode"></param> /// <returns>Bytes of the binary or text AIS command</returns> public static Byte[] GenAIS(String coffFileName, AISGen devAISGen, INISection[] iniSecs) { UInt32 busWidth = 8; UInt32 addrWidth = 16; UInt32 numTargetSections = 0; UInt32 numWords; UInt32 entryPoint = 0x00000000; Boolean seqReadEn = false; // Not supported on all devices String finalFxnName = null; // Not supported in all devices Hashtable UARTSendDONE_DataSection=null, UARTSendDONE_TextSection=null; // Lists to keep track of the input object and binary files List<ObjectFile> objectFiles = new List<ObjectFile>(); List<BinaryFile> binaryFiles = new List<BinaryFile>(); // COFF file objects for the main application and the AIS extras executable COFFFile AISExtrasCF=null; // Set defaults devAISGen.finalFxnName = null; // List to keep track of loadable sections and their occupied memory ranges devAISGen.sectionMemory = new List<MemoryRange>(); // Setup the binary writer to generate the temp AIS file devAISGen.devAISStream = new MemoryStream(); EndianBinaryWriter tempAIS_bw = new EndianBinaryWriter( devAISGen.devAISStream, devAISGen.devEndian); #region INI Data parsing // Get data from the GENERAL INI Section for (UInt32 i = 0; i < iniSecs.Length; i++) { INISection sec = iniSecs[i]; if (sec.iniSectionName.Equals("GENERAL", StringComparison.OrdinalIgnoreCase)) { foreach (DictionaryEntry de in sec.sectionValues) { // Read buswidth if (((String)de.Key).Equals("BUSWIDTH", StringComparison.OrdinalIgnoreCase)) busWidth = (UInt32)sec.sectionValues["BUSWIDTH"]; // Read BootMode (unless already set) if ((((String)de.Key).Equals("BOOTMODE", StringComparison.OrdinalIgnoreCase)) && (devAISGen.bootMode == BootModes.NONE)) devAISGen.bootMode = (BootModes) Enum.Parse(typeof(BootModes), (String)sec.sectionValues["BOOTMODE"], true); // Read Addr width (for I2C/SPI) if (((String)de.Key).Equals("ADDRWIDTH", StringComparison.OrdinalIgnoreCase)) addrWidth = (UInt32)sec.sectionValues["ADDRWIDTH"]; // Sequential Read ENABLE if (((String)de.Key).Equals("SEQREADEN", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["SEQREADEN"]).Equals("ON", StringComparison.OrdinalIgnoreCase)) seqReadEn = true; if (((String)sec.sectionValues["SEQREADEN"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) seqReadEn = true; } // CRC Type override if (((String)de.Key).Equals("CRCCHECKTYPE", StringComparison.OrdinalIgnoreCase)) { devAISGen.CRCType = (CRCCheckType) Enum.Parse(typeof(CRCCheckType), (String)sec.sectionValues["CRCCHECKTYPE"], true); } // Finalize fxn symbol name if (((String)de.Key).Equals("FINALFXNSYMBOLNAME", StringComparison.OrdinalIgnoreCase)) { finalFxnName = (String)sec.sectionValues["FINALFXNSYMBOLNAME"]; } // Read entrypoint value if (((String)de.Key).Equals("ENTRYPOINT", StringComparison.OrdinalIgnoreCase)) entryPoint = (UInt32)sec.sectionValues["ENTRYPOINT"]; } } if (sec.iniSectionName.Equals("BINARYINPUTFILE", StringComparison.OrdinalIgnoreCase)) { BinaryFile currFile = new BinaryFile(); currFile.fileName = null; currFile.useEntryPoint = false; currFile.loadAddr = 0x00000000; currFile.entryPointAddr = 0x00000000; foreach (DictionaryEntry de in sec.sectionValues) { // File name for binary section data if (((String)de.Key).Equals("FILENAME", StringComparison.OrdinalIgnoreCase)) { currFile.fileName = (String) sec.sectionValues["FILENAME"]; } // Binary section's load address in the memory map if (((String)de.Key).Equals("LOADADDRESS", StringComparison.OrdinalIgnoreCase)) { currFile.loadAddr = (UInt32) sec.sectionValues["LOADADDRESS"]; } // Binary section's entry point address in the memory map if (((String)de.Key).Equals("ENTRYPOINTADDRESS", StringComparison.OrdinalIgnoreCase)) { currFile.entryPointAddr = (UInt32) sec.sectionValues["ENTRYPOINTADDRESS"]; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("USEENTRYPOINT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; } } if (currFile.fileName == null) { Console.WriteLine("ERROR: File name must be provided for binary input file."); return null; } if (currFile.loadAddr == 0x00000000) { Console.WriteLine("ERROR: Valid load address must be provided for binary input file."); return null; } binaryFiles.Add(currFile); } if (sec.iniSectionName.Equals("OBJECTINPUTFILE", StringComparison.OrdinalIgnoreCase)) { ObjectFile currFile = new ObjectFile(); currFile.useEntryPoint = false; currFile.fileName = null; foreach (DictionaryEntry de in sec.sectionValues) { // File name for binary section data if (((String)de.Key).Equals("FILENAME", StringComparison.OrdinalIgnoreCase)) { currFile.fileName = (String) sec.sectionValues["FILENAME"]; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("USEENTRYPOINT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; } } if (currFile.fileName == null) { Console.WriteLine("ERROR: File name must be provided for input object file."); return null; } objectFiles.Add(currFile); } } #endregion #region AIS Generation // --------------------------------------------------------- // ****************** BEGIN AIS GENERATION ***************** // --------------------------------------------------------- Console.WriteLine("Begining the AIS file generation."); // Diaplay currently selected boot mode Console.WriteLine("AIS file being generated for bootmode: {0}.",Enum.GetName(typeof(BootModes),devAISGen.bootMode)); #region AIS Extras and UARTSendDONE Setup //Create the COFF file object for the AISExtras file (if it exists/is defined) if (devAISGen.AISExtraFileName != null) { EmbeddedFileIO.ExtractFile(Assembly.GetExecutingAssembly(), devAISGen.AISExtraFileName, false); if (File.Exists(devAISGen.AISExtraFileName)) { // The file exists, so use it AISExtrasCF = new COFFFile(devAISGen.AISExtraFileName); } else { throw new FileNotFoundException("The AISExtra file, " + devAISGen.AISExtraFileName + ", was not found."); } } // If we have the AISExtras COFF file object, use it to setup the addresses // for the AISExtra functions. These will utilize the L1P and L1D spaces that // are usually cache. if ( (AISExtrasCF != null) && (devAISGen.AISExtraFunc != null)) { // Use symbols to get address for AISExtra functions and parameters for (Int32 i = 0; i < devAISGen.AISExtraFunc.Length; i++) { Hashtable sym = AISExtrasCF.symFind("_" + devAISGen.AISExtraFunc[i].funcName); devAISGen.AISExtraFunc[i].funcAddr = (UInt32)sym["value"]; sym = AISExtrasCF.symFind(".params"); devAISGen.AISExtraFunc[i].paramAddr = (UInt32)sym["value"]; } // If the bootMode is UART we need the UARTSendDONE function if (devAISGen.bootMode == BootModes.UART) { // Set address for the UARTSendDone Function in the .text:uart section UARTSendDONE_TextSection = AISExtrasCF.secFind(".text:uart"); UARTSendDONE_DataSection = AISExtrasCF.secFind(".data:uart"); // Eliminate these as loadable since they will be loaded first, separate // from the main COFF file UARTSendDONE_TextSection["copyToTarget"] = false; UARTSendDONE_DataSection["copyToTarget"] = false; AISExtrasCF.Header["numTargetSections"] = ((UInt32)AISExtrasCF.Header["numTargetSections"] - (UInt32)2); // Set the actual run address for the UARTSendDONE function if ((UARTSendDONE_TextSection != null) && (UARTSendDONE_DataSection != null)) { Debug.DebugMSG("UART section found"); devAISGen.UARTSendDONEAddr = (UInt32)UARTSendDONE_TextSection["phyAddr"]; Hashtable sym = AISExtrasCF.symFind("_UARTSendDONE"); if (sym != null) { devAISGen.UARTSendDONEAddr = (UInt32)sym["value"]; Debug.DebugMSG("UARTSendDONE at 0x{0:X8}",devAISGen.UARTSendDONEAddr); } } else { Console.WriteLine("UARTSendDONE function not found in AISExtra COFF file!!!"); return null; } } } // Setup boolean indicating whether to include UARTSendDONE jump commands if ((devAISGen.bootMode == BootModes.UART) && (devAISGen.UARTSendDONEAddr != 0x0)) devAISGen.SendUARTSendDONE = true; else devAISGen.SendUARTSendDONE = false; #endregion #region Write AIS MAGIC Number and initial data // Write the premilinary header and fields (everything before first AIS command) switch (devAISGen.bootMode) { case BootModes.EMIFA: { if (busWidth == 16) tempAIS_bw.Write((UInt32)(0x1 << 0)|(0x2 << 4)); else tempAIS_bw.Write((UInt32)(0x0 << 0)|(0x2 << 4)); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.NAND: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); tempAIS_bw.Write((UInt32)0); tempAIS_bw.Write((UInt32)0); tempAIS_bw.Write((UInt32)0); break; } case BootModes.UART: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.I2CMASTER: { if (addrWidth == 16) tempAIS_bw.Write((UInt32)2); else tempAIS_bw.Write((UInt32)1); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.SPIMASTER: { if (addrWidth == 24) tempAIS_bw.Write((UInt32)3); else if (addrWidth == 16) tempAIS_bw.Write((UInt32)2); else tempAIS_bw.Write((UInt32)1); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } default: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } }; #endregion #region Send UARTSendDONE sections //Send UART code if it exists if (devAISGen.SendUARTSendDONE) { CRCCheckType tempCRCType = devAISGen.crcType; devAISGen.crcType = CRCCheckType.NO_CRC; devAISGen.SendUARTSendDONE = false; AISSectionLoad(AISExtrasCF, UARTSendDONE_TextSection, devAISGen); AISSectionLoad(AISExtrasCF, UARTSendDONE_DataSection, devAISGen); devAISGen.SendUARTSendDONE = true; devAISGen.crcType = tempCRCType; } #endregion #region ROM Function insertion // Insert words for ROM function execution for (UInt32 i = 0; i < devAISGen.ROMFunc.Length; i++) { for (UInt32 j = 0; j < iniSecs.Length; j++) { if (iniSecs[j].iniSectionName.Equals(devAISGen.ROMFunc[i].iniSectionName)) { UInt32 funcIndex = i; tempAIS_bw.Write((UInt32)AIS.FunctionExec); tempAIS_bw.Write((((UInt32)devAISGen.ROMFunc[i].numParams) << 16) + ((UInt32)funcIndex)); // Write Paramter values read from INI file for (Int32 k = 0; k < devAISGen.ROMFunc[i].numParams; k++) { //FIXME Debug.DebugMSG("\tParam name: {0}, Param num: {1}, Value: {2}\n", devAISGen.ROMFunc[i].paramNames[k], k, iniSecs[j].sectionValues[devAISGen.ROMFunc[i].paramNames[k].ToUpper()]); tempAIS_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.ROMFunc[i].paramNames[k].ToUpper()]); } // Call UARTSendDONE from AIS Extras if this is for UART boot if (devAISGen.SendUARTSendDONE) { tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.UARTSendDONEAddr); } } } } #endregion #region Insert seqread command if (seqReadEn == true) tempAIS_bw.Write((UInt32)AIS.SeqReadEnable); #endregion #region AIS executable data download if (AISExtrasCF != null) { // Load the AISExtras COFF file AISCOFFLoad(AISExtrasCF, devAISGen); } #endregion #region AIS Extras init function execution //Insert calls for any AISExtra Init functions (like power domains) if (AISExtrasCF != null) { for (UInt32 i = 0; i < devAISGen.AISExtraFunc.Length; i++) { if (devAISGen.AISExtraFunc[i].isInitFunc) { for (UInt32 j = 0; j < iniSecs.Length; j++) { if (iniSecs[j].iniSectionName.Equals(devAISGen.AISExtraFunc[i].iniSectionName)) { for (UInt32 k = 0; k < devAISGen.AISExtraFunc[i].numParams; k++) { // Write SET command tempAIS_bw.Write((UInt32)AIS.Set); //Write type field (32-bit only) tempAIS_bw.Write((UInt32)0x3); // Write appropriate parameter address tempAIS_bw.Write((UInt32) (devAISGen.AISExtraFunc[i].paramAddr + (k * 4))); //Write data to write tempAIS_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.AISExtraFunc[i].paramNames[k].ToString()]); //Write Sleep value (should always be zero) //tempAIS_bw.Write((UInt32)0x1000); tempAIS_bw.Write((UInt32)0x0); } // Now that params are set, Jump to function tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.AISExtraFunc[i].funcAddr); // Call UARTSendDONE from AIS Extras if this is for UART boot if (devAISGen.SendUARTSendDONE) { tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.UARTSendDONEAddr); } } } } } } #endregion Debug.DebugMSG("Starting binary file section loads."); #region Insert binary data files as SECTION_LOAD commands // Insert binary files for (Int32 i=0; i<binaryFiles.Count; i++) { if (File.Exists(binaryFiles[i].fileName)) { AISBinarySectionLoad(binaryFiles[i].fileName, devAISGen, binaryFiles[i].loadAddr); Debug.DebugMSG("Binary file {0} found.", binaryFiles[i].fileName); numTargetSections++; if (binaryFiles[i].useEntryPoint) { entryPoint = binaryFiles[i].entryPointAddr; } } else { Console.WriteLine("WARNING: Binary input file {0} was not found. Skipping.",binaryFiles[i].fileName); } } #endregion Debug.DebugMSG("Starting object file section loads."); #region COFF file parsing and loading // Create the COFF file object for the main application being loaded (if it exists) if (File.Exists(coffFileName)) { ObjectFile currFile = new ObjectFile(); currFile.useEntryPoint = true; currFile.fileName = coffFileName; // Cycle throught all other object files loaded via INI file and unset their // useEntryPoint boolean, warning us as we do Boolean showWarning = false; for (Int32 i=0; i<objectFiles.Count; i++) { // Insert binary file if (objectFiles[i].useEntryPoint) { objectFiles[i].useEntryPoint = false; showWarning = true; } } if (showWarning) Console.WriteLine("WARNING: Ignoring useEntryPoint flag from all object file sections of INI file"); objectFiles.Add(currFile); } // Insert object files for (Int32 i=0; i<objectFiles.Count; i++) { if (File.Exists(objectFiles[i].fileName)) { // FIXME: Add support to detect ELF or COFF and support ELF parsing // Parse the object file COFFFile cf = new COFFFile(objectFiles[i].fileName); if (cf != null) { // Load the object file contents AISCOFFLoad(cf, devAISGen); } else { Console.WriteLine("ERROR: Parsing the input object file {0} failed!",objectFiles[i].fileName); } // If entry point is still null, use the coff file one if (entryPoint == 0x00000000) { if (objectFiles[i].useEntryPoint) { entryPoint = (UInt32)cf.Header["optEntryPoint"]; } } // Insert final function register function if (devAISGen.finalFxnName != null) { Hashtable symbol; // Look for the symbol in the Coff file symbols table symbol = cf.symFind(devAISGen.finalFxnName); // If found, insert the command if (symbol != null) { tempAIS_bw.Write((UInt32)AIS.FinalFxnReg); tempAIS_bw.Write((UInt32)symbol["value"]); Console.WriteLine("Finalize function symbol, '{0}', found as address 0x{1:X8}.",devAISGen.finalFxnName,(UInt32)symbol["value"]); } else { Console.WriteLine("Finalize function symbol, '{0}', not found.",devAISGen.finalFxnName); } } // Close object file if (cf != null) cf.Close(); } else { Console.WriteLine("WARNING: Input object file {0} was not found. Skipping.",objectFiles[i].fileName); } } #endregion #region Insert Final JUMP_CLOSE command tempAIS_bw.Write((UInt32)AIS.Jump_Close); tempAIS_bw.Write(entryPoint); if (entryPoint == 0x00000000) Console.WriteLine("WARNING: Entry point never set or set to invalid value"); // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); #endregion // Console output Console.WriteLine("AIS file generation was successful."); // --------------------------------------------------------- // ******************* END AIS GENERATION ****************** // --------------------------------------------------------- #endregion #region Prepare the return byte array // Now create return Byte array based on tempAIS file and the bootmode EndianBinaryReader tempAIS_br; tempAIS_br = new EndianBinaryReader( devAISGen.devAISStream, Endian.LittleEndian); // Setup the binary reader object numWords = ((UInt32)tempAIS_br.BaseStream.Length) >> 2; devAISGen.AISData = new Byte[numWords << 2]; //Each word converts to 4 binary bytes Debug.DebugMSG("Number of words in the stream is {0}", numWords); // Copy the data to the output Byte array for (UInt32 i = 0; i < numWords; i++) { BitConverter.GetBytes(tempAIS_br.ReadUInt32()).CopyTo(devAISGen.AISData, i * 4); } // Close the binary reader tempAIS_br.Close(); // Close the COFF files since we are done with them if (AISExtrasCF != null) { AISExtrasCF.Close(); } // Clean up any embedded file resources that may have been extracted EmbeddedFileIO.CleanUpEmbeddedFiles(); #endregion // Return Byte Array return devAISGen.AISData; }
/// <summary> /// SecureGenAIS command. /// </summary> /// <param name="coffFileName">File name of input .out file</param> /// <param name="bootMode">AISGen Object for the particular device</param> /// <returns>Bytes of the binary or AIS boot image</returns> public static Byte[] SecureGenAIS(String coffFileName, AISGen devAISGen, INISection[] iniSecs) { UInt32 busWidth = 8; UInt32 addrWidth = 16; UInt32 numTargetSections = 0; UInt32 numWords; UInt32 entryPoint = 0x00000000; Boolean seqReadEn = false; // Not supported on all devices Byte[] secureKeyData = null; String currHashAlgorithmString = "SHA1"; // Default hash algorithm Hashtable UARTSendDONE_DataSection=null, UARTSendDONE_TextSection=null; // Hash tables to keep track of the input object and binary files List<SecureObjectFile> objectFiles = new List<SecureObjectFile>(); List<SecureBinaryFile> binaryFiles = new List<SecureBinaryFile>(); // COFF file objects for the main application and the AIS extras executable COFFFile AISExtrasCF=null; // Set defaults devAISGen.secureType = SecureType.NONE; devAISGen.bootLoaderExitType = BootLoaderExitType.NONE; devAISGen.currHashAlgorithmValue = SHA_Algorithm.SHA1; devAISGen.finalFxnName = null; devAISGen.sectionsToEncrypt = null; devAISGen.rsaObject = null; devAISGen.customerEncryptionKey = null; devAISGen.keyEncryptionKey = null; devAISGen.genericKeyHeaderData = null; devAISGen.currHashAlgorithm = null; devAISGen.signatureByteCnt = 0; devAISGen.signatureCnt = 0; // List to keep track of loadable sections and their occupied memory ranges devAISGen.sectionMemory = new List<MemoryRange>(); // Setup the binary writer to generate the temp AIS file devAISGen.devAISStream = new MemoryStream(); EndianBinaryWriter tempAIS_bw = new EndianBinaryWriter( devAISGen.devAISStream, devAISGen.devEndian); // Setup the binary writer to store data for signing devAISGen.signatureStream = new MemoryStream(); EndianBinaryWriter sig_bw = new EndianBinaryWriter( devAISGen.signatureStream, devAISGen.devEndian); #region INI Data parsing // Get data from the GENERAL INI Section for (UInt32 i = 0; i < iniSecs.Length; i++) { INISection sec = iniSecs[i]; if (sec.iniSectionName.Equals("GENERAL", StringComparison.OrdinalIgnoreCase)) { foreach (DictionaryEntry de in sec.sectionValues) { // Read buswidth if (((String)de.Key).Equals("BUSWIDTH", StringComparison.OrdinalIgnoreCase)) busWidth = (UInt32)sec.sectionValues["BUSWIDTH"]; // Read BootMode (unless already set) if ((((String)de.Key).Equals("BOOTMODE", StringComparison.OrdinalIgnoreCase)) && (devAISGen.bootMode == BootModes.NONE)) devAISGen.bootMode = (BootModes) Enum.Parse(typeof(BootModes), (String)sec.sectionValues["BOOTMODE"], true); // Read Addr width (for I2C/SPI) if (((String)de.Key).Equals("ADDRWIDTH", StringComparison.OrdinalIgnoreCase)) addrWidth = (UInt32)sec.sectionValues["ADDRWIDTH"]; // Sequential Read ENABLE if (((String)de.Key).Equals("SEQREADEN", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["SEQREADEN"]).Equals("ON", StringComparison.OrdinalIgnoreCase)) seqReadEn = true; if (((String)sec.sectionValues["SEQREADEN"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) seqReadEn = true; } // Finalize fxn symbol name if (((String)de.Key).Equals("FINALFXNSYMBOLNAME", StringComparison.OrdinalIgnoreCase)) { devAISGen.finalFxnName = (String)sec.sectionValues["FINALFXNSYMBOLNAME"]; } // Read entrypoint value if (((String)de.Key).Equals("ENTRYPOINT", StringComparison.OrdinalIgnoreCase)) entryPoint = (UInt32)sec.sectionValues["ENTRYPOINT"]; } } if (sec.iniSectionName.Equals("SECURITY", StringComparison.OrdinalIgnoreCase)) { foreach (DictionaryEntry de in sec.sectionValues) { // Security Type if (((String)de.Key).Equals("SECURITYTYPE", StringComparison.OrdinalIgnoreCase)) { devAISGen.secureType = (SecureType) Enum.Parse(typeof(SecureType), (String)sec.sectionValues["SECURITYTYPE"], true); } // Boot exit type if (((String)de.Key).Equals("BOOTEXITTYPE", StringComparison.OrdinalIgnoreCase)) { devAISGen.bootLoaderExitType = (BootLoaderExitType) Enum.Parse(typeof(BootLoaderExitType), (String)sec.sectionValues["BOOTEXITTYPE"], true); } // Encrypted section settings if (((String)de.Key).Equals("ENCRYPTSECTIONS", StringComparison.OrdinalIgnoreCase)) { Char[] separators = new Char[]{','}; String encryptSections = (String)sec.sectionValues["ENCRYPTSECTIONS"]; devAISGen.sectionsToEncrypt = encryptSections.Split(separators,StringSplitOptions.RemoveEmptyEntries); for( int k = 0; k<devAISGen.sectionsToEncrypt.Length; k++) { devAISGen.sectionsToEncrypt[k] = devAISGen.sectionsToEncrypt[k].Trim(); } } // AES Encryption Key (CEK) if (((String)de.Key).Equals("ENCRYPTIONKEY", StringComparison.OrdinalIgnoreCase)) { devAISGen.customerEncryptionKey = new Byte[16]; devAISGen.CEKInitialValue = new Byte[16]; String keyString = (String)sec.sectionValues["ENCRYPTIONKEY"]; if (keyString.Length != 32) { Console.WriteLine("AES Encryption Key is wrong length!"); return null; } for (int j=0; j<keyString.Length; j+=2) { devAISGen.customerEncryptionKey[(j>>1)] = Convert.ToByte(keyString.Substring(j,2),16); } // Generate IV as encrypted version of AES Key using (MemoryStream ms = new MemoryStream(devAISGen.CEKInitialValue)) { Aes myAES = new AesManaged(); myAES.KeySize = 128; myAES.Mode = CipherMode.ECB; myAES.Padding = PaddingMode.None; ICryptoTransform encryptor = myAES.CreateEncryptor(devAISGen.customerEncryptionKey, new Byte[16]); CryptoStream cs = new CryptoStream(ms,encryptor,CryptoStreamMode.Write); cs.Write(devAISGen.customerEncryptionKey,0,devAISGen.customerEncryptionKey.Length); } FileIO.SetFileData("cek.bin",devAISGen.customerEncryptionKey,true); FileIO.SetFileText("FROM_cek.init",KeyToBinaryString(devAISGen.customerEncryptionKey,0xA,true,true),true); FileIO.SetFileData("cek_cbc_iv.bin",devAISGen.CEKInitialValue,true); } // Key Encryption Key (not normally known, here for debug/testing purposes) if (((String)de.Key).Equals("KEYENCRYPTIONKEY", StringComparison.OrdinalIgnoreCase)) { devAISGen.keyEncryptionKey = new Byte[16]; String keyString = (String)sec.sectionValues["KEYENCRYPTIONKEY"]; if (keyString.Length != 32) { Console.WriteLine("Key Encryption Key is wrong length!"); return null; } for (int j=0; j<keyString.Length; j+=2) { devAISGen.keyEncryptionKey[(j>>1)] = Convert.ToByte(keyString.Substring(j,2),16); } FileIO.SetFileData("kek.bin",devAISGen.keyEncryptionKey,true); FileIO.SetFileText("FROM_kek.init",KeyToBinaryString(devAISGen.keyEncryptionKey,0xE,true,true),true); } // Generic Secure Option to force JTAG off as part of the key loading if (((String)de.Key).Equals("GENERICJTAGFORCEOFF", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["GENERICJTAGFORCEOFF"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) devAISGen.genericJTAGForceOff = true; else devAISGen.genericJTAGForceOff = false; } // Generic Secure Option to select the hash algorithm for signatures if (((String)de.Key).Equals("GENERICSHASELECTION", StringComparison.OrdinalIgnoreCase)) { currHashAlgorithmString = (String)sec.sectionValues["GENERICSHASELECTION"]; devAISGen.currHashAlgorithmValue = (SHA_Algorithm) Enum.Parse(typeof(SHA_Algorithm), (String)sec.sectionValues["GENERICSHASELECTION"], true); } // Generic Key Header file if (((String)de.Key).Equals("GENKEYHEADERFILENAME", StringComparison.OrdinalIgnoreCase)) { String genKeyHeaderFileName = (String)sec.sectionValues["GENKEYHEADERFILENAME"]; devAISGen.genericKeyHeaderData = new Byte[32]; // Open file, read contents, copy to our AIS array using (FileStream tempFS = new FileStream(genKeyHeaderFileName, FileMode.Open, FileAccess.Read)) { tempFS.Read(devAISGen.genericKeyHeaderData,0,32); } } // Custom Secure RSA Key File if (((String)de.Key).Equals("RSAKEYFILENAME", StringComparison.OrdinalIgnoreCase)) { String rsaKeyFileName = (String)sec.sectionValues["RSAKEYFILENAME"]; devAISGen.rsaObject = RSAKey.LoadFromFile(rsaKeyFileName); if (devAISGen.rsaObject == null) { Console.WriteLine("RSA key loading failed!"); return null; } // Update the hash algo string if RSA key size is 2048 bits if (devAISGen.rsaObject.KeySize == 2048) { currHashAlgorithmString = "SHA256"; devAISGen.currHashAlgorithmValue = SHA_Algorithm.SHA256; } Console.WriteLine("MapNameToOid({1}) = {0}",CryptoConfig.MapNameToOID(currHashAlgorithmString),currHashAlgorithmString); } } } if (sec.iniSectionName.Equals("SECURELEGACY", StringComparison.OrdinalIgnoreCase)) { foreach (DictionaryEntry de in sec.sectionValues) { // Legacy secure option to encrypt the boot image if (((String)de.Key).Equals("ENCRYPTIMAGE", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["ENCRYPTIMAGE"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) devAISGen.secureLegacyEncryptImage = true; else devAISGen.secureLegacyEncryptImage = false; } } devAISGen.bootMode = BootModes.LEGACY; } if (sec.iniSectionName.Equals("BINARYINPUTFILE", StringComparison.OrdinalIgnoreCase)) { SecureBinaryFile currFile = new SecureBinaryFile(); currFile.fileName = null; currFile.useEntryPoint = false; currFile.loadAddr = 0x00000000; currFile.entryPointAddr = 0x00000000; currFile.encrypt = false; foreach (DictionaryEntry de in sec.sectionValues) { // File name for binary section data if (((String)de.Key).Equals("FILENAME", StringComparison.OrdinalIgnoreCase)) { currFile.fileName = (String) sec.sectionValues["FILENAME"]; } // Binary section's load address in the memory map if (((String)de.Key).Equals("LOADADDRESS", StringComparison.OrdinalIgnoreCase)) { currFile.loadAddr = (UInt32) sec.sectionValues["LOADADDRESS"]; } // Binary section's entry point address in the memory map if (((String)de.Key).Equals("ENTRYPOINTADDRESS", StringComparison.OrdinalIgnoreCase)) { currFile.entryPointAddr = (UInt32) sec.sectionValues["ENTRYPOINTADDRESS"]; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("USEENTRYPOINT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("ENCRYPT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["ENCRYPT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.encrypt = true; if (((String)sec.sectionValues["ENCRYPT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.encrypt = true; } } if (currFile.fileName == null) { Console.WriteLine("ERROR: File name must be provided for binary input file."); return null; } if (currFile.loadAddr == 0x00000000) { Console.WriteLine("ERROR: Valid load address must be provided for binary input file."); return null; } binaryFiles.Add(currFile); } if (sec.iniSectionName.Equals("OBJECTINPUTFILE", StringComparison.OrdinalIgnoreCase)) { SecureObjectFile currFile = new SecureObjectFile(); currFile.useEntryPoint = false; currFile.fileName = null; currFile.encrypt = false; foreach (DictionaryEntry de in sec.sectionValues) { // File name for binary section data if (((String)de.Key).Equals("FILENAME", StringComparison.OrdinalIgnoreCase)) { currFile.fileName = (String) sec.sectionValues["FILENAME"]; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("USEENTRYPOINT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; if (((String)sec.sectionValues["USEENTRYPOINT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.useEntryPoint = true; } // Option to specify that this entry point should be used for AIS if (((String)de.Key).Equals("ENCRYPT", StringComparison.OrdinalIgnoreCase)) { if (((String)sec.sectionValues["ENCRYPT"]).Equals("YES", StringComparison.OrdinalIgnoreCase)) currFile.encrypt = true; if (((String)sec.sectionValues["ENCRYPT"]).Equals("TRUE", StringComparison.OrdinalIgnoreCase)) currFile.encrypt = true; } } if (currFile.fileName == null) { Console.WriteLine("ERROR: File name must be provided for input object file."); return null; } objectFiles.Add(currFile); } } #endregion #region INI data validation // INI Input Validation // 1) Make sure a secure type has been specified if (devAISGen.secureType == SecureType.NONE) { Console.WriteLine("ERROR: The device's security type was not specified!"); return null; } else { Console.WriteLine("Creating boot image for a {0} secure device.",devAISGen.secureType.ToString().ToLower()); // 2) Make sure we have a CEK and IV if (devAISGen.customerEncryptionKey == null) { Console.WriteLine("ERROR: No encryption key was specified!"); return null; } // 3) If custom secure, make sure we have an rsaObject and CEK if ((devAISGen.secureType == SecureType.CUSTOM) && (devAISGen.rsaObject == null)) { Console.WriteLine("ERROR: No RSA key file was specified!"); return null; } // 3b) Make sure RSA key size is supported if ((devAISGen.secureType == SecureType.CUSTOM) && (devAISGen.rsaObject != null)) { if ( (devAISGen.rsaObject.KeySize != 1024) && (devAISGen.rsaObject.KeySize != 2048) ) { Console.WriteLine("ERROR: No RSA key size is invalid!"); return null; } else { Console.WriteLine("INFO: RSA key is {0} bits.",devAISGen.rsaObject.KeySize); } } // 4) Specify Boot Exit type (if not legacy boot) if (devAISGen.bootMode != BootModes.LEGACY) { if (devAISGen.bootLoaderExitType == BootLoaderExitType.NONE) { Console.WriteLine("ERROR: No boot loader exit type was specified!"); return null; } else { Console.WriteLine("INFO: Boot exit type has been selected as {0}.",devAISGen.bootLoaderExitType); } } // 5) If generic secure, make sure we have the CEK header info (either encrypted or unencrypted) if ((devAISGen.secureType == SecureType.GENERIC) && (devAISGen.genericKeyHeaderData == null)) { Console.WriteLine("WARNING: Encrypted Key Header data is absent - generating plaintext version. "); Console.WriteLine(" The Customer Encryption Key will be transferred in plaintext! "); } // 6) Give warning if generic device and no sections are specified for encryption if (devAISGen.bootMode != BootModes.LEGACY) { if ((devAISGen.secureType == SecureType.GENERIC) && (devAISGen.sectionsToEncrypt == null)) { Console.WriteLine("WARNING: Generic Secure device was specified, but no input sections were indicated for encryption."); Console.WriteLine(" Only boot image signing will take place."); } } } // 2) Make sure valid hash algorithm was selected try { devAISGen.currHashAlgorithm = HashAlgorithm.Create(currHashAlgorithmString); Console.WriteLine("INFO: Current SHA algorithm is {0}.",devAISGen.currHashAlgorithmValue); } catch (Exception e) { Console.WriteLine("Invalid Hash Algorithm Selected. Exception message: {0}.",e.Message); return null; } #endregion #region Secure Key Structure and Data preparation if ( devAISGen.secureType == SecureType.GENERIC ) { if ((devAISGen.genericKeyHeaderData != null) && (devAISGen.genericKeyHeaderData.Length >= 32)) { // Create our own key header secureKeyData = new Byte[32]; Array.Copy(devAISGen.genericKeyHeaderData,0,secureKeyData,0,32); } else { // Create our own key header secureKeyData = new Byte[32]; // Init with Random Data (new Random()).NextBytes(secureKeyData); // Copy in the magic word for the generic key header structure BitConverter.GetBytes((UInt32)SecureLoadMagic.GENKEY_MAGIC).CopyTo(secureKeyData, 0); // Insert JTAGForceOff word BitConverter.GetBytes( (UInt32) (devAISGen.genericJTAGForceOff ? 0x00000001 : 0x00000000) ).CopyTo(secureKeyData, 4); // Inset Hash algorithm selection word (right now default to SHA-1 BitConverter.GetBytes( (UInt32)devAISGen.currHashAlgorithmValue ).CopyTo(secureKeyData, 8); // Insert key Data (at offset 16) devAISGen.customerEncryptionKey.CopyTo(secureKeyData, 16); // FIXME: For debug write the data out to file FileIO.SetFileData("gen_keyhdr_unencrypted.bin",secureKeyData,true); // FIXME: Debug to write out the encrypted CEK structure (encrypted with KEK, using KEK encrypted KEK as IV) if (devAISGen.keyEncryptionKey != null) { Byte[] iv = new Byte[16]; using (MemoryStream ms = new MemoryStream(iv)) { Aes myAES = new AesManaged(); myAES.KeySize = 128; myAES.Mode = CipherMode.ECB; myAES.Padding = PaddingMode.None; ICryptoTransform encryptor = myAES.CreateEncryptor(devAISGen.keyEncryptionKey, new Byte[16]); CryptoStream cs = new CryptoStream(ms,encryptor,CryptoStreamMode.Write); cs.Write(devAISGen.keyEncryptionKey,0,devAISGen.keyEncryptionKey.Length); } Byte[] encSecureKeyData = new Byte[32]; using (MemoryStream ms = new MemoryStream(encSecureKeyData)) { Aes myAES = new AesManaged(); myAES.KeySize = 128; myAES.Mode = CipherMode.CBC; myAES.Padding = PaddingMode.None; ICryptoTransform encryptor = myAES.CreateEncryptor(devAISGen.keyEncryptionKey, iv); CryptoStream cs = new CryptoStream(ms,encryptor,CryptoStreamMode.Write); cs.Write(secureKeyData,0,secureKeyData.Length); } // FIXME: For debug write the data out to file FileIO.SetFileData("gen_keyhdr_encrypted.bin",encSecureKeyData,true); } } } else if ( devAISGen.secureType == SecureType.CUSTOM ) { // Create RPK Verify Struct secureKeyData = RSAKey.CreateCustomSecureKeyVerifyStruct(devAISGen.rsaObject); FileIO.SetFileData("rpk_struct.bin",secureKeyData,true); // Calculate the SHA hash of the Root Public Key Byte[] digest = devAISGen.currHashAlgorithm.ComputeHash(secureKeyData); #if (!OLD_MPK_METHOD) for (int i=16;i<digest.Length;i++) { digest[i-16] ^= digest[i]; } #endif // Write the expected MPK (hash of RPK structure truncated to 128 bits) in binary format to file mpk.bin Byte[] mpk = new Byte[16]; Array.Copy(digest,0,mpk,0,16); FileIO.SetFileData("mpk.bin",mpk,true); FileIO.SetFileText("FROM_mpk.init",KeyToBinaryString(mpk,0x12,false,true),true); } #endregion #region Handle the case of Legacy boot mode if (devAISGen.bootMode == BootModes.LEGACY) { UInt32 fileSize = 0, secureDataSize = 0, totalImgSize = 0, paddingSize = 0; UInt32 loadAddr = 0; Byte[] fileData; // Validate an input binary file was given in the INI file if (binaryFiles.Count == 0) { Console.WriteLine("ERROR: You did not supply a binary file section in the INI file!"); return null; } if (binaryFiles.Count > 1) { Console.WriteLine("WARNING: You supplied too many biinary file sections in the INI file."); Console.WriteLine(" Only using the first one."); } // Set load addr to start of L2 for legacy boot mode loadAddr = devAISGen.Cache[0].startAddr + 0x10; // Figure out the size of the secure data region (signature + keystruct) if (devAISGen.secureType == SecureType.CUSTOM) { // On custom secure we have rsa keySize bits for signature and modulus of key struct, // plus eight additional bytes from key struct secureDataSize = (UInt32) (8 + (devAISGen.rsaObject.KeySize >> 3) + (devAISGen.rsaObject.KeySize >> 3)); } else if (devAISGen.secureType == SecureType.GENERIC) { // On generic secure we have 32 for key and HashSize bits rounded up to nearst 16 bytes // for signature data. secureDataSize = (UInt32) (32 + ((((devAISGen.currHashAlgorithm.HashSize >> 3)+15)>>4)<<4)); } // Verify legacy input binary file exists, and get data if it does if (File.Exists(binaryFiles[0].fileName)) { Byte[] tempFileData = FileIO.GetFileData(binaryFiles[0].fileName); fileSize = (UInt32) tempFileData.Length; totalImgSize = 16 + fileSize + secureDataSize; if (totalImgSize > 16*1024) { Console.WriteLine("The input image is too large. Reduce its size by {0} bytes.", (totalImgSize - (16*1024))); return null; } // Figure out how much to pad input file region to acheive complete image ending on 1K boundary paddingSize = (((totalImgSize+1023) >> 10) << 10) - totalImgSize; // Copy to final data array of fileSize fileSize = fileSize + paddingSize; fileData = new Byte[fileSize]; tempFileData.CopyTo(fileData,0); // Adjust total image size to final amount totalImgSize = 16 + fileSize + secureDataSize; } else { Console.WriteLine("Error: Binary file was not found!"); return null; } if ( ((binaryFiles[0].entryPointAddr & 0x00FFFFFF) < loadAddr) || ((binaryFiles[0].entryPointAddr & 0x00FFFFFF) > (loadAddr+fileSize)) ) { Console.WriteLine("ERROR: Entry point falls outside load image region."); return null; } // Place header // Config Word - indicates total image size, nor width (if applicable) if (busWidth == 16) { tempAIS_bw.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xF) << 8)|(0x1 << 0)|(0x0 << 4))); sig_bw.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xF) << 8)|(0x1 << 0)|(0x0 << 4))); } else { tempAIS_bw.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xF) << 8)|(0x0 << 0)|(0x0 << 4))); sig_bw.Write((UInt32)(((((totalImgSize >> 10)-1) & 0xF) << 8)|(0x0 << 0)|(0x0 << 4))); } devAISGen.signatureByteCnt += 4; // Magic Number - indicates signed or encrypted if (devAISGen.secureLegacyEncryptImage) { tempAIS_bw.Write((UInt32)SecureLegacyMagic.ENCMOD_MAGIC); sig_bw.Write((UInt32)SecureLegacyMagic.ENCMOD_MAGIC); } else { tempAIS_bw.Write((UInt32)SecureLegacyMagic.SIGNMOD_MAGIC); sig_bw.Write((UInt32)SecureLegacyMagic.SIGNMOD_MAGIC); } devAISGen.signatureByteCnt += 4; // Entry Point - where to jump within the image upon load tempAIS_bw.Write( (UInt32)binaryFiles[0].entryPointAddr ); sig_bw.Write( (UInt32)binaryFiles[0].entryPointAddr ); devAISGen.signatureByteCnt += 4; // SecureDataSize - size of data following image for key struct & signature tempAIS_bw.Write( (UInt32)secureDataSize ); sig_bw.Write( (UInt32)secureDataSize ); // Now place padded binary contents if (!devAISGen.secureLegacyEncryptImage) { // Non-encrypted section tempAIS_bw.Write(fileData); sig_bw.Write(fileData); } else { // Encrypted section // Write unencrypted data to the signature buffer sig_bw.Write(fileData); // Encrypt data using CBC algorithm try { Byte[] encData = AesManagedUtil.AesCTSEncrypt(fileData,devAISGen.customerEncryptionKey,devAISGen.CEKInitialValue); // Write encrypted section data out to AIS data stream tempAIS_bw.Write(encData); } catch(Exception e) { Console.WriteLine("Exception during encryption operation: {0}",e.Message); } } devAISGen.signatureByteCnt += (Int32) fileSize; // Now place the key data tempAIS_bw.Write(secureKeyData); sig_bw.Write(secureKeyData); devAISGen.signatureByteCnt += secureKeyData.Length; // Finally place the signature which covers the entire image SecureAISInsertSignature(devAISGen.signatureStream, devAISGen); // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); devAISGen.signatureStream.Close(); } #endregion #region AIS Generation else { // --------------------------------------------------------- // ****************** BEGIN AIS GENERATION ***************** // --------------------------------------------------------- Console.WriteLine("Begining the AIS file generation."); // Diaplay currently selected boot mode Console.WriteLine("AIS file being generated for bootmode: {0}.",Enum.GetName(typeof(BootModes),devAISGen.bootMode)); #region AIS Extras and UARTSendDONE Setup //Create the COFF file object for the AISExtras file (if it exists/is defined) if (devAISGen.AISExtraFileName != null) { EmbeddedFileIO.ExtractFile(Assembly.GetExecutingAssembly(), devAISGen.AISExtraFileName, false); if (File.Exists(devAISGen.AISExtraFileName)) { // The file exists, so use it AISExtrasCF = new COFFFile(devAISGen.AISExtraFileName); } else { throw new FileNotFoundException("The AISExtra file, " + devAISGen.AISExtraFileName + ", was not found."); } } // If we have the AISExtras COFF file object, use it to setup the addresses // for the AISExtra functions. These will utilize the L1P and L1D spaces that // are usually cache. if ( (AISExtrasCF != null) && (devAISGen.AISExtraFunc != null)) { // Use symbols to get address for AISExtra functions and parameters for (Int32 i = 0; i < devAISGen.AISExtraFunc.Length; i++) { Hashtable sym = AISExtrasCF.symFind("_" + devAISGen.AISExtraFunc[i].funcName); devAISGen.AISExtraFunc[i].funcAddr = (UInt32)sym["value"]; sym = AISExtrasCF.symFind(".params"); devAISGen.AISExtraFunc[i].paramAddr = (UInt32)sym["value"]; } // If the bootMode is UART we need the UARTSendDONE function if (devAISGen.bootMode == BootModes.UART) { // Set address for the UARTSendDone Function in the .text:uart section UARTSendDONE_TextSection = AISExtrasCF.secFind(".text:uart"); UARTSendDONE_DataSection = AISExtrasCF.secFind(".data:uart"); // Eliminate these as loadable since they will be loaded first, separate // from the main COFF file UARTSendDONE_TextSection["copyToTarget"] = false; UARTSendDONE_DataSection["copyToTarget"] = false; AISExtrasCF.Header["numTargetSections"] = ((UInt32)AISExtrasCF.Header["numTargetSections"] - (UInt32)2); // Set the actual run address for the UARTSendDONE function if ((UARTSendDONE_TextSection != null) && (UARTSendDONE_DataSection != null)) { Debug.DebugMSG("UART section found"); devAISGen.UARTSendDONEAddr = (UInt32)UARTSendDONE_TextSection["phyAddr"]; Hashtable sym = AISExtrasCF.symFind("_UARTSendDONE"); if (sym != null) { devAISGen.UARTSendDONEAddr = (UInt32)sym["value"]; Debug.DebugMSG("UARTSendDONE at 0x{0:X8}",devAISGen.UARTSendDONEAddr); } } else { Console.WriteLine("UARTSendDONE function not found in AISExtra COFF file!!!"); return null; } } } // Setup boolean indicating whether to include UARTSendDONE jump commands if ((devAISGen.bootMode == BootModes.UART) && (devAISGen.UARTSendDONEAddr != 0x0)) devAISGen.SendUARTSendDONE = true; else devAISGen.SendUARTSendDONE = false; #endregion #region Write AIS MAGIC Number and initial data // Write the premilinary header and fields (everything before first AIS command) switch (devAISGen.bootMode) { case BootModes.EMIFA: { if (busWidth == 16) tempAIS_bw.Write((UInt32)(0x1 << 0)|(0x2 << 4)); else tempAIS_bw.Write((UInt32)(0x0 << 0)|(0x2 << 4)); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.NAND: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); tempAIS_bw.Write((UInt32)0); tempAIS_bw.Write((UInt32)0); tempAIS_bw.Write((UInt32)0); break; } case BootModes.UART: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.I2CMASTER: { if (addrWidth == 16) tempAIS_bw.Write((UInt32)2); else tempAIS_bw.Write((UInt32)1); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } case BootModes.SPIMASTER: { if (addrWidth == 24) tempAIS_bw.Write((UInt32)3); else if (addrWidth == 16) tempAIS_bw.Write((UInt32)2); else tempAIS_bw.Write((UInt32)1); tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } default: { tempAIS_bw.Write((UInt32)AIS.MagicNumber); break; } }; // Add the AIS magic number to signature buffer if ( devAISGen.secureType != SecureType.NONE ) { sig_bw.Write((UInt32)AIS.MagicNumber); devAISGen.signatureByteCnt += 4; } #endregion #region Send Secure Key Load command and data tempAIS_bw.Write((UInt32)AIS.SecureKeyLoad); sig_bw.Write((UInt32)AIS.SecureKeyLoad); devAISGen.signatureByteCnt += 4; tempAIS_bw.Write(secureKeyData); sig_bw.Write(secureKeyData); devAISGen.signatureByteCnt += secureKeyData.Length; #endregion #region Send the exit mode type if ( devAISGen.secureType != SecureType.NONE ) { // Write AIS opcode tempAIS_bw.Write((UInt32)AIS.SetSecExitMode); sig_bw.Write((UInt32)AIS.SetSecExitMode); // Write exit type tempAIS_bw.Write((UInt32)devAISGen.bootLoaderExitType); sig_bw.Write((UInt32)devAISGen.bootLoaderExitType); devAISGen.signatureByteCnt += 8; } #endregion #region Send UARTSendDONE sections // Send UART code if it exists if (devAISGen.SendUARTSendDONE) { CRCCheckType tempCRCType = devAISGen.crcType; devAISGen.crcType = CRCCheckType.NO_CRC; devAISGen.SendUARTSendDONE = false; SecureAISSectionLoad(AISExtrasCF, UARTSendDONE_TextSection, devAISGen, false); SecureAISSectionLoad(AISExtrasCF, UARTSendDONE_DataSection, devAISGen, false); devAISGen.SendUARTSendDONE = true; devAISGen.crcType = tempCRCType; } #endregion #region ROM Function insertion // Insert words for ROM function execution for (UInt32 i = 0; i < devAISGen.ROMFunc.Length; i++) { for (UInt32 j = 0; j < iniSecs.Length; j++) { if (iniSecs[j].iniSectionName.Equals(devAISGen.ROMFunc[i].iniSectionName)) { UInt32 funcIndex = i; tempAIS_bw.Write((UInt32)AIS.FunctionExec); sig_bw.Write((UInt32)AIS.FunctionExec); devAISGen.signatureByteCnt += 4; tempAIS_bw.Write((((UInt32)devAISGen.ROMFunc[i].numParams) << 16) + ((UInt32)funcIndex)); sig_bw.Write((((UInt32)devAISGen.ROMFunc[i].numParams) << 16) + ((UInt32)funcIndex)); devAISGen.signatureByteCnt += 4; // Write Paramter values read from INI file for (Int32 k = 0; k < devAISGen.ROMFunc[i].numParams; k++) { //FIXME Debug.DebugMSG("\tParam name: {0}, Param num: {1}, Value: {2}\n", devAISGen.ROMFunc[i].paramNames[k], k, iniSecs[j].sectionValues[devAISGen.ROMFunc[i].paramNames[k].ToUpper()]); tempAIS_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.ROMFunc[i].paramNames[k].ToUpper()]); sig_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.ROMFunc[i].paramNames[k].ToUpper()]); devAISGen.signatureByteCnt += 4; } //Insert signature SecureAISInsertSignature(devAISGen.signatureStream,devAISGen); // Call UARTSendDONE from AIS Extras if this is for UART boot if (devAISGen.SendUARTSendDONE) { tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.UARTSendDONEAddr); sig_bw.Write((UInt32)AIS.Jump); sig_bw.Write(devAISGen.UARTSendDONEAddr); devAISGen.signatureByteCnt += 8; // Insert signature SecureAISInsertSignature(devAISGen.signatureStream,devAISGen); } } } } #endregion #region Insert seqread command if (seqReadEn == true) { tempAIS_bw.Write((UInt32)AIS.SeqReadEnable); sig_bw.Write((UInt32)AIS.SeqReadEnable); devAISGen.signatureByteCnt += 4; } #endregion #region AIS executable data download if (AISExtrasCF != null) { // Load the AISExtras COFF file SecureAISCOFFLoad(AISExtrasCF, devAISGen); // Increment section count numTargetSections += (UInt32)AISExtrasCF.Header["numTargetSections"]; } #endregion #region AIS Extras init function execution //Insert calls for any AISExtra Init functions (like power domains) if (AISExtrasCF != null) { for (UInt32 i = 0; i < devAISGen.AISExtraFunc.Length; i++) { if (devAISGen.AISExtraFunc[i].isInitFunc) { for (UInt32 j = 0; j < iniSecs.Length; j++) { if (iniSecs[j].iniSectionName.Equals(devAISGen.AISExtraFunc[i].iniSectionName)) { for (UInt32 k = 0; k < devAISGen.AISExtraFunc[i].numParams; k++) { // Write SET command tempAIS_bw.Write((UInt32)AIS.Set); sig_bw.Write((UInt32)AIS.Set); //Write type field (32-bit only) tempAIS_bw.Write((UInt32)0x3); sig_bw.Write((UInt32)0x3); // Write appropriate parameter address tempAIS_bw.Write((UInt32) (devAISGen.AISExtraFunc[i].paramAddr + (k * 4))); sig_bw.Write((UInt32) (devAISGen.AISExtraFunc[i].paramAddr + (k * 4))); //Write data to write tempAIS_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.AISExtraFunc[i].paramNames[k].ToString()]); sig_bw.Write((UInt32)iniSecs[j].sectionValues[devAISGen.AISExtraFunc[i].paramNames[k].ToString()]); //Write Sleep value (should always be zero) tempAIS_bw.Write((UInt32)0x0); sig_bw.Write((UInt32)0x0); devAISGen.signatureByteCnt += 20; // Insert signature SecureAISInsertSignature(devAISGen.signatureStream, devAISGen); } // Now that params are set, Jump to function tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.AISExtraFunc[i].funcAddr); sig_bw.Write((UInt32)AIS.Jump); sig_bw.Write(devAISGen.AISExtraFunc[i].funcAddr); devAISGen.signatureByteCnt += 8; // Insert signature SecureAISInsertSignature(devAISGen.signatureStream, devAISGen); // Call UARTSendDONE from AIS Extras if this is for UART boot if (devAISGen.SendUARTSendDONE) { tempAIS_bw.Write((UInt32)AIS.Jump); tempAIS_bw.Write(devAISGen.UARTSendDONEAddr); sig_bw.Write((UInt32)AIS.Jump); sig_bw.Write(devAISGen.UARTSendDONEAddr); devAISGen.signatureByteCnt += 8; // Insert signature SecureAISInsertSignature(devAISGen.signatureStream, devAISGen); } } } } } } #endregion Debug.DebugMSG("Starting binary file section loads."); #region Insert binary data files as SECTION_LOAD commands // Insert binary files for (Int32 i=0; i<binaryFiles.Count; i++) { if (File.Exists(binaryFiles[i].fileName)) { SecureAISBinarySectionLoad(binaryFiles[i].fileName, devAISGen, binaryFiles[i].loadAddr, binaryFiles[i].encrypt); Debug.DebugMSG("Binary file {0} found.", binaryFiles[i].fileName); numTargetSections++; if (binaryFiles[i].useEntryPoint) { entryPoint = binaryFiles[i].entryPointAddr; } } else { Console.WriteLine("WARNING: Binary input file {0} was not found. Skipping.",binaryFiles[i].fileName); } } #endregion Debug.DebugMSG("Starting object file section loads."); #region COFF file parsing and loading // Create the COFF file object for the main application being loaded if (File.Exists(coffFileName)) { SecureObjectFile currFile = new SecureObjectFile(); currFile.useEntryPoint = true; currFile.fileName = coffFileName; currFile.encrypt = false; // Cycle throught all other object files loaded via INI file and unset their // useEntryPoint boolean, warning us as we do Boolean showWarning = false; for (Int32 i=0; i<objectFiles.Count; i++) { // Insert binary file if (objectFiles[i].useEntryPoint) { objectFiles[i].useEntryPoint = false; showWarning = true; } } if (showWarning) Console.WriteLine("WARNING: Ignoring useEntryPoint flag from all object file sections of INI file"); objectFiles.Add(currFile); } // Insert object files for (Int32 i=0; i<objectFiles.Count; i++) { if (File.Exists(objectFiles[i].fileName)) { // FIXME: Add support to detect ELF or COFF and support ELF parsing // Parse the object file COFFFile cf = new COFFFile(objectFiles[i].fileName); if (cf != null) { String[] tempEncryptString = null; if (objectFiles[i].encrypt) { // If this Object file is specified for encryption, temporarily set // global sectionsToEncrypt string to "ALL" tempEncryptString = devAISGen.sectionsToEncrypt; devAISGen.sectionsToEncrypt = new String[1]{"ALL"}; // Load the object file contents SecureAISCOFFLoad(cf, devAISGen); // Increment section count numTargetSections += (UInt32)cf.Header["numTargetSections"]; // If this Object file is specified for encryption, reset the // global sectionsToEncrypt string to its original value devAISGen.sectionsToEncrypt = tempEncryptString; } else { // Load the object file contents SecureAISCOFFLoad(cf, devAISGen); } } else { Console.WriteLine("ERROR: Parsing the input object file {0} failed!",objectFiles[i].fileName); } if (entryPoint == 0x00000000) { if (objectFiles[i].useEntryPoint) { entryPoint = (UInt32)cf.Header["optEntryPoint"]; } } // Insert final function register function if (devAISGen.finalFxnName != null) { Hashtable symbol; // Look for the symbol in the Coff file symbols table symbol = cf.symFind(devAISGen.finalFxnName); // If found, insert the command if (symbol != null) { tempAIS_bw.Write((UInt32)AIS.FinalFxnReg); tempAIS_bw.Write((UInt32)symbol["value"]); sig_bw.Write((UInt32)AIS.FinalFxnReg); sig_bw.Write((UInt32)symbol["value"]); devAISGen.signatureByteCnt += 8; Console.WriteLine("Finalize function symbol, '{0}', found as address 0x{1:X8}.",devAISGen.finalFxnName,(UInt32)symbol["value"]); } else { Console.WriteLine("Finalize function symbol, '{0}', not found.",devAISGen.finalFxnName); } } // Close object file if (cf != null) cf.Close(); } else { Console.WriteLine("WARNING: Input object file {0} was not found. Skipping.",objectFiles[i].fileName); } } #endregion #region Insert Final JUMP_CLOSE command tempAIS_bw.Write((UInt32)AIS.Jump_Close); tempAIS_bw.Write(entryPoint); sig_bw.Write((UInt32)AIS.Jump_Close); sig_bw.Write(entryPoint); devAISGen.signatureByteCnt += 8; if (entryPoint == 0x00000000) Console.WriteLine("WARNING: Entry point never set or set to invalid value"); // Insert signature SecureAISInsertSignature(devAISGen.signatureStream, devAISGen); // Flush the data and then return to start devAISGen.devAISStream.Flush(); devAISGen.devAISStream.Seek(0,SeekOrigin.Begin); devAISGen.signatureStream.Close(); #endregion // Console output Console.WriteLine("AIS file generation was successful."); // --------------------------------------------------------- // ******************* END AIS GENERATION ****************** // --------------------------------------------------------- } #endregion #region Prepare the return byte array // Now create return byte array based on AIS Stream data EndianBinaryReader tempAIS_br; tempAIS_br = new EndianBinaryReader( devAISGen.devAISStream, Endian.LittleEndian); numWords = ((UInt32)tempAIS_br.BaseStream.Length) >> 2; devAISGen.AISData = new Byte[numWords << 2]; //Each word converts to 4 binary bytes Debug.DebugMSG("Number of words in the stream is {0}", numWords); // Copy the data to the output Byte array for (UInt32 i = 0; i < numWords; i++) { BitConverter.GetBytes(tempAIS_br.ReadUInt32()).CopyTo(devAISGen.AISData, i * 4); } // Close the binary reader tempAIS_br.Close(); // Close the COFF files since we are done with them if (AISExtrasCF != null) AISExtrasCF.Close(); // Clean up any embedded file resources that may have been extracted EmbeddedFileIO.CleanUpEmbeddedFiles(); #endregion // Return Byte Array return devAISGen.AISData; }