Index: conf/i386-pc.rmk =================================================================== --- conf/i386-pc.rmk (revision 2008) +++ conf/i386-pc.rmk (working copy) @@ -146,7 +147,11 @@ \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ - grub_emu_init.c + grub_emu_init.c efiemu/main.c efiemu/loadcore64.c \ + efiemu/loadcore32.c efiemu/loadcore_common.c efiemu/mm.c \ + efiemu/modules/pnvram.c efiemu/i386/loadcore32.c \ + efiemu/i386/loadcore64.c efiemu/symbols.c efiemu/prepare32.c \ + efiemu/prepare64.c lib/crc.c \ grub_emu_LDFLAGS = $(LIBCURSES) @@ -172,3 +180,3 @@ vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod \ ata.mod vga.mod memdisk.mod pci.mod lspci.mod \ aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \ datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \ - usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod + usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \ + efiemu.mod efiemu_acpi.mod efiemu_pnvram.mod _linux_efi.mod linux_efi.mod +# For efiemu.mod. +efiemu_mod_SOURCES = efiemu/main.c efiemu/i386/loadcore32.c efiemu/i386/loadcore64.c efiemu/i386/pc/cfgtables.c efiemu/mm.c efiemu/loadcore_common.c efiemu/symbols.c efiemu/loadcore32.c efiemu/loadcore64.c efiemu/prepare32.c efiemu/prepare64.c lib/i386/pc/acpi.c +efiemu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall +efiemu_mod_LDFLAGS = $(COMMON_LDFLAGS) + +efiemu_acpi_mod_SOURCES = efiemu/modules/acpi.c +efiemu_acpi_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall +efiemu_acpi_mod_LDFLAGS = $(COMMON_LDFLAGS) + +efiemu_pnvram_mod_SOURCES = efiemu/modules/pnvram.c +efiemu_pnvram_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall +efiemu_pnvram_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c biosdisk_mod_CFLAGS = $(COMMON_CFLAGS) @@ -200,6 +228,16 @@ linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _linux.mod. +_linux_efi_mod_SOURCES = loader/i386/efi/linux.c +_linux_efi_mod_CFLAGS = $(COMMON_CFLAGS) +_linux_efi_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For linux.mod. +linux_efi_mod_SOURCES = loader/linux_normal_efiemu.c +linux_efi_mod_CFLAGS = $(COMMON_CFLAGS) +linux_efi_mod_LDFLAGS = $(COMMON_LDFLAGS) + # # Only arch dependant part of normal.mod will be here. Common part for # all architecures of normal.mod is at start and should be kept at sync @@ -380,5 +423,19 @@ hdparm_mod_CFLAGS = $(COMMON_CFLAGS) hdparm_mod_LDFLAGS = $(COMMON_LDFLAGS) +efiemu32.o: efiemu/runtime/efiemu.c + $(CC) -c -m32 -DELF32 -o $@ -Wall -Werror efiemu/runtime/efiemu.c -nostdlib -O2 -Iefiemu/runtime -Iinclude +efiemu64_c.o: efiemu/runtime/efiemu.c + $(CC) -c -m64 -DELF64 -o $@ -Wall -Werror efiemu/runtime/efiemu.c -nostdlib -mcmodel=large -O2 -Iefiemu/runtime -Iinclude + +efiemu64_s.o: efiemu/runtime/efiemu.S + $(CC) -c -m64 -DELF64 -o $@ -Wall -Werror efiemu/runtime/efiemu.S -nostdlib -mcmodel=large -O2 -Iefiemu/runtime -Iinclude + +efiemu64.o: efiemu64_c.o efiemu64_s.o + ld -o $@ -r efiemu64_c.o efiemu64_s.o -nostdlib + +CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_S.o +lib_DATA += efiemu32.o efiemu64.o + include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk Index: lib/i386/pc/acpi.c =================================================================== --- lib/i386/pc/acpi.c (revision 0) +++ lib/i386/pc/acpi.c (revision 0) @@ -0,0 +1,59 @@ +/* Find ACPI tables */ +/* + * 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 . + */ + +#include +#include +#include + +/* Simple checksum by summing all bytes. Used by ACPI and SMBIOS */ +grub_uint8_t +grub_byte_checksum (void *base, grub_size_t size) +{ + grub_uint8_t *ptr; + grub_uint8_t ret = 0; + for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size; + ptr++) + ret += *ptr; + return ret; +} + +struct grub_acpi_rsdp_v10 * +grub_machine_acpi_get_rsdp (void) +{ + int ebda_len; + grub_uint8_t *ptr; + + grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n"); + ebda_len = 1024 * (*((grub_uint8_t *)0x40e)); + for (ptr = (grub_uint8_t *) 0x410; ptr < (grub_uint8_t *) (0x410 + ebda_len); + ptr += 16) + if (!grub_memcmp (ptr, "RSD PTR ", 8) + && grub_efiemu_byte_checksum (ptr, + sizeof (struct grub_acpi_rsdp_v10)) == 0) + return (struct grub_acpi_rsdp_v10 *) ptr; + + grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n"); + for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000; + ptr += 16) + if (!grub_memcmp (ptr, "RSD PTR ", 8) + && grub_efiemu_byte_checksum (ptr, + sizeof (struct grub_acpi_rsdp_v10)) == 0) + return (struct grub_acpi_rsdp_v10 *) ptr; + return 0; +} Property changes on: lib/i386/pc/acpi.c ___________________________________________________________________ Added: svn:mergeinfo Index: loader/linux_normal_efiemu.c =================================================================== --- loader/linux_normal_efiemu.c (revision 0) +++ loader/linux_normal_efiemu.c (revision 0) @@ -0,0 +1,64 @@ +/* linux_normal.c - boot linux */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005,2006,2007 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 . + */ + +#include +#include +#include +#include + +void grub_rescue_cmd_linuxefi (int argc, char *argv[]); +void grub_rescue_cmd_initrdefi (int argc, char *argv[]); + + +static grub_err_t +grub_normal_linuxefi_command (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_linuxefi (argc, args); + return grub_errno; +} + + +static grub_err_t +grub_normal_initrd_command (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_initrdefi (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT(linux_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("linux_efiemu", grub_normal_linuxefi_command, + GRUB_COMMAND_FLAG_BOTH, + "linux_efiemu FILE [ARGS...]", + "Load a linux kernel.", 0); + + grub_register_command ("initrd_efiemu", grub_normal_initrd_command, + GRUB_COMMAND_FLAG_BOTH, + "initrd_efiemu FILE", + "Load an initrd.", 0); +} + +GRUB_MOD_FINI(linux_normal) +{ + grub_unregister_command ("linux"); + grub_unregister_command ("initrd"); +} Index: loader/i386/efi/linux.c =================================================================== --- loader/i386/efi/linux.c (revision 2008) +++ loader/i386/efi/linux.c (working copy) @@ -31,6 +31,7 @@ #include #include #include +#include #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -113,7 +114,7 @@ if (! mmap) return 0; - ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); + ret = GRUB_EFI (get_memory_map) (&mmap_size, mmap, 0, &desc_size, 0); grub_free (mmap); if (ret < 0) @@ -187,7 +188,7 @@ return 0; tmp_mmap_size = mmap_size; - if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) + if (GRUB_EFI (get_memory_map) (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) grub_fatal ("cannot get memory map"); mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size); @@ -292,7 +293,7 @@ #endif static grub_err_t -grub_linux_boot (void) +grub_linux_efi_boot (void) { struct linux_kernel_params *params; grub_efi_uintn_t mmap_size; @@ -313,8 +314,8 @@ (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base); mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) + if (GRUB_EFI (get_memory_map) (&mmap_size, mmap_buf, &map_key, + &desc_size, &desc_version) <= 0) grub_fatal ("cannot get memory map"); e820_num = 0; @@ -390,7 +391,7 @@ params->mmap_size = e820_num; - if (! grub_efi_exit_boot_services (map_key)) + if (! GRUB_EFI (exit_boot_services) (map_key)) grub_fatal ("cannot exit boot services"); /* Note that no boot services are available from here. */ @@ -504,6 +505,7 @@ return 1; } +#ifdef GRUB_MACHINE_EFI static int grub_linux_setup_video (struct linux_kernel_params *params) { @@ -555,9 +557,15 @@ return 0; } +#endif +#ifndef GRUB_MACHINE_EFI void +grub_rescue_cmd_linuxefi (int argc, char *argv[]) +#else +void grub_rescue_cmd_linux (int argc, char *argv[]) +#endif { grub_file_t file = 0; struct linux_kernel_header lh; @@ -660,7 +668,11 @@ params->video_cursor_x = grub_getxy () >> 8; params->video_cursor_y = grub_getxy () & 0xff; params->video_page = 0; /* ??? */ +#ifdef GRUB_MACHINE_EFI params->video_mode = grub_efi_system_table->con_out->mode->mode; +#else + params->video_mode = 0; +#endif params->video_width = (grub_getwh () >> 8); params->video_ega_bx = 0; params->video_height = (grub_getwh () & 0xff); @@ -670,15 +682,15 @@ if (grub_le_to_cpu16 (params->version) >= 0x0206) { params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE; - params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; + params->v0206.efi_system_table = PTR_TO_UINT32 (GRUB_EFI (system_table)); #ifdef __x86_64__ - params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32); + params->v0206.efi_system_table_hi = (grub_uint32_t) (PTR_TO_UINT64 (GRUB_EFI (system_table)) >> 32); #endif } else if (grub_le_to_cpu16 (params->version) >= 0x0204) { params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204; - params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; + params->v0204.efi_system_table = PTR_TO_UINT32 (GRUB_EFI (system_table)); } #if 0 @@ -800,11 +812,13 @@ video_type = GRUB_VIDEO_TYPE_EFI; } +#ifdef GRUB_EFI_MACHINE_EFI if (video_type) { if (! grub_linux_setup_video (params)) - params->have_vga = video_type; + params->have_vga = video_type; } +#endif /* Specify the boot file. */ dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET, @@ -828,7 +842,7 @@ if (grub_errno == GRUB_ERR_NONE) { - grub_loader_set (grub_linux_boot, grub_linux_unload, 1); + grub_loader_set (grub_linux_efi_boot, grub_linux_unload, 1); loaded = 1; } @@ -844,8 +858,13 @@ } } +#ifndef GRUB_MACHINE_EFI void +grub_rescue_cmd_initrdefi (int argc, char *argv[]) +#else +void grub_rescue_cmd_initrd (int argc, char *argv[]) +#endif { grub_file_t file = 0; grub_ssize_t size; @@ -893,7 +912,7 @@ /* Find the highest address to put the initrd. */ mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) + if (GRUB_EFI (get_memory_map) (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) grub_fatal ("cannot get memory map"); addr = 0; @@ -949,17 +968,31 @@ GRUB_MOD_INIT(linux) { +#ifndef GRUB_MACHINE_EFI + grub_rescue_register_command ("linuxefi", + grub_rescue_cmd_linuxefi, + "load linux"); + grub_rescue_register_command ("initrdefi", + grub_rescue_cmd_initrdefi, + "load initrd"); +#else grub_rescue_register_command ("linux", - grub_rescue_cmd_linux, + grub_rescue_cmd_linuxefi, "load linux"); grub_rescue_register_command ("initrd", - grub_rescue_cmd_initrd, + grub_rescue_cmd_initrdefi, "load initrd"); +#endif my_mod = mod; } GRUB_MOD_FINI(linux) { +#ifndef GRUB_MACHINE_EFI + grub_rescue_unregister_command ("linuxefi"); + grub_rescue_unregister_command ("initrdefi"); +#else grub_rescue_unregister_command ("linux"); grub_rescue_unregister_command ("initrd"); +#endif } Index: util/i386/pc/grub-install.in =================================================================== --- util/i386/pc/grub-install.in (revision 2008) +++ util/i386/pc/grub-install.in (working copy) @@ -211,7 +211,7 @@ fi # Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img; do +for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do if test -f $file && [ "`basename $file`" != menu.lst ]; then rm -f $file || exit 1 fi @@ -295,7 +295,7 @@ $grub_mkimage --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 # Now perform the installation. - $grub_setup ${setup_verbose} --directory=${grubdir} --device-map=${device_map} \ + $grub_setup ${setup_verbose} --directory=${grubdir} --prefix=${relative_grubdir} --device-map=${device_map} \ ${install_device} || exit 1 else $grub_mkimage -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 Index: include/grub/autoefi.h =================================================================== --- include/grub/autoefi.h (revision 0) +++ include/grub/autoefi.h (revision 0) @@ -0,0 +1,46 @@ +/* + * 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 . + */ +/* This file provides some abstractions so that the same code compiles with + both efi and efiemu + */ +#ifndef GRUB_AUTOEFI_HEADER +#define GRUB_AUTOEFI_HEADER 1 + +#include + +#ifdef GRUB_MACHINE_EFI +# include +# define GRUB_EFI(x) grub_efi_ ## x +# define SYSTEM_TABLE_SIZEOF(x) (sizeof(grub_efi_system_table->x)) +# define SYSTEM_TABLE_VAR(x) ((void *)&(grub_efi_system_table->x)) +# define SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x)) +# define SIZEOF_OF_UINTN sizeof (grub_efi_uintn_t) +# define SYSTEM_TABLE(x) (grub_efi_system_table->x) +#else +# include +# define GRUB_EFI(x) grub_efiemu_ ## x +# define SYSTEM_TABLE_SIZEOF GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF +# define SYSTEM_TABLE_VAR GRUB_EFIEMU_SYSTEM_TABLE_VAR +# define SYSTEM_TABLE_PTR GRUB_EFIEMU_SYSTEM_TABLE_PTR +# define SIZEOF_OF_UINTN GRUB_EFIEMU_SIZEOF_OF_UINTN +# define SYSTEM_TABLE GRUB_EFIEMU_SYSTEM_TABLE +# define grub_efi_allocate_pages(x,y) (x) +# define grub_efi_free_pages(x,y) GRUB_EFI_SUCCESS +#endif + +#endif Index: include/grub/i386/efiemu.h =================================================================== --- include/grub/i386/efiemu.h (revision 0) +++ include/grub/i386/efiemu.h (revision 0) @@ -0,0 +1,33 @@ +/* + * 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 . + */ + +#ifndef GRUB_ARCH_EFI_EMU_HEADER +#define GRUB_ARCH_EFI_EMU_HEADER 1 + +grub_err_t +grub_arch_efiemu_relocate_symbols32 (grub_efiemu_segment_t segs, + struct grub_efiemu_elf_sym *elfsyms, + void *ehdr); +grub_err_t +grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs, + struct grub_efiemu_elf_sym *elfsyms, + void *ehdr); + +int grub_arch_efiemu_check_header32 (void *ehdr); +int grub_arch_efiemu_check_header64 (void *ehdr); +#endif Index: include/grub/i386/pc/efiemu.h =================================================================== --- include/grub/i386/pc/efiemu.h (revision 0) +++ include/grub/i386/pc/efiemu.h (revision 0) @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +#ifndef GRUB_MACHINE_EFI_EMU_HEADER +#define GRUB_MACHINE_EFI_EMU_HEADER 1 + +grub_err_t grub_machine_efiemu_init_tables (void); + +#endif Index: include/grub/i386/pc/memory.h =================================================================== --- include/grub/i386/pc/memory.h (revision 2008) +++ include/grub/i386/pc/memory.h (working copy) @@ -92,6 +92,8 @@ grub_uint64_t len; #define GRUB_MACHINE_MEMORY_AVAILABLE 1 #define GRUB_MACHINE_MEMORY_RESERVED 2 +#define GRUB_MACHINE_MEMORY_ACPI 3 +#define GRUB_MACHINE_MEMORY_NVS 4 grub_uint32_t type; } __attribute__((packed)); Index: include/grub/efi/api.h =================================================================== --- include/grub/efi/api.h (revision 2008) +++ include/grub/efi/api.h (working copy) @@ -40,15 +40,15 @@ #define GRUB_EFI_TPL_NOTIFY 16 #define GRUB_EFI_TPL_HIGH_LEVEL 31 -#define GRUB_EFI_MEMORY_UC 0x0000000000000001 -#define GRUB_EFI_MEMORY_WC 0x0000000000000002 -#define GRUB_EFI_MEMORY_WT 0x0000000000000004 -#define GRUB_EFI_MEMORY_WB 0x0000000000000008 -#define GRUB_EFI_MEMORY_UCE 0x0000000000000010 -#define GRUB_EFI_MEMORY_WP 0x0000000000001000 -#define GRUB_EFI_MEMORY_RP 0x0000000000002000 -#define GRUB_EFI_MEMORY_XP 0x0000000000004000 -#define GRUB_EFI_MEMORY_RUNTIME 0x8000000000000000 +#define GRUB_EFI_MEMORY_UC 0x0000000000000001LL +#define GRUB_EFI_MEMORY_WC 0x0000000000000002LL +#define GRUB_EFI_MEMORY_WT 0x0000000000000004LL +#define GRUB_EFI_MEMORY_WB 0x0000000000000008LL +#define GRUB_EFI_MEMORY_UCE 0x0000000000000010LL +#define GRUB_EFI_MEMORY_WP 0x0000000000001000LL +#define GRUB_EFI_MEMORY_RP 0x0000000000002000LL +#define GRUB_EFI_MEMORY_XP 0x0000000000004000LL +#define GRUB_EFI_MEMORY_RUNTIME 0x8000000000000000LL #define GRUB_EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 #define GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 @@ -599,7 +599,7 @@ grub_efi_int16_t time_zone; grub_efi_uint8_t daylight; grub_efi_uint8_t pad2; -}; +} __attribute__ ((packed)); typedef struct grub_efi_time grub_efi_time_t; struct grub_efi_time_capabilities @@ -916,6 +916,20 @@ }; typedef struct grub_efi_configuration_table grub_efi_configuration_table_t; +#define GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE 0x5453595320494249LL +#define GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552LL + +#define GRUB_EFI_ACPI_20_TABLE_GUID \ + {0x8868e871,0xe4f1,0x11d3,{0xbc,0x22,0x0,0x80,0xc7,0x3c,0x88,0x81}} +#define GRUB_EFI_ACPI_TABLE_GUID \ + {0xeb9d2d30,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}} +#define GRUB_EFI_SAL_SYSTEM_TABLE_GUID \ + {0xeb9d2d32,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}} +#define GRUB_EFI_SMBIOS_TABLE_GUID \ + {0xeb9d2d31,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}} +#define GRUB_EFI_MPS_TABLE_GUID \ + {0xeb9d2d2f,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}} + struct grub_efi_simple_input_interface { grub_efi_status_t Index: include/grub/types.h =================================================================== --- include/grub/types.h (revision 2008) +++ include/grub/types.h (working copy) @@ -100,6 +100,16 @@ # define LONG_MAX 2147483647UL #endif +#if GRUB_CPU_SIZEOF_VOID_P == 4 +#define UINT_TO_PTR(x) ((void*)(grub_uint32_t)(x)) +#define PTR_TO_UINT64(x) ((grub_uint64_t)(grub_uint32_t)(x)) +#define PTR_TO_UINT32(x) ((grub_uint32_t)(x)) +#else +#define UINT_TO_PTR(x) ((void*)(grub_uint64_t)(x)) +#define PTR_TO_UINT64(x) ((grub_uint64_t)(x)) +#define PTR_TO_UINT32(x) ((grub_uint32_t)(grub_uint64_t)(x)) +#endif + /* The type for representing a file offset. */ typedef grub_uint64_t grub_off_t; Index: include/grub/acpi.h =================================================================== --- include/grub/acpi.h (revision 0) +++ include/grub/acpi.h (revision 0) @@ -0,0 +1,64 @@ +/* + * 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 . + */ + +#ifndef GRUB_ACPI_HEADER +#define GRUB_ACPI_HEADER 1 + +struct grub_acpi_rsdp_v10 +{ + grub_uint8_t signature[8]; + grub_uint8_t checksum; + grub_uint8_t oemid[6]; + grub_uint8_t revision; + grub_uint32_t rsdt_addr; +} __attribute__ ((packed)); +struct grub_acpi_rsdp_v20 +{ + struct grub_acpi_rsdp_v10 rsdpv1; + grub_uint32_t length; + grub_uint64_t xsdt_addr; + grub_uint8_t checksum; + grub_uint8_t reserved[3]; +} __attribute__ ((packed)); +struct grub_acpi_table_header +{ + grub_uint8_t signature[4]; + grub_uint32_t length; + grub_uint8_t revision; + grub_uint8_t checksum; + grub_uint8_t oemid[6]; + grub_uint8_t oemtable[8]; + grub_uint32_t oemrev; + grub_uint8_t creator_id[4]; + grub_uint32_t creator_rev; +} __attribute__ ((packed)); +struct grub_acpi_fadt +{ + struct grub_acpi_table_header hdr; + grub_uint32_t facs_addr; + grub_uint32_t dsdt_addr; + grub_uint8_t somefields1[88]; + grub_uint64_t facs_xaddr; + grub_uint64_t dsdt_xaddr; + grub_uint8_t somefields2[96]; +} __attribute__ ((packed)); + +struct grub_acpi_rsdp_v10 *grub_machine_acpi_get_rsdp (void); +grub_uint8_t grub_byte_checksum (void *base, grub_size_t size); + +#endif /* ! GRUB_ACPI_HEADER */ Property changes on: include/grub/acpi.h ___________________________________________________________________ Added: svn:mergeinfo Index: include/grub/efiemu/efiemu.h =================================================================== --- include/grub/efiemu/efiemu.h (revision 0) +++ include/grub/efiemu/efiemu.h (revision 0) @@ -0,0 +1,259 @@ +/* + * 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 . + */ + +#ifndef GRUB_EFI_EMU_HEADER +#define GRUB_EFI_EMU_HEADER 1 + +#include +#include + +#define GRUB_EFIEMU_PAGESIZE 4096 + +/* EFI api defined in 32-bit and 64-bit version*/ +struct grub_efi_system_table32 +{ + grub_efi_table_header_t hdr; + grub_efi_uint32_t firmware_vendor; + grub_efi_uint32_t firmware_revision; + grub_efi_uint32_t console_in_handler; + grub_efi_uint32_t con_in; + grub_efi_uint32_t console_out_handler; + grub_efi_uint32_t con_out; + grub_efi_uint32_t standard_error_handle; + grub_efi_uint32_t std_err; + grub_efi_uint32_t runtime_services; + grub_efi_uint32_t boot_services; + grub_efi_uint32_t num_table_entries; + grub_efi_uint32_t configuration_table; +} __attribute__ ((packed)); +typedef struct grub_efi_system_table32 grub_efi_system_table32_t; + +struct grub_efi_system_table64 +{ + grub_efi_table_header_t hdr; + grub_efi_uint64_t firmware_vendor; + grub_efi_uint32_t firmware_revision; + grub_efi_uint32_t pad; + grub_efi_uint64_t console_in_handler; + grub_efi_uint64_t con_in; + grub_efi_uint64_t console_out_handler; + grub_efi_uint64_t con_out; + grub_efi_uint64_t standard_error_handle; + grub_efi_uint64_t std_err; + grub_efi_uint64_t runtime_services; + grub_efi_uint64_t boot_services; + grub_efi_uint64_t num_table_entries; + grub_efi_uint64_t configuration_table; +} __attribute__ ((packed)); +typedef struct grub_efi_system_table64 grub_efi_system_table64_t; + +struct grub_efiemu_runtime_services32 +{ + grub_efi_table_header_t hdr; + grub_efi_uint32_t get_time; + grub_efi_uint32_t set_time; + grub_efi_uint32_t get_wakeup_time; + grub_efi_uint32_t set_wakeup_time; + grub_efi_uint32_t set_virtual_address_map; + grub_efi_uint32_t convert_pointer; + grub_efi_uint32_t get_variable; + grub_efi_uint32_t get_next_variable_name; + grub_efi_uint32_t set_variable; + grub_efi_uint32_t get_next_high_monotonic_count; + grub_efi_uint32_t reset_system; +} __attribute__ ((packed)); +typedef struct grub_efiemu_runtime_services32 grub_efiemu_runtime_services32_t; + +struct grub_efiemu_runtime_services64 +{ + grub_efi_table_header_t hdr; + grub_efi_uint64_t get_time; + grub_efi_uint64_t set_time; + grub_efi_uint64_t get_wakeup_time; + grub_efi_uint64_t set_wakeup_time; + grub_efi_uint64_t set_virtual_address_map; + grub_efi_uint64_t convert_pointer; + grub_efi_uint64_t get_variable; + grub_efi_uint64_t get_next_variable_name; + grub_efi_uint64_t set_variable; + grub_efi_uint64_t get_next_high_monotonic_count; + grub_efi_uint64_t reset_system; +} __attribute__ ((packed)); +typedef struct grub_efiemu_runtime_services64 grub_efiemu_runtime_services64_t; + +extern grub_efi_system_table32_t *grub_efiemu_system_table32; +extern grub_efi_system_table64_t *grub_efiemu_system_table64; + +/* Convenience macroses to access currently loaded efiemu */ +#define grub_efiemu_system_table ((grub_efiemu_sizeof_uintn_t () == 8) \ + ? (void *) grub_efiemu_system_table64 \ + : (void *) grub_efiemu_system_table32) +#define GRUB_EFIEMU_SIZEOF_OF_UINTN (grub_efiemu_sizeof_uintn_t ()) +#define GRUB_EFIEMU_SYSTEM_TABLE(x) ((grub_efiemu_sizeof_uintn_t () == 8) \ + ? grub_efiemu_system_table64->x \ + : grub_efiemu_system_table32->x) +#define GRUB_EFIEMU_SYSTEM_TABLE_SET(x,y) ((grub_efiemu_sizeof_uintn_t () == 8)\ + ? (grub_efiemu_system_table64->x \ + = (y)) \ + : (grub_efiemu_system_table32->x \ + = (y))) +#define GRUB_EFIEMU_SYSTEM_TABLE_PTR(x) ((grub_efiemu_sizeof_uintn_t () == 8)\ + ? UINT_TO_PTR \ + (grub_efiemu_system_table64->x) \ + : UINT_TO_PTR \ + (grub_efiemu_system_table32->x)) +#define GRUB_EFIEMU_SYSTEM_TABLE_VAR(x) ((grub_efiemu_sizeof_uintn_t () == 8) \ + ? (void *) \ + &(grub_efiemu_system_table64->x) \ + : (void *) \ + &(grub_efiemu_system_table32->x)) +#define GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF(x) \ + ((grub_efiemu_sizeof_uintn_t () == 8) \ + ? sizeof(grub_efiemu_system_table64->x)\ + : sizeof(grub_efiemu_system_table32->x)) +#define GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF_TOTAL ((grub_efiemu_sizeof_uintn_t () == 8) ? sizeof(*grub_efiemu_system_table64):sizeof(*grub_efiemu_system_table32)) + +/* ELF management definitions and functions */ + +struct grub_efiemu_segment +{ + struct grub_efiemu_segment *next; + grub_size_t size; + unsigned section; + int handle; + int ptv_rel_needed; + grub_off_t off; + void *srcptr; +}; +typedef struct grub_efiemu_segment *grub_efiemu_segment_t; + +struct grub_efiemu_elf_sym +{ + int handle; + grub_off_t off; + unsigned section; +}; + +int grub_efiemu_check_header32 (void *ehdr, grub_size_t size); +int grub_efiemu_check_header64 (void *ehdr, grub_size_t size); +grub_err_t grub_efiemu_loadcore_init32 (void *core, grub_size_t core_size, + grub_efiemu_segment_t *segments); +grub_err_t grub_efiemu_loadcore_init64 (void *core, grub_size_t core_size, + grub_efiemu_segment_t *segments); +grub_err_t grub_efiemu_loadcore_load32 (void *core, + grub_size_t core_size, + grub_efiemu_segment_t segments); +grub_err_t grub_efiemu_loadcore_load64 (void *core, + grub_size_t core_size, + grub_efiemu_segment_t segments); +grub_err_t grub_efiemu_loadcore_unload32 (void); +grub_err_t grub_efiemu_loadcore_unload64 (void); +grub_err_t grub_efiemu_loadcore_unload(void); +grub_err_t grub_efiemu_loadcore_init (grub_file_t file); +grub_err_t grub_efiemu_loadcore_load (void); + +/* Configuration tables manipulation. Definitions and functions */ +struct grub_efiemu_configuration_table +{ + struct grub_efiemu_configuration_table *next; + grub_efi_guid_t guid; + void * (*get_table) (void *data); + void (*unload) (void *data); + void *data; +}; +struct grub_efiemu_configuration_table32 +{ + grub_efi_guid_t vendor_guid; + grub_efi_uint32_t vendor_table; +} __attribute__ ((packed)); +typedef struct grub_efiemu_configuration_table32 grub_efiemu_configuration_table32_t; +struct grub_efiemu_configuration_table64 +{ + grub_efi_guid_t vendor_guid; + grub_efi_uint64_t vendor_table; +} __attribute__ ((packed)); +typedef struct grub_efiemu_configuration_table32 grub_efiemu_configuration_table64_t; +grub_err_t grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid); +grub_err_t +grub_efiemu_register_configuration_table (grub_efi_guid_t guid, + void * (*get_table) (void *data), + void (*unload) (void *data), + void *data); + +/* Memory management functions */ +int grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, + grub_efi_memory_type_t type); +void *grub_efiemu_mm_obtain_request (int handle); +int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); +grub_err_t grub_efiemu_mm_unload (void); +grub_err_t grub_efiemu_mm_do_alloc (void); +grub_err_t grub_efiemu_mm_init (void); +void *grub_efiemu_mm_obtain_request (int handle); +void grub_efiemu_mm_return_request (int handle); +grub_efi_memory_type_t grub_efiemu_mm_get_type (int handle); + +/* Drop-in replacements for grub_efi_* */ +int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); +int grub_efiemu_sizeof_uintn_t (void); +int grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key); + +/* efiemu main control definitions and functions*/ +typedef enum {GRUB_EFIEMU_NOTLOADED, + GRUB_EFIEMU32, GRUB_EFIEMU64} grub_efiemu_mode_t; +struct grub_efiemu_prepare_hook +{ + struct grub_efiemu_prepare_hook *next; + grub_err_t (*hook) (void *data); + void (*unload) (void *data); + void *data; +}; +grub_err_t grub_efiemu_prepare32 (struct grub_efiemu_prepare_hook + *prepare_hooks, + struct grub_efiemu_configuration_table + *config_tables); +grub_err_t grub_efiemu_prepare64 (struct grub_efiemu_prepare_hook + *prepare_hooks, + struct grub_efiemu_configuration_table + *config_tables); +grub_err_t grub_efiemu_unload (void); +grub_err_t grub_efiemu_prepare (void); +grub_err_t +grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data), + void (*unload) (void *data), + void *data); + +/* symbols and pointers */ +grub_err_t grub_efiemu_alloc_syms (void); +grub_err_t grub_efiemu_request_symbols (int num); +grub_err_t grub_efiemu_resolve_symbol (const char *name, + int *handle, grub_off_t *off); +grub_err_t grub_efiemu_register_symbol (const char *name, + int handle, grub_off_t off); +void grub_efiemu_free_syms (void); +grub_err_t grub_efiemu_write_value (void * addr, grub_uint32_t value, + int plus_handle, + int minus_handle, int ptv_needed, int size); +#endif /* ! GRUB_EFI_EMU_HEADER */ Property changes on: include/grub/efiemu/efiemu.h ___________________________________________________________________ Added: svn:mergeinfo Index: include/grub/efiemu/runtime.h =================================================================== --- include/grub/efiemu/runtime.h (revision 0) +++ include/grub/efiemu/runtime.h (revision 0) @@ -0,0 +1,37 @@ +/* + * 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 . + */ + +#ifndef GRUB_EFI_EMU_RUNTIME_HEADER +#define GRUB_EFI_EMU_RUNTIME_HEADER 1 + +struct grub_efiemu_ptv_rel +{ + grub_uint64_t addr; + grub_efi_memory_type_t plustype; + grub_efi_memory_type_t minustype; + grub_uint32_t size; +} __attribute__ ((packed)); + +struct efi_variable +{ + grub_efi_guid_t guid; + grub_uint32_t namelen; + grub_uint32_t size; + grub_efi_uint32_t attributes; +} __attribute__ ((packed)); +#endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */ Index: efiemu/prepare.c =================================================================== --- efiemu/prepare.c (revision 0) +++ efiemu/prepare.c (revision 0) @@ -0,0 +1,127 @@ +/* Prepare efiemu. E.g. allocate memory, load the runtime + to appropriate place, etc */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include + +grub_err_t +SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, + struct grub_efiemu_configuration_table + *config_tables) +{ + grub_err_t err; + int conftable_handle; + struct grub_efiemu_configuration_table *cur; + struct grub_efiemu_prepare_hook *curhook; + + int cntconftables = 0; + TYPE (grub_efiemu_configuration_table) *conftables = 0; + TYPE (grub_efiemu_runtime_services) *runtime_services; + int i; + int handle; + grub_off_t off; + + grub_dprintf ("efiemu", "Preparing EfiEmu\n"); + + /* Request space for the list of configuration tables */ + for (cur = config_tables; cur; cur = cur->next) + cntconftables++; + conftable_handle + = grub_efiemu_request_memalign (GRUB_EFIEMU_PAGESIZE, + cntconftables * sizeof (*conftables), + GRUB_EFI_RUNTIME_SERVICES_DATA); + + /* Switch from phase 1 (counting) to phase 2 (real job) */ + grub_efiemu_alloc_syms (); + grub_efiemu_mm_do_alloc (); + + grub_efiemu_system_table32 = 0; + grub_efiemu_system_table64 = 0; + + /* Execute hooks */ + for (curhook = prepare_hooks; curhook; curhook = curhook->next) + curhook->hook (curhook->data); + + /* Move runtime to its due place */ + if ((err = grub_efiemu_loadcore_load ())) + { + grub_efiemu_unload (); + return err; + } + + if ((err = grub_efiemu_resolve_symbol ("efiemu_system_table", + &handle, &off))) + { + grub_efiemu_unload (); + return err; + } + + SUFFIX (grub_efiemu_system_table) + = (TYPE (grub_efi_system_table) *) + ((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off); + + /* compute CRC32 of runtime_services */ + if ((err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", + &handle, &off))) + return err; + runtime_services = (TYPE (grub_efiemu_runtime_services) *) + ((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off); + runtime_services->hdr.crc32 = 0; + runtime_services->hdr.crc32 = grub_getcrc32 + (0, runtime_services, runtime_services->hdr.header_size); + + /* Put pointer to the list of configuration tables in system table */ + grub_efiemu_write_value + (&(SUFFIX (grub_efiemu_system_table)->configuration_table), 0, + conftable_handle, 0, 1, + sizeof (SUFFIX (grub_efiemu_system_table)->configuration_table)); + SUFFIX(grub_efiemu_system_table)->num_table_entries = cntconftables; + + /* Fill the list of configuration tables */ + conftables = (TYPE (grub_efiemu_configuration_table) *) + grub_efiemu_mm_obtain_request (conftable_handle); + i = 0; + for (cur = config_tables; cur; cur = cur->next, i++) + { + grub_memcpy (&(conftables[i].vendor_guid), &(cur->guid), + sizeof (cur->guid)); + if (cur->get_table) + conftables[i].vendor_table + = PTR_TO_UINT64 (cur->get_table (cur->data)); + else + conftables[i].vendor_table = PTR_TO_UINT64 (cur->data); + } + + /* compute CRC32 of system table */ + SUFFIX (grub_efiemu_system_table)->hdr.crc32 = 0; + SUFFIX (grub_efiemu_system_table)->hdr.crc32 + = grub_getcrc32 (0, SUFFIX (grub_efiemu_system_table), + SUFFIX (grub_efiemu_system_table)->hdr.header_size); + + grub_dprintf ("efiemu","system_table = %p, runtime_services = %p," + " conftables = %p (%d entries)\n", + SUFFIX (grub_efiemu_system_table), runtime_services, + conftables, cntconftables); + + return GRUB_ERR_NONE; +} Index: efiemu/loadcore_common.c =================================================================== --- efiemu/loadcore_common.c (revision 0) +++ efiemu/loadcore_common.c (revision 0) @@ -0,0 +1,189 @@ +/* Load runtime image of EFIemu. Functions common to 32/64-bit mode */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Are we in 32 or 64-bit mode?*/ +static grub_efiemu_mode_t grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED; +/* Runtime ELF file */ +static grub_ssize_t efiemu_core_size; +static void *efiemu_core = 0; +/* Linked list of segments */ +static grub_efiemu_segment_t efiemu_segments = 0; + +/* equivalent to sizeof (grub_efi_uintn_t) but taking the mode into account*/ +int +grub_efiemu_sizeof_uintn_t (void) +{ + if (grub_efiemu_mode == GRUB_EFIEMU32) + return 4; + if (grub_efiemu_mode == GRUB_EFIEMU64) + return 8; + return 0; +} + +/* Check the header and set mode */ +static grub_err_t +grub_efiemu_check_header (void *ehdr, grub_size_t size, + grub_efiemu_mode_t *mode) +{ + /* Check the magic numbers. */ + if ((*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU32) + && grub_efiemu_check_header32 (ehdr,size)) + { + *mode = GRUB_EFIEMU32; + return GRUB_ERR_NONE; + } + if ((*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU64) + && grub_efiemu_check_header64 (ehdr,size)) + { + *mode = GRUB_EFIEMU64; + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF magic"); +} + +/* Unload segments */ +static int +grub_efiemu_unload_segs (grub_efiemu_segment_t seg) +{ + grub_efiemu_segment_t segn; + for (; seg; seg = segn) + { + segn = seg->next; + grub_efiemu_mm_return_request (seg->handle); + grub_free (seg); + } + return 1; +} + + +grub_err_t +grub_efiemu_loadcore_unload(void) +{ + switch (grub_efiemu_mode) + { + case GRUB_EFIEMU32: + grub_efiemu_loadcore_unload32 (); + break; + + case GRUB_EFIEMU64: + grub_efiemu_loadcore_unload64 (); + break; + + default: + break; + } + + grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED; + + grub_free (efiemu_core); + efiemu_core = 0; + + grub_efiemu_unload_segs (efiemu_segments); + efiemu_segments = 0; + + grub_efiemu_free_syms (); + + return GRUB_ERR_NONE; +} + +/* Load runtime file and do some initial preparations */ +grub_err_t +grub_efiemu_loadcore_init (grub_file_t file) +{ + grub_err_t err; + + efiemu_core_size = grub_file_size (file); + efiemu_core = 0; + efiemu_core = grub_malloc (efiemu_core_size); + if (! efiemu_core) + return grub_errno; + + if (grub_file_read (file, efiemu_core, efiemu_core_size) + != (int) efiemu_core_size) + { + grub_free (efiemu_core); + efiemu_core = 0; + return grub_errno; + } + + if (grub_efiemu_check_header (efiemu_core, efiemu_core_size, + &grub_efiemu_mode)) + { + grub_free (efiemu_core); + efiemu_core = 0; + return GRUB_ERR_BAD_MODULE; + } + + switch (grub_efiemu_mode) + { + case GRUB_EFIEMU32: + if ((err = grub_efiemu_loadcore_init32 (efiemu_core, efiemu_core_size, + &efiemu_segments))) + { + grub_free (efiemu_core); + efiemu_core = 0; + grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED; + return err; + } + break; + + case GRUB_EFIEMU64: + if ((err = grub_efiemu_loadcore_init64 (efiemu_core, efiemu_core_size, + &efiemu_segments))) + { + grub_free (efiemu_core); + efiemu_core = 0; + grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED; + return err; + } + break; + + default: + return grub_error (GRUB_ERR_BAD_OS, "unknown EFI runtime"); + } + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efiemu_loadcore_load (void) +{ + grub_err_t err; + switch (grub_efiemu_mode) + { + case GRUB_EFIEMU32: + if ((err = grub_efiemu_loadcore_load32 (efiemu_core, efiemu_core_size, + efiemu_segments))) + grub_efiemu_loadcore_unload (); + return err; + case GRUB_EFIEMU64: + if ((err = grub_efiemu_loadcore_load64 (efiemu_core, efiemu_core_size, + efiemu_segments))) + grub_efiemu_loadcore_unload (); + return err; + default: + return grub_error (GRUB_ERR_BAD_OS, "unknown EFI runtime"); + } +} Index: efiemu/loadcore64.c =================================================================== --- efiemu/loadcore64.c (revision 0) +++ efiemu/loadcore64.c (revision 0) @@ -0,0 +1,27 @@ +/* This file contains definitions so that loadcore.c compiles for 64-bit */ +/* + * 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 . + */ + +#define SUFFIX(x) x ## 64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define Elf_Word Elf64_Word +#define ELF_ST_TYPE ELF64_ST_TYPE +#define ELF_ST_BIND ELF64_ST_BIND +#include "loadcore.c" Index: efiemu/runtime/efiemu.sh =================================================================== --- efiemu/runtime/efiemu.sh (revision 0) +++ efiemu/runtime/efiemu.sh (revision 0) @@ -0,0 +1,6 @@ +gcc -c -m32 -DELF32 -o efiemu32.o ./efiemu.c -Wall -Werror -nostdlib -O2 -I. -I../../include +gcc -c -m64 -DELF64 -o efiemu64_c.o ./efiemu.c -Wall -Werror -mcmodel=large -O2 -I. -I../../include +gcc -c -m64 -DELF64 -o efiemu64_s.o ./efiemu.S -Wall -Werror -mcmodel=large -O2 -I. -I../../include +ld -o efiemu64.o -r efiemu64_s.o efiemu64_c.o -nostdlib + + Index: efiemu/runtime/efiemu.S =================================================================== --- efiemu/runtime/efiemu.S (revision 0) +++ efiemu/runtime/efiemu.S (revision 0) @@ -0,0 +1,160 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,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 . + */ + +#include + +/* + * x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use + * different call conversion, so we need to do some conversion. + * + * gcc: + * %rdi, %rsi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ... + * + * efi: + * %rcx, %rdx, %r8, %r9, 32(%rsp), 40(%rsp), 48(%rsp), ... + * + */ + + .file "efiemu.S" + .text + +FUNCTION (efiemu_get_time) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + call efiemu_get_time_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_set_time) + push %rdi + push %rsi + mov %rcx, %rdi + call efiemu_set_time_real + pop %rsi + pop %rdi + ret + + +FUNCTION (efiemu_get_wakeup_time) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + call efiemu_get_wakeup_time_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_set_wakeup_time) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + call efiemu_set_wakeup_time_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_get_variable) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + mov %r9, %rcx + mov 56(%rsp), %r8 + call efiemu_get_variable_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_get_next_variable_name) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + call efiemu_get_next_variable_name_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_set_variable) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + mov %r9, %rcx + mov 56(%rsp), %r8 + call efiemu_set_variable_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_get_next_high_monotonic_count) + push %rdi + push %rsi + mov %rcx, %rdi + call efiemu_get_next_high_monotonic_count_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_reset_system) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + mov %r9, %rcx + call efiemu_reset_system_real + pop %rsi + pop %rdi + ret + + /* The following functions are always called in physical mode */ + .section ".text-physical", "ax" + +FUNCTION (efiemu_set_virtual_address_map) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + mov %r8, %rdx + mov %r9, %rcx + call efiemu_set_virtual_address_map_real + pop %rsi + pop %rdi + ret + +FUNCTION (efiemu_convert_pointer) + push %rdi + push %rsi + mov %rcx, %rdi + mov %rdx, %rsi + call efiemu_convert_pointer_real + pop %rsi + pop %rdi + ret + + Index: efiemu/runtime/efiemu.c =================================================================== --- efiemu/runtime/efiemu.c (revision 0) +++ efiemu/runtime/efiemu.c (revision 0) @@ -0,0 +1,623 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,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 . + */ + +/* This is an emulation of EFI runtime services. + This allows a more uniform boot on i386 machines. + As it emulates only runtime serviceit isn't able + to chainload EFI bootloader on non-EFI system (TODO) */ + +#include +#include +#include +#include + +grub_efi_status_t +efiemu_get_time (grub_efi_time_t *time, + grub_efi_time_capabilities_t *capabilities); +grub_efi_status_t +efiemu_set_time (grub_efi_time_t *time); + +grub_efi_status_t +efiemu_get_wakeup_time (grub_efi_boolean_t *enabled, + grub_efi_boolean_t *pending, + grub_efi_time_t *time); +grub_efi_status_t +efiemu_set_wakeup_time (grub_efi_boolean_t enabled, + grub_efi_time_t *time); + + +grub_efi_status_t +efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map) + __attribute__ ((section(".text-physical"))); + +grub_efi_status_t +efiemu_convert_pointer (grub_efi_uintn_t debug_disposition, + void **address) + __attribute__ ((section(".text-physical"))); + +grub_efi_status_t +efiemu_get_variable (grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t *attributes, + grub_efi_uintn_t *data_size, + void *data); + +grub_efi_status_t +efiemu_get_next_variable_name (grub_efi_uintn_t *variable_name_size, + grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid); + +grub_efi_status_t +efiemu_set_variable (grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t attributes, + grub_efi_uintn_t data_size, + void *data); +grub_efi_status_t +efiemu_get_next_high_monotonic_count (grub_efi_uint32_t *high_count); +void +efiemu_reset_system (grub_efi_reset_type_t reset_type, + grub_efi_status_t reset_status, + grub_efi_uintn_t data_size, + grub_efi_char16_t *reset_data); + +grub_efi_status_t +EFI_FUNC (efiemu_set_virtual_address_map) (grub_efi_uintn_t, + grub_efi_uintn_t, + grub_efi_uint32_t, + grub_efi_memory_descriptor_t *) + __attribute__ ((section(".text-physical"))); +grub_efi_status_t +EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition, + void **address) + __attribute__ ((section(".text-physical"))); +static grub_uint32_t +efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size) + __attribute__ ((section(".text-physical"))); +static void +init_crc32_table (void) + __attribute__ ((section(".text-physical"))); + +/* + The log. It's used when examining memory dump +*/ +static grub_uint8_t loge[1000] = "EFIEMULOG"; +static int logn = 9; +#define LOG(x) { if (logn<900) loge[logn++]=x; } + +static int ptv_relocated = 0; + +/* Interface with grub */ +struct grub_efi_runtime_services efiemu_runtime_services; +struct grub_efi_system_table efiemu_system_table; +extern struct grub_efiemu_ptv_rel efiemu_ptv_relloc[]; +extern grub_uint8_t efiemu_variables[]; +extern grub_uint32_t efiemu_varsize; +extern grub_uint32_t efiemu_high_monotonic_count; +extern grub_int16_t efiemu_time_zone; +extern grub_uint8_t efiemu_time_daylight; +extern grub_uint32_t efiemu_time_accuracy; + +/* Some standard functions because we need to be stadalone */ +static void +efiemu_memcpy (void *to, void *from, int count) +{ + int i; + for (i = 0; i < count; i++) + ((grub_uint8_t *) to)[i] = ((grub_uint8_t *) from)[i]; +} + +static int +efiemu_str16equal (grub_uint16_t *a, grub_uint16_t *b) +{ + grub_uint16_t *ptr1, *ptr2; + for (ptr1=a,ptr2=b; *ptr1 && *ptr2 == *ptr1; ptr1++, ptr2++); + return *ptr2 == *ptr1; +} + +static grub_size_t +efiemu_str16len (grub_uint16_t *a) +{ + grub_uint16_t *ptr1; + for (ptr1 = a; *ptr1; ptr1++); + return ptr1 - a; +} + +static int +efiemu_memequal (void *a, void *b, grub_size_t n) +{ + grub_uint8_t *ptr1, *ptr2; + for (ptr1 = (grub_uint8_t *) a, ptr2 = (grub_uint8_t *)b; + ptr1 < (grub_uint8_t *)a + n && *ptr2 == *ptr1; ptr1++, ptr2++); + return ptr1 == a + n; +} + +static void +efiemu_memset (grub_uint8_t *a, grub_uint8_t b, grub_size_t n) +{ + grub_uint8_t *ptr1; + for (ptr1=a; ptr1 < a + n; ptr1++) + *ptr1 = b; +} + +static inline void +write_cmos (grub_uint8_t addr, grub_uint8_t val) +{ + __asm__ __volatile__ ("outb %%al,$0x70\n" + "mov %%bl, %%al\n" + "outb %%al,$0x71": :"a" (addr), "b" (val)); +} + +static inline grub_uint8_t +read_cmos (grub_uint8_t addr) +{ + grub_uint8_t ret; + __asm__ __volatile__ ("outb %%al, $0x70\n" + "inb $0x71, %%al": "=a"(ret) :"a" (addr)); + return ret; +} + +/* Needed by some gcc versions */ +int __stack_chk_fail () +{ + return 0; +} + +/* The function that implement runtime services as specified in + EFI specification */ +static inline grub_uint8_t +bcd_to_hex (grub_uint8_t in) +{ + return 10 * ((in & 0xf0) >> 4) + (in & 0x0f); +} + +grub_efi_status_t +EFI_FUNC (efiemu_get_time) (grub_efi_time_t *time, + grub_efi_time_capabilities_t *capabilities) +{ + LOG ('a'); + grub_uint8_t state; + state = read_cmos (0xb); + if (!(state & (1 << 2))) + { + time->year = 2000 + bcd_to_hex (read_cmos (0x9)); + time->month = bcd_to_hex (read_cmos (0x8)); + time->day = bcd_to_hex (read_cmos (0x7)); + time->hour = bcd_to_hex (read_cmos (0x4)); + if (time->hour >= 81) + time->hour -= 80 - 12; + if (time->hour == 24) + time->hour = 0; + time->minute = bcd_to_hex (read_cmos (0x2)); + time->second = bcd_to_hex (read_cmos (0x0)); + } + else + { + time->year = 2000 + read_cmos (0x9); + time->month = read_cmos (0x8); + time->day = read_cmos (0x7); + time->hour = read_cmos (0x4); + if (time->hour >= 0x81) + time->hour -= 0x80 - 12; + if (time->hour == 24) + time->hour = 0; + time->minute = read_cmos (0x2); + time->second = read_cmos (0x0); + } + time->nanosecond = 0; + time->pad1 = 0; + time->pad2 = 0; + time->time_zone = efiemu_time_zone; + time->daylight = efiemu_time_daylight; + capabilities->resolution = 1; + capabilities->accuracy = efiemu_time_accuracy; + capabilities->sets_to_zero = 0; + return GRUB_EFI_SUCCESS; +} + +grub_efi_status_t +EFI_FUNC (efiemu_set_time) (grub_efi_time_t *time) +{ + LOG ('b'); + grub_uint8_t state; + state = read_cmos (0xb); + write_cmos (0xb, state | 0x6); + write_cmos (0x9, time->year - 2000); + write_cmos (0x8, time->month); + write_cmos (0x7, time->day); + write_cmos (0x4, time->hour); + write_cmos (0x2, time->minute); + write_cmos (0x0, time->second); + efiemu_time_zone = time->time_zone; + efiemu_time_daylight = time->daylight; + return GRUB_EFI_SUCCESS; +} + +/* Folowing 2 functions are vendor specific. So announce it as unsupported */ +grub_efi_status_t +EFI_FUNC (efiemu_get_wakeup_time) (grub_efi_boolean_t *enabled, + grub_efi_boolean_t *pending, + grub_efi_time_t *time) +{ + LOG ('c'); + return GRUB_EFI_UNSUPPORTED; +} + +grub_efi_status_t +EFI_FUNC (efiemu_set_wakeup_time) (grub_efi_boolean_t enabled, + grub_efi_time_t *time) +{ + LOG ('d'); + return GRUB_EFI_UNSUPPORTED; +} + +static grub_uint32_t crc32_table [256]; + +static void +init_crc32_table (void) +{ + auto grub_uint32_t reflect (grub_uint32_t ref, int len); + grub_uint32_t reflect (grub_uint32_t ref, int len) + { + grub_uint32_t result = 0; + int i; + + for (i = 1; i <= len; i++) + { + if (ref & 1) + result |= 1 << (len - i); + ref >>= 1; + } + + return result; + } + + grub_uint32_t polynomial = 0x04c11db7; + int i, j; + + for(i = 0; i < 256; i++) + { + crc32_table[i] = reflect(i, 8) << 24; + for (j = 0; j < 8; j++) + crc32_table[i] = (crc32_table[i] << 1) ^ + (crc32_table[i] & (1 << 31) ? polynomial : 0); + crc32_table[i] = reflect(crc32_table[i], 32); + } +} + +static grub_uint32_t +efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size) +{ + int i; + grub_uint8_t *data = buf; + + if (! crc32_table[1]) + init_crc32_table (); + + crc^= 0xffffffff; + + for (i = 0; i < size; i++) + { + crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data]; + data++; + } + + return crc ^ 0xffffffff; +} + + +grub_efi_status_t EFI_FUNC +(efiemu_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map) +{ + struct grub_efiemu_ptv_rel *cur_relloc; + + LOG ('e'); + + /* Ensure that we are called only once */ + if (ptv_relocated) + return GRUB_EFI_UNSUPPORTED; + ptv_relocated = 1; + + /* Correct addresses using information supplied by grub */ + for (cur_relloc = efiemu_ptv_relloc; cur_relloc->size;cur_relloc++) + { + grub_int64_t corr = 0; + grub_efi_memory_descriptor_t *descptr; + + /* Compute correction */ + for (descptr = virtual_map; + ((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 *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 4: + *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 2: + *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 1: + *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + } + } + + /* Recompute crc32 of system table and runtime services */ + efiemu_system_table.hdr.crc32 = 0; + efiemu_system_table.hdr.crc32 = efiemu_getcrc32 + (0, &efiemu_system_table, sizeof (efiemu_system_table)); + + efiemu_runtime_services.hdr.crc32 = 0; + efiemu_runtime_services.hdr.crc32 = efiemu_getcrc32 + (0, &efiemu_runtime_services, sizeof (efiemu_runtime_services)); + + return GRUB_EFI_SUCCESS; +} + +/* since efiemu_set_virtual_address_map corrects all the pointers + we don't need efiemu_convert_pointer */ +grub_efi_status_t +EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition, + void **address) +{ + LOG ('f'); + return GRUB_EFI_UNSUPPORTED; +} + +/* Next comes variable services. Because we have no vendor-independent + way to store these variables we have no non-volatility */ + +/* Find variable by name and GUID. */ +static struct efi_variable * +find_variable (grub_efi_guid_t *vendor_guid, + grub_efi_char16_t *variable_name) +{ + grub_uint8_t *ptr; + struct efi_variable *efivar; + + for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; ) + { + efivar = (struct efi_variable *) ptr; + if (!efivar->namelen) + return 0; + if (efiemu_str16equal((grub_efi_char16_t *)(efivar + 1), variable_name) + && efiemu_memequal (&(efivar->guid), vendor_guid, + sizeof (efivar->guid))) + return efivar; + ptr += efivar->namelen + efivar->size + sizeof (*efivar); + } + return 0; +} + +grub_efi_status_t +EFI_FUNC (efiemu_get_variable) (grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t *attributes, + grub_efi_uintn_t *data_size, + void *data) +{ + struct efi_variable *efivar; + LOG ('g'); + efivar = find_variable (vendor_guid, variable_name); + if (!efivar) + return GRUB_EFI_NOT_FOUND; + if (*data_size < efivar->size) + { + *data_size = efivar->size; + return GRUB_EFI_BUFFER_TOO_SMALL; + } + *data_size = efivar->size; + efiemu_memcpy (data, (grub_uint8_t *)(efivar + 1) + efivar->namelen, + efivar->size); + *attributes = efivar->attributes; + + return GRUB_EFI_SUCCESS; +} + +grub_efi_status_t EFI_FUNC +(efiemu_get_next_variable_name) (grub_efi_uintn_t *variable_name_size, + grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid) +{ + struct efi_variable *efivar; + LOG ('l'); + + if (!variable_name_size || !variable_name || !vendor_guid) + return GRUB_EFI_INVALID_PARAMETER; + if (variable_name[0]) + { + efivar = find_variable (vendor_guid, variable_name); + if (!efivar) + return GRUB_EFI_NOT_FOUND; + efivar = (struct efi_variable *)((grub_uint8_t *)efivar + + efivar->namelen + + efivar->size + sizeof (*efivar)); + } + else + efivar = (struct efi_variable *) (efiemu_variables); + + LOG ('m'); + if ((grub_uint8_t *)efivar >= efiemu_variables + efiemu_varsize + || !efivar->namelen) + return GRUB_EFI_NOT_FOUND; + if (*variable_name_size < efivar->namelen) + { + *variable_name_size = efivar->namelen; + return GRUB_EFI_BUFFER_TOO_SMALL; + } + + efiemu_memcpy (variable_name, efivar + 1, efivar->namelen); + efiemu_memcpy (vendor_guid, &(efivar->guid), + sizeof (efivar->guid)); + + LOG('h'); + return GRUB_EFI_SUCCESS; +} + +grub_efi_status_t +EFI_FUNC (efiemu_set_variable) (grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t attributes, + grub_efi_uintn_t data_size, + void *data) +{ + struct efi_variable *efivar; + grub_uint8_t *ptr; + LOG('i'); + if (!variable_name[0]) + return GRUB_EFI_INVALID_PARAMETER; + efivar = find_variable (vendor_guid, variable_name); + + /* Delete variable if any */ + if (efivar) + { + efiemu_memcpy (efivar, (grub_uint8_t *)(efivar + 1) + + efivar->namelen + efivar->size, + (efiemu_variables + efiemu_varsize) + - ((grub_uint8_t *)(efivar + 1) + + efivar->namelen + efivar->size)); + efiemu_memset (efiemu_variables + efiemu_varsize + - (sizeof (*efivar) + efivar->namelen + efivar->size), + 0, (sizeof (*efivar) + efivar->namelen + efivar->size)); + } + + if (!data_size) + return GRUB_EFI_SUCCESS; + + for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; ) + { + efivar = (struct efi_variable *) ptr; + ptr += efivar->namelen + efivar->size + sizeof (*efivar); + if (!efivar->namelen) + break; + } + if ((grub_uint8_t *)(efivar + 1) + data_size + + 2 * (efiemu_str16len (variable_name) + 1) + >= efiemu_variables + efiemu_varsize) + return GRUB_EFI_OUT_OF_RESOURCES; + + efiemu_memcpy (&(efivar->guid), vendor_guid, sizeof (efivar->guid)); + efivar->namelen = 2 * (efiemu_str16len (variable_name) + 1); + efivar->size = data_size; + efivar->attributes = attributes; + efiemu_memcpy (efivar + 1, variable_name, + 2 * (efiemu_str16len (variable_name) + 1)); + efiemu_memcpy ((grub_uint8_t *)(efivar + 1) + + 2 * (efiemu_str16len (variable_name) + 1), + data, data_size); + + return GRUB_EFI_SUCCESS; +} + +grub_efi_status_t EFI_FUNC +(efiemu_get_next_high_monotonic_count) (grub_efi_uint32_t *high_count) +{ + LOG ('j'); + if (!high_count) + return GRUB_EFI_INVALID_PARAMETER; + *high_count = ++efiemu_high_monotonic_count; + return GRUB_EFI_SUCCESS; +} + +/* To implement it with APM we need to go to real mode. It's too much hassle + Besides EFI specification says that this function shouldn't be used + on systems supporting ACPI + */ +void +EFI_FUNC (efiemu_reset_system) (grub_efi_reset_type_t reset_type, + grub_efi_status_t reset_status, + grub_efi_uintn_t data_size, + grub_efi_char16_t *reset_data) +{ + LOG ('k'); +} + +struct grub_efi_runtime_services efiemu_runtime_services = +{ + .hdr = + { + .signature = GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE, + .revision = 0x0001000a, + .header_size = sizeof (struct grub_efi_runtime_services), + .crc32 = 0, /* filled later*/ + .reserved = 0 + }, + .get_time = efiemu_get_time, + .set_time = efiemu_set_time, + .get_wakeup_time = efiemu_get_wakeup_time, + .set_wakeup_time = efiemu_set_wakeup_time, + + .set_virtual_address_map = efiemu_set_virtual_address_map, + .convert_pointer = efiemu_convert_pointer, + + .get_variable = efiemu_get_variable, + .get_next_variable_name = efiemu_get_next_variable_name, + .set_variable = efiemu_set_variable, + .get_next_high_monotonic_count = efiemu_get_next_high_monotonic_count, + + .reset_system = efiemu_reset_system +}; + + +static grub_uint16_t efiemu_vendor[] = + {'G', 'R', 'U', 'B', ' ', 'E', 'F', 'I', ' ', + 'R', 'U', 'N', 'T', 'I', 'M', 'E', 0}; + +struct grub_efi_system_table efiemu_system_table = +{ + .hdr = + { + .signature = GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE, + .revision = 0x0001000a, + .header_size = sizeof (struct grub_efi_system_table), + .crc32 = 0, /* filled later*/ + .reserved = 0 + }, + .firmware_vendor = efiemu_vendor, + .firmware_revision = 0x0001000a, + .console_in_handler = 0, + .con_in = 0, + .console_out_handler = 0, + .con_out = 0, + .standard_error_handle = 0, + .std_err = 0, + .runtime_services = &efiemu_runtime_services, + .boot_services = 0, + .num_table_entries = 0, + .configuration_table = 0 +}; + Index: efiemu/runtime/config.h =================================================================== --- efiemu/runtime/config.h (revision 0) +++ efiemu/runtime/config.h (revision 0) @@ -0,0 +1,35 @@ +/* This is a pseudo config.h so that types.h compiles nicely */ +/* + * 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 . + */ + +#define GRUB_TYPES_CPU_HEADER 1 + +#ifdef ELF32 +# define SIZEOF_VOID_P 4 +# define SIZEOF_LONG 4 +# define GRUB_TARGET_SIZEOF_VOID_P 4 +# define GRUB_TARGET_SIZEOF_LONG 4 +# define EFI_FUNC(x) x +#else +# define SIZEOF_VOID_P 8 +# define SIZEOF_LONG 8 +# define GRUB_TARGET_SIZEOF_VOID_P 8 +# define GRUB_TARGET_SIZEOF_LONG 8 +# define EFI_FUNC(x) x ## _real +#endif + Index: efiemu/prepare32.c =================================================================== --- efiemu/prepare32.c (revision 0) +++ efiemu/prepare32.c (revision 0) @@ -0,0 +1,23 @@ +/* This file contains definitions so that prepare.c compiles for 32-bit */ +/* + * 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 . + */ + +#define SUFFIX(x) x ## 32 +#define TYPE(x) x ## 32_t + +#include "prepare.c" Index: efiemu/main.c =================================================================== --- efiemu/main.c (revision 0) +++ efiemu/main.c (revision 0) @@ -0,0 +1,276 @@ +/* This is an emulation of EFI runtime services. + This allows a more uniform boot on i386 machines. + As it emulates only runtime service it isn't able + to chainload EFI bootloader on non-EFI system. */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* System table. Two version depending on mode */ +grub_efi_system_table32_t *grub_efiemu_system_table32 = 0; +grub_efi_system_table64_t *grub_efiemu_system_table64 = 0; +/* Modules may need to execute some actions after memory allocation happens */ +static struct grub_efiemu_prepare_hook *efiemu_prepare_hooks = 0; +/* Linked list of configuration tables */ +static struct grub_efiemu_configuration_table *efiemu_config_tables = 0; + +/* Free all allocated space */ +grub_err_t +grub_efiemu_unload (void) +{ + struct grub_efiemu_configuration_table *cur, *d; + struct grub_efiemu_prepare_hook *curhook, *d2; + grub_efiemu_loadcore_unload (); + + grub_efiemu_mm_unload (); + + for (cur = efiemu_config_tables; cur;) + { + d = cur->next; + if (cur->unload) + cur->unload (cur->data); + grub_free (cur); + cur = d; + } + efiemu_config_tables = 0; + + for (curhook = efiemu_prepare_hooks; curhook;) + { + d2 = curhook->next; + if (curhook->unload) + curhook->unload (curhook->data); + grub_free (curhook); + curhook = d2; + } + efiemu_prepare_hooks = 0; + + return GRUB_ERR_NONE; +} + +/* Remove previously registered table from the list */ +grub_err_t +grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid) +{ + struct grub_efiemu_configuration_table *cur, *prev; + + /* Special treating if head is to remove */ + while (efiemu_config_tables + && !grub_memcmp (&(efiemu_config_tables->guid), &guid, sizeof (guid))) + { + if (efiemu_config_tables->unload) + efiemu_config_tables->unload (efiemu_config_tables->data); + cur = efiemu_config_tables->next; + grub_free (efiemu_config_tables); + efiemu_config_tables = cur; + } + if (!efiemu_config_tables) + return GRUB_ERR_NONE; + + /* Remove from chain */ + for (prev = efiemu_config_tables, cur=prev->next;cur;) + if (!grub_memcmp (&(cur->guid),&guid, sizeof (guid))) + { + if (cur->unload) + cur->unload (cur->data); + prev->next = cur->next; + grub_free (cur); + cur = prev->next; + } + else + { + prev = cur; + cur = cur->next; + } + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data), + void (*unload) (void *data), + void *data) +{ + struct grub_efiemu_prepare_hook *nhook; + if (!hook) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "you must set at least get_table or data"); + nhook = (struct grub_efiemu_prepare_hook *) grub_malloc (sizeof (*nhook)); + if (!nhook) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't prepare hook"); + nhook->hook = hook; + nhook->unload = unload; + nhook->data = data; + nhook->next = efiemu_prepare_hooks; + efiemu_prepare_hooks = nhook; + return GRUB_ERR_NONE; +} + +/* Register a configuration table either supplying the address directly + or with a hook +*/ +grub_err_t +grub_efiemu_register_configuration_table (grub_efi_guid_t guid, + void * (*get_table) (void *data), + void (*unload) (void *data), + void *data) +{ + struct grub_efiemu_configuration_table *tbl; + grub_err_t err; + + if (!get_table && !data) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "you must set at least get_table or data"); + if ((err = grub_efiemu_unregister_configuration_table (guid))) + return err; + + tbl = (struct grub_efiemu_configuration_table *) grub_malloc (sizeof (*tbl)); + if (!tbl) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register table"); + + tbl->guid = guid; + tbl->get_table = get_table; + tbl->unload = unload; + tbl->data = data; + tbl->next = efiemu_config_tables; + efiemu_config_tables = tbl; + + return GRUB_ERR_NONE; +} + + +static grub_err_t +grub_cmd_efiemu_unload (struct grub_arg_list *state __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + return grub_efiemu_unload (); +} + +static grub_err_t +grub_cmd_efiemu_prepare (struct grub_arg_list *state __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n", + 8*grub_efiemu_sizeof_uintn_t ()); + if (grub_efiemu_sizeof_uintn_t () == 4) + return grub_efiemu_prepare32 (efiemu_prepare_hooks, efiemu_config_tables); + else + return grub_efiemu_prepare64 (efiemu_prepare_hooks, efiemu_config_tables); +} + + + + +int +grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key + __attribute__ ((unused))) +{ + /* Nothing to do here yet */ + return 1; +} + + +/* Load the runtime from the file FILENAME. */ +static grub_err_t +grub_efiemu_load_file (const char *filename) +{ + grub_file_t file; + grub_err_t err; + + file = grub_file_open (filename); + if (! file) + return 0; + + err = grub_efiemu_mm_init (); + if (err) + { + grub_file_close (file); + grub_efiemu_unload (); + return grub_error (grub_errno, "Couldn't init memory management"); + } + + grub_dprintf ("efiemu", "mm inited\n"); + + if ((err = grub_efiemu_loadcore_init (file))) + { + grub_file_close (file); + grub_efiemu_unload (); + return err; + } + + grub_file_close (file); + + /* for configuration tables entry in system table*/ + grub_efiemu_request_symbols (1); + + return GRUB_ERR_NONE; +} + + +static grub_err_t +grub_cmd_efiemu_load (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + + grub_efiemu_unload (); + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename required"); + + if ((err = grub_efiemu_load_file (args[0]))) + return err; +#ifndef GRUB_UTIL + if ((err = grub_machine_efiemu_init_tables ())) + return err; +#endif + return GRUB_ERR_NONE; +} + + +GRUB_MOD_INIT(efiemu) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("efiemu_loadcore", grub_cmd_efiemu_load, + GRUB_COMMAND_FLAG_BOTH, + "efiemu_loadcore FILE", + "Load and initialize EFI emulator", 0); + grub_register_command ("efiemu_prepare", grub_cmd_efiemu_prepare, + GRUB_COMMAND_FLAG_BOTH, + "efiemu_prepare", + "Finalize loading of EFI emulator", 0); + grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload, + GRUB_COMMAND_FLAG_BOTH, + "efiemu_unload", + "Unload EFI emulator", 0); +} + +GRUB_MOD_FINI(efiemu) +{ + grub_unregister_command ("efiemu_loadcore"); + grub_unregister_command ("efiemu_prepare"); + grub_unregister_command ("efiemu_unload"); +} Property changes on: efiemu/main.c ___________________________________________________________________ Added: svn:mergeinfo Index: efiemu/modules/pnvram.c =================================================================== --- efiemu/modules/pnvram.c (revision 0) +++ efiemu/modules/pnvram.c (revision 0) @@ -0,0 +1,355 @@ +/* Export pnvram and some variables for runtime */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Place for final location of variables */ +static int nvram_handle = 0; +static int nvramsize_handle = 0; +static int high_monotonic_count_handle = 0; +static int timezone_handle = 0; +static int accuracy_handle = 0; +static int daylight_handle = 0; + +/* Temporary place */ +static grub_uint8_t *nvram; +static grub_size_t nvramsize; +static grub_dl_t my_mod; +static grub_uint32_t high_monotonic_count; +static grub_int8_t timezone; +static grub_uint16_t daylight; +static grub_uint32_t accuracy; + +static const struct grub_arg_option options[] = { + {"size", 's', 0, "number of bytes to reserve for pseudo NVRAM", 0, + ARG_TYPE_INT}, + {"high-monotonic-count", 'm', 0, + "Initial value of high monotonic count", 0, ARG_TYPE_INT}, + {"timezone", 't', 0, + "Timezone, offset in minutes from GMT", 0, ARG_TYPE_INT}, + {"accuracy", 'a', 0, + "Accuracy of clock, in 1e-12 units", 0, ARG_TYPE_INT}, + {"daylight", 'd', 0, + "Daylight value, as per EFI specifications", 0, ARG_TYPE_INT}, + {0, 0, 0, 0, 0, 0} +}; + +/* Parse signed value */ +static int +grub_strtosl (char *arg, char **end, int base) +{ + if (arg[0] == '-') + return -grub_strtoul (arg + 1, end, base); + return grub_strtoul (arg, end, base); +} + +/* Export stuff for efiemu */ +static grub_err_t +nvram_set (void * data __attribute__ ((unused))) +{ + /* Take definitive pointers */ + grub_uint8_t *nvram_def = grub_efiemu_mm_obtain_request (nvram_handle); + grub_uint32_t *nvramsize_def + = grub_efiemu_mm_obtain_request (nvramsize_handle); + grub_uint32_t *high_monotonic_count_def + = grub_efiemu_mm_obtain_request (high_monotonic_count_handle); + grub_int8_t *timezone_def + = grub_efiemu_mm_obtain_request (timezone_handle); + grub_uint16_t *daylight_def + = grub_efiemu_mm_obtain_request (daylight_handle); + grub_uint32_t *accuracy_def + = grub_efiemu_mm_obtain_request (accuracy_handle); + + /* Copy to definitive loaction */ + grub_dprintf ("efiemu", "preparing pnvram\n"); + grub_memcpy (nvram_def, nvram, nvramsize); + *nvramsize_def = nvramsize; + *high_monotonic_count_def = high_monotonic_count; + *timezone_def = timezone; + *daylight_def = daylight; + *accuracy_def = accuracy; + + /* Register symbols */ + grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0); + grub_efiemu_register_symbol ("efiemu_varsize", nvramsize_handle, 0); + grub_efiemu_register_symbol ("efiemu_high_monotonic_count", + high_monotonic_count_handle, 0); + grub_efiemu_register_symbol ("efiemu_time_zone", timezone_handle, 0); + grub_efiemu_register_symbol ("efiemu_time_daylight", daylight_handle, 0); + grub_efiemu_register_symbol ("efiemu_time_accuracy", + accuracy_handle, 0); + + return GRUB_ERR_NONE; +} + +static void +nvram_unload (void * data __attribute__ ((unused))) +{ + grub_efiemu_mm_return_request (nvram_handle); + grub_efiemu_mm_return_request (nvramsize_handle); + grub_efiemu_mm_return_request (high_monotonic_count_handle); + grub_efiemu_mm_return_request (timezone_handle); + grub_efiemu_mm_return_request (accuracy_handle); + grub_efiemu_mm_return_request (daylight_handle); + + grub_free (nvram); + nvram = 0; +} + +/* Load the variables file It's in format + guid1:attr1:name1:data1; + guid2:attr2:name2:data2; + ... + Where all fields are in hex +*/ +static grub_err_t +read_pnvram (char *filename) +{ + char *buf, *ptr, *ptr2; + grub_file_t file; + grub_size_t size; + grub_uint8_t *nvramptr = nvram; + struct efi_variable *efivar; + grub_size_t guidlen, datalen; + unsigned i, j; + + file = grub_file_open (filename); + if (!file) + return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram"); + size = grub_file_size (file); + buf = grub_malloc (size + 1); + if (!buf) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read pnvram"); + if (grub_file_read (file, buf, size) != (grub_ssize_t) size) + return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram"); + buf[size] = 0; + grub_file_close (file); + + for (ptr = buf; *ptr; ) + { + if (grub_isspace (*ptr)) + { + ptr++; + continue; + } + + efivar = (struct efi_variable *) nvramptr; + if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "file is too large for reserved variable space"); + + nvramptr += sizeof (struct efi_variable); + + /* look ahow long guid field is*/ + guidlen = 0; + for (ptr2 = ptr; (grub_isspace (*ptr2) + || (*ptr2 >= '0' && *ptr2 <= '9') + || (*ptr2 >= 'a' && *ptr2 <= 'f') + || (*ptr2 >= 'A' && *ptr2 <= 'F')); + ptr2++) + if (!grub_isspace (*ptr2)) + guidlen++; + guidlen /= 2; + + /* Read guid */ + if (guidlen != sizeof (efivar->guid)) + { + grub_free (buf); + return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); + } + for (i = 0; i < 2 * sizeof (efivar->guid); i++) + { + int hex = 0; + while (grub_isspace (*ptr)) + ptr++; + if (*ptr >= '0' && *ptr <= '9') + hex = *ptr - '0'; + if (*ptr >= 'a' && *ptr <= 'f') + hex = *ptr - 'a' + 10; + if (*ptr >= 'A' && *ptr <= 'F') + hex = *ptr - 'A' + 10; + + if (i%2 == 0) + ((grub_uint8_t *)&(efivar->guid))[i/2] = hex << 4; + else + ((grub_uint8_t *)&(efivar->guid))[i/2] |= hex; + ptr++; + } + + while (grub_isspace (*ptr)) + ptr++; + if (*ptr != ':') + { + grub_dprintf ("efiemu", "Not colon\n"); + grub_free (buf); + return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); + } + ptr++; + while (grub_isspace (*ptr)) + ptr++; + + /* Attributes can be just parsed by existing functions */ + efivar->attributes = grub_strtoul (ptr, &ptr, 16); + + while (grub_isspace (*ptr)) + ptr++; + if (*ptr != ':') + { + grub_dprintf ("efiemu", "Not colon\n"); + grub_free (buf); + return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); + } + ptr++; + while (grub_isspace (*ptr)) + ptr++; + + /* Read name and value */ + for (j = 0; j < 2; j++) + { + /* Look the length */ + datalen = 0; + for (ptr2 = ptr; *ptr2 && (grub_isspace (*ptr2) + || (*ptr2 >= '0' && *ptr2 <= '9') + || (*ptr2 >= 'a' && *ptr2 <= 'f') + || (*ptr2 >= 'A' && *ptr2 <= 'F')); + ptr2++) + if (!grub_isspace (*ptr2)) + datalen++; + datalen /= 2; + + if (nvramptr - nvram + datalen > nvramsize) + { + grub_free (buf); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "file is too large for reserved " + " variable space"); + } + + for (i = 0; i < 2 * datalen; i++) + { + int hex = 0; + while (grub_isspace (*ptr)) + ptr++; + if (*ptr >= '0' && *ptr <= '9') + hex = *ptr - '0'; + if (*ptr >= 'a' && *ptr <= 'f') + hex = *ptr - 'a' + 10; + if (*ptr >= 'A' && *ptr <= 'F') + hex = *ptr - 'A' + 10; + + if (i%2 == 0) + nvramptr[i/2] = hex << 4; + else + nvramptr[i/2] |= hex; + ptr++; + } + nvramptr += datalen; + while (grub_isspace (*ptr)) + ptr++; + if (*ptr != (j ? ';' : ':')) + { + grub_free (buf); + grub_dprintf ("efiemu", j?"Not semicolon\n":"Not colon\n"); + return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); + } + if (j) + efivar->size = datalen; + else + efivar->namelen = datalen; + + ptr++; + } + } + grub_free (buf); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_efiemu_pnvram (struct grub_arg_list *state, + int argc, char **args) +{ + grub_err_t err; + + if (argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one argument expected"); + + nvramsize = state[0].set ? grub_strtoul (state[0].arg, 0, 0) : 2048; + high_monotonic_count = state[1].set ? grub_strtoul (state[1].arg, 0, 0) : 1; + timezone = state[2].set ? grub_strtosl (state[2].arg, 0, 0) + : GRUB_EFI_UNSPECIFIED_TIMEZONE; + accuracy = state[3].set ? grub_strtoul (state[3].arg, 0, 0) : 50000000; + daylight = state[4].set ? grub_strtoul (state[4].arg, 0, 0) : 0; + + nvram = grub_malloc (nvramsize); + if (!nvram) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Couldn't allocate space for temporary pnvram storage"); + grub_memset (nvram, 0, nvramsize); + + if (argc == 1 && (err = read_pnvram (args[0]))) + { + grub_free (nvram); + return err; + } + + if ((err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0))) + { + grub_free (nvram); + return err; + } + nvram_handle + = grub_efiemu_request_memalign (1, nvramsize, + GRUB_EFI_RUNTIME_SERVICES_DATA); + nvramsize_handle + = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t), + GRUB_EFI_RUNTIME_SERVICES_DATA); + high_monotonic_count_handle + = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t), + GRUB_EFI_RUNTIME_SERVICES_DATA); + grub_efiemu_request_symbols (6); +#ifndef GRUB_UTIL + grub_dl_ref (my_mod); +#endif + return GRUB_ERR_NONE; +} + + + +GRUB_MOD_INIT(efiemu_pnvram) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("efiemu_pnvram", grub_cmd_efiemu_pnvram, + GRUB_COMMAND_FLAG_BOTH, + "efiemu_pnvram [FILENAME]", + "Initialise pseudo-NVRAM and load variables from FILE", + options); + my_mod=mod; +} + +GRUB_MOD_FINI(efiemu_pnvram) +{ + grub_unregister_command ("efiemu_pnvram"); +} Property changes on: efiemu/modules/pnvram.c ___________________________________________________________________ Added: svn:mergeinfo Index: efiemu/modules/acpi.c =================================================================== --- efiemu/modules/acpi.c (revision 0) +++ efiemu/modules/acpi.c (revision 0) @@ -0,0 +1,592 @@ +/* Register and manipulate ACPI tables */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = { + {"exclude", 'x', 0, + "Don't load host tables specified by comma-separated list", + 0, ARG_TYPE_STRING}, + {"load-only", 'n', 0, + "Load only tables specified by comma-separated list", 0, ARG_TYPE_STRING}, + {"v1", '1', 0, "Expose v1 tables", 0, ARG_TYPE_NONE}, + {"v2", '2', 0, "Expose v2 and v3 tables", 0, ARG_TYPE_NONE}, + {"oemid", 'o', 0, "Set OEMID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + {"oemtable", 't', 0, + "Set OEMTABLE ID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + {"oemtablerev", 'r', 0, + "Set OEMTABLE revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT}, + {"oemtablecreator", 'c', 0, + "Set creator field of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + {"oemtablecreatorrev", 'd', 0, + "Set creator revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT}, + {0, 0, 0, 0, 0, 0} +}; + +/* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise. + rev2 contains the revision of ACPIv2+ to generate or 0 if */ +static int rev1, rev2; +static grub_dl_t my_mod; +/* OEMID of RSDP, RSDT and XSDT */ +static char root_oemid[6]; +/* OEMTABLE of the same tables */ +static char root_oemtable[8]; +/* OEMREVISION of the same tables */ +static grub_uint32_t root_oemrev; +/* CreatorID of the same tables */ +static char root_creator_id[4]; +/* CreatorRevision of the same tables */ +static grub_uint32_t root_creator_rev; + +/* Linked list of ACPI tables */ +struct efiemu_acpi_table +{ + void *data; + void *addr; + grub_size_t size; + int alloc_handle; + struct efiemu_acpi_table *next; +}; +static struct efiemu_acpi_table *acpi_tables = 0; + +/* DSDT isn't in RSDT. So treat it specially */ +static void *table_dsdt = 0; +/* Pointer to recreated RSDT*/ +static void *rsdt_addr = 0; + +/* Allocation handles for different tables */ +static int dsdt_alloc_handle = 0; +static grub_size_t dsdt_size = 0; +static int rsdpv1_alloc_handle = 0; +static int rsdpv2_alloc_handle = 0; +static int rsdt_alloc_handle = 0; +static int xsdt_alloc_handle = 0; + +/* Address of original FACS */ +static grub_uint32_t facs_addr = 0; + +/* Are RDSP and FACP already generated */ +static int tables_set = 0; +static int locked = 0; + +/* Free common v1 & v2 structures */ +static void +grub_efiemu_acpi_clear (void) +{ + static struct efiemu_acpi_table *cur, *d; + for (cur = acpi_tables; cur; ) + { + grub_free (cur->data); + d = cur->next; + grub_free (cur); + cur = d; + } + + acpi_tables = 0; + grub_free (table_dsdt); + table_dsdt = 0; + dsdt_size = 0; + dsdt_alloc_handle = 0; + rev1 = rev2 = 0; + + grub_efiemu_mm_return_request (dsdt_alloc_handle); + grub_efiemu_mm_return_request (rsdpv1_alloc_handle); + grub_efiemu_mm_return_request (rsdpv2_alloc_handle); + grub_efiemu_mm_return_request (rsdt_alloc_handle); + grub_efiemu_mm_return_request (xsdt_alloc_handle); + + dsdt_alloc_handle = 0; + rsdpv1_alloc_handle = 0; + rsdpv2_alloc_handle = 0; + rsdt_alloc_handle = 0; + xsdt_alloc_handle = 0; + + tables_set = 0; + rsdt_addr = 0; + + if (locked) + grub_dl_unref (my_mod); +} + +static void +unloadv1table (void *data __attribute__ ((unused))) +{ + rev1 = 0; + grub_efiemu_mm_return_request (rsdpv1_alloc_handle); + rsdpv1_alloc_handle = 0; + + /* If we have no ACPIv2+ free common structures */ + if (!rev2) + grub_efiemu_acpi_clear (); +} + +static void +unloadv2table (void *data __attribute__ ((unused))) +{ + rev2 = 0; + grub_efiemu_mm_return_request (rsdpv2_alloc_handle); + grub_efiemu_mm_return_request (xsdt_alloc_handle); + rsdpv2_alloc_handle = 0; + xsdt_alloc_handle = 0; + + /* If we have no ACPIv1 free common structures */ + if (!rev1) + grub_efiemu_acpi_clear (); +} + +/* Create tables common to ACPIv1 and ACPIv2+ */ +static void +setup_common_tables (void) +{ + struct efiemu_acpi_table *cur; + void *dest; + void *dsdt_addr = 0; + struct grub_acpi_table_header *rsdt; + grub_uint32_t *rsdt_entry; + int numoftables; + + /* Don't redo the same job twice */ + if (tables_set) + return; + + /* Copy override dsdt if any */ + if (table_dsdt) + { + dsdt_addr = grub_efiemu_mm_obtain_request (dsdt_alloc_handle); + grub_memcpy (dsdt_addr, table_dsdt, dsdt_size); + } + + /* Copy other tables */ + for (cur = acpi_tables; cur; cur = cur->next) + { + struct grub_acpi_fadt *fadt; + + cur->addr = dest = grub_efiemu_mm_obtain_request (cur->alloc_handle); + grub_memcpy (dest, cur->data, cur->size); + + /* If it's FADT correct DSDT and FACS addresses */ + fadt = (struct grub_acpi_fadt *) dest; + if (!grub_memcmp (fadt->hdr.signature, "FACP", 4)) + { + fadt->dsdt_addr = PTR_TO_UINT32 (dsdt_addr); + fadt->facs_addr = facs_addr; + + /* Does a revision 2 exist at all? */ + if (fadt->hdr.revision >= 3) + { + fadt->dsdt_xaddr = PTR_TO_UINT64 (dsdt_addr); + fadt->facs_xaddr = facs_addr; + } + + /* Recompute checksum */ + fadt->hdr.checksum = 0; + fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length); + } + } + + /* Fill RSDT entries */ + rsdt_addr = rsdt = (struct grub_acpi_table_header *) + grub_efiemu_mm_obtain_request (rsdt_alloc_handle); + rsdt_entry = (grub_uint32_t *)(rsdt + 1); + numoftables = 0; + for (cur = acpi_tables; cur; cur = cur->next) + { + *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr); + numoftables++; + } + + /* Fill RSDT header */ + grub_memcpy (&(rsdt->signature), "RSDT", 4); + rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables; + rsdt->revision = 1; + grub_memcpy (&(rsdt->oemid), root_oemid, 6); + grub_memcpy (&(rsdt->oemtable), root_oemtable, 4); + rsdt->oemrev = root_oemrev; + grub_memcpy (&(rsdt->creator_id), root_creator_id, 6); + rsdt->creator_rev = root_creator_rev; + + /* Recompute checksum */ + rsdt->checksum = 0; + rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length); +} + +/* Get address of regenerated ACPIv1 RSDP */ +static void * +getv1table (void *data __attribute__ ((unused))) +{ + struct grub_acpi_rsdp_v10 *rsdp; + + setup_common_tables (); + + /* Create RSDP */ + rsdp = (struct grub_acpi_rsdp_v10 *) + grub_efiemu_mm_obtain_request (rsdpv1_alloc_handle); + grub_memcpy (&(rsdp->signature), "RSD PTR ", 8); + grub_memcpy (&(rsdp->oemid), root_oemid, sizeof (rsdp->oemid)); + rsdp->revision = 0; + rsdp->rsdt_addr = PTR_TO_UINT32 (rsdt_addr); + rsdp->checksum = 0; + rsdp->checksum = 1 + ~grub_byte_checksum (rsdp, sizeof (*rsdp)); + grub_dprintf ("efiemu", "Generated ACPIv1 tables\n"); + + return rsdp; +} + +static void * +getv2table (void *data __attribute__ ((unused))) +{ + struct grub_acpi_rsdp_v20 *rsdp; + struct grub_acpi_table_header *xsdt; + struct efiemu_acpi_table *cur; + grub_uint64_t *xsdt_entry; + int numoftables; + + setup_common_tables (); + + /* Create XSDT */ + xsdt = (struct grub_acpi_table_header *) + grub_efiemu_mm_obtain_request (xsdt_alloc_handle); + xsdt_entry = (grub_uint64_t *)(xsdt + 1); + numoftables = 0; + for (cur = acpi_tables; cur; cur = cur->next) + { + *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr); + numoftables++; + } + grub_memcpy (&(xsdt->signature), "XSDT", 4); + xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables; + xsdt->revision = 1; + grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid)); + grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable)); + xsdt->oemrev = root_oemrev; + grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id)); + xsdt->creator_rev = root_creator_rev; + xsdt->checksum = 0; + xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length); + + /* Create RSDP */ + rsdp = (struct grub_acpi_rsdp_v20 *) + grub_efiemu_mm_obtain_request (rsdpv2_alloc_handle); + grub_memcpy (&(rsdp->rsdpv1.signature), "RSD PTR ", + sizeof (rsdp->rsdpv1.signature)); + grub_memcpy (&(rsdp->rsdpv1.oemid), root_oemid, sizeof (rsdp->rsdpv1.oemid)); + rsdp->rsdpv1.revision = rev2; + rsdp->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr); + rsdp->rsdpv1.checksum = 0; + rsdp->rsdpv1.checksum = 1 + ~grub_byte_checksum + (&(rsdp->rsdpv1), sizeof (rsdp->rsdpv1)); + rsdp->length = sizeof (*rsdp); + rsdp->xsdt_addr = PTR_TO_UINT64 (xsdt); + rsdp->checksum = 0; + rsdp->checksum = 1 + ~grub_byte_checksum (rsdp, rsdp->length); + grub_dprintf ("efiemu", "Generated ACPIv2 tables\n"); + + return rsdp; +} + +static grub_err_t +grub_cmd_efiemu_acpi (struct grub_arg_list *state, + int argc, char **args) +{ + grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID; + grub_efi_guid_t acpi = GRUB_EFI_ACPI_TABLE_GUID; + struct grub_acpi_rsdp_v10 *rsdp; + int i; + int numtables; + + grub_efiemu_unregister_configuration_table (acpi); + grub_efiemu_unregister_configuration_table (acpi20); + + /* Default values if no RSDP is found */ + rev1 = 1; + rev2 = 3; + + facs_addr = 0; + + rsdp = grub_machine_acpi_get_rsdp (); + + if (rsdp) + { + grub_uint32_t *entry_ptr; + char *exclude = 0; + char *load_only = 0; + char *ptr; + /* RSDT consists of header and an array of 32-bit pointers */ + struct grub_acpi_table_header *rsdt; + + exclude = state[0].set ? grub_strdup (state[0].arg) : 0; + if (exclude) + { + for (ptr = exclude; ptr; ptr++) + *ptr = grub_tolower (*ptr); + } + + load_only = state[1].set ? grub_strdup (state[1].arg) : 0; + if (load_only) + { + for (ptr = load_only; ptr; ptr++) + *ptr = grub_tolower (*ptr); + } + + /* Set revision variables to replicant the same version as host */ + rev1 = !rsdp->revision; + rev2 = rsdp->revision; + rsdt = (struct grub_acpi_table_header *)(rsdp->rsdt_addr); + /* Load host tables */ + for (entry_ptr = (grub_uint32_t *)(rsdt + 1); + entry_ptr < (grub_uint32_t *)(((grub_uint8_t *) rsdt)+rsdt->length); + entry_ptr++) + { + char signature[5]; + struct efiemu_acpi_table *table; + struct grub_acpi_table_header *curtable + = (struct grub_acpi_table_header *)*entry_ptr; + signature[4] = 0; + for (i = 0; i < 4;i++) + signature[i] = grub_tolower (curtable->signature[i]); + + /* If it's FADT it contains addresses of DSDT and FACS */ + if (!grub_strcmp (signature, "facp")) + { + struct grub_acpi_table_header *dsdt; + struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable; + + /* Set root header variables to the same values + as FACP by default */ + grub_memcpy (&root_oemid, &(fadt->hdr.oemid), + sizeof (root_oemid)); + grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable), + sizeof (root_oemtable)); + root_oemrev = fadt->hdr.oemrev; + grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id), + sizeof (root_creator_id)); + root_creator_rev = fadt->hdr.creator_rev; + + /* Load DSDT if not excluded */ + dsdt = (struct grub_acpi_table_header *) fadt->dsdt_addr; + if (dsdt && (!exclude || !grub_strword (exclude, "dsdt")) + && (!load_only || grub_strword (load_only, "dsdt")) + && dsdt->length >= sizeof (*dsdt)) + { + dsdt_size = dsdt->length; + table_dsdt = grub_malloc (dsdt->length); + if (!table_dsdt) + { + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Could allocate table"); + } + grub_memcpy (table_dsdt, dsdt, dsdt->length); + } + + /* Save FACS address. FACS shouldn't be overriden */ + facs_addr = fadt->facs_addr; + } + + /* skip excluded tables */ + if (exclude && grub_strword (exclude, signature)) + continue; + if (load_only && !grub_strword (load_only, signature)) + continue; + + /* Sanity check */ + if (curtable->length < sizeof (*curtable)) + continue; + + table = (struct efiemu_acpi_table *) grub_malloc + (sizeof (struct efiemu_acpi_table)); + if (!table) + { + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Could allocate table structure"); + } + table->size = curtable->length; + table->data = grub_malloc (table->size); + if (!table->data) + { + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Could allocate table"); + } + table->alloc_handle = 0; + table->next = acpi_tables; + acpi_tables = table; + grub_memcpy (table->data, curtable, table->size); + } + grub_free (exclude); + grub_free (load_only); + } + + /* Does user specify versions to generate ? */ + if (state[2].set || state[3].set) + { + rev1 = state[2].set; + if (state[3].set) + rev2 = rev2 ? : 2; + else + rev2 = 0; + } + + /* Does user override root header information? */ + if (state[4].set) + grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid)); + if (state[5].set) + grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable)); + if (state[6].set) + root_oemrev = grub_strtoul (state[6].arg, 0, 0); + if (state[7].set) + grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id)); + if (state[8].set) + root_creator_rev = grub_strtoul (state[8].arg, 0, 0); + + /* Load user tables */ + for (i = 0; i < argc; i++) + { + grub_file_t file; + grub_size_t size; + char *buf; + + file = grub_gzfile_open (args[i], 1); + if (!file) + { + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]); + } + + size = grub_file_size (file); + if (size < sizeof (struct grub_acpi_table_header)) + { + grub_file_close (file); + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_BAD_OS, "file %s is too small", args[i]); + } + + buf = (char *) grub_malloc (size); + if (grub_file_read (file, buf, size) != (int) size) + { + grub_file_close (file); + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]); + } + grub_file_close (file); + + if (!grub_memcmp (((struct grub_acpi_table_header *) buf)->signature, + "DSDT", 4)) + { + grub_free (table_dsdt); + table_dsdt = buf; + dsdt_size = size; + } + else + { + struct efiemu_acpi_table *table; + table = (struct efiemu_acpi_table *) grub_malloc + (sizeof (struct efiemu_acpi_table)); + if (!table) + { + grub_efiemu_acpi_clear (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Could allocate table structure"); + } + table->alloc_handle = 0; + table->size = size; + table->data = buf; + } + } + + /* Request space for normal tables */ + numtables = 0; + { + struct efiemu_acpi_table *cur; + for (cur = acpi_tables; cur; cur = cur->next) + { + cur->alloc_handle = grub_efiemu_request_memalign + (1, cur->size, GRUB_EFI_ACPI_RECLAIM_MEMORY); + numtables++; + } + } + + /* Request space for RSDT */ + rsdt_alloc_handle = grub_efiemu_request_memalign + (1, sizeof (struct grub_acpi_table_header)+4*numtables, + GRUB_EFI_ACPI_RECLAIM_MEMORY); + + /* Request space for RSDPv1 */ + if (rev1) + { + rsdpv1_alloc_handle = grub_efiemu_request_memalign + (1, sizeof (struct grub_acpi_rsdp_v10), + GRUB_EFI_ACPI_RECLAIM_MEMORY); + grub_efiemu_register_configuration_table (acpi, getv1table, + unloadv1table, 0); + } + + /* Request space for RSDPv2+ and XSDT */ + if (rev2) + { + rsdpv2_alloc_handle = grub_efiemu_request_memalign + (1, sizeof (struct grub_acpi_rsdp_v20), + GRUB_EFI_ACPI_RECLAIM_MEMORY); + xsdt_alloc_handle = grub_efiemu_request_memalign + (1, sizeof (struct grub_acpi_table_header)+8*numtables, + GRUB_EFI_ACPI_RECLAIM_MEMORY); + grub_efiemu_register_configuration_table (acpi20, getv2table, + unloadv2table, 0); + } + + /* Request space for DSDT */ + if (dsdt_size) + dsdt_alloc_handle = grub_efiemu_request_memalign + (1, dsdt_size, GRUB_EFI_ACPI_RECLAIM_MEMORY); + + /* Lock the module */ + grub_dl_ref (my_mod); + locked = 1; + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT(efiemu_acpi) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("efiemu_acpi", grub_cmd_efiemu_acpi, + GRUB_COMMAND_FLAG_BOTH, + "efiemu_acpi [-1|-2] [--exclude=table1,table2|" + "--load-only=table1,table2] filename1 [filename2] " + "[...]", + "Load host acpi tables and tables " + "specified by arguments", + options); + my_mod=mod; +} + +GRUB_MOD_FINI(efiemu_acpi) +{ + grub_unregister_command ("efiemu_acpi"); +} Index: efiemu/i386/pc/cfgtables.c =================================================================== --- efiemu/i386/pc/cfgtables.c (revision 0) +++ efiemu/i386/pc/cfgtables.c (revision 0) @@ -0,0 +1,46 @@ +/* Find SMBIOS table */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include + +grub_err_t +grub_machine_efiemu_init_tables () +{ + grub_uint8_t *ptr; + grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID; + + + for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000; + ptr += 16) + if (!grub_memcmp (ptr, "_SM_", 4) + && grub_efiemu_byte_checksum (ptr, *(ptr+5)) == 0) + break; + + if (ptr < (grub_uint8_t *)0x100000) + { + grub_dprintf ("efiemu", "Registering SMBIOS\n"); + grub_efiemu_register_configuration_table (smbios, 0, 0, ptr); + } + + return GRUB_ERR_NONE; +} Property changes on: efiemu/i386/pc/cfgtables.c ___________________________________________________________________ Added: svn:mergeinfo Index: efiemu/i386/loadcore64.c =================================================================== --- efiemu/i386/loadcore64.c (revision 0) +++ efiemu/i386/loadcore64.c (revision 0) @@ -0,0 +1,121 @@ +/* i386 CPU-specific part of loadcore.c for 32-bit mode */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Check if EHDR is a valid ELF header. */ +int +grub_arch_efiemu_check_header64 (void *ehdr) +{ + Elf64_Ehdr *e = ehdr; + + return (e->e_ident[EI_CLASS] == ELFCLASS64 + && e->e_ident[EI_DATA] == ELFDATA2LSB + && e->e_machine == EM_X86_64); +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs, + struct grub_efiemu_elf_sym *elfsyms, + void *ehdr) +{ + unsigned i; + Elf64_Ehdr *e = ehdr; + Elf64_Shdr *s; + grub_err_t err; + + for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_RELA) + { + grub_efiemu_segment_t seg; + grub_dprintf ("efiemu", "shtrel\n"); + + /* Find the target segment. */ + for (seg = segs; seg; seg = seg->next) + if (seg->section == s->sh_info) + break; + + if (seg) + { + Elf64_Rela *rel, *max; + + for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset), + max = rel + (unsigned long) s->sh_size + / (unsigned long)s->sh_entsize; + rel < max; + rel++) + { + void *addr; + grub_uint32_t *addr32; + grub_uint64_t *addr64; + struct grub_efiemu_elf_sym sym; + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr = + ((char *) grub_efiemu_mm_obtain_request (seg->handle) + + seg->off + rel->r_offset); + addr32 = (grub_uint32_t *) addr; + addr64 = (grub_uint64_t *) addr; + sym = elfsyms[ELF64_R_SYM (rel->r_info)]; + + switch (ELF64_R_TYPE (rel->r_info)) + { + case R_X86_64_64: + if ((err = grub_efiemu_write_value + (addr, *addr64 + rel->r_addend + sym.off, sym.handle, + 0, seg->ptv_rel_needed, sizeof (grub_uint64_t)))) + return err; + break; + + case R_X86_64_PC32: + if ((err = grub_efiemu_write_value + (addr, *addr32 + rel->r_addend + sym.off + - rel->r_offset - seg->off, sym.handle, seg->handle, + seg->ptv_rel_needed, sizeof (grub_uint32_t)))) + return err; + break; + + case R_X86_64_32: + case R_X86_64_32S: + if ((err = grub_efiemu_write_value + (addr, *addr32 + rel->r_addend + sym.off, sym.handle, + 0, seg->ptv_rel_needed, sizeof (grub_uint32_t)))) + return err; + break; + default: + return grub_error (GRUB_ERR_BAD_OS, + "unrecognised relocation"); + } + } + } + } + + return GRUB_ERR_NONE; +} + Index: efiemu/i386/loadcore32.c =================================================================== --- efiemu/i386/loadcore32.c (revision 0) +++ efiemu/i386/loadcore32.c (revision 0) @@ -0,0 +1,113 @@ +/* i386 CPU-specific part of loadcore.c for 32-bit mode */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Check if EHDR is a valid ELF header. */ +int +grub_arch_efiemu_check_header32 (void *ehdr) +{ + Elf32_Ehdr *e = ehdr; + + /* Check the magic numbers. */ + return (e->e_ident[EI_CLASS] == ELFCLASS32 + && e->e_ident[EI_DATA] == ELFDATA2LSB + && e->e_machine == EM_386); +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_efiemu_relocate_symbols32 (grub_efiemu_segment_t segs, + struct grub_efiemu_elf_sym *elfsyms, + void *ehdr) +{ + unsigned i; + Elf32_Ehdr *e = ehdr; + Elf32_Shdr *s; + grub_err_t err; + + grub_dprintf ("efiemu", "relocating symbols %d %d\n", + e->e_shoff, e->e_shnum); + + for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_REL) + { + grub_efiemu_segment_t seg; + grub_dprintf ("efiemu", "shtrel\n"); + + /* Find the target segment. */ + for (seg = segs; seg; seg = seg->next) + if (seg->section == s->sh_info) + break; + + if (seg) + { + Elf32_Rel *rel, *max; + + for (rel = (Elf32_Rel *) ((char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + { + Elf32_Word *addr; + struct grub_efiemu_elf_sym sym; + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr = (Elf32_Word *) + ((char *) grub_efiemu_mm_obtain_request (seg->handle) + + seg->off + rel->r_offset); + sym = elfsyms[ELF32_R_SYM (rel->r_info)]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_32: + if ((err = grub_efiemu_write_value + (addr, sym.off + *addr, sym.handle, 0, + seg->ptv_rel_needed, sizeof (grub_uint32_t)))) + return err; + + break; + + case R_386_PC32: + if ((err = grub_efiemu_write_value + (addr, sym.off + *addr - rel->r_offset + - seg->off, sym.handle, seg->handle, + seg->ptv_rel_needed, sizeof (grub_uint32_t)))) + return err; + break; + default: + return grub_error (GRUB_ERR_BAD_OS, + "unrecognised relocation"); + } + } + } + } + + return GRUB_ERR_NONE; +} + Index: efiemu/prepare64.c =================================================================== --- efiemu/prepare64.c (revision 0) +++ efiemu/prepare64.c (revision 0) @@ -0,0 +1,23 @@ +/* This file contains definitions so that prepare.c compiles for 64-bit */ +/* + * 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 . + */ + +#define SUFFIX(x) x ## 64 +#define TYPE(x) x ## 64_t + +#include "prepare.c" Index: efiemu/loadcore.c =================================================================== --- efiemu/loadcore.c (revision 0) +++ efiemu/loadcore.c (revision 0) @@ -0,0 +1,370 @@ +/* Load runtime image of EFIemu. Functions specific to 32/64-bit mode */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* ELF symbols and their values */ +static struct grub_efiemu_elf_sym *grub_efiemu_elfsyms = 0; +static int grub_efiemu_nelfsyms = 0; + +/* Return the address of a section whose index is N. */ +static grub_err_t +grub_efiemu_get_section_addr (grub_efiemu_segment_t segs, unsigned n, + int *handle, grub_off_t *off) +{ + grub_efiemu_segment_t seg; + + for (seg = segs; seg; seg = seg->next) + if (seg->section == n) + { + *handle = seg->handle; + *off = seg->off; + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_BAD_OS, "section %d not found", n); +} + +grub_err_t +SUFFIX (grub_efiemu_loadcore_unload) (void) +{ + grub_free (grub_efiemu_elfsyms); + grub_efiemu_elfsyms = 0; + return GRUB_ERR_NONE; +} + +/* Check if EHDR is a valid ELF header. */ +int +SUFFIX (grub_efiemu_check_header) (void *ehdr, grub_size_t size) +{ + Elf_Ehdr *e = ehdr; + + /* Check the header size. */ + if (size < sizeof (Elf_Ehdr)) + return 0; + + /* Check the magic numbers. */ + if (!SUFFIX (grub_arch_efiemu_check_header) (ehdr) + || e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || e->e_version != EV_CURRENT) + return 0; + + return 1; +} + +/* Load all segments from memory specified by E. */ +static grub_err_t +grub_efiemu_load_segments (grub_efiemu_segment_t segs, const Elf_Ehdr *e) +{ + Elf_Shdr *s; + grub_efiemu_segment_t cur; + + grub_dprintf ("efiemu", "loading segments\n"); + + for (cur=segs; cur; cur = cur->next) + { + s = (Elf_Shdr *)cur->srcptr; + + if ((s->sh_flags & SHF_ALLOC) && s->sh_size) + { + void *addr; + + addr = (grub_uint8_t *) grub_efiemu_mm_obtain_request (cur->handle) + + cur->off; + + switch (s->sh_type) + { + case SHT_PROGBITS: + grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); + break; + case SHT_NOBITS: + grub_memset (addr, 0, s->sh_size); + break; + } + } + } + + return GRUB_ERR_NONE; +} + +/* Get a string at offset OFFSET from strtab */ +static char * +grub_efiemu_get_string (unsigned offset, const Elf_Ehdr *e) +{ + unsigned i; + Elf_Shdr *s; + + for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_STRTAB && offset < s->sh_size) + return (char *) e + s->sh_offset + offset; + return 0; +} + +/* Request memory for segments and fill segments info */ +static grub_err_t +grub_efiemu_init_segments (grub_efiemu_segment_t *segs, const Elf_Ehdr *e) +{ + unsigned i; + Elf_Shdr *s; + + for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { + if (s->sh_flags & SHF_ALLOC) + { + grub_efiemu_segment_t seg; + seg = (grub_efiemu_segment_t) grub_malloc (sizeof (*seg)); + if (! seg) + return grub_errno; + + if (s->sh_size) + { + seg->handle + = grub_efiemu_request_memalign + (s->sh_addralign, s->sh_size, + s->sh_flags & SHF_EXECINSTR ? GRUB_EFI_RUNTIME_SERVICES_CODE + : GRUB_EFI_RUNTIME_SERVICES_DATA); + if (seg->handle < 0) + return grub_errno; + seg->off = 0; + } + + /* + .text-physical doesn't need to be relocated when switching to + virtual mode + */ + if (!grub_strcmp (grub_efiemu_get_string (s->sh_name, e), + ".text-physical")) + seg->ptv_rel_needed = 0; + else + seg->ptv_rel_needed = 1; + seg->size = s->sh_size; + seg->section = i; + seg->next = *segs; + seg->srcptr = s; + *segs = seg; + } + } + + return GRUB_ERR_NONE; +} + +/* Count symbols and relocators and allocate/request memory for them */ +static grub_err_t +grub_efiemu_count_symbols (const Elf_Ehdr *e) +{ + unsigned i; + Elf_Shdr *s; + int num = 0; + + /* Symbols */ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_OS, "no symbol table"); + + grub_efiemu_nelfsyms = (unsigned) s->sh_size / (unsigned) s->sh_entsize; + grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) + grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms); + + /* Relocators */ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA) + num += ((unsigned) s->sh_size) / ((unsigned) s->sh_entsize); + + grub_efiemu_request_symbols (num); + + return GRUB_ERR_NONE; +} + +/* Fill grub_efiemu_elfsyms with symbol values */ +static grub_err_t +grub_efiemu_resolve_symbols (grub_efiemu_segment_t segs, Elf_Ehdr *e) +{ + unsigned i; + Elf_Shdr *s; + Elf_Sym *sym; + const char *str; + Elf_Word size, entsize; + + grub_dprintf ("efiemu", "resolving symbols\n"); + + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_OS, "no symbol table"); + + sym = (Elf_Sym *) ((char *) e + s->sh_offset); + size = s->sh_size; + entsize = s->sh_entsize; + + grub_efiemu_nelfsyms = size / entsize; + grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) + grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms); + + + s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link); + str = (char *) e + s->sh_offset; + + for (i = 0; + i < size / entsize; + i++, sym = (Elf_Sym *) ((char *) sym + entsize)) + { + unsigned char type = ELF_ST_TYPE (sym->st_info); + unsigned char bind = ELF_ST_BIND (sym->st_info); + int handle; + grub_off_t off; + grub_err_t err; + const char *name = str + sym->st_name; + grub_efiemu_elfsyms[i].section = sym->st_shndx; + switch (type) + { + case STT_NOTYPE: + /* Resolve a global symbol. */ + if (sym->st_name != 0 && sym->st_shndx == 0) + { + if ((err = grub_efiemu_resolve_symbol (name, &handle, &off))) + return err; + grub_efiemu_elfsyms[i].handle = handle; + grub_efiemu_elfsyms[i].off = off; + } + else + sym->st_value = 0; + break; + + case STT_OBJECT: + if ((err = grub_efiemu_get_section_addr + (segs, sym->st_shndx, &handle, &off))) + return err; + + off += sym->st_value; + if (bind != STB_LOCAL) + if ((err = grub_efiemu_register_symbol (name, handle, off))) + return err; + grub_efiemu_elfsyms[i].handle = handle; + grub_efiemu_elfsyms[i].off = off; + break; + + case STT_FUNC: + if ((err = grub_efiemu_get_section_addr + (segs, sym->st_shndx, &handle, &off))) + return err; + + off += sym->st_value; + if (bind != STB_LOCAL) + if ((err = grub_efiemu_register_symbol (name, handle, off))) + return err; + grub_efiemu_elfsyms[i].handle = handle; + grub_efiemu_elfsyms[i].off = off; + break; + + case STT_SECTION: + if ((err = grub_efiemu_get_section_addr + (segs, sym->st_shndx, &handle, &off))) + { + grub_efiemu_elfsyms[i].handle = 0; + grub_efiemu_elfsyms[i].off = 0; + grub_errno = GRUB_ERR_NONE; + break; + } + + grub_efiemu_elfsyms[i].handle = handle; + grub_efiemu_elfsyms[i].off = off; + break; + + case STT_FILE: + grub_efiemu_elfsyms[i].handle = 0; + grub_efiemu_elfsyms[i].off = 0; + break; + + default: + return grub_error (GRUB_ERR_BAD_MODULE, + "unknown symbol type `%d'", (int) type); + } + } + + return GRUB_ERR_NONE; +} + +/* Load runtime to the memory and request memory for definitive location*/ +grub_err_t +SUFFIX (grub_efiemu_loadcore_init) (void *core, grub_size_t core_size, + grub_efiemu_segment_t *segments) +{ + Elf_Ehdr *e = (Elf_Ehdr *) core; + grub_err_t err; + + if (e->e_type != ET_REL) + return grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type"); + + /* Make sure that every section is within the core. */ + if ((grub_size_t) core_size < e->e_shoff + e->e_shentsize * e->e_shnum) + return grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core"); + + if ((err = grub_efiemu_init_segments (segments, core))) + return err; + if ((err = grub_efiemu_count_symbols (core))) + return err; + + grub_efiemu_request_symbols (1); + return GRUB_ERR_NONE; +} + +/* Load runtime definitively */ +grub_err_t +SUFFIX (grub_efiemu_loadcore_load) (void *core, + grub_size_t core_size + __attribute__ ((unused)), + grub_efiemu_segment_t segments) +{ + grub_err_t err; + if ((err = grub_efiemu_load_segments (segments, core))) + return err; + if ((err = grub_efiemu_resolve_symbols (segments, core))) + return err; + if ((err = SUFFIX (grub_arch_efiemu_relocate_symbols) (segments, + grub_efiemu_elfsyms, + core))) + return err; + + return GRUB_ERR_NONE; +} Index: efiemu/symbols.c =================================================================== --- efiemu/symbols.c (revision 0) +++ efiemu/symbols.c (revision 0) @@ -0,0 +1,187 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include + +static int ptv_written = 0; +static int ptv_alloc = 0; +static int ptv_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; +} + +/* Announce that the module will need NUM allocators */ +/* 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) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "symbols have already been allocated"); + if (num < 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "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, "symbol %s isn't 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)); + if (!cur) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register symbol"); + 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; + ptv_handle = grub_efiemu_request_memalign + (1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel), + GRUB_EFI_RUNTIME_SERVICES_DATA); + grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0); + return grub_errno; +} + +/* 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) + { + 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_OUT_OF_MEMORY, + "your module didn't declare efiemu " + " relocators correctly"); + + if (minus_handle) + ptv_rels[ptv_written].minustype + = grub_efiemu_mm_get_type (minus_handle); + else + ptv_rels[ptv_written].minustype = 0; + + if (plus_handle) + ptv_rels[ptv_written].plustype + = grub_efiemu_mm_get_type (plus_handle); + else + ptv_rels[ptv_written].plustype = 0; + + ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr); + ptv_rels[ptv_written].size = size; + ptv_written++; + + /* 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 -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle)); + + if (plus_handle) + value += PTR_TO_UINT32 (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_BAD_ARGUMENT, "wrong symbol size"); + } + + return GRUB_ERR_NONE; +} Index: efiemu/mm.c =================================================================== --- efiemu/mm.c (revision 0) +++ efiemu/mm.c (revision 0) @@ -0,0 +1,585 @@ +/* Memory management for 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 . + */ +/* + To keep efiemu runtime contiguous this mm is special. + It uses deffered allocation. + In the first stage you may request memory with grub_efiemu_request_memalign + It will give you a handle with which in the second phase you can access your + memory with grub_efiemu_mm_obtain_request (handle). It's guaranteed that + subsequent calls with the same handle return the same result. You can't request any additional memory once you're in the second phase +*/ + +#include +#include +#include +#include +#include +#include + +struct grub_efiemu_memrequest +{ + struct grub_efiemu_memrequest *next; + grub_efi_memory_type_t type; + grub_size_t size; + grub_size_t align_overhead; + int handle; + void *val; +}; +/* Linked list of requested memory */ +static struct grub_efiemu_memrequest *memrequests = 0; +/* Memory map */ +static grub_efi_memory_descriptor_t *efiemu_mmap = 0; +/* Pointer to allocated memory */ +static void *resident_memory = 0; +/* Size of requested memory per type */ +static grub_size_t requested_memory[GRUB_EFI_MAX_MEMORY_TYPE]; +/* How many slots is allocated for memory_map and how many are already used */ +static int mmap_reserved_size = 0, mmap_num = 0; + +/* Add a memory region to map*/ +static grub_err_t +grub_efiemu_add_to_mmap (grub_uint64_t start, grub_uint64_t size, + grub_efi_memory_type_t type) +{ + grub_uint64_t page_start, npages; + + /* Extend map if necessary*/ + if (mmap_num >= mmap_reserved_size) + { + efiemu_mmap = (grub_efi_memory_descriptor_t *) + grub_realloc (efiemu_mmap, (++mmap_reserved_size) + * sizeof (grub_efi_memory_descriptor_t)); + if (!efiemu_mmap) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Not enough space for memory map"); + } + + /* Fill slot*/ + page_start = start - (start % GRUB_EFIEMU_PAGESIZE); + npages = (size + (start % GRUB_EFIEMU_PAGESIZE) + GRUB_EFIEMU_PAGESIZE - 1) + / GRUB_EFIEMU_PAGESIZE; + efiemu_mmap[mmap_num].physical_start = page_start; + efiemu_mmap[mmap_num].virtual_start = page_start; + efiemu_mmap[mmap_num].num_pages = npages; + efiemu_mmap[mmap_num].type = type; + mmap_num++; + + return GRUB_ERR_NONE; +} + +/* Request a resident memory of type TYPE of size SIZE aligned at ALIGN + ALIGN must be a divisor of page size (if it's a divisor of 4096 + it should be ok on all platforms) + */ +int +grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, + grub_efi_memory_type_t type) +{ + grub_size_t align_overhead; + struct grub_efiemu_memrequest *ret, *cur, *prev; + /* Check that the request is correct */ + if (type >= GRUB_EFI_MAX_MEMORY_TYPE || type <= GRUB_EFI_LOADER_CODE) + return -2; + + /* Add new size to requested size */ + align_overhead = align - (requested_memory[type]%align); + if (align_overhead == align) + align_overhead = 0; + requested_memory[type] += align_overhead + size; + + /* Remember the request */ + ret = grub_malloc (sizeof (*ret)); + if (!ret) + return -1; + ret->type = type; + ret->size = size; + ret->align_overhead = align_overhead; + ret->val = 0; + ret->next = 0; + prev = 0; + + /* Add request to the end of the chain. + It should be at the end because otherwise alignment isn't guaranteed */ + for (cur = memrequests; cur; prev = cur, cur = cur->next); + if (prev) + { + ret->handle = prev->handle + 1; + prev->next = ret; + } + else + { + ret->handle = 1; /* Avoid 0 handle*/ + memrequests = ret; + } + return ret->handle; +} + +/* Really allocate the memory */ +static grub_err_t +efiemu_alloc_requests (void) +{ + grub_size_t align_overhead = 0; + grub_uint8_t *curptr, *typestart; + struct grub_efiemu_memrequest *cur; + grub_size_t total_alloc = 0; + unsigned i; + /* Order of memory regions */ + grub_efi_memory_type_t reqorder[] = + { + /* First come regions usable by OS*/ + GRUB_EFI_LOADER_CODE, + GRUB_EFI_LOADER_DATA, + GRUB_EFI_BOOT_SERVICES_CODE, + GRUB_EFI_BOOT_SERVICES_DATA, + GRUB_EFI_CONVENTIONAL_MEMORY, + GRUB_EFI_ACPI_RECLAIM_MEMORY, + + /* Then memory used by runtime */ + /* This way all our regions are in a single block */ + GRUB_EFI_RUNTIME_SERVICES_CODE, + GRUB_EFI_RUNTIME_SERVICES_DATA, + GRUB_EFI_ACPI_MEMORY_NVS, + + /* And then unavailable memory types. This is more for a completeness. + You should double think before allocating memory of any of these types + */ + GRUB_EFI_UNUSABLE_MEMORY, + GRUB_EFI_MEMORY_MAPPED_IO, + GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE, + GRUB_EFI_PAL_CODE + }; + + /* Compute total memory needed */ + for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) + { + align_overhead = GRUB_EFIEMU_PAGESIZE + - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); + if (align_overhead == GRUB_EFIEMU_PAGESIZE) + align_overhead = 0; + total_alloc += requested_memory[reqorder[i]] + align_overhead; + } + + /* Allocate the whole memory in one block */ + resident_memory = grub_memalign (GRUB_EFIEMU_PAGESIZE, total_alloc); + if (!resident_memory) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't allocate resident memory"); + + /* Split the memory into blocks by type */ + curptr = resident_memory; + for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) + { + if (!requested_memory[reqorder[i]]) + continue; + typestart = curptr; + + /* Write pointers to requests */ + for (cur = memrequests; cur; cur = cur->next) + if (cur->type == reqorder[i]) + { + curptr = ((grub_uint8_t *)curptr) + cur->align_overhead; + cur->val = curptr; + curptr = ((grub_uint8_t *)curptr) + cur->size; + } + + /* Ensure that the regions are page-aligned */ + align_overhead = GRUB_EFIEMU_PAGESIZE + - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); + if (align_overhead == GRUB_EFIEMU_PAGESIZE) + align_overhead = 0; + curptr = ((grub_uint8_t *)curptr) + align_overhead; + + /* Add the region to memory map */ + grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart), + curptr - typestart, reqorder[i]); + } + + return GRUB_ERR_NONE; +} + +/* Get a pointer to requested memory from handle */ +void * +grub_efiemu_mm_obtain_request (int handle) +{ + struct grub_efiemu_memrequest *cur; + for (cur = memrequests; cur; cur = cur->next) + if (cur->handle == handle) + return cur->val; + return 0; +} + +/* Get type of requested memory by handle */ +grub_efi_memory_type_t +grub_efiemu_mm_get_type (int handle) +{ + struct grub_efiemu_memrequest *cur; + for (cur = memrequests; cur; cur = cur->next) + if (cur->handle == handle) + return cur->type; + return 0; +} + +/* Free a request */ +void +grub_efiemu_mm_return_request (int handle) +{ + struct grub_efiemu_memrequest *cur, *prev; + + /* Remove head if necessary */ + while (memrequests && memrequests->handle == handle) + { + cur = memrequests->next; + grub_free (memrequests); + memrequests = cur; + } + if (!memrequests) + return; + + /* Remove request from a middle of chain*/ + for (prev = memrequests, cur = prev->next; cur;) + if (cur->handle == handle) + { + prev->next = cur->next; + grub_free (cur); + cur = prev->next; + } + else + { + prev = cur; + cur = prev->next; + } +} + +/* Reserve space for memory map */ +static grub_err_t +grub_efiemu_mmap_init (void) +{ + auto int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t, grub_uint64_t, + grub_uint32_t); + int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + mmap_reserved_size++; + return 0; + } + + // the place for memory used by efiemu itself + mmap_reserved_size = GRUB_EFI_MAX_MEMORY_TYPE + 1; + +#ifndef GRUB_UTIL + grub_machine_mmap_iterate (bounds_hook); +#endif + + return GRUB_ERR_NONE; +} + +/* This is a drop-in replacement of grub_efi_get_memory_map */ +/* Get the memory map as defined in the EFI spec. Return 1 if successful, + return 0 if partial, or return -1 if an error occurs. */ +int +grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version) +{ + if (!efiemu_mmap) + { + grub_error (GRUB_ERR_INVALID_COMMAND, + "you need to first launch efiemu_prepare"); + return -1; + } + + if (*memory_map_size < mmap_num * sizeof (grub_efi_memory_descriptor_t)) + { + *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t); + return 0; + } + + *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t); + grub_memcpy (memory_map, efiemu_mmap, *memory_map_size); + if (descriptor_size) + *descriptor_size = sizeof (grub_efi_memory_descriptor_t); + if (descriptor_version) + *descriptor_version = 1; + if (map_key) + *map_key = 0; + + return 1; +} + +/* Free everything */ +grub_err_t +grub_efiemu_mm_unload (void) +{ + struct grub_efiemu_memrequest *cur, *d; + for (cur = memrequests; cur;) + { + d = cur->next; + grub_free (cur); + cur = d; + } + memrequests = 0; + grub_memset (&requested_memory, 0, sizeof (requested_memory)); + grub_free (resident_memory); + resident_memory = 0; + grub_free (efiemu_mmap); + efiemu_mmap = 0; + mmap_reserved_size = mmap_num = 0; + return GRUB_ERR_NONE; +} + +/* This function should be called before doing any requests */ +grub_err_t +grub_efiemu_mm_init (void) +{ + grub_err_t err; + + err = grub_efiemu_mm_unload (); + if (err) + return err; + + grub_efiemu_mmap_init (); + + return GRUB_ERR_NONE; +} + +/* Copy host memory map */ +static grub_err_t +grub_efiemu_mmap_fill (void) +{ + auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, + grub_uint64_t size, + grub_uint32_t type) + { + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + return grub_efiemu_add_to_mmap (addr, size, + GRUB_EFI_CONVENTIONAL_MEMORY); + +#ifdef GRUB_MACHINE_MEMORY_ACPI + case GRUB_MACHINE_MEMORY_ACPI: + return grub_efiemu_add_to_mmap (addr, size, + GRUB_EFI_ACPI_RECLAIM_MEMORY); +#endif + +#ifdef GRUB_MACHINE_MEMORY_NVS + case GRUB_MACHINE_MEMORY_NVS: + return grub_efiemu_add_to_mmap (addr, size, + GRUB_EFI_ACPI_MEMORY_NVS); +#endif + + default: + grub_printf ("Unknown memory type %d. Marking as unusable\n", type); + case GRUB_MACHINE_MEMORY_RESERVED: + return grub_efiemu_add_to_mmap (addr, size, + GRUB_EFI_UNUSABLE_MEMORY); + } + } + +#ifndef GRUB_UTIL + grub_machine_mmap_iterate (fill_hook); +#endif + + return GRUB_ERR_NONE; +} + +/* This function resolves overlapping regions and sorts the memory map + It uses scanline (sweeping) algorithm + */ +static grub_err_t +grub_efiemu_mmap_sort_and_uniq (void) +{ + /* If same page is used by multiple types it's resolved + according to priority + 0 - free memory + 1 - memory immediately usable after ExitBootServices + 2 - memory usable after loading ACPI tables + 3 - efiemu memory + 4 - unusable memory + */ + int priority[GRUB_EFI_MAX_MEMORY_TYPE] = + { + [GRUB_EFI_RESERVED_MEMORY_TYPE] = 4, + [GRUB_EFI_LOADER_CODE] = 1, + [GRUB_EFI_LOADER_DATA] = 1, + [GRUB_EFI_BOOT_SERVICES_CODE] = 1, + [GRUB_EFI_BOOT_SERVICES_DATA] = 1, + [GRUB_EFI_RUNTIME_SERVICES_CODE] = 3, + [GRUB_EFI_RUNTIME_SERVICES_DATA] = 3, + [GRUB_EFI_CONVENTIONAL_MEMORY] = 0, + [GRUB_EFI_UNUSABLE_MEMORY] = 4, + [GRUB_EFI_ACPI_RECLAIM_MEMORY] = 2, + [GRUB_EFI_ACPI_MEMORY_NVS] = 3, + [GRUB_EFI_MEMORY_MAPPED_IO] = 4, + [GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE] = 4, + [GRUB_EFI_PAL_CODE] = 4 + }; + + int i, j, k, done; + + /* Scanline events */ + struct grub_efiemu_mmap_scan + { + /* At which memory address*/ + grub_uint64_t pos; + /* 0 = region starts, 1 = region ends */ + int type; + /* Which type of memory region */ + grub_efi_memory_type_t memtype; + }; + struct grub_efiemu_mmap_scan *scanline_events; + struct grub_efiemu_mmap_scan t; + + /* Previous scanline event */ + grub_uint64_t lastaddr; + int lasttype; + /* Current scanline event */ + int curtype; + /* how many regions of given type overlap at current location */ + int present[GRUB_EFI_MAX_MEMORY_TYPE]; + /* Here is stored the resulting memory map*/ + grub_efi_memory_descriptor_t *result; + + /* Initialize variables*/ + grub_memset (present, 0, sizeof (int) * GRUB_EFI_MAX_MEMORY_TYPE); + scanline_events = (struct grub_efiemu_mmap_scan *) + grub_malloc (sizeof (struct grub_efiemu_mmap_scan) * 2 * mmap_num); + + /* Number of chunks can't increase more than by factor of 2 */ + result = (grub_efi_memory_descriptor_t *) + grub_malloc (sizeof (grub_efi_memory_descriptor_t) * 2 * mmap_num); + if (!result || !scanline_events) + { + grub_free (result); + grub_free (scanline_events); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't allocate space for new memory map"); + } + + /* Register scanline events */ + for (i = 0; i < mmap_num; i++) + { + scanline_events[2 * i].pos = efiemu_mmap[i].physical_start; + scanline_events[2 * i].type = 0; + scanline_events[2 * i].memtype = efiemu_mmap[i].type; + scanline_events[2 * i + 1].pos = efiemu_mmap[i].physical_start + + efiemu_mmap[i].num_pages * GRUB_EFIEMU_PAGESIZE; + scanline_events[2 * i + 1].type = 1; + scanline_events[2 * i + 1].memtype = efiemu_mmap[i].type; + } + + /* Primitive bubble sort. It has complexity O(n^2) but since we're + unlikely to have more than 100 chunks it's probably one of the + fastest for one purpose */ + done = 1; + while (done) + { + done = 0; + for (i = 0; i < 2 * mmap_num - 1; i++) + if (scanline_events[i + 1].pos < scanline_events[i].pos) + { + t = scanline_events[i + 1]; + scanline_events[i + 1] = scanline_events[i]; + scanline_events[i] = t; + done = 1; + } + } + + /* Pointer in resulting memory map */ + j = 0; + lastaddr = scanline_events[0].pos; + lasttype = scanline_events[0].memtype; + for (i = 0; i < 2 * mmap_num; i++) + { + /* Process event */ + if (scanline_events[i].type) + present[scanline_events[i].memtype]--; + else + present[scanline_events[i].memtype]++; + + /* Determine current region type */ + curtype = -1; + for (k = 0; k < GRUB_EFI_MAX_MEMORY_TYPE; k++) + if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) + curtype = k; + + /* Add memory region to resulting map if necessary */ + if ((curtype == -1 || curtype != lasttype) + && lastaddr != scanline_events[i].pos + && lasttype != -1) + { + result[j].virtual_start = result[j].physical_start = lastaddr; + result[j].num_pages = (scanline_events[i].pos - lastaddr) + / GRUB_EFIEMU_PAGESIZE; + result[j].type = lasttype; + + /* We set runtime attribute on pages we need to be mapped */ + result[j].attribute + = (lasttype == GRUB_EFI_RUNTIME_SERVICES_CODE + || lasttype == GRUB_EFI_RUNTIME_SERVICES_DATA) + ? GRUB_EFI_MEMORY_RUNTIME : 0; + grub_dprintf ("efiemu", + "mmap entry: type %d start 0x%llx 0x%llx pages\n", + result[j].type, + result[j].physical_start, result[j].num_pages); + j++; + } + + /* Update last values if necessary */ + if (curtype == -1 || curtype != lasttype) + { + lasttype = curtype; + lastaddr = scanline_events[i].pos; + } + } + + grub_free (scanline_events); + + /* Shrink resulting memory map to really used size and replace efiemu_mmap + by new value */ + grub_free (efiemu_mmap); + efiemu_mmap = grub_realloc (result, j * sizeof (*result)); + return GRUB_ERR_NONE; +} + +/* This function is called to switch from first to second phase */ +grub_err_t +grub_efiemu_mm_do_alloc (void) +{ + grub_err_t err; + + /* Preallocate mmap */ + efiemu_mmap = (grub_efi_memory_descriptor_t *) + grub_malloc (mmap_reserved_size * sizeof (grub_efi_memory_descriptor_t)); + if (!efiemu_mmap) + { + grub_efiemu_unload (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't initilaize mmap"); + } + + if ((err = efiemu_alloc_requests ())) + return err; + if ((err = grub_efiemu_mmap_fill ())) + return err; + return grub_efiemu_mmap_sort_and_uniq (); +} Index: efiemu/loadcore32.c =================================================================== --- efiemu/loadcore32.c (revision 0) +++ efiemu/loadcore32.c (revision 0) @@ -0,0 +1,27 @@ +/* This file contains definitions so that loadcore.c compiles for 32-bit */ +/* + * 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 . + */ + +#define SUFFIX(x) x ## 32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Word Elf32_Word +#define ELF_ST_TYPE ELF32_ST_TYPE +#define ELF_ST_BIND ELF32_ST_BIND +#include "loadcore.c" Index: ChangeLog =================================================================== --- ChangeLog (revision 2008) +++ ChangeLog (working copy) @@ -1,3 +1,50 @@ +2009-02-28 Vladimir Serbinenko + + Efiemu + + * conf/i386-pc.rmk: new modules efiemu, efiemu_acpi, efiemu_pnvram, + _linux_efi, linux_efi. + new files in grub-emu + new targets efiemu32.o and efiemu64.o + * lib/i386/pc/acpi.c: new file + * loader/linux_normal_efiemu.c: likewise + * loader/i386/efi/linux.c: added preliminary efiemu support + * util/i386/pc/grub-install.in: add efiemu??.o to the list of + files to copy + * include/grub/autoefi.h: new file + * nclude/grub/i386/efiemu.h: likewise + * include/grub/i386/pc/efiemu.h: likewise + * include/grub/acpi.h: likewise + * include/grub/i386/pc/memory.h: + (GRUB_MACHINE_MEMORY_ACPI): new definition + (GRUB_MACHINE_MEMORY_NVS): likewise + * include/grub/efi/api.h: add LL suffix when necessary + new definitions relating to tables + * include/grub/types.h: new definitions for pointer conversion + * include/grub/efiemu/efiemu.h: new file + * include/grub/efiemu/runtime.h: likewise + * efiemu/prepare.c: likewise + * efiemu/loadcore_common.c: likewise + * efiemu/loadcore64.c: likewise + * efiemu/runtime/efiemu.sh: likewise + * efiemu/runtime/efiemu.S: likewise + * efiemu/runtime/efiemu.c: likewise + * efiemu/runtime/config.h: likewise + * efiemu/prepare32.c: likewise + * efiemu/main.c: likewise + * efiemu/modules/pnvram.c: likewise + * efiemu/modules/i386: likewise + * efiemu/modules/i386/pc: likewise + * efiemu/modules/acpi.c: likewise + * efiemu/i386/pc/cfgtables.c: likewise + * efiemu/i386/loadcore64.c: likewise + * efiemu/i386/loadcore32.c: likewise + * efiemu/prepare64.c: likewise + * efiemu/loadcore.c: likewise + * efiemu/symbols.c: likewise + * efiemu/mm.c: likewise + * efiemu/loadcore32.c: likewise + 2009-02-27 Robert Millan Factorize elf32 / elf64 code in Multiboot loader. This will