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