Files
xen/tools/firmware/hvmloader/32bitbios_support.c
T
Keir Fraser f7ffac81ac hvmloader: Fix ROMBIOS highmem relocation. Only SHF_ALLOC sections
should be relocated. SHT_NOBITS must be handled properly (space
explicitly allocated and zeroed).
Signed-off-by: Keir Fraser <keir@xensource.com>
2007-04-19 21:06:29 +01:00

169 lines
5.2 KiB
C

/*
* 32bitbios_support.c - relocation of 32bit BIOS implementation
*
* Stefan Berger, stefanb@us.ibm.com
* Copyright (c) 2006, International Business Machines Corporation.
*
* Keir Fraser, keir@xensource.com
* Copyright (c) 2007, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include <inttypes.h>
#include <elf.h>
#ifdef __sun__
#include <sys/machelf.h>
#endif
#include "util.h"
#include "config.h"
#include "../rombios/32bit/32bitbios_flat.h"
static void relocate_32bitbios(char *elfarray, uint32_t elfarraysize)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
char *secstrings = &elfarray[shdr[ehdr->e_shstrndx].sh_offset];
char *jump_table;
uint32_t reloc_off, reloc_size;
char *highbiosarea;
int i, jump_sec_idx = 0;
/*
* Step 1. General elf cleanup, and compute total relocation size.
*/
reloc_off = 0;
for ( i = 0; i < ehdr->e_shnum; i++ )
{
/* By default all section data points into elf image data array. */
shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
if ( !strcmp(".biosjumptable", secstrings + shdr[i].sh_name) )
{
/* We do not relocate the BIOS jump table to high memory. */
shdr[i].sh_flags &= ~SHF_ALLOC;
jump_sec_idx = i;
}
/* Fix up a corner case of address alignment. */
if ( shdr[i].sh_addralign == 0 )
shdr[i].sh_addralign = 1;
/* Any section which contains run-time data must be relocated. */
if ( shdr[i].sh_flags & SHF_ALLOC )
{
uint32_t mask = shdr[i].sh_addralign - 1;
reloc_off = (reloc_off + mask) & ~mask;
reloc_off += shdr[i].sh_size;
}
}
/*
* Step 2. Now we know the relocation size, allocate a chunk of high mem.
*/
reloc_size = reloc_off;
printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size);
highbiosarea = (char *)(long)e820_malloc(reloc_size);
BUG_ON(highbiosarea == NULL);
printf(" Relocating to 0x%x-0x%x ... ",
(uint32_t)&highbiosarea[0],
(uint32_t)&highbiosarea[reloc_size]);
/*
* Step 3. Copy run-time data into the newly-allocated high-memory chunk.
*/
reloc_off = 0;
for ( i = 0; i < ehdr->e_shnum; i++ )
{
uint32_t mask = shdr[i].sh_addralign - 1;
/* Nothing to do for non-run-time sections. */
if ( !(shdr[i].sh_flags & SHF_ALLOC) )
continue;
/* Copy from old location. */
reloc_off = (reloc_off + mask) & ~mask;
if ( shdr[i].sh_type == SHT_NOBITS )
memset(&highbiosarea[reloc_off], 0, shdr[i].sh_size);
else
memcpy(&highbiosarea[reloc_off], (void *)shdr[i].sh_addr,
shdr[i].sh_size);
/* Update address to new location. */
shdr[i].sh_addr = (Elf32_Addr)&highbiosarea[reloc_off];
reloc_off += shdr[i].sh_size;
}
BUG_ON(reloc_off != reloc_size);
/*
* Step 4. Perform relocations in high memory.
*/
for ( i = 0; i < ehdr->e_shnum; i++ )
{
Elf32_Sym *syms, *sym;
Elf32_Rel *rels;
char *code;
uint32_t *loc, fix;
int j;
if ( shdr[i].sh_type == SHT_RELA )
printf("Unsupported section type SHT_RELA\n");
if ( shdr[i].sh_type != SHT_REL )
continue;
syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr;
rels = (Elf32_Rel *)shdr[i].sh_addr;
code = (char *)shdr[shdr[i].sh_info].sh_addr;
for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ )
{
sym = &syms[ELF32_R_SYM(rels[j].r_info)];
loc = (uint32_t *)&code[rels[j].r_offset];
fix = shdr[sym->st_shndx].sh_addr + sym->st_value;
switch ( ELF32_R_TYPE(rels[j].r_info) )
{
case R_386_PC32:
*loc += fix - (uint32_t)loc;
break;
case R_386_32:
*loc += fix;
break;
}
}
}
/* Step 5. Find the ROMBIOS jump-table stub and copy in the real table. */
for ( jump_table = (char *)ROMBIOS_BEGIN;
jump_table != (char *)ROMBIOS_END;
jump_table++ )
if ( !strncmp(jump_table, "___JMPT", 7) )
break;
BUG_ON(jump_table == NULL);
BUG_ON(jump_sec_idx == 0);
memcpy(jump_table, (char *)shdr[jump_sec_idx].sh_addr,
shdr[jump_sec_idx].sh_size);
printf("done\n");
}
void highbios_setup(void)
{
relocate_32bitbios((char *)highbios_array, sizeof(highbios_array));
}