grub/grub-core/efiemu/symbols.c

273 lines
7.7 KiB
C
Raw Normal View History

/* Code for managing symbols and pointers in efiemu */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/efiemu/efiemu.h>
#include <grub/efiemu/runtime.h>
#include <grub/i18n.h>
static int ptv_written = 0;
static int ptv_alloc = 0;
static int ptv_handle = 0;
2009-09-02 11:34:40 +00:00
static int relocated_handle = 0;
static int ptv_requested = 0;
static struct grub_efiemu_sym *efiemu_syms = 0;
struct grub_efiemu_sym
{
struct grub_efiemu_sym *next;
char *name;
int handle;
grub_off_t off;
};
void
grub_efiemu_free_syms (void)
{
struct grub_efiemu_sym *cur, *d;
for (cur = efiemu_syms; cur;)
{
d = cur->next;
grub_free (cur->name);
grub_free (cur);
cur = d;
}
efiemu_syms = 0;
ptv_written = 0;
ptv_alloc = 0;
ptv_requested = 0;
grub_efiemu_mm_return_request (ptv_handle);
ptv_handle = 0;
2009-09-02 11:34:40 +00:00
grub_efiemu_mm_return_request (relocated_handle);
relocated_handle = 0;
}
/* Announce that the module will need NUM allocators */
2009-06-10 21:04:23 +00:00
/* Because of deferred memory allocation all the relocators have to be
announced during phase 1*/
grub_err_t
grub_efiemu_request_symbols (int num)
{
if (ptv_alloc)
2009-06-10 21:04:23 +00:00
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"symbols have already been allocated");
if (num < 0)
return grub_error (GRUB_ERR_BUG,
"can't request negative symbols");
ptv_requested += num;
return GRUB_ERR_NONE;
}
/* Resolve the symbol name NAME and set HANDLE and OFF accordingly */
grub_err_t
grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off)
{
struct grub_efiemu_sym *cur;
for (cur = efiemu_syms; cur; cur = cur->next)
if (!grub_strcmp (name, cur->name))
{
*handle = cur->handle;
*off = cur->off;
return GRUB_ERR_NONE;
}
grub_dprintf ("efiemu", "%s not found\n", name);
return grub_error (GRUB_ERR_BAD_OS, N_("symbol `%s' not found"), name);
}
/* Register symbol named NAME in memory handle HANDLE at offset OFF */
grub_err_t
grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off)
{
struct grub_efiemu_sym *cur;
cur = (struct grub_efiemu_sym *) grub_malloc (sizeof (*cur));
grub_dprintf ("efiemu", "registering symbol '%s'\n", name);
if (!cur)
return grub_errno;
cur->name = grub_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 */
grub_err_t
grub_efiemu_alloc_syms (void)
{
ptv_alloc = ptv_requested;
2009-06-10 21:04:23 +00:00
ptv_handle = grub_efiemu_request_memalign
(1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel),
GRUB_EFI_RUNTIME_SERVICES_DATA);
2009-09-02 11:34:40 +00:00
relocated_handle = grub_efiemu_request_memalign
(1, sizeof (grub_uint8_t), GRUB_EFI_RUNTIME_SERVICES_DATA);
grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0);
grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
return grub_errno;
}
2009-09-02 11:34:40 +00:00
grub_err_t
grub_efiemu_write_sym_markers (void)
{
struct grub_efiemu_ptv_rel *ptv_rels
= grub_efiemu_mm_obtain_request (ptv_handle);
grub_uint8_t *relocated = grub_efiemu_mm_obtain_request (relocated_handle);
grub_memset (ptv_rels, 0, (ptv_requested + 1)
* sizeof (struct grub_efiemu_ptv_rel));
*relocated = 0;
return GRUB_ERR_NONE;
}
2009-06-10 21:04:23 +00:00
/* 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
*/
grub_err_t
grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
int minus_handle, int ptv_needed, int size)
{
/* Announce relocator to runtime */
if (ptv_needed)
{
2009-06-10 21:04:23 +00:00
struct grub_efiemu_ptv_rel *ptv_rels
= grub_efiemu_mm_obtain_request (ptv_handle);
if (ptv_needed && ptv_written >= ptv_alloc)
return grub_error (GRUB_ERR_BUG,
"your module didn't declare efiemu "
" relocators correctly");
if (minus_handle)
2009-06-10 21:04:23 +00:00
ptv_rels[ptv_written].minustype
= grub_efiemu_mm_get_type (minus_handle);
else
ptv_rels[ptv_written].minustype = 0;
if (plus_handle)
2009-06-10 21:04:23 +00:00
ptv_rels[ptv_written].plustype
= grub_efiemu_mm_get_type (plus_handle);
else
ptv_rels[ptv_written].plustype = 0;
ptv_rels[ptv_written].addr = (grub_addr_t) addr;
ptv_rels[ptv_written].size = size;
ptv_written++;
2009-06-10 21:04:23 +00:00
/* memset next value to zero to mark the end */
grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
}
/* Compute the value */
if (minus_handle)
value -= (grub_addr_t) grub_efiemu_mm_obtain_request (minus_handle);
if (plus_handle)
value += (grub_addr_t) grub_efiemu_mm_obtain_request (plus_handle);
/* Write the value */
switch (size)
{
case 8:
*((grub_uint64_t *) addr) = value;
break;
case 4:
*((grub_uint32_t *) addr) = value;
break;
case 2:
*((grub_uint16_t *) addr) = value;
break;
case 1:
*((grub_uint8_t *) addr) = value;
break;
default:
return grub_error (GRUB_ERR_BUG, "wrong symbol size");
}
return GRUB_ERR_NONE;
}
2009-09-02 11:34:40 +00:00
grub_err_t
grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version
__attribute__ ((unused)),
grub_efi_memory_descriptor_t *virtual_map)
{
grub_uint8_t *ptv_relocated;
struct grub_efiemu_ptv_rel *cur_relloc;
struct grub_efiemu_ptv_rel *ptv_rels;
ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle);
ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle);
/* Ensure that we are called only once */
if (*ptv_relocated)
2009-12-24 Carles Pina i Estany <carles@pina.cat> * bus/usb/usbhub.c: Fix capitalization, fullstop and newlines in grub_errno calls. * commands/acpi.c: Likewise. * commands/blocklist.c: Likewise. * commands/efi/loadbios.c: Likewise. * commands/i386/pc/drivemap.c: Likewise. * commands/loadenv.c: Likewise. * commands/memrw.c: Likewise. * commands/password.c: Likewise. * commands/videotest.c: Likewise. * disk/ata.c: Likewise. * disk/ata_pthru.c: Likewise. * disk/dmraid_nvidia.c: Likewise. * disk/ieee1275/nand.c: Likewise. * disk/ieee1275/ofdisk.c: Likewise. * disk/loopback.c: Likewise. * disk/lvm.c: Likewise. * disk/mdraid_linux.c: Likewise. * disk/raid.c: Likewise. * disk/raid6_recover.c: Likewise. * disk/scsi.c: Likewise. * efiemu/main.c: Likewise. * efiemu/mm.c: Likewise. * efiemu/pnvram.c: Likewise. * efiemu/symbols.c: Likewise. * font/font.c: Likewise. * fs/cpio.c: Likewise. * fs/hfsplus.c: Likewise. * fs/iso9660.c: Likewise. * fs/jfs.c: Likewise. * fs/minix.c: Likewise. * fs/ntfs.c: Likewise. * fs/ntfscomp.c: Likewise. * fs/reiserfs.c: Likewise. * fs/ufs.c: Likewise. * fs/xfs.c: Likewise. * gettext/gettext.c: Likewise. * include/grub/auth.h: Likewise. * kern/elf.c: Likewise. * kern/file.c: Likewise. * kern/ieee1275/init.c: Likewise. * kern/ieee1275/mmap.c: Likewise. * kern/ieee1275/openfw.c: Likewise. * kern/powerpc/dl.c: Likewise. * kern/sparc64/dl.c: Likewise. * lib/arg.c: Likewise. * loader/i386/bsd.c: Likewise. * loader/i386/bsdXX.c: Likewise. * loader/i386/efi/linux.c: Likewise. * loader/i386/efi/xnu.c: Likewise. * loader/i386/ieee1275/linux.c: Likewise. * loader/i386/linux.c: Likewise. * loader/i386/multiboot.c: Likewise. * loader/i386/pc/linux.c: Likewise. * loader/i386/pc/multiboot2.c: Likewise. * loader/i386/xnu.c: Likewise. * loader/ieee1275/multiboot2.c: Likewise. * loader/macho.c: Likewise. * loader/machoXX.c: Likewise. * loader/multiboot2.c: Likewise. * loader/multiboot_loader.c: Likewise. * loader/powerpc/ieee1275/linux.c: Likewise. * loader/sparc64/ieee1275/linux.c: Likewise. * loader/xnu.c: Likewise. * loader/xnu_resume.c: Likewise. * mmap/i386/pc/mmap.c: Likewise. * normal/menu_viewer.c: Likewise. * partmap/acorn.c: Likewise. * partmap/amiga.c: Likewise. * partmap/apple.c: Likewise. * script/lexer.c: Likewise. * term/gfxterm.c: Likewise. * term/i386/pc/serial.c: Likewise. * term/i386/pc/vga.c: Likewise. * term/ieee1275/ofconsole.c: Likewise. * term/terminfo.c: Likewise. * video/bitmap.c: Likewise. * video/efi_gop.c: Likewise. * video/efi_uga.c: Likewise. * video/fb/video_fb.c: Likewise. * video/i386/pc/vbe.c: Likewise. * video/readers/tga.c: Likewise. * video/video.c: Likewise.
2009-12-24 22:53:05 +00:00
return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated");
2009-09-02 11:34:40 +00:00
*ptv_relocated = 1;
/* Correct addresses using information supplied by grub */
for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++)
{
grub_int64_t corr = 0;
grub_efi_memory_descriptor_t *descptr;
/* Compute correction */
for (descptr = virtual_map;
(grub_size_t) ((grub_uint8_t *) descptr
- (grub_uint8_t *) virtual_map) < memory_map_size;
descptr = (grub_efi_memory_descriptor_t *)
((grub_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:
*((grub_uint64_t *) (grub_addr_t) cur_relloc->addr) += corr;
2009-09-02 11:34:40 +00:00
break;
case 4:
*((grub_uint32_t *) (grub_addr_t) cur_relloc->addr) += corr;
2009-09-02 11:34:40 +00:00
break;
case 2:
*((grub_uint16_t *) (grub_addr_t) cur_relloc->addr) += corr;
2009-09-02 11:34:40 +00:00
break;
case 1:
*((grub_uint8_t *) (grub_addr_t) cur_relloc->addr) += corr;
2009-09-02 11:34:40 +00:00
break;
}
}
/* Recompute crc32 of system table and runtime services */
if (grub_efiemu_sizeof_uintn_t () == 4)
return grub_efiemu_crc32 ();
else
return grub_efiemu_crc64 ();
}