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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <stdint.h>
24 #include <xen/libelf/elfstructs.h>
25
26 #include "util.h"
27 #include "config.h"
28
29 #include "../rombios/32bit/32bitbios_flat.h"
30
relocate_32bitbios(char * elfarray,uint32_t elfarraysize)31 static uint32_t relocate_32bitbios(char *elfarray, uint32_t elfarraysize)
32 {
33 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
34 Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
35 uint32_t reloc_off, reloc_size;
36 char *highbiosarea;
37 int i;
38
39 /*
40 * Step 1. General elf cleanup, and compute total relocation size.
41 */
42 reloc_off = 0;
43 for ( i = 0; i < ehdr->e_shnum; i++ )
44 {
45 /* By default all section data points into elf image data array. */
46 shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
47
48 /* Fix up a corner case of address alignment. */
49 if ( shdr[i].sh_addralign == 0 )
50 shdr[i].sh_addralign = 1;
51
52 /* Any section which contains run-time data must be relocated. */
53 if ( shdr[i].sh_flags & SHF_ALLOC )
54 {
55 uint32_t mask = shdr[i].sh_addralign - 1;
56 reloc_off = (reloc_off + mask) & ~mask;
57 reloc_off += shdr[i].sh_size;
58 }
59 }
60
61 /*
62 * Step 2. Now we know the relocation size, allocate a chunk of high mem.
63 */
64 reloc_size = reloc_off;
65 printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size);
66 highbiosarea = mem_alloc(reloc_size, 1024);
67 BUG_ON(highbiosarea == NULL);
68 printf(" Relocating to 0x%x-0x%x ... ",
69 (uint32_t)&highbiosarea[0],
70 (uint32_t)&highbiosarea[reloc_size]);
71
72 /*
73 * Step 3. Copy run-time data into the newly-allocated high-memory chunk.
74 */
75 reloc_off = 0;
76 for ( i = 0; i < ehdr->e_shnum; i++ )
77 {
78 uint32_t mask = shdr[i].sh_addralign - 1;
79
80 /* Nothing to do for non-run-time sections. */
81 if ( !(shdr[i].sh_flags & SHF_ALLOC) )
82 continue;
83
84 /* Copy from old location. */
85 reloc_off = (reloc_off + mask) & ~mask;
86 if ( shdr[i].sh_type == SHT_NOBITS )
87 memset(&highbiosarea[reloc_off], 0, shdr[i].sh_size);
88 else
89 memcpy(&highbiosarea[reloc_off], (void *)shdr[i].sh_addr,
90 shdr[i].sh_size);
91
92 /* Update address to new location. */
93 shdr[i].sh_addr = (Elf32_Addr)&highbiosarea[reloc_off];
94 reloc_off += shdr[i].sh_size;
95 }
96 BUG_ON(reloc_off != reloc_size);
97
98 /*
99 * Step 4. Perform relocations in high memory.
100 */
101 for ( i = 0; i < ehdr->e_shnum; i++ )
102 {
103 Elf32_Sym *syms, *sym;
104 Elf32_Rel *rels;
105 char *code;
106 uint32_t *loc, fix;
107 int j;
108
109 if ( shdr[i].sh_type == SHT_RELA )
110 printf("Unsupported section type SHT_RELA\n");
111
112 if ( shdr[i].sh_type != SHT_REL )
113 continue;
114
115 syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr;
116 rels = (Elf32_Rel *)shdr[i].sh_addr;
117 code = (char *)shdr[shdr[i].sh_info].sh_addr;
118
119 for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ )
120 {
121 sym = &syms[ELF32_R_SYM(rels[j].r_info)];
122 loc = (uint32_t *)&code[rels[j].r_offset];
123 fix = shdr[sym->st_shndx].sh_addr + sym->st_value;
124
125 switch ( ELF32_R_TYPE(rels[j].r_info) )
126 {
127 case R_386_PC32:
128 *loc += fix - (uint32_t)loc;
129 break;
130
131 case R_386_32:
132 *loc += fix;
133 break;
134 }
135 }
136 }
137
138 printf("done\n");
139
140 return (uint32_t)highbiosarea;
141 }
142
rombios_highbios_setup(void)143 uint32_t rombios_highbios_setup(void)
144 {
145 return relocate_32bitbios((char *)highbios_array, sizeof(highbios_array));
146 }
147
148 /*
149 * Local variables:
150 * mode: C
151 * c-file-style: "BSD"
152 * c-basic-offset: 4
153 * tab-width: 4
154 * indent-tabs-mode: nil
155 * End:
156 */
157