diff --git a/.gitignore b/.gitignore index c65b28e..357a912 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ /build/check_makefile /build/check_makefile_targets /build/check_makefile_w_arnings +/build/gpt_guid1 +/build/gpt_guid2 /build/iso_files/boot/iso_boot.sys /build/iso_files/os.zip /build/makefile_built_directories @@ -85,6 +87,11 @@ /build/os.offsets.hex /build/os.reasm /build/os.reasm.asm +/build/os_with_guid_0 +/build/os_with_guid_hash +/build/os_with_guid_hash.fixed_gpt_crc +/build/os_with_guid_hash.gpt_header_fixed_crc +/build/os_with_guid_hash.partition_array /build/os.zip /build/os.zip.adjusted /build/test_pass/emu_bochs diff --git a/Makefile.example-os b/Makefile.example-os index da255b5..5f29008 100644 --- a/Makefile.example-os +++ b/Makefile.example-os @@ -1,6 +1,7 @@ offset_names = bytes_os_size \ bytes_mbr_start \ bytes_mbr_end \ + bytes_gpt_header_start \ bytes_header_32k_start \ bytes_header_32k_end \ bytes_iso_start \ @@ -9,6 +10,7 @@ offset_names = bytes_os_size \ bytes_fat12_end \ bytes_gpt_mirror_start \ bytes_gpt_mirror_end \ + bytes_gpt_header_mirror_start \ bytes_zip_start \ bytes_zip_end @@ -51,6 +53,13 @@ built_files += ${os_filename} \ ${bld}/os.hex_with_offsets \ ${bld}/iso_files/os.zip \ ${bld}/iso_files/boot/iso_boot.sys \ + ${bld}/gpt_guid1 \ + ${bld}/gpt_guid2 \ + ${bld}/os_with_guid_0 \ + ${bld}/os_with_guid_hash \ + ${bld}/os_with_guid_hash.partition_array \ + ${bld}/os_with_guid_hash.gpt_header_fixed_crc \ + ${bld}/os_with_guid_hash.fixed_gpt_crc \ ${more_offset_dec} \ ${more_offset_hex} \ @@ -141,6 +150,9 @@ ${eval ${call offset,bytes_os_size, $${os_image_size_kb} * 1024,, ${eval ${call offset,sectors_os_size, $${bytes_os_size} / $${sector_size}, bytes_os_size,}} ${eval ${call offset,tracks_os_size, $${sectors_os_size} / $${os_floppy_chs_s}, sectors_os_size,}} +# Primary GPT +${eval ${call offset,bytes_gpt_header_start, $${sector_size},, }} + # round up ${eval ${call offset,bytes_iso_size, $$$$(utils/file-length.sh -c ${bld}/os.iso), ,${bld}/os.iso}} ${eval ${call offset,sectors_iso_size, ${call div_round_up,$${bytes_iso_size},$${sector_size}}, bytes_iso_size,}} @@ -176,6 +188,7 @@ ${eval ${call offset,bytes_fat12_end, $${bytes_fat12_start} + $${bytes_fa # It is probably not necessary to align the GPT mirror end on a track boundary. ${eval ${call offset,bytes_gpt_mirror_size, $${sectors_gpt_mirror_size} * $${sector_size}, sectors_gpt_mirror_size,}} ${eval ${call offset,bytes_gpt_mirror_end, $${bytes_fat12_end} + $${bytes_gpt_mirror_size}, bytes_fat12_end bytes_gpt_mirror_size,}} +${eval ${call offset,bytes_gpt_header_mirror_start, $${bytes_gpt_mirror_end} - $${sector_size}, bytes_gpt_mirror_end,}} ${eval ${call offset,bytes_gpt_mirror_start, $${bytes_gpt_mirror_end} - $${bytes_gpt_mirror_size}, bytes_gpt_mirror_end bytes_gpt_mirror_size,}} ${eval ${call offset,bytes_zip_end, $${bytes_os_size}, bytes_os_size,}} @@ -221,22 +234,27 @@ ${bld}/os.zip.adjusted: ${bld}/os.zip ${dep_bytes_zip_start} ${bld}/check_makefi gdisk_pipe_commands_slowly=while read str; do echo "$$str"; printf "\033[1;33m%s\033[m\n" "$$str" >&2; sleep 0.01; done -commit_hash_as_guid=$$((git log -1 --pretty=format:%H || echo 0000000000000000000000000000000000000000) | sed -e 's/^\(.\{8\}\)\(.\{4\}\)\(.\{4\}\)\(.\{4\}\)\(.\{12\}\).*$$/\1-\2-\3-\4-\5/' | tr '[:lower:]' '[:upper:]') -git_dirty=test -n "$$(git diff --shortstat)" -gpt_disk_guid=${commit_hash_as_guid}$$(if $$git_dirty; then printf '0'; else printf '2'; fi) -gpt_partition_guid=${commit_hash_as_guid}$$(if $$git_dirty; then printf '1'; else printf '3'; fi) +# The last digit of guid1 is 1, for guid2 it's 2, and so on. +# This allows us to have a disk GUID which is different from the partition GUID +${bld}/gpt_guid%: ${bld}/os_with_guid_0 ${bld}/check_makefile + sha256sum $< \ + | sed -e 's/^\(.\{8\}\)\(.\{4\}\)\(.\{4\}\)\(.\{4\}\)\(.\{11\}\).*$$/\1-\2-\3-\4-\5$*/' \ + | tr '[:lower:]' '[:upper:]' \ + > $@ -${os_filename}: ${bld}/os.32k ${bld}/os.iso ${bld}/os.fat12 ${bld}/os.zip.adjusted \ - ${dep_bytes_header_32k_start} \ - ${dep_bytes_header_32k_size} \ - ${dep_bytes_fat12_start} \ - ${dep_bytes_fat12_size} \ - ${dep_bytes_gpt_mirror_start} \ - ${dep_bytes_gpt_mirror_end} \ - ${dep_sectors_fat12_start} \ - ${dep_sectors_fat12_size} \ - ${dep_bytes_zip_start} \ - ${bld}/check_makefile +gpt_disk_guid=${bld}/gpt_guid1 +gpt_partition_guid=${bld}/gpt_guid2 + +${bld}/os_with_guid_0: ${bld}/os.32k ${bld}/os.iso ${bld}/os.fat12 \ + ${dep_bytes_header_32k_start} \ + ${dep_bytes_header_32k_size} \ + ${dep_bytes_fat12_start} \ + ${dep_bytes_fat12_size} \ + ${dep_bytes_gpt_mirror_start} \ + ${dep_bytes_gpt_mirror_end} \ + ${dep_sectors_fat12_start} \ + ${dep_sectors_fat12_size} \ + ${bld}/check_makefile rm -f $@ # start with the .iso cp ${bld}/os.iso $@ @@ -266,8 +284,23 @@ ${os_filename}: ${bld}/os.32k ${bld}/os.iso ${bld}/os.fat12 ${bld}/os.zip.adjust printf "1\nN\n"; \ printf "01\nY\nN\n"; \ printf "x\n"; \ - printf "g\n${gpt_disk_guid}\n"; \ - printf "c\n${gpt_partition_guid}\n"; \ + printf "g\n00000000-0000-0000-0000-000000000000\n"; \ + printf "c\n00000000-0000-0000-0000-000000000000\n"; \ + printf "p\no\nw\nY\n") | ${gdisk_pipe_commands_slowly} | gdisk $@ + +${bld}/os_with_guid_hash: ${bld}/os_with_guid_0 \ + ${gpt_disk_guid} ${gpt_partition_guid} \ + ${bld}/check_makefile + cp $< $@ +# gdisk commands: +# * eXpert mode, +# * Change partition GUID, the GUID itself, +# * change disk GUID, the GUID itself, +# * Print GPT, print prOtective MBR, Write, Proceed. + (if test "$$(uname -o)" = "Cygwin"; then printf "Y\n"; fi; \ + printf "x\n"; \ + printf "g\n$$(cat ${gpt_disk_guid})\n"; \ + printf "c\n$$(cat ${gpt_partition_guid})\n"; \ printf "p\no\nw\nY\n") | ${gdisk_pipe_commands_slowly} | gdisk $@ # Inject MS-DOS newlines (CR+LF) and comments (":: ") in the GUID field of unused partition table entries, # so that the part that is to be skipped by MS-DOS does not form a line longer than the MS-DOS maximum @@ -277,6 +310,49 @@ ${os_filename}: ${bld}/os.32k ${bld}/os.iso ${bld}/os.fat12 ${bld}/os.zip.adjust printf "\r\n:: %02x" $$i | dd bs=1 seek=$$(( 1024 + ( ($$i) - 1) * 128 + 16)) count=7 conv=notrunc of=$@; \ printf "\r\n:: %02x" $$i | dd bs=1 seek=$$(( ${bytes_gpt_mirror_start} + ( ($$i) - 1) * 128 + 16)) count=7 conv=notrunc of=$@; \ done + +%.partition_array: % ${bld}/check_makefile +# Extract the partition array header + dd if=$< bs=512 skip=2 count=32 of=$@ + +# The GPT header of the given disk image, with its CRC adjusted to the actual +# data. It is used to fix the CRC after injecting MS-DOS comments in ignored +# parts of the partition array. +%.gpt_header_fixed_crc: % %.partition_array % ${bld}/check_makefile +# Extract the GPT header + dd if=$< bs=512 skip=1 count=1 of=$@ +# * Compute the CRC32 of the particion array +# * Convert endianness +# * Convert to binary +# * Inject into the GPT header + crc32 $*.partition_array \ + | sed -e 's/^\(..\)\(..\)\(..\)\(..\)$$/\4\3\2\1/' \ + | xxd -r -ps \ + | dd bs=1 seek=88 count=4 conv=notrunc of=$@ +# Zero-out the CRC of the header itself + printf '00000000' | xxd -r -ps | dd bs=1 seek=16 count=4 conv=notrunc of=$@ +# * Compute the CRC32 of the GPT header (with the CRC field itself zeroed out) +# * Convert endianness +# * Convert to binary +# * Inject into the GPT header + crc32 $@ \ + | sed -e 's/^\(..\)\(..\)\(..\)\(..\)$$/\4\3\2\1/' \ + | xxd -r -ps \ + | dd bs=1 seek=16 count=4 conv=notrunc of=$@ + +%.fixed_gpt_crc: % %.gpt_header_fixed_crc \ + ${dep_bytes_gpt_header_start} ${dep_bytes_gpt_header_mirror_start} \ + ${bld}/check_makefile + cp $< $@ +# Inject the fixed GPT header + dd if=$*.gpt_header_fixed_crc bs=1 seek=${bytes_gpt_header_start} count=${sector_size} conv=notrunc of=$@ +# Inject the fixed GPT header in the mirror + dd if=$*.gpt_header_fixed_crc bs=1 seek=${bytes_gpt_header_mirror_start} count=${sector_size} conv=notrunc of=$@ + +${os_filename}: ${bld}/os_with_guid_hash.fixed_gpt_crc ${bld}/os.zip.adjusted \ + ${dep_bytes_zip_start} \ + ${bld}/check_makefile + cp -f $< $@ # splice in zip at the end set -x; dd skip=${bytes_zip_start} seek=${bytes_zip_start} bs=1 conv=notrunc if=${bld}/os.zip.adjusted of=$@ chmod a+x-w $@ diff --git a/guix.scm b/guix.scm index 898b5de..0625496 100644 --- a/guix.scm +++ b/guix.scm @@ -31,7 +31,9 @@ (gnu packages cdrom) (gnu packages compression) (gnu packages disk) - (gnu packages linux)) + (gnu packages vim) + (gnu packages linux) + (gnu packages perl)) ;; For faketime (use-modules (guix git-download)) @@ -106,7 +108,10 @@ ("zip" ,zip) ("faketime" ,faketime) ("gdisk" ,gptfdisk) - ("column" ,util-linux))) + ("xxd" ,xxd) + ("column" ,util-linux) + ;; perl is needed as an extra dependency to get crc32 to work. + ("perl" ,perl) ("crc32" ,perl-archive-zip))) (description "Test framework to run an OS in multiple emulators, as a guest graphical / text shell on linux, and so on.") (home-page "https://github.com/jsmaniac/os-test-framework") (license "CC0-1.0")