vaseboot/VasEBoot-core/lib/i386/relocator.c

211 lines
7.0 KiB
C

/*
* VAS_EBOOT -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* VAS_EBOOT 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.
*
* VAS_EBOOT 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 VAS_EBOOT. If not, see <http://www.gnu.org/licenses/>.
*/
#include <VasEBoot/mm.h>
#include <VasEBoot/misc.h>
#include <VasEBoot/types.h>
#include <VasEBoot/err.h>
#include <VasEBoot/term.h>
#include <VasEBoot/i386/relocator.h>
#include <VasEBoot/relocator_private.h>
#include <VasEBoot/i386/relocator_private.h>
#include <VasEBoot/i386/pc/int.h>
extern VasEBoot_uint8_t VasEBoot_relocator16_start;
extern VasEBoot_uint8_t VasEBoot_relocator16_end;
extern VasEBoot_uint16_t VasEBoot_relocator16_cs;
extern VasEBoot_uint16_t VasEBoot_relocator16_ip;
extern VasEBoot_uint16_t VasEBoot_relocator16_ds;
extern VasEBoot_uint16_t VasEBoot_relocator16_es;
extern VasEBoot_uint16_t VasEBoot_relocator16_fs;
extern VasEBoot_uint16_t VasEBoot_relocator16_gs;
extern VasEBoot_uint16_t VasEBoot_relocator16_ss;
extern VasEBoot_uint16_t VasEBoot_relocator16_sp;
extern VasEBoot_uint32_t VasEBoot_relocator16_edx;
extern VasEBoot_uint32_t VasEBoot_relocator16_ebx;
extern VasEBoot_uint32_t VasEBoot_relocator16_esi;
extern VasEBoot_uint32_t VasEBoot_relocator16_ebp;
extern VasEBoot_uint16_t VasEBoot_relocator16_keep_a20_enabled;
extern VasEBoot_uint8_t VasEBoot_relocator32_start;
extern VasEBoot_uint8_t VasEBoot_relocator32_end;
extern VasEBoot_uint32_t VasEBoot_relocator32_eax;
extern VasEBoot_uint32_t VasEBoot_relocator32_ebx;
extern VasEBoot_uint32_t VasEBoot_relocator32_ecx;
extern VasEBoot_uint32_t VasEBoot_relocator32_edx;
extern VasEBoot_uint32_t VasEBoot_relocator32_eip;
extern VasEBoot_uint32_t VasEBoot_relocator32_esp;
extern VasEBoot_uint32_t VasEBoot_relocator32_ebp;
extern VasEBoot_uint32_t VasEBoot_relocator32_esi;
extern VasEBoot_uint32_t VasEBoot_relocator32_edi;
extern VasEBoot_uint8_t VasEBoot_relocator64_start;
extern VasEBoot_uint8_t VasEBoot_relocator64_end;
extern VasEBoot_uint64_t VasEBoot_relocator64_rax;
extern VasEBoot_uint64_t VasEBoot_relocator64_rbx;
extern VasEBoot_uint64_t VasEBoot_relocator64_rcx;
extern VasEBoot_uint64_t VasEBoot_relocator64_rdx;
extern VasEBoot_uint64_t VasEBoot_relocator64_rip;
extern VasEBoot_uint64_t VasEBoot_relocator64_rsp;
extern VasEBoot_uint64_t VasEBoot_relocator64_rsi;
extern VasEBoot_addr_t VasEBoot_relocator64_cr3;
extern struct VasEBoot_i386_idt VasEBoot_relocator16_idt;
#define RELOCATOR_SIZEOF(x) (&VasEBoot_relocator##x##_end - &VasEBoot_relocator##x##_start)
VasEBoot_err_t
VasEBoot_relocator32_boot (struct VasEBoot_relocator *rel,
struct VasEBoot_relocator32_state state,
int avoid_efi_bootservices)
{
VasEBoot_err_t err;
void *relst;
VasEBoot_relocator_chunk_t ch;
/* Specific memory range due to Global Descriptor Table for use by payload
that we will store in returned chunk. The address range and preference
are based on "THE LINUX/x86 BOOT PROTOCOL" specification. */
err = VasEBoot_relocator_alloc_chunk_align_safe (rel, &ch, 0x1000, 0x9a000,
RELOCATOR_SIZEOF (32), 16,
VAS_EBOOT_RELOCATOR_PREFERENCE_LOW,
avoid_efi_bootservices);
if (err)
return err;
VasEBoot_relocator32_eax = state.eax;
VasEBoot_relocator32_ebx = state.ebx;
VasEBoot_relocator32_ecx = state.ecx;
VasEBoot_relocator32_edx = state.edx;
VasEBoot_relocator32_eip = state.eip;
VasEBoot_relocator32_esp = state.esp;
VasEBoot_relocator32_ebp = state.ebp;
VasEBoot_relocator32_esi = state.esi;
VasEBoot_relocator32_edi = state.edi;
VasEBoot_memmove (get_virtual_current_address (ch), &VasEBoot_relocator32_start,
RELOCATOR_SIZEOF (32));
err = VasEBoot_relocator_prepare_relocs (rel, get_physical_target_address (ch),
&relst, NULL);
if (err)
return err;
asm volatile ("cli");
((void (*) (void)) relst) ();
/* Not reached. */
return VAS_EBOOT_ERR_NONE;
}
VasEBoot_err_t
VasEBoot_relocator16_boot (struct VasEBoot_relocator *rel,
struct VasEBoot_relocator16_state state)
{
VasEBoot_err_t err;
void *relst;
VasEBoot_relocator_chunk_t ch;
/* Put it higher than the byte it checks for A20 check. */
err = VasEBoot_relocator_alloc_chunk_align_safe (rel, &ch, 0x8010, 0xa0000,
RELOCATOR_SIZEOF (16) +
VAS_EBOOT_RELOCATOR16_STACK_SIZE, 16,
VAS_EBOOT_RELOCATOR_PREFERENCE_NONE, 0);
if (err)
return err;
VasEBoot_relocator16_cs = state.cs;
VasEBoot_relocator16_ip = state.ip;
VasEBoot_relocator16_ds = state.ds;
VasEBoot_relocator16_es = state.es;
VasEBoot_relocator16_fs = state.fs;
VasEBoot_relocator16_gs = state.gs;
VasEBoot_relocator16_ss = state.ss;
VasEBoot_relocator16_sp = state.sp;
VasEBoot_relocator16_ebp = state.ebp;
VasEBoot_relocator16_ebx = state.ebx;
VasEBoot_relocator16_edx = state.edx;
VasEBoot_relocator16_esi = state.esi;
#ifdef VAS_EBOOT_MACHINE_PCBIOS
VasEBoot_relocator16_idt = *VasEBoot_realidt;
#else
VasEBoot_relocator16_idt.base = 0;
VasEBoot_relocator16_idt.limit = 0;
#endif
VasEBoot_relocator16_keep_a20_enabled = state.a20;
VasEBoot_memmove (get_virtual_current_address (ch), &VasEBoot_relocator16_start,
RELOCATOR_SIZEOF (16));
err = VasEBoot_relocator_prepare_relocs (rel, get_physical_target_address (ch),
&relst, NULL);
if (err)
return err;
asm volatile ("cli");
((void (*) (void)) relst) ();
/* Not reached. */
return VAS_EBOOT_ERR_NONE;
}
VasEBoot_err_t
VasEBoot_relocator64_boot (struct VasEBoot_relocator *rel,
struct VasEBoot_relocator64_state state,
VasEBoot_addr_t min_addr, VasEBoot_addr_t max_addr)
{
VasEBoot_err_t err;
void *relst;
VasEBoot_relocator_chunk_t ch;
err = VasEBoot_relocator_alloc_chunk_align_safe (rel, &ch, min_addr, max_addr,
RELOCATOR_SIZEOF (64), 16,
VAS_EBOOT_RELOCATOR_PREFERENCE_NONE, 0);
if (err)
return err;
VasEBoot_relocator64_rax = state.rax;
VasEBoot_relocator64_rbx = state.rbx;
VasEBoot_relocator64_rcx = state.rcx;
VasEBoot_relocator64_rdx = state.rdx;
VasEBoot_relocator64_rip = state.rip;
VasEBoot_relocator64_rsp = state.rsp;
VasEBoot_relocator64_rsi = state.rsi;
VasEBoot_relocator64_cr3 = state.cr3;
VasEBoot_memmove (get_virtual_current_address (ch), &VasEBoot_relocator64_start,
RELOCATOR_SIZEOF (64));
err = VasEBoot_relocator_prepare_relocs (rel, get_physical_target_address (ch),
&relst, NULL);
if (err)
return err;
asm volatile ("cli");
((void (*) (void)) relst) ();
/* Not reached. */
return VAS_EBOOT_ERR_NONE;
}