ia64/xen-unstable

view xen/common/elf.c @ 10123:d9f63f9361c4

[LOADER] Another change to the elf_paddr_offset/virt_base logic.
This avoids using zero to indicate 'undefined'. Instead we use
an explicit boolean to indicate whether suitable defaults should
be used. As well as making the logic clearer (I believe) it also
avoids problems if anyone ever explicitly specifies virt_base
(and also elf_paddr_offset) as zero.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun May 21 18:55:14 2006 +0100 (2006-05-21)
parents 4dcb93547710
children 14717dedba02
line source
1 /******************************************************************************
2 * elf.c
3 *
4 * Generic Elf-loading routines.
5 */
7 #include <xen/config.h>
8 #include <xen/init.h>
9 #include <xen/lib.h>
10 #include <xen/mm.h>
11 #include <xen/elf.h>
12 #include <xen/sched.h>
14 static void loadelfsymtab(struct domain_setup_info *dsi, int doload);
15 static inline int is_loadable_phdr(Elf_Phdr *phdr)
16 {
17 return ((phdr->p_type == PT_LOAD) &&
18 ((phdr->p_flags & (PF_W|PF_X)) != 0));
19 }
21 int parseelfimage(struct domain_setup_info *dsi)
22 {
23 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
24 Elf_Phdr *phdr;
25 Elf_Shdr *shdr;
26 unsigned long kernstart = ~0UL, kernend=0UL, vaddr, virt_base, elf_pa_off;
27 char *shstrtab, *guestinfo=NULL, *p;
28 char *elfbase = (char *)dsi->image_addr;
29 int h, virt_base_defined, elf_pa_off_defined;
31 if ( !elf_sanity_check(ehdr) )
32 return -EINVAL;
34 if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > dsi->image_len )
35 {
36 printk("ELF program headers extend beyond end of image.\n");
37 return -EINVAL;
38 }
40 if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > dsi->image_len )
41 {
42 printk("ELF section headers extend beyond end of image.\n");
43 return -EINVAL;
44 }
46 /* Find the section-header strings table. */
47 if ( ehdr->e_shstrndx == SHN_UNDEF )
48 {
49 printk("ELF image has no section-header strings table (shstrtab).\n");
50 return -EINVAL;
51 }
52 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
53 (ehdr->e_shstrndx*ehdr->e_shentsize));
54 shstrtab = elfbase + shdr->sh_offset;
56 /* Find the special '__xen_guest' section and check its contents. */
57 for ( h = 0; h < ehdr->e_shnum; h++ )
58 {
59 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
60 if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
61 continue;
63 guestinfo = elfbase + shdr->sh_offset;
65 if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
66 (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
67 {
68 printk("ERROR: Xen will only load images built for the generic "
69 "loader or Linux images\n");
70 return -EINVAL;
71 }
73 if ( (strstr(guestinfo, "XEN_VER=xen-3.0") == NULL) )
74 {
75 printk("ERROR: Xen will only load images built for Xen v3.0\n");
76 return -EINVAL;
77 }
79 break;
80 }
82 dsi->xen_section_string = guestinfo;
84 if ( guestinfo == NULL )
85 guestinfo = "";
87 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
88 p = strstr(guestinfo, "VIRT_BASE=");
89 virt_base_defined = (p != NULL);
90 virt_base = virt_base_defined ? simple_strtoul(p+10, &p, 0) : 0;
92 /* Initial guess for elf_pa_off is virt_base if not explicitly defined. */
93 p = strstr(guestinfo, "ELF_PADDR_OFFSET=");
94 elf_pa_off_defined = (p != NULL);
95 elf_pa_off = elf_pa_off_defined ? simple_strtoul(p+17, &p, 0) : virt_base;
97 for ( h = 0; h < ehdr->e_phnum; h++ )
98 {
99 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
100 if ( !is_loadable_phdr(phdr) )
101 continue;
102 vaddr = phdr->p_paddr - elf_pa_off + virt_base;
103 if ( vaddr < kernstart )
104 kernstart = vaddr;
105 if ( (vaddr + phdr->p_memsz) > kernend )
106 kernend = vaddr + phdr->p_memsz;
107 }
109 /*
110 * Legacy compatibility and images with no __xen_guest section: assume
111 * header addresses are virtual addresses, and that guest memory should be
112 * mapped starting at kernel load address.
113 */
114 dsi->v_start = virt_base_defined ? virt_base : kernstart;
115 dsi->elf_paddr_offset = elf_pa_off_defined ? elf_pa_off : dsi->v_start;
117 dsi->v_kernentry = ehdr->e_entry;
118 if ( (p = strstr(guestinfo, "VIRT_ENTRY=")) != NULL )
119 dsi->v_kernentry = simple_strtoul(p+11, &p, 0);
121 if ( (kernstart > kernend) ||
122 (dsi->v_kernentry < kernstart) ||
123 (dsi->v_kernentry > kernend) )
124 {
125 printk("Malformed ELF image.\n");
126 return -EINVAL;
127 }
129 if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
130 dsi->load_symtab = 1;
132 dsi->v_kernstart = kernstart;
133 dsi->v_kernend = kernend;
134 dsi->v_end = dsi->v_kernend;
136 loadelfsymtab(dsi, 0);
138 return 0;
139 }
141 int loadelfimage(struct domain_setup_info *dsi)
142 {
143 char *elfbase = (char *)dsi->image_addr;
144 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
145 Elf_Phdr *phdr;
146 unsigned long vaddr;
147 int h;
149 for ( h = 0; h < ehdr->e_phnum; h++ )
150 {
151 phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
152 if ( !is_loadable_phdr(phdr) )
153 continue;
154 vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start;
155 if ( phdr->p_filesz != 0 )
156 memcpy((char *)vaddr, elfbase + phdr->p_offset, phdr->p_filesz);
157 if ( phdr->p_memsz > phdr->p_filesz )
158 memset((char *)vaddr + phdr->p_filesz, 0,
159 phdr->p_memsz - phdr->p_filesz);
160 }
162 loadelfsymtab(dsi, 1);
164 return 0;
165 }
167 #define ELFROUND (ELFSIZE / 8)
169 static void loadelfsymtab(struct domain_setup_info *dsi, int doload)
170 {
171 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr, *sym_ehdr;
172 Elf_Shdr *shdr;
173 unsigned long maxva, symva;
174 char *p, *elfbase = (char *)dsi->image_addr;
175 int h, i;
177 if ( !dsi->load_symtab )
178 return;
180 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
181 symva = maxva;
182 maxva += sizeof(int);
183 dsi->symtab_addr = maxva;
184 dsi->symtab_len = 0;
185 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
186 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
187 if ( doload )
188 {
189 p = (void *)symva;
190 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
191 memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum*sizeof(Elf_Shdr));
192 }
193 else
194 {
195 p = NULL;
196 shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff);
197 }
199 for ( h = 0; h < ehdr->e_shnum; h++ )
200 {
201 if ( shdr[h].sh_type == SHT_STRTAB )
202 {
203 /* Look for a strtab @i linked to symtab @h. */
204 for ( i = 0; i < ehdr->e_shnum; i++ )
205 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
206 (shdr[i].sh_link == h) )
207 break;
208 /* Skip symtab @h if we found no corresponding strtab @i. */
209 if ( i == ehdr->e_shnum )
210 {
211 if (doload) {
212 shdr[h].sh_offset = 0;
213 }
214 continue;
215 }
216 }
218 if ( (shdr[h].sh_type == SHT_STRTAB) ||
219 (shdr[h].sh_type == SHT_SYMTAB) )
220 {
221 if (doload) {
222 memcpy((void *)maxva, elfbase + shdr[h].sh_offset,
223 shdr[h].sh_size);
225 /* Mangled to be based on ELF header location. */
226 shdr[h].sh_offset = maxva - dsi->symtab_addr;
228 }
229 dsi->symtab_len += shdr[h].sh_size;
230 maxva += shdr[h].sh_size;
231 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
232 }
234 if ( doload )
235 shdr[h].sh_name = 0; /* Name is NULL. */
236 }
238 if ( dsi->symtab_len == 0 )
239 {
240 dsi->symtab_addr = 0;
241 return;
242 }
244 if ( doload )
245 {
246 *(int *)p = maxva - dsi->symtab_addr;
247 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
248 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
249 sym_ehdr->e_phoff = 0;
250 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
251 sym_ehdr->e_phentsize = 0;
252 sym_ehdr->e_phnum = 0;
253 sym_ehdr->e_shstrndx = SHN_UNDEF;
254 }
256 dsi->symtab_len = maxva - dsi->symtab_addr;
257 dsi->v_end = maxva;
258 }
260 /*
261 * Local variables:
262 * mode: C
263 * c-set-style: "BSD"
264 * c-basic-offset: 4
265 * tab-width: 4
266 * indent-tabs-mode: nil
267 * End:
268 */