From c9e5a6b91406fe0e1b8188c2818c5e2f7ad3e267 Mon Sep 17 00:00:00 2001 From: Andrew Robbins Date: Tue, 25 Dec 2018 21:41:27 -0500 Subject: Automate updating SeaGRUB floppy image blocklists Related issue #553 Determining the byte offset of core.img on the SeaGRUB floppy is accomplished using grub_bo(), though it is memory bound as it requires reading hex dumps for the pattern and comparand into memory. The blocklists that are stored in the boot record and core.img are sector numbers. Of particular note is the blocklist written to core.img is always the location of its *second* sector--not the first. Blocklists are used because floppy disks DO NOT have an MBR or MBR gap as the filesystem spans the entire disk. Consequently, the core.img cannot be stored in the usual ~1MiB gap. Unfortunately, using blocklists means they will have to be updated whenever core.img is moved. New functions added to grub-helper: * grub_bo * grub_bo_dump * grub_bo_search * grub_blocklist_format * grub_blocklist_generate * grub_floppy_image_make_bootable * grub_floppy_image_update_blocklists --- projects/grub/grub-helper | 96 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) (limited to 'projects') diff --git a/projects/grub/grub-helper b/projects/grub/grub-helper index 04814575..ccc9cd73 100755 --- a/projects/grub/grub-helper +++ b/projects/grub/grub-helper @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright (C) 2017 Andrew Robbins +# Copyright (C) 2017,2018 Andrew Robbins # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -62,6 +62,47 @@ grub_modmin_path() { project_file_path "$project" "$CONFIGS" "$MODMIN" "$@" } +grub_bo_search() { + local pattern="$1" + local comparand="$2" + + grep -Fbof <(grub_bo_dump "$pattern") <(grub_bo_dump "$comparand") | cut -d: -f1 +} + +grub_bo_dump() { + local file="$1" + + od -Anx -t x1 -w16 -v "$file" | paste -sd '' | tr -d ' ' +} + +grub_bo() { + local pattern="$1" + local comparand="$2" + + local nibble_offset="$(grub_bo_search "$pattern" "$comparand")" + + if [[ -n "$nibble_offset" ]]; then + printf '0x%X\n' $((nibble_offset / 2)) + else + return 1 + fi +} + +grub_blocklist_format() { + local blocklist="$1" + local byte + + while read -N 2 byte; do + printf '%s' "\\x$byte" + done <<< "$blocklist" +} + +grub_blocklist_generate() { + local -i byte_offset="$1" + + printf '%04x' $((byte_offset / 512)) | tac -rs .. +} + grub_copy_modules() { local grub_module_dir="$sources_path/grub-core" local keep_dir="$build_path/$(grub_format "$target" "$@")" @@ -179,6 +220,7 @@ grub_build_floppy_image() { grub_floppy_image_mmd "$floppyimg" /boot /boot/grub "/boot/grub/$format" grub_floppy_image_mcopy "$floppyimg" "/boot/grub/$format" "${modules[@]}" + grub_floppy_image_make_bootable "$floppyimg" } grub_build_standalone_image() { @@ -232,3 +274,55 @@ grub_floppy_image_mcopy() { mcopy -i "$img" -pQv "${files[@]}" "::$target" fi } + +grub_floppy_image_make_bootable() { + local floppyimg="$1" + local bootimg="$build_path/boot.img" + local coreimg="$build_path/core.img" + local oem_name='\x4C\x49\x42\x52\x45\x20\x20\x20' + + # write $floppyimg Bios Parameter Block to $bootimg first + dd if="$floppyimg" of="$bootimg" bs=1 skip=11 seek=11 count=52 conv=notrunc + dd if=<(printf "$oem_name") of="$bootimg" bs=1 seek=3 conv=notrunc + dd if=/dev/zero of="$floppyimg" count=1 conv=notrunc + dd if="$bootimg" of="$floppyimg" conv=notrunc + + grub_floppy_image_mcopy "$floppyimg" /boot/grub "$bootimg" + grub_floppy_image_mcopy "$floppyimg" /boot/grub "$coreimg" + + grub_floppy_image_update_blocklists "$coreimg" "$floppyimg" + rm -f "$bootimg" "$coreimg" +} + +grub_floppy_image_update_blocklists() { + local coreimg="$1" + local floppyimg="$2" + + local -i coreimg_offset="$(grub_bo "$coreimg" "$floppyimg")" + local -i coreimg_second_sector_offset=$((coreimg_offset + 0x200)) + + local -i boot_record_blocklist_offset=0x5C + local -i coreimg_blocklist_offset=$((coreimg_offset + 0x1F4)) + + # blocklists (little endian) describe the $coreimg_offset in sectors + local boot_record_blocklist="$(grub_blocklist_generate "$coreimg_offset")" + local coreimg_blocklist="$(grub_blocklist_generate "$coreimg_second_sector_offset")" + + if [[ $coreimg_offset -gt 0 ]]; then + dd if=<(printf "$(grub_blocklist_format "$boot_record_blocklist")") \ + of="$floppyimg" \ + bs=1 \ + seek="$boot_record_blocklist_offset" \ + conv=notrunc + + dd if=<(printf "$(grub_blocklist_format "$coreimg_blocklist")") \ + of="$floppyimg" \ + bs=1 \ + seek="$coreimg_blocklist_offset" \ + conv=notrunc + else + printf 1>&2 '%s\n' "Error: ${coreimg##*/} offset not found" + + return 1 + fi +} -- cgit v1.2.3-70-g09d2