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