wok-undigest diff linux/stuff/bootloader.sh @ rev 1257
recook binutils
author | Hans-Günter Theisgen |
---|---|
date | Sat Aug 13 10:55:58 2022 +0100 (2022-08-13) |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/linux/stuff/bootloader.sh Sat Aug 13 10:55:58 2022 +0100 1.3 @@ -0,0 +1,299 @@ 1.4 +#!/bin/sh 1.5 +# 1.6 +# This script creates a floppy image set from a linux bzImage and can merge 1.7 +# a cmdline and/or one or more initramfs. 1.8 +# The total size can not exceed 15M because INT 15H function 87H limitations. 1.9 +# 1.10 +# (C) 2009 Pascal Bellard - GNU General Public License v3. 1.11 + 1.12 +usage() 1.13 +{ 1.14 +cat <<EOT 1.15 +Usage: $0 bzImage [--prefix image_prefix] [--info file ] 1.16 + [--format 1200|1440|1680|1920|2880|... ] [--mem mb] 1.17 + [--rdev device] [--video mode] [--flags rootflags] [--tracks cnt] 1.18 + [--cmdline 'args'] [--dont-edit-cmdline] [--no-syssize-fix] 1.19 + [--address-initrd address] [--initrd initrdfile]... 1.20 + 1.21 +Default values: --format 1440 --tracks 80 --rdev /dev/fd0 --prefix floppy. --mem 16 1.22 + 1.23 +Example: 1.24 +$0 /boot/bzImage --rdev /dev/ram0 --video -3 --cmdline 'rw lang=fr_FR kmap=fr-latin1 laptop autologin' --initrd /boot/rootfs.gz --initrd ./myconfig.gz 1.25 +EOT 1.26 +exit 1 1.27 +} 1.28 + 1.29 +KERNEL="" 1.30 +INITRD="" 1.31 +ADRSRD="" 1.32 +CMDLINE="" 1.33 +PREFIX="floppy." 1.34 +FORMAT="1440" 1.35 +RDEV="" 1.36 +VIDEO="" 1.37 +FLAGS="" 1.38 +TRACKS="80" 1.39 +MEM="16" 1.40 +NOEDIT="" 1.41 +NOSYSSIZEFIX="" 1.42 +INFOFILE="" 1.43 +DEBUG="" 1.44 +while [ -n "$1" ]; do 1.45 + case "${1/--/-}" in 1.46 + -c*) CMDLINE="$2"; shift;; 1.47 + -inf*) INFOFILE="$2"; shift;; 1.48 + -i*) INITRD="$INITRD $2"; shift;; 1.49 + -a*) ADRSRD="$2"; shift;; 1.50 + -h*) HEAP="$2"; shift;; 1.51 + -l*) LOADERTYPE="$2"; shift;; 1.52 + -p*) PREFIX="$2"; shift;; 1.53 + -fl*)FLAGS="$2"; shift;; # 1 read-only, 0 read-write 1.54 + -f*) FORMAT="$2"; shift;; 1.55 + -m*) MEM="$(echo $2 | sed 's/[^0-9]//g')"; shift;; 1.56 + -r*) RDEV="$2"; shift;; 1.57 + -v*) VIDEO="$2"; shift;; # -3 .. n 1.58 + -t*) TRACKS="$2"; shift;; # likely 81 .. 84 1.59 + -n*) NOSYSSIZEFIX="1";; 1.60 + -debug) DEBUG="1";; 1.61 + -d*) NOEDIT="1";; 1.62 + *) KERNEL="$1";; 1.63 + esac 1.64 + shift 1.65 +done 1.66 +[ -n "$KERNEL" -a -f "$KERNEL" ] || usage 1.67 +while [ -L "$KERNEL" ]; do KERNEL="$(readlink "$KERNEL")"; done 1.68 +if [ $(( $FORMAT % $TRACKS )) -ne 0 ]; then 1.69 + echo "Invalid track count for format $FORMAT." 1.70 + usage 1.71 +fi 1.72 +[ 0$MEM -lt 4 ] && MEM=4 1.73 +[ $MEM -gt 16 ] && MEM=16 1.74 + 1.75 +ddq() { dd $@ 2> /dev/null; } 1.76 + 1.77 +patch() 1.78 +{ 1.79 + echo -en $(echo ":$2" | sed 's/:/\\x/g') | \ 1.80 + ddq bs=1 conv=notrunc of=$3 seek=$((0x$1)) 1.81 + [ -n "$DEBUG" ] && echo "patch $1 $2 $4" 1>&2 1.82 +} 1.83 + 1.84 +# usage: store bits offset data file 1.85 +store() 1.86 +{ 1.87 + n=$3; for i in $(seq 8 8 $1); do 1.88 + printf '\\\\x%02X' $(($n & 255)) 1.89 + n=$(($n >> 8)) 1.90 + done | xargs echo -en | ddq bs=1 conv=notrunc of=$4 seek=$(($2)) 1.91 + [ -n "$DEBUG" ] && printf "store%d(%03X) = %0$(($1/4))X %s\n" $1 $2 $3 "$5" 1>&2 1.92 +} 1.93 + 1.94 +# usage: getlong offset file [bytes] 1.95 +getlong() 1.96 +{ 1.97 + echo $(od -j $1 -N ${3:-4} -t u${3:-4} -An $2) 1.98 +} 1.99 + 1.100 +error() 1.101 +{ 1.102 + echo $@ 1>&2 1.103 + rm -f $bs 1.104 + exit 1 1.105 +} 1.106 + 1.107 +floppyset() 1.108 +{ 1.109 + # bzImage offsets 1.110 + SetupSzOfs=497 1.111 + FlagsOfs=498 1.112 + VideoModeOfs=506 1.113 + RootDevOfs=508 1.114 + Magic=0x202 1.115 + RamfsAdrOfs=0x218 1.116 + RamfsLenOfs=0x21C 1.117 + 1.118 + # boot+setup address 1.119 + SetupBase=0x90000 1.120 + 1.121 + bs=/tmp/bs$$ 1.122 + 1.123 + # Get and patch boot sector 1.124 + # See http://hg.slitaz.org/wok/raw-file/66e38bd6a132/linux/stuff/linux-header.u 1.125 + [ -n "$DEBUG" ] && echo "Read bootsector..." 1>&2 1.126 + ddq if=$KERNEL bs=512 count=1 of=$bs 1.127 + 1.128 + [ $(getlong 0x1FE $bs 2) -eq 43605 ] || error "Not bootable" 1.129 + 1.130 + uudecode <<EOT | ddq of=$bs conv=notrunc 1.131 +begin-base64 644 - 1.132 +/L+4nWgAkBeJ/BYHMcC5HgDzq1sfD6Gg8X1AxXd4BlexBvOlFh9kZo9HeMZF 1.133 ++D/6l1hB6DwBvgACgUwQIIDGRCWbA3QO6GoBWwseKAJ0LFNH6AYBXuhaAbAg 1.134 +zRCwCM0QTuhZATwIdAOIBK05NigCdPDoMgE8CnXgiHz+W4nm/0gQxkAVk4Dz 1.135 +CHX0u/QBoRUCsQVmix9mS2bT60NoAAgHv4AAiXwTiUQbAfjR7yn7nHMCAd9Q 1.136 +V1ZTMdvongBbXlmGzbSHFgfNFVidd9ChGQK7HAKxCTlEG3K6l80T6gAAIJCw 1.137 +RijIvtgB6MoAXesjgPkTcgQ4wXdrgP4CcgQ45ndsYIH9AAZ0KgZSUVOWtAJQ 1.138 +sQa1BMHFBLAPIegEkCcUQCfohAD+zXXssCDNEOK06I4AmM0TYVJQKMh3ArAB 1.139 +mDn4cgKJ+FC0As0TlV5YWnKglUGO6YDHAk90S0519IzplTjBdT+IyP7GsQE4 1.140 +5nU1iPT+xYD9ULYAdSq1AGC+2wH+RAxT6C8AW+g2AHUWUpjNE7gBAs0TWtDU 1.141 +OmT+depGCOR15WHrkbAxLAO0DrsHAM0QPA1088OwDejv/6wIwHX4w79sBLFb 1.142 +ZAINuA0BZDoNdArNFnT0mM0WjudHw1g6AEluc2VydCBkaXNrIDEHDQA= 1.143 +==== 1.144 +EOT 1.145 + # Get setup 1.146 + setupsz=$(getlong $SetupSzOfs $bs 1) 1.147 + if [ $setupsz -eq 0 ]; then 1.148 + setupsz=4 1.149 + store 8 $SetupSzOfs $setupsz $bs "setup size $setupsz" 1.150 + fi 1.151 + [ -n "$DEBUG" ] && echo "Read setup ($setupsz sectors) ..." 1>&2 1.152 + ddq if=$KERNEL bs=512 skip=1 count=$setupsz >> $bs 1.153 + 1.154 + Version=$(getlong 0x206 $bs 2) 1.155 + [ $(getlong $Magic $bs) -ne 1400005704 ] && Version=0 1.156 + feature="" 1.157 + while read prot kern info ; do 1.158 + [ $Version -lt $((0x$prot)) ] && continue 1.159 + feature="features $prot starting from kernel $kern " 1.160 + done <<EOT 1.161 +200 1.3.73 kernel_version, bzImage, initrd, loadflags/type_of_loader 1.162 +201 1.3.76 heap_end_ptr 1.163 +202 2.4.0 new cmdline 1.164 +204 2.6.14 long syssize 1.165 +EOT 1.166 + [ -n "$DEBUG" ] && printf "Protocol %X $feature\n" $Version 1>&2 1.167 + 1.168 + # Old kernels need bootsector patches to disable rescent features 1.169 + while read minversion maxversion offset bytes rem; do 1.170 + [ $Version -gt $(( 0x$maxversion )) ] && continue 1.171 + [ $Version -lt $(( 0x$minversion )) ] && continue 1.172 + patch $offset $bytes $bs "$rem" 1.173 + done <<EOT 1.174 +000 1FF 08D B8:00:01 force zImage (movw \$0x100, %ax) 1.175 +000 1FF 0CB EB:0B skip initrd code 1.176 +000 201 01E EB:1E:00:00:00:00 room for the cmdline magic 1.177 +000 201 036 BE:00:00:E8:76:01:EB:0A:06:57:B1:06:F3:A5:EB:DE code in cmdline magic moved 1.178 +000 1FF 039 90:90:90 no kernel version 1.179 +000 201 04B 22:00 old cmdline ptr 1 1.180 +000 201 06D 22:00 old cmdline ptr 2 1.181 +000 203 1F6 00:00 syssize32 1.182 +200 FFF 210 FF type_of_loader=FF 1.183 +201 FFF 224 00:9B heap_end_ptr 1.184 +EOT 1.185 + if [ $Version -lt 514 ]; then 1.186 + version_string=$((0x200 + $(getlong 0x20E $bs 2) )) 1.187 + store 16 0x0037 $version_string $bs version_string 1.188 + fi 1.189 + if [ $Version -ge 512 -a $(getlong 0x214 $bs) -ge $((0x100000)) ]; then 1.190 + patch 211 81 $bs loadflags=can_use_heap+loadhigh 1.191 + patch 09D 10 $bs LOADSEG=0x1000 1.192 + patch 0A0 00:01 $bs LOADSZ=0x10000 1.193 + fi 1.194 + [ -n "$CMDLINE" ] || patch 04D EB $bs "No cmdline" 1.195 + [ -n "$NOEDIT" ] && patch 059 0D:46:EB:14 $bs 'mov CR,%al ; inc %si; jmp putal' 1.196 + [ 1$TRACKS -ne 180 ] && store 8 0x171 $TRACKS $bs TRACKS 1.197 + 1.198 + [ -n "$FLAGS" ] && store 16 $FlagsOfs $FLAGS $bs FLAGS 1.199 + [ -n "$VIDEO" ] && store 16 $VideoModeOfs $VIDEO $bs VIDEO 1.200 + [ -n "$RDEV" ] || case "$FORMAT" in 1.201 + 1200) RDEV=0x0208 ;; 1.202 + 1440) RDEV=0x021C ;; 1.203 + 2880) RDEV=0x0220 ;; 1.204 + *) RDEV=0x0200 ;; 1.205 + esac 1.206 + while [ -L "$RDEV" ]; do RDEV="$(readlink "$RDEV")"; done 1.207 + [ -b "$RDEV" ] && RDEV=$(stat -c '0x%02t%02T' $RDEV 2> /dev/null) 1.208 + store 16 $RootDevOfs $RDEV $bs RDEV 1.209 + 1.210 + [ $FORMAT -lt 1440 ] && store 8 0xEF 16 $bs 1.2M 1.211 + [ $FORMAT -lt 1200 ] && store 8 0xEF 10 $bs 720K 1.212 + [ $FORMAT -lt 720 ] && store 8 0x171 40 $bs 360K 1.213 + [ $FORMAT -lt 360 ] && store 8 0xEF 9 $bs 320K 1.214 + [ $FORMAT -lt 320 ] && store 8 0xF8 2 $bs 160K 1.215 + 1.216 + # Info text after setup 1.217 + if [ -s "$INFOFILE" ]; then 1.218 + patch 048 9a:00:00:00:90 $bs lcall displayinfo 1.219 + uudecode >$bs.infotext <<EOT 1.220 +begin-base64 644 - 1.221 +MdsGYI7D6AAAXoHGSgCJ8MHoCUii8QGwDbQOuwcAzRCsPAx1I79sBLFbJgIN 1.222 +uBsBJjoNdAnNFnT0mM0Wjsc8IHPjPBt0BuvPCMB1zWEHCx4oAss= 1.223 +==== 1.224 +EOT 1.225 + cat "$INFOFILE" >>$bs.infotext 1.226 + if [ $Version -lt 514 ]; then 1.227 + store 16 0x050 0x0022 $bs.infotext 1.228 + fi 1.229 + ddq if=/dev/zero bs=512 count=1 >>$bs.infotext 1.230 + n=$(($(stat -c %s $bs.infotext)/512)) 1.231 + ddq if=$bs.infotext count=$n bs=512 >> $bs 1.232 + rm -f $bs.infotext 1.233 + store 8 0x1F1 $(($setupsz+$n)) $bs update setup size 1.234 + store 8 0x04A $((2+2*$setupsz)) $bs update displayinfo call 1.235 + fi 1.236 + 1.237 + # Store cmdline after setup for kernels >= 0.99 1.238 + if [ -n "$CMDLINE" ]; then 1.239 + echo -n "$CMDLINE" | ddq bs=512 count=1 conv=sync >> $bs 1.240 + CmdlineOfs=0x9E00 # Should be in 0x8000 .. 0xA000 1.241 + ArgPtrOfs=0x228 1.242 + ArgPtrVal=$(( $SetupBase + $CmdlineOfs )) 1.243 + if [ $Version -lt 514 ]; then 1.244 + ArgPtrOfs=0x0020 1.245 + ArgPtrVal=$(( 0xA33F + ($CmdlineOfs << 16) )) 1.246 + fi 1.247 + store 32 $ArgPtrOfs $ArgPtrVal $bs "Cmdline '$CMDLINE'" 1.248 + fi 1.249 + 1.250 + # Compute initramfs size (protocol >= 2.00) 1.251 + [ $Version -lt 512 ] && INITRD="" 1.252 + initrdlen=0 1.253 +INITRDPAD=4 1.254 +INITRDALIGN=0x1000 1.255 + for i in $( echo $INITRD | sed 's/,/ /' ); do 1.256 + [ -s "$i" ] || continue 1.257 + while [ -L "$i" ]; do i="$(readlink $i)"; done 1.258 + size=$(( ($(stat -c %s "$i") + $INITRDPAD - 1) & -$INITRDPAD )) 1.259 + [ -n "$DEBUG" ] && echo "initrd $i $size " 1>&2 1.260 + initrdlen=$(( $initrdlen + $size )) 1.261 + ADRSRD=$(( (($MEM * 0x100000) - $initrdlen) & -$INITRDALIGN )) 1.262 + store 32 $RamfsAdrOfs $(( $ADRSRD )) $bs initrd adrs 1.263 + store 32 $RamfsLenOfs $initrdlen $bs initrdlen 1.264 + done 1.265 + 1.266 + [ -n "$NOSYSSIZEFIX" ] || store 32 0x1F4 \ 1.267 + $(( ($(stat -c %s $KERNEL)+15)/16 - ($setupsz+1)*32)) $bs fix system size 1.268 + 1.269 + # Output boot sector + setup + cmdline 1.270 + ddq if=$bs 1.271 + 1.272 + # Output kernel code 1.273 + syssz=$(( ($(getlong 0x1F4 $bs)+31)/32 )) 1.274 + cat $KERNEL /dev/zero | ddq bs=512 skip=$(( $setupsz+1 )) count=$syssz conv=sync 1.275 + 1.276 + # Output initramfs 1.277 + for i in $( echo $INITRD | sed 's/,/ /' ); do 1.278 + [ -s "$i" ] || continue 1.279 + ddq if=$i 1.280 + padding=$(( $INITRDPAD - ($(stat -c %s $i) % $INITRDPAD) )) 1.281 + [ $padding -eq $INITRDPAD ] || ddq if=/dev/zero bs=1 count=$padding 1.282 + done 1.283 + 1.284 + # Cleanup 1.285 + rm -f $bs 1.286 +} 1.287 + 1.288 +if [ "$FORMAT" == "0" ]; then # unsplitted 1.289 + floppyset > $PREFIX 1.290 + PAD=$(( 512 - ($(stat -c %s $PREFIX) % 512) )) 1.291 + [ $PAD -ne 512 ] && ddq if=/dev/zero bs=1 count=$PAD >> $PREFIX 1.292 + exit 1.293 +fi 1.294 +floppyset | split -b ${FORMAT}k /dev/stdin floppy$$ 1.295 +i=1 1.296 +ls floppy$$* 2> /dev/null | while read file ; do 1.297 + output=$PREFIX$(printf "%03d" $i) 1.298 + cat $file /dev/zero | ddq bs=1k count=$FORMAT conv=sync of=$output 1.299 + echo $output 1.300 + rm -f $file 1.301 + i=$(( $i + 1 )) 1.302 +done