Integrate grub2 for hybrid boot
[grml-live.git] / scripts / bootgrub.mksh
1 #!/usr/bin/env mksh
2 # $Id$
3 # $miros: src/sys/arch/i386/stand/bootxx/mkbxinst.sh,v 1.15 2009/02/08 20:47:48 tg Exp $
4 #-
5 # Copyright (c) 2007, 2008, 2009
6 #       Thorsten Glaser <tg@mirbsd.org>
7 #
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.
13 #
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.
22 #-
23 # Self-installing 32-bit x86 boot blocks for GNU GRUB2 on i386-pc
24 # Reads a list of extents (firstblock lastblock) from standard input
25 # and writes bootxx to standard output, which can subsequentially be
26 # stored as partition boot record (or floppy boot sector) on disc.
27
28 set -A thecode 0x66 0x31 0xC9 0xBB 0x00 0x30 0x8E 0xD3 0xBC 0xFC 0xFF 0x66 0x51 0x66 0x9D 0x8E 0xC1 0xBF 0x00 0x7C 0x57 0xB1 0x10 0xF3 0xA4 0x5E 0x8E 0xD9 0xBB 0x00 0x08 0x53 0x53 0x8E 0xC3 0xBF 0x00 0xFE 0xB5 0x02 0xF3 0xA4 0x1F 0x68 0x7D 0xFE 0xCB 0x30 0x41 0x41 0x37 0x20 0x4C 0x6F 0x61 0x64 0x69 0x6E 0x67 0x20 0x00 0x62 0x61 0x64 0x20 0x6D 0x61 0x67 0x69 0x63 0x20 0x65 0x72 0x72 0x6F 0x72 0x0D 0x0A 0x00 0xAB 0x02 0x00 0x12 0x00 0x00 0x80 0x50 0xFF 0xB4 0x0E 0xBB 0x07 0x00 0xCD 0x10 0xAC 0x08 0xC0 0x75 0xF4 0xC3 0xE8 0xF7 0xFF 0xB8 0x30 0xFF 0x87 0x06 0x56 0xFE 0x3D 0x30 0xFF 0x75 0x19 0x31 0xC0 0xCD 0x16 0xEA 0xF0 0xFF 0x00 0xF0 0xFB 0x88 0x16 0x55 0xFE 0xBE 0x2F 0xFE 0x80 0xFA 0x80 0x72 0xDB 0xE8 0xD2 0xFF 0x31 0xDB 0xBE 0x53 0xFF 0x0F 0xB6 0x2E 0x4F 0xFE 0xAC 0x0F 0xB6 0xC8 0xC0 0xE9 0x05 0x83 0xE0 0x1F 0x40 0x41 0x50 0xBF 0x10 0xFE 0xB8 0x10 0x00 0xAB 0xB0 0x01 0xAB 0x89 0xD8 0xAB 0x8C 0xC8 0xAB 0xF3 0xA4 0x31 0xC0 0xAB 0xAB 0xAB 0xAB 0x5F 0x55 0x56 0xBE 0x10 0xFE 0xFF 0x16 0x56 0xFE 0xBD 0x04 0x00 0x8A 0x16 0x55 0xFE 0x60 0xF9 0xCD 0x13 0x9C 0xB8 0x2E 0x0E 0xBB 0x07 0x00 0xCD 0x10 0x9D 0xFB 0x61 0x73 0x1C 0x4D 0x60 0x9C 0x31 0xC0 0xCD 0x13 0x9D 0xBE 0x46 0xFE 0x0F 0x84 0x77 0xFF 0xB8 0x30 0x0E 0x01 0xE8 0xBB 0x07 0x00 0xCD 0x10 0x61 0xEB 0xD2 0xB4 0x02 0x00 0xE7 0x89 0x5C 0x04 0x00 0xFC 0x72 0x14 0x66 0x83 0x44 0x08 0x01 0x66 0x83 0x54 0x0C 0x00 0x4F 0x75 0xAC 0x5E 0x5D 0x4D 0x0F 0x85 0x7D 0xFF 0xBE 0x4C 0xFE 0xE8 0x3F 0xFF 0x66 0x31 0xD2 0x52 0x66 0x4A 0x8A 0x16 0x55 0xFE 0xB8 0x00 0x82 0x50 0xFA 0xCB 0x8B 0x44 0x08 0x8B 0x54 0x0A 0xF7 0x36 0x52 0xFE 0x42 0x31 0xC9 0x87 0xD1 0xF7 0x36 0x50 0xFE 0xC0 0xE4 0x06 0x86 0xC4 0x09 0xC1 0x88 0xD6 0xB8 0x01 0x02 0xC3 0xB4 0x42 0xC3
29 typeset -i ofs_bkcnt=79
30 typeset -i ofs_geomh=80
31 typeset -i ofs_geoms=82
32 typeset -i ofs_partp=84
33 typeset -i ofs_secsz=252
34 typeset -i begptr=339
35 typeset -Uui8 thecode
36
37 typeset -Uui16 curptr=begptr
38 typeset -i wnum=0 wofs=0 wrec=0
39
40 function do_record {
41         typeset -i blk=$1 cnt=$2 n
42         typeset -Uui16 x=blk y
43
44         (( blk && cnt )) || return
45
46         print -u2 "$wrec @0x${curptr#16#}: $cnt @$blk (0x${x#16#})"
47
48         while (( cnt )); do
49                 let wrec++
50                 (( n = blk < 0x00000100 ? 0 :
51                     blk < 0x00010000 ? 1 :
52                     blk < 0x01000000 ? 2 : 3 ))
53                 (( x = cnt < 33 ? cnt : 32 ))
54                 (( y = blk ))
55                 print -u2 " - 0x${curptr#16#}: $((x)) (0x${x#16#}) @ $blk" \
56                     "(0x${y#16#})"
57                 (( thecode[curptr++] = (n++ << 5) | (x - 1) ))
58                 (( blk += x ))
59                 (( cnt -= x ))
60                 while (( n-- )); do
61                         (( thecode[curptr++] = y & 0xFF ))
62                         (( y >>= 8 ))
63                 done
64         done
65 }
66
67 function record_block {
68         typeset -i sv blk=$1
69
70         if (( !blk || (wofs && blk != (wofs + wnum)) )); then
71                 # flush the blocks from the cache
72                 (( wnum )) && do_record $wofs $wnum
73                 wofs=0
74                 wnum=0
75         fi
76         if (( blk )); then
77                 # record some new block into the cache
78                 (( wofs )) || let wofs=blk
79                 (( wnum += 1 << sscale ))
80         fi
81 }
82
83 typeset -i partp=0 numheads=0 numsecs=0 sscale=0 bsh=9
84
85 while getopts ":0:1B:h:p:S:s:" ch; do
86         case $ch {
87         (0)     ;;
88         (1)     ;;
89         (B)     if (( (bsh = OPTARG) < 9 || OPTARG > 15 )); then
90                         print -u2 error: invalid block size "2^'$OPTARG'"
91                         exit 1
92                 fi
93                 ;;
94         (h)     if (( (numheads = OPTARG) < 1 || OPTARG > 256 )); then
95                         print -u2 warning: invalid head count "'$OPTARG'"
96                         numheads=0
97                 fi ;;
98         (p)     if (( (partp = OPTARG) < 1 || OPTARG > 255 )); then
99                         print -u2 warning: invalid partition type "'$OPTARG'"
100                         partp=0
101                 fi ;;
102         (S)     if (( (sscale = OPTARG) < 0 || OPTARG > 24 )); then
103                         print -u2 error: invalid input scale "'$OPTARG'"
104                         exit 1
105                 fi ;;
106         (s)     if (( (numsecs = OPTARG) < 1 || OPTARG > 63 )); then
107                         print -u2 warning: invalid sector count "'$OPTARG'"
108                         numsecs=0
109                 fi ;;
110         (*)     print -u2 'Syntax:
111         bxinst [-1] [-B blocksize] [-h heads] [-p partitiontype] [-S scale]
112             [-s sectors] <sectorlist | dd of=image conv=notrunc
113 Default values: blocksize=9 heads=16 sectors=63 partitiontype=0x27 scale=0'
114                 exit 1 ;;
115         }
116 done
117 shift $((OPTIND - 1))
118
119 if (( !numheads )); then
120         print -u2 warning: using default value of 16 heads
121         numheads=16
122 fi
123
124 if (( !numsecs )); then
125         print -u2 warning: using default value of 63 sectors
126         numsecs=63
127 fi
128
129 # read in the extents
130 while read firstblock lastblock junk; do
131         while (( firstblock <= lastblock )); do
132                 record_block $((firstblock++ << sscale))
133         done
134 done
135 record_block 0  # just flush
136 print -u2 "using $wrec blocks, $((curptr-begptr)) bytes ($((510-curptr)) free)"
137
138 # fill the block table
139 if (( curptr-- > 510 )); then
140         print -u2 error: too many blocks
141         exit 1
142 fi
143 while (( ++curptr < 510 )); do
144         (( thecode[curptr] = (curptr & 0xFCF) == 0x1C2 ? 0 : RANDOM & 0xFF ))
145         # ensure the “active” flag is never set to 0x00 or 0x80
146         if (( ((curptr + 2) & 0xFCF) == 0x01C0 )); then
147                 (( thecode[curptr] & 0x7F )) || let --curptr
148         fi
149 done
150 thecode[510]=0x55
151 thecode[511]=0xAA
152
153 # fill in other data
154 (( thecode[ofs_bkcnt] = wrec ))
155 (( thecode[ofs_geomh] = numheads & 0xFF ))
156 (( thecode[ofs_geomh + 1] = numheads >> 8 ))
157 (( thecode[ofs_geoms] = numsecs ))
158 (( thecode[ofs_partp] = partp ))
159 print -u2 "using sectors of 2^$bsh = $((1 << bsh)) bytes"
160 (( thecode[ofs_secsz] = (1 << (bsh - 8)) ))
161
162 # create the output string
163 ostr=
164 curptr=0
165 while (( curptr < 512 )); do
166         ostr=$ostr\\0${thecode[curptr++]#8#}
167 done
168
169 # over and out
170 print -n "$ostr"
171 exit 0