aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_load_aout9.c
blob: 76ee55fcc650c015bc79bacc09cb063e37ed3718 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "xc_private.h"
#include "xc_aout9.h"

#if defined(__i386__)
  #define A9_MAGIC I_MAGIC
#elif defined(__x86_64__)
  #define A9_MAGIC S_MAGIC
#elif defined(__ia64__)
  #define A9_MAGIC 0
#else
#error "Unsupported architecture"
#endif


#define round_pgup(_p)    (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
#define round_pgdown(_p)  ((_p)&PAGE_MASK)

static int parseaout9image(char *, unsigned long, struct domain_setup_info *);
static int loadaout9image(char *, unsigned long, int, u32, unsigned long *, struct domain_setup_info *);
static void copyout(int, u32, unsigned long *, unsigned long, void *, int);
struct Exec *get_header(unsigned char *, unsigned long, struct Exec *);


int 
probe_aout9(
    char *image,
    unsigned long image_size,
    struct load_funcs *load_funcs)
{
    struct Exec ehdr;

    if (!get_header(image, image_size, &ehdr)) {
        ERROR("Kernel image does not have a a.out9 header.");
        return -EINVAL;
    }

    load_funcs->parseimage = parseaout9image;
    load_funcs->loadimage = loadaout9image;
    return 0;
}

static int 
parseaout9image(
    char *image,
    unsigned long image_size,
    struct domain_setup_info *dsi)
{
    struct Exec ehdr;
    unsigned long start, txtsz, end;

    if (!get_header(image, image_size, &ehdr)) {
        ERROR("Kernel image does not have a a.out9 header.");
        return -EINVAL;
    }

    if (sizeof ehdr + ehdr.text + ehdr.data > image_size) {
        ERROR("a.out program extends past end of image.");
        return -EINVAL;
    }

    start = round_pgdown(ehdr.entry);
    txtsz = round_pgup(ehdr.text);
    end = start + txtsz + ehdr.data + ehdr.bss;

    dsi->v_start	= start;
    dsi->v_kernstart	= start;
    dsi->v_kernend	= end;
    dsi->v_kernentry	= ehdr.entry;
    dsi->v_end		= end;

    /* XXX load symbols */

    return 0;
}

static int 
loadaout9image(
    char *image,
    unsigned long image_size,
    int xch, u32 dom,
    unsigned long *parray,
    struct domain_setup_info *dsi)
{
    struct Exec ehdr;
    unsigned long txtsz;

    if (!get_header(image, image_size, &ehdr)) {
        ERROR("Kernel image does not have a a.out9 header.");
        return -EINVAL;
    }

    txtsz = round_pgup(ehdr.text);
    copyout(xch, dom, parray, 
            0, image, sizeof ehdr + ehdr.text);
    copyout(xch, dom, parray, 
            txtsz, image + sizeof ehdr + ehdr.text, ehdr.data);
    /* XXX zeroing of BSS needed? */

    /* XXX load symbols */

    return 0;
}

/*
 * copyout data to the domain given an offset to the start
 * of its memory region described by parray.
 */
static void
copyout(
    int xch, u32 dom,
    unsigned long *parray,
    unsigned long off,
    void *buf,
    int sz)
{
    unsigned long pgoff, chunksz;
    void *pg;

    while (sz > 0) {
        pgoff = off & (PAGE_SIZE-1);
        chunksz = sz;
        if(chunksz > PAGE_SIZE - pgoff)
            chunksz = PAGE_SIZE - pgoff;

        pg = xc_map_foreign_range(xch, dom, PAGE_SIZE, PROT_WRITE, 
                                  parray[off>>PAGE_SHIFT]);
        memcpy(pg + pgoff, buf, chunksz);
        munmap(pg, PAGE_SIZE);

        off += chunksz;
        buf += chunksz;
        sz -= chunksz;
    }
}
    
/*
 * Decode the header from the start of image and return it.
 */
struct Exec *
get_header(
    unsigned char *image,
    unsigned long image_size,
    struct Exec *ehdr)
{
    unsigned long *v;
    int i;

    if (A9_MAGIC == 0)
        return 0;

    if (image_size < sizeof ehdr)
        return 0;

    /* ... all big endian words */
    v = (unsigned long *)ehdr;
    for (i = 0; i < sizeof *ehdr; i += 4) {
        v[i/4] = (image[i+0]<<24) | (image[i+1]<<16) | 
                 (image[i+2]<<8) | image[i+3];
    }

    if(ehdr->magic != A9_MAGIC)
        return 0;
    return ehdr;
}