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 * - 0x4(%esp) = MAGIC,
18 * - 0x8(%esp) = INFORMATION_ADDRESS,
19 * - 0xc(%esp) = TOPMOST_LOW_MEMORY_STACK_ADDRESS.
20 */
21 asm (
22 " .text \n"
23 " .globl _start \n"
24 "_start: \n"
25 " jmp reloc \n"
26 );
27
28 #include "defs.h"
29 #include "../../../include/xen/multiboot.h"
30 #include "../../../include/xen/multiboot2.h"
31
32 #include "../../../include/xen/kconfig.h"
33 #include <public/arch-x86/hvm/start_info.h>
34
35 #define get_mb2_data(tag, type, member) (((multiboot2_tag_##type##_t *)(tag))->member)
36 #define get_mb2_string(tag, type, member) ((u32)get_mb2_data(tag, type, member))
37
38 static u32 alloc;
39
alloc_mem(u32 bytes)40 static u32 alloc_mem(u32 bytes)
41 {
42 return alloc -= ALIGN_UP(bytes, 16);
43 }
44
zero_mem(u32 s,u32 bytes)45 static void zero_mem(u32 s, u32 bytes)
46 {
47 while ( bytes-- )
48 *(char *)s++ = 0;
49 }
50
copy_mem(u32 src,u32 bytes)51 static u32 copy_mem(u32 src, u32 bytes)
52 {
53 u32 dst, dst_ret;
54
55 dst = alloc_mem(bytes);
56 dst_ret = dst;
57
58 while ( bytes-- )
59 *(char *)dst++ = *(char *)src++;
60
61 return dst_ret;
62 }
63
copy_string(u32 src)64 static u32 copy_string(u32 src)
65 {
66 u32 p;
67
68 if ( !src )
69 return 0;
70
71 for ( p = src; *(char *)p != '\0'; p++ )
72 continue;
73
74 return copy_mem(src, p - src + 1);
75 }
76
pvh_info_reloc(u32 in)77 static struct hvm_start_info *pvh_info_reloc(u32 in)
78 {
79 struct hvm_start_info *out;
80
81 out = _p(copy_mem(in, sizeof(*out)));
82
83 if ( out->cmdline_paddr )
84 out->cmdline_paddr = copy_string(out->cmdline_paddr);
85
86 if ( out->nr_modules )
87 {
88 unsigned int i;
89 struct hvm_modlist_entry *mods;
90
91 out->modlist_paddr =
92 copy_mem(out->modlist_paddr,
93 out->nr_modules * sizeof(struct hvm_modlist_entry));
94
95 mods = _p(out->modlist_paddr);
96
97 for ( i = 0; i < out->nr_modules; i++ )
98 {
99 if ( mods[i].cmdline_paddr )
100 mods[i].cmdline_paddr = copy_string(mods[i].cmdline_paddr);
101 }
102 }
103
104 return out;
105 }
106
mbi_reloc(u32 mbi_in)107 static multiboot_info_t *mbi_reloc(u32 mbi_in)
108 {
109 int i;
110 multiboot_info_t *mbi_out;
111
112 mbi_out = _p(copy_mem(mbi_in, sizeof(*mbi_out)));
113
114 if ( mbi_out->flags & MBI_CMDLINE )
115 mbi_out->cmdline = copy_string(mbi_out->cmdline);
116
117 if ( mbi_out->flags & MBI_MODULES )
118 {
119 module_t *mods;
120
121 mbi_out->mods_addr = copy_mem(mbi_out->mods_addr,
122 mbi_out->mods_count * sizeof(module_t));
123
124 mods = _p(mbi_out->mods_addr);
125
126 for ( i = 0; i < mbi_out->mods_count; i++ )
127 {
128 if ( mods[i].string )
129 mods[i].string = copy_string(mods[i].string);
130 }
131 }
132
133 if ( mbi_out->flags & MBI_MEMMAP )
134 mbi_out->mmap_addr = copy_mem(mbi_out->mmap_addr, mbi_out->mmap_length);
135
136 if ( mbi_out->flags & MBI_LOADERNAME )
137 mbi_out->boot_loader_name = copy_string(mbi_out->boot_loader_name);
138
139 /* Mask features we don't understand or don't relocate. */
140 mbi_out->flags &= (MBI_MEMLIMITS |
141 MBI_CMDLINE |
142 MBI_MODULES |
143 MBI_MEMMAP |
144 MBI_LOADERNAME);
145
146 return mbi_out;
147 }
148
mbi2_reloc(u32 mbi_in)149 static multiboot_info_t *mbi2_reloc(u32 mbi_in)
150 {
151 const multiboot2_fixed_t *mbi_fix = _p(mbi_in);
152 const multiboot2_memory_map_t *mmap_src;
153 const multiboot2_tag_t *tag;
154 module_t *mbi_out_mods = NULL;
155 memory_map_t *mmap_dst;
156 multiboot_info_t *mbi_out;
157 u32 ptr;
158 unsigned int i, mod_idx = 0;
159
160 ptr = alloc_mem(sizeof(*mbi_out));
161 mbi_out = _p(ptr);
162 zero_mem(ptr, sizeof(*mbi_out));
163
164 /* Skip Multiboot2 information fixed part. */
165 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
166
167 /* Get the number of modules. */
168 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
169 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
170 {
171 if ( tag->type == MULTIBOOT2_TAG_TYPE_MODULE )
172 ++mbi_out->mods_count;
173 else if ( tag->type == MULTIBOOT2_TAG_TYPE_END )
174 break;
175 }
176
177 if ( mbi_out->mods_count )
178 {
179 mbi_out->flags |= MBI_MODULES;
180 /*
181 * We have to allocate one more module slot here. At some point
182 * __start_xen() may put Xen image placement into it.
183 */
184 mbi_out->mods_addr = alloc_mem((mbi_out->mods_count + 1) *
185 sizeof(*mbi_out_mods));
186 mbi_out_mods = _p(mbi_out->mods_addr);
187 }
188
189 /* Skip Multiboot2 information fixed part. */
190 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
191
192 /* Put all needed data into mbi_out. */
193 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
194 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
195 switch ( tag->type )
196 {
197 case MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME:
198 mbi_out->flags |= MBI_LOADERNAME;
199 ptr = get_mb2_string(tag, string, string);
200 mbi_out->boot_loader_name = copy_string(ptr);
201 break;
202
203 case MULTIBOOT2_TAG_TYPE_CMDLINE:
204 mbi_out->flags |= MBI_CMDLINE;
205 ptr = get_mb2_string(tag, string, string);
206 mbi_out->cmdline = copy_string(ptr);
207 break;
208
209 case MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO:
210 mbi_out->flags |= MBI_MEMLIMITS;
211 mbi_out->mem_lower = get_mb2_data(tag, basic_meminfo, mem_lower);
212 mbi_out->mem_upper = get_mb2_data(tag, basic_meminfo, mem_upper);
213 break;
214
215 case MULTIBOOT2_TAG_TYPE_MMAP:
216 if ( get_mb2_data(tag, mmap, entry_size) < sizeof(*mmap_src) )
217 break;
218
219 mbi_out->flags |= MBI_MEMMAP;
220 mbi_out->mmap_length = get_mb2_data(tag, mmap, size);
221 mbi_out->mmap_length -= sizeof(multiboot2_tag_mmap_t);
222 mbi_out->mmap_length /= get_mb2_data(tag, mmap, entry_size);
223 mbi_out->mmap_length *= sizeof(*mmap_dst);
224
225 mbi_out->mmap_addr = alloc_mem(mbi_out->mmap_length);
226
227 mmap_src = get_mb2_data(tag, mmap, entries);
228 mmap_dst = _p(mbi_out->mmap_addr);
229
230 for ( i = 0; i < mbi_out->mmap_length / sizeof(*mmap_dst); i++ )
231 {
232 /* Init size member properly. */
233 mmap_dst[i].size = sizeof(*mmap_dst);
234 mmap_dst[i].size -= sizeof(mmap_dst[i].size);
235 /* Now copy a given region data. */
236 mmap_dst[i].base_addr_low = (u32)mmap_src->addr;
237 mmap_dst[i].base_addr_high = (u32)(mmap_src->addr >> 32);
238 mmap_dst[i].length_low = (u32)mmap_src->len;
239 mmap_dst[i].length_high = (u32)(mmap_src->len >> 32);
240 mmap_dst[i].type = mmap_src->type;
241 mmap_src = _p(mmap_src) + get_mb2_data(tag, mmap, entry_size);
242 }
243 break;
244
245 case MULTIBOOT2_TAG_TYPE_MODULE:
246 if ( mod_idx >= mbi_out->mods_count )
247 break;
248
249 mbi_out_mods[mod_idx].mod_start = get_mb2_data(tag, module, mod_start);
250 mbi_out_mods[mod_idx].mod_end = get_mb2_data(tag, module, mod_end);
251 ptr = get_mb2_string(tag, module, cmdline);
252 mbi_out_mods[mod_idx].string = copy_string(ptr);
253 mbi_out_mods[mod_idx].reserved = 0;
254 ++mod_idx;
255 break;
256
257 case MULTIBOOT2_TAG_TYPE_END:
258 return mbi_out;
259
260 default:
261 break;
262 }
263
264 return mbi_out;
265 }
266
reloc(u32 magic,u32 in,u32 trampoline)267 void * __stdcall reloc(u32 magic, u32 in, u32 trampoline)
268 {
269 alloc = trampoline;
270
271 switch ( magic )
272 {
273 case MULTIBOOT_BOOTLOADER_MAGIC:
274 return mbi_reloc(in);
275
276 case MULTIBOOT2_BOOTLOADER_MAGIC:
277 return mbi2_reloc(in);
278
279 case XEN_HVM_START_MAGIC_VALUE:
280 if ( IS_ENABLED(CONFIG_PVH_GUEST) )
281 return pvh_info_reloc(in);
282 /* Fallthrough */
283
284 default:
285 /* Nothing we can do */
286 return NULL;
287 }
288 }
289
290 /*
291 * Local variables:
292 * mode: C
293 * c-file-style: "BSD"
294 * c-basic-offset: 4
295 * tab-width: 4
296 * indent-tabs-mode: nil
297 * End:
298 */
299