Rev 25 | Rev 30 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 25 | Rev 26 | ||
---|---|---|---|
Line 28... | Line 28... | ||
28 | #include <dirent.h> |
28 | #include <dirent.h> |
29 | #include <utime.h> |
29 | #include <utime.h> |
30 | #endif // _MSC_VER |
30 | #endif // _MSC_VER |
31 | 31 | ||
32 | // own includes |
32 | // own includes |
- | 33 | #include "ucl/ucl.h" |
|
- | 34 | #include "minilzo.h" |
|
33 | #include "buffer.h" |
35 | #include "buffer.h" |
34 | #include "sha512.h" |
36 | #include "sha512.h" |
35 | #include "elffile.h" |
37 | #include "elffile.h" |
36 | #include "ifsfile.h" |
38 | #include "ifsfile.h" |
37 | #include "utility.h" |
39 | #include "utility.h" |
Line 130... | Line 132... | ||
130 | static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit) |
132 | static uint32_t image_maxsize = UINT32_MAX; // default image max size (no limit) |
131 | static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file |
133 | static uint32_t image_totalsize = 0; // image total size, measured once all the blocks have been written to the output IFS file |
132 | static uint32_t image_align = 4; // default image alignment, as per QNX docs |
134 | static uint32_t image_align = 4; // default image alignment, as per QNX docs |
133 | static uint32_t image_kernel_ino = 0; |
135 | static uint32_t image_kernel_ino = 0; |
134 | static uint32_t image_bootscript_ino = 0; |
136 | static uint32_t image_bootscript_ino = 0; |
- | 137 | static int startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_NONE; |
|
135 | #if defined(__x86_64__) |
138 | #if defined(__x86_64__) |
136 | static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
139 | static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
137 | static char image_processor_base[16] = "x86_64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
140 | static char image_processor_base[16] = "x86_64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
138 | #elif defined(__aarch64__) |
141 | #elif defined(__aarch64__) |
139 | static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
142 | static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET) |
Line 175... | Line 178... | ||
175 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
178 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
176 | 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 |
179 | 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 |
177 | 180 | ||
178 | 181 | ||
179 | // imported function prototypes |
182 | // imported function prototypes |
180 | extern int dump_ifs_info (const char *ifs_pathname, bool want_everything); // [implemented in ifsdump.c] dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
183 | extern int dump_ifs_info (const char *ifs_pathname, bool want_everything, bool hide_filename); // [implemented in ifsdump.c] dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
181 | extern int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // [implemented in ifsdump.c] dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error |
184 | extern int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // [implemented in ifsdump.c] dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error |
182 | extern int dump_file_hex (const char *pathname); // [implemented in ifsdump.c] dumps the contents of pathname to stdout in mixed hexadecimal + ASCII (hex editor) format |
185 | extern int dump_file_hex (const char *pathname); // [implemented in ifsdump.c] dumps the contents of pathname to stdout in mixed hexadecimal + ASCII (hex editor) format |
183 | 186 | ||
184 | 187 | ||
185 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness) |
188 | int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness) |
Line 1775... | Line 1778... | ||
1775 | } |
1778 | } |
1776 | utc_time.tm_mon--; // convert month from [1-12] to [0-11] |
1779 | utc_time.tm_mon--; // convert month from [1-12] to [0-11] |
1777 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
1780 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
1778 | } |
1781 | } |
1779 | } |
1782 | } |
- | 1783 | else if (strncmp (token, "compress=", 9) == 0) { REACH_TOKEN_VALUE (); startup_header_compression_flag = (strcmp (value, "1") == 0 ? STARTUP_HDR_FLAGS1_COMPRESS_ZLIB : (strcmp (value, "2") == 0 ? STARTUP_HDR_FLAGS1_COMPRESS_LZO : STARTUP_HDR_FLAGS1_COMPRESS_UCL)); } |
|
- | 1784 | else if (strcmp (token, "+compress") == 0) startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_UCL; |
|
- | 1785 | else if (strcmp (token, "-compress") == 0) startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_NONE; |
|
1780 | else if (strcmp (token, "+script") == 0) entry_parms.is_compiled_bootscript = true; |
1786 | else if (strcmp (token, "+script") == 0) entry_parms.is_compiled_bootscript = true; |
1781 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1787 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
1782 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1788 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
1783 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1789 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
1784 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
1790 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
Line 2015... | Line 2021... | ||
2015 | char path_in_ifs[MAXPATHLEN] = ""; |
2021 | char path_in_ifs[MAXPATHLEN] = ""; |
2016 | const char *ifs_pathname = NULL; |
2022 | const char *ifs_pathname = NULL; |
2017 | const char *rootdir_pathname = NULL; |
2023 | const char *rootdir_pathname = NULL; |
2018 | const fsentry_t *fsentry; |
2024 | const fsentry_t *fsentry; |
2019 | void *reallocated_ptr; |
2025 | void *reallocated_ptr; |
- | 2026 | buffer_t compressed_imagefs; |
|
- | 2027 | uint8_t *compressor_out; |
|
- | 2028 | uint8_t *compressor_in; |
|
- | 2029 | size_t compressor_outlen; |
|
- | 2030 | size_t compressor_inlen; |
|
2020 | size_t reallocated_size; |
2031 | size_t reallocated_size; |
2021 | size_t available_space; |
2032 | size_t available_space; |
2022 | size_t fsentry_index; |
2033 | size_t fsentry_index; |
2023 | size_t largest_index; |
2034 | size_t largest_index; |
2024 | size_t largest_size; |
2035 | size_t largest_size; |
2025 | size_t imgdir_size; |
2036 | size_t imgdir_size; |
2026 | size_t curr_offset; |
2037 | size_t curr_offset; |
- | 2038 | size_t remaining_len; |
|
2027 | ifs_t ifs = { 0 }; |
2039 | ifs_t ifs = { 0 }; |
2028 | int32_t checksum; |
2040 | int32_t checksum; |
2029 | char *first_pathname = NULL; |
2041 | char *first_pathname = NULL; |
2030 | char *second_pathname = NULL; |
2042 | char *second_pathname = NULL; |
2031 | char *third_pathname = NULL; |
2043 | char *third_pathname = NULL; |
Line 2038... | Line 2050... | ||
2038 | bool want_everything = false; |
2050 | bool want_everything = false; |
2039 | bool want_help = false; |
2051 | bool want_help = false; |
2040 | bool want_dump = false; |
2052 | bool want_dump = false; |
2041 | bool want_strip = false; |
2053 | bool want_strip = false; |
2042 | bool want_hexdump = false; |
2054 | bool want_hexdump = false; |
- | 2055 | bool hide_filename = false; |
|
2043 | bool is_foreign_endianness; |
2056 | bool is_foreign_endianness; |
- | 2057 | int compressor_ret; |
|
2044 | FILE *buildfile_fp; |
2058 | FILE *buildfile_fp; |
2045 | 2059 | ||
2046 | // initialize stuff |
2060 | // initialize stuff |
2047 | saved_ELF_sections = (char **) malloc (4 * sizeof (char *)); |
2061 | saved_ELF_sections = (char **) malloc (4 * sizeof (char *)); |
2048 | ASSERT_WITH_ERRNO (saved_ELF_sections); |
2062 | ASSERT_WITH_ERRNO (saved_ELF_sections); |
Line 2091... | Line 2105... | ||
2091 | want_hexdump = true; |
2105 | want_hexdump = true; |
2092 | else if (strcmp (argv[arg_index], "--strip") == 0) |
2106 | else if (strcmp (argv[arg_index], "--strip") == 0) |
2093 | want_strip = true; |
2107 | want_strip = true; |
2094 | else if (strcmp (argv[arg_index], "--everything") == 0) |
2108 | else if (strcmp (argv[arg_index], "--everything") == 0) |
2095 | want_everything = true; |
2109 | want_everything = true; |
- | 2110 | else if (strcmp (argv[arg_index], "--hide-filename") == 0) |
|
- | 2111 | hide_filename = true; |
|
2096 | else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....] |
2112 | else if (strncmp (argv[arg_index], "-v", 2) == 0) // -v[....] |
2097 | verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag |
2113 | verbose_level += (int) strlen (argv[arg_index] + 1); // increase verbosity by the number of characters in this flag |
2098 | else if ((strcmp (argv[arg_index], "-l") == 0) && (arg_index + 1 < argc)) |
2114 | else if ((strcmp (argv[arg_index], "-l") == 0) && (arg_index + 1 < argc)) |
2099 | arg_index++; // these args will be parsed once the build file is open |
2115 | arg_index++; // these args will be parsed once the build file is open |
2100 | else if ((strcmp (argv[arg_index], "-r") == 0) && (arg_index + 1 < argc)) |
2116 | else if ((strcmp (argv[arg_index], "-r") == 0) && (arg_index + 1 < argc)) |
Line 2133... | Line 2149... | ||
2133 | fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
2149 | fprintf (out, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
2134 | fprintf (out, " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2150 | fprintf (out, " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2135 | if (!want_help) |
2151 | if (!want_help) |
2136 | fprintf (out, "error: missing parameters\n"); |
2152 | fprintf (out, "error: missing parameters\n"); |
2137 | fprintf (out, "usage:\n"); |
2153 | fprintf (out, "usage:\n"); |
2138 | fprintf (out, " ifstool --info [--everything] <ifs file>\n"); |
2154 | fprintf (out, " ifstool --info [--everything] [--hide-filename] <ifs file>\n"); |
2139 | fprintf (out, " ifstool --dump [--outdir <path>] <ifs file>\n"); |
2155 | fprintf (out, " ifstool --dump [--outdir <path>] <ifs file>\n"); |
2140 | fprintf (out, " ifstool --strip [--outfile <pathname>] <ELF file>\n"); |
2156 | fprintf (out, " ifstool --strip [--outfile <pathname>] <ELF file>\n"); |
2141 | fprintf (out, " ifstool [-?|--help]\n"); |
2157 | fprintf (out, " ifstool [-?|--help]\n"); |
2142 | // mkifs [-?] [-l inputline] [-n[n]] [-o directory] [-p patchfile] [-r rootdir] [-s section] [-v] [buildfile] [directory] [outputfile] |
2158 | // mkifs [-?] [-l inputline] [-n[n]] [-o directory] [-p patchfile] [-r rootdir] [-s section] [-v] [buildfile] [directory] [outputfile] |
2143 | 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"); |
2159 | 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"); |
Line 2212... | Line 2228... | ||
2212 | exit (want_help ? 0 : 1); |
2228 | exit (want_help ? 0 : 1); |
2213 | } |
2229 | } |
2214 | 2230 | ||
2215 | // else do we want info about a particular IFS ? if so, dissecate it |
2231 | // else do we want info about a particular IFS ? if so, dissecate it |
2216 | else if (want_info) |
2232 | else if (want_info) |
2217 | exit (dump_ifs_info (first_pathname, want_everything)); |
2233 | exit (dump_ifs_info (first_pathname, want_everything, hide_filename)); |
2218 | 2234 | ||
2219 | // else do we want to dump its contents ? if so, do so |
2235 | // else do we want to dump its contents ? if so, do so |
2220 | else if (want_dump) |
2236 | else if (want_dump) |
2221 | exit (dump_ifs_contents (first_pathname, (second_pathname != NULL ? second_pathname : "."))); |
2237 | exit (dump_ifs_contents (first_pathname, (second_pathname != NULL ? second_pathname : "."))); |
2222 | 2238 | ||
Line 2307... | Line 2323... | ||
2307 | 2323 | ||
2308 | ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use |
2324 | ifs.offsets.startupheader = ifs.data.size; // save startup header offset for future use |
2309 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
2325 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
2310 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
2326 | memcpy (startup_header.signature, "\xeb\x7e\xff\x00", 4); // startup header signature, i.e. 0xff7eeb |
2311 | startup_header.version = 1; |
2327 | startup_header.version = 1; |
2312 | startup_header.flags1 = STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2; // flags, 0x21 (STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2) |
2328 | startup_header.flags1 = STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2 | startup_header_compression_flag; // flags, 0x21 (STARTUP_HDR_FLAGS1_VIRTUAL | STARTUP_HDR_FLAGS1_TRAILER_V2) |
2313 | startup_header.header_size = sizeof (startup_header); // 256 |
2329 | startup_header.header_size = sizeof (startup_header); // 256 |
2314 | if (strcmp (image_processor, "x86_64") == 0) |
2330 | if (strcmp (image_processor, "x86_64") == 0) |
2315 | startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64 |
2331 | startup_header.machine = ELF_MACHINE_X86_64; // EM_X86_64 |
2316 | else if (strcmp (image_processor, "aarch64le") == 0) |
2332 | else if (strcmp (image_processor, "aarch64le") == 0) |
2317 | startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64 |
2333 | startup_header.machine = ELF_MACHINE_AARCH64; // EM_AARCH64 |
Line 2320... | Line 2336... | ||
2320 | 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.*") |
2336 | 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.*") |
2321 | 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) |
2337 | 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) |
2322 | 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) |
2338 | 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) |
2323 | 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) |
2339 | 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) |
2324 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
2340 | startup_header.startup_size = WILL_BE_FILLED_LATER; // [I ] Size of startup (never compressed), here 0x02f148 or 192 840 bytes |
2325 | startup_header.stored_size = WILL_BE_FILLED_LATER; // [I ] Size of entire |
2341 | startup_header.stored_size = WILL_BE_FILLED_LATER; // [I ] Size of entire image file (startup + *optionally compressed* imagefs) without optional boot prefix, here 0x00cd6128 |
2326 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
2342 | startup_header.imagefs_size = WILL_BE_FILLED_LATER; // [ S] Size of uncompressed imagefs, here 0x00ca6fe0 or 13 266 912 bytes |
2327 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
2343 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
2328 | ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_header, sizeof (startup_header))); // write startup header |
2344 | ASSERT_WITH_ERRNO (Buffer_Append (&ifs.data, &startup_header, sizeof (startup_header))); // write startup header |
2329 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
2345 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (&ifs.data, ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_align))); // pad as necessary |
2330 | 2346 | ||
Line 2376... | Line 2392... | ||
2376 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2392 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2377 | 2393 | ||
2378 | // is it a bootable image with a startup file ? |
2394 | // is it a bootable image with a startup file ? |
2379 | if (startupfile_pathname != NULL) |
2395 | if (startupfile_pathname != NULL) |
2380 | { |
2396 | { |
2381 | // start by writing the startup script data blob, if we have one |
- | |
2382 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
- | |
2383 | if (fsentries[fsentry_index].header.ino == image_bootscript_ino) |
- | |
2384 | break; // locate the startup script directory entry |
- | |
2385 | if (fsentry_index < fsentry_count) // found it ? |
- | |
2386 | { |
- | |
2387 | if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset) |
- | |
2388 | DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd. Use --kerneloffs <addr> to relocate (warning: untested)", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size); |
- | |
2389 | fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure |
- | |
2390 | Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data |
- | |
2391 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
- | |
2392 | } |
- | |
2393 | - | ||
2394 | // |
2397 | // write the filesystem entries that may fit before the kernel |
2395 | for (;;) |
2398 | for (;;) |
2396 | { |
2399 | { |
2397 | available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel |
2400 | available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel |
2398 | 2401 | ||
2399 | // look for the biggest one that can fit |
2402 | // look for the biggest one that can fit |
Line 2488... | Line 2491... | ||
2488 | Buffer_WriteIFSDirectoryEntryAt (&ifs.data, curr_offset, &fsentries[fsentry_index]); // rewrite each dirent |
2491 | Buffer_WriteIFSDirectoryEntryAt (&ifs.data, curr_offset, &fsentries[fsentry_index]); // rewrite each dirent |
2489 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one |
2492 | curr_offset += fsentries[fsentry_index].header.size; // advance to the next one |
2490 | } |
2493 | } |
2491 | 2494 | ||
2492 | // ALL CHECKSUMS AT THE VERY END |
2495 | // ALL CHECKSUMS AT THE VERY END |
- | 2496 | ||
- | 2497 | // compute SHA-512 checksum and V1 checksum of image block |
|
- | 2498 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
|
- | 2499 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ))) |
|
- | 2500 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
|
- | 2501 | else |
|
- | 2502 | is_foreign_endianness = false; // else this header is for the same endianness as us |
|
- | 2503 | ||
- | 2504 | if (image_header.flags & IMAGE_FLAGS_TRAILER_V2) // is it a V2 trailer ? |
|
- | 2505 | { |
|
- | 2506 | SHA512 (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, &ifs.data.bytes[ifs.offsets.imagetrailer]); // compute SHA512 checksum and write it in place |
|
- | 2507 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum |
|
- | 2508 | memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
|
- | 2509 | } |
|
- | 2510 | else // old V1 trailer |
|
- | 2511 | { |
|
- | 2512 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum |
|
- | 2513 | memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer], &checksum, 4); // and write it in place |
|
- | 2514 | } |
|
- | 2515 | ||
- | 2516 | // should we compress the image block ? |
|
- | 2517 | if (startup_header_compression_flag != STARTUP_HDR_FLAGS1_COMPRESS_NONE) |
|
- | 2518 | { |
|
- | 2519 | // it appears mkifs compresses data in blocks, prefixed by 2-byte block size in BIG ENDIAN |
|
- | 2520 | Buffer_InitWithSize (&compressed_imagefs, image_header.image_size * 11 / 10); // mallocate and add 10% for safety |
|
- | 2521 | compressed_imagefs.size = 0; |
|
- | 2522 | compressor_in = &ifs.data.bytes[ifs.offsets.imageheader]; // point at the start of the data to compress |
|
- | 2523 | compressor_out = &compressed_imagefs.bytes[2]; // point after the compressed block size word |
|
- | 2524 | remaining_len = ifs.data.size - ifs.offsets.imageheader; // see how many bytes there are to compress |
|
- | 2525 | ||
- | 2526 | if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 2527 | ASSERT (ucl_init () == UCL_E_OK, "UCL library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 2528 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 2529 | ASSERT (ucl_init () == UCL_E_OK, "LZO library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 2530 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 2531 | DIE_WITH_EXITCODE (1, "unimplemented compression scheme: zlib (FIXME)"); |
|
- | 2532 | else |
|
- | 2533 | DIE_WITH_EXITCODE (1, "unsupported compression flags: 0x%2x", startup_header_compression_flag); |
|
- | 2534 | ||
- | 2535 | // run the compressible payload (the imagefs) through the right compression algorithm |
|
- | 2536 | while (remaining_len > 0) |
|
- | 2537 | { |
|
- | 2538 | compressor_inlen = (ucl_uint) remaining_len; // size the compressor input appropriately |
|
- | 2539 | if (compressor_inlen > 65536) |
|
- | 2540 | compressor_inlen = 65536; // cap it to a VERY conservative value |
|
- | 2541 | if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 2542 | { |
|
- | 2543 | // UCL compression. NOTE: the decompressor function used in startup-x86 is "ucl_nrv2b_decompress_8". Also compression level is hardcoded at 9 in mkifs, but can range from 1 to 10 |
|
- | 2544 | static ucl_uint ucl_outlen; // have a different variable because of pointer size mismatch |
|
- | 2545 | while (((compressor_ret = ucl_nrv2b_99_compress (compressor_in, (ucl_uint) compressor_inlen, compressor_out, &ucl_outlen, NULL, 9, NULL, NULL)) == UCL_E_OK) && (ucl_outlen > 0xFFFF)) |
|
- | 2546 | compressor_inlen -= 4096; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with 4kb input less |
|
- | 2547 | ASSERT (compressor_ret == UCL_E_OK, "UCL compression error: ucl_nrv2b_99_compress() returned %d", compressor_ret); // make sure it's not a compression error |
|
- | 2548 | compressor_outlen = ucl_outlen; // cast back to size_t |
|
- | 2549 | } |
|
- | 2550 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 2551 | { |
|
- | 2552 | // LZO compression. NOTE: the compressor function used in mkifs is "lzo1x_999_compress" which is from the full LZO package... I use use minilzo, but I have to admit the compression ratio of the full LZO is *much* better. |
|
- | 2553 | static lzo_align_t lzo_workmem[(LZO1X_1_MEM_COMPRESS + (sizeof (lzo_align_t) - 1)) / sizeof(lzo_align_t)]; // heap-allocated aligned buffer |
|
- | 2554 | static lzo_uint lzo_outlen; // have a different variable because of pointer size mismatch |
|
- | 2555 | while (((compressor_ret = lzo1x_1_compress (compressor_in, compressor_inlen, compressor_out, &lzo_outlen, lzo_workmem)) == UCL_E_OK) && (lzo_outlen > 0xFFFF)) |
|
- | 2556 | compressor_inlen -= 4096; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with 4kb input less |
|
- | 2557 | ASSERT (compressor_ret == LZO_E_OK, "LZO compression error: lzo1x_1_compress() returned %d", compressor_ret); // make sure it's not a compression error |
|
- | 2558 | compressor_outlen = lzo_outlen; // cast back to size_t |
|
- | 2559 | } |
|
- | 2560 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 2561 | { |
|
- | 2562 | // Zlib (TODO) |
|
- | 2563 | } |
|
- | 2564 | ||
- | 2565 | // the compression produced a block smaller than 65536 bytes |
|
- | 2566 | LOG_DEBUG ("compressed block size %zd", compressor_outlen); |
|
- | 2567 | compressed_imagefs.bytes[compressed_imagefs.size + 0] = (uint8_t) (compressor_outlen >> 8); // write compressed block size word (in big endian) |
|
- | 2568 | compressed_imagefs.bytes[compressed_imagefs.size + 1] = (uint8_t) (compressor_outlen >> 0); |
|
- | 2569 | compressed_imagefs.size += 2 + (size_t) compressor_outlen; // advance in compression buffer by the compressed block size word plus the compressed block size |
|
- | 2570 | ||
- | 2571 | remaining_len -= compressor_inlen; // see how many bytes remain to compress |
|
- | 2572 | ||
- | 2573 | compressor_in += compressor_inlen; // advance in input stream |
|
- | 2574 | compressor_out += 2 + compressor_outlen; // advance in output stream |
|
- | 2575 | } |
|
- | 2576 | ||
- | 2577 | compressed_imagefs.bytes[compressed_imagefs.size + 0] = 0; // write the end of stream marker (empty block with nil size) |
|
- | 2578 | compressed_imagefs.bytes[compressed_imagefs.size + 1] = 0; |
|
- | 2579 | compressed_imagefs.size += 2; |
|
- | 2580 | LOG_INFO ("compressed %zd bytes into %zd bytes\n", ifs.data.size - ifs.offsets.imageheader, compressed_imagefs.size); |
|
- | 2581 | ||
- | 2582 | ///////////////////////////////////////////////////////////// |
|
- | 2583 | // WARNING: ALL IFS OFFSETS BECOME INVALID PAST THIS POINT // |
|
- | 2584 | ///////////////////////////////////////////////////////////// |
|
- | 2585 | ||
- | 2586 | // now place the compressed buffer in the payload at the imagefs offset |
|
- | 2587 | ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&ifs.data, ifs.offsets.imageheader, &compressed_imagefs)); |
|
- | 2588 | ifs.data.size = ifs.offsets.imageheader + compressed_imagefs.size; // update IFS data size |
|
- | 2589 | Buffer_Forget (&compressed_imagefs); |
|
- | 2590 | ||
- | 2591 | // fix the stored size in the startup header |
|
- | 2592 | startup_header.stored_size = (uint32_t) (ifs.data.size - ifs.offsets.startupheader); |
|
- | 2593 | ASSERT_WITH_ERRNO (Buffer_WriteAt (&ifs.data, ifs.offsets.startupheader, &startup_header, sizeof (startup_header))); // write the final startup header at its right offset |
|
- | 2594 | } |
|
2493 | 2595 | ||
2494 | // do we have a startup file ? if so, this is a bootable image |
2596 | // do we have a startup file ? if so, this is a bootable image |
2495 | if (startupfile_pathname != NULL) |
2597 | if (startupfile_pathname != NULL) |
2496 | { |
2598 | { |
2497 | // compute SHA-512 checksum and V1 checksum of startup block |
2599 | // compute SHA-512 checksum and V1 checksum of startup block |
2498 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2600 | if ( ( (startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2499 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2601 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ))) |
2500 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2602 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2501 | else |
2603 | else |
2502 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2604 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2503 | 2605 | ||
2504 | if (startup_header.flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) // is it a V2 trailer ? |
2606 | if (startup_header.flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) // is it a V2 trailer ? |
Line 2510... | Line 2612... | ||
2510 | else // old V1 trailer |
2612 | else // old V1 trailer |
2511 | { |
2613 | { |
2512 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.startupheader], ifs.offsets.startuptrailer - ifs.offsets.startupheader, is_foreign_endianness); // compute old checksum |
2614 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.startupheader], ifs.offsets.startuptrailer - ifs.offsets.startupheader, is_foreign_endianness); // compute old checksum |
2513 | memcpy (&ifs.data.bytes[ifs.offsets.startuptrailer], &checksum, 4); // and write it in place |
2615 | memcpy (&ifs.data.bytes[ifs.offsets.startuptrailer], &checksum, 4); // and write it in place |
2514 | } |
2616 | } |
2515 | } |
- | |
2516 | - | ||
2517 | // compute SHA-512 checksum and V1 checksum of image block |
- | |
2518 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
- | |
2519 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
- | |
2520 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
- | |
2521 | else |
- | |
2522 | is_foreign_endianness = false; // else this header is for the same endianness as us |
- | |
2523 | - | ||
2524 | if (image_header.flags & IMAGE_FLAGS_TRAILER_V2) // is it a V2 trailer ? |
- | |
2525 | { |
- | |
2526 | SHA512 (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, &ifs.data.bytes[ifs.offsets.imagetrailer]); // compute SHA512 checksum and write it in place |
- | |
2527 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum |
- | |
2528 | memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
- | |
2529 | } |
- | |
2530 | else // old V1 trailer |
- | |
2531 | { |
- | |
2532 | checksum = update_checksum (&ifs.data.bytes[ifs.offsets.imageheader], ifs.offsets.imagetrailer - ifs.offsets.imageheader, is_foreign_endianness); // compute old checksum |
- | |
2533 | memcpy (&ifs.data.bytes[ifs.offsets.imagetrailer], &checksum, 4); // and write it in place |
- | |
2534 | } |
2617 | } |
2535 | 2618 | ||
2536 | // now rewrite IFS with the correct checksums |
2619 | // now rewrite IFS with the correct checksums |
2537 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&ifs.data, (ifs_pathname != NULL ? ifs_pathname : "<stdout>"))); |
2620 | ASSERT_WITH_ERRNO (Buffer_WriteToFile (&ifs.data, (ifs_pathname != NULL ? ifs_pathname : "<stdout>"))); |
2538 | 2621 |