Index: conf/i386-pc.rmk =================================================================== --- conf/i386-pc.rmk (revision 1998) +++ conf/i386-pc.rmk (working copy) @@ -146,7 +147,8 @@ \ 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/loadcore.c efiemu/mm.c \ + efiemu/modules/pnvram.c efiemu/i386/loadcore.c lib/crc.c \ grub_emu_LDFLAGS = $(LIBCURSES) @@ -172,3 +177,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 + 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/loadcore.c efiemu/i386/pc/cfgtables.c efiemu/mm.c efiemu/loadcore.c +efiemu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall +efiemu_mod_LDFLAGS = $(COMMON_LDFLAGS) + +efiemu_acpi_mod_SOURCES = efiemu/modules/acpi.c efiemu/modules/i386/pc/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 +225,16 @@ linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _linux_efi.mod. +_linux_efi_mod_SOURCES = loader/i386/efi/linux.c +_linux_efi_mod_CFLAGS = $(COMMON_CFLAGS) +_linux_efi_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For linux_efi.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 Index: kern/i386/pc/init.c =================================================================== --- kern/i386/pc/init.c (revision 1998) +++ kern/i386/pc/init.c (working copy) @@ -149,9 +149,9 @@ #endif /* Add the lower memory into free memory. */ - if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END) + /* if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END) add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END, - grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END); + grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);*/ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) Index: efiemu/main.c =================================================================== --- efiemu/main.c (revision 0) +++ efiemu/main.c (revision 0) @@ -0,0 +1,363 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* These are function for loading and configuring EFI emulator*/ + +grub_efi_system_table32_t *grub_efiemu_system_table32 = 0; +grub_efi_system_table64_t *grub_efiemu_system_table64 = 0; + +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_prepare_hook +{ + struct grub_efiemu_prepare_hook *next; + grub_err_t (*hook) (void *data); + void (*unload) (void *data); + void *data; +}; + +static struct grub_efiemu_prepare_hook *efiemu_prepare_hooks = 0; +static struct grub_efiemu_configuration_table *efiemu_config_tables = 0; + +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; +} + +grub_err_t +grub_efiemu_prepare (void) +{ + grub_err_t err; + int conftable_handle; + struct grub_efiemu_configuration_table *cur; + struct grub_efiemu_prepare_hook *curhook; + + int cntconftables = 0; + grub_efiemu_configuration_table32_t *conftables32 = 0; + + grub_dprintf ("efiemu", "Preparing EfiEmu\n"); + + for (cur = efiemu_config_tables; cur; cur = cur->next) + cntconftables++; + + if (grub_arch_efiemu_sizeof_uintn_t () == 4) + { + conftable_handle + = grub_efiemu_request_memalign (GRUB_EFIEMU_PAGESIZE, + cntconftables * sizeof (*conftables32), + GRUB_EFI_RUNTIME_SERVICES_DATA); + + } + else + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "loading 64-bit efiemu isn't implemented yet"); + + grub_efiemu_alloc_syms (); + + grub_efiemu_mm_do_alloc (); + + grub_efiemu_system_table32 = 0; + grub_efiemu_system_table64 = 0; + grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n", + 8*grub_arch_efiemu_sizeof_uintn_t ()); + if (grub_arch_efiemu_sizeof_uintn_t () == 4) + { + grub_efiemu_runtime_services32_t *runtime_services; + int i; + int handle; + grub_off_t off; + + for (curhook = efiemu_prepare_hooks; curhook; curhook = curhook->next) + curhook->hook (curhook->data); + + if ((err = grub_efiemu_loadcore_load ())) + { + grub_efiemu_unload (); + return err; + } + + if ((err = grub_efiemu_resolve_symbol ("efiemu_system_table", + &handle, &off))) + return err; + + grub_efiemu_system_table32 = (grub_efi_system_table32_t *) + ((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off); + grub_dprintf ("efiemu", "system_table = %p\n", + grub_efiemu_system_table32); + + + if ((err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", + &handle, &off))) + return err; + runtime_services = (grub_efiemu_runtime_services32_t *) + ((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off); + runtime_services->hdr.crc32 = 0; + runtime_services->hdr.crc32 = grub_getcrc32 (0, runtime_services, + sizeof (*runtime_services)); + + + grub_efiemu_write_uint32 + (&(grub_efiemu_system_table32->configuration_table), 0, + conftable_handle, 0, 1); + grub_efiemu_system_table32->num_table_entries = cntconftables; + + conftables32 = (grub_efiemu_configuration_table32_t *) + grub_efiemu_mm_obtain_request (conftable_handle); + i = 0; + for (cur = efiemu_config_tables; cur; cur = cur->next, i++) + { + grub_memcpy (&(conftables32[i].vendor_guid), &(cur->guid), + sizeof (cur->guid)); + if (cur->get_table) + conftables32[i].vendor_table + = PTR_TO_UINT32 (cur->get_table (cur->data)); + else + conftables32[i].vendor_table = PTR_TO_UINT32 (cur->data); + } + + grub_efiemu_system_table32->hdr.crc32 = 0; + grub_efiemu_system_table32->hdr.crc32 + = grub_getcrc32 (0, grub_efiemu_system_table32, + sizeof (*grub_efiemu_system_table32)); + grub_dprintf ("efiemu","system_table = %p, runtime_services = %p," + " conftables = %p (%d entries)\n", + grub_efiemu_system_table32, runtime_services, + conftables32, cntconftables); + } + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid) +{ + struct grub_efiemu_configuration_table *cur, *prev; + 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; + 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; +} + + +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; + grub_dprintf ("efiemu", "registering table %x\n",guid.data1); + 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))) +{ + return grub_efiemu_prepare (); +} + + + + +int +grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key + __attribute__ ((unused))) +{ + /* Nothing to do here yet */ + return 1; +} + + +/* Load a module 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; + + grub_dprintf ("efiemu", "file opened\n"); + + 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,282 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct efi_variable +{ + grub_efi_guid_t guid; + grub_uint32_t namelen; + grub_uint32_t size; + grub_efi_uint32_t attributes; +} __attribute__ ((packed)); + +static int nvram_handle = 0; +static int nvramsize_handle = 0; +static int high_monotonic_count_handle = 0; +static grub_uint8_t *nvram; +static grub_size_t nvramsize; +static grub_dl_t my_mod; +static grub_uint32_t high_monotonic_count; +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}, + {0, 0, 0, 0, 0, 0} +}; + +static grub_err_t +nvram_set (void * data __attribute__ ((unused))) +{ + + 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_dprintf ("efiemu", "preparing pnvram\n"); + grub_memcpy (nvram_def, nvram, nvramsize); + *nvramsize_def = nvramsize; + *high_monotonic_count_def = high_monotonic_count; + 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); + 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_free (nvram); + nvram = 0; +} + +/* guid:attr:name:data;*/ +static grub_err_t +read_pnvram (char *filename) +{ + char *buf, *end, *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); + end = buf + size; + 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); + + 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; + 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++; + 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++; + + for (j = 0; j < 2; j++) + { + datalen = 0; + for (ptr2 = ptr; ptr2 < end && (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; + + 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 (3); +#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/i386/pc/acpi.c =================================================================== --- efiemu/modules/i386/pc/acpi.c (revision 0) +++ efiemu/modules/i386/pc/acpi.c (revision 0) @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct grub_acpi_rsdp_v10 * +grub_machine_efiemu_get_rsdp (void) +{ + int ebda_len; + grub_uint8_t *ptr; + + grub_dprintf ("efiemu", "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_acpi_checksum (ptr, + sizeof (struct grub_acpi_rsdp_v10)) == 0) + return (struct grub_acpi_rsdp_v10 *) ptr; + + grub_dprintf ("efiemu", "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_acpi_checksum (ptr, + sizeof (struct grub_acpi_rsdp_v10)) == 0) + return (struct grub_acpi_rsdp_v10 *) ptr; + return 0; +} Index: efiemu/modules/acpi.c =================================================================== --- efiemu/modules/acpi.c (revision 0) +++ efiemu/modules/acpi.c (revision 0) @@ -0,0 +1,514 @@ +#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} +}; + +static int rev1, rev2; +static grub_dl_t my_mod; +static char root_oemid[6]; +static char root_oemtable[8]; +static grub_uint32_t root_oemrev; +static char root_creator_id[4]; +static grub_uint32_t root_creator_rev; + +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; +static void *rsdt_addr = 0; +static int dsdt_alloc_handle = 0; +static grub_size_t dsdt_size = 0; +static grub_uint32_t facs_addr = 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; +static int tables_set = 0; +static int locked = 0; + +grub_uint8_t +grub_efiemu_acpi_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; +} + +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 (!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 (!rev1) + grub_efiemu_acpi_clear (); +} + +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; + + if (tables_set) + return; + if (table_dsdt) + { + dsdt_addr = grub_efiemu_mm_obtain_request (dsdt_alloc_handle); + grub_memcpy (dsdt_addr, table_dsdt, dsdt_size); + } + 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); + fadt = (struct grub_acpi_fadt *) dest; + if (!grub_memcmp (fadt->hdr.signature, "FACP", 4)) + { + fadt->dsdt_addr = PTR_TO_UINT32 (dsdt_addr); + /* Does a revision 2 exist at all? */ + if (fadt->hdr.revision >= 3) + fadt->dsdt_xaddr = PTR_TO_UINT64 (dsdt_addr); + fadt->hdr.checksum = 0; + fadt->hdr.checksum = 1 + ~grub_efiemu_acpi_checksum + (fadt, fadt->hdr.length); + } + } + 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++; + } + 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; + + rsdt->checksum = 0; + rsdt->checksum = 1 + ~grub_efiemu_acpi_checksum (rsdt, rsdt->length); +} + +static void * +getv1table (void *data __attribute__ ((unused))) +{ + struct grub_acpi_rsdp_v10 *rsdp; + grub_dprintf ("efiemu", "Generating common tables\n"); + setup_common_tables (); + grub_dprintf ("efiemu", "Generating ACPIv1 tables\n"); + 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_efiemu_acpi_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; + grub_dprintf ("efiemu", "Generating common tables\n"); + setup_common_tables (); + grub_dprintf ("efiemu", "Generating ACPIv2 tables\n"); + 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_efiemu_acpi_checksum (xsdt, xsdt->length); + + 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_efiemu_acpi_checksum + (&(rsdp->rsdpv1), sizeof (rsdp->rsdpv1)); + rsdp->length = sizeof (*rsdp); + rsdp->xsdt_addr = PTR_TO_UINT64 (xsdt); + rsdp->checksum = 0; + rsdp->checksum = 1 + ~grub_efiemu_acpi_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_acpi_clear (); + + rev1 = 1; + rev2 = 3; + + rsdp = grub_machine_efiemu_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); + } + + rev1 = !rsdp->revision; + rev2 = rsdp->revision; + rsdt = (struct grub_acpi_table_header *)(rsdp->rsdt_addr); + 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 (!grub_strcmp (signature, "facp")) + { + struct grub_acpi_table_header *dsdt; + struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable; + + dsdt = (struct grub_acpi_table_header *) fadt->dsdt_addr; + 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; + + 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); + } + facs_addr = ((struct grub_acpi_fadt *) entry_ptr)->facs_addr; + } + + if (exclude && grub_strword (exclude, signature)) + continue; + if (load_only && !grub_strword (load_only, signature)) + continue; + + 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); + } + if (state[2].set || state[3].set) + { + rev1 = state[2].set; + if (state[3].set) + rev2 = rev2 ? : 2; + else + rev2 = 0; + } + + 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); + + 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; + } + } + + 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++; + } + } + + + rsdt_alloc_handle = grub_efiemu_request_memalign + (1, sizeof (struct grub_acpi_table_header)+4*numtables, + GRUB_EFI_ACPI_RECLAIM_MEMORY); + + 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); + } + + 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); + } + if (dsdt_size) + dsdt_alloc_handle = grub_efiemu_request_memalign + (1, dsdt_size, GRUB_EFI_ACPI_RECLAIM_MEMORY); + grub_dl_ref (my_mod); + 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/loadcore.c =================================================================== --- efiemu/loadcore.c (revision 0) +++ efiemu/loadcore.c (revision 0) @@ -0,0 +1,544 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +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 grub_efiemu_sym +{ + struct grub_efiemu_sym *next; + char *name; + int handle; + grub_off_t off; +}; +struct grub_efiemu_elf_sym *grub_efiemu_elfsyms = 0; +int grub_efiemu_nelfsyms = 0; +static struct grub_efiemu_sym *efiemu_syms = 0; +static grub_efiemu_segment_t efiemu_segments = 0; +static grub_ssize_t efiemu_core_size; +static void *efiemu_core = 0; +grub_efiemu_mode_t grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED; +static int ptv_written = 0; +static int ptv_alloc = 0; +static int ptv_handle = 0; +static int ptv_requested = 0; +static int grub_efiemu_unload_segs (grub_efiemu_segment_t seg); +static void grub_efiemu_free_syms (void); + +static 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; +} + +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 return the address. + Return NULL, if not found. */ +grub_err_t +grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off) +{ + struct grub_efiemu_sym *cur; + grub_dprintf ("efiemu", "looking for %s\n", name); + 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); +} + +grub_err_t +grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off) +{ + struct grub_efiemu_sym *cur; + cur = (struct grub_efiemu_sym *) grub_malloc (sizeof (*cur)); + grub_dprintf ("efiemu", "registering %s\n", name); + 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; +} + +grub_err_t +grub_efiemu_write_uint32 (void * addr, grub_uint32_t value, int plus_handle, + int minus_handle, int 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 symbols correctly"); + if (ptv_needed) + { + 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 = sizeof (grub_uint32_t); + ptv_written++; + grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written])); + } + + if (minus_handle) + value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle)); + else + ptv_rels[ptv_written].minustype = 0; + + if (plus_handle) + value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle)); + else + ptv_rels[ptv_written].plustype = 0; + + *((grub_uint32_t *) addr) = value; + + return GRUB_ERR_NONE; +} + +/* 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); +} + +/* Check if EHDR is a valid ELF header. */ +static grub_err_t +grub_efiemu_check_header (void *ehdr, grub_size_t size) +{ + Elf32_Ehdr *e = ehdr; + + /* Check the header size. */ + if (size < sizeof (Elf32_Ehdr)) + return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected"); + + /* Check the magic numbers. */ + if (grub_arch_efiemu_check_header (ehdr, &grub_efiemu_mode) + || 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 grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic"); + + return GRUB_ERR_NONE; +} + +/* Load all segments from memory specified by E. */ +static grub_err_t +grub_efiemu_load_segments32 (grub_efiemu_segment_t segs, const Elf32_Ehdr *e) +{ + Elf32_Shdr *s; + grub_efiemu_segment_t cur; + + grub_dprintf ("efiemu", "loading segments\n"); + + for (cur=segs; cur; cur = cur->next) + { + s = (Elf32_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; +} + +static char * +grub_efiemu_get_string32 (unsigned offset, const Elf32_Ehdr *e) +{ + unsigned i; + Elf32_Shdr *s; + + 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_STRTAB && offset < s->sh_size) + { + grub_dprintf ("efiemu", "string:%s\n", (char *) e + s->sh_offset + offset); + return (char *) e + s->sh_offset + offset; + } + return 0; +} + +static grub_err_t +grub_efiemu_init_segments32 (grub_efiemu_segment_t *segs, const Elf32_Ehdr *e) +{ + unsigned i; + Elf32_Shdr *s; + + grub_dprintf ("efiemu", "allocating segments\n"); + + 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_flags & SHF_ALLOC) + { + grub_efiemu_segment_t seg; + grub_dprintf ("efiemu", "section %d, %d\n", i, s->sh_size); + 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; + } + + if (!grub_strcmp (grub_efiemu_get_string32 (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; +} + +static grub_err_t +grub_efiemu_count_symbols32 (const Elf32_Ehdr *e) +{ + unsigned i; + Elf32_Shdr *s; + int num = 0; + + grub_dprintf ("efiemu", "counting symbols\n"); + + 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_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_OS, "no symbol table"); + + grub_efiemu_nelfsyms = s->sh_size / s->sh_entsize; + grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) + grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms); + + 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) + num += s->sh_size / s->sh_entsize; + grub_efiemu_request_symbols (num); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_efiemu_resolve_symbols32 (grub_efiemu_segment_t segs, Elf32_Ehdr *e) +{ + unsigned i; + Elf32_Shdr *s; + Elf32_Sym *sym; + const char *str; + Elf32_Word size, entsize; + + grub_dprintf ("efiemu", "resolving symbols\n"); + + 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_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_OS, "no symbol table"); + + sym = (Elf32_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 = (Elf32_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 = (Elf32_Sym *) ((char *) sym + entsize)) + { + unsigned char type = ELF32_ST_TYPE (sym->st_info); + unsigned char bind = ELF32_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; +} + +/* 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) +{ + 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 (); + + grub_free (grub_efiemu_elfsyms); + grub_efiemu_elfsyms = 0; + + ptv_written = 0; + ptv_alloc = 0; + ptv_requested = 0; + grub_efiemu_mm_return_request (ptv_handle); + ptv_handle = 0; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efiemu_loadcore_init (grub_file_t file) +{ + Elf32_Ehdr *e; + 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); + return grub_errno; + } + + e = efiemu_core; + if (grub_efiemu_check_header (e, efiemu_core_size)) + { + grub_free (efiemu_core); + return GRUB_ERR_BAD_MODULE; + } + + if (e->e_type != ET_REL) + { + grub_free (efiemu_core); + return grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type"); + } + + /* Make sure that every section is within the core. */ + if ((grub_size_t)efiemu_core_size < e->e_shoff + e->e_shentsize * e->e_shnum) + { + grub_free (efiemu_core); + return grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core"); + } + + if ((err = grub_efiemu_init_segments32 (&efiemu_segments, efiemu_core))) + { + grub_free (efiemu_core); + return err; + } + if ((err = grub_efiemu_count_symbols32 (efiemu_core))) + { + grub_free (efiemu_core); + return err; + } + grub_efiemu_request_symbols (1); + return GRUB_ERR_NONE; +} + +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; +} + +grub_err_t +grub_efiemu_loadcore_load (void) +{ + if (grub_efiemu_load_segments32 (efiemu_segments, efiemu_core) + || grub_efiemu_resolve_symbols32 (efiemu_segments, efiemu_core) + || grub_arch_efiemu_relocate_symbols (efiemu_segments, efiemu_core, + grub_efiemu_mode)) + grub_efiemu_loadcore_unload (); + + return grub_errno; +} Index: efiemu/i386/pc/cfgtables.c =================================================================== --- efiemu/i386/pc/cfgtables.c (revision 0) +++ efiemu/i386/pc/cfgtables.c (revision 0) @@ -0,0 +1,22 @@ +#include +#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; + grub_dprintf ("efiemu", "Registering SMBIOS\n"); + for (ptr=(grub_uint8_t *)0xf0000;ptr<(grub_uint8_t *)0x100000;ptr+=16) + if (!grub_memcmp (ptr, "_SM_", 4)) + break; + /* FIXME: checksum ! */ + if (ptr < (grub_uint8_t *)0x100000) + 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/loadcore.c =================================================================== --- efiemu/i386/loadcore.c (revision 0) +++ efiemu/i386/loadcore.c (revision 0) @@ -0,0 +1,129 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +int +grub_arch_efiemu_sizeof_uintn_t (void) +{ + if (grub_efiemu_mode == GRUB_EFIEMU32) + return 4; + if (grub_efiemu_mode == GRUB_EFIEMU64) + return 8; + return 0; +} + +/* Check if EHDR is a valid ELF header. */ +grub_err_t +grub_arch_efiemu_check_header (void *ehdr, grub_efiemu_mode_t *mode) +{ + Elf32_Ehdr *e32 = ehdr; + Elf64_Ehdr *e64 = ehdr; + + /* Check the magic numbers. */ + if (e32->e_ident[EI_CLASS] == ELFCLASS32 + && e32->e_ident[EI_DATA] == ELFDATA2LSB + && e32->e_machine == EM_386 + && (*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU32)) + { + *mode = GRUB_EFIEMU32; + return GRUB_ERR_NONE; + } + if (e64->e_ident[EI_CLASS] == ELFCLASS64 + && e64->e_ident[EI_DATA] == ELFDATA2LSB + && e64->e_machine == EM_X86_64 + && (*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU64)) + { + *mode = GRUB_EFIEMU64; + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic"); +} + +/* Relocate symbols. */ +static grub_err_t +grub_arch_efiemu32_relocate_symbols (grub_efiemu_segment_t segs, 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 = grub_efiemu_elfsyms[ELF32_R_SYM (rel->r_info)]; + + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_32: + if ((err = grub_efiemu_write_uint32 (addr, + sym.off + *addr, + sym.handle, + 0, + seg->ptv_rel_needed))) + return err; + + break; + + case R_386_PC32: + if ((err = grub_efiemu_write_uint32 + (addr, sym.off + *addr - rel->r_offset + - seg->off, sym.handle, + seg->handle, + seg->ptv_rel_needed))) + return err; + break; + } + } + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_arch_efiemu_relocate_symbols (grub_efiemu_segment_t segs, void *ehdr, + grub_efiemu_mode_t mode) +{ + if (mode == GRUB_EFIEMU32) + return grub_arch_efiemu32_relocate_symbols (segs, ehdr); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "64-bit EFI emulation isn't implemented yet"); +} Property changes on: efiemu/i386/loadcore.c ___________________________________________________________________ Added: svn:mergeinfo Index: efiemu/mm.c =================================================================== --- efiemu/mm.c (revision 0) +++ efiemu/mm.c (revision 0) @@ -0,0 +1,463 @@ +#include +#include +#include +#include +#include +#include +#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; +}; +static struct grub_efiemu_memrequest *memrequests = 0; +//static int mmap_handle; +//static grub_uint8_t *efiemu_mmap = 0; +static grub_efi_memory_descriptor_t *efiemu_mmap = 0; +static void *resident_memory = 0; +static grub_size_t total_alloc = 0; +static grub_size_t requested_memory[GRUB_EFI_MAX_MEMORY_TYPE]; +static grub_uint64_t type_start[GRUB_EFI_MAX_MEMORY_TYPE]; +static grub_uint64_t type_end[GRUB_EFI_MAX_MEMORY_TYPE]; + +//static grub_uint64_t mmap_startaddr, mmap_endaddr, mmap_size; +static int mmap_reserved_size = 0, mmap_num = 0; + +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; + 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"); + } + grub_dprintf ("efiemu", "grub_efiemu_add_to_mmap: %d, 0x%llx, 0x%llx\n", + type, start, size); + 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 = start; + efiemu_mmap[mmap_num].virtual_start = start; + efiemu_mmap[mmap_num].num_pages = npages; + efiemu_mmap[mmap_num].type = type; + mmap_num++; + return GRUB_ERR_NONE; +} + +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; + align_overhead = align - (requested_memory[type]%align); + if (align_overhead == align) + align_overhead = 0; + requested_memory[type] += align_overhead + size; + if (type >= GRUB_EFI_MAX_MEMORY_TYPE || type <= GRUB_EFI_LOADER_CODE) + return -2; + 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; + 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; +} + +static grub_err_t +efiemu_alloc_requests (void) +{ + grub_size_t align_overhead = 0; + grub_uint8_t *curptr, *typestart; + struct grub_efiemu_memrequest *cur; + unsigned i; + 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, + + GRUB_EFI_RUNTIME_SERVICES_CODE, + GRUB_EFI_RUNTIME_SERVICES_DATA, + GRUB_EFI_ACPI_MEMORY_NVS, + GRUB_EFI_UNUSABLE_MEMORY, + GRUB_EFI_MEMORY_MAPPED_IO, + GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE, + GRUB_EFI_PAL_CODE + }; + total_alloc = 0; + 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; + } + 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"); + curptr = resident_memory; + for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) + { + if (!requested_memory[reqorder[i]]) + { + type_start[reqorder[i]] = type_end[reqorder[i]] = 0; + continue; + } + typestart = curptr; + 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; + } + 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; + grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart), + curptr - typestart, reqorder[i]); + } + return GRUB_ERR_NONE; +} + +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; +} + +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; +} + +void +grub_efiemu_mm_return_request (int handle) +{ + struct grub_efiemu_memrequest *cur, *prev; + while (memrequests && memrequests->handle == handle) + { + cur = memrequests->next; + grub_free (memrequests); + memrequests = cur; + } + if (!memrequests) + return; + + 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; + } + +} + + +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; +} +/* 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) + return grub_error (GRUB_ERR_INVALID_COMMAND, + "you need to first launch efiemu_prepare"); + 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; +} + +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; +} + +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; +} + +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); + 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; +} + +static grub_err_t +grub_efiemu_mmap_sort_and_uniq (void) +{ + int priority[GRUB_EFI_MAX_MEMORY_TYPE] = + { + [GRUB_EFI_RESERVED_MEMORY_TYPE] = 4, + [GRUB_EFI_LOADER_CODE] = 2, + [GRUB_EFI_LOADER_DATA] = 2, + [GRUB_EFI_BOOT_SERVICES_CODE] = 2, + [GRUB_EFI_BOOT_SERVICES_DATA] = 2, + [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] = 1, + [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; + struct grub_efiemu_mmap_scan + { + grub_uint64_t pos; + int type; + grub_efi_memory_type_t memtype; + }; + + struct grub_efiemu_mmap_scan *scanline_events; + struct grub_efiemu_mmap_scan t; + grub_uint64_t lastaddr; + int lasttype; + int curtype; + int present[GRUB_EFI_MAX_MEMORY_TYPE]; + grub_efi_memory_descriptor_t *result; + + grub_dprintf ("efiemu", "mmap %d entries originally\n", mmap_num); + for (j = 0; j < mmap_num; j++) + { + grub_dprintf ("efiemu", + "mmap entry: type %d start 0x%llx 0x%llx pages\n", + efiemu_mmap[j].type, + efiemu_mmap[j].physical_start, efiemu_mmap[j].num_pages) + + } + + 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) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate space for"); + + 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; + } + + 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; + } + } + j = 0; + lastaddr = scanline_events[0].pos; + lasttype = scanline_events[0].memtype; + for (i = 0; i < 2 * mmap_num; i++) + { + if (scanline_events[i].type) + present[scanline_events[i].memtype]--; + else + present[scanline_events[i].memtype]++; + curtype = -1; + for (k = 0; k < GRUB_EFI_MAX_MEMORY_TYPE; k++) + if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) + curtype = k; + if ((curtype == -1 || curtype != lasttype) + && lastaddr != scanline_events[i].pos + && lasttype != -1 && (scanline_events[i].pos - lastaddr) + / GRUB_EFIEMU_PAGESIZE != 0) + { + 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; + 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++; + } + if (curtype == -1 || curtype != lasttype) + { + lasttype = curtype; + lastaddr = scanline_events[i].pos; + } + } + grub_free (efiemu_mmap); + grub_free (scanline_events); + efiemu_mmap = grub_realloc (result, j * sizeof (*result)); + return GRUB_ERR_NONE; +} + + +grub_err_t +grub_efiemu_mm_do_alloc (void) +{ + /* 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"); + } + efiemu_alloc_requests (); + grub_efiemu_mmap_fill (); + grub_efiemu_mmap_sort_and_uniq (); + return GRUB_ERR_NONE; +} Index: include/grub/autoefi.h =================================================================== --- include/grub/autoefi.h (revision 0) +++ include/grub/autoefi.h (revision 0) @@ -0,0 +1,22 @@ +#include + +#ifdef GRUB_MACHINE_EFI +#include +#define GRUB_EFI(x) grub_efi_ ## x +#define SYSTEM_TABLE_SIZEOF GRUB_EFI_SYSTEM_TABLE_SIZEOF +#define SYSTEM_TABLE_VAR GRUB_EFI_SYSTEM_TABLE_VAR +#define SYSTEM_TABLE_PTR GRUB_EFI_SYSTEM_TABLE_PTR +#define SIZEOF_OF_UINTN GRUB_EFI_SIZEOF_OF_UINTN +#define SYSTEM_TABLE GRUB_EFI_SYSTEM_TABLE +#else +#include +#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 Index: include/grub/i386/efiemu.h =================================================================== --- include/grub/i386/efiemu.h (revision 0) +++ include/grub/i386/efiemu.h (revision 0) @@ -0,0 +1,15 @@ +#ifndef GRUB_ARCH_EFI_EMU_HEADER +#define GRUB_ARCH_EFI_EMU_HEADER 1 + +typedef enum {GRUB_EFIEMU_NOTLOADED, + GRUB_EFIEMU32, GRUB_EFIEMU64} grub_efiemu_mode_t; + +grub_err_t +grub_arch_efiemu_relocate_symbols (grub_efiemu_segment_t segs, void *ehdr, + grub_efiemu_mode_t mode); +grub_err_t +grub_arch_efiemu_check_header (void *ehdr, grub_efiemu_mode_t *mode); + +extern grub_efiemu_mode_t grub_efiemu_mode; + +#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,6 @@ +#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/efi/api.h =================================================================== --- include/grub/efi/api.h (revision 1998) +++ 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 @@ -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/efi/efi.h =================================================================== --- include/grub/efi/efi.h (revision 1998) +++ include/grub/efi/efi.h (working copy) @@ -24,6 +24,12 @@ #include #include +#define GRUB_EFI_SYSTEM_TABLE_SIZEOF(x) (sizeof(grub_efi_system_table->x)) +#define GRUB_EFI_SYSTEM_TABLE_VAR(x) ((void *)&(grub_efi_system_table->x)) +#define GRUB_EFI_SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x)) +#define GRUB_EFI_SIZEOF_OF_UINTN sizeof (grub_efi_uintn_t) +#define GRUB_EFI_SYSTEM_TABLE(x) (grub_efi_system_table->x) + /* Functions. */ void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol, void *registration); Index: include/grub/types.h =================================================================== --- include/grub/types.h (revision 1998) +++ 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/efiemu/efiemu.h =================================================================== --- include/grub/efiemu/efiemu.h (revision 0) +++ include/grub/efiemu/efiemu.h (revision 0) @@ -0,0 +1,180 @@ +#ifndef GRUB_EFI_EMU_HEADER +#define GRUB_EFI_EMU_HEADER 1 + +#include + +#define GRUB_EFIEMU_PAGESIZE 4096 + +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_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; +}; +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_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; +}; +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_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; + +extern grub_efi_system_table32_t *grub_efiemu_system_table32; +extern grub_efi_system_table64_t *grub_efiemu_system_table64; + +#define grub_efiemu_system_table ((grub_arch_efiemu_sizeof_uintn_t () == 8) ? (void *)grub_efiemu_system_table64:(void *)grub_efiemu_system_table32) +#define GRUB_EFIEMU_SIZEOF_OF_UINTN (grub_arch_efiemu_sizeof_uintn_t ()) +#define GRUB_EFIEMU_SYSTEM_TABLE(x) ((grub_arch_efiemu_sizeof_uintn_t () == 8) ? grub_efiemu_system_table64->x:grub_efiemu_system_table32->x) +#define GRUB_EFIEMU_SYSTEM_TABLE_SET(x,y) ((grub_arch_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_arch_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_arch_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_arch_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_arch_efiemu_sizeof_uintn_t () == 8) ? sizeof(*grub_efiemu_system_table64):sizeof(*grub_efiemu_system_table32)) + +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); + +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_unload (void); + +grub_err_t grub_efiemu_prepare (void); + +int grub_arch_efiemu_sizeof_uintn_t (void); + +int grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key); + +/* loadcore.c */ +struct grub_efiemu_elf_sym +{ + int handle; + grub_off_t off; + unsigned section; +}; +extern struct grub_efiemu_elf_sym *grub_efiemu_elfsyms; +extern int grub_efiemu_nelfsyms; + +grub_err_t grub_efiemu_alloc_syms (void); +grub_err_t grub_efiemu_request_symbols (int num); +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); +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); + +/* mm.c */ +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_err_t +grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data), + void (*unload) (void *data), + void *data); + +grub_err_t +grub_efiemu_write_uint32 (void * addr, grub_uint32_t value, int plus_handle, + int minus_handle, int ptv_needed); +grub_efi_memory_type_t grub_efiemu_mm_get_type (int handle); +#endif /* GRUB_EFI_EMU_HEADER */ Property changes on: include/grub/efiemu/efiemu.h ___________________________________________________________________ Added: svn:mergeinfo Index: include/grub/efiemu/acpi.h =================================================================== --- include/grub/efiemu/acpi.h (revision 0) +++ include/grub/efiemu/acpi.h (revision 0) @@ -0,0 +1,42 @@ + +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)); + +grub_uint8_t grub_efiemu_acpi_checksum (void *ptr, grub_size_t size); +struct grub_acpi_rsdp_v10 *grub_machine_efiemu_get_rsdp (void); 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 1998) +++ loader/i386/efi/linux.c (working copy) @@ -32,6 +32,7 @@ #include #include #include +#include #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -114,7 +115,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) @@ -188,7 +189,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); @@ -293,7 +294,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; @@ -314,8 +315,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; @@ -391,7 +392,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. */ @@ -513,6 +514,7 @@ return 0; } +#ifdef GRUB_MACHINE_EFI static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; static int @@ -562,9 +564,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; @@ -667,7 +675,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); @@ -677,15 +689,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 @@ -807,11 +819,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, @@ -835,7 +849,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; } @@ -851,8 +865,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; @@ -900,7 +919,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; @@ -956,4 +975,12 @@ 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, "load linux"); grub_rescue_register_command ("initrd", grub_rescue_cmd_initrd, "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 }