#!/bin/sh # # This script creates a floppy image set from a linux bzImage and can merge # a cmdline and/or one or more initramfs. # The total size can not exceed 15M because INT 15H function 87H limitations. # # (C) 2009 Pascal Bellard - GNU General Public License v3. usage() { cat < /dev/null; } patch() { echo -en $(echo ":$2" | sed 's/:/\\x/g') | \ ddq bs=1 conv=notrunc of=$3 seek=$((0x$1)) [ -n "$DEBUG" ] && echo "patch $1 $2 $4" 1>&2 } # usage: store bits offset data file store() { n=$3; for i in $(seq 8 8 $1); do printf '\\\\x%02X' $(($n & 255)) n=$(($n >> 8)) done | xargs echo -en | ddq bs=1 conv=notrunc of=$4 seek=$(($2)) [ -n "$DEBUG" ] && printf "store%d(%03X) = %0$(($1/4))X %s\n" $1 $2 $3 "$5" 1>&2 } # usage: getlong offset file getlong() { ddq if=$2 bs=1 skip=$(($1)) count=4 | hexdump -e '"" 1/4 "%d" "\n"' } error() { echo $@ 1>&2 rm -f $bs exit 1 } floppyset() { # bzImage offsets SetupSzOfs=497 FlagsOfs=498 VideoModeOfs=506 RootDevOfs=508 Magic=0x202 RamfsAdrOfs=0x218 RamfsLenOfs=0x21C # boot+setup address SetupBase=0x90000 bs=/tmp/bs$$ # Get and patch boot sector # See http://hg.slitaz.org/wok/raw-file/66e38bd6a132/linux/stuff/linux-header.u [ -n "$DEBUG" ] && echo "Read bootsector..." 1>&2 ddq if=$KERNEL bs=512 count=1 of=$bs [ $(( $(getlong 0x1FE $bs) & 0xFFFF )) -eq 43605 ] || error "Not bootable" uudecode <&2 ddq if=$KERNEL bs=512 skip=1 count=$setupsz >> $bs Version=$(( $(getlong 0x206 $bs) & 0xFFFF )) [ $(getlong $Magic $bs) -ne 1400005704 ] && Version=0 feature="" while read prot kern info ; do [ $Version -lt $((0x$prot)) ] && continue feature="features $prot starting from kernel $kern " done <&2 # Old kernels need bootsector patches to disable rescent features while read minversion maxversion offset bytes rem; do [ $Version -gt $(( 0x$maxversion )) ] && continue [ $Version -lt $(( 0x$minversion )) ] && continue patch $offset $bytes $bs "$rem" done < /dev/null) store 16 $RootDevOfs $RDEV $bs RDEV # Info text after setup if [ -s "$INFOFILE" ]; then patch 048 9a:00:00:00:90 $bs lcall displayinfo uudecode >$bs.infotext <>$bs.infotext if [ $Version -lt 514 ]; then store 16 0x050 0x0022 $bs.infotext fi ddq if=/dev/zero bs=512 count=1 >>$bs.infotext n=$(($(stat -c %s $bs.infotext)/512)) ddq if=$bs.infotext count=$n bs=512 >> $bs rm -f $bs.infotext store 8 0x1F1 $(($setupsz+$n)) $bs update setup size store 8 0x04A $((2+2*$setupsz)) $bs update displayinfo call fi # Store cmdline after setup if [ -n "$CMDLINE" ]; then echo -n "$CMDLINE" | ddq bs=512 count=1 conv=sync >> $bs CmdlineOfs=0x9E00 # Should be in 0x8000 .. 0xA000 ArgPtrOfs=0x228 ArgPtrVal=$(( $SetupBase + $CmdlineOfs )) if [ $Version -lt 514 ]; then ArgPtrOfs=0x0020 ArgPtrVal=$(( 0xA33F + ($CmdlineOfs << 16) )) fi store 32 $ArgPtrOfs $ArgPtrVal $bs "Cmdline '$CMDLINE'" fi # Compute initramfs size (protocol >= 2.00) [ $Version -lt 512 ] && INITRD="" initrdlen=0 INITRDPAD=4 INITRDALIGN=0x1000 for i in $( echo $INITRD | sed 's/,/ /' ); do [ -s "$i" ] || continue while [ -L "$i" ]; do i="$(readlink $i)"; done size=$(( ($(stat -c %s "$i") + $INITRDPAD - 1) & -$INITRDPAD )) [ -n "$DEBUG" ] && echo "initrd $i $size " 1>&2 initrdlen=$(( $initrdlen + $size )) [ -n "$ADRSRD" ] || ADRSRD=$(( (($MEM * 0x100000) - $initrdlen) & -$INITRDALIGN )) store 32 $RamfsAdrOfs $(( $ADRSRD )) $bs initrd adrs store 32 $RamfsLenOfs $initrdlen $bs initrdlen done [ -n "$NOSYSSIZEFIX" ] || store 32 0x1F4 \ $(( ($(stat -c %s $KERNEL)+15)/16 - ($setupsz+1)*32)) $bs fix system size # Output boot sector + setup + cmdline ddq if=$bs # Output kernel code syssz=$(( ($(getlong 0x1F4 $bs)+31)/32 )) cat $KERNEL /dev/zero | ddq bs=512 skip=$(( $setupsz+1 )) count=$syssz conv=sync # Output initramfs for i in $( echo $INITRD | sed 's/,/ /' ); do [ -s "$i" ] || continue ddq if=$i padding=$(( $INITRDPAD - ($(stat -c %s $i) % $INITRDPAD) )) [ $padding -eq $INITRDPAD ] || ddq if=/dev/zero bs=1 count=$padding done # Cleanup rm -f $bs } if [ "$FORMAT" == "0" ]; then # unsplitted floppyset > $PREFIX PAD=$(( 512 - ($(stat -c %s $PREFIX) % 512) )) [ $PAD -ne 512 ] && ddq if=/dev/zero bs=1 count=$PAD >> $PREFIX exit fi floppyset | split -b ${FORMAT}k /dev/stdin floppy$$ i=1 ls floppy$$* 2> /dev/null | while read file ; do output=$PREFIX$(printf "%03d" $i) cat $file /dev/zero | ddq bs=1k count=$FORMAT conv=sync of=$output echo $output rm -f $file i=$(( $i + 1 )) done