wok-current view tazpanel-extra/stuff/bootloader @ rev 18248

tazpanel-extra/floppy.cgi: multiple files support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Aug 02 13:31:26 2015 +0200 (2015-08-02)
parents 01f2e8c0ea7b
children
line source
1 #!/bin/sh
2 #
3 # This script creates a floppy image set from a linux bzImage and can merge
4 # a cmdline and/or one or more initramfs.
5 #
6 # (C) 2009-2015 Pascal Bellard - GNU General Public License v3.
8 usage()
9 {
10 cat <<EOT
11 Usage: $0 bzImage [--prefix image_prefix] [--info file] [--quiet]
12 [--format 1200|1440|1680|1920|2880|...] [--mem mb] [--tracks cnt]
13 [--rdev device] [--video mode] [--flags rootflags] [--no-syssize-fix]
14 [--dont-edit-cmdline] [--cmdline 'args'] [--hide-version-string]
15 [--address-initrd address] [--initrd initrdfile]...
17 Default values: --format 1440 --tracks 80 --rdev /dev/fd0 --prefix floppy. --mem 16
19 Example:
20 $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
22 or: $0 --extract floppy*
24 Create kernel and maybe cmdline, initrd and info files from a floppy images set
25 EOT
26 exit 1
27 }
29 # bzImage offsets
30 SetupSzOfs=497
31 FlagsOfs=498
32 OldRamfsLenOfs=504
33 VideoModeOfs=506
34 RootDevOfs=508
35 Magic=0x202
36 RamfsAdrOfs=0x218
37 RamfsLenOfs=0x21C
39 ddq() { dd $@ 2> /dev/null; }
41 get()
42 {
43 echo $( od -v -j $(($1)) -N ${4:-${3:-2}} -t u${3:-2} -w${3:-2} -An $2 2>/dev/null ||
44 hexdump -v -s $(($1)) -n ${4:-${3:-2}} -e "\"\" 1/${3:-2} \" %d\n\"" $2 )
45 }
47 trace()
48 {
49 [ -n "$DEBUG" ] && printf "$@" 1>&2 && echo 1>&2
50 }
52 # usage: store bits offset data file
53 store()
54 {
55 n=$3; for i in $(seq 8 8 $1); do
56 printf '\\\\x%02X' $(($n & 255))
57 n=$(($n >> 8))
58 done | xargs echo -en | ddq bs=1 conv=notrunc of=$4 seek=$(($2))
59 s=$1; a=$2; d=$3; shift 4; c="$@"
60 trace "store$s(%03X) = %0$(($s/4))X $c" $a $d
61 }
63 die()
64 {
65 echo $@ 1>&2
66 exit 1
67 }
68 extract()
69 {
70 shift
71 [ ! -s "$1" ] && die "No floppy ?"
72 [ $(get 0x1FE "$1") -ne 43605 ] && die "Not bootable"
73 [ $(get $Magic "$1" 4) != 1400005704 ] &&
74 [ $(get 0x1F4 "$1") -gt 32768 -o $(get 0x1F6 "$1") -ne 0 ] &&
75 die "Not linux."
76 FORMAT="$(($(stat -c "%s" $1)/1024))"
77 cat <<EOT
78 --format $FORMAT
79 --rdev $(printf "0x%04X" $(get $RootDevOfs $1))
80 --video $(get $VideoModeOfs $1)
81 --flags $(get $FlagsOfs $1)
82 EOT
83 MYBB="$(ddq if=$1 bs=512 count=1 | strings | grep "Insert disk 00")"
84 cmdline=0
85 info=0
86 if [ "$MYBB" ]; then
87 cmdline=$(get 0x22 $1)
88 info=$(get 0x1EF $1)
89 [ $(get 0x75 $1) -eq $((0xDB0)) ] && echo "--dont-edit-cmdline"
90 [ $(get 0x58 $1) -eq $((0x9090)) ] && echo "--hide-version-string"
91 fi
92 n=$(($(get $SetupSzOfs $1 1)+1))
93 [ $n -eq 1 ] && n=5
94 [ $info -ne 0 ] && infolen=$(($n-$info/512)) && n=$(($info/512))
95 [ $cmdline -ne 0 ] && n=$(($cmdline/512))
96 cat "$@" | {
97 ddq bs=512 count=$n >kernel
98 files="kernel"
99 if [ "$MYBB" ]; then
100 store 8 $SetupSzOfs $(($n-1)) kernel "setup size $n"
101 store 16 0x22 0 kernel "clear cmdline"
102 store 16 0x1EF 0 kernel "clear info"
103 fi
104 [ $cmdline -ne 0 ] && files="$files cmdline" &&
105 ddq bs=512 count=1 | strings | sed q > cmdline
106 [ $info -ne 0 ] && files="$files info" &&
107 ddq bs=512 count=$infolen | sed \
108 's/'$(echo -en "\xff\xff$//;s/\xff/\f")'/g;s/\r/\n/g;q' > info
109 syssz=$(get 0x1F4 kernel 4)
110 ddq bs=16 count=$syssz >>kernel
111 [ $(($syssz % 32)) -ne 0 ] &&
112 ddq bs=16 of=/dev/null count=$((32 - ($syssz % 32)))
113 if [ $(get $Magic kernel 4) == 1400005704 ]; then
114 ddq bs=1 count=200 skip=$((512+$(get 0x20E kernel 2))) \
115 if=kernel | strings | sed q
116 len=$(get $RamfsLenOfs kernel 4)
117 if [ $len -ne 0 ]; then
118 adrs=$(get $RamfsAdrOfs kernel 4)
119 printf "--address-initrd 0x%X \n" $adrs
120 echo "--mem $(((($adrs+$len)/1024+512)/1024))"
121 ddq bs=512 count=$((($len+511)/512)) > initrd
122 ddq count=0 bs=1 seek=$len of=initrd
123 files="$files initrd"
124 store 64 $RamfsAdrOfs 0 kernel "reset initrd"
125 fi
126 if [ $(get 0x206 kernel) -ge 514 ]; then
127 store 32 0x228 0 kernel "clean cmdline32"
128 fi
129 else
130 len=$(get $OldRamfsLenOfs kernel)
131 [ $len -ne 0 ] && files="$files initrd" &&
132 if [ -s "$2" ]; then
133 ddq if=$2 bs=1024 count=$len of=initrd
134 else
135 ddq if=$1 bs=1024 skip=256 count=$len of=initrd
136 fi
137 fi
138 ls -l $files
139 }
140 exit
141 }
143 KERNEL=""
144 INITRD=""
145 ADRSRD=""
146 CMDLINE=""
147 PREFIX="floppy."
148 FORMAT="1440"
149 RDEV=""
150 VIDEO=""
151 FLAGS=""
152 TRACKS="80"
153 MEM="16"
154 HIDE=""
155 NOEDIT=""
156 QUIET=""
157 NOSYSSIZEFIX=""
158 INFOFILE=""
159 DEBUG=""
160 while [ -n "$1" ]; do
161 case "${1/--/-}" in
162 -c*) CMDLINE="$2"; shift;;
163 -inf*) INFOFILE="$2"; shift;;
164 -i*) INITRD="$INITRD $2"; shift;;
165 -a*) ADRSRD="$2"; shift;;
166 -h*) HIDE="1";;
167 -p*) PREFIX="$2"; shift;;
168 -fl*)FLAGS="$2"; shift;; # 1 read-only, 0 read-write
169 -f*) FORMAT="$2"; shift;;
170 -m*) MEM="$(echo $2 | sed 's/[^0-9]//g')"; shift;;
171 -r*) RDEV="$2"; shift;;
172 -v*) VIDEO="$2"; shift;; # -3 .. n
173 -t*) TRACKS="$2"; shift;; # likely 81 .. 84
174 -n*) NOSYSSIZEFIX="1";;
175 -debug) DEBUG="1";;
176 -d*) NOEDIT="1";;
177 -q*) QUIET="1";;
178 -e*) extract "$@";;
179 *) KERNEL="$1";;
180 esac
181 shift
182 done
183 [ -n "$KERNEL" -a -f "$KERNEL" ] || usage
184 while [ -L "$KERNEL" ]; do KERNEL="$(readlink "$KERNEL")"; done
185 if [ $(( $FORMAT % $TRACKS )) -ne 0 ]; then
186 echo "Invalid track count for format $FORMAT."
187 usage
188 fi
189 [ 0$MEM -lt 2 ] && MEM=2
191 patch()
192 {
193 echo -en $(echo ":$2" | sed 's/:/\\x/g') | \
194 ddq bs=1 conv=notrunc of=$3 seek=$((0x$1))
195 trace "patch $1 $2 $4"
196 }
198 error()
199 {
200 rm -f $bs
201 die $@
202 }
204 floppyset()
205 {
206 # boot+setup address
207 SetupBase=0x90000
209 bs=/tmp/bs$$
211 # Get and patch boot sector
212 # See http://hg.slitaz.org/wok/raw-file/13835bce7189/syslinux/stuff/iso2exe/bootloader.S
213 trace "Read bootsector..."
214 ddq if=$KERNEL bs=512 count=1 of=$bs
216 [ $(get 0x1FE $bs) -eq 43605 ] || error "Not bootable"
218 uudecode <<EOT | ddq of=$bs conv=notrunc
219 begin-base64 644 -
220 v8adaACQF4n8FgcxwLk7APOqWx+g8X1AD6H6xXd4XwZXvQAAsQbzpRYfZGaP
221 R3jGRfg/l1hB6CQBMfYLNu8BdAzoggF0B+hgATwbdfS+AAKBTBAggMZEJZvo
222 ZwEx9gt3G3Q6x0cZP6PoWwGwIOgtASwYc/lO6DEBmDwIdAOIBK05dxt08OgV
223 ATwKdd+IfP4WB78AgIn+h3cbtQLzpFuJ5v9IEMdAFAiTgPMIdfO79AGxBaEV
224 AmaLH2ZLZtPrZkOJRBtmv4AAAABmKfuccwIB31BTVjHbaACAB+hwAF5bjMG0
225 hxYHzRVYBQABEEwfnXfPuQkCuxwCOE/+che0iM0VPQCwcgaIbB+Ib/+hGQLT
226 b+J1o5fNE+oAACCQWjjBdzRgzRP56HMAYVJQKMh3ArABOfhyAon4ULQCzRNa
227 WHLclQHRjukA1wDXKddadE2M6ZU4wXXUiMixATDOdcz+xYD9UHXFtQBgvtEB
228 U7sPAIAg8Ev+AIA4OXf16EwAW4n16CkAdRVSmM0TuAECzRNa0NQ6Zv516kVI
229 debrjbAxHAO0DrsHAM0QPA1088O/bARkxgWmuA0BZDoldArNFnT0mM0WjudH
230 wwN0DrAN6NL/rDwAf/jDSW5zZXJ0IGRpc2sgMDAxIGFuZCBFbnRlci4HDQAA
231 AAA=
232 ====
233 EOT
234 # Get setup
235 setupsz=$(get $SetupSzOfs $bs 1)
236 if [ $setupsz -eq 0 ]; then
237 setupsz=4
238 store 8 $SetupSzOfs $setupsz $bs "setup size $setupsz"
239 fi
240 trace "Read setup ($setupsz sectors) ..."
241 ddq if=$KERNEL bs=512 skip=1 count=$setupsz >> $bs
243 Version=$(get 0x206 $bs)
244 [ $(get $Magic $bs 4) != 1400005704 ] && Version=0
245 feature=""
246 while read prot kern info ; do
247 [ $Version -lt $((0x$prot)) ] && continue
248 feature="features $prot starting from kernel $kern "
249 done <<EOT
250 200 1.3.73 kernel_version, bzImage, initrd, loadflags/type_of_loader
251 201 1.3.76 heap_end_ptr
252 202 2.4.0 new cmdline + relocatable setup
253 204 2.6.14 long syssize
254 206 2.6.22 cmdline maxsize $(get 0x238 $bs 4)
255 EOT
256 trace "Protocol %X $feature" $Version
258 # Old kernels need bootsector patches to disable rescent features
259 while read minversion maxversion offset bytes rem; do
260 [ $Version -gt $(( 0x$maxversion )) ] && continue
261 [ $Version -lt $(( 0x$minversion )) ] && continue
262 patch $offset $bytes $bs "$rem"
263 done <<EOT
264 000 1FF 0B2 B8:00:01 force zImage (movw \$0x100, %ax)
265 000 1FF 0F9 EB skip initrd code
266 000 1FF 059 90:90:90 no kernel version
267 000 1FF 050 90:90:90:90:90 type_of_loader
268 000 200 055 90:90:90:90 heap_end_ptr
269 000 203 1F6 00:00 syssize32
270 EOT
271 [ -n "$CMDLINE" ] || patch 061 EB $bs "No cmdline"
272 [ -n "$HIDE" ] && patch 058 90 90 90 $bs "Hide version"
273 [ -n "$NOEDIT" ] && patch 075 B0:0D:90 $bs 'mov CR,%al ; nop'
274 [ 1$TRACKS -ne 180 ] && store 8 0x15F $TRACKS $bs TRACKS
276 [ -n "$FLAGS" ] && store 16 $FlagsOfs $FLAGS $bs FLAGS
277 [ -n "$VIDEO" ] && store 16 $VideoModeOfs $VIDEO $bs VIDEO
278 [ -n "$RDEV" ] || case "$FORMAT" in
279 1200) RDEV=0x0208 ;;
280 1440) RDEV=0x021C ;;
281 2880) RDEV=0x0220 ;;
282 *) RDEV=0x0200 ;;
283 esac
284 while [ -L "$RDEV" ]; do RDEV="$(readlink "$RDEV")"; done
285 [ -b "$RDEV" ] && RDEV=$(stat -c '0x%02t%02T' $RDEV 2> /dev/null)
286 [ "$(echo $RDEV | tr '[0-9A-FXa-fx]' 0 | sed 's/0//g')" ] ||
287 store 16 $RootDevOfs $RDEV $bs RDEV
289 [ $FORMAT -lt 720 ] && store 8 0x15F 40 $bs 360K
290 [ $FORMAT -lt 320 ] && store 8 0x158 237 $bs 160K
292 extra=0
293 # Store cmdline after setup for kernels >= 0.99
294 if [ -n "$CMDLINE" ]; then
295 CmdlineOfs=$(stat -c '%s' $bs)
296 store 16 0x22 $CmdlineOfs $bs "Cmdline @$CmdlineOfs '$CMDLINE'"
297 [ $Version -ge 514 ] &&
298 store 32 0x228 $(( $SetupBase + 0x8000 )) $bs "Cmdline32"
299 echo -n "$CMDLINE" | ddq bs=512 count=1 conv=sync >> $bs
300 extra=$(($extra+1))
301 store 8 0x1F1 $(($setupsz+$extra)) $bs setup size
302 [ $Version -ge 512 ] && [ -n "$QUIET" ] &&
303 store 8 0x211 $(($(get 0x211 $bs 1) | 32)) $bs suppress early messages
304 fi
306 # Info text after setup
307 if [ -s "$INFOFILE" ]; then
308 InfoOfs=$(stat -c '%s' $bs)
309 sed -e ':a;N;$!ba;s/\r\n/\r/g;s/\n/\r/g' \
310 -e 's/'$(echo -e "\f/\xff/g;s/$/\xff\xff")'/' \
311 < "$INFOFILE" > $bs.infotext
312 ddq if=/dev/zero bs=512 count=1 >>$bs.infotext
313 infolen=$(($(stat -c %s $bs.infotext)/512))
314 ddq if=$bs.infotext count=$infolen bs=512 >> $bs
315 extra=$(($extra+$infolen))
316 rm -f $bs.infotext
317 store 8 0x1F1 $(($setupsz+$extra)) $bs setup size
318 store 16 0x1EF $InfoOfs $bs update infoptr
319 fi
321 syssz=$((($(stat -c %s $KERNEL)+15)/16-32*(1+$setupsz)))
322 #syssz=$(get 0x1F4 $bs 4)
323 sysszsect=$((($syssz+31)/32))
324 store 16 $OldRamfsLenOfs 0 $bs clear oldramfs
325 INITRD="${INITRD# }"
326 INITRDPAD=4
327 [ -n "$INITRD" ] &&
328 if [ $Version -lt 512 ]; then
329 # Compute initramfs location (protocol < 2.00)
330 [ $syssz -gt 32768 ] && syssz=$(get 0x1F4 $bs 2)
331 [ $syssz -eq 0 ] && syssz=$((0x7F00))
332 sysszsect=$((($syssz+31)/32))
333 INITRD="${INITRD%%,*}"
334 initrdlen=$(stat -c %s "$INITRD")
335 store 16 $OldRamfsLenOfs $(($initrdlen/1024)) $bs set oldramfs
336 INITRDDISKALIGN=$((0x40000))
337 [ $(($initrdlen+$INITRDDISKALIGN)) -gt $(($FORMAT*1024)) -o \
338 $(((512*$sysszsect) + $(stat -c %s $bs))) -gt $INITRDDISKALIGN -o \
339 -n "$ADRSRD" ] && INITRDDISKALIGN=$(($FORMAT*1024))
340 else
341 INITRDRAMALIGN=0x1000
342 # Compute initramfs size (protocol >= 2.00)
343 initrdlen=0
344 INITRDDISKALIGN=0
345 for i in ${INITRD//,/ }; do
346 [ -s "$i" ] || continue
347 while [ -L "$i" ]; do i="$(readlink $i)"; done
348 size=$(stat -c %s "$i")
349 trace "initrd $i $size "
350 initrdlen=$(((($initrdlen + $INITRDPAD - 1) & -$INITRDPAD) + $size))
351 ADRSRD2=$(( (($MEM * 0x100000) - $initrdlen) & -$INITRDRAMALIGN ))
352 store 32 $RamfsAdrOfs $(( ${ADRSRD:-$ADRSRD2} )) $bs initrd adrs
353 store 32 $RamfsLenOfs $initrdlen $bs initrdlen
354 done
355 fi
357 [ -n "$NOSYSSIZEFIX" ] || store 32 0x1F4 $syssz $bs fix system size
359 # Output boot sector + setup + cmdline + info
360 ddq if=$bs
362 # Output kernel code
363 [ $INITRDDISKALIGN -ne 0 ] &&
364 INITRDDISKALIGN=$(($INITRDDISKALIGN/512-$sysszsect-$extra-$setupsz-1))
365 cat $KERNEL /dev/zero | ddq bs=512 skip=$(( $setupsz+1 )) \
366 count=$(($sysszsect+$INITRDDISKALIGN)) conv=sync
368 # Output initramfs
369 padding=$INITRDPAD
370 for i in ${INITRD//,/ }; do
371 [ -s "$i" ] || continue
372 [ $padding -eq $INITRDPAD ] || ddq if=/dev/zero bs=1 count=$padding
373 ddq if=$i
374 trace "initrd $i ($(stat -c %s $i) bytes) padding $INITRDPAD"
375 padding=$(( $INITRDPAD - ($(stat -c %s $i) % $INITRDPAD) ))
376 done
378 # Cleanup
379 rm -f $bs
380 }
382 if [ "$FORMAT" == "0" ]; then # unsplitted
383 floppyset > $PREFIX
384 PAD=$(( 512 - ($(stat -c %s $PREFIX) % 512) ))
385 [ $PAD -ne 512 ] && ddq if=/dev/zero bs=1 count=$PAD >> $PREFIX
386 exit
387 fi
388 floppyset | split -b ${FORMAT}k /dev/stdin floppy$$
389 i=1
390 ls floppy$$* 2> /dev/null | while read file ; do
391 output=$PREFIX$(printf "%03d" $i)
392 cat $file /dev/zero | ddq bs=1k count=$FORMAT conv=sync of=$output
393 echo $output
394 rm -f $file
395 i=$(( $i + 1 ))
396 done