1 /*
2 * Xen domain builder -- ARM zImage bits
3 *
4 * Parse and load ARM zImage kernel images.
5 *
6 * Copyright (C) 2012, Citrix Systems.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation;
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26
27 #include "xg_private.h"
28 #include "xc_dom.h"
29
30 #include <arpa/inet.h> /* XXX ntohl is not the right function... */
31
32 struct minimal_dtb_header {
33 uint32_t magic;
34 uint32_t total_size;
35 /* There are other fields but we don't use them yet. */
36 };
37
38 #define DTB_MAGIC 0xd00dfeed
39
40 /* ------------------------------------------------------------ */
41 /* 32-bit zImage Support */
42 /* ------------------------------------------------------------ */
43
44 #define ZIMAGE32_MAGIC_OFFSET 0x24
45 #define ZIMAGE32_START_OFFSET 0x28
46 #define ZIMAGE32_END_OFFSET 0x2c
47
48 #define ZIMAGE32_MAGIC 0x016f2818
49
xc_dom_probe_zimage32_kernel(struct xc_dom_image * dom)50 static int xc_dom_probe_zimage32_kernel(struct xc_dom_image *dom)
51 {
52 uint32_t *zimage;
53
54 if ( dom->kernel_blob == NULL )
55 {
56 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
57 "%s: no kernel image loaded", __FUNCTION__);
58 return -EINVAL;
59 }
60
61 if ( dom->kernel_size < 0x30 /*sizeof(struct setup_header)*/ )
62 {
63 xc_dom_printf(dom->xch, "%s: kernel image too small", __FUNCTION__);
64 return -EINVAL;
65 }
66
67 zimage = (uint32_t *)dom->kernel_blob;
68 if ( zimage[ZIMAGE32_MAGIC_OFFSET/4] != ZIMAGE32_MAGIC )
69 {
70 xc_dom_printf(dom->xch, "%s: kernel is not an arm32 zImage", __FUNCTION__);
71 return -EINVAL;
72 }
73
74 return 0;
75 }
76
xc_dom_parse_zimage32_kernel(struct xc_dom_image * dom)77 static int xc_dom_parse_zimage32_kernel(struct xc_dom_image *dom)
78 {
79 uint32_t *zimage;
80 uint32_t start, entry_addr;
81 uint64_t v_start, v_end;
82 uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT;
83
84 DOMPRINTF_CALLED(dom->xch);
85
86 zimage = (uint32_t *)dom->kernel_blob;
87
88 /* Do not load kernel at the very first RAM address */
89 v_start = rambase + 0x8000;
90
91 if ( dom->kernel_size > UINT64_MAX - v_start )
92 {
93 DOMPRINTF("%s: kernel is too large\n", __FUNCTION__);
94 return -EINVAL;
95 }
96
97 v_end = v_start + dom->kernel_size;
98
99 /*
100 * If start is invalid then the guest will start at some invalid
101 * address and crash, but this happens in guest context so doesn't
102 * concern us here.
103 */
104 start = zimage[ZIMAGE32_START_OFFSET/4];
105
106 if (start == 0)
107 entry_addr = v_start;
108 else
109 entry_addr = start;
110
111 /* find kernel segment */
112 dom->kernel_seg.vstart = v_start;
113 dom->kernel_seg.vend = v_end;
114
115 dom->parms.virt_entry = entry_addr;
116 dom->parms.virt_base = rambase;
117
118 dom->guest_type = "xen-3.0-armv7l";
119 DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
120 __FUNCTION__, dom->guest_type,
121 dom->kernel_seg.vstart, dom->kernel_seg.vend);
122 return 0;
123 }
124
125 /* ------------------------------------------------------------ */
126 /* 64-bit zImage Support */
127 /* ------------------------------------------------------------ */
128
129 #define ZIMAGE64_MAGIC_V0 0x14000008
130 #define ZIMAGE64_MAGIC_V1 0x644d5241 /* "ARM\x64" */
131
132 /* linux/Documentation/arm64/booting.txt */
133 struct zimage64_hdr {
134 uint32_t magic0;
135 uint32_t res0;
136 uint64_t text_offset; /* Image load offset */
137 uint64_t res1;
138 uint64_t res2;
139 /* zImage V1 only from here */
140 uint64_t res3;
141 uint64_t res4;
142 uint64_t res5;
143 uint32_t magic1;
144 uint32_t res6;
145 };
xc_dom_probe_zimage64_kernel(struct xc_dom_image * dom)146 static int xc_dom_probe_zimage64_kernel(struct xc_dom_image *dom)
147 {
148 struct zimage64_hdr *zimage;
149
150 if ( dom->kernel_blob == NULL )
151 {
152 xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
153 "%s: no kernel image loaded", __FUNCTION__);
154 return -EINVAL;
155 }
156
157 if ( dom->kernel_size < sizeof(*zimage) )
158 {
159 xc_dom_printf(dom->xch, "%s: kernel image too small", __FUNCTION__);
160 return -EINVAL;
161 }
162
163 zimage = dom->kernel_blob;
164 if ( zimage->magic0 != ZIMAGE64_MAGIC_V0 &&
165 zimage->magic1 != ZIMAGE64_MAGIC_V1 )
166 {
167 xc_dom_printf(dom->xch, "%s: kernel is not an arm64 Image", __FUNCTION__);
168 return -EINVAL;
169 }
170
171 return 0;
172 }
173
xc_dom_parse_zimage64_kernel(struct xc_dom_image * dom)174 static int xc_dom_parse_zimage64_kernel(struct xc_dom_image *dom)
175 {
176 struct zimage64_hdr *zimage;
177 uint64_t v_start, v_end;
178 uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT;
179
180 DOMPRINTF_CALLED(dom->xch);
181
182 zimage = dom->kernel_blob;
183
184 if ( zimage->text_offset > UINT64_MAX - rambase )
185 {
186 DOMPRINTF("%s: kernel text offset is too large\n", __FUNCTION__);
187 return -EINVAL;
188 }
189
190 v_start = rambase + zimage->text_offset;
191
192 if ( dom->kernel_size > UINT64_MAX - v_start )
193 {
194 DOMPRINTF("%s: kernel is too large\n", __FUNCTION__);
195 return -EINVAL;
196 }
197
198 v_end = v_start + dom->kernel_size;
199
200 dom->kernel_seg.vstart = v_start;
201 dom->kernel_seg.vend = v_end;
202
203 /* Call the kernel at offset 0 */
204 dom->parms.virt_entry = v_start;
205 dom->parms.virt_base = rambase;
206
207 dom->guest_type = "xen-3.0-aarch64";
208 DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
209 __FUNCTION__, dom->guest_type,
210 dom->kernel_seg.vstart, dom->kernel_seg.vend);
211
212 return 0;
213 }
214
215 /* ------------------------------------------------------------ */
216 /* Common zImage Support */
217 /* ------------------------------------------------------------ */
218
xc_dom_load_zimage_kernel(struct xc_dom_image * dom)219 static int xc_dom_load_zimage_kernel(struct xc_dom_image *dom)
220 {
221 void *dst;
222
223 DOMPRINTF_CALLED(dom->xch);
224
225 dst = xc_dom_seg_to_ptr(dom, &dom->kernel_seg);
226 if ( dst == NULL )
227 {
228 DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->kernel_seg) => NULL",
229 __func__);
230 return -1;
231 }
232
233 DOMPRINTF("%s: kernel seg %#"PRIx64"-%#"PRIx64,
234 __func__, dom->kernel_seg.vstart, dom->kernel_seg.vend);
235 DOMPRINTF("%s: copy %zd bytes from blob %p to dst %p",
236 __func__, dom->kernel_size, dom->kernel_blob, dst);
237
238 memcpy(dst, dom->kernel_blob, dom->kernel_size);
239
240 return 0;
241 }
242
243 static struct xc_dom_loader zimage32_loader = {
244 .name = "Linux zImage (ARM32)",
245 .probe = xc_dom_probe_zimage32_kernel,
246 .parser = xc_dom_parse_zimage32_kernel,
247 .loader = xc_dom_load_zimage_kernel,
248 };
249
250 static struct xc_dom_loader zimage64_loader = {
251 .name = "Linux zImage (ARM64)",
252 .probe = xc_dom_probe_zimage64_kernel,
253 .parser = xc_dom_parse_zimage64_kernel,
254 .loader = xc_dom_load_zimage_kernel,
255 };
256
register_loader(void)257 static void __init register_loader(void)
258 {
259 xc_dom_register_loader(&zimage32_loader);
260 xc_dom_register_loader(&zimage64_loader);
261 }
262
263 /*
264 * Local variables:
265 * mode: C
266 * c-file-style: "BSD"
267 * c-basic-offset: 4
268 * tab-width: 4
269 * indent-tabs-mode: nil
270 * End:
271 */
272