direct-io.hg

view tools/firmware/hvmloader/32bitbios_support.c @ 14392:5bc5ed857cc6

hvmloader: Simplify 32bit-bios relocator.
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Thu Mar 15 10:38:06 2007 +0000 (2007-03-15)
parents bef8a8b1e400
children cf32c9e54c8f
line source
1 /*
2 * 32bitbios_support.c - relocation of 32bit BIOS implementation
3 *
4 * Stefan Berger, stefanb@us.ibm.com
5 * Copyright (c) 2006, International Business Machines Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 */
20 #include <inttypes.h>
21 #include <elf.h>
22 #ifdef __sun__
23 #include <sys/machelf.h>
24 #endif
26 #include <xen/hvm/e820.h>
27 #include "util.h"
28 #include "config.h"
30 #include "../rombios/32bit/32bitbios_flat.h"
31 #include "../rombios/32bit/jumptable.h"
34 /*
35 * relocate ELF file of type ET_REL
36 */
37 static int relocate_elf(unsigned char *elfarray) {
38 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
39 Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
40 int i;
42 if (ehdr->e_type != ET_REL) {
43 printf("Not a relocatable BIOS object file. Has type %d, need %d\n",
44 ehdr->e_type, ET_REL);
45 return -1;
46 }
48 for (i = 0; i < ehdr->e_shnum; i++)
49 shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
51 for (i = 0; i < ehdr->e_shnum; i++) {
52 if (shdr[i].sh_type == SHT_REL) {
53 Elf32_Shdr *targetsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_info]);
54 Elf32_Shdr *symtabsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_link]);
55 Elf32_Sym *syms = (Elf32_Sym *)symtabsec->sh_addr;
56 Elf32_Rel *rels = (Elf32_Rel *)shdr[i].sh_addr;
57 unsigned char *code = (unsigned char *)targetsec->sh_addr;
58 int j;
60 /* must not have been stripped */
61 if (shdr[i].sh_size == 0)
62 return -6;
64 for (j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++) {
65 int idx = ELF32_R_SYM(rels[j].r_info);
66 Elf32_Sym *symbol = &syms[idx];
67 uint32_t *loc = (uint32_t *)&code[rels[j].r_offset];
68 uint32_t fix = shdr[symbol->st_shndx].sh_addr +
69 symbol->st_value;
71 switch (ELF32_R_TYPE(rels[j].r_info)) {
72 case R_386_PC32:
73 *loc += (fix - (uint32_t)loc);
74 break;
76 case R_386_32:
77 *loc += fix;
78 break;
79 }
80 }
81 } else if (shdr[i].sh_type == SHT_RELA) {
82 return -2;
83 }
84 }
85 return 0;
86 }
88 /* scan the rombios for the destination of the jumptable */
89 static char* get_jump_table_start(void)
90 {
91 char *bios_mem;
93 for ( bios_mem = (char *)ROMBIOS_BEGIN;
94 bios_mem != (char *)ROMBIOS_END;
95 bios_mem++ ) {
96 if (strncmp(bios_mem, "___JMPT", 7) == 0)
97 return bios_mem;
98 }
100 return NULL;
101 }
103 /* copy relocated jumptable into the rombios */
104 static int copy_jumptable(unsigned char *elfarray)
105 {
106 int rc = 0;
107 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
108 Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
109 Elf32_Shdr *shdr_strings = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx];
110 char *secstrings = (char *)&elfarray[shdr_strings->sh_offset];
111 uint32_t *rombiosjumptable = (uint32_t *)get_jump_table_start();
112 uint32_t *biosjumptable = NULL;
113 int i;
115 if (rombiosjumptable == NULL) {
116 return -3;
117 }
119 /* find the section with the jump table and copy to lower BIOS memory */
120 for (i = 0; i < ehdr->e_shnum; i++) {
121 if (!strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name)) {
122 uint32_t biosjumptableentries;
123 biosjumptable = (uint32_t *)shdr[i].sh_addr;
124 biosjumptableentries = shdr[i].sh_size / 4;
125 for (int j = 0; j < biosjumptableentries; j++) {
126 rombiosjumptable[j] = biosjumptable[j];
127 if (biosjumptable[j] == 0 &&
128 j < (biosjumptableentries - 1)) {
129 printf("WARNING: jumptable entry %d is NULL!\n",j);
130 }
131 }
132 break;
133 }
134 }
136 if (biosjumptable == NULL) {
137 printf("Could not find " JUMPTABLE_SECTION_NAME " section in file.\n");
138 rc = -4;
139 }
141 return 0;
142 }
144 static int relocate_32bitbios(unsigned char *elfarray, uint32_t elfarraysize)
145 {
146 int rc = 0;
147 uint32_t mask = (64 * 1024) - 1;
148 uint32_t to_malloc = (elfarraysize + mask) & ~mask; /* round to 64kb */
149 unsigned char *highbiosarea;
151 highbiosarea = (unsigned char *)(long)
152 e820_malloc((uint64_t)to_malloc,
153 E820_RESERVED,
154 (uint64_t)0xffffffff);
156 if (highbiosarea != 0) {
157 memcpy(highbiosarea, elfarray, elfarraysize);
158 rc = relocate_elf(highbiosarea);
159 if (rc == 0) {
160 rc = copy_jumptable(highbiosarea);
161 }
162 } else {
163 rc = -5;
164 }
166 return rc;
167 }
169 int highbios_setup(void)
170 {
171 return relocate_32bitbios((unsigned char *)highbios_array,
172 sizeof(highbios_array));
173 }