Annotation of prex-old/boot/common/elf.c, Revision 1.1
1.1 ! nbrk 1: /*-
! 2: * Copyright (c) 2005-2006, Kohsuke Ohtani
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. Neither the name of the author nor the names of any co-contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * elf.c - ELF file format support
! 32: */
! 33:
! 34: #include <boot.h>
! 35: #include <prex/bootinfo.h>
! 36: #include <sys/elf.h>
! 37: #include <platform.h>
! 38:
! 39: extern int nr_img; /* number of images */
! 40:
! 41: #define SHF_VALID (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
! 42:
! 43: static char *sect_addr[32]; /* array of section address */
! 44:
! 45: static int
! 46: load_executable(char *img, struct module *m)
! 47: {
! 48: Elf32_Ehdr *ehdr;
! 49: Elf32_Phdr *phdr;
! 50: u_long phys_base;
! 51: int i;
! 52:
! 53: phys_base = load_base;
! 54: ehdr = (Elf32_Ehdr *)img;
! 55: phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_phoff);
! 56: m->phys = load_base;
! 57: phys_base = load_base;
! 58: elf_print("phys addr=%x\n", phys_base);
! 59:
! 60: for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) {
! 61: if (phdr->p_type != PT_LOAD)
! 62: continue;
! 63:
! 64: elf_print("p_flags=%x\n", (int)phdr->p_flags);
! 65: elf_print("p_align=%x\n", (int)phdr->p_align);
! 66: elf_print("p_paddr=%x\n", (int)phdr->p_paddr);
! 67:
! 68: if (i >= 2) {
! 69: elf_print("skipping extra phdr\n");
! 70: continue;
! 71: }
! 72: if (phdr->p_flags & PF_X) {
! 73: /* Text */
! 74: m->text = phdr->p_vaddr;
! 75: m->textsz = (size_t)phdr->p_memsz;
! 76: } else {
! 77: /* Data & BSS */
! 78: m->data = phdr->p_vaddr;
! 79: m->datasz = (size_t)phdr->p_filesz;
! 80: m->bsssz =
! 81: (size_t)(phdr->p_memsz - phdr->p_filesz);
! 82: load_base = phys_base + (m->data - m->text);
! 83: }
! 84: if (phdr->p_filesz > 0) {
! 85: memcpy((char *)load_base, img + phdr->p_offset,
! 86: (size_t)phdr->p_filesz);
! 87: elf_print("load: offset=%x size=%x\n",
! 88: load_base, (int)phdr->p_filesz);
! 89: }
! 90: if (!(phdr->p_flags & PF_X)) {
! 91: if (m->bsssz > 0) {
! 92: /* Zero fill BSS */
! 93: memset((char *)load_base + m->datasz,
! 94: 0, m->bsssz);
! 95: }
! 96: load_base += phdr->p_memsz;
! 97: }
! 98: }
! 99: /* workaround for data/bss size is 0 */
! 100: if (m->data == 0)
! 101: load_base = phys_base + m->textsz;
! 102:
! 103: load_base = PAGE_ALIGN(load_base);
! 104: m->size = (size_t)(load_base - m->phys);
! 105: m->entry = ehdr->e_entry;
! 106: elf_print("module size=%x entry=%x\n", m->size, m->entry);
! 107: return 0;
! 108: }
! 109:
! 110: static int
! 111: relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela,
! 112: char *target_sect, int nr_reloc)
! 113: {
! 114: Elf32_Sym *sym;
! 115: Elf32_Addr sym_val;
! 116: int i;
! 117:
! 118: for (i = 0; i < nr_reloc; i++) {
! 119: sym = &sym_table[ELF32_R_SYM(rela->r_info)];
! 120: if (sym->st_shndx != STN_UNDEF) {
! 121: sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
! 122: + sym->st_value;
! 123: if (relocate_rela(rela, sym_val, target_sect) != 0)
! 124: return -1;
! 125: } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
! 126: printk("Undefined symbol for rela[%x] sym=%x\n",
! 127: i, sym);
! 128: return -1;
! 129: } else {
! 130: elf_print("Undefined weak symbol for rela[%x]\n", i);
! 131: }
! 132: rela++;
! 133: }
! 134: return 0;
! 135: }
! 136:
! 137: static int
! 138: relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel,
! 139: char *target_sect, int nr_reloc)
! 140: {
! 141: Elf32_Sym *sym;
! 142: Elf32_Addr sym_val;
! 143: int i;
! 144:
! 145: for (i = 0; i < nr_reloc; i++) {
! 146: sym = &sym_table[ELF32_R_SYM(rel->r_info)];
! 147: if (sym->st_shndx != STN_UNDEF) {
! 148: sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
! 149: + sym->st_value;
! 150: if (relocate_rel(rel, sym_val, target_sect) != 0)
! 151: return -1;
! 152: } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
! 153: printk("Undefined symbol for rel[%x] sym=%x\n",
! 154: i, sym);
! 155: return -1;
! 156: } else {
! 157: elf_print("Undefined weak symbol for rel[%x]\n", i);
! 158: }
! 159: rel++;
! 160: }
! 161: return 0;
! 162: }
! 163:
! 164: static int
! 165: relocate_section(char *img, Elf32_Shdr *shdr)
! 166: {
! 167: Elf32_Sym *sym_table;
! 168: char *target_sect;
! 169: int nr_reloc, err;
! 170:
! 171: if (shdr->sh_entsize == 0)
! 172: return 0;
! 173: if ((target_sect = sect_addr[shdr->sh_info]) == 0)
! 174: return -1;
! 175: if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
! 176: return -1;
! 177:
! 178: nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
! 179: switch (shdr->sh_type) {
! 180: case SHT_REL:
! 181: err = relocate_section_rel(sym_table,
! 182: (Elf32_Rel *)(img + shdr->sh_offset),
! 183: target_sect, nr_reloc);
! 184: break;
! 185:
! 186: case SHT_RELA:
! 187: err = relocate_section_rela(sym_table,
! 188: (Elf32_Rela *)(img + shdr->sh_offset),
! 189: target_sect, nr_reloc);
! 190: break;
! 191:
! 192: default:
! 193: err = -1;
! 194: break;
! 195: }
! 196: return err;
! 197: }
! 198:
! 199: static int
! 200: load_relocatable(char *img, struct module *m)
! 201: {
! 202: Elf32_Ehdr *ehdr;
! 203: Elf32_Shdr *shdr;
! 204: u_long sect_base, bss_base;
! 205: int i;
! 206:
! 207: ehdr = (Elf32_Ehdr *)img;
! 208: shdr = (Elf32_Shdr *)((u_long)ehdr + ehdr->e_shoff);
! 209: bss_base = 0;
! 210: m->phys = load_base;
! 211: elf_print("phys addr=%x\n", load_base);
! 212:
! 213: /* Copy sections */
! 214: for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
! 215: sect_addr[i] = 0;
! 216: if (shdr->sh_type == SHT_PROGBITS) {
! 217:
! 218: elf_print("sh_addr=%x\n", shdr->sh_addr);
! 219: elf_print("sh_size=%x\n", shdr->sh_size);
! 220: elf_print("sh_offset=%x\n", shdr->sh_offset);
! 221: elf_print("sh_flags=%x\n", shdr->sh_flags);
! 222:
! 223: switch (shdr->sh_flags & SHF_VALID) {
! 224: case (SHF_ALLOC | SHF_EXECINSTR):
! 225: /* Text */
! 226: m->text = (u_long)phys_to_virt(load_base);
! 227: break;
! 228: case (SHF_ALLOC | SHF_WRITE):
! 229: /* Data */
! 230: if (m->data == 0)
! 231: m->data =
! 232: (u_long)phys_to_virt(load_base + shdr->sh_addr);
! 233: break;
! 234: case SHF_ALLOC:
! 235: /* rodata */
! 236: /* Note: rodata is treated as text. */
! 237: break;
! 238: default:
! 239: continue;
! 240: }
! 241: sect_base = load_base + shdr->sh_addr;
! 242: memcpy((char *)sect_base, img + shdr->sh_offset,
! 243: (size_t)shdr->sh_size);
! 244: elf_print("load: offset=%x size=%x\n",
! 245: sect_base, (int)shdr->sh_size);
! 246:
! 247: sect_addr[i] = (char *)sect_base;
! 248: } else if (shdr->sh_type == SHT_NOBITS) {
! 249: /* BSS */
! 250: m->bsssz = (size_t)shdr->sh_size;
! 251: sect_base = load_base + shdr->sh_addr;
! 252: bss_base = sect_base;
! 253:
! 254: /* Zero fill BSS */
! 255: memset((char *)sect_base, 0, (size_t)shdr->sh_size);
! 256:
! 257: sect_addr[i] = (char *)sect_base;
! 258: } else if (shdr->sh_type == SHT_SYMTAB) {
! 259: /* Symbol table */
! 260: sect_addr[i] = img + shdr->sh_offset;
! 261: }
! 262: }
! 263: m->textsz = (size_t)(m->data - m->text);
! 264: m->datasz = (size_t)(bss_base - m->data);
! 265:
! 266: load_base = bss_base + m->bsssz;
! 267: load_base = PAGE_ALIGN(load_base);
! 268:
! 269: elf_print("module load_base=%x text=%x\n", load_base, m->text);
! 270: m->size = (size_t)(load_base - (u_long)virt_to_phys(m->text));
! 271: m->entry = (u_long)phys_to_virt(ehdr->e_entry + m->phys);
! 272: elf_print("module size=%x entry=%x\n", m->size, m->entry);
! 273:
! 274: /* Process relocation */
! 275: shdr = (Elf32_Shdr *)((u_long)ehdr + ehdr->e_shoff);
! 276: for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
! 277: if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
! 278: if (relocate_section(img, shdr) != 0)
! 279: return -1;
! 280: }
! 281: }
! 282: return 0;
! 283: }
! 284:
! 285: /*
! 286: * Load the program from specified ELF image data stored in memory.
! 287: * The boot information is filled after loading the program.
! 288: */
! 289: int
! 290: elf_load(char *img, struct module *m)
! 291: {
! 292: Elf32_Ehdr *ehdr;
! 293: Elf32_Phdr *phdr;
! 294:
! 295: elf_print("\nelf_load\n");
! 296:
! 297: ehdr = (Elf32_Ehdr *)img;
! 298:
! 299: /* Check ELF header */
! 300: if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
! 301: (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
! 302: (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
! 303: (ehdr->e_ident[EI_MAG3] != ELFMAG3))
! 304: return -1;
! 305:
! 306: phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_ehsize);
! 307:
! 308: if (nr_img == 0) {
! 309: /* Initialize the load address */
! 310: load_base = (u_long)phys_to_virt(phdr->p_paddr);
! 311: if (load_base == 0)
! 312: return -1;
! 313: elf_print("kernel base=%x\n", load_base);
! 314: load_start = load_base;
! 315: }
! 316: else if (nr_img == 1) {
! 317: /* Second image => Driver */
! 318: elf_print("driver base=%x\n", load_base);
! 319: }
! 320: else {
! 321: /* Other images => Boot tasks */
! 322: elf_print("task base=%x\n", load_base);
! 323: }
! 324:
! 325: switch (ehdr->e_type) {
! 326: case ET_EXEC:
! 327: if (load_executable(img, m) != 0)
! 328: return -1;
! 329: break;
! 330: case ET_REL:
! 331: if (load_relocatable(img, m) != 0)
! 332: return -1;
! 333: break;
! 334: default:
! 335: elf_print("Unsupported file type\n");
! 336: return -1;
! 337: }
! 338: nr_img++;
! 339: return 0;
! 340: }
CVSweb