~ubuntu-virt/ubuntu/maverick/eucalyptus/2.0

1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
1
Description: add support for booting a multiboot image from a floppy
2
 This adds a tool 'mk-mb-loader' which takes a multiboot compliant image
3
 and puts it onto a floppy disk image and loads it.
4
 .
5
 It also contains modifications to gen_kvm_libvirt_xml that
6
 a.) make mk-mb-loader run 
7
 b.) modify libvirt xml output to add a floppy disk and boot
8
     off it rather than booting via '<kernel>'
9
 .
10
 The hack to boot off of a floppy is required because when a multiboot
11
 image is loaded by 'kvm -kernel "mb.img"', it will not have access to
12
 scsi disks.  That means that if a scsi disk is the root block device
13
 that the multiboot image will not see any disks.  
14
 .
15
 The solution is to boot via floppy instead.  The mk-mb-image creates
16
 a floppy disk that loads the user provided multiboot image.
17
 .
18
 In the future, this patch can be dropped if either of the following occur:
19
 a.) scsi root disk support is abandoned
20
 b.) seabios gains native support for scsi disks, such that 
21
     'kvm -kernel <mb.img' has access to scsi disks as it has access to
22
     ide or virtio disks in seabios 0.6.0-0ubuntu1.
23
 .
24
 That would provide a much more clean solution of simply booting with 
25
 '-kernel' whatever the user provided.
26
Author: Scott Moser <scott.moser@canonical.com>
27
Last-Update: 2010-07-28
28
Bug: https://bugs.launchpad.net/eucalyptus/+bug/611144
29
--- a/node/handlers.c
30
+++ b/node/handlers.c
31
@@ -380,6 +380,7 @@
32
 			char **xml)
33
 {
34
     char buf [MAX_PATH];
35
+    char patharg [MAX_PATH];
36
 
37
     snprintf(buf, MAX_PATH, "%s", gen_libvirt_cmd_path);
38
     if (strnlen(ramdiskId, CHAR_BUFFER_SIZE)) {
39
@@ -395,6 +396,9 @@
40
     if (params->disk > 0) { /* TODO: get this info from scMakeImage */
41
         strncat (buf, " --ephemeral", MAX_PATH);
42
     }
43
+    snprintf(buf+strnlen(buf,MAX_PATH), MAX_PATH-strnlen(buf,MAX_PATH),
44
+             " --basepath='%s'", disk_path);
45
+
46
     * xml = system_output (buf);
47
     if ( ( * xml ) == NULL ) {
48
         logprintfl (EUCAFATAL, "%s: %s\n", gen_libvirt_cmd_path, strerror (errno));
49
--- a/tools/gen_kvm_libvirt_xml
50
+++ b/tools/gen_kvm_libvirt_xml
51
@@ -76,6 +76,8 @@
52
 our $local_kvm="";
53
 our $use_virtio_net = 0;
54
 our $use_virtio_root = 0;
55
+our $base_path = "";
56
+our $multi_boot_floppy = 0;
57
 
58
 if ( -x "/usr/bin/kvm" ) {
59
     $local_kvm="/usr/bin/kvm";
1062 by Scott Moser
work around kvm virtio bug with -kernel by using boot floppy LP: #615529
60
@@ -90,24 +92,38 @@
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
61
            'ephemeral'      => sub { }, # option ignored 
62
            'virtionet'      => sub { $use_virtio_net = 1; },
63
            'virtioroot'      => sub { $use_virtio_root = 1; },
64
+           'basepath=s'      => \$base_path,
65
 		   ) or exit (1);
66
 
1062 by Scott Moser
work around kvm virtio bug with -kernel by using boot floppy LP: #615529
67
+if ($base_path && &is_multiboot_img($base_path . "/kernel")) {
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
68
+   $multi_boot_floppy = 1;
69
+}
70
+
71
 print <<EOF;
72
 <domain type='kvm'>
73
     <name>NAME</name>
74
     <os>
75
     <type>hvm</type>
76
-        <kernel>BASEPATH/kernel</kernel>
77
 EOF
78
 
79
-if ( $use_ramdisk ) {
80
-    print "        <initrd>BASEPATH/ramdisk</initrd>\n";
81
-}
82
-
83
-if ( $use_virtio_root ) {
84
-    print "        <cmdline>root=/dev/vda1 console=ttyS0</cmdline>\n"
85
+if ( $multi_boot_floppy ) {
86
+    my $mb_load_cmd = "/usr/share/eucalyptus/mk-mb-loader " .
87
+        "'" . $base_path . "/kernel' '" .  $base_path .  "/loader' 2>&1";
88
+    my $mb_out = `$mb_load_cmd`;
89
+    if ( $? != 0 ) { print("failed to make loader\n${mb_out}\n"); exit(1); }
90
+    print "        <boot dev='fd'/>\n";
91
+    print "        <boot dev='hd'/>\n";
92
 } else {
93
-    print "        <cmdline>root=/dev/sda1 console=ttyS0</cmdline>\n"
94
+    print "        <kernel>BASEPATH/kernel</kernel>\n";
95
+    if ( $use_ramdisk ) {
96
+        print "        <initrd>BASEPATH/ramdisk</initrd>\n";
97
+    }
98
+
99
+    if ( $use_virtio_root ) {
100
+        print "        <cmdline>root=/dev/vda1 console=ttyS0</cmdline>\n"
101
+    } else {
102
+        print "        <cmdline>root=/dev/sda1 console=ttyS0</cmdline>\n"
103
+    }
104
 }
105
 
106
 print <<EOF;
1062 by Scott Moser
work around kvm virtio bug with -kernel by using boot floppy LP: #615529
107
@@ -121,6 +137,15 @@
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
108
         <emulator>$local_kvm</emulator>
109
 EOF
110
 
111
+if ( $multi_boot_floppy ) {
112
+   print <<EOF
113
+        <disk type='file' device='floppy'>
114
+            <source file='BASEPATH/loader'/>
115
+            <target dev='fda' bus='fdc'/>
116
+        </disk>
117
+EOF
118
+}
119
+
120
 if ( $use_virtio_root ) {
121
     print <<EOF;
122
         <disk type='file' device='disk'>
1089 by Scott Moser
take the multiboot path only if kernel really is a multiboot
123
@@ -163,3 +188,42 @@
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
124
     </devices>
125
 </domain>
126
 EOF
127
+
1089 by Scott Moser
take the multiboot path only if kernel really is a multiboot
128
+# This checks if a binary looks like a multiboot image
129
+# The check is similar to grub 0.97's mbchk and to kvm's multiboot
130
+# check in hw/multiboot.c:load_multiboot
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
131
+sub is_multiboot_img
132
+{
1089 by Scott Moser
take the multiboot path only if kernel really is a multiboot
133
+    my $kpath=$_[0];
134
+    my $buf;
135
+    my $found = 0;
136
+    my $header_magic = 0x1BADB002;
137
+    my $header_size = 32;     # there are 8 uint32 values
138
+    my $search_bytes = 8192;  # copied from kvm and grub's mbchk
139
+    my $magic = 0;
140
+    my $flags = 0;
141
+    my $checksum = 0;
142
+    my $count = 0;
143
+
144
+    if (! (-s $kpath)) { return(0); }
145
+    open INF, $kpath or return(0);
146
+    binmode INF;
147
+    if (!($count = read (INF, $buf, $search_bytes))) {
148
+        close INF;
149
+        return(0);
150
+    }
151
+    close INF;
152
+    for(my $i=0;$i < ($count - $header_size);$i=$i+4) {
153
+        if (unpack("V",substr($buf,$i,4)) == $header_magic ) {
154
+            $found=$i; last;
155
+        }
156
+    }
157
+
158
+    if ($found == 0) { return(0); }
1090 by Scott Moser
gen_kvm_libvirt_xml: fix incorrect length in substr argument
159
+    ($magic,$flags,$checksum) = unpack("VVV",substr($buf,$found,4*3));
1089 by Scott Moser
take the multiboot path only if kernel really is a multiboot
160
+    # magic + flags + checksum == (uint32) 0 == 2**32
1098 by Scott Moser
fix determination of 'is_multiboot'.
161
+    if(($magic+$flags+$checksum) % 2**32 == 0 ) {
1089 by Scott Moser
take the multiboot path only if kernel really is a multiboot
162
+        return(1);
163
+    }
164
+    return(0);
1054 by Scott Moser
Add support for booting multiboot images from a floppy (LP: #611144)
165
+}
166
--- a/tools/Makefile
167
+++ b/tools/Makefile
168
@@ -47,6 +47,7 @@
169
 	@$(INSTALL) -m 755 connect_iscsitarget.pl $(DESTDIR)$(datarootdir)/eucalyptus
170
 	@$(INSTALL) -m 755 disconnect_iscsitarget.pl $(DESTDIR)$(datarootdir)/eucalyptus
171
 	@$(INSTALL) -m 755 get_iscsitarget.pl $(DESTDIR)$(datarootdir)/eucalyptus
172
+	@$(INSTALL) -m 755 mk-mb-loader $(DESTDIR)$(datarootdir)/eucalyptus
173
 
174
 uninstall: 
175
 	@$(RM) -f $(DESTDIR)$(etcdir)/init.d/eucalyptus-cloud
176
@@ -68,4 +69,5 @@
177
 	@$(RM) -f $(DESTDIR)$(sbindir)/euca_conf
178
 	@$(RM) -f $(DESTDIR)/etc/bash_completion.d/euca_conf
179
 	@$(RM) -f $(DESTDIR)$(sbindir)/euca_sync_key
180
+	@$(RM) -f $(DESTDIR)$(datarootdir)/eucalyptus/mk-mb-loader
181
 
182
--- /dev/null
183
+++ b/tools/mk-mb-loader
184
@@ -0,0 +1,113 @@
185
+#!/bin/sh
186
+# vi: ts=4 noexpandtab
187
+#
188
+#    Copyright (C) 2010 Canonical Ltd.
189
+#
190
+#    Authors: Scott Moser <smoser@canonical.com>
191
+#
192
+#    This program is free software: you can redistribute it and/or modify
193
+#    it under the terms of the GNU General Public License as published by
194
+#    the Free Software Foundation, version 3 of the License.
195
+#
196
+#    This program is distributed in the hope that it will be useful,
197
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
198
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
199
+#    GNU General Public License for more details.
200
+#
201
+#    You should have received a copy of the GNU General Public License
202
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
203
+
204
+TEMP_D=""
205
+
206
+error() { echo "$@" 1>&2; }
207
+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
208
+Usage() {
209
+	cat <<EOF
210
+Usage: ${0##*/} loader.img output.img
211
+   Create a multiboot floppy image that will multiboot 'loader.img'
212
+   where loader.img is a multiboot complient loader
213
+
214
+   The output.img file can then be booted with
215
+      kvm -fda output.img -boot a -drive ...
216
+   and will load 'loader.img'
217
+EOF
218
+}
219
+bad_Usage() { Usage 1>&2; fail "$@"; }
220
+cleanup() {
221
+	[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
222
+}
223
+
224
+getsize() {
225
+	local f="$1" size=""
226
+	size=$(ls -l "${f}" 2>/dev/null | awk '{print $5}') &&
227
+		[ -n "${size}" ] && _RET=${size} && return 0
228
+}
229
+checksize() {
230
+	getsize "$1" || return 1
231
+	[ "${_RET}" "$2" "$3" ]
232
+}
233
+
234
+mk_grub_rescue() {
235
+	local input=${1} output=${2}
236
+	local bdir="${TEMP_D}/bdir"
237
+	local err="${TEMP_D}/err"
238
+	local modules="configfile"
239
+	local modules=""
240
+	mkdir "${bdir}" &&
241
+		mkdir -p "${bdir}/boot/grub" &&
242
+		cp "${input}" "${bdir}/boot/grub/loader.img" &&
243
+		cat > "${bdir}/boot/grub/grub.cfg" <<EOF
244
+multiboot /boot/grub/loader.img
245
+boot
246
+EOF
247
+		[ $? -eq 0 ] || return
248
+		grub-mkrescue --output="${output}" \
249
+			${modules:+"--modules=${modules}"} "${bdir}" > "${err}" 2>&1 ||
250
+			{ cat "${err}" 1>&2; return 1; }
251
+}
252
+
253
+short_opts="h"
254
+long_opts="help"
255
+getopt_out=$(getopt --name "${0##*/}" \
256
+	--options "${short_opts}" --long "${long_opts}" -- "$@") &&
257
+	eval set -- "${getopt_out}" ||
258
+	bad_Usage
259
+
260
+mode="grub-rescue-floppy"
261
+while [ $# -ne 0 ]; do
262
+	cur=${1}; next=${2};
263
+	case "$cur" in
264
+		-h|--help) Usage; exit 0;;
265
+		--) shift; break;;
266
+	esac
267
+	shift;
268
+done
269
+
270
+[ $# -eq 2 ] || bad_Usage "must multiboot loader input and output file"
271
+
272
+TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/.${0##*/}.XXXXXX") ||
273
+	fail "failed to make tempd"
274
+trap cleanup EXIT
275
+
276
+loader=${1}
277
+output=${2}
278
+
279
+case "${mode}" in
280
+	grub-rescue-floppy)
281
+		mk_grub_rescue "${loader}" "${output}" ||
282
+			fail "failed to make rescue floppy"
283
+		checksize "${output}" -lt $((2880*1024)) ||
284
+			fail "output of mk_rescue was to large for floppy"
285
+		size=${_RET}
286
+		truncate --size 2880K "${output}" ||
287
+			fail "failed to pad ${output} to 2880K"
288
+		echo "created ${mode} loader in ${output} (payload $size)"
289
+		;;
290
+	grub-rescue-cdrom)
291
+		mk_grub_rescue "${loader}" "${output}" ||
292
+			fail "failed to make rescue cdrom"
293
+		echo "created ${mode} loader in ${output}"
294
+		;;
295
+esac
296
+
297
+[ $? -eq 0 ] || fail "failed to create loader"