ia64/xen-unstable

view xen/common/elf.c @ 12390:e28beea6d228

[IA64] Fix time services of EFI emulation

This patch serializes the execution of following efi.runtimes.
- GetTime
- SetTime
- GetWakeTime
- SetWakeTime

Linux/ia64 uses similar spinlocks in the EFI RTC driver.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author awilliam@xenbuild.aw
date Fri Nov 10 12:03:19 2006 -0700 (2006-11-10)
parents f028e3732803
children ac51e8f37108
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>
13 #include <xen/errno.h>
14 #include <xen/inttypes.h>
16 #include <public/elfnote.h>
18 static void loadelfsymtab(struct domain_setup_info *dsi, int doload);
19 static inline int is_loadable_phdr(Elf_Phdr *phdr)
20 {
21 return ((phdr->p_type == PT_LOAD) &&
22 ((phdr->p_flags & (PF_W|PF_X)) != 0));
23 }
25 /*
26 * Fallback for kernels containing only the legacy __xen_guest string
27 * and no ELF notes.
28 */
29 static int is_xen_guest_section(Elf_Shdr *shdr, const char *shstrtab)
30 {
31 return strcmp(&shstrtab[shdr->sh_name], "__xen_guest") == 0;
32 }
34 static const char *xen_guest_lookup(struct domain_setup_info *dsi, int type)
35 {
36 const char *xenguest_fallbacks[] = {
37 [XEN_ELFNOTE_ENTRY] = "VIRT_ENTRY=",
38 [XEN_ELFNOTE_HYPERCALL_PAGE] = "HYPERCALL_PAGE=",
39 [XEN_ELFNOTE_VIRT_BASE] = "VIRT_BASE=",
40 [XEN_ELFNOTE_PADDR_OFFSET] = "ELF_PADDR_OFFSET=",
41 [XEN_ELFNOTE_XEN_VERSION] = "XEN_VER=",
42 [XEN_ELFNOTE_GUEST_OS] = "GUEST_OS=",
43 [XEN_ELFNOTE_GUEST_VERSION] = "GUEST_VER=",
44 [XEN_ELFNOTE_LOADER] = "LOADER=",
45 [XEN_ELFNOTE_PAE_MODE] = "PAE=",
46 [XEN_ELFNOTE_FEATURES] = "FEATURES=",
47 [XEN_ELFNOTE_BSD_SYMTAB] = "BSD_SYMTAB=",
48 };
49 const char *fallback;
50 const char *p;
52 if ( !dsi->__xen_guest_string )
53 return NULL;
55 if ( type > sizeof(xenguest_fallbacks) )
56 return NULL;
58 if ( (fallback = xenguest_fallbacks[type]) == NULL )
59 return NULL;
61 if ( (p = strstr(dsi->__xen_guest_string,fallback)) == NULL )
62 return NULL;
64 return p + strlen(fallback);
65 }
67 static const char *xen_guest_string(struct domain_setup_info *dsi, int type)
68 {
69 const char *p = xen_guest_lookup(dsi, type);
71 /*
72 * We special case this since the __xen_guest_section treats the
73 * mere precense of the BSD_SYMTAB string as true or false.
74 */
75 if ( type == XEN_ELFNOTE_BSD_SYMTAB )
76 return p ? "yes" : "no";
78 return p;
79 }
81 static unsigned long long xen_guest_numeric(struct domain_setup_info *dsi,
82 int type, int *defined)
83 {
84 const char *p = xen_guest_lookup(dsi, type);
85 unsigned long long value;
87 if ( p == NULL )
88 return 0;
90 value = simple_strtoull(p, NULL, 0);
92 /* We special case this since __xen_guest_section contains a PFN
93 * for this field not a virtual address.
94 */
95 if (type == XEN_ELFNOTE_HYPERCALL_PAGE)
96 value = dsi->v_start + (value<<PAGE_SHIFT);
98 *defined = 1;
99 return value;
100 }
102 /*
103 * Interface to the Xen ELF notes.
104 */
105 #define ELFNOTE_NAME(_n_) ((void*)(_n_) + sizeof(*(_n_)))
106 #define ELFNOTE_DESC(_n_) (ELFNOTE_NAME(_n_) + (((_n_)->namesz+3)&~3))
107 #define ELFNOTE_NEXT(_n_) (ELFNOTE_DESC(_n_) + (((_n_)->descsz+3)&~3))
109 static int is_xen_elfnote_section(const char *image, Elf_Shdr *shdr)
110 {
111 Elf_Note *note;
113 if ( shdr->sh_type != SHT_NOTE )
114 return 0;
116 for ( note = (Elf_Note *)(image + shdr->sh_offset);
117 note < (Elf_Note *)(image + shdr->sh_offset + shdr->sh_size);
118 note = ELFNOTE_NEXT(note) )
119 {
120 if ( !strncmp(ELFNOTE_NAME(note), "Xen", 4) )
121 return 1;
122 }
124 return 0;
125 }
127 static Elf_Note *xen_elfnote_lookup(struct domain_setup_info *dsi, int type)
128 {
129 Elf_Note *note;
131 if ( !dsi->__elfnote_section )
132 return NULL;
134 for ( note = (Elf_Note *)dsi->__elfnote_section;
135 note < (Elf_Note *)dsi->__elfnote_section_end;
136 note = ELFNOTE_NEXT(note) )
137 {
138 if ( strncmp(ELFNOTE_NAME(note), "Xen", 4) )
139 continue;
141 if ( note->type == type )
142 return note;
143 }
145 return NULL;
146 }
148 const char *xen_elfnote_string(struct domain_setup_info *dsi, int type)
149 {
150 Elf_Note *note;
152 if ( !dsi->__elfnote_section )
153 return xen_guest_string(dsi, type);
155 note = xen_elfnote_lookup(dsi, type);
156 if ( note == NULL )
157 return NULL;
159 return (const char *)ELFNOTE_DESC(note);
160 }
162 unsigned long long xen_elfnote_numeric(struct domain_setup_info *dsi,
163 int type, int *defined)
164 {
165 Elf_Note *note;
167 *defined = 0;
169 if ( !dsi->__elfnote_section )
170 return xen_guest_numeric(dsi, type, defined);
172 note = xen_elfnote_lookup(dsi, type);
173 if ( note == NULL )
174 {
175 return 0;
176 }
178 switch ( note->descsz )
179 {
180 case 4:
181 *defined = 1;
182 return *(uint32_t*)ELFNOTE_DESC(note);
183 case 8:
184 *defined = 1;
185 return *(uint64_t*)ELFNOTE_DESC(note);
186 default:
187 printk("ERROR: unknown data size %#x for numeric type note %#x\n",
188 note->descsz, type);
189 return 0;
190 }
191 }
193 int parseelfimage(struct domain_setup_info *dsi)
194 {
195 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
196 Elf_Phdr *phdr;
197 Elf_Shdr *shdr;
198 Elf_Addr kernstart = ~0, kernend = 0, vaddr, virt_entry;
199 const char *shstrtab, *p;
200 const char *image = (char *)dsi->image_addr;
201 const unsigned long image_len = dsi->image_len;
202 int h, virt_base_defined, elf_pa_off_defined, virt_entry_defined;
204 if ( !elf_sanity_check(ehdr) )
205 return -EINVAL;
207 if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > image_len )
208 {
209 printk("ELF program headers extend beyond end of image.\n");
210 return -EINVAL;
211 }
213 if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > image_len )
214 {
215 printk("ELF section headers extend beyond end of image.\n");
216 return -EINVAL;
217 }
219 /* Find the section-header strings table. */
220 if ( ehdr->e_shstrndx == SHN_UNDEF )
221 {
222 printk("ELF image has no section-header strings table (shstrtab).\n");
223 return -EINVAL;
224 }
225 shdr = (Elf_Shdr *)(image + ehdr->e_shoff +
226 (ehdr->e_shstrndx*ehdr->e_shentsize));
227 shstrtab = image + shdr->sh_offset;
229 dsi->__elfnote_section = NULL;
230 dsi->__xen_guest_string = NULL;
232 /* Look for .notes segment containing at least one Xen note */
233 for ( h = 0; h < ehdr->e_shnum; h++ )
234 {
235 shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
236 if ( !is_xen_elfnote_section(image, shdr) )
237 continue;
238 dsi->__elfnote_section = (void *)image + shdr->sh_offset;
239 dsi->__elfnote_section_end =
240 (void *)image + shdr->sh_offset + shdr->sh_size;
241 break;
242 }
244 /* Fall back to looking for the special '__xen_guest' section. */
245 if ( dsi->__elfnote_section == NULL )
246 {
247 for ( h = 0; h < ehdr->e_shnum; h++ )
248 {
249 shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
250 if ( is_xen_guest_section(shdr, shstrtab) )
251 {
252 dsi->__xen_guest_string = (char *)image + shdr->sh_offset;
253 break;
254 }
255 }
256 }
258 /* Check the contents of the Xen notes or guest string. */
259 if ( dsi->__elfnote_section || dsi->__xen_guest_string )
260 {
261 const char *loader = xen_elfnote_string(dsi, XEN_ELFNOTE_LOADER);
262 const char *guest_os = xen_elfnote_string(dsi, XEN_ELFNOTE_GUEST_OS);
263 const char *xen_version =
264 xen_elfnote_string(dsi, XEN_ELFNOTE_XEN_VERSION);
266 if ( ( loader == NULL || strncmp(loader, "generic", 7) ) &&
267 ( guest_os == NULL || strncmp(guest_os, "linux", 5) ) )
268 {
269 printk("ERROR: Will only load images built for the generic "
270 "loader or Linux images");
271 return -EINVAL;
272 }
274 if ( xen_version == NULL || strncmp(xen_version, "xen-3.0", 7) )
275 {
276 printk("ERROR: Xen will only load images built for Xen v3.0\n");
277 }
278 }
279 else
280 {
281 #if defined(__x86_64__) || defined(__i386__)
282 printk("ERROR: Not a Xen-ELF image: "
283 "No ELF notes or '__xen_guest' section found.\n");
284 return -EINVAL;
285 #endif
286 }
288 /*
289 * If we have ELF notes then PAE=yes implies that we must support
290 * the extended cr3 syntax. Otherwise we need to find the
291 * [extended-cr3] syntax in the __xen_guest string.
292 */
293 dsi->pae_kernel = PAEKERN_no;
294 if ( dsi->__elfnote_section )
295 {
296 p = xen_elfnote_string(dsi, XEN_ELFNOTE_PAE_MODE);
297 if ( p != NULL && strncmp(p, "yes", 3) == 0 )
298 dsi->pae_kernel = PAEKERN_extended_cr3;
300 }
301 else
302 {
303 p = xen_guest_lookup(dsi, XEN_ELFNOTE_PAE_MODE);
304 if ( p != NULL && strncmp(p, "yes", 3) == 0 )
305 {
306 dsi->pae_kernel = PAEKERN_yes;
307 if ( !strncmp(p+3, "[extended-cr3]", 14) )
308 dsi->pae_kernel = PAEKERN_extended_cr3;
309 }
310 }
312 /* Initial guess for v_start is 0 if it is not explicitly defined. */
313 dsi->v_start =
314 xen_elfnote_numeric(dsi, XEN_ELFNOTE_VIRT_BASE, &virt_base_defined);
315 if ( !virt_base_defined )
316 dsi->v_start = 0;
318 /*
319 * If we are using the legacy __xen_guest section then elf_pa_off
320 * defaults to v_start in order to maintain compatibility with
321 * older hypervisors which set padd in the ELF header to
322 * virt_base.
323 *
324 * If we are using the modern ELF notes interface then the default
325 * is 0.
326 */
327 dsi->elf_paddr_offset =
328 xen_elfnote_numeric(dsi, XEN_ELFNOTE_PADDR_OFFSET, &elf_pa_off_defined);
329 if ( !elf_pa_off_defined )
330 {
331 if ( dsi->__elfnote_section )
332 dsi->elf_paddr_offset = 0;
333 else
334 dsi->elf_paddr_offset = dsi->v_start;
335 }
337 if ( elf_pa_off_defined && !virt_base_defined )
338 {
339 printk("ERROR: Neither ELF_PADDR_OFFSET nor VIRT_BASE found in"
340 " Xen ELF notes.\n");
341 return -EINVAL;
342 }
344 for ( h = 0; h < ehdr->e_phnum; h++ )
345 {
346 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
347 if ( !is_loadable_phdr(phdr) )
348 continue;
349 vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start;
350 if ( (vaddr + phdr->p_memsz) < vaddr )
351 {
352 printk("ERROR: ELF program header %d is too large.\n", h);
353 return -EINVAL;
354 }
356 if ( vaddr < kernstart )
357 kernstart = vaddr;
358 if ( (vaddr + phdr->p_memsz) > kernend )
359 kernend = vaddr + phdr->p_memsz;
360 }
362 dsi->v_kernentry = ehdr->e_entry;
364 virt_entry =
365 xen_elfnote_numeric(dsi, XEN_ELFNOTE_ENTRY, &virt_entry_defined);
366 if ( virt_entry_defined )
367 dsi->v_kernentry = virt_entry;
369 if ( (kernstart > kernend) ||
370 (dsi->v_kernentry < kernstart) ||
371 (dsi->v_kernentry > kernend) ||
372 (dsi->v_start > kernstart) )
373 {
374 printk("ERROR: ELF start or entries are out of bounds.\n");
375 return -EINVAL;
376 }
378 p = xen_elfnote_string(dsi, XEN_ELFNOTE_BSD_SYMTAB);
379 if ( p != NULL && strncmp(p, "yes", 3) == 0 )
380 dsi->load_symtab = 1;
382 dsi->v_kernstart = kernstart;
383 dsi->v_kernend = kernend;
384 dsi->v_end = dsi->v_kernend;
386 loadelfsymtab(dsi, 0);
388 return 0;
389 }
391 int loadelfimage(struct domain_setup_info *dsi)
392 {
393 char *image = (char *)dsi->image_addr;
394 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
395 Elf_Phdr *phdr;
396 unsigned long vaddr;
397 int h;
399 for ( h = 0; h < ehdr->e_phnum; h++ )
400 {
401 phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
402 if ( !is_loadable_phdr(phdr) )
403 continue;
404 vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start;
405 if ( phdr->p_filesz != 0 )
406 memcpy((char *)vaddr, image + phdr->p_offset, phdr->p_filesz);
407 if ( phdr->p_memsz > phdr->p_filesz )
408 memset((char *)vaddr + phdr->p_filesz, 0,
409 phdr->p_memsz - phdr->p_filesz);
410 }
412 loadelfsymtab(dsi, 1);
414 return 0;
415 }
417 #define ELFROUND (ELFSIZE / 8)
419 static void loadelfsymtab(struct domain_setup_info *dsi, int doload)
420 {
421 Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr, *sym_ehdr;
422 Elf_Shdr *shdr;
423 unsigned long maxva, symva;
424 char *p, *image = (char *)dsi->image_addr;
425 int h, i;
427 if ( !dsi->load_symtab )
428 return;
430 maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
431 symva = maxva;
432 maxva += sizeof(int);
433 dsi->symtab_addr = maxva;
434 dsi->symtab_len = 0;
435 maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
436 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
437 if ( doload )
438 {
439 p = (void *)symva;
440 shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
441 memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum*sizeof(Elf_Shdr));
442 }
443 else
444 {
445 p = NULL;
446 shdr = (Elf_Shdr *)(image + ehdr->e_shoff);
447 }
449 for ( h = 0; h < ehdr->e_shnum; h++ )
450 {
451 if ( shdr[h].sh_type == SHT_STRTAB )
452 {
453 /* Look for a strtab @i linked to symtab @h. */
454 for ( i = 0; i < ehdr->e_shnum; i++ )
455 if ( (shdr[i].sh_type == SHT_SYMTAB) &&
456 (shdr[i].sh_link == h) )
457 break;
458 /* Skip symtab @h if we found no corresponding strtab @i. */
459 if ( i == ehdr->e_shnum )
460 {
461 if (doload) {
462 shdr[h].sh_offset = 0;
463 }
464 continue;
465 }
466 }
468 if ( (shdr[h].sh_type == SHT_STRTAB) ||
469 (shdr[h].sh_type == SHT_SYMTAB) )
470 {
471 if (doload) {
472 memcpy((void *)maxva, image + shdr[h].sh_offset,
473 shdr[h].sh_size);
475 /* Mangled to be based on ELF header location. */
476 shdr[h].sh_offset = maxva - dsi->symtab_addr;
478 }
479 dsi->symtab_len += shdr[h].sh_size;
480 maxva += shdr[h].sh_size;
481 maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
482 }
484 if ( doload )
485 shdr[h].sh_name = 0; /* Name is NULL. */
486 }
488 if ( dsi->symtab_len == 0 )
489 {
490 dsi->symtab_addr = 0;
491 return;
492 }
494 if ( doload )
495 {
496 *(int *)p = maxva - dsi->symtab_addr;
497 sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
498 memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
499 sym_ehdr->e_phoff = 0;
500 sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
501 sym_ehdr->e_phentsize = 0;
502 sym_ehdr->e_phnum = 0;
503 sym_ehdr->e_shstrndx = SHN_UNDEF;
504 }
506 dsi->symtab_len = maxva - dsi->symtab_addr;
507 dsi->v_end = maxva;
508 }
510 /*
511 * Local variables:
512 * mode: C
513 * c-set-style: "BSD"
514 * c-basic-offset: 4
515 * tab-width: 4
516 * indent-tabs-mode: nil
517 * End:
518 */