1 /*
2 * Xen domain builder -- ELF bits.
3 *
4 * Parse and load ELF kernel images.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 *
19 * written 2006 by Gerd Hoffmann <kraxel@suse.de>.
20 *
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <inttypes.h>
27
28 #include "xg_private.h"
29 #include "xc_dom.h"
30 #include "xc_bitops.h"
31
32 #define XEN_VER "xen-3.0"
33
34 /* ------------------------------------------------------------------------ */
35
log_callback(struct elf_binary * elf,void * caller_data,bool iserr,const char * fmt,va_list al)36 static void log_callback(struct elf_binary *elf, void *caller_data,
37 bool iserr, const char *fmt, va_list al) {
38 xc_interface *xch = caller_data;
39
40 xc_reportv(xch,
41 xch->dombuild_logger ? xch->dombuild_logger : xch->error_handler,
42 iserr ? XTL_ERROR : XTL_DETAIL,
43 iserr ? XC_INVALID_KERNEL : XC_ERROR_NONE,
44 fmt, al);
45 }
46
xc_elf_set_logfile(xc_interface * xch,struct elf_binary * elf,int verbose)47 void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf,
48 int verbose) {
49 elf_set_log(elf, log_callback, xch, verbose /* convert to bool */);
50 }
51
52 /* ------------------------------------------------------------------------ */
53
xc_dom_guest_type(struct xc_dom_image * dom,struct elf_binary * elf)54 static char *xc_dom_guest_type(struct xc_dom_image *dom,
55 struct elf_binary *elf)
56 {
57 uint64_t machine = elf_uval(elf, elf->ehdr, e_machine);
58
59 if ( dom->container_type == XC_DOM_HVM_CONTAINER &&
60 dom->parms.phys_entry != UNSET_ADDR32 )
61 return "hvm-3.0-x86_32";
62 if ( dom->container_type == XC_DOM_HVM_CONTAINER )
63 {
64 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
65 "%s: image not capable of booting inside a HVM container",
66 __FUNCTION__);
67 return NULL;
68 }
69
70 switch ( machine )
71 {
72 case EM_386:
73 switch ( dom->parms.pae )
74 {
75 case XEN_PAE_BIMODAL:
76 if ( strstr(dom->xen_caps, "xen-3.0-x86_32p") )
77 return "xen-3.0-x86_32p";
78 return "xen-3.0-x86_32";
79 case XEN_PAE_EXTCR3:
80 case XEN_PAE_YES:
81 return "xen-3.0-x86_32p";
82 case XEN_PAE_NO:
83 default:
84 return "xen-3.0-x86_32";
85 }
86 case EM_X86_64:
87 return "xen-3.0-x86_64";
88 default:
89 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
90 "%s: unknown image type %"PRIu64,
91 __FUNCTION__, machine);
92 return NULL;
93 }
94 }
95
96 /* ------------------------------------------------------------------------ */
97 /* parse elf binary */
98
check_elf_kernel(struct xc_dom_image * dom,bool verbose)99 static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose)
100 {
101 if ( dom->kernel_blob == NULL )
102 {
103 if ( verbose )
104 xc_dom_panic(dom->xch,
105 XC_INTERNAL_ERROR, "%s: no kernel image loaded",
106 __FUNCTION__);
107 return -EINVAL;
108 }
109
110 if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) )
111 {
112 if ( verbose )
113 xc_dom_panic(dom->xch,
114 XC_INVALID_KERNEL, "%s: kernel is not an ELF image",
115 __FUNCTION__);
116 return -EINVAL;
117 }
118 return 0;
119 }
120
xc_dom_probe_elf_kernel(struct xc_dom_image * dom)121 static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom)
122 {
123 struct elf_binary elf;
124 int rc;
125
126 rc = check_elf_kernel(dom, 0);
127 if ( rc != 0 )
128 return rc;
129
130 rc = elf_init(&elf, dom->kernel_blob, dom->kernel_size);
131 if ( rc != 0 )
132 return rc;
133
134 /*
135 * We need to check that it contains Xen ELFNOTES,
136 * or else we might be trying to load a plain ELF.
137 */
138 elf_parse_binary(&elf);
139 rc = elf_xen_parse(&elf, &dom->parms);
140 if ( rc != 0 )
141 return rc;
142
143 return 0;
144 }
145
xc_dom_parse_elf_kernel(struct xc_dom_image * dom)146 static elf_negerrnoval xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
147 {
148 struct elf_binary *elf;
149 elf_negerrnoval rc;
150
151 rc = check_elf_kernel(dom, 1);
152 if ( rc != 0 )
153 return rc;
154
155 elf = xc_dom_malloc(dom, sizeof(*elf));
156 if ( elf == NULL )
157 return -ENOMEM;
158 dom->private_loader = elf;
159 rc = elf_init(elf, dom->kernel_blob, dom->kernel_size) != 0 ? -EINVAL : 0;
160 xc_elf_set_logfile(dom->xch, elf, 1);
161 if ( rc != 0 )
162 {
163 xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: corrupted ELF image",
164 __FUNCTION__);
165 return rc;
166 }
167
168 /* parse binary and get xen meta info */
169 elf_parse_binary(elf);
170 if ( elf_xen_parse(elf, &dom->parms) != 0 )
171 {
172 rc = -EINVAL;
173 goto out;
174 }
175
176 if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) )
177 {
178 xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not"
179 " support unprivileged (DomU) operation", __FUNCTION__);
180 rc = -EINVAL;
181 goto out;
182 }
183
184 /* find kernel segment */
185 dom->kernel_seg.vstart = dom->parms.virt_kstart;
186 dom->kernel_seg.vend = dom->parms.virt_kend;
187
188 dom->guest_type = xc_dom_guest_type(dom, elf);
189 if ( dom->guest_type == NULL )
190 return -EINVAL;
191 DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
192 __FUNCTION__, dom->guest_type,
193 dom->kernel_seg.vstart, dom->kernel_seg.vend);
194 rc = 0;
195 out:
196 if ( elf_check_broken(elf) )
197 DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
198 elf_check_broken(elf));
199
200 return rc;
201 }
202
xc_dom_load_elf_kernel(struct xc_dom_image * dom)203 static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom)
204 {
205 struct elf_binary *elf = dom->private_loader;
206 elf_errorstatus rc;
207 xen_pfn_t pages;
208
209 elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages);
210 if ( elf->dest_base == NULL )
211 {
212 DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)"
213 " => NULL", __FUNCTION__);
214 return -1;
215 }
216 elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
217
218 rc = elf_load_binary(elf);
219 if ( rc < 0 )
220 {
221 DOMPRINTF("%s: failed to load elf binary", __FUNCTION__);
222 return rc;
223 }
224 return 0;
225 }
226
227 /* ------------------------------------------------------------------------ */
228
229 struct xc_dom_loader elf_loader = {
230 .name = "ELF-generic",
231 .probe = xc_dom_probe_elf_kernel,
232 .parser = xc_dom_parse_elf_kernel,
233 .loader = xc_dom_load_elf_kernel,
234 };
235
register_loader(void)236 static void __init register_loader(void)
237 {
238 xc_dom_register_loader(&elf_loader);
239 }
240
241 /*
242 * Local variables:
243 * mode: C
244 * c-file-style: "BSD"
245 * c-basic-offset: 4
246 * tab-width: 4
247 * indent-tabs-mode: nil
248 * End:
249 */
250