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