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) = MULTIBOOT_MAGIC,
18 * - 0x8(%esp) = MULTIBOOT_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 #define get_mb2_data(tag, type, member) (((multiboot2_tag_##type##_t *)(tag))->member)
33 #define get_mb2_string(tag, type, member) ((u32)get_mb2_data(tag, type, member))
34
35 static u32 alloc;
36
alloc_mem(u32 bytes)37 static u32 alloc_mem(u32 bytes)
38 {
39 return alloc -= ALIGN_UP(bytes, 16);
40 }
41
zero_mem(u32 s,u32 bytes)42 static void zero_mem(u32 s, u32 bytes)
43 {
44 while ( bytes-- )
45 *(char *)s++ = 0;
46 }
47
copy_mem(u32 src,u32 bytes)48 static u32 copy_mem(u32 src, u32 bytes)
49 {
50 u32 dst, dst_ret;
51
52 dst = alloc_mem(bytes);
53 dst_ret = dst;
54
55 while ( bytes-- )
56 *(char *)dst++ = *(char *)src++;
57
58 return dst_ret;
59 }
60
copy_string(u32 src)61 static u32 copy_string(u32 src)
62 {
63 u32 p;
64
65 if ( !src )
66 return 0;
67
68 for ( p = src; *(char *)p != '\0'; p++ )
69 continue;
70
71 return copy_mem(src, p - src + 1);
72 }
73
mbi_reloc(u32 mbi_in)74 static multiboot_info_t *mbi_reloc(u32 mbi_in)
75 {
76 int i;
77 multiboot_info_t *mbi_out;
78
79 mbi_out = _p(copy_mem(mbi_in, sizeof(*mbi_out)));
80
81 if ( mbi_out->flags & MBI_CMDLINE )
82 mbi_out->cmdline = copy_string(mbi_out->cmdline);
83
84 if ( mbi_out->flags & MBI_MODULES )
85 {
86 module_t *mods;
87
88 mbi_out->mods_addr = copy_mem(mbi_out->mods_addr,
89 mbi_out->mods_count * sizeof(module_t));
90
91 mods = _p(mbi_out->mods_addr);
92
93 for ( i = 0; i < mbi_out->mods_count; i++ )
94 {
95 if ( mods[i].string )
96 mods[i].string = copy_string(mods[i].string);
97 }
98 }
99
100 if ( mbi_out->flags & MBI_MEMMAP )
101 mbi_out->mmap_addr = copy_mem(mbi_out->mmap_addr, mbi_out->mmap_length);
102
103 if ( mbi_out->flags & MBI_LOADERNAME )
104 mbi_out->boot_loader_name = copy_string(mbi_out->boot_loader_name);
105
106 /* Mask features we don't understand or don't relocate. */
107 mbi_out->flags &= (MBI_MEMLIMITS |
108 MBI_CMDLINE |
109 MBI_MODULES |
110 MBI_MEMMAP |
111 MBI_LOADERNAME);
112
113 return mbi_out;
114 }
115
mbi2_reloc(u32 mbi_in)116 static multiboot_info_t *mbi2_reloc(u32 mbi_in)
117 {
118 const multiboot2_fixed_t *mbi_fix = _p(mbi_in);
119 const multiboot2_memory_map_t *mmap_src;
120 const multiboot2_tag_t *tag;
121 module_t *mbi_out_mods = NULL;
122 memory_map_t *mmap_dst;
123 multiboot_info_t *mbi_out;
124 u32 ptr;
125 unsigned int i, mod_idx = 0;
126
127 ptr = alloc_mem(sizeof(*mbi_out));
128 mbi_out = _p(ptr);
129 zero_mem(ptr, sizeof(*mbi_out));
130
131 /* Skip Multiboot2 information fixed part. */
132 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
133
134 /* Get the number of modules. */
135 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
136 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
137 {
138 if ( tag->type == MULTIBOOT2_TAG_TYPE_MODULE )
139 ++mbi_out->mods_count;
140 else if ( tag->type == MULTIBOOT2_TAG_TYPE_END )
141 break;
142 }
143
144 if ( mbi_out->mods_count )
145 {
146 mbi_out->flags |= MBI_MODULES;
147 mbi_out->mods_addr = alloc_mem(mbi_out->mods_count * sizeof(*mbi_out_mods));
148 mbi_out_mods = _p(mbi_out->mods_addr);
149 }
150
151 /* Skip Multiboot2 information fixed part. */
152 ptr = ALIGN_UP(mbi_in + sizeof(*mbi_fix), MULTIBOOT2_TAG_ALIGN);
153
154 /* Put all needed data into mbi_out. */
155 for ( tag = _p(ptr); (u32)tag - mbi_in < mbi_fix->total_size;
156 tag = _p(ALIGN_UP((u32)tag + tag->size, MULTIBOOT2_TAG_ALIGN)) )
157 switch ( tag->type )
158 {
159 case MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME:
160 mbi_out->flags |= MBI_LOADERNAME;
161 ptr = get_mb2_string(tag, string, string);
162 mbi_out->boot_loader_name = copy_string(ptr);
163 break;
164
165 case MULTIBOOT2_TAG_TYPE_CMDLINE:
166 mbi_out->flags |= MBI_CMDLINE;
167 ptr = get_mb2_string(tag, string, string);
168 mbi_out->cmdline = copy_string(ptr);
169 break;
170
171 case MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO:
172 mbi_out->flags |= MBI_MEMLIMITS;
173 mbi_out->mem_lower = get_mb2_data(tag, basic_meminfo, mem_lower);
174 mbi_out->mem_upper = get_mb2_data(tag, basic_meminfo, mem_upper);
175 break;
176
177 case MULTIBOOT2_TAG_TYPE_MMAP:
178 if ( get_mb2_data(tag, mmap, entry_size) < sizeof(*mmap_src) )
179 break;
180
181 mbi_out->flags |= MBI_MEMMAP;
182 mbi_out->mmap_length = get_mb2_data(tag, mmap, size);
183 mbi_out->mmap_length -= sizeof(multiboot2_tag_mmap_t);
184 mbi_out->mmap_length /= get_mb2_data(tag, mmap, entry_size);
185 mbi_out->mmap_length *= sizeof(*mmap_dst);
186
187 mbi_out->mmap_addr = alloc_mem(mbi_out->mmap_length);
188
189 mmap_src = get_mb2_data(tag, mmap, entries);
190 mmap_dst = _p(mbi_out->mmap_addr);
191
192 for ( i = 0; i < mbi_out->mmap_length / sizeof(*mmap_dst); i++ )
193 {
194 /* Init size member properly. */
195 mmap_dst[i].size = sizeof(*mmap_dst);
196 mmap_dst[i].size -= sizeof(mmap_dst[i].size);
197 /* Now copy a given region data. */
198 mmap_dst[i].base_addr_low = (u32)mmap_src->addr;
199 mmap_dst[i].base_addr_high = (u32)(mmap_src->addr >> 32);
200 mmap_dst[i].length_low = (u32)mmap_src->len;
201 mmap_dst[i].length_high = (u32)(mmap_src->len >> 32);
202 mmap_dst[i].type = mmap_src->type;
203 mmap_src = _p(mmap_src) + get_mb2_data(tag, mmap, entry_size);
204 }
205 break;
206
207 case MULTIBOOT2_TAG_TYPE_MODULE:
208 if ( mod_idx >= mbi_out->mods_count )
209 break;
210
211 mbi_out_mods[mod_idx].mod_start = get_mb2_data(tag, module, mod_start);
212 mbi_out_mods[mod_idx].mod_end = get_mb2_data(tag, module, mod_end);
213 ptr = get_mb2_string(tag, module, cmdline);
214 mbi_out_mods[mod_idx].string = copy_string(ptr);
215 mbi_out_mods[mod_idx].reserved = 0;
216 ++mod_idx;
217 break;
218
219 case MULTIBOOT2_TAG_TYPE_END:
220 return mbi_out;
221
222 default:
223 break;
224 }
225
226 return mbi_out;
227 }
228
reloc(u32 mb_magic,u32 mbi_in,u32 trampoline)229 multiboot_info_t __stdcall *reloc(u32 mb_magic, u32 mbi_in, u32 trampoline)
230 {
231 alloc = trampoline;
232
233 if ( mb_magic == MULTIBOOT2_BOOTLOADER_MAGIC )
234 return mbi2_reloc(mbi_in);
235 else
236 return mbi_reloc(mbi_in);
237 }
238
239 /*
240 * Local variables:
241 * mode: C
242 * c-file-style: "BSD"
243 * c-basic-offset: 4
244 * tab-width: 4
245 * indent-tabs-mode: nil
246 * End:
247 */
248