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_bitops.h"
30
31 #define XEN_VER "xen-3.0"
32
33 /* ------------------------------------------------------------------------ */
34
log_callback(struct elf_binary * elf,void * caller_data,bool iserr,const char * fmt,va_list al)35 static void log_callback(struct elf_binary *elf, void *caller_data,
36 bool iserr, const char *fmt, va_list al) {
37 xc_interface *xch = caller_data;
38
39 xc_reportv(xch,
40 xch->dombuild_logger ? xch->dombuild_logger : xch->error_handler,
41 iserr ? XTL_ERROR : XTL_DETAIL,
42 iserr ? XC_INVALID_KERNEL : XC_ERROR_NONE,
43 fmt, al);
44 }
45
xc_elf_set_logfile(xc_interface * xch,struct elf_binary * elf,int verbose)46 void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf,
47 int verbose) {
48 elf_set_log(elf, log_callback, xch, verbose /* convert to bool */);
49 }
50
51 /* ------------------------------------------------------------------------ */
52
xc_dom_guest_type(struct xc_dom_image * dom,struct elf_binary * elf)53 static const char *xc_dom_guest_type(struct xc_dom_image *dom,
54 struct elf_binary *elf)
55 {
56 uint64_t machine = elf_uval(elf, elf->ehdr, e_machine);
57
58 if ( dom->container_type == XC_DOM_HVM_CONTAINER &&
59 dom->parms->phys_entry != UNSET_ADDR32 )
60 return "hvm-3.0-x86_32";
61 if ( dom->container_type == XC_DOM_HVM_CONTAINER )
62 {
63 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
64 "%s: image not capable of booting inside a HVM container",
65 __FUNCTION__);
66 return NULL;
67 }
68
69 switch ( machine )
70 {
71 case EM_386:
72 switch ( dom->parms->pae )
73 {
74 case XEN_PAE_BIMODAL:
75 if ( strstr(dom->xen_caps, "xen-3.0-x86_32p") )
76 return "xen-3.0-x86_32p";
77 return "xen-3.0-x86_32";
78 case XEN_PAE_EXTCR3:
79 case XEN_PAE_YES:
80 return "xen-3.0-x86_32p";
81 case XEN_PAE_NO:
82 default:
83 return "xen-3.0-x86_32";
84 }
85 case EM_X86_64:
86 return "xen-3.0-x86_64";
87 default:
88 xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
89 "%s: unknown image type %"PRIu64,
90 __FUNCTION__, machine);
91 return NULL;
92 }
93 }
94
95 /* ------------------------------------------------------------------------ */
96 /* parse elf binary */
97
check_elf_kernel(struct xc_dom_image * dom,bool verbose)98 static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose)
99 {
100 if ( dom->kernel_blob == NULL )
101 {
102 if ( verbose )
103 xc_dom_panic(dom->xch,
104 XC_INTERNAL_ERROR, "%s: no kernel image loaded",
105 __FUNCTION__);
106 return -EINVAL;
107 }
108
109 if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) )
110 {
111 if ( verbose )
112 xc_dom_panic(dom->xch,
113 XC_INVALID_KERNEL, "%s: kernel is not an ELF image",
114 __FUNCTION__);
115 return -EINVAL;
116 }
117 return 0;
118 }
119
xc_dom_probe_elf_kernel(struct xc_dom_image * dom)120 static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom)
121 {
122 struct elf_binary elf;
123 int rc;
124
125 rc = check_elf_kernel(dom, 0);
126 if ( rc != 0 )
127 return rc;
128
129 rc = elf_init(&elf, dom->kernel_blob, dom->kernel_size);
130 if ( rc != 0 )
131 return rc;
132
133 /*
134 * We need to check that it contains Xen ELFNOTES,
135 * or else we might be trying to load a plain ELF.
136 */
137 elf_parse_binary(&elf);
138 rc = elf_xen_parse(&elf, dom->parms,
139 dom->container_type == XC_DOM_HVM_CONTAINER);
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,
171 dom->container_type == XC_DOM_HVM_CONTAINER) != 0 )
172 {
173 rc = -EINVAL;
174 goto out;
175 }
176
177 if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms->f_required) )
178 {
179 xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not"
180 " support unprivileged (DomU) operation", __FUNCTION__);
181 rc = -EINVAL;
182 goto out;
183 }
184
185 /* find kernel segment */
186 dom->kernel_seg.vstart = dom->parms->virt_kstart;
187 dom->kernel_seg.vend = dom->parms->virt_kend;
188
189 dom->guest_type = xc_dom_guest_type(dom, elf);
190 if ( dom->guest_type == NULL )
191 return -EINVAL;
192 DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
193 __FUNCTION__, dom->guest_type,
194 dom->kernel_seg.vstart, dom->kernel_seg.vend);
195 rc = 0;
196 out:
197 if ( elf_check_broken(elf) )
198 DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
199 elf_check_broken(elf));
200
201 return rc;
202 }
203
xc_dom_load_elf_kernel(struct xc_dom_image * dom)204 static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom)
205 {
206 struct elf_binary *elf = dom->private_loader;
207 elf_errorstatus rc;
208 xen_pfn_t pages;
209
210 elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages);
211 if ( elf->dest_base == NULL )
212 {
213 DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)"
214 " => NULL", __FUNCTION__);
215 return -1;
216 }
217 elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
218
219 rc = elf_load_binary(elf);
220 if ( rc < 0 )
221 {
222 DOMPRINTF("%s: failed to load elf binary", __FUNCTION__);
223 return rc;
224 }
225 return 0;
226 }
227
228 /* ------------------------------------------------------------------------ */
229
230 struct xc_dom_loader elf_loader = {
231 .name = "ELF-generic",
232 .probe = xc_dom_probe_elf_kernel,
233 .parser = xc_dom_parse_elf_kernel,
234 .loader = xc_dom_load_elf_kernel,
235 };
236
register_loader(void)237 static void __init register_loader(void)
238 {
239 xc_dom_register_loader(&elf_loader);
240 }
241
242 /*
243 * Local variables:
244 * mode: C
245 * c-file-style: "BSD"
246 * c-basic-offset: 4
247 * tab-width: 4
248 * indent-tabs-mode: nil
249 * End:
250 */
251