1 /*
2 * reloc.c
3 *
4 * 32-bit flat memory-map routines for relocating Multiboot structures
5 * and modules. This is most easily done early with paging disabled.
6 *
7 * Copyright (c) 2009, Citrix Systems, Inc.
8 * Copyright (c) 2013-2016 Oracle and/or its affiliates. All rights reserved.
9 *
10 * Authors:
11 * Keir Fraser <keir@xen.org>
12 * Daniel Kiper <daniel.kiper@oracle.com>
13 */
14
15 /*
16 * This entry point is entered from xen/arch/x86/boot/head.S with:
17 * - 0x04(%esp) = MAGIC,
18 * - 0x08(%esp) = INFORMATION_ADDRESS,
19 * - 0x0c(%esp) = TOPMOST_LOW_MEMORY_STACK_ADDRESS.
20 * - 0x10(%esp) = BOOT_VIDEO_INFO_ADDRESS.
21 */
22 asm (
23 " .text \n"
24 " .globl _start \n"
25 "_start: \n"
26 " jmp reloc \n"
27 );
28
29 #include "defs.h"
30
31 #include <xen/kconfig.h>
32 #include <xen/multiboot.h>
33 #include <xen/multiboot2.h>
34
35 #include <public/arch-x86/hvm/start_info.h>
36
37 #ifdef CONFIG_VIDEO
38 # include "video.h"
39
40 /* VESA control information */
41 struct __packed vesa_ctrl_info {
42 uint8_t signature[4];
43 uint16_t version;
44 uint32_t oem_name;
45 uint32_t capabilities;
46 uint32_t mode_list;
47 uint16_t mem_size;
48 /* We don't use any further fields. */
49 };
50
51 /* VESA 2.0 mode information */
52 struct vesa_mode_info {
53 uint16_t attrib;
54 uint8_t window[14]; /* We don't use the individual fields. */
55 uint16_t bytes_per_line;
56 uint16_t width;
57 uint16_t height;
58 uint8_t cell_width;
59 uint8_t cell_height;
60 uint8_t nr_planes;
61 uint8_t depth;
62 uint8_t memory[5]; /* We don't use the individual fields. */
63 struct boot_video_colors colors;
64 uint8_t direct_color;
65 uint32_t base;
66 /* We don't use any further fields. */
67 };
68 #endif /* CONFIG_VIDEO */
69
70 #define get_mb2_data(tag, type, member) (((const multiboot2_tag_##type##_t *)(tag))->member)
71 #define get_mb2_string(tag, type, member) ((u32)get_mb2_data(tag, type, member))
72
73 static u32 alloc;
74
alloc_mem(u32 bytes)75 static u32 alloc_mem(u32 bytes)
76 {
77 return alloc -= ALIGN_UP(bytes, 16);
78 }
79
zero_mem(u32 s,u32 bytes)80 static void zero_mem(u32 s, u32 bytes)
81 {
82 while ( bytes-- )
83 *(char *)s++ = 0;
84 }
85
copy_mem(u32 src,u32 bytes)86 static u32 copy_mem(u32 src, u32 bytes)
87 {
88 u32 dst, dst_ret;
89
90 dst = alloc_mem(bytes);
91 dst_ret = dst;
92
93 while ( bytes-- )
94 *(char *)dst++ = *(char *)src++;
95
96 return dst_ret;
97 }
98
copy_string(u32 src)99 static u32 copy_string(u32 src)
100 {
101 u32 p;
102
103 if ( !src )
104 return 0;
105
106 for ( p = src; *(char *)p != '\0'; p++ )
107 continue;
108
109 return copy_mem(src, p - src + 1);
110 }
111
pvh_info_reloc(u32 in)112 static struct hvm_start_info *pvh_info_reloc(u32 in)
113 {
114 struct hvm_start_info *out;
115
116 out = _p(copy_mem(in, sizeof(*out)));
117
118 if ( out->cmdline_paddr )
119 out->cmdline_paddr = copy_string(out->cmdline_paddr);
120
121 if ( out->nr_modules )
122 {
123 unsigned int i;
124 struct hvm_modlist_entry *mods;
125
126 out->modlist_paddr =
127 copy_mem(out->modlist_paddr,
128 out->nr_modules * sizeof(struct hvm_modlist_entry));
129
130 mods = _p(out->modlist_paddr);
131
132 for ( i = 0; i < out->nr_modules; i++ )
133 {
134 if ( mods[i].cmdline_paddr )
135 mods[i].cmdline_paddr = copy_string(mods[i].cmdline_paddr);
136 }
137 }
138
139 return out;
140 }
141
mbi_reloc(u32 mbi_in)142 static multiboot_info_t *mbi_reloc(u32 mbi_in)
143 {
144 int i;
145 multiboot_info_t *mbi_out;
146
147 mbi_out = _p(copy_mem(mbi_in, sizeof(*mbi_out)));
148
149 if ( mbi_out->flags & MBI_CMDLINE )
150 mbi_out->cmdline = copy_string(mbi_out->cmdline);
151
152 if ( mbi_out->flags & MBI_MODULES )
153 {
154 module_t *mods;
155
156 mbi_out->mods_addr = copy_mem(mbi_out->mods_addr,
157 mbi_out->mods_count * sizeof(module_t));
158
159 mods = _p(mbi_out->mods_addr);
160
161 for ( i = 0; i < mbi_out->mods_count; i++ )
162 {
163 if ( mods[i].string )
164 mods[i].string = copy_string(mods[i].string);
165 }
166 }
167
168 if ( mbi_out->flags & MBI_MEMMAP )
169 mbi_out->mmap_addr = copy_mem(mbi_out->mmap_addr, mbi_out->mmap_length);
170
171 if ( mbi_out->flags & MBI_LOADERNAME )
172 mbi_out->boot_loader_name = copy_string(mbi_out->boot_loader_name);
173
174 /* Mask features we don't understand or don't relocate. */
175 mbi_out->flags &= (MBI_MEMLIMITS |
176 MBI_CMDLINE |
177 MBI_MODULES |
178 MBI_MEMMAP |
179 MBI_LOADERNAME);
180
181 return mbi_out;
182 }
183
mbi2_reloc(uint32_t mbi_in,uint32_t video_out)184 static multiboot_info_t *mbi2_reloc(uint32_t mbi_in, uint32_t video_out)
185 {
186 const multiboot2_fixed_t *mbi_fix = _p(mbi_in);
187 const multiboot2_memory_map_t *mmap_src;
188 const multiboot2_tag_t *tag;
189 module_t *mbi_out_mods = NULL;
190 memory_map_t *mmap_dst;
191 multiboot_info_t *mbi_out;
192 #ifdef CONFIG_VIDEO
193 struct boot_video_info *video = NULL;
194 #endif
195 u32 ptr;
196 unsigned int i, mod_idx = 0;
197
198 ptr = alloc_mem(sizeof(*mbi_out));
199 mbi_out = _p(ptr);
200 zero_mem(ptr, sizeof(*mbi_out));
201
202 /* Skip Multiboot2 information fixed part. */
203 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
204
205 /* Get the number of modules. */
206 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
207 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
208 {
209 if ( tag->type == MULTIBOOT2_TAG_TYPE_MODULE )
210 ++mbi_out->mods_count;
211 else if ( tag->type == MULTIBOOT2_TAG_TYPE_END )
212 break;
213 }
214
215 if ( mbi_out->mods_count )
216 {
217 mbi_out->flags |= MBI_MODULES;
218 /*
219 * We have to allocate one more module slot here. At some point
220 * __start_xen() may put Xen image placement into it.
221 */
222 mbi_out->mods_addr = alloc_mem((mbi_out->mods_count + 1) *
223 sizeof(*mbi_out_mods));
224 mbi_out_mods = _p(mbi_out->mods_addr);
225 }
226
227 /* Skip Multiboot2 information fixed part. */
228 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
229
230 /* Put all needed data into mbi_out. */
231 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
232 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
233 {
234 switch ( tag->type )
235 {
236 case MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME:
237 mbi_out->flags |= MBI_LOADERNAME;
238 ptr = get_mb2_string(tag, string, string);
239 mbi_out->boot_loader_name = copy_string(ptr);
240 break;
241
242 case MULTIBOOT2_TAG_TYPE_CMDLINE:
243 mbi_out->flags |= MBI_CMDLINE;
244 ptr = get_mb2_string(tag, string, string);
245 mbi_out->cmdline = copy_string(ptr);
246 break;
247
248 case MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO:
249 mbi_out->flags |= MBI_MEMLIMITS;
250 mbi_out->mem_lower = get_mb2_data(tag, basic_meminfo, mem_lower);
251 mbi_out->mem_upper = get_mb2_data(tag, basic_meminfo, mem_upper);
252 break;
253
254 case MULTIBOOT2_TAG_TYPE_MMAP:
255 if ( get_mb2_data(tag, mmap, entry_size) < sizeof(*mmap_src) )
256 break;
257
258 mbi_out->flags |= MBI_MEMMAP;
259 mbi_out->mmap_length = get_mb2_data(tag, mmap, size);
260 mbi_out->mmap_length -= sizeof(multiboot2_tag_mmap_t);
261 mbi_out->mmap_length /= get_mb2_data(tag, mmap, entry_size);
262 mbi_out->mmap_length *= sizeof(*mmap_dst);
263
264 mbi_out->mmap_addr = alloc_mem(mbi_out->mmap_length);
265
266 mmap_src = get_mb2_data(tag, mmap, entries);
267 mmap_dst = _p(mbi_out->mmap_addr);
268
269 for ( i = 0; i < mbi_out->mmap_length / sizeof(*mmap_dst); i++ )
270 {
271 /* Init size member properly. */
272 mmap_dst[i].size = sizeof(*mmap_dst);
273 mmap_dst[i].size -= sizeof(mmap_dst[i].size);
274 /* Now copy a given region data. */
275 mmap_dst[i].base_addr_low = (u32)mmap_src->addr;
276 mmap_dst[i].base_addr_high = (u32)(mmap_src->addr >> 32);
277 mmap_dst[i].length_low = (u32)mmap_src->len;
278 mmap_dst[i].length_high = (u32)(mmap_src->len >> 32);
279 mmap_dst[i].type = mmap_src->type;
280 mmap_src = _p(mmap_src) + get_mb2_data(tag, mmap, entry_size);
281 }
282 break;
283
284 case MULTIBOOT2_TAG_TYPE_MODULE:
285 if ( mod_idx >= mbi_out->mods_count )
286 break;
287
288 mbi_out_mods[mod_idx].mod_start = get_mb2_data(tag, module, mod_start);
289 mbi_out_mods[mod_idx].mod_end = get_mb2_data(tag, module, mod_end);
290 ptr = get_mb2_string(tag, module, cmdline);
291 mbi_out_mods[mod_idx].string = copy_string(ptr);
292 mbi_out_mods[mod_idx].reserved = 0;
293 ++mod_idx;
294 break;
295
296 #ifdef CONFIG_VIDEO
297 case MULTIBOOT2_TAG_TYPE_VBE:
298 if ( video_out )
299 {
300 const struct vesa_ctrl_info *ci;
301 const struct vesa_mode_info *mi;
302
303 video = _p(video_out);
304 ci = (const void *)get_mb2_data(tag, vbe, vbe_control_info);
305 mi = (const void *)get_mb2_data(tag, vbe, vbe_mode_info);
306
307 if ( ci->version >= 0x0200 && (mi->attrib & 0x9b) == 0x9b )
308 {
309 video->capabilities = ci->capabilities;
310 video->lfb_linelength = mi->bytes_per_line;
311 video->lfb_width = mi->width;
312 video->lfb_height = mi->height;
313 video->lfb_depth = mi->depth;
314 video->lfb_base = mi->base;
315 video->lfb_size = ci->mem_size;
316 video->colors = mi->colors;
317 video->vesa_attrib = mi->attrib;
318 }
319
320 video->vesapm.seg = get_mb2_data(tag, vbe, vbe_interface_seg);
321 video->vesapm.off = get_mb2_data(tag, vbe, vbe_interface_off);
322 }
323 break;
324
325 case MULTIBOOT2_TAG_TYPE_FRAMEBUFFER:
326 if ( (get_mb2_data(tag, framebuffer, framebuffer_type) !=
327 MULTIBOOT2_FRAMEBUFFER_TYPE_RGB) )
328 {
329 video_out = 0;
330 video = NULL;
331 }
332 break;
333 #endif /* CONFIG_VIDEO */
334
335 case MULTIBOOT2_TAG_TYPE_END:
336 goto end;
337
338 default:
339 break;
340 }
341 }
342
343 end:
344
345 #ifdef CONFIG_VIDEO
346 if ( video )
347 video->orig_video_isVGA = 0x23;
348 #endif
349
350 return mbi_out;
351 }
352
353 /* SAF-1-safe */
reloc(uint32_t magic,uint32_t in,uint32_t trampoline,uint32_t video_info)354 void *__stdcall reloc(uint32_t magic, uint32_t in, uint32_t trampoline,
355 uint32_t video_info)
356 {
357 alloc = trampoline;
358
359 switch ( magic )
360 {
361 case MULTIBOOT_BOOTLOADER_MAGIC:
362 return mbi_reloc(in);
363
364 case MULTIBOOT2_BOOTLOADER_MAGIC:
365 return mbi2_reloc(in, video_info);
366
367 case XEN_HVM_START_MAGIC_VALUE:
368 if ( IS_ENABLED(CONFIG_PVH_GUEST) )
369 return pvh_info_reloc(in);
370 /* Fallthrough */
371
372 default:
373 /* Nothing we can do */
374 return NULL;
375 }
376 }
377
378 /*
379 * Local variables:
380 * mode: C
381 * c-file-style: "BSD"
382 * c-basic-offset: 4
383 * tab-width: 4
384 * indent-tabs-mode: nil
385 * End:
386 */
387