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