1 /*
2  * Xen domain builder -- HVM specific bits.
3  *
4  * Parse and load ELF firmware images for HVM domains.
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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <inttypes.h>
26 #include <assert.h>
27 
28 #include "xg_private.h"
29 #include "xc_dom.h"
30 #include "xc_bitops.h"
31 
32 /* ------------------------------------------------------------------------ */
33 /* parse elf binary                                                         */
34 
check_elf_kernel(struct xc_dom_image * dom,bool verbose)35 static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose)
36 {
37     if ( dom->kernel_blob == NULL )
38     {
39         if ( verbose )
40             xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
41                          "%s: no kernel image loaded", __func__);
42         return -EINVAL;
43     }
44 
45     if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) )
46     {
47         if ( verbose )
48             xc_dom_panic(dom->xch, XC_INVALID_KERNEL,
49                          "%s: kernel is not an ELF image", __func__);
50         return -EINVAL;
51     }
52     return 0;
53 }
54 
xc_dom_probe_hvm_kernel(struct xc_dom_image * dom)55 static elf_negerrnoval xc_dom_probe_hvm_kernel(struct xc_dom_image *dom)
56 {
57     struct elf_binary elf;
58     int rc;
59 
60     /* This loader is designed for HVM guest firmware. */
61     if ( dom->container_type != XC_DOM_HVM_CONTAINER )
62         return -EINVAL;
63 
64     rc = check_elf_kernel(dom, 0);
65     if ( rc != 0 )
66         return rc;
67 
68     rc = elf_init(&elf, dom->kernel_blob, dom->kernel_size);
69     if ( rc != 0 )
70         return rc;
71 
72     /*
73      * We need to check that there are no Xen ELFNOTES, or
74      * else we might be trying to load a PV kernel.
75      */
76     elf_parse_binary(&elf);
77     rc = elf_xen_parse(&elf, &dom->parms);
78     if ( rc == 0 )
79         return -EINVAL;
80 
81     return 0;
82 }
83 
xc_dom_parse_hvm_kernel(struct xc_dom_image * dom)84 static elf_errorstatus xc_dom_parse_hvm_kernel(struct xc_dom_image *dom)
85     /*
86      * This function sometimes returns -1 for error and sometimes
87      * an errno value.  ?!?!
88      */
89 {
90     struct elf_binary *elf;
91     elf_errorstatus rc;
92 
93     rc = check_elf_kernel(dom, 1);
94     if ( rc != 0 )
95         return rc;
96 
97     elf = xc_dom_malloc(dom, sizeof(*elf));
98     if ( elf == NULL )
99         return -1;
100     dom->private_loader = elf;
101     rc = elf_init(elf, dom->kernel_blob, dom->kernel_size);
102     xc_elf_set_logfile(dom->xch, elf, 1);
103     if ( rc != 0 )
104     {
105         xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: corrupted ELF image",
106                      __func__);
107         return rc;
108     }
109 
110     if ( !elf_32bit(elf) )
111     {
112         xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: ELF image is not 32bit",
113                      __func__);
114         return -EINVAL;
115     }
116 
117     /* parse binary and get xen meta info */
118     elf_parse_binary(elf);
119 
120     /* find kernel segment */
121     dom->kernel_seg.vstart = elf->pstart;
122     dom->kernel_seg.vend   = elf->pend;
123 
124     dom->guest_type = "hvm-3.0-x86_32";
125 
126     if ( elf_check_broken(elf) )
127         DOMPRINTF("%s: ELF broken: %s", __func__, elf_check_broken(elf));
128 
129     return rc;
130 }
131 
module_init_one(struct xc_dom_image * dom,struct xc_hvm_firmware_module * module,char * name)132 static int module_init_one(struct xc_dom_image *dom,
133                            struct xc_hvm_firmware_module *module,
134                            char *name)
135 {
136     struct xc_dom_seg seg;
137     void *dest;
138 
139     if ( module->length )
140     {
141         if ( xc_dom_alloc_segment(dom, &seg, name, 0, module->length) )
142             goto err;
143         dest = xc_dom_seg_to_ptr(dom, &seg);
144         if ( dest == NULL )
145         {
146             DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &seg) => NULL",
147                       __FUNCTION__);
148             goto err;
149         }
150         memcpy(dest, module->data, module->length);
151         module->guest_addr_out = seg.vstart;
152 
153         assert(dom->mmio_start > 0 && dom->mmio_start < UINT32_MAX);
154         if ( module->guest_addr_out > dom->mmio_start ||
155              module->guest_addr_out + module->length > dom->mmio_start )
156         {
157             DOMPRINTF("%s: Module %s would be loaded abrove 4GB",
158                       __FUNCTION__, name);
159             goto err;
160         }
161     }
162 
163     return 0;
164 err:
165     return -1;
166 }
167 
modules_init(struct xc_dom_image * dom)168 static int modules_init(struct xc_dom_image *dom)
169 {
170     int rc;
171 
172     rc = module_init_one(dom, &dom->system_firmware_module,
173                          "System Firmware module");
174     if ( rc ) goto err;
175     /* Only one module can be added */
176     rc = module_init_one(dom, &dom->acpi_modules[0], "ACPI module");
177     if ( rc ) goto err;
178     rc = module_init_one(dom, &dom->smbios_module, "SMBIOS module");
179     if ( rc ) goto err;
180 
181     return 0;
182 err:
183     return -1;
184 }
185 
xc_dom_load_hvm_kernel(struct xc_dom_image * dom)186 static elf_errorstatus xc_dom_load_hvm_kernel(struct xc_dom_image *dom)
187 {
188     struct elf_binary *elf = dom->private_loader;
189     privcmd_mmap_entry_t *entries = NULL;
190     size_t pages = (elf->pend - elf->pstart + PAGE_SIZE - 1) >> PAGE_SHIFT;
191     elf_errorstatus rc;
192     int i;
193 
194     /* Map address space for initial elf image. */
195     entries = calloc(pages, sizeof(privcmd_mmap_entry_t));
196     if ( entries == NULL )
197         return -ENOMEM;
198 
199     for ( i = 0; i < pages; i++ )
200         entries[i].mfn = (elf->pstart >> PAGE_SHIFT) + i;
201 
202     elf->dest_base = xc_map_foreign_ranges(
203         dom->xch, dom->guest_domid, pages << PAGE_SHIFT,
204         PROT_READ | PROT_WRITE, 1 << PAGE_SHIFT,
205         entries, pages);
206     if ( elf->dest_base == NULL )
207     {
208         DOMPRINTF("%s: unable to map guest memory space", __func__);
209         rc = -EFAULT;
210         goto error;
211     }
212 
213     elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
214 
215     rc = elf_load_binary(elf);
216     if ( rc < 0 )
217     {
218         DOMPRINTF("%s: failed to load elf binary", __func__);
219         goto error;
220     }
221 
222     munmap(elf->dest_base, elf->dest_size);
223 
224     rc = modules_init(dom);
225     if ( rc != 0 )
226     {
227         DOMPRINTF("%s: unable to load modules.", __func__);
228         goto error;
229     }
230 
231     dom->parms.phys_entry = elf_uval(elf, elf->ehdr, e_entry);
232 
233     free(entries);
234     return 0;
235 
236  error:
237     assert(rc != 0);
238     free(entries);
239     return rc;
240 }
241 
242 /* ------------------------------------------------------------------------ */
243 
244 struct xc_dom_loader hvm_loader = {
245     .name = "HVM-generic",
246     .probe = xc_dom_probe_hvm_kernel,
247     .parser = xc_dom_parse_hvm_kernel,
248     .loader = xc_dom_load_hvm_kernel,
249 };
250 
register_loader(void)251 static void __init register_loader(void)
252 {
253     xc_dom_register_loader(&hvm_loader);
254 }
255 
256 /*
257  * Local variables:
258  * mode: C
259  * c-file-style: "BSD"
260  * c-basic-offset: 4
261  * tab-width: 4
262  * indent-tabs-mode: nil
263  * End:
264  */
265