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