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 |
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 |
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 |
|
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 |
|
1194 | // prelink procnto, map its .text segment at the right virtual address for the IFS and stamp in its executable arguments |
1078 |
|
1195 | // then store the result in this entry's data blob |
1079 |
|
1196 | prelink (entry_parms->search, // binary executable search path |
- | 1197 | (boot_type == BOOTTYPE_UEFI ? ".text=0xffff800000002000" : ".text=0xffff800000001000"), // FIXME: wild assumption! |
|
1080 |
|
1198 | &procnto_argv, &procnto_envp, // executable arguments (including its name) and environment to stamp in it |
1081 |
|
1199 | entry_parms->should_keep_ld_output, // whether to keep the linker-produced output file |
1082 |
|
1200 | &entry_parms->data, // buffer where to save the output |
1083 |
|
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 |
1203 | // strip this prelinked ELF file from all the sections we don't need |
1156 | ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, |
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 |
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 |
|
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 |
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 ( |
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 = |
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) |
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 |
|
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 |
|
2479 | bootcode_start = Buffer_FindFirstByteArray (&boot_code, " boot"); |
2452 |
|
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 ( |
2485 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&boot_code, 3888)); // pad as necessary |
- | 2486 | ||
2454 |
|
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 = |
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) |
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; |
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; |
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; |
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; |
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; |
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) |
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 | // |
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 | // |
2517 | prelink (startup_entry_parms.search, // binary executable search path |
- | 2518 | textbase_mapaddr_string, // "--section-start" linker argument (e.g. ".text=0xXXXXXXXX") |
|
2484 |
|
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 |
|
2522 | &startup_bootargs_offset); // where to save the offset of the boot arguments |
- | 2523 | ||
2486 | // |
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 | // |
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 |
|
2530 | if (boot_type == BOOTTYPE_UEFI) |
2490 |
|
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 |
|
2534 | } |
- | 2535 | first_segment_offset = 0; |
|
- | 2536 | minimal_padded_length = 0; |
|
2492 |
|
2537 | cumulated_segment_length = 0; |
2493 |
|
2538 | program_header_table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers |
2494 |
|
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 |
|
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 |
|
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 ( |
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 + |
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 ( |
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 |
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 ( |
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 |