riscv: add PLIC
[openadk.git] / scripts / create.sh
blob1d0c467d0cf42e9128826949c3fb4d91f7b64a4c
1 #!/usr/bin/env bash
2 #-
3 # Copyright © 2010, 2011, 2012
4 # Thorsten Glaser <tg@mirbsd.org>
5 # Copyright © 2010-2014
6 # Waldemar Brodkorb <wbx@openadk.org>
8 # Provided that these terms and disclaimer and all copyright notices
9 # are retained or reproduced in an accompanying document, permission
10 # is granted to deal in this work without restriction, including un‐
11 # limited rights to use, publicly perform, distribute, sell, modify,
12 # merge, give away, or sublicence.
14 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
15 # the utmost extent permitted by applicable law, neither express nor
16 # implied; without malicious intent or gross negligence. In no event
17 # may a licensor, author or contributor be held liable for indirect,
18 # direct, other damage, loss, or other issues arising in any way out
19 # of dealing in the work, even if advised of the possibility of such
20 # damage or existence of a defect, except proven that it results out
21 # of said person’s immediate fault when using the work as intended.
23 # Alternatively, this work may be distributed under the Terms of the
24 # General Public License, any version as published by the Free Soft‐
25 # ware Foundation.
27 # Create a hard disc image, bootable using GNU GRUB2, with an ext2fs
28 # root partition and an OpenADK cfgfs partition.
30 ADK_TOPDIR=$(pwd)
31 HOST=$(gcc -dumpmachine)
32 me=$0
34 case :$PATH: in
35 (*:$ADK_TOPDIR/host_$HOST/usr/bin:*) ;;
36 (*) export PATH=$PATH:$ADK_TOPDIR/host_$HOST/usr/bin ;;
37 esac
39 test -n "$KSH_VERSION" || exec mksh "$me" "$@"
40 if test -z "$KSH_VERSION"; then
41 echo >&2 Fatal error: could not run myself with mksh!
42 exit 255
45 ### run with mksh from here onwards ###
47 me=${me##*/}
49 ADK_TOPDIR=$(realpath .)
50 ostype=$(uname -s)
52 function usage {
53 cat >&2 <<EOF
54 Syntax: $me [-c cfgfssize] [+g] [-i imagesize] [-p panictime]
55 [-s serialspeed] [-t] [-T imagetype] [+U] target.ima source.tgz
56 Explanation/Defaults:
57 -c: minimum 0, maximum 5, default 1 (MiB)
58 -g: enable installing GNU GRUB 2
59 -i: total image, default 512 (MiB; max. approx. 2 TiB)
60 -p: default 10 (seconds; 0 disables; max. 300)
61 -s: default 115200 (bps, others: 9600 19200 38400 57600)
62 -t: enable serial console (+t disables it, default)
63 -T: image type (default raw, others: vdi)
64 EOF
65 exit ${1:-1}
68 cfgfs=1
69 usegrub=0
70 tgtmib=512
71 panicreboot=10
72 speed=115200
73 serial=0
74 tgttype=raw
76 while getopts "c:ghi:p:s:tT:" ch; do
77 case $ch {
78 (c) if (( (cfgfs = OPTARG) < 0 || cfgfs > 5 )); then
79 print -u2 "$me: -c $OPTARG out of bounds"
80 usage
81 fi ;;
82 (g) usegrub=1 ;;
83 (h) usage 0 ;;
84 (i) if (( (tgtmib = OPTARG) < 7 || tgtmib > 2097150 )); then
85 print -u2 "$me: -i $OPTARG out of bounds"
86 usage
87 fi ;;
88 (p) if (( (panicreboot = OPTARG) < 0 || panicreboot > 300 )); then
89 print -u2 "$me: -p $OPTARG out of bounds"
90 usage
91 fi ;;
92 (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
93 print -u2 "$me: serial speed $OPTARG invalid"
94 usage
96 speed=$OPTARG ;;
97 (t) serial=1 ;;
98 (+t) serial=0 ;;
99 (T) if [[ $OPTARG != @(raw|vdi) ]]; then
100 print -u2 "$me: image type $OPTARG invalid"
101 usage
103 tgttype=$OPTARG ;;
104 (*) usage 1 ;;
106 done
107 shift $((OPTIND - 1))
109 (( $# == 2 )) || usage 1
112 tools='bc genext2fs'
113 [[ $tgttype = vdi ]] && tools="$tools VBoxManage"
114 for tool in $tools; do
115 print -n Checking if $tool is installed...
116 if whence -p $tool >/dev/null; then
117 print " okay"
118 else
119 print " failed"
122 done
123 (( f )) && exit 1
124 if bc --help >/dev/null 2>&1; then
125 # GNU bc shows a “welcome message” which irritates scripts
126 bc='bc -q'
127 else
128 bc=bc
131 tgt=$1
132 [[ $tgt = /* ]] || tgt=$PWD/$tgt
133 src=$2
135 if [[ ! -f $src ]]; then
136 print -u2 "'$src' is not a file, exiting"
137 exit 1
139 if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
140 print -u2 Error creating temporary directory.
141 exit 1
143 print "Installing $src on $tgt."
145 cyls=$tgtmib
146 heads=64
147 secs=32
148 if stat -qs .>/dev/null 2>&1; then
149 statcmd='stat -f %z' # BSD stat (or so we assume)
150 else
151 statcmd='stat -c %s' # GNU stat
154 if (( usegrub )); then
155 tar -xOJf "$src" boot/grub/core.img >"$T/core.img"
156 integer coreimgsz=$($statcmd "$T/core.img")
157 if (( coreimgsz < 1024 )); then
158 print -u2 core.img is probably too small: $coreimgsz
159 rm -rf "$T"
160 exit 1
162 if (( coreimgsz > 65024 )); then
163 print -u2 core.img is larger than 64K-512: $coreimgsz
164 rm -rf "$T"
165 exit 1
167 else
168 # fake it
169 integer coreimgsz=1
171 (( coreendsec = (coreimgsz + 511) / 512 ))
172 corestartsec=1
173 corepatchofs=$((0x414))
174 # partition offset: at least coreendsec+1 but aligned on a multiple of secs
175 (( partofs = ((coreendsec / secs) + 1) * secs ))
176 # calculate size of ext2fs in KiB as image size minus cfgfs minus firsttrack
177 ((# partfssz = ((cyls - cfgfs) * 64 * 32 - partofs) / 2 ))
179 if (( usegrub )); then
180 print Preparing MBR and GRUB2...
181 else
182 print Preparing partition table...
184 dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
185 echo $corestartsec $coreendsec | mksh "$ADK_TOPDIR/scripts/bootgrub.mksh" \
186 -A -g $((cyls - cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \
187 dd of="$T/firsttrack" conv=notrunc 2>/dev/null
188 if (( usegrub )); then
189 dd if="$T/core.img" of="$T/firsttrack" conv=notrunc \
190 seek=$corestartsec 2>/dev/null
191 # set partition where it can find /boot/grub
192 print -n '\0\0\0\0' | \
193 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$corepatchofs \
194 2>/dev/null
197 # create cfgfs partition (mostly taken from bootgrub.mksh)
198 set -A thecode
199 typeset -Uui8 thecode
200 mbrpno=0
201 set -A g_code $cyls $heads $secs
202 (( pssz = cfgfs * g_code[1] * g_code[2] ))
203 (( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
204 set -A o_code # g_code equivalent for partition offset
205 (( o_code[2] = pofs % g_code[2] + 1 ))
206 (( o_code[1] = pofs / g_code[2] ))
207 (( o_code[0] = o_code[1] / g_code[1] + 1 ))
208 (( o_code[1] = o_code[1] % g_code[1] + 1 ))
209 # boot flag; C/H/S offset
210 thecode[mbrpno++]=0x00
211 (( thecode[mbrpno++] = o_code[1] - 1 ))
212 (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
213 (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
214 (( thecode[mbrpno++] = cylno & 0x00FF ))
215 # partition type; C/H/S end
216 (( thecode[mbrpno++] = 0x88 ))
217 (( thecode[mbrpno++] = g_code[1] - 1 ))
218 (( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
219 (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
220 (( thecode[mbrpno++] = cylno & 0x00FF ))
221 # partition offset, size (LBA)
222 (( thecode[mbrpno++] = pofs & 0xFF ))
223 (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
224 (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
225 (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
226 (( thecode[mbrpno++] = pssz & 0xFF ))
227 (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
228 (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
229 (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
230 # write partition table entry
231 ostr=
232 curptr=0
233 while (( curptr < 16 )); do
234 ostr=$ostr\\0${thecode[curptr++]#8#}
235 done
236 print -n "$ostr" | \
237 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
239 print Extracting installation archive...
240 mkdir "$T/src"
241 xz -dc "$src" | (cd "$T/src"; tar -xpf -)
242 cd "$T/src"
243 rnddev=/dev/urandom
244 [[ -c /dev/arandom ]] && rnddev=/dev/arandom
245 dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
246 print Fixing up permissions...
247 chmod 1777 tmp
248 [[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudo
250 if (( usegrub )); then
251 print Configuring GRUB2 bootloader...
252 mkdir -p boot/grub
254 print set default=0
255 print set timeout=1
256 if (( serial )); then
257 print serial --unit=0 --speed=$speed
258 print terminal_output serial
259 print terminal_input serial
260 consargs="console=ttyS0,$speed console=tty0"
261 else
262 print terminal_output console
263 print terminal_input console
264 consargs="console=tty0"
266 print
267 print 'menuentry "GNU/Linux (OpenADK)" {'
268 linuxargs="root=/dev/sda1 $consargs"
269 (( panicreboot )) && linuxargs="$linuxargs panic=$panicreboot"
270 print "\tlinux /boot/kernel $linuxargs"
271 print '}'
272 ) >boot/grub/grub.cfg
275 print "Creating ext2fs filesystem image..."
276 cd "$T"
278 genext2fs -U -N 32768 -b $((partfssz)) -d src fsimg || f=1
279 if (( !f )); then
280 # use bc(1): this may be over the shell’s 32-bit arithmetics
281 wantsz=$($bc <<<"$((partfssz))*1024")
282 gotsz=$($statcmd fsimg)
283 if [[ $wantsz != "$gotsz" ]]; then
284 print -u2 "Error: want $wantsz bytes, got $gotsz bytes!"
288 if (( f )); then
289 print -u2 "Error creating ext2fs filesystem image"
290 cd /
291 rm -rf "$T"
292 exit 1
294 # delete source tree, to save disc space
295 rm -rf src
297 if [[ $tgttype = raw ]]; then
298 tgttmp=$tgt
299 else
300 tgttmp=$T/dst.ima
302 print "Putting together raw output image $tgttmp..."
303 dd if=/dev/zero bs=1048576 count=$cfgfs 2>/dev/null | \
304 cat firsttrack fsimg - >"$tgttmp"
305 # use bc(1): this may be over the shell’s 32-bit arithmetics
306 wantsz=$($bc <<<"$tgtmib*1048576")
307 gotsz=$($statcmd "$tgttmp")
308 if [[ $wantsz != "$gotsz" ]]; then
309 print -u2 "Error: want $wantsz bytes, got $gotsz bytes!"
310 cd /
311 rm -rf "$T"
312 exit 1
315 case $tgttype {
316 (raw)
318 (vdi)
319 print "Converting raw image to VDI..."
320 VBoxManage convertdd dst.ima dst.vdi
321 rm dst.ima
322 print "Moving VDI image to $tgt.vdi..."
323 mv -f dst.vdi "$tgt".vdi
327 print Finishing up...
328 cd "$ADK_TOPDIR"
329 rm -rf "$T"
330 exit 0