Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 38 | Rev 42 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 38 Rev 41
Line 163... Line 163...
163
static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array
163
static size_t saved_ELF_section_count = 0; // number of elements in the saved_ELF_sections array
164
static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument
164
static char *sym_suffix = ""; // .sym files extra suffix, settable with the -a command-line argument
165
 
165
 
166
// bootable IFS support
166
// bootable IFS support
167
static int boot_type = BOOTTYPE_NONE;
167
static int boot_type = BOOTTYPE_NONE;
168
static char *bootfile_pathname = NULL;           // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS in BIOS mode
-
 
169
static size_t bootfile_size = 0;                 // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS in BIOS mode
168
static buffer_t boot_code    = { NULL, 0 };      // boot code (boot prefix) to put at the start of a bootable IFS
170
static char *startupfile_pathname = NULL;        // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
-
 
171
static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS 
169
static buffer_t startup_code = { NULL, 0 };      // startup code to embed in the IFS between the boot prefix and the image header
172
static size_t kernelfile_offset = 0;             // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table)
170
static size_t kernelfile_offset = 0;             // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table)
-
 
171
static size_t startup_bootargs_offset = 0;       // offset in the startup file to the boot args structure, so that it can be patched late
173
static size_t procnto_bootargs_offset = 0;       // offset in the procnto file to the boot args structure, so that it can be patched late
172
static size_t procnto_bootargs_offset = 0;       // offset in the procnto file to the boot args structure, so that it can be patched late
-
 
173
static parms_t startup_entry_parms; // copied from entry parms, so as to preserve the search path and whether to preserve linker output files
-
 
174
static stringarray_t global_envp  = { NULL, 0 }; // global environment table from the startup block that applies to all executables (esp. startup and procnto)
-
 
175
static stringarray_t startup_argv = { NULL, 0 }; // arguments table of the startup program
-
 
176
static stringarray_t startup_envp = { NULL, 0 }; // environment table specific to the startup program
-
 
177
static stringarray_t procnto_argv = { NULL, 0 }; // arguments table of the procnto kernel
-
 
178
static stringarray_t procnto_envp = { NULL, 0 }; // environment table specific to the procnto kernel
174
 
179
 
175
 
180
 
176
// exported function prototypes
181
// exported function prototypes
177
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
182
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
178
 
183
 
Line 183... Line 188...
183
static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)
188
static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)
184
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
189
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
185
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer
190
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer
186
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
191
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
187
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
192
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
-
 
193
static void prelink (const char *search, const char *section_start_arg, const stringarray_t *exe_cmdline, const stringarray_t *exe_env, const bool should_keep_ld_output, buffer_t *out_buffer, size_t *bootargs_offset); // produces a prelinked version of a given executable mapped at the given address and stamped with the given arguments
188
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array
194
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array
189
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
195
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
190
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
196
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
191
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array
197
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array
192
 
198
 
Line 780... Line 786...
780
   for (table_index = 0; table_index < elf_section_count; table_index++)
786
   for (table_index = 0; table_index < elf_section_count; table_index++)
781
      Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers
787
      Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers
782
 
788
 
783
   #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
789
   #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
784
   return (1); // success
790
   return (1); // success
-
 
791
}
-
 
792
 
-
 
793
 
-
 
794
static void prelink (const char *search, const char *section_start_arg, const stringarray_t *exe_cmdline, const stringarray_t *exe_env, const bool should_keep_ld_output, buffer_t *out_buffer, size_t *bootargs_offset)
-
 
795
{
-
 
796
   static thread_local struct linker_s
-
 
797
   {
-
 
798
      char pathname[MAXPATHLEN];
-
 
799
      char sysroot_arg[MAXPATHLEN];
-
 
800
      char script_pathname_arg[MAXPATHLEN];
-
 
801
   } linker = { "", "", "" };
-
 
802
 
-
 
803
   static thread_local char buildhost_pathname[MAXPATHLEN] = "";
-
 
804
   static thread_local char sym_filename[MAXPATHLEN] = "";
-
 
805
   stringarray_t linker_argv = { NULL, 0 };
-
 
806
   buffer_t bootargs_buffer = { 0 };
-
 
807
   char *resolved_pathname;
-
 
808
   char *exeargs_location;
-
 
809
   void *reallocated_ptr;
-
 
810
   size_t array_index;
-
 
811
 
-
 
812
   // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET)
-
 
813
   if (linker.pathname[0] == 0)
-
 
814
   {
-
 
815
#if defined(_WIN32)
-
 
816
      sprintf_s (linker.pathname, sizeof (linker.pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/ ".exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension
-
 
817
#elif defined(__linux__)
-
 
818
      sprintf_s (linker.pathname, sizeof (linker.pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
819
#elif defined(__QNXNTO__)
-
 
820
      sprintf_s (linker.pathname, sizeof (linker.pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
821
#elif defined(__APPLE__) // why not!?
-
 
822
      sprintf_s (linker.pathname, sizeof (linker.pathname), "%s/../../host/darwin/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
823
#else // wtf are you building this on?
-
 
824
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
-
 
825
#endif
-
 
826
      ASSERT (access (linker.pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker.pathname);
-
 
827
      sprintf_s (linker.sysroot_arg, sizeof (linker.sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor);
-
 
828
      sprintf_s (linker.script_pathname_arg, sizeof (linker.script_pathname_arg), "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
-
 
829
   }
-
 
830
 
-
 
831
   resolved_pathname = resolve_pathname (exe_cmdline->args[0], search); // locate the executable location
-
 
832
   ASSERT (resolved_pathname, "QNX startup \"%s\" not found in search path", exe_cmdline->args[0]);
-
 
833
   strcpy_s (buildhost_pathname, sizeof (buildhost_pathname), resolved_pathname);
-
 
834
 
-
 
835
   sprintf_s (sym_filename, sizeof (sym_filename), "%s.sym%s", exe_cmdline->args[0], sym_suffix);
-
 
836
 
-
 
837
   // construct the linker invokation command-line arguments array (argv)
-
 
838
   STRINGARRAY_INIT (&linker_argv);
-
 
839
   STRINGARRAY_PUSH (&linker_argv, strrchr (linker.pathname, '/') + 1); // "${TARGET_TRIPLE}-ld"
-
 
840
   STRINGARRAY_PUSH (&linker_argv, linker.sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
-
 
841
   STRINGARRAY_PUSH (&linker_argv, linker.script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"
-
 
842
   STRINGARRAY_PUSH (&linker_argv, "--section-start");
-
 
843
   STRINGARRAY_PUSH (&linker_argv, section_start_arg);
-
 
844
   STRINGARRAY_PUSH (&linker_argv, "--no-relax");
-
 
845
   STRINGARRAY_PUSH (&linker_argv, buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/startup-x86"
-
 
846
   STRINGARRAY_PUSH (&linker_argv, "-o");
-
 
847
   STRINGARRAY_PUSH (&linker_argv, sym_filename); // "startup-x86.sym"
-
 
848
#ifdef __GNUC__
-
 
849
#pragma GCC diagnostic push
-
 
850
#pragma GCC diagnostic ignored "-Wnonnull" // the GCC linter is wrong here: I *do* check for NULL before calling strdup()
-
 
851
#endif // __GNUC__
-
 
852
   STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer
-
 
853
#ifdef __GNUC__
-
 
854
#pragma GCC diagnostic pop
-
 
855
#endif // __GNUC__
-
 
856
   if (verbose_level > 2)
-
 
857
   {
-
 
858
      fprintf (stderr, "ifstool: calling:");
-
 
859
      for (array_index = 0; array_index < linker_argv.count - 1; array_index++)
-
 
860
         fprintf (stderr, " '%s'", linker_argv.args[array_index]);
-
 
861
      fputc ('\n', stderr);
-
 
862
   }
-
 
863
#ifdef _WIN32
-
 
864
   _spawnv (_P_WAIT, linker.pathname, linker_argv.args); // spawn the linker and produce a relinked startup (wait for completion)
-
 
865
#else // !_WIN32, thus POSIX
-
 
866
   do { // QNX does have spawnv(), but Linux does not. So let's stick to common POSIX ground, i.e. fork/exec/wait.
-
 
867
      int status;
-
 
868
      pid_t pid = fork (); // duplicate ourselves so as to create a new process
-
 
869
      ASSERT_WITH_ERRNO (pid != -1);
-
 
870
      if (pid == 0) // we are the child
-
 
871
      {
-
 
872
         execv (linker.pathname, linker_argv.args); // execute the linker and produce a relinked startup (wait for completion)
-
 
873
         DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns
-
 
874
      }
-
 
875
      else // we are the parent
-
 
876
         waitpid (pid, &status, 0); // wait for the child to finish
-
 
877
   } while (0);
-
 
878
#endif // _WIN32
-
 
879
   STRINGARRAY_FREE (&linker_argv);
-
 
880
   if (!Buffer_ReadFromFile (out_buffer, sym_filename)) // load the output file
-
 
881
      DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable relinked \"%s\" startup: %s", sym_filename, strerror (errno));
-
 
882
   if (!should_keep_ld_output)
-
 
883
      unlink (sym_filename); // remove the linker output file if we want to
-
 
884
 
-
 
885
   // save the boot arguments. The magic to look for is "ddpvbskr" -- whatever that means
-
 
886
   if ((exeargs_location = Buffer_FindFirstByteArray (out_buffer, "ddpvbskr")) == NULL)
-
 
887
      DIE_WITH_EXITCODE (1, "unable to find boot args location in the stripped \"%s\" startup", exe_cmdline->args[0]);
-
 
888
   Buffer_InitWithSize (&bootargs_buffer, sizeof (bootargs_entry_t)); // prepare a boot args entry
-
 
889
   ((bootargs_entry_t *) bootargs_buffer.bytes)->argc = (uint8_t) exe_cmdline->count;
-
 
890
   ((bootargs_entry_t *) bootargs_buffer.bytes)->envc = (uint8_t) exe_env->count;
-
 
891
   ((bootargs_entry_t *) bootargs_buffer.bytes)->shdr_addr = WILL_BE_FILLED_LATER; // same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
-
 
892
   for (array_index = 0; array_index < exe_cmdline->count; array_index++)
-
 
893
      ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, exe_cmdline->args[array_index], strlen (exe_cmdline->args[array_index]) + 1)); // append string including NUL terminator
-
 
894
   for (array_index = 0; array_index < exe_env->count; array_index++)
-
 
895
      ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, exe_env->args[array_index], strlen (exe_env->args[array_index]) + 1)); // append string including NUL terminator
-
 
896
   ((bootargs_entry_t *) bootargs_buffer.bytes)->size_hi = (uint8_t) ((bootargs_buffer.size >> 8) & 0xff);
-
 
897
   ((bootargs_entry_t *) bootargs_buffer.bytes)->size_lo = (uint8_t) ((bootargs_buffer.size >> 0) & 0xff);
-
 
898
   *bootargs_offset = (size_t) exeargs_location - (size_t) out_buffer->bytes; // compute the boot args offset
-
 
899
   ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (out_buffer, *bootargs_offset, &bootargs_buffer));
-
 
900
   Buffer_Forget (&bootargs_buffer); // release the boot args buffer once it's written
-
 
901
 
-
 
902
   return; // either we made it through, or we're dead
785
}
903
}
786
 
904
 
787
 
905
 
788
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
906
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
789
{
907
{
790
   static thread_local char *candidate_pathname = NULL;
908
   static thread_local char *candidate_pathname = NULL;
791
   static thread_local parms_t default_parms = { 0 };
909
   static thread_local parms_t default_parms = { 0 };
792
   static thread_local stringarray_t global_envp = { NULL, 0 };
-
 
793
   static thread_local stringarray_t aps_partnames = { NULL, 0 };
910
   static thread_local stringarray_t aps_partnames = { NULL, 0 };
794
   static int inode_count = 0; // will be preincremented each time this function is called
911
   static int inode_count = 0; // will be preincremented each time this function is called
795
 
912
 
796
   typedef struct scriptcmd_s
913
   typedef struct scriptcmd_s
797
   {
914
   {
Line 809... Line 926...
809
   scriptcmd_t default_scriptcmd_params = { NULL, -1, false, -1, -1, -1, false, false, false };
926
   scriptcmd_t default_scriptcmd_params = { NULL, -1, false, -1, -1, -1, false, false, false };
810
   scriptcmd_t current_scriptcmd_params = { 0 };
927
   scriptcmd_t current_scriptcmd_params = { 0 };
811
   stringarray_t global_argv = { NULL, 0 };
928
   stringarray_t global_argv = { NULL, 0 };
812
   stringarray_t line_argv = { NULL, 0 };
929
   stringarray_t line_argv = { NULL, 0 };
813
   stringarray_t line_envp = { NULL, 0 };
930
   stringarray_t line_envp = { NULL, 0 };
814
   stringarray_t startup_argv = { NULL, 0 };
-
 
815
   stringarray_t startup_envp = { NULL, 0 };
-
 
816
   stringarray_t procnto_argv = { NULL, 0 };
-
 
817
   stringarray_t procnto_envp = { NULL, 0 };
-
 
818
   stringarray_t linker_argv = { NULL, 0 };
931
//   stringarray_t linker_argv = { NULL, 0 };
819
   const char *stored_pathname_without_leading_slash;
932
   const char *stored_pathname_without_leading_slash;
820
   const char *original_stored_pathname = NULL;
933
   const char *original_stored_pathname = NULL;
821
   const char *filename_bit;
934
   const char *filename_bit;
822
   buffer_t current_line;
935
   buffer_t current_line;
823
   buffer_t compiled_script;
936
   buffer_t compiled_script;
Line 1039... Line 1152...
1039
               {
1152
               {
1040
                  startup_argv.args = line_argv.args; // relocate these pointers to the right place
1153
                  startup_argv.args = line_argv.args; // relocate these pointers to the right place
1041
                  startup_argv.count = line_argv.count;
1154
                  startup_argv.count = line_argv.count;
1042
                  startup_envp.args = line_envp.args; // relocate these pointers to the right place
1155
                  startup_envp.args = line_envp.args; // relocate these pointers to the right place
1043
                  startup_envp.count = line_envp.count;
1156
                  startup_envp.count = line_envp.count;
-
 
1157
                  for (array_index = 0; array_index < global_envp.count; array_index++)
-
 
1158
                     STRINGARRAY_PUSH (&startup_envp, global_envp.args[array_index]); // concatenate the global environment to the executable environment
1044
               }
1159
               }
1045
               else
1160
               else
1046
               {
1161
               {
1047
                  STRINGARRAY_FREE (&procnto_argv); // if procnto's argv was already assigned, free the previous array as we'll be replacing it with a new one
1162
                  STRINGARRAY_FREE (&procnto_argv); // if procnto's argv was already assigned, free the previous array as we'll be replacing it with a new one
1048
                  procnto_argv.args = line_argv.args; // relocate these pointers to the right place
1163
                  procnto_argv.args = line_argv.args; // relocate these pointers to the right place
1049
                  procnto_argv.count = line_argv.count;
1164
                  procnto_argv.count = line_argv.count;
1050
                  STRINGARRAY_FREE (&procnto_envp); // if procnto's envp was already assigned, free the previous array as we'll be replacing it with a new one
1165
                  STRINGARRAY_FREE (&procnto_envp); // if procnto's envp was already assigned, free the previous array as we'll be replacing it with a new one
1051
                  procnto_envp.args = line_envp.args; // relocate these pointers to the right place
1166
                  procnto_envp.args = line_envp.args; // relocate these pointers to the right place
1052
                  procnto_envp.count = line_envp.count;
1167
                  procnto_envp.count = line_envp.count;
-
 
1168
                  for (array_index = 0; array_index < global_envp.count; array_index++)
-
 
1169
                     STRINGARRAY_PUSH (&procnto_envp, global_envp.args[array_index]); // concatenate the global environment to the executable environment
1053
               }
1170
               }
1054
               line_argv.args = NULL; // void the line_argv array so as to not free it as we stole its args pointers
1171
               line_argv.args = NULL; // void the line_argv array so as to not free it as we stole its args pointers
1055
               line_argv.count = 0;
1172
               line_argv.count = 0;
1056
               line_envp.args = NULL; // void the line_envp array so as to not free it as we stole its args pointers
1173
               line_envp.args = NULL; // void the line_envp array so as to not free it as we stole its args pointers
1057
               line_envp.count = 0;
1174
               line_envp.count = 0;
Line 1072... Line 1189...
1072
 
1189
 
1073
         // now we know which startup and procnto executables to use
1190
         // now we know which startup and procnto executables to use
1074
         LOG_DEBUG ("Startup: %s", startup_argv.args[0]);
1191
         LOG_DEBUG ("Startup: %s", startup_argv.args[0]);
1075
         LOG_DEBUG ("Kernel: %s",  procnto_argv.args[0]);
1192
         LOG_DEBUG ("Kernel: %s",  procnto_argv.args[0]);
1076
 
1193
 
1077
         static thread_local char linker_pathname[MAXPATHLEN] = "";
1194
         // prelink procnto, map its .text segment at the right virtual address for the IFS and stamp in its executable arguments
1078
         static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";
1195
         // then store the result in this entry's data blob
1079
         static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";
1196
         prelink (entry_parms->search, // binary executable search path
-
 
1197
                  (boot_type == BOOTTYPE_UEFI ? ".text=0xffff800000002000" : ".text=0xffff800000001000"), // FIXME: wild assumption!
1080
         static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";
1198
                  &procnto_argv, &procnto_envp, // executable arguments (including its name) and environment to stamp in it
1081
         static thread_local char procnto_sym_filename[MAXPATHLEN] = "";
1199
                  entry_parms->should_keep_ld_output, // whether to keep the linker-produced output file
1082
         buffer_t bootargs_buffer = { 0 };
1200
                  &entry_parms->data, // buffer where to save the output
1083
         void *bootargs_location;
1201
                  &procnto_bootargs_offset); // where to save the offset of the boot arguments
1084
 
1202
 
1085
         // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET)
-
 
1086
#if defined(_WIN32)
-
 
1087
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/ ".exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension
-
 
1088
#elif defined(__linux__)
-
 
1089
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
1090
#elif defined(__QNXNTO__)
-
 
1091
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
1092
#elif defined(__APPLE__) // why not!?
-
 
1093
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/darwin/x86_64/usr/bin/%s-ld" /*"-2.41.0"*/, QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
-
 
1094
#else // wtf are you building this on?
-
 
1095
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
-
 
1096
#endif
-
 
1097
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
-
 
1098
         sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor);
-
 
1099
         sprintf_s (linker_script_pathname_arg, sizeof (linker_script_pathname_arg), "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
-
 
1100
 
-
 
1101
         resolved_pathname = resolve_pathname (procnto_argv.args[0], entry_parms->search); // locate the procnto kernel location
-
 
1102
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_argv.args[0]);
-
 
1103
         strcpy_s (procnto_buildhost_pathname, sizeof (procnto_buildhost_pathname), resolved_pathname);
-
 
1104
 
-
 
1105
         sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_argv.args[0], sym_suffix);
-
 
1106
 
-
 
1107
         // construct the linker invokation command-line arguments array (argv)
-
 
1108
         STRINGARRAY_INIT (&linker_argv);
-
 
1109
         STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld"
-
 
1110
         STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
-
 
1111
         STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"
-
 
1112
         STRINGARRAY_PUSH (&linker_argv, "--section-start");
-
 
1113
         STRINGARRAY_PUSH (&linker_argv, (boot_type == BOOTTYPE_UEFI ? ".text=0xffff800000002000" : ".text=0xffff800000001000")); // FIXME: wild assumption!
-
 
1114
         STRINGARRAY_PUSH (&linker_argv, "--no-relax");
-
 
1115
         STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr"
-
 
1116
         STRINGARRAY_PUSH (&linker_argv, "-o");
-
 
1117
         STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym"
-
 
1118
#ifdef __GNUC__
-
 
1119
#pragma GCC diagnostic push
-
 
1120
#pragma GCC diagnostic ignored "-Wnonnull" // the GCC linter is wrong here: I *do* check for NULL before calling strdup()
-
 
1121
#endif // __GNUC__
-
 
1122
         STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer
-
 
1123
#ifdef __GNUC__
-
 
1124
#pragma GCC diagnostic pop
-
 
1125
#endif // __GNUC__
-
 
1126
         if (verbose_level > 2)
-
 
1127
         {
-
 
1128
            fprintf (stderr, "ifstool: calling:");
-
 
1129
            for (array_index = 0; array_index < linker_argv.count - 1; array_index++)
-
 
1130
               fprintf (stderr, " '%s'", linker_argv.args[array_index]);
-
 
1131
            fputc ('\n', stderr);
-
 
1132
         }
-
 
1133
#ifdef _WIN32
-
 
1134
         _spawnv (_P_WAIT, linker_pathname, linker_argv.args); // spawn the linker and produce a stripped procnto (wait for completion)
-
 
1135
#else // !_WIN32, thus POSIX
-
 
1136
         do { // QNX does have spawnv(), but Linux does not. So let's stick to common POSIX ground, i.e. fork/exec/wait.
-
 
1137
            int status;
-
 
1138
            pid_t pid = fork (); // duplicate ourselves so as to create a new process
-
 
1139
            ASSERT_WITH_ERRNO (pid != -1);
-
 
1140
            if (pid == 0) // we are the child
-
 
1141
            {
-
 
1142
               execv (linker_pathname, linker_argv.args); // execute the linker and produce a stripped procnto (wait for completion)
-
 
1143
               DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns
-
 
1144
            }
-
 
1145
            else // we are the parent
-
 
1146
               waitpid (pid, &status, 0); // wait for the child to finish
-
 
1147
         } while (0);
-
 
1148
#endif // _WIN32
-
 
1149
         STRINGARRAY_FREE (&linker_argv);
-
 
1150
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
-
 
1151
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
-
 
1152
         if (!entry_parms->should_keep_ld_output)
-
 
1153
            unlink (procnto_sym_filename); // remove the linker output file if we want to
-
 
1154
 
-
 
1155
         // strip this prelinked ELF kernel file from all the sections we don't need
1203
         // strip this prelinked ELF file from all the sections we don't need
1156
         ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, true, stored_pathname)); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info", and align the segment size in file with the size it occupies in memory)
1204
         ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, NULL, 0, true, procnto_argv.args[0])); // strip procnto as per QNX docs (align the segment size in file with the size it occupies in memory)
1157
 
-
 
1158
         // save the boot arguments. The magic to look for is "ddpvbskr" -- whatever that means
-
 
1159
         if ((bootargs_location = Buffer_FindFirstByteArray (&entry_parms->data, "ddpvbskr")) == NULL)
-
 
1160
            DIE_WITH_EXITCODE (1, "unable to find boot args location in the stripped \"%s\" kernel", stored_pathname);
-
 
1161
         Buffer_InitWithSize (&bootargs_buffer, sizeof (bootargs_entry_t)); // prepare a boot args entry
-
 
1162
         ((bootargs_entry_t *) bootargs_buffer.bytes)->argc = (uint8_t) procnto_argv.count;
-
 
1163
         ((bootargs_entry_t *) bootargs_buffer.bytes)->envc = (uint8_t) (global_envp.count + procnto_envp.count);
-
 
1164
         ((bootargs_entry_t *) bootargs_buffer.bytes)->shdr_addr = WILL_BE_FILLED_LATER; // same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
-
 
1165
         for (array_index = 0; array_index < procnto_argv.count; array_index++)
-
 
1166
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_argv.args[array_index], strlen (procnto_argv.args[array_index]) + 1)); // append string including NUL terminator
-
 
1167
         for (array_index = 0; array_index < global_envp.count; array_index++)
-
 
1168
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // append string including NUL terminator
-
 
1169
         for (array_index = 0; array_index < procnto_envp.count; array_index++)
-
 
1170
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_envp.args[array_index], strlen (procnto_envp.args[array_index]) + 1)); // append string including NUL terminator
-
 
1171
         ((bootargs_entry_t *) bootargs_buffer.bytes)->size_hi = (uint8_t) ((bootargs_buffer.size >> 8) & 0xff);
-
 
1172
         ((bootargs_entry_t *) bootargs_buffer.bytes)->size_lo = (uint8_t) ((bootargs_buffer.size >> 0) & 0xff);
-
 
1173
         procnto_bootargs_offset = (size_t) bootargs_location - (size_t) entry_parms->data.bytes; // save the boot args offset so that the section header address in it can be patched late
-
 
1174
         ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&entry_parms->data, procnto_bootargs_offset, &bootargs_buffer));
-
 
1175
         Buffer_Forget (&bootargs_buffer); // release the boot args buffer once it's written
-
 
1176
 
1205
 
1177
         sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_argv.args[0]); // fix the entry name
1206
         sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_argv.args[0]); // fix the entry name
1178
         stored_pathname = candidate_pathname;
1207
         stored_pathname = candidate_pathname;
1179
 
1208
 
1180
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // mark this inode as a preprocessed *bootstrap* ELF file
1209
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // mark this inode as a preprocessed *bootstrap* ELF file
1181
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file
1210
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file
1182
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
1211
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
-
 
1212
 
-
 
1213
         memcpy (&startup_entry_parms, entry_parms, sizeof (parms_t)); // backup the startup entry parameters
1183
 
1214
 
1184
         STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array
1215
         STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array
1185
         STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array
1216
         STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array
1186
         //STRINGARRAY_FREE (&global_envp); // DO NOT release the global envp array. It is inherited by the boot scripts.
1217
         //STRINGARRAY_FREE (&global_envp); // DO NOT release the global envp array. It is inherited by the boot scripts.
-
 
1218
 
1187
      } // end of "is bootstrap file"
1219
      } // end of "is bootstrap file"
1188
      else if (entry_parms->is_compiled_bootscript) // [+script]
1220
      else if (entry_parms->is_compiled_bootscript) // [+script]
1189
      {
1221
      {
1190
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
1222
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
1191
         Buffer_Initialize (&compiled_script);
1223
         Buffer_Initialize (&compiled_script);
Line 1728... Line 1760...
1728
   thread_local static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
1760
   thread_local static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
1729
 
1761
 
1730
   bool should_discard_inline_contents;
1762
   bool should_discard_inline_contents;
1731
   bool is_quoted_context;
1763
   bool is_quoted_context;
1732
   bool is_escaped_char;
1764
   bool is_escaped_char;
1733
   struct stat stat_buf;
-
 
1734
   struct tm utc_time;
1765
   struct tm utc_time;
1735
   void *reallocated_ptr;
1766
   void *reallocated_ptr;
1736
   size_t allocated_size;
1767
   size_t allocated_size;
1737
   size_t string_len;
1768
   size_t string_len;
1738
   char *attrblock_start;
1769
   char *attrblock_start;
Line 1832... Line 1863...
1832
                  DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
1863
                  DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
1833
               value = sep + 1;
1864
               value = sep + 1;
1834
            }
1865
            }
1835
            boot_type = (strstr (value, "uefi") != NULL ? BOOTTYPE_UEFI : BOOTTYPE_BIOS); // FIXME: this should be a boot FILE, not a hardcoded tag
1866
            boot_type = (strstr (value, "uefi") != NULL ? BOOTTYPE_UEFI : BOOTTYPE_BIOS); // FIXME: this should be a boot FILE, not a hardcoded tag
1836
            if (boot_type == BOOTTYPE_UEFI)
1867
            if (boot_type == BOOTTYPE_UEFI)
1837
            {
-
 
1838
               if (startupfile_pathname == NULL) // FIXME: HACK until I figure out how to re-create it
-
 
1839
                  DIE_WITH_EXITCODE (1, "creating bootable UEFI images requires the --startupfile command-line option in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1840
               bootfile_size = ROUND_TO_UPPER_MULTIPLE (sizeof (uefi64_header_t), 512); // round to upper filesystem block (PE header constraint)
-
 
1841
               LOG_INFO ("processor \"%s\" bootfile <generated, UEFI>\n", image_processor);
1868
               LOG_INFO ("processor \"%s\" bootfile <generated, UEFI>\n", image_processor);
1842
            }
-
 
1843
            else
1869
            else
1844
            {
-
 
1845
               if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them
-
 
1846
                  DIE_WITH_EXITCODE (1, "creating bootable BIOS images requires the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
-
 
1847
               if (stat (bootfile_pathname, &stat_buf) != 0)
-
 
1848
                  DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
-
 
1849
               bootfile_size = stat_buf.st_size; // save preboot file size
-
 
1850
               LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
1870
               LOG_INFO ("processor \"%s\" bootfile <boot.bios, BIOS>\n", image_processor);
1851
            }
-
 
1852
            entry_parms.is_bootstrap_file = true;
1871
            entry_parms.is_bootstrap_file = true;
1853
         }
1872
         }
1854
         else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
1873
         else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
1855
               // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
1874
               // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
1856
               memset (&utc_time, 0, sizeof (utc_time));
1875
               memset (&utc_time, 0, sizeof (utc_time));
Line 2108... Line 2127...
2108
      .should_follow_symlinks = true, // [+|-followlink]
2127
      .should_follow_symlinks = true, // [+|-followlink]
2109
      .should_autosymlink_dylib = true, // [+|-autolink]
2128
      .should_autosymlink_dylib = true, // [+|-autolink]
2110
   };
2129
   };
2111
   parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
2130
   parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file)
2112
 
2131
 
-
 
2132
   char textbase_mapaddr_string[64];
-
 
2133
   elf_program_header_t *phdr = NULL;
2113
   uefi64_header_t *uefi_header = NULL;
2134
   uefi64_header_t *uefi_header = NULL;
2114
   char path_on_buildhost[MAXPATHLEN] = "";
2135
   char path_on_buildhost[MAXPATHLEN] = "";
2115
   char path_in_ifs[MAXPATHLEN] = "";
2136
   char path_in_ifs[MAXPATHLEN] = "";
2116
   const char *ifs_pathname = NULL;
2137
   const char *ifs_pathname = NULL;
2117
   const char *rootdir_pathname = NULL;
2138
   const char *rootdir_pathname = NULL;
2118
   const fsentry_t *fsentry;
2139
   const fsentry_t *fsentry;
2119
   void *reallocated_ptr;
2140
   void *reallocated_ptr;
2120
   buffer_t compressed_imagefs;
2141
   buffer_t compressed_imagefs;
2121
   buffer_t opaqueblob_file;
-
 
2122
   uint8_t *compressor_out;
2142
   uint8_t *compressor_out;
2123
   uint8_t *compressor_in;
2143
   uint8_t *compressor_in;
-
 
2144
   uint8_t *bootcode_start;
-
 
2145
   size_t program_header_table_count;
-
 
2146
   size_t cumulated_segment_length;
-
 
2147
   size_t minimal_padded_length;
-
 
2148
   size_t first_segment_offset;
2124
   size_t compressor_outlen;
2149
   size_t compressor_outlen;
2125
   size_t compressor_inlen;
2150
   size_t compressor_inlen;
2126
   size_t reallocated_size;
2151
   size_t reallocated_size;
2127
   size_t available_space;
2152
   size_t available_space;
2128
   size_t fsentry_index;
2153
   size_t fsentry_index;
2129
   size_t largest_index;
2154
   size_t largest_index;
2130
   size_t largest_size;
2155
   size_t largest_size;
2131
   size_t imgdir_size;
2156
   size_t imgdir_size;
2132
   size_t curr_offset;
2157
   size_t curr_offset;
-
 
2158
   size_t table_index;
2133
   size_t remaining_len;
2159
   size_t remaining_len;
2134
   ifs_t ifs = { 0 };
2160
   ifs_t ifs = { 0 };
2135
   int32_t checksum;
2161
   int32_t checksum;
-
 
2162
   char *resolved_pathname;
2136
   char *first_pathname = NULL;
2163
   char *first_pathname = NULL;
2137
   char *second_pathname = NULL;
2164
   char *second_pathname = NULL;
2138
   char *third_pathname = NULL;
2165
   char *third_pathname = NULL;
2139
   char *sep;
-
 
2140
   int arg_index;
2166
   int arg_index;
2141
   bool is_quoted_context = false;
2167
   bool is_quoted_context = false;
2142
   bool is_escaped_char = false;
2168
   bool is_escaped_char = false;
2143
   bool should_discard_inline_contents = false;
2169
   bool should_discard_inline_contents = false;
2144
   bool want_info = false;
2170
   bool want_info = false;
Line 2164... Line 2190...
2164
   ASSERT_WITH_ERRNO (default_parms.prefix);
2190
   ASSERT_WITH_ERRNO (default_parms.prefix);
2165
 
2191
 
2166
   // parse arguments
2192
   // parse arguments
2167
   for (arg_index = 1; arg_index < argc; arg_index++)
2193
   for (arg_index = 1; arg_index < argc; arg_index++)
2168
   {
2194
   {
2169
      if ((strcmp (argv[arg_index], "--bootfile") == 0) && (arg_index + 1 < argc)) // --bootfile path/to/blob.bin
-
 
2170
         bootfile_pathname = argv[++arg_index];
-
 
2171
      else if ((strcmp (argv[arg_index], "--startupfile") == 0) && (arg_index + 1 < argc)) // --startupfile path/to/blob.bin@0x1030
-
 
2172
      {
-
 
2173
         sep = strchr (argv[++arg_index], '@');
-
 
2174
         if ((sep == NULL) || (sep[1] == 0))
-
 
2175
            DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");
-
 
2176
         *sep = 0;
-
 
2177
         startupfile_pathname = argv[arg_index];
-
 
2178
         startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1, 0);
-
 
2179
      }
-
 
2180
      else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix
2195
      if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix
2181
         sym_suffix = argv[++arg_index];
2196
         sym_suffix = argv[++arg_index];
2182
      else if (strcmp (argv[arg_index], "-n") == 0)
2197
      else if (strcmp (argv[arg_index], "-n") == 0)
2183
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
2198
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
2184
      else if (strcmp (argv[arg_index], "-nn") == 0)
2199
      else if (strcmp (argv[arg_index], "-nn") == 0)
2185
      {
2200
      {
Line 2247... Line 2262...
2247
      fprintf (out, "    ifstool --info [--everything] [--hide-filename] <ifs file>\n");
2262
      fprintf (out, "    ifstool --info [--everything] [--hide-filename] <ifs file>\n");
2248
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
2263
      fprintf (out, "    ifstool --dump [--outdir <path>] <ifs file>\n");
2249
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
2264
      fprintf (out, "    ifstool --strip [--outfile <pathname>] <ELF file>\n");
2250
      fprintf (out, "    ifstool [-?|--help]\n");
2265
      fprintf (out, "    ifstool [-?|--help]\n");
2251
      // mkifs [-?] [-l inputline] [-n[n]] [-o directory] [-p patchfile] [-r rootdir] [-s section] [-v] [buildfile] [directory] [outputfile]
2266
      // mkifs [-?] [-l inputline] [-n[n]] [-o directory] [-p patchfile] [-r rootdir] [-s section] [-v] [buildfile] [directory] [outputfile]
2252
      fprintf (out, "    ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kerneloffs <fileoffs>] [-a suffix] [-l inputline] [-n[n]] [-r rootdir] [-s section] [-v[...]] [buildfile] [directory] [outputfile]\n");
2267
      fprintf (out, "    ifstool [-a suffix] [-l inputline] [-n[n]] [-r rootdir] [-s section] [-v[...]] [buildfile] [directory] [outputfile]\n");
2253
      fprintf (out, "NOTE: the compiler mode requires predigested boot and startup files produced by mkifs.\n");
2268
      fprintf (out, "NOTE: the compiler mode requires predigested boot and startup files produced by mkifs.\n");
2254
      fprintf (out, "options:\n");
2269
      fprintf (out, "options:\n");
2255
      fprintf (out, "    -?       Display some help information.\n");
2270
      fprintf (out, "    -?       Display some help information.\n");
2256
      fprintf (out, "    -a .ext  Append a suffix to symbol files generated via [+keeplinked].\n");
2271
      fprintf (out, "    -a .ext  Append a suffix to symbol files generated via [+keeplinked].\n");
2257
      fprintf (out, "    -l line  Process line before interpreting the buildfile. Input lines given\n");
2272
      fprintf (out, "    -l line  Process line before interpreting the buildfile. Input lines given\n");
Line 2399... Line 2414...
2399
   // start constructing the IFS file
2414
   // start constructing the IFS file
2400
 
2415
 
2401
   Buffer_Initialize (&ifs.data);
2416
   Buffer_Initialize (&ifs.data);
2402
 
2417
 
2403
   // do we have a startup file ? if so, this is a bootable image
2418
   // do we have a startup file ? if so, this is a bootable image
2404
   if (startupfile_pathname != NULL)
2419
   if (startup_argv.count > 0)
2405
   {
2420
   {
2406
      // write boot prefix
2421
      // write boot prefix
2407
      if (boot_type == BOOTTYPE_UEFI) // UEFI boot
2422
      if (boot_type == BOOTTYPE_UEFI) // UEFI boot
2408
      {
2423
      {
-
 
2424
         boot_code.size = ROUND_TO_UPPER_MULTIPLE (sizeof (uefi64_header_t), 512); // round to upper filesystem block (PE header constraint)
-
 
2425
 
2409
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, sizeof (uefi64_header_t))); // start by writing an empty UEFI header
2426
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, sizeof (uefi64_header_t))); // start by writing an empty UEFI header
2410
         uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer
2427
         uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer
2411
         memcpy (&uefi_header->dos_header.signature, "MZ", 2); // store the MZ magic
2428
         memcpy (&uefi_header->dos_header.signature, "MZ", 2); // store the MZ magic
2412
         uefi_header->dos_header.bytes_in_last_page = 144; // fixed value
2429
         uefi_header->dos_header.bytes_in_last_page = 144; // fixed value
2413
         uefi_header->dos_header.number_of_pages = 3; // fixed value
2430
         uefi_header->dos_header.number_of_pages = 3; // fixed value
Line 2423... Line 2440...
2423
         uefi_header->pe_header.epoch_timestamp = (uint32_t) time (NULL); // store timestamp (NOTE: mkifs doesn't obey its -nn arguments here, so neither shall we)
2440
         uefi_header->pe_header.epoch_timestamp = (uint32_t) time (NULL); // store timestamp (NOTE: mkifs doesn't obey its -nn arguments here, so neither shall we)
2424
         uefi_header->pe_header.size_of_optional_header = sizeof (uefi_header->optional_header64); // 240 bytes
2441
         uefi_header->pe_header.size_of_optional_header = sizeof (uefi_header->optional_header64); // 240 bytes
2425
         uefi_header->pe_header.characteristics_bitmap = 0x0223; // store characteristics bitmap (executable, uses large addresses, relocs stripped, debug info stripped)
2442
         uefi_header->pe_header.characteristics_bitmap = 0x0223; // store characteristics bitmap (executable, uses large addresses, relocs stripped, debug info stripped)
2426
         memcpy (uefi_header->optional_header64.signature, "\x0b\x02", 2); // store the 64-bit optional header magic
2443
         memcpy (uefi_header->optional_header64.signature, "\x0b\x02", 2); // store the 64-bit optional header magic
2427
         uefi_header->optional_header64.code_size = WILL_BE_FILLED_LATER; // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image
2444
         uefi_header->optional_header64.code_size = WILL_BE_FILLED_LATER; // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image
2428
         uefi_header->optional_header64.entrypoint_address = (uint32_t) startupfile_ep_from_imagebase;
2445
         uefi_header->optional_header64.entrypoint_address = WILL_BE_FILLED_LATER;
2429
         uefi_header->optional_header64.image_base = image_base;
2446
         uefi_header->optional_header64.image_base = image_base;
2430
         uefi_header->optional_header64.section_alignment = (uint32_t) image_pagesize;
2447
         uefi_header->optional_header64.section_alignment = (uint32_t) image_pagesize;
2431
         uefi_header->optional_header64.file_alignment = 512; // i.e. one filesystem block
2448
         uefi_header->optional_header64.file_alignment = 512; // i.e. one filesystem block
2432
         uefi_header->optional_header64.image_size = WILL_BE_FILLED_LATER; // total IFS file size
2449
         uefi_header->optional_header64.image_size = WILL_BE_FILLED_LATER; // total IFS file size
2433
         uefi_header->optional_header64.size_of_headers = (uint32_t) bootfile_size;
2450
         uefi_header->optional_header64.size_of_headers = (uint32_t) boot_code.size;
2434
         uefi_header->optional_header64.subsystem_type = 10; // IMAGE_SUBSYSTEM_EFI_APPLICATION
2451
         uefi_header->optional_header64.subsystem_type = 10; // IMAGE_SUBSYSTEM_EFI_APPLICATION
2435
         uefi_header->optional_header64.stack_reserve_size = image_pagesize;
2452
         uefi_header->optional_header64.stack_reserve_size = image_pagesize;
2436
         uefi_header->optional_header64.stack_commit_size = image_pagesize;
2453
         uefi_header->optional_header64.stack_commit_size = image_pagesize;
2437
         uefi_header->optional_header64.number_of_data_directories = 16; // mkifs reserves 16 data directories, filled with zeroes (FIXME: why?)
2454
         uefi_header->optional_header64.number_of_data_directories = 16; // mkifs reserves 16 data directories, filled with zeroes (FIXME: why?)
2438
         memcpy (uefi_header->unique_section.section_name, "image\0\0\0", 8); // store the unique section name
2455
         memcpy (uefi_header->unique_section.section_name, "image\0\0\0", 8); // store the unique section name
Line 2443... Line 2460...
2443
         uefi_header->unique_section.characteristics_bitmap = 0x60; // image contains code + image contains initialized data
2460
         uefi_header->unique_section.characteristics_bitmap = 0x60; // image contains code + image contains initialized data
2444
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, uefi_header->optional_header64.size_of_headers)); // pad as necessary
2461
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, uefi_header->optional_header64.size_of_headers)); // pad as necessary
2445
      }
2462
      }
2446
      else // BIOS boot
2463
      else // BIOS boot
2447
      {
2464
      {
-
 
2465
         // resolve the "bios.boot" file
2448
         // ######################################################################################################################################################################################################################################
2466
         resolved_pathname = resolve_pathname ("bios.boot", startup_entry_parms.search); // locate the executable location
2449
         // # FIXME: figure out how mkifs produces the boot prefix out of the BIOS "boot file" here
2467
         ASSERT (resolved_pathname, "QNX BIOS boot \"bios.boot\" not found in search path");
-
 
2468
         ASSERT_WITH_ERRNO (Buffer_ReadFromFile (&boot_code, resolved_pathname)); // load it
-
 
2469
 
-
 
2470
         // isolate its first segment
-
 
2471
         #define ELFHDR ((elf_header_t *) boot_code.bytes) // this convenient definition will make sure the ELF header points at the right location
2450
         // ######################################################################################################################################################################################################################################
2472
         phdr = (elf_program_header_t *) &boot_code.bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset)]; // quick access to first program header
-
 
2473
         first_segment_offset = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset); // get the first segment's start offset in the ELF file
-
 
2474
         cumulated_segment_length = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // get this ELF segment's length in the ELF file
-
 
2475
         #undef ELFHDR
-
 
2476
         ASSERT_WITH_ERRNO (Buffer_SubsetWithLength (&boot_code, first_segment_offset, cumulated_segment_length)); // isolate it
-
 
2477
 
-
 
2478
         // locate the "            boot" string (16 bytes) and chop it off along with everything preceding it
2451
         if (!Buffer_ReadFromFile (&opaqueblob_file, bootfile_pathname))
2479
         bootcode_start = Buffer_FindFirstByteArray (&boot_code, "            boot");
2452
            DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", bootfile_pathname, strerror (errno));
2480
         ASSERT (bootcode_start != NULL, "bios.boot does not contain the expected '            boot' marker");
-
 
2481
         bootcode_start += 16; // skip the marker
-
 
2482
         ASSERT_WITH_ERRNO (Buffer_SubsetFromTo (&boot_code, (size_t) bootcode_start - (size_t) boot_code.bytes, boot_code.size)); // isolate what's after
-
 
2483
 
-
 
2484
         // pad it to 3888 bytes (FIXME: why this value? Can it be less?)
2453
         ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &opaqueblob_file)); // write boot blob
2485
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&boot_code, 3888)); // pad as necessary
-
 
2486
 
2454
         Buffer_Forget (&opaqueblob_file);
2487
         ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &boot_code)); // write boot blob
2455
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2488
         ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2456
      }
2489
      }
2457
 
2490
 
2458
      ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use
2491
      ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use
2459
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
2492
      memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header
Line 2465... Line 2498...
2465
         startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64
2498
         startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64
2466
      else if (strcmp (image_processor, "aarch64le") == 0)
2499
      else if (strcmp (image_processor, "aarch64le") == 0)
2467
         startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64
2500
         startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64
2468
      else
2501
      else
2469
         DIE_WITH_EXITCODE (1, "unsupported processor type '%s' found in build file \"%s\"", image_processor, buildfile_pathname); // should not happen
2502
         DIE_WITH_EXITCODE (1, "unsupported processor type '%s' found in build file \"%s\"", image_processor, buildfile_pathname); // should not happen
2470
      startup_header.startup_vaddr = image_base + (uint32_t) startupfile_ep_from_imagebase; // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
2503
      startup_header.startup_vaddr = WILL_BE_FILLED_LATER;                   // [I ] Virtual Address to transfer to after IPL is done, here 0x01403008 (appears in "Entry" column for "startup.*")
2471
      startup_header.image_paddr   = image_base + (uint32_t) bootfile_size;                 // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
2504
      startup_header.image_paddr   = image_base + (uint32_t) boot_code.size; // F[IS] Physical address of image, here 0x01400f30 (appears in "Offset" column for "startup-header" which is the first entry/start of file)
2472
      startup_header.ram_paddr     = startup_header.image_paddr;                            // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
2505
      startup_header.ram_paddr     = startup_header.image_paddr;             // [IS] Physical address of RAM to copy image to (startup_size bytes copied), here 0x01400f30 (same as above)
2473
      startup_header.ram_size      = WILL_BE_FILLED_LATER;                                  // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686)
2506
      startup_header.ram_size      = WILL_BE_FILLED_LATER;                   // [ S] Amount of RAM used by the startup program and executables contained in the file system, here 0x00cd6128 i.e. 13 459 752 dec. which is 13 Mb. i.e. IFS file size minus 0x9eee (40686)
2474
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                                  // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
2507
      startup_header.startup_size  = WILL_BE_FILLED_LATER;                   // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes
2475
      startup_header.stored_size   = WILL_BE_FILLED_LATER;                                  // [I ] Size of entire image file (startup + *optionally compressed* imagefs) without optional boot prefix, here 0x00cd6128
2508
      startup_header.stored_size   = WILL_BE_FILLED_LATER;                   // [I ] Size of entire image file (startup + *optionally compressed* imagefs) without optional boot prefix, here 0x00cd6128
2476
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                                  // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
2509
      startup_header.imagefs_size  = WILL_BE_FILLED_LATER;                   // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes
2477
      startup_header.preboot_size  = (uint16_t) bootfile_size;                              // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
2510
      startup_header.preboot_size  = (uint16_t) boot_code.size;              // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file))
2478
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_header, sizeof (startup_header))); // write startup header
2511
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_header, sizeof (startup_header))); // write startup header
2479
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2512
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2480
 
2513
 
2481
      // ######################################################################################################################################################################################################################################
2514
      // prelink the startup executable, map its .text segment at the right virtual address for the IFS and stamp in its executable arguments
2482
      // # FIXME: figure out how to re-create it:
2515
      // then store the result in this entry's data blob
-
 
2516
      sprintf_s (textbase_mapaddr_string, sizeof (textbase_mapaddr_string), ".text=0x%zx", image_base + ifs.data.size); // image base + sizeof (boot prefix + startup header)
2483
      // first: open "startup-x86" ELF file,
2517
      prelink (startup_entry_parms.search, // binary executable search path
-
 
2518
               textbase_mapaddr_string, // "--section-start" linker argument (e.g. ".text=0xXXXXXXXX")
2484
      //        lookup section headers table (there is no program headers table in this one)
2519
               &startup_argv, &startup_envp, // executable arguments (including its name) and environment to stamp in it
-
 
2520
               startup_entry_parms.should_keep_ld_output, // whether to keep the linker-produced output file
-
 
2521
               &startup_code, // buffer where to save the output
2485
      //        FIXME: figure out something in there where the result is 0x1401030 !!!
2522
               &startup_bootargs_offset); // where to save the offset of the boot arguments
-
 
2523
 
2486
      // then: call the linker: ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED
2524
      // fix shdr_addr in procnto's arguments structure, same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
-
 
2525
      ((bootargs_entry_t *) &startup_code.bytes[startup_bootargs_offset])->shdr_addr = (uint32_t) (image_base + boot_code.size);
-
 
2526
 
2487
      // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?)
2527
      // backup two interesting values and chop off the ELF header until the start of the first segment
-
 
2528
      #define ELFHDR ((elf_header_t *) startup_code.bytes) // this convenient definition will make sure the ELF header points at the right location
2488
      // ######################################################################################################################################################################################################################################
2529
      startup_header.startup_vaddr = (uint32_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, entrypoint_offset); // read ELF entrypoint and store it in the startup header (it will be rewritten at the end of the process)
2489
#if 0 // nonworking
2530
      if (boot_type == BOOTTYPE_UEFI)
2490
      // <deleted>
2531
      {
-
 
2532
         uefi_header = (uefi64_header_t *) ifs.data.bytes; // restore UEFI header pointer
-
 
2533
         uefi_header->optional_header64.entrypoint_address = (uint32_t) (startup_header.startup_vaddr - image_base); // save UEFI startup address by substracting image base from ELF entrypoint
2491
#else // working
2534
      }
-
 
2535
      first_segment_offset = 0;
-
 
2536
      minimal_padded_length = 0;
2492
      if (!Buffer_ReadFromFile (&opaqueblob_file, startupfile_pathname))
2537
      cumulated_segment_length = 0;
2493
         DIE_WITH_EXITCODE (1, "failed to open \"%s\" for reading: %s", startupfile_pathname, strerror (errno));
2538
      program_header_table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers
2494
      ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &opaqueblob_file)); // write startup blob
2539
      for (table_index = 0; table_index < program_header_table_count; table_index++)
-
 
2540
      {
-
 
2541
         phdr = (elf_program_header_t *) &startup_code.bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
2495
      Buffer_Forget (&opaqueblob_file);
2542
         if (first_segment_offset == 0)
-
 
2543
            first_segment_offset = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset); // get the first segment's start offset in the ELF file
-
 
2544
         minimal_padded_length += ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); // get this ELF segment's required memory in the ELF file
-
 
2545
         cumulated_segment_length += ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // get this ELF segment's length in the ELF file
-
 
2546
      }
2496
#endif // working
2547
      #undef ELFHDR
-
 
2548
 
-
 
2549
      // FIXME: more bytes are read from the file past the last segment. Either a mkifs bug, or I'm wrong somewhere?
-
 
2550
      ASSERT_WITH_ERRNO (Buffer_SubsetWithLength (&startup_code, first_segment_offset, cumulated_segment_length + (boot_type == BOOTTYPE_UEFI ? 0x400 : 0x820)));
-
 
2551
 
-
 
2552
      // pad with zeroes up to the required memory length and align with page size plus 4 (FIXME: understand why +4)
-
 
2553
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&startup_code, ROUND_TO_UPPER_MULTIPLE (minimal_padded_length, image_pagesize) + 4)); // pad as necessary
-
 
2554
 
-
 
2555
      // write the startup blob and pad as necessary
-
 
2556
      ASSERT_WITH_ERRNO (Buffer_AppendBuffer (&ifs.data, &startup_code)); // write startup blob
2497
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2557
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2498
 
2558
 
2499
      ifs.offsets.startuptrailer = ifs.data.size; // save startup trailer offset for future use
2559
      ifs.offsets.startuptrailer = ifs.data.size; // save startup trailer offset for future use
2500
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_trailer, sizeof (startup_trailer))); // write startup trailer
2560
      ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_trailer, sizeof (startup_trailer))); // write startup trailer
2501
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
2561
      ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary
Line 2524... Line 2584...
2524
   }
2584
   }
2525
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory
2585
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory
2526
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2586
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2527
 
2587
 
2528
   // is it a bootable image with a startup file ?
2588
   // is it a bootable image with a startup file ?
2529
   if (startupfile_pathname != NULL)
2589
   if (startup_argv.count > 0)
2530
   {
2590
   {
2531
      // compute the kernel offset: address of the first page that comes after the directory entries
2591
      // compute the kernel offset: address of the first page that comes after the directory entries
2532
      kernelfile_offset = ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_pagesize);
2592
      kernelfile_offset = ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_pagesize);
2533
 
2593
 
2534
      // write the filesystem entries that may fit before the kernel
2594
      // write the filesystem entries that may fit before the kernel
Line 2565... Line 2625...
2565
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2625
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2566
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2626
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2567
            break; // locate the kernel directory entry (can't fail)
2627
            break; // locate the kernel directory entry (can't fail)
2568
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2628
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2569
      ASSERT (procnto_bootargs_offset + sizeof (bootargs_entry_t) < fsentries[fsentry_index].u.file.size, "can't fix boot args in procnto, would write beyond the end of file! This is a bug in the program. Please contact the author.");
2629
      ASSERT (procnto_bootargs_offset + sizeof (bootargs_entry_t) < fsentries[fsentry_index].u.file.size, "can't fix boot args in procnto, would write beyond the end of file! This is a bug in the program. Please contact the author.");
2570
      ((bootargs_entry_t *) &fsentries[fsentry_index].UNSAVED_databuf[procnto_bootargs_offset])->shdr_addr = (uint32_t) (image_base + bootfile_size); // fix shdr_addr in procnto's arguments structure, same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
2630
      ((bootargs_entry_t *) &fsentries[fsentry_index].UNSAVED_databuf[procnto_bootargs_offset])->shdr_addr = (uint32_t) (image_base + boot_code.size); // fix shdr_addr in procnto's arguments structure, same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
2571
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data
2631
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data
2572
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2632
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2573
   }
2633
   }
2574
 
2634
 
2575
   // then write all the other files by increasing inode number: ELF files first
2635
   // then write all the other files by increasing inode number: ELF files first
Line 2620... Line 2680...
2620
   // see if we are past the image max size, in which case it's an error
2680
   // see if we are past the image max size, in which case it's an error
2621
   if (ifs.final_size > image_maxsize)
2681
   if (ifs.final_size > image_maxsize)
2622
      DIE_WITH_EXITCODE (1, "image file size %zd exceeds max size (%zd)", ifs.final_size, (size_t) image_maxsize);
2682
      DIE_WITH_EXITCODE (1, "image file size %zd exceeds max size (%zd)", ifs.final_size, (size_t) image_maxsize);
2623
 
2683
 
2624
   // do we have a startup file ? if so, this is a bootable image
2684
   // do we have a startup file ? if so, this is a bootable image
2625
   if (startupfile_pathname != NULL)
2685
   if (startup_argv.count > 0)
2626
   {
2686
   {
2627
      // patch the startup header with its final values
2687
      // patch the startup header with its final values
2628
      startup_header.startup_size = (uint32_t) (ifs.offsets.imageheader - ifs.offsets.startupheader); // size of startup header up to image header
2688
      startup_header.startup_size = (uint32_t) (ifs.offsets.imageheader - ifs.offsets.startupheader); // size of startup header up to image header
2629
      startup_header.imagefs_size = (uint32_t) (ifs.final_size - ifs.offsets.imageheader); // size of uncompressed imagefs
2689
      startup_header.imagefs_size = (uint32_t) (ifs.final_size - ifs.offsets.imageheader); // size of uncompressed imagefs
2630
      startup_header.ram_size     = (uint32_t) (ifs.final_size - ifs.offsets.startupheader);
2690
      startup_header.ram_size     = (uint32_t) (ifs.final_size - ifs.offsets.startupheader);
Line 2681... Line 2741...
2681
      if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL)
2741
      if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL)
2682
         ASSERT (ucl_init () == UCL_E_OK, "UCL library initialization failed -- please recompile this tool with less aggressive optimizations");
2742
         ASSERT (ucl_init () == UCL_E_OK, "UCL library initialization failed -- please recompile this tool with less aggressive optimizations");
2683
      else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO)
2743
      else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO)
2684
         ASSERT (ucl_init () == UCL_E_OK, "LZO library initialization failed -- please recompile this tool with less aggressive optimizations");
2744
         ASSERT (ucl_init () == UCL_E_OK, "LZO library initialization failed -- please recompile this tool with less aggressive optimizations");
2685
      else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB)
2745
      else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB)
2686
         DIE_WITH_EXITCODE (1, "unimplemented compression scheme: zlib (FIXME)");
2746
         DIE_WITH_EXITCODE (1, "unimplemented compression scheme: zlib"); // deprecated by QNX: won't fix
2687
      else
2747
      else
2688
         DIE_WITH_EXITCODE (1, "unsupported compression flags: 0x%2x", startup_header_compression_flag);
2748
         DIE_WITH_EXITCODE (1, "unsupported compression flags: 0x%2x", startup_header_compression_flag);
2689
   
2749
   
2690
      // run the compressible payload (the imagefs) through the right compression algorithm
2750
      // run the compressible payload (the imagefs) through the right compression algorithm
2691
      while (remaining_len > 0)
2751
      while (remaining_len > 0)
Line 2747... Line 2807...
2747
      startup_header.stored_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader);
2807
      startup_header.stored_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader);
2748
      ASSERT_WITH_ERRNO (Buffer_WriteAt (&ifs.data, ifs.offsets.startupheader, &startup_header, sizeof (startup_header))); // write the final startup header at its right offset
2808
      ASSERT_WITH_ERRNO (Buffer_WriteAt (&ifs.data, ifs.offsets.startupheader, &startup_header, sizeof (startup_header))); // write the final startup header at its right offset
2749
   }
2809
   }
2750
 
2810
 
2751
   // do we have a startup file ? if so, this is a bootable image
2811
   // do we have a startup file ? if so, this is a bootable image
2752
   if (startupfile_pathname != NULL)
2812
   if (startup_argv.count > 0)
2753
   {
2813
   {
2754
      if (boot_type == BOOTTYPE_UEFI) // UEFI boot: fix the final offsets and sizes in the EFI executable's PE header
2814
      if (boot_type == BOOTTYPE_UEFI) // UEFI boot: fix the final offsets and sizes in the EFI executable's PE header
2755
      {
2815
      {
2756
         uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer
2816
         uefi_header = (uefi64_header_t *) ifs.data.bytes; // have a convenience pointer
2757
         uefi_header->optional_header64.code_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader); // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image
2817
         uefi_header->optional_header64.code_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader); // total size of IFS minus 512 bytes for the UEFI boot header, i.e. size of startup blob plus size of image