os-test-framework/Makefile.example-os

309 lines
15 KiB
Makefile
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

offset_names = bytes_os_size \
bytes_mbr_start \
bytes_mbr_end \
bytes_header_32k_start \
bytes_header_32k_end \
bytes_iso_start \
bytes_iso_end \
bytes_fat12_start \
bytes_fat12_end \
bytes_gpt_mirror_start \
bytes_gpt_mirror_end \
bytes_zip_start \
bytes_zip_end
more_offset_names = ${offset_names} \
bytes_fat12_size \
bytes_gpt_mirror_size \
bytes_header_32k_size \
bytes_iso_size \
bytes_zip_size \
sectors_fat12_size \
sectors_fat12_start \
sectors_gpt_mirror_size \
sectors_iso_size \
sectors_os_size \
sectors_zip_size \
tracks_fat12_size \
tracks_gpt_mirror_size \
tracks_iso_size \
tracks_os_size \
tracks_zip_size
more_offset_dec = ${more_offset_names:%=${bld}/offsets/%.dec}
more_offset_hex = ${more_offset_names:%=${bld}/offsets/%.hex}
# + os.arm.disasm
# + os.reasm.disasm
built_files += ${os_filename} \
${bld}/os.ndisasm.disasm \
${bld}/os.reasm.asm \
${bld}/os.reasm \
${bld}/os.file \
${bld}/os.gdisk \
${bld}/os.zip \
${bld}/os.zip.adjusted \
${bld}/os.iso \
${bld}/os.32k \
${bld}/os.fat12 \
${bld}/os.offsets.hex \
${bld}/os.offsets.dec \
${bld}/os.hex_with_offsets \
${bld}/iso_files/os.zip \
${bld}/iso_files/boot/iso_boot.sys \
${more_offset_dec} \
${more_offset_hex} \
# Temporary copies used to adjust timestamps for reproducible builds.
# These are normally created and deleted within a single target, but
# could remain if make is interrupted during the build.
temp_files = ${bld}/iso_files.tmp/os.zip \
${bld}/iso_files.tmp/boot/iso_boot.sys
temp_directories = ${bld}/iso_files.tmp \
${bld}/iso_files.tmp/boot/
built_directories += ${bld}/iso_files/boot \
${bld}/iso_files \
${bld}/offsets
os_image_size_kb = 1440
os_partition_start_sectors = 3
os_partition_size_sectors = 717 # 720 - start
# CHS parameters for 1.44 MB floppy disk
os_floppy_chs_h = 2
os_floppy_chs_s = 9
all: ${os_filename} \
${bld}/os.ndisasm.disasm \
${bld}/os.reasm.asm \
${bld}/os.file \
${bld}/os.gdisk \
${bld}/os.offsets.hex \
${bld}/os.offsets.dec \
${bld}/os.hex_with_offsets \
${more_offset_dec} \
${more_offset_hex} \
${bld}/check_makefile
# 32k header of the ISO9660 image
${bld}/os.32k: example-os/os.asm ${bld}/check_makefile
nasm -w+macro-params -w+macro-selfref -w+orphan-labels -w+gnu-elf-extensions -o $@ $<
# Circumvent the fact that faketime does not work on system binaries in macos
./utils/mkisofs ./utils/mformat ./utils/mcopy: ${bld}/check_makefile # TODO: depend on the mkisofs binary
cp $$(which $$(basename $@)) $@
chmod u+x $@
cp_T_option = $$(if test "$$(uname -s)" = Darwin; then echo ''; else echo '-T'; fi)
${bld}/os.iso: ${bld}/iso_files/os.zip ${bld}/iso_files/boot/iso_boot.sys ./utils/mkisofs ${bld}/check_makefile
! test -d ${bld}/iso_files.tmp
cp -a ${cp_T_option} -- ${bld}/iso_files ${bld}/iso_files.tmp
find ${bld}/iso_files.tmp -depth -exec touch -t ${commit_timestamp} '{}' ';'
UTILS="$$PWD/utils" ./utils/faketime.sh ${commit_timestamp_iso_8601} sh -c '(cd ./${bld}/iso_files.tmp/ && "$$UTILS/mkisofs" \
--input-charset utf-8 \
-rock \
-joliet \
-eltorito-catalog boot/boot.cat \
-eltorito-boot boot/iso_boot.sys \
-no-emul-boot \
-boot-load-size 4 \
-pad \
-output ../os.iso \
.)'
rm -- ${bld}/iso_files.tmp/os.zip \
${bld}/iso_files.tmp/boot/iso_boot.sys
rmdir ${bld}/iso_files.tmp/boot/
rmdir ${bld}/iso_files.tmp/
# Layout:
# MBR; GPT; UNIX sh & MS-DOS batch scripts; ISO9660; FAT12; GPT mirror; ZIP
define offset
tmp_${1} = ${3}
${bld}/offsets/${1}.dec: $${tmp_${1}:%=${bld}/offsets/%.dec} ${4} ${bld}/check_makefile
echo $$$$(( ${2} )) | tee $$@
${1} = $$$$(cat ${bld}/offsets/${1}.dec)
dep_${1} = ${bld}/offsets/${1}.dec
endef
define div_round_up
( ( ( ${1} ) + ( ${2} ) - 1 ) / ( ${2} ) )
endef
sector_size = 512
# should be exact (TODO: make a check)
${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,}}
# 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,}}
${eval ${call offset,tracks_iso_size, ${call div_round_up,$${sectors_iso_size},$${os_floppy_chs_s}}, sectors_iso_size,}}
# round up
${eval ${call offset,bytes_zip_size, $$$$(utils/file-length.sh -c ${bld}/os.zip), ,${bld}/os.zip}}
${eval ${call offset,sectors_zip_size, ${call div_round_up,$${bytes_zip_size},$${sector_size}}, bytes_zip_size,}}
${eval ${call offset,tracks_zip_size, ${call div_round_up,$${sectors_zip_size},$${os_floppy_chs_s}}, sectors_zip_size,}}
# round up
${eval ${call offset,sectors_gpt_mirror_size, 33,, }}
${eval ${call offset,tracks_gpt_mirror_size, ${call div_round_up,$${sectors_gpt_mirror_size},$${os_floppy_chs_s}}, sectors_gpt_mirror_size,}}
# allocate the remaining sectors to the FAT, aligned on tracks
${eval ${call offset,tracks_fat12_size, $${tracks_os_size} - $${tracks_iso_size} - $${tracks_gpt_mirror_size} - $${tracks_zip_size}, tracks_os_size tracks_iso_size tracks_gpt_mirror_size tracks_zip_size,}}
${eval ${call offset,sectors_fat12_size,$${tracks_fat12_size} * $${os_floppy_chs_s}, tracks_fat12_size,}}
# zip should probably have its end aligned, not its start
${eval ${call offset,bytes_zip_start, $${bytes_os_size} - $${bytes_zip_size}, bytes_os_size bytes_zip_size,}}
${eval ${call offset,bytes_mbr_start, 0,,}}
${eval ${call offset,bytes_mbr_end, 512,,}}
${eval ${call offset,bytes_header_32k_start, 0,,}}
${eval ${call offset,bytes_header_32k_end, 32 * 1024,,}}
${eval ${call offset,bytes_header_32k_size, $${bytes_header_32k_end} - $${bytes_header_32k_start}, bytes_header_32k_end bytes_header_32k_start,}}
${eval ${call offset,bytes_iso_start, 32 * 1024,,}}
${eval ${call offset,bytes_iso_end, $${sectors_iso_size} * $${sector_size}, sectors_iso_size,}}
${eval ${call offset,bytes_fat12_start, $${tracks_iso_size} * $${os_floppy_chs_s} * $${sector_size}, tracks_iso_size,}}
${eval ${call offset,sectors_fat12_start, $${bytes_fat12_start} / $${sector_size}, bytes_fat12_start,}}
${eval ${call offset,bytes_fat12_size, $${sectors_fat12_size} * $${sector_size}, sectors_fat12_size,}}
${eval ${call offset,bytes_fat12_end, $${bytes_fat12_start} + $${bytes_fat12_size}, bytes_fat12_start bytes_fat12_size,}}
# 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_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,}}
os_fat12_partition = "$@@@${bytes_fat12_start}"
${bld}/os.fat12: ${bld}/os.zip ${dep_bytes_fat12_size} ${dep_bytes_fat12_start} ${dep_sectors_os_size} \
./utils/mformat ./utils/mcopy ${bld}/check_makefile
set -x; dd if=/dev/zero bs=${sector_size} count=${sectors_os_size} of=$@
./utils/faketime.sh ${commit_timestamp_iso_8601} ./utils/mformat -v "Example OS" \
-T ${sectors_fat12_size} \
-h ${os_floppy_chs_h} \
-s ${os_floppy_chs_s} \
-i ${os_fat12_partition}
./utils/faketime.sh ${commit_timestamp_iso_8601} ./utils/mcopy -i ${os_fat12_partition} $< "::os.zip"
${bld}/iso_files/os.zip: ${bld}/os.zip ${bld}/check_makefile
# TODO: make it so that the various file formats are mutual quines:
# * the ISO should contain the original file
# * the ZIP should contain the original file
# * the FAT12 should contain the original file
cp $< $@
# 4 sectors loaded when booting from optical media (CD-ROM, …):
${bld}/iso_files/boot/iso_boot.sys: ${bld}/os.32k ${bld}/check_makefile
# TODO: this copy of the (or alternate) bootsector should contain a Boot Information Table,
# see https://wiki.osdev.org/El-Torito#A_BareBones_Boot_Image_with_Boot_Information_Table
dd if=$< bs=512 count=4 of=$@
${bld}/os.zip: ${bld}/os.32k ${bld}/check_makefile
# We copy os.32k and alter its timestamp to ensure reproducible
# builds.
mkdir -p ${bld}/os.32k.tmp
cp -a $< ${bld}/os.32k.tmp/os.32k
touch -t ${commit_timestamp} ${bld}/os.32k.tmp/os.32k
(cd ${bld}/os.32k.tmp/ && zip -X ../os.zip os.32k)
rm ${bld}/os.32k.tmp/os.32k
rmdir ${bld}/os.32k.tmp
${bld}/os.zip.adjusted: ${bld}/os.zip ${dep_bytes_zip_start} ${bld}/check_makefile
# TODO: the ZIP file can end with a variable-length comment, this would allow us to hide the GPT mirrors.
set -x; dd if=/dev/zero bs=1 count=${bytes_zip_start} of=$@
cat $< >> $@
zip --adjust-sfx $@
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 | 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)
${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
rm -f $@
# start with the .iso
cp ${bld}/os.iso $@
# splice in the first 32k (bootsector and partition table)
set -x; dd skip=${bytes_header_32k_start} seek=${bytes_header_32k_start} bs=1 count=${bytes_header_32k_size} conv=notrunc if=${bld}/os.32k of=$@
# splice in fat12
set -x; dd skip=${bytes_fat12_start} seek=${bytes_fat12_start} bs=1 count=${bytes_fat12_size} conv=notrunc if=${bld}/os.fat12 of=$@
# pad with zeroes to prepare for GPT table
set -x; dd if=/dev/zero seek=$$((${bytes_gpt_mirror_end} - 1 )) bs=1 count=1 conv=notrunc of=$@
# patch the partition table
# Thanks to https://wiki.gentoo.org/wiki/Hybrid_partition_table for showing that gdisk can be used to make a hybrid MBR / GPT.
# gdisk commands:
# * Delete (the only) partition, eXpert mode, sector aLignment = 1, back to Main menu,
# * New partition (number = 1, start sector, end sector, type 0700)
# * Recovery and transformation options, make Hybrid,
# * add GPT partition #1 to the hybrid MBR, do Not put the EFI partition first,
# * MBR partition type=0x01, bootable=Yes, do Not add extra partitions,
# * back to Main menu,
# * 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 "d\nx\nl\n1\nm\n"; \
printf "n\n1\n${sectors_fat12_start}\n${sectors_fat12_size}\n0700\n"; \
printf "r\nh\n"; \
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 "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
# line length (8192 excluding CR+LF). $i below is the partition entry number, starting from 1
# The numbers 55 and 118 are arbitrarily chosen so that the space between two CR+LF is less than 8192.
for i in 55 118; do \
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
# 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 $@
${bld}/os.file: ${os_filename} ${bld}/check_makefile
file -kr $< > $@
${bld}/os.gdisk: ${os_filename} ${bld}/check_makefile
# gdisk commands:
# * eXpert mode
# * Print partition table
#  * print detailed Information about the (only) partition
# * print prOtective MBR table
# * Quit
printf '2\nx\np\ni\nr\no\nq\n' | ${gdisk_pipe_commands_slowly} | gdisk $< | tee $@
${bld}/os.offsets.hex: ${offset_names:%=${bld}/offsets/%.hex} ${bld}/check_makefile
grep '^' ${offset_names:%=${bld}/offsets/%.hex} | sed -e 's|^.*/||' -e 's/:/: 0x/' | column -t > $@
${bld}/os.offsets.dec: ${offset_names:%=${bld}/offsets/%.dec} ${bld}/check_makefile
grep '^' ${offset_names:%=${bld}/offsets/%.dec} | sed -e 's|^.*/||' -e 's/:/: /' | column -t > $@
${bld}/offsets/%.hex: ${bld}/offsets/%.dec
printf '%x\n' $$(cat $<) > $@
${bld}/os.hex_with_offsets: ${os_filename} ${bld}/os.offsets.hex
hexdump -C $< \
| grep -E -e "($$(cat ${bld}/os.offsets.hex | cut -d '=' -f 2 | sed -e 's/^[[:space:]]*0x\(.*\).$$/^\10/' | tr '\n' '|')^)" --color=yes > $@
${bld}/os.ndisasm.disasm: ${os_filename} utils/compact-ndisasm.sh ${bld}/check_makefile
./utils/compact-ndisasm.sh $< $@
${bld}/os.reasm.asm: ${bld}/os.ndisasm.disasm ${bld}/check_makefile
sed -e 's/^[^ ]\+ \+[^ ]\+ \+//' $< > $@