273 lines
8.2 KiB
C
273 lines
8.2 KiB
C
/* Code for managing symbols and pointers in efiemu */
|
|
/*
|
|
* VasEBoot -- GRand Unified Bootloader
|
|
* Copyright (C) 2009 Free Software Foundation, Inc.
|
|
*
|
|
* VasEBoot is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* VasEBoot is distributed in the hope that 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 VasEBoot. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <VasEBoot/err.h>
|
|
#include <VasEBoot/mm.h>
|
|
#include <VasEBoot/misc.h>
|
|
#include <VasEBoot/efiemu/efiemu.h>
|
|
#include <VasEBoot/efiemu/runtime.h>
|
|
#include <VasEBoot/i18n.h>
|
|
|
|
static int ptv_written = 0;
|
|
static int ptv_alloc = 0;
|
|
static int ptv_handle = 0;
|
|
static int relocated_handle = 0;
|
|
static int ptv_requested = 0;
|
|
static struct VasEBoot_efiemu_sym *efiemu_syms = 0;
|
|
|
|
struct VasEBoot_efiemu_sym
|
|
{
|
|
struct VasEBoot_efiemu_sym *next;
|
|
char *name;
|
|
int handle;
|
|
VasEBoot_off_t off;
|
|
};
|
|
|
|
void
|
|
VasEBoot_efiemu_free_syms (void)
|
|
{
|
|
struct VasEBoot_efiemu_sym *cur, *d;
|
|
for (cur = efiemu_syms; cur;)
|
|
{
|
|
d = cur->next;
|
|
VasEBoot_free (cur->name);
|
|
VasEBoot_free (cur);
|
|
cur = d;
|
|
}
|
|
efiemu_syms = 0;
|
|
ptv_written = 0;
|
|
ptv_alloc = 0;
|
|
ptv_requested = 0;
|
|
VasEBoot_efiemu_mm_return_request (ptv_handle);
|
|
ptv_handle = 0;
|
|
VasEBoot_efiemu_mm_return_request (relocated_handle);
|
|
relocated_handle = 0;
|
|
}
|
|
|
|
/* Announce that the module will need NUM allocators */
|
|
/* Because of deferred memory allocation all the relocators have to be
|
|
announced during phase 1*/
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_request_symbols (int num)
|
|
{
|
|
if (ptv_alloc)
|
|
return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT,
|
|
"symbols have already been allocated");
|
|
if (num < 0)
|
|
return VasEBoot_error (VasEBoot_ERR_BUG,
|
|
"can't request negative symbols");
|
|
ptv_requested += num;
|
|
return VasEBoot_ERR_NONE;
|
|
}
|
|
|
|
/* Resolve the symbol name NAME and set HANDLE and OFF accordingly */
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_resolve_symbol (const char *name, int *handle, VasEBoot_off_t *off)
|
|
{
|
|
struct VasEBoot_efiemu_sym *cur;
|
|
for (cur = efiemu_syms; cur; cur = cur->next)
|
|
if (!VasEBoot_strcmp (name, cur->name))
|
|
{
|
|
*handle = cur->handle;
|
|
*off = cur->off;
|
|
return VasEBoot_ERR_NONE;
|
|
}
|
|
VasEBoot_dprintf ("efiemu", "%s not found\n", name);
|
|
return VasEBoot_error (VasEBoot_ERR_BAD_OS, N_("symbol `%s' not found"), name);
|
|
}
|
|
|
|
/* Register symbol named NAME in memory handle HANDLE at offset OFF */
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_register_symbol (const char *name, int handle, VasEBoot_off_t off)
|
|
{
|
|
struct VasEBoot_efiemu_sym *cur;
|
|
cur = (struct VasEBoot_efiemu_sym *) VasEBoot_malloc (sizeof (*cur));
|
|
VasEBoot_dprintf ("efiemu", "registering symbol '%s'\n", name);
|
|
if (!cur)
|
|
return VasEBoot_errno;
|
|
cur->name = VasEBoot_strdup (name);
|
|
cur->next = efiemu_syms;
|
|
cur->handle = handle;
|
|
cur->off = off;
|
|
efiemu_syms = cur;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_alloc_syms (void)
|
|
{
|
|
ptv_alloc = ptv_requested;
|
|
ptv_handle = VasEBoot_efiemu_request_memalign
|
|
(1, (ptv_requested + 1) * sizeof (struct VasEBoot_efiemu_ptv_rel),
|
|
VasEBoot_EFI_RUNTIME_SERVICES_DATA);
|
|
relocated_handle = VasEBoot_efiemu_request_memalign
|
|
(1, sizeof (VasEBoot_uint8_t), VasEBoot_EFI_RUNTIME_SERVICES_DATA);
|
|
|
|
VasEBoot_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0);
|
|
VasEBoot_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
|
|
return VasEBoot_errno;
|
|
}
|
|
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_write_sym_markers (void)
|
|
{
|
|
struct VasEBoot_efiemu_ptv_rel *ptv_rels
|
|
= VasEBoot_efiemu_mm_obtain_request (ptv_handle);
|
|
VasEBoot_uint8_t *relocated = VasEBoot_efiemu_mm_obtain_request (relocated_handle);
|
|
VasEBoot_memset (ptv_rels, 0, (ptv_requested + 1)
|
|
* sizeof (struct VasEBoot_efiemu_ptv_rel));
|
|
*relocated = 0;
|
|
return VasEBoot_ERR_NONE;
|
|
}
|
|
|
|
/* Write value (pointer to memory PLUS_HANDLE)
|
|
- (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the
|
|
size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this
|
|
value needs to be recomputed before going to virtual mode
|
|
*/
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_write_value (void *addr, VasEBoot_uint32_t value, int plus_handle,
|
|
int minus_handle, int ptv_needed, int size)
|
|
{
|
|
/* Announce relocator to runtime */
|
|
if (ptv_needed)
|
|
{
|
|
struct VasEBoot_efiemu_ptv_rel *ptv_rels
|
|
= VasEBoot_efiemu_mm_obtain_request (ptv_handle);
|
|
|
|
if (ptv_needed && ptv_written >= ptv_alloc)
|
|
return VasEBoot_error (VasEBoot_ERR_BUG,
|
|
"your module didn't declare efiemu "
|
|
" relocators correctly");
|
|
|
|
if (minus_handle)
|
|
ptv_rels[ptv_written].minustype
|
|
= VasEBoot_efiemu_mm_get_type (minus_handle);
|
|
else
|
|
ptv_rels[ptv_written].minustype = 0;
|
|
|
|
if (plus_handle)
|
|
ptv_rels[ptv_written].plustype
|
|
= VasEBoot_efiemu_mm_get_type (plus_handle);
|
|
else
|
|
ptv_rels[ptv_written].plustype = 0;
|
|
|
|
ptv_rels[ptv_written].addr = (VasEBoot_addr_t) addr;
|
|
ptv_rels[ptv_written].size = size;
|
|
ptv_written++;
|
|
|
|
/* memset next value to zero to mark the end */
|
|
VasEBoot_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
|
|
}
|
|
|
|
/* Compute the value */
|
|
if (minus_handle)
|
|
value -= (VasEBoot_addr_t) VasEBoot_efiemu_mm_obtain_request (minus_handle);
|
|
|
|
if (plus_handle)
|
|
value += (VasEBoot_addr_t) VasEBoot_efiemu_mm_obtain_request (plus_handle);
|
|
|
|
/* Write the value */
|
|
switch (size)
|
|
{
|
|
case 8:
|
|
*((VasEBoot_uint64_t *) addr) = value;
|
|
break;
|
|
case 4:
|
|
*((VasEBoot_uint32_t *) addr) = value;
|
|
break;
|
|
case 2:
|
|
*((VasEBoot_uint16_t *) addr) = value;
|
|
break;
|
|
case 1:
|
|
*((VasEBoot_uint8_t *) addr) = value;
|
|
break;
|
|
default:
|
|
return VasEBoot_error (VasEBoot_ERR_BUG, "wrong symbol size");
|
|
}
|
|
|
|
return VasEBoot_ERR_NONE;
|
|
}
|
|
|
|
VasEBoot_err_t
|
|
VasEBoot_efiemu_set_virtual_address_map (VasEBoot_efi_uintn_t memory_map_size,
|
|
VasEBoot_efi_uintn_t descriptor_size,
|
|
VasEBoot_efi_uint32_t descriptor_version
|
|
__attribute__ ((unused)),
|
|
VasEBoot_efi_memory_descriptor_t *virtual_map)
|
|
{
|
|
VasEBoot_uint8_t *ptv_relocated;
|
|
struct VasEBoot_efiemu_ptv_rel *cur_relloc;
|
|
struct VasEBoot_efiemu_ptv_rel *ptv_rels;
|
|
|
|
ptv_relocated = VasEBoot_efiemu_mm_obtain_request (relocated_handle);
|
|
ptv_rels = VasEBoot_efiemu_mm_obtain_request (ptv_handle);
|
|
|
|
/* Ensure that we are called only once */
|
|
if (*ptv_relocated)
|
|
return VasEBoot_error (VasEBoot_ERR_BUG, "EfiEmu is already relocated");
|
|
*ptv_relocated = 1;
|
|
|
|
/* Correct addresses using information supplied by VasEBoot */
|
|
for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++)
|
|
{
|
|
VasEBoot_int64_t corr = 0;
|
|
VasEBoot_efi_memory_descriptor_t *descptr;
|
|
|
|
/* Compute correction */
|
|
for (descptr = virtual_map;
|
|
(VasEBoot_size_t) ((VasEBoot_uint8_t *) descptr
|
|
- (VasEBoot_uint8_t *) virtual_map) < memory_map_size;
|
|
descptr = (VasEBoot_efi_memory_descriptor_t *)
|
|
((VasEBoot_uint8_t *) descptr + descriptor_size))
|
|
{
|
|
if (descptr->type == cur_relloc->plustype)
|
|
corr += descptr->virtual_start - descptr->physical_start;
|
|
if (descptr->type == cur_relloc->minustype)
|
|
corr -= descptr->virtual_start - descptr->physical_start;
|
|
}
|
|
|
|
/* Apply correction */
|
|
switch (cur_relloc->size)
|
|
{
|
|
case 8:
|
|
*((VasEBoot_uint64_t *) (VasEBoot_addr_t) cur_relloc->addr) += corr;
|
|
break;
|
|
case 4:
|
|
*((VasEBoot_uint32_t *) (VasEBoot_addr_t) cur_relloc->addr) += corr;
|
|
break;
|
|
case 2:
|
|
*((VasEBoot_uint16_t *) (VasEBoot_addr_t) cur_relloc->addr) += corr;
|
|
break;
|
|
case 1:
|
|
*((VasEBoot_uint8_t *) (VasEBoot_addr_t) cur_relloc->addr) += corr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Recompute crc32 of system table and runtime services */
|
|
|
|
if (VasEBoot_efiemu_sizeof_uintn_t () == 4)
|
|
return VasEBoot_efiemu_crc32 ();
|
|
else
|
|
return VasEBoot_efiemu_crc64 ();
|
|
}
|