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 "xen-3.0-unknown";
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         return "xen-3.0-unknown";
90     }
91 }
92 
93 /* ------------------------------------------------------------------------ */
94 /* parse elf binary                                                         */
95 
check_elf_kernel(struct xc_dom_image * dom,bool verbose)96 static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose)
97 {
98     if ( dom->kernel_blob == NULL )
99     {
100         if ( verbose )
101             xc_dom_panic(dom->xch,
102                          XC_INTERNAL_ERROR, "%s: no kernel image loaded",
103                          __FUNCTION__);
104         return -EINVAL;
105     }
106 
107     if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) )
108     {
109         if ( verbose )
110             xc_dom_panic(dom->xch,
111                          XC_INVALID_KERNEL, "%s: kernel is not an ELF image",
112                          __FUNCTION__);
113         return -EINVAL;
114     }
115     return 0;
116 }
117 
xc_dom_probe_elf_kernel(struct xc_dom_image * dom)118 static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom)
119 {
120     struct elf_binary elf;
121     int rc;
122 
123     rc = check_elf_kernel(dom, 0);
124     if ( rc != 0 )
125         return rc;
126 
127     rc = elf_init(&elf, dom->kernel_blob, dom->kernel_size);
128     if ( rc != 0 )
129         return rc;
130 
131     /*
132      * We need to check that it contains Xen ELFNOTES,
133      * or else we might be trying to load a plain ELF.
134      */
135     elf_parse_binary(&elf);
136     rc = elf_xen_parse(&elf, &dom->parms);
137     if ( rc != 0 )
138         return rc;
139 
140     return 0;
141 }
142 
xc_dom_parse_elf_kernel(struct xc_dom_image * dom)143 static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
144     /*
145      * This function sometimes returns -1 for error and sometimes
146      * an errno value.  ?!?!
147      */
148 {
149     struct elf_binary *elf;
150     elf_errorstatus rc;
151 
152     rc = check_elf_kernel(dom, 1);
153     if ( rc != 0 )
154         return rc;
155 
156     elf = xc_dom_malloc(dom, sizeof(*elf));
157     if ( elf == NULL )
158         return -1;
159     dom->private_loader = elf;
160     rc = elf_init(elf, dom->kernel_blob, dom->kernel_size);
161     xc_elf_set_logfile(dom->xch, elf, 1);
162     if ( rc != 0 )
163     {
164         xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: corrupted ELF image",
165                      __FUNCTION__);
166         return rc;
167     }
168 
169     /* Find the section-header strings table. */
170     if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
171     {
172         xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: ELF image"
173                      " has no shstrtab", __FUNCTION__);
174         rc = -EINVAL;
175         goto out;
176     }
177 
178     /* parse binary and get xen meta info */
179     elf_parse_binary(elf);
180     if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 )
181     {
182         goto out;
183     }
184 
185     if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) )
186     {
187         xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not"
188                      " support unprivileged (DomU) operation", __FUNCTION__);
189         rc = -EINVAL;
190         goto out;
191     }
192 
193     /* find kernel segment */
194     dom->kernel_seg.vstart = dom->parms.virt_kstart;
195     dom->kernel_seg.vend   = dom->parms.virt_kend;
196 
197     dom->guest_type = xc_dom_guest_type(dom, elf);
198     DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
199               __FUNCTION__, dom->guest_type,
200               dom->kernel_seg.vstart, dom->kernel_seg.vend);
201     rc = 0;
202 out:
203     if ( elf_check_broken(elf) )
204         DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
205                   elf_check_broken(elf));
206 
207     return rc;
208 }
209 
xc_dom_load_elf_kernel(struct xc_dom_image * dom)210 static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom)
211 {
212     struct elf_binary *elf = dom->private_loader;
213     elf_errorstatus rc;
214     xen_pfn_t pages;
215 
216     elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages);
217     if ( elf->dest_base == NULL )
218     {
219         DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)"
220                   " => NULL", __FUNCTION__);
221         return -1;
222     }
223     elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
224 
225     rc = elf_load_binary(elf);
226     if ( rc < 0 )
227     {
228         DOMPRINTF("%s: failed to load elf binary", __FUNCTION__);
229         return rc;
230     }
231     return 0;
232 }
233 
234 /* ------------------------------------------------------------------------ */
235 
236 struct xc_dom_loader elf_loader = {
237     .name = "ELF-generic",
238     .probe = xc_dom_probe_elf_kernel,
239     .parser = xc_dom_parse_elf_kernel,
240     .loader = xc_dom_load_elf_kernel,
241 };
242 
register_loader(void)243 static void __init register_loader(void)
244 {
245     xc_dom_register_loader(&elf_loader);
246 }
247 
248 /*
249  * Local variables:
250  * mode: C
251  * c-file-style: "BSD"
252  * c-basic-offset: 4
253  * tab-width: 4
254  * indent-tabs-mode: nil
255  * End:
256  */
257