aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/boot/reloc.c
blob: fa0fb6bfb34f32aa41c1d19f3242f7f3c36acb64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/******************************************************************************
 * reloc.c
 * 
 * 32-bit flat memory-map routines for relocating Multiboot structures
 * and modules. This is most easily done early with paging disabled.
 * 
 * Copyright (c) 2009, Citrix Systems, Inc.
 * 
 * Authors:
 *    Keir Fraser <keir@xen.org>
 */

/* entered with %eax = BOOT_TRAMPOLINE */
asm (
    "    .text                         \n"
    "    .globl _start                 \n"
    "_start:                           \n"
    "    call 1f                       \n"
    "1:  pop  %ebx                     \n"
    "    mov  %eax,alloc-1b(%ebx)      \n"
    "    jmp  reloc                    \n"
    );

/* This is our data.  Because the code must be relocatable, no BSS is
 * allowed.  All data is accessed PC-relative with inline assembly.
 */
asm (
    "alloc:                            \n"
    "    .long 0                       \n"
    );

typedef unsigned int u32;
#include "../../../include/xen/multiboot.h"

static void *reloc_mbi_struct(void *old, unsigned int bytes)
{
    void *new;
    asm(
    "    call 1f                      \n"
    "1:  pop  %%edx                   \n"
    "    mov  alloc-1b(%%edx),%0      \n"
    "    sub  %1,%0                   \n"
    "    and  $~15,%0                 \n"
    "    mov  %0,alloc-1b(%%edx)      \n"
    "    mov  %0,%%edi                \n"
    "    rep  movsb                   \n"
       : "=&r" (new), "+c" (bytes), "+S" (old)
	: : "edx", "edi");
    return new;
}

static char *reloc_mbi_string(char *old)
{
    char *p;
    for ( p = old; *p != '\0'; p++ )
        continue;
    return reloc_mbi_struct(old, p - old + 1);
}

multiboot_info_t *reloc(multiboot_info_t *mbi_old)
{
    multiboot_info_t *mbi = reloc_mbi_struct(mbi_old, sizeof(*mbi));
    int i;

    if ( mbi->flags & MBI_CMDLINE )
        mbi->cmdline = (u32)reloc_mbi_string((char *)mbi->cmdline);

    if ( mbi->flags & MBI_MODULES )
    {
        module_t *mods = reloc_mbi_struct(
            (module_t *)mbi->mods_addr, mbi->mods_count * sizeof(module_t));

        mbi->mods_addr = (u32)mods;

        for ( i = 0; i < mbi->mods_count; i++ )
        {
            if ( mods[i].string )
                mods[i].string = (u32)reloc_mbi_string((char *)mods[i].string);
        }
    }

    if ( mbi->flags & MBI_MEMMAP )
        mbi->mmap_addr = (u32)reloc_mbi_struct(
            (memory_map_t *)mbi->mmap_addr, mbi->mmap_length);

    if ( mbi->flags & MBI_LOADERNAME )
        mbi->boot_loader_name = (u32)reloc_mbi_string(
            (char *)mbi->boot_loader_name);

    /* Mask features we don't understand or don't relocate. */
    mbi->flags &= (MBI_MEMLIMITS |
                   MBI_BOOTDEV |
                   MBI_CMDLINE |
                   MBI_MODULES |
                   MBI_MEMMAP |
                   MBI_LOADERNAME);

    return mbi;
}