ia64/xen-unstable

view tools/firmware/hvmloader/32bitbios_support.c @ 19079:f3240cd3cd2b

rombios: Indirect through 32-bit jump table from within the 32-bit bios.

This gets rid of shenanigans with relocating the jump table around the
place.

Also clean up bios_info table while we are updating it.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jan 23 14:32:41 2009 +0000 (2009-01-23)
parents 67ffce500feb
children
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 * Keir Fraser, keir@xensource.com
8 * Copyright (c) 2007, XenSource Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms and conditions of the GNU General Public License,
12 * version 2, as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 * Place - Suite 330, Boston, MA 02111-1307 USA.
22 */
24 #include <inttypes.h>
25 #include <elf.h>
26 #ifdef __sun__
27 #include <sys/machelf.h>
28 #endif
30 #include "util.h"
31 #include "config.h"
33 #include "../rombios/32bit/32bitbios_flat.h"
35 static uint32_t relocate_32bitbios(char *elfarray, uint32_t elfarraysize)
36 {
37 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
38 Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
39 uint32_t reloc_off, reloc_size;
40 char *highbiosarea;
41 int i;
43 /*
44 * Step 1. General elf cleanup, and compute total relocation size.
45 */
46 reloc_off = 0;
47 for ( i = 0; i < ehdr->e_shnum; i++ )
48 {
49 /* By default all section data points into elf image data array. */
50 shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
52 /* Fix up a corner case of address alignment. */
53 if ( shdr[i].sh_addralign == 0 )
54 shdr[i].sh_addralign = 1;
56 /* Any section which contains run-time data must be relocated. */
57 if ( shdr[i].sh_flags & SHF_ALLOC )
58 {
59 uint32_t mask = shdr[i].sh_addralign - 1;
60 reloc_off = (reloc_off + mask) & ~mask;
61 reloc_off += shdr[i].sh_size;
62 }
63 }
65 /*
66 * Step 2. Now we know the relocation size, allocate a chunk of high mem.
67 */
68 reloc_size = reloc_off;
69 printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size);
70 highbiosarea = mem_alloc(reloc_size, 0);
71 BUG_ON(highbiosarea == NULL);
72 printf(" Relocating to 0x%x-0x%x ... ",
73 (uint32_t)&highbiosarea[0],
74 (uint32_t)&highbiosarea[reloc_size]);
76 /*
77 * Step 3. Copy run-time data into the newly-allocated high-memory chunk.
78 */
79 reloc_off = 0;
80 for ( i = 0; i < ehdr->e_shnum; i++ )
81 {
82 uint32_t mask = shdr[i].sh_addralign - 1;
84 /* Nothing to do for non-run-time sections. */
85 if ( !(shdr[i].sh_flags & SHF_ALLOC) )
86 continue;
88 /* Copy from old location. */
89 reloc_off = (reloc_off + mask) & ~mask;
90 if ( shdr[i].sh_type == SHT_NOBITS )
91 memset(&highbiosarea[reloc_off], 0, shdr[i].sh_size);
92 else
93 memcpy(&highbiosarea[reloc_off], (void *)shdr[i].sh_addr,
94 shdr[i].sh_size);
96 /* Update address to new location. */
97 shdr[i].sh_addr = (Elf32_Addr)&highbiosarea[reloc_off];
98 reloc_off += shdr[i].sh_size;
99 }
100 BUG_ON(reloc_off != reloc_size);
102 /*
103 * Step 4. Perform relocations in high memory.
104 */
105 for ( i = 0; i < ehdr->e_shnum; i++ )
106 {
107 Elf32_Sym *syms, *sym;
108 Elf32_Rel *rels;
109 char *code;
110 uint32_t *loc, fix;
111 int j;
113 if ( shdr[i].sh_type == SHT_RELA )
114 printf("Unsupported section type SHT_RELA\n");
116 if ( shdr[i].sh_type != SHT_REL )
117 continue;
119 syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr;
120 rels = (Elf32_Rel *)shdr[i].sh_addr;
121 code = (char *)shdr[shdr[i].sh_info].sh_addr;
123 for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ )
124 {
125 sym = &syms[ELF32_R_SYM(rels[j].r_info)];
126 loc = (uint32_t *)&code[rels[j].r_offset];
127 fix = shdr[sym->st_shndx].sh_addr + sym->st_value;
129 switch ( ELF32_R_TYPE(rels[j].r_info) )
130 {
131 case R_386_PC32:
132 *loc += fix - (uint32_t)loc;
133 break;
135 case R_386_32:
136 *loc += fix;
137 break;
138 }
139 }
140 }
142 printf("done\n");
144 return (uint32_t)highbiosarea;
145 }
147 uint32_t highbios_setup(void)
148 {
149 return relocate_32bitbios((char *)highbios_array, sizeof(highbios_array));
150 }