From 8a10b2c63296e5f5e19511549db2b78ca7998907 Mon Sep 17 00:00:00 2001 From: phcoder Date: Wed, 2 Sep 2009 13:34:40 +0200 Subject: [PATCH] now hangs at maxDec --- efiemu/prepare.c | 55 ++++++++++++++++------- efiemu/runtime/efiemu.c | 7 ++- efiemu/symbols.c | 84 ++++++++++++++++++++++++++++++++++++ include/grub/autoefi.h | 2 + include/grub/efi/efi.h | 4 ++ include/grub/efiemu/efiemu.h | 10 +++++ include/grub/xnu.h | 1 + kern/efi/efi.c | 19 ++++++++ loader/i386/xnu.c | 9 +++- loader/xnu.c | 14 +++--- 10 files changed, 177 insertions(+), 28 deletions(-) diff --git a/efiemu/prepare.c b/efiemu/prepare.c index 9e6d46fa1..620260049 100644 --- a/efiemu/prepare.c +++ b/efiemu/prepare.c @@ -36,7 +36,6 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, int cntconftables = 0; struct SUFFIX (grub_efiemu_configuration_table) *conftables = 0; - struct SUFFIX (grub_efiemu_runtime_services) *runtime_services; int i; int handle; grub_off_t off; @@ -54,6 +53,7 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, /* Switch from phase 1 (counting) to phase 2 (real job) */ grub_efiemu_alloc_syms (); grub_efiemu_mm_do_alloc (); + grub_efiemu_write_sym_markers (); grub_efiemu_system_table32 = 0; grub_efiemu_system_table64 = 0; @@ -81,16 +81,6 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, = (struct SUFFIX (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 = (struct SUFFIX (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, @@ -113,16 +103,51 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, conftables[i].vendor_table = PTR_TO_UINT64 (cur->data); } + err = SUFFIX (grub_efiemu_crc) (); + if (err) + { + grub_efiemu_unload (); + return err; + } + + grub_dprintf ("efiemu","system_table = %p, conftables = %p (%d entries)\n", + SUFFIX (grub_efiemu_system_table), conftables, cntconftables); + + return GRUB_ERR_NONE; +} + +grub_err_t +SUFFIX (grub_efiemu_crc) (void) +{ + grub_err_t err; + int handle; + grub_off_t off; + struct SUFFIX (grub_efiemu_runtime_services) *runtime_services; + + /* compute CRC32 of runtime_services */ + err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", + &handle, &off); + if (err) + return err; + + runtime_services = (struct SUFFIX (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); + + err = grub_efiemu_resolve_symbol ("efiemu_system_table", &handle, &off); + if (err) + return err; + /* 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); + grub_dprintf ("efiemu","system_table = %p, runtime_services = %p\n", + SUFFIX (grub_efiemu_system_table), runtime_services); return GRUB_ERR_NONE; } diff --git a/efiemu/runtime/efiemu.c b/efiemu/runtime/efiemu.c index 085e75d0c..73893414a 100644 --- a/efiemu/runtime/efiemu.c +++ b/efiemu/runtime/efiemu.c @@ -111,9 +111,8 @@ 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 */ +extern grub_uint8_t efiemu_ptv_relocated; 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[]; @@ -343,9 +342,9 @@ grub_efi_status_t EFI_FUNC LOG ('e'); /* Ensure that we are called only once */ - if (ptv_relocated) + if (efiemu_ptv_relocated) return GRUB_EFI_UNSUPPORTED; - ptv_relocated = 1; + efiemu_ptv_relocated = 1; /* Correct addresses using information supplied by grub */ for (cur_relloc = efiemu_ptv_relloc; cur_relloc->size;cur_relloc++) diff --git a/efiemu/symbols.c b/efiemu/symbols.c index ec508d975..f20761565 100644 --- a/efiemu/symbols.c +++ b/efiemu/symbols.c @@ -26,9 +26,11 @@ static int ptv_written = 0; static int ptv_alloc = 0; static int ptv_handle = 0; +static int relocated_handle = 0; static int ptv_requested = 0; static struct grub_efiemu_sym *efiemu_syms = 0; + struct grub_efiemu_sym { struct grub_efiemu_sym *next; @@ -54,6 +56,8 @@ grub_efiemu_free_syms (void) ptv_requested = 0; grub_efiemu_mm_return_request (ptv_handle); ptv_handle = 0; + grub_efiemu_mm_return_request (relocated_handle); + relocated_handle = 0; } /* Announce that the module will need NUM allocators */ @@ -114,10 +118,26 @@ grub_efiemu_alloc_syms (void) ptv_handle = grub_efiemu_request_memalign (1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel), GRUB_EFI_RUNTIME_SERVICES_DATA); + relocated_handle = grub_efiemu_request_memalign + (1, sizeof (grub_uint8_t), GRUB_EFI_RUNTIME_SERVICES_DATA); + + grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0); grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0); return grub_errno; } +grub_err_t +grub_efiemu_write_sym_markers (void) +{ + struct grub_efiemu_ptv_rel *ptv_rels + = grub_efiemu_mm_obtain_request (ptv_handle); + grub_uint8_t *relocated = grub_efiemu_mm_obtain_request (relocated_handle); + grub_memset (ptv_rels, 0, (ptv_requested + 1) + * sizeof (struct grub_efiemu_ptv_rel)); + *relocated = 0; + return GRUB_ERR_NONE; +} + /* 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 @@ -186,3 +206,67 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle, return GRUB_ERR_NONE; } + +grub_err_t +grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version + __attribute__ ((unused)), + grub_efi_memory_descriptor_t *virtual_map) +{ + grub_uint8_t *ptv_relocated; + struct grub_efiemu_ptv_rel *cur_relloc; + struct grub_efiemu_ptv_rel *ptv_rels; + + ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle); + ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle); + + /* Ensure that we are called only once */ + if (*ptv_relocated) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated."); + *ptv_relocated = 1; + + /* Correct addresses using information supplied by grub */ + for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++) + { + grub_int64_t corr = 0; + grub_efi_memory_descriptor_t *descptr; + + /* Compute correction */ + for (descptr = virtual_map; + (grub_size_t) ((grub_uint8_t *) descptr + - (grub_uint8_t *) virtual_map) < memory_map_size; + descptr = (grub_efi_memory_descriptor_t *) + ((grub_uint8_t *) descptr + descriptor_size)) + { + if (descptr->type == cur_relloc->plustype) + corr += descptr->virtual_start - descptr->physical_start; + if (descptr->type == cur_relloc->minustype) + corr -= descptr->virtual_start - descptr->physical_start; + } + + /* Apply correction */ + switch (cur_relloc->size) + { + case 8: + *((grub_uint64_t *) 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 */ + + if (grub_efiemu_sizeof_uintn_t () == 4) + return grub_efiemu_crc32 (); + else + return grub_efiemu_crc64 (); +} diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h index 4acd43965..4f5e262f0 100644 --- a/include/grub/autoefi.h +++ b/include/grub/autoefi.h @@ -29,6 +29,7 @@ # define grub_autoefi_finish_boot_services grub_efi_finish_boot_services # define grub_autoefi_system_table grub_efi_system_table # define grub_autoefi_mmap_iterate grub_machine_mmap_iterate +# define grub_autoefi_set_virtual_address_map grub_efi_set_virtual_address_map static inline grub_err_t grub_autoefi_prepare (void) { return GRUB_ERR_NONE; @@ -57,6 +58,7 @@ static inline grub_err_t grub_autoefi_prepare (void) # define grub_autoefi_system_table grub_efiemu_system_table # define grub_autoefi_mmap_iterate grub_efiemu_mmap_iterate # define grub_autoefi_prepare grub_efiemu_prepare +# define grub_autoefi_set_virtual_address_map grub_efiemu_set_virtual_address_map # define GRUB_AUTOEFI_MEMORY_AVAILABLE GRUB_EFIEMU_MEMORY_AVAILABLE # define GRUB_AUTOEFI_MEMORY_RESERVED GRUB_EFIEMU_MEMORY_RESERVED # define GRUB_AUTOEFI_MEMORY_ACPI GRUB_EFIEMU_MEMORY_ACPI diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 916f9d662..754c4a7cb 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -57,6 +57,10 @@ int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key); void EXPORT_FUNC (grub_reboot) (void); void EXPORT_FUNC (grub_halt) (void); int EXPORT_FUNC (grub_efi_finish_boot_services) (void); +grub_err_t EXPORT_FUNC (grub_efiemu_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); void grub_efi_mm_init (void); void grub_efi_mm_fini (void); diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 20163dd61..3980d32cd 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -268,9 +268,19 @@ 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); +grub_err_t grub_efiemu_write_sym_markers (void); grub_err_t grub_efiemu_pnvram (void); grub_err_t grub_efiemu_prepare (void); char *grub_efiemu_get_default_core_name (void); void grub_efiemu_pnvram_cmd_unregister (void); grub_err_t grub_efiemu_autocore (void); +grub_err_t grub_efiemu_crc32 (void); +grub_err_t grub_efiemu_crc64 (void); +grub_err_t +grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version + __attribute__ ((unused)), + grub_efi_memory_descriptor_t *virtual_map); + #endif /* ! GRUB_EFI_EMU_HEADER */ diff --git a/include/grub/xnu.h b/include/grub/xnu.h index 67d78d92c..29689479b 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -106,4 +106,5 @@ extern grub_uint32_t grub_xnu_heap_real_start; extern grub_size_t grub_xnu_heap_size; extern char *grub_xnu_heap_start; extern struct grub_video_bitmap *grub_xnu_bitmap; +extern int grub_xnu_is_64bit; #endif diff --git a/kern/efi/efi.c b/kern/efi/efi.c index 8e09a90c0..630f012b6 100644 --- a/kern/efi/efi.c +++ b/kern/efi/efi.c @@ -188,6 +188,25 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key) return status == GRUB_EFI_SUCCESS; } +grub_err_t +grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map) +{ + grub_efi_runtime_services_t *r; + grub_efi_status_t status; + + r = grub_efi_system_table->runtime_services; + status = efi_call_4 (r->set_virtual_address_map, memory_map_size, + descriptor_size, descriptor_version, virtual_map); + + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + + return grub_errno (GRUB_ERR_IO, "set_virtual_address_map failed"); +} + grub_uint32_t grub_get_rtc (void) { diff --git a/loader/i386/xnu.c b/loader/i386/xnu.c index 06e375c69..2bcedebe2 100644 --- a/loader/i386/xnu.c +++ b/loader/i386/xnu.c @@ -474,13 +474,15 @@ grub_xnu_boot (void) grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *) ((char *) memory_map + descriptor_size * i); - /* Some EFI implementations set physical_start to 0 which - causes XNU crash. */ curdesc->virtual_start = curdesc->physical_start; if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE) { + if (grub_xnu_is_64bit && (SIZEOF_OF_UINTN == 8)) + curdesc->virtual_start |= 0xffffff8000000000ULL; + else + curdesc->virtual_start &= 0x000000007fffffffULL; if (firstruntimeaddr > curdesc->physical_start) firstruntimeaddr = curdesc->physical_start; if (lastruntimeaddr < curdesc->physical_start @@ -572,6 +574,9 @@ grub_xnu_boot (void) if (! grub_autoefi_finish_boot_services ()) return grub_error (GRUB_ERR_IO, "can't exit boot services"); + grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, + descriptor_version,memory_map); + grub_xnu_launch (); /* Never reaches here. */ diff --git a/loader/xnu.c b/loader/xnu.c index 271a746e6..2ebca3218 100644 --- a/loader/xnu.c +++ b/loader/xnu.c @@ -35,7 +35,7 @@ struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0; static int driverspackagenum = 0; static int driversnum = 0; -static int is_64bit; +int grub_xnu_is_64bit = 0; /* Allocate heap by 32MB-blocks. */ #define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000 @@ -444,7 +444,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); grub_xnu_lock (); - is_64bit = 0; + grub_xnu_is_64bit = 0; return 0; } @@ -549,7 +549,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); grub_xnu_lock (); - is_64bit = 1; + grub_xnu_is_64bit = 1; return 0; } @@ -668,7 +668,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) return grub_error (GRUB_ERR_BAD_OS, "Extension doesn't contain suitable architecture"); } - if (is_64bit) + if (grub_xnu_is_64bit) machosize = grub_macho_filesize64 (macho); else machosize = grub_macho_filesize32 (macho); @@ -706,7 +706,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) exthead->binaryaddr = (buf - grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->binarysize = machosize; - if (is_64bit) + if (grub_xnu_is_64bit) err = grub_macho_readfile64 (macho, buf); else err = grub_macho_readfile32 (macho, buf); @@ -810,13 +810,13 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), } for (i = 0; i < narchs; i++) { - if (!is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32 + if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32 (grub_be_to_cpu32 (archs[i].cputype))) { readoff = grub_be_to_cpu32 (archs[i].offset); readlen = grub_be_to_cpu32 (archs[i].size); } - if (is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64 + if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64 (grub_be_to_cpu32 (archs[i].cputype))) { readoff = grub_be_to_cpu32 (archs[i].offset);