Rev 26 | Rev 31 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 26 | Rev 30 | ||
---|---|---|---|
Line 134... | Line 134... | ||
134 | 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 |
135 | static uint32_t image_kernel_ino = 0; |
135 | static uint32_t image_kernel_ino = 0; |
136 | 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; |
137 | static int startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_NONE; |
138 | #if defined(__x86_64__) |
138 | #if defined(__x86_64__) |
139 | static char |
139 | static char *image_processor = "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) |
140 | static char |
140 | static char *image_processor_base = "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) |
- | 141 | static size_t image_pagesize = 4 * 1024; // default page size for the image, depends on the CPU type. Intel has 4kb pages, ARM has 16kb ones. |
|
141 | #elif defined(__aarch64__) |
142 | #elif defined(__aarch64__) |
142 | static char |
143 | static char *image_processor = "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) |
143 | static char |
144 | static char *image_processor_base = "aarch64"; // 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) |
- | 145 | static size_t image_pagesize = 16 * 1024; // default page size for the image, depends on the CPU type. Intel has 4kb pages, ARM has 16kb ones. |
|
144 | #else // unknown platform |
146 | #else // unknown platform |
145 | #error Please port ifstool to this platform |
147 | #error Please port ifstool to this platform |
146 | #endif |
148 | #endif |
147 | static char *buildfile_pathname = NULL; // pathname of IFS build file |
149 | static char *buildfile_pathname = NULL; // pathname of IFS build file |
148 | static char *current_line = NULL; // copy of current line in IFS build file |
150 | static char *current_line = NULL; // copy of current line in IFS build file |
Line 156... | Line 158... | ||
156 | // bootable IFS support |
158 | // bootable IFS support |
157 | static char *bootfile_pathname = NULL; // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
159 | static char *bootfile_pathname = NULL; // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
158 | static size_t bootfile_size = 0; // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
160 | static size_t bootfile_size = 0; // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS |
159 | static char *startupfile_pathname = NULL; // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
161 | static char *startupfile_pathname = NULL; // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS |
160 | static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS |
162 | static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS |
161 | static size_t kernelfile_offset = |
163 | static size_t kernelfile_offset = 0; // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table) |
162 | 164 | ||
163 | 165 | ||
164 | // exported function prototypes |
166 | // exported function prototypes |
165 | 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 |
167 | 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 |
166 | 168 | ||
Line 635... | Line 637... | ||
635 | size_t size_in_file; |
637 | size_t size_in_file; |
636 | size_t file_offset; |
638 | size_t file_offset; |
637 | size_t array_index; |
639 | size_t array_index; |
638 | size_t table_index; |
640 | size_t table_index; |
639 | size_t table_count; |
641 | size_t table_count; |
640 | size_t page_size; |
- | |
641 | - | ||
642 | // find out the platform page size |
- | |
643 | if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_X86_64) |
- | |
644 | page_size = 4 * 1024; // 4 kb pages on Intel processors |
- | |
645 | else if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_AARCH64) |
- | |
646 | page_size = 16 * 1024; // 16 kb pages on ARM64 |
- | |
647 | else |
- | |
648 | { |
- | |
649 | errno = ENOTSUP; // unsupported architecture: set errno to something meaningful |
- | |
650 | return (0); // and return an error value |
- | |
651 | } |
- | |
652 | 642 | ||
653 | // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first |
643 | // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first |
654 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers |
644 | table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers |
655 | for (table_index = 0; table_index < table_count; table_index++) |
645 | for (table_index = 0; table_index < table_count; table_index++) |
656 | { |
646 | { |
Line 703... | Line 693... | ||
703 | if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory) > new_shdrtable_offset_method2) |
693 | if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory) > new_shdrtable_offset_method2) |
704 | new_shdrtable_offset_method2 = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); |
694 | new_shdrtable_offset_method2 = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); |
705 | } |
695 | } |
706 | if (new_shdrtable_offset_method2 > new_shdrtable_offset) |
696 | if (new_shdrtable_offset_method2 > new_shdrtable_offset) |
707 | LOG_DEBUG ("METHOD2: %llx > %llx", new_shdrtable_offset_method2, new_shdrtable_offset);*/ |
697 | LOG_DEBUG ("METHOD2: %llx > %llx", new_shdrtable_offset_method2, new_shdrtable_offset);*/ |
708 | //new_shdrtable_offset = ROUND_TO_UPPER_MULTIPLE (new_shdrtable_offset, |
698 | //new_shdrtable_offset = ROUND_TO_UPPER_MULTIPLE (new_shdrtable_offset, image_pagesize); // round to page size |
709 | 699 | ||
710 | // re-create the section header table |
700 | // re-create the section header table |
711 | ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table |
701 | ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table |
712 | ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table |
702 | ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table |
713 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator |
703 | ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator |
Line 766... | Line 756... | ||
766 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset); |
756 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset); |
767 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, new_shdrtable_len); |
757 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, new_shdrtable_len); |
768 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section |
758 | ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section |
769 | 759 | ||
770 | // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space |
760 | // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space |
771 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, |
761 | ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, image_pagesize))); |
772 | 762 | ||
773 | // cleanup |
763 | // cleanup |
774 | for (table_index = 0; table_index < elf_section_count; table_index++) |
764 | for (table_index = 0; table_index < elf_section_count; table_index++) |
775 | Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers |
765 | Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers |
776 | 766 | ||
Line 1757... | Line 1747... | ||
1757 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them |
1747 | if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them |
1758 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
1748 | DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno); |
1759 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1749 | if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ? |
1760 | { |
1750 | { |
1761 | *sep = 0; |
1751 | *sep = 0; |
- | 1752 | if (strcmp (value, "x86_64") == 0) |
|
- | 1753 | { |
|
- | 1754 | image_processor = "x86_64"; // save processor |
|
- | 1755 | image_processor_base = "x86_64"; // save processor base |
|
- | 1756 | image_pagesize = 4 * 1024; // Intel processors use 4 Kb pages |
|
- | 1757 | } |
|
- | 1758 | else if (strcmp (value, "aarch64le") == 0) |
|
- | 1759 | { |
|
1762 |
|
1760 | image_processor = "aarch64le"; // save processor |
- | 1761 | image_processor_base = "aarch64"; // save processor base |
|
- | 1762 | image_pagesize = 16 * 1024; // ARM processors use 16 Kb pages |
|
- | 1763 | } |
|
- | 1764 | else |
|
- | 1765 | DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value); |
|
1763 | value = sep + 1; |
1766 | value = sep + 1; |
1764 | } |
1767 | } |
1765 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1768 | if (stat (bootfile_pathname, &stat_buf) != 0) |
1766 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1769 | DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
1767 | bootfile_size = stat_buf.st_size; // save preboot file size |
1770 | bootfile_size = stat_buf.st_size; // save preboot file size |
Line 1905... | Line 1908... | ||
1905 | else |
1908 | else |
1906 | { |
1909 | { |
1907 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1910 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
1908 | if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet |
1911 | if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet |
1909 | { |
1912 | { |
1910 | if (entry_parms.data.size == allocated_size) // reallocate in |
1913 | if (entry_parms.data.size == allocated_size) // reallocate in 16k blocks |
1911 | { |
1914 | { |
1912 | reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + |
1915 | reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 16384); |
1913 | ASSERT_WITH_ERRNO (reallocated_ptr); |
1916 | ASSERT_WITH_ERRNO (reallocated_ptr); |
1914 | entry_parms.data.bytes = reallocated_ptr; |
1917 | entry_parms.data.bytes = reallocated_ptr; |
1915 | allocated_size += |
1918 | allocated_size += 16384; |
1916 | } |
1919 | } |
1917 | entry_parms.data.bytes[entry_parms.data.size++] = read_char; |
1920 | entry_parms.data.bytes[entry_parms.data.size++] = read_char; |
1918 | } |
1921 | } |
1919 | if (read_char == '\n') |
1922 | if (read_char == '\n') |
1920 | lineno++; // update line counter as we parse the inline content |
1923 | lineno++; // update line counter as we parse the inline content |
Line 2392... | Line 2395... | ||
2392 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2395 | imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use |
2393 | 2396 | ||
2394 | // is it a bootable image with a startup file ? |
2397 | // is it a bootable image with a startup file ? |
2395 | if (startupfile_pathname != NULL) |
2398 | if (startupfile_pathname != NULL) |
2396 | { |
2399 | { |
- | 2400 | // compute the kernel offset: address of the first page that comes after the directory entries |
|
- | 2401 | kernelfile_offset = ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_pagesize); |
|
- | 2402 | ||
2397 | // write the filesystem entries that may fit before the kernel |
2403 | // write the filesystem entries that may fit before the kernel |
2398 | for (;;) |
2404 | for (;;) |
2399 | { |
2405 | { |
2400 | available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel |
2406 | available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel |
2401 | 2407 | ||
Line 2541... | Line 2547... | ||
2541 | if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
2547 | if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
2542 | { |
2548 | { |
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 |
2549 | // 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 |
2550 | 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)) |
2551 | 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 -= |
2552 | compressor_inlen -= image_pagesize; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with one page 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 |
2553 | 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 |
2554 | compressor_outlen = ucl_outlen; // cast back to size_t |
2549 | } |
2555 | } |
2550 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
2556 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
2551 | { |
2557 | { |
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. |
2558 | // 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 |
2559 | 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 |
2560 | 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)) |
2561 | 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 -= |
2562 | compressor_inlen -= image_pagesize; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with one page 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 |
2563 | 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 |
2564 | compressor_outlen = lzo_outlen; // cast back to size_t |
2559 | } |
2565 | } |
2560 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
2566 | else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
2561 | { |
2567 | { |
2562 | // Zlib (TODO) |
2568 | // Zlib (TODO) |
2563 | } |
2569 | } |
2564 | 2570 | ||
2565 | // the compression produced a block smaller than 65536 bytes |
2571 | // the compression produced a block smaller than 65536 bytes |
2566 | LOG_DEBUG |
2572 | //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) |
2573 | 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); |
2574 | 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 |
2575 | compressed_imagefs.size += 2 + (size_t) compressor_outlen; // advance in compression buffer by the compressed block size word plus the compressed block size |
2570 | 2576 | ||
2571 | remaining_len -= compressor_inlen; // see how many bytes remain to compress |
2577 | remaining_len -= compressor_inlen; // see how many bytes remain to compress |