diff --git a/ChangeLog b/ChangeLog index b3b6c342b..4d5d6653a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,424 @@ +2010-08-29 Vladimir Serbinenko + + New relocator. Allows for more kernel support and more straightforward + loader writing. + + * Makefile.am (BOOTTARGET): New variable. + (QEMU32): Likewise. + (linux.init.x86_64): New target. + (linux.init.i386): Likewise. + (multiboot.elf): Likewise. + (kfreebsd.elf): Likewise. + (kfreebsd.aout): Likewise. + (pc-chainloader.elf): Likewise. + (pc-chainloader.bin): Likewise. + (ntldr.elf): Likewise. + (ntldr.bin): Likewise. + (multiboot2.elf): Likewise. + (kfreebsd.init.x86_64): Likewise. + (kfreebsd.init.i386): Likewise. + (knetbsd.init.i386): Likewise. + (kopenbsd.init.i386): Likewise. + (knetbsd.init.x86_64): Likewise. + (kopenbsd.init.x86_64): Likewise. + (linux-initramfs.i386): Likewise. + (linux-initramfs.x86_64): Likewise. + (kfreebsd-mfsroot.i386.img): Likewise. + (knetbsd.image.i386): Likewise. + (kopenbsd.image.i386): Likewise. + (kopenbsd.image.x86_64): Likewise. + (knetbsd.miniroot-image.i386.img): Likewise. + (kfreebsd-mfsroot.x86_64.img): Likewise. + (knetbsd.image.x86_64): Likewise. + (knetbsd.miniroot-image.x86_64.img): Likewise. + (kfreebsd-mfsroot.i386.gz): Likewise. + (bootcheck-kfreebsd-i386): Likewise. + (kfreebsd-mfsroot.x86_64.gz): Likewise. + (bootcheck-kfreebsd-x86_64): Likewise. + (knetbsd.miniroot-image.i386.gz): Likewise. + (bootcheck-knetbsd-i386): Likewise. + (bootcheck-kopenbsd-i386): Likewise. + (bootcheck-kopenbsd-x86_64): Likewise. + (knetbsd.miniroot-image.x86_64.gz): Likewise. + (bootcheck-knetbsd-x86_64): Likewise. + (bootcheck-linux-i386): Likewise. + (bootcheck-linux-x86_64): Likewise. + (bootcheck-linux16-i386): Likewise. + (bootcheck-linux16-x86_64): Likewise. + (bootcheck-multiboot): Likewise. + (bootcheck-multiboot2): Likewise. + (bootcheck-kfreebsd-aout): Likewise. + (bootcheck-pc-chainloader): Likewise. + (bootcheck-ntldr): Likewise. + (CLEANFILES): Add new targets. + (BOOTCHECKS): New variable. + (.PHONY): Add bootchecks. + (SUCCESSFUL_BOOT_STRING): New variable. + (BOOTCHECK_TIMEOUT): Likewise. + (bootcheck): New target + * Makefile.util.def (grub-mkrescue): Enable on i386-multiboot. + * configure.ac: Correct efiemu excuse. + * docs/grub.texi (Supported kernels): New chapter. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Add + include/grub/mm_private.h. Simplify inclusion of + include/grub/boot.h, include/grub/loader.h + and include/grub/msdos_partition.h + (KERNEL_HEADER_FILES) [i386_coreboot]: + Remove include/grub/machine/loader.h. Add include/grub/i386/pit.h. + (KERNEL_HEADER_FILES) [i386_multiboot]: Likewise. + (KERNEL_HEADER_FILES) [i386_qemu]: Likewise. + (KERNEL_HEADER_FILES) [i386_ieee1275]: Remove + include/grub/machine/loader.h. + (KERNEL_HEADER_FILES) [x86_64-efi]: Likewise. + * grub-core/Makefile.core.def (kernel): Remove kern/i386/loader.S from + extra_dist. + (pci.mod): Enable on i386-multiboot. + (acpi.mod): Enable on i386-multiboot and i386-coreboot. + (efiemu.mod): Enable on i386-coreboot, i386-ieee1275, i386-multiboot and + i386-qemu. + (relocator.mod): Rewritten. + (aout.mod): Enable on all x86. + (bsd.mod): Likewise. + (ntldr.mod): New module. + (linux.mod): Use loader/i386/linux.c on all x86. + (xnu.mod): Enable on all x86. + (vga_text.mod): disable on EFI and QEMU. + * grub-core/efiemu/i386/coredetect.c: Remove useless include. + * grub-core/efiemu/i386/pc/cfgtables.c: Likewise. + * grub-core/efiemu/loadcore.c: Likewise. + * grub-core/efiemu/main.c: Likewise. + (grub_efiemu_exit_boot_services): Removed. + (grub_efiemu_finish_boot_services): Likewise. + * grub-core/efiemu/mm.c (grub_efiemu_finish_boot_services): New + function. + * grub-core/efiemu/i386/nocfgtables.c: New file. + * grub-core/kern/dl.c (grub_dl_unload_all): Removed. + * grub-core/kern/efi/efi.c (grub_efi_exit_boot_services): Removed. + (grub_efi_finish_boot_services): Moved from here ... + * grub-core/kern/efi/mm.c (grub_efi_finish_boot_services): ...here. + Fille finish memory map and related data. + (finish_mmap_buf): New variable. + (grub_efi_uintn_t finish_mmap_size): Likewise. + (grub_efi_uintn_t finish_key): Likewise. + (grub_efi_uintn_t finish_desc_size): Likewise. + (grub_efi_uint32_t finish_desc_version): Likewise. + (grub_efi_is_finished): Likewise. + (grub_efi_get_memory_map): Use saved memory map if EFI is already + finished. + * grub-core/kern/elf.c (grub_elf32_phdr_iterate): Make global. + (grub_elf64_phdr_iterate): Likewise. + * grub-core/kern/i386/coreboot/init.c (grub_os_area_addr): Removed. + (grub_os_area_size): Likewise. + (grub_machine_init): Don't reserve os area. + * grub-core/kern/i386/coreboot/startup.S: Don't include loader.S. + * grub-core/kern/i386/ieee1275/startup.S: Likewise. + * grub-core/kern/i386/loader.S: Removed. + * grub-core/kern/i386/pc/init.c (grub_os_area_addr): Removed. + (grub_os_area_size): Likewise. + (grub_machine_init): Don't reserve os area. + * grub-core/kern/i386/pc/startup.S (grub_chainloader_real_boot): + Don't call grub_dl_unload_all. + Don't include loader.S. + * grub-core/kern/i386/qemu/mmap.c (grub_machine_mmap_iterate): + Declare the memory after _end as available. + * grub-core/kern/mm.c (GRUB_MM_FREE_MAGIC): Moved from here... + * include/grub/mm_private.h (GRUB_MM_FREE_MAGIC): ... here. + (GRUB_MM_ALLOC_MAGIC): Moved from here... + * include/grub/mm_private.h (GRUB_MM_ALLOC_MAGIC): ... here. + * grub-core/kern/mm.c (grub_mm_header): Moved from here... + * include/grub/mm_private.h (grub_mm_header): ... here. + * grub-core/kern/mm.c (GRUB_MM_ALIGN): Moved from here... + * include/grub/mm_private.h (GRUB_MM_ALIGN): ... here. + * grub-core/kern/mm.c (grub_mm_region): Moved from here ... + (grub_mm_region): ..here. Removed addr. Added pre_size. + All users updated. + * grub-core/kern/mm.c (base): Renamed to ... + (grub_mm_base): ... this. Made global. + (grub_real_malloc): Alloc from end of region. + (grub_memalign): Don't attempt to malloc if grub_mm_base is NULL. + * grub-core/kern/powerpc/cache.S (grub_arch_sync_caches): Move to ... + * grub-core/kern/powerpc/cache_flush.S: ... here. + * grub-core/lib/efi/relocator.c: New file. + * grub-core/lib/i386/relocator.c: Rewritten. + * grub-core/lib/i386/relocator16.S: New file. + * grub-core/lib/i386/relocator32.S: Likewise. + * grub-core/lib/i386/relocator64.S: Likewise. + * grub-core/lib/i386/relocator_asm.S: Rewritten. + * grub-core/lib/i386/relocator_common.S: New file. + * grub-core/lib/ieee1275/relocator.c: Likewise. + * grub-core/lib/mips/relocator.c: Rewritten. + * grub-core/lib/mips/relocator_asm.S: Renamed variables and minor + stylistic adjustments. + * grub-core/lib/powerpc/relocator.c: New file. + * grub-core/lib/powerpc/relocator_asm.S: Likewise. + * grub-core/lib/relocator.c: Rewritten. + * grub-core/lib/x86_64/relocator_asm.S: New file. + * grub-core/loader/aout.c (grub_aout_load): Make load_addr a void *. + * grub-core/loader/i386/bsd.c (NETBSD_DEFAULT_VIDEO_MODE): New const. + (bsd_tag): New struct. + (tags): New variable. + (tags_last): Likewise. + (netbsd_module): New struct. + (netbsd_mods): New variable. + (netbsd_mods_last): Likewise. + (openbsd_opts): New parameter "serial". + (OPENBSD_SERIAL_ARG): New definition. + (netbsd_opts): New parameter "serial". + (NETBSD_SERIAL_ARG): New definition. + (grub_freebsd_add_meta): Reorganised into ... + (grub_bsd_add_meta): ...this. All users updated. + (grub_freebsd_add_mmap): Reorganised into ... + (generate_e820_mmap): ...this... + (grub_bsd_add_mmap): ...and this. All users updated. + (grub_freebsd_list_modules): Use tags. + (grub_netbsd_add_meta_module): New function. + (grub_netbsd_list_modules): Likewise. + (grub_freebsd_boot): Use relocator and finish EFI. + (grub_openbsd_boot): Likewise. + (grub_netbsd_setup_video): New function. + (grub_netbsd_add_modules): Likewise. + (grub_netbsd_boot): Use grub_netbsd_add_modules, relocator, netbsd_tags + and finish EFI. + (grub_bsd_unload): Unload tags. + (grub_bsd_load_aout): Use relocator. + (grub_bsd_elf32_size_hook): New function. + (grub_bsd_elf32_hook): Use relocator. + (grub_bsd_elf64_size_hook): New function. + (grub_bsd_elf64_hook): Use relocator. + (grub_bsd_load_elf): Use relocator and call grub_openbsd_find_ramdisk. + (grub_bsd_load): Zero-out openbsd_ramdisk. + (grub_bsd_load): Use relocator. + (grub_cmd_openbsd): Support serial. + (grub_cmd_netbsd): Support modules. + (grub_cmd_freebsd_module): Use relocator. + (grub_netbsd_module_load): New function. + (grub_cmd_netbsd_module): Likewise. + (grub_cmd_openbsd_ramdisk): Likewise. + (GRUB_MOD_INIT): Register knetbsd_module, knetbsd_module_elf and + kopenbsd_ramdisk. + (GRUB_MOD_FINI): Unregister new commands. + * grub-core/loader/i386/bsdXX.c (load): Remove useless checks. + (grub_freebsd_load_elfmodule_obj): Use relocator. + (grub_freebsd_load_elfmodule): Likewise. + (grub_freebsd_load_elf_meta): Likewise. + (grub_netbsd_load_elf_meta): New function. + (grub_openbsd_find_ramdisk): Likewise. + * grub-core/loader/i386/bsd_helper.S: Removed. + * grub-core/loader/i386/bsd_pagetable.c: Support relocator. + * grub-core/loader/i386/bsd_trampoline.S: Removed. + * grub-core/loader/i386/efi/linux.c: Likewise. + * grub-core/loader/i386/ieee1275/linux.c: Likewise. + * grub-core/loader/i386/linux.c (HAS_VGA_TEXT): New const. + (DEFAULT_VIDEO_MODE): Likewise. + (real_mode_target): New variable. + (prot_mode_target): Likewise. + (initrd_mem_target): Likewise. + (relocator): Likewise. + (efi_mmap_buf): Likewise. + (efi_mmap_size): Likewise. + (find_efi_mmap_size): Moved from grub-core/loader/i386/efi/linux.c. + (free_pages): Use relocator. + (allocate_pages): Account for efi_mmap and use relocator. Return error. + (grub_linux_setup_video): Return error. + (grub_linux_trampoline_start): Removed. + (grub_linux_trampoline_end): Likewise. + (grub_linux_boot): Use relocator and DEFAULT_VIDEO_MODE. Pass console + andd video parameters depending on firmware. + [GRUB_MACHINE_IEEE1275]: Pass OFW parameters. + [GRUB_MACHINE_EFI]: Pass EFI parameters. + (grub_cmd_linux) [GRUB_MACHINE_EFI]: Likewise. + (grub_cmd_initrd): Use relocator. + * grub-core/loader/i386/linux_trampoline.S: Removed. + * grub-core/loader/i386/multiboot_mbi.c (elf_sec_num): New variable. + (elf_sec_entsize): Likewise. + (elf_sec_shstrndx): Likewise. + (elf_sections): Likewise. + (grub_multiboot_load): Use relocator. + (grub_multiboot_get_mbi_size): Account for sections. + (grub_multiboot_make_mbi): Use relocator and support sections. + (grub_multiboot_add_elfsyms): New function. + (grub_multiboot_free_mbi): Free sections. + * grub-core/loader/i386/pc/linux.c (relocator): New variable. + (grub_linux_real_target): Likewise. + (grub_linux_real_chunk): Likewise. + (grub_linux16_prot_size): Likewise. + (grub_linux16_boot): Use relocator. + (grub_linux_unload): Unload relocator. + (grub_cmd_linux): Use relocator. + (grub_cmd_initrd): Likewise. + * grub-core/loader/i386/pc/ntldr.c: New file. + * grub-core/loader/i386/xnu.c (guessfsb) [GRUB_MACHINE_IEEE1275]: + Don't try to guess CPU frequency. + (grub_xnu_set_video): Stretch bitmap. + (grub_xnu_boot): Use relocator. + * grub-core/loader/mips/linux.c (grub_linux_boot): Use relocator. + (grub_linux_unload): Free relocator. + (grub_linux_load32): Use relocator. + (grub_linux_load64): Likewise. + (grub_cmd_initrd): Likewise. + * grub-core/loader/multiboot.c (grub_multiboot_boot): Use relocator. + (grub_multiboot_unload): Unload relocator. + (grub_cmd_multiboot): Use relocator. + (grub_cmd_module): Likewise. + * grub-core/loader/multiboot_elfxx.c (grub_multiboot_load_elfXX): + Use relocator and support sections. + * grub-core/loader/multiboot_mbi2.c(elf_sec_num): New variable. + (elf_sec_entsize): Likewise. + (elf_sec_shstrndx): Likewise. + (elf_sections): Likewise. + (grub_multiboot_load): Use relocator. + (grub_multiboot_get_mbi_size): Account for sections. + (grub_multiboot_make_mbi): Use relocator and support sections. + (grub_multiboot_add_elfsyms): New function. + * grub-core/loader/powerpc/ieee1275/linux.c: Remove useless include. + * grub-core/loader/sparc64/ieee1275/linux.c: Likewise. + * grub-core/loader/xnu.c (grub_xnu_heap_malloc): Use relocator. + Prototype changed. All users updated. + (grub_xnu_align_heap): Simplified. + (grub_xnu_writetree_toheap): Likewise. + (grub_xnu_unload): Unload relocator. + (grub_cmd_xnu_kernel): Use relocator. + (grub_cmd_xnu_kernel64): Likewise. + (grub_xnu_register_memory): Simplified. + * grub-core/loader/xnu_resume.c (grub_xnu_resume): Use relocator. + * grub-core/term/efi/console.c (grub_console_putchar): Abort if + EFI is finished. + (grub_console_checkkey): Likewise. + (grub_console_getkey): Likewise. + (grub_console_getwh): Likewise. + (grub_console_getxy): Likewise. + (grub_console_gotoxy): Likewise. + (grub_console_cls): Likewise. + (grub_console_setcolorstate): Likewise. + (grub_console_setcursor): Likewise. + * grub-core/term/ns8250.c (grub_ns8250_hw_get_port): New function. + * grub-core/tests/boot/kbsd.init-i386.S: New file. + * grub-core/tests/boot/kbsd.init-x86_64.S: Likewise. + * grub-core/tests/boot/kbsd.spec.txt: Likewise. + * grub-core/tests/boot/kernel-8086.S: Likewise. + * grub-core/tests/boot/kernel-i386.S: Likewise. + * grub-core/tests/boot/kfreebsd-aout.cfg: Likewise. + * grub-core/tests/boot/kfreebsd.cfg: Likewise. + * grub-core/tests/boot/kfreebsd.init-i386.S: Likewise. + * grub-core/tests/boot/kfreebsd.init-x86_64.S: Likewise. + * grub-core/tests/boot/knetbsd.cfg: Likewise. + * grub-core/tests/boot/kopenbsd.cfg: Likewise. + * grub-core/tests/boot/kopenbsdlabel.txt: Likewise. + * grub-core/tests/boot/linux.cfg: Likewise. + * grub-core/tests/boot/linux.init-i386.S: Likewise. + * grub-core/tests/boot/linux.init-x86_64.S: Likewise. + * grub-core/tests/boot/linux16.cfg: Likewise. + * grub-core/tests/boot/multiboot.cfg: Likewise. + * grub-core/tests/boot/multiboot2.cfg: Likewise. + * grub-core/tests/boot/ntldr.cfg: Likewise. + * grub-core/tests/boot/pc-chainloader.cfg: Likewise. + * include/grub/aout.h (grub_aout_load): Make load_addr a void *. + * include/grub/autoefi.h (grub_autoefi_finish_boot_services): + New definition. + * include/grub/dl.h (grub_dl_unload_all): Removed. + * include/grub/efi/efi.h (grub_efi_exit_boot_services): Likewise. + (grub_efi_finish_boot_services): Change prototype. + (grub_efi_is_finished): New variable. + * include/grub/efiemu/efiemu.h (grub_efiemu_finish_boot_services): + Changed prototype. + (grub_efiemu_finish_boot_services): Removed. + (grub_machine_efiemu_init_tables): New prototype. + * include/grub/elfload.h (grub_elf32_phdr_iterate): Likewise. + (grub_elf64_phdr_iterate): Likewise. + * include/grub/i386/bsd.h: Include relocator.h. + (freebsd_tag_header): New struct. + (grub_openbsd_bios_mmap): Removed. + (grub_unix_real_boot): Removed. + (grub_freebsd_load_elfmodule32): Changed prototype. + (grub_freebsd_load_elfmodule_obj64): Likewise. + (grub_freebsd_load_elf_meta32): Likewise. + (grub_freebsd_load_elf_meta64): Likewise. + (grub_freebsd_add_meta): Removed. + (grub_netbsd_load_elf_meta32): New prototype. + (grub_netbsd_load_elf_meta64): Likewise. + (grub_bsd_add_meta): Likewise. + (grub_openbsd_ramdisk_descriptor): New struct. + (grub_openbsd_find_ramdisk32): New prototype. + (grub_openbsd_find_ramdisk64): Likewise. + * include/grub/i386/coreboot/loader.h: Removed. + * include/grub/i386/efi/loader.h: Likewise. + * include/grub/i386/ieee1275/loader.h: Likewise. + * include/grub/i386/linux.h (linux_kernel_header): Change void * + to grub_uint32_t. + * include/grub/i386/loader.h: Removed. + * include/grub/i386/memory.h (GRUB_MEMORY_CPU_CR4_PAE_ON): Correct the + value. + (GRUB_MEMORY_CPU_CR4_PSE_ON): New definition. + (grub_phys_addr_t): New type. + (grub_vtop): New inline function. + (grub_map_memory): Likewise. + (grub_unmap_memory): Likewise. + * include/grub/i386/multiboot/loader.h: Removed. + * include/grub/i386/netbsd_bootinfo.h (NETBSD_BTINFO_BOOTDISK): Removed. + (NETBSD_BTINFO_CONSOLE): New definition. + (NETBSD_BTINFO_SYMTAB): Likewise. + (NETBSD_BTINFO_MODULES): Likewise. + (NETBSD_BTINFO_FRAMEBUF): Likewise. + (grub_netbsd_bootinfo): New struct. + (grub_netbsd_btinfo_common): Use explicit bitsize. + (grub_netbsd_btinfo_mmap_entry): Removed. + (GRUB_NETBSD_MAX_BOOTPATH_LEN): New definition. + (grub_netbsd_btinfo_bootdisk): New struct. + (grub_netbsd_btinfo_symtab): Likewise. + (grub_netbsd_btinfo_serial): Likewise. + (grub_netbsd_btinfo_modules): Likewise. + (grub_netbsd_btinfo_framebuf): Likewise. + (GRUB_NETBSD_MAX_ROOTDEVICE_LEN): New definition. + * include/grub/i386/openbsd_bootarg.h (OPENBSD_BOOTARG_CONSOLE): + Likewise. + (grub_openbsd_bootargs): Use explicit bitsize. + (grub_openbsd_bootarg_console): New struct. + (GRUB_OPENBSD_COM_MAJOR): New definition. + (GRUB_OPENBSD_VGA_MAJOR): Likewise. + * include/grub/i386/pc/efiemu.h: Removed. + * include/grub/i386/pc/loader.h: Don't include cpu/loader.h. + * include/grub/i386/qemu/loader.h: Removed. + * include/grub/i386/relocator.h: Rewritten. + * include/grub/i386/xnu.h (grub_xnu_heap_will_be_at): Removed. + * include/grub/mips/memory.h: New file. + * include/grub/mips/multiboot.h: Rewritten. + * include/grub/mips/relocator.h: Rewritten. + * include/grub/mips/yeeloong/memory.h (grub_phys_addr_t): New type. + (grub_vtop): New function. + (grub_map_memory): Likewise. + (grub_unmap_memory): Likewise. + * include/grub/misc.h (ALIGN_DOWN): New definition. + * include/grub/mm.h (grub_mm_check_real): New proto. + (GRUB_MM_CHECK): New definition. + * include/grub/mm_private.h: New file. + * include/grub/multiboot.h (grub_multiboot_relocator): New variable. + (grub_multiboot_get_mbi_size): Removed. + (grub_multiboot_make_mbi): Change prottype. + (grub_multiboot_set_accepts_video): New proto. + (grub_multiboot_add_elfsyms): Likewise. + (grub_multiboot_payload_eip): New variable. + * include/grub/ns8250.h (grub_ns8250_hw_get_port) [!ASM_FILE]: + New prototype. + * include/grub/offsets.h (GRUB_KERNEL_I386_MULTIBOOT_PREFIX): + New definition. + (GRUB_KERNEL_I386_MULTIBOOT_DATA_END): Likewise. + (GRUB_KERNEL_I386_MULTIBOOT_MOD_ALIGN): Likewise. + * include/grub/powerpc/ieee1275/loader.h: Removed. + * include/grub/powerpc/memory.h: New file. + * include/grub/powerpc/relocator.h: Likewise. + * include/grub/relocator.h: Likewise. + * include/grub/relocator_private.h: Likewise. + * include/grub/sparc64/ieee1275/loader.h: Removed. + * include/grub/x86_64/memory.h: New file. + * include/grub/xnu.h (grub_xnu_writetree_toheap): Changed prototype. + (grub_xnu_heap_malloc): Likewise. + (grub_xnu_heap_real_start): Removed. + (grub_xnu_heap_start): Likewise. + (grub_xnu_relocator): New variable. + (grub_xnu_heap_target_start): Likewise. + * tests/util/grub-shell.in: Support non-pc. + * util/grub-mkimage.c (image_targets): Fix multiboot target. + 2010-08-29 Vladimir Serbinenko * grub-core/normal/charset.c (grub_utf8_to_ucs4_alloc): Avoid deadloop diff --git a/Makefile.am b/Makefile.am index f49a92ead..1cf2297bd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,4 +82,223 @@ CLEANFILES += widthspec.h platform_HEADERS = config.h pkglib_DATA += grub-mkconfig_lib -pkglib_DATA += update-grub_lib \ No newline at end of file +pkglib_DATA += update-grub_lib + + +if COND_i386_coreboot +BOOTTARGET=coreboot +QEMU32=qemu-system-i386 +endif + +if COND_i386_multiboot +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_ieee1275 +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_qemu +BOOTTARGET=qemu +QEMU32=qemu-system-i386 +endif + +if COND_i386_pc +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_efi +QEMU32=qemu-system-i386 +BOOTTARGET=cd +endif + +if COND_x86_64_efi +QEMU32=qemu-system-x86_64 +BOOTTARGET=cd +endif + +linux.init.x86_64: $(srcdir)/grub-core/tests/boot/linux.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +linux.init.i386: $(srcdir)/grub-core/tests/boot/linux.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +multiboot.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -DTARGET_MULTIBOOT=1 -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include + +kfreebsd.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include + +kfreebsd.aout: kfreebsd.elf + $(OBJCOPY) -O a.out-i386-linux $< $@ -R .note.gnu.build-id + +pc-chainloader.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S + $(TARGET_CC) -o $@ $< -DTARGET_CHAINLOADER=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x7c00 -m32 + +pc-chainloader.bin: pc-chainloader.elf + $(OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn $< $@; + +ntldr.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S + $(TARGET_CC) -o $@ $< -DTARGET_NTLDR=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0 -m32 + +ntldr.bin: ntldr.elf + $(OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn $< $@; + +multiboot2.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include -DTARGET_MULTIBOOT2=1 + +kfreebsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kfreebsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" && freebsd-brandelf -t FreeBSD $@ + +kfreebsd.init.i386: $(srcdir)/grub-core/tests/boot/kfreebsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" && freebsd-brandelf -t FreeBSD $@ + +knetbsd.init.i386: $(srcdir)/grub-core/tests/boot/kbsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DTARGET_NETBSD=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +kopenbsd.init.i386: $(srcdir)/grub-core/tests/boot/kbsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DTARGET_OPENBSD=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +knetbsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kbsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -DTARGET_NETBSD=1 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +kopenbsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kbsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -DTARGET_OPENBSD=1 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +linux-initramfs.i386: linux.init.i386 Makefile + TDIR=`mktemp -d`; cp $< $$TDIR/init; (cd $$TDIR; echo ./init | cpio --quiet --dereference -o -H newc) | gzip > $@; rm -rf $$TDIR + +linux-initramfs.x86_64: linux.init.x86_64 Makefile + TDIR=`mktemp -d`; cp $< $$TDIR/init; (cd $$TDIR; echo ./init | cpio --quiet --dereference -o -H newc) | gzip > $@; rm -rf $$TDIR + +kfreebsd-mfsroot.i386.img: kfreebsd.init.i386 Makefile + TDIR=`mktemp -d`; mkdir $$TDIR/dev; mkdir $$TDIR/sbin; cp $< $$TDIR/sbin/init; makefs -t ffs -s 30m -f 1000 -o minfree=0,version=1 $@ $$TDIR; rm -rf $$TDIR + +knetbsd.image.i386: knetbsd.init.i386 $(srcdir)/grub-core/tests/boot/kbsd.spec.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 64k -f 10 -o minfree=0,version=1 $@ $$TDIR && rm -rf $$TDIR + +kopenbsd.image.i386: kopenbsd.init.i386 $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 128k -f 10 -o minfree=0,version=1 $@ $$TDIR && bsdlabel -f -R $@ $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt && rm -rf $$TDIR || rm -f $@ + +kopenbsd.image.x86_64: kopenbsd.init.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 128k -f 10 -o minfree=0,version=1 $@ $$TDIR && bsdlabel -f -R $@ $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt && rm -rf $$TDIR || rm -f $@ + +knetbsd.miniroot-image.i386.img: knetbsd.image.i386 $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.i386 + $(OBJCOPY) --add-section=miniroot=$< $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.i386 $@ + +kfreebsd-mfsroot.x86_64.img: kfreebsd.init.x86_64 Makefile + TDIR=`mktemp -d`; mkdir $$TDIR/dev; mkdir $$TDIR/sbin; cp $< $$TDIR/sbin/init; makefs -t ffs -s 30m -f 1000 -o minfree=0,version=1 $@ $$TDIR; rm -rf $$TDIR + +knetbsd.image.x86_64: knetbsd.init.x86_64 $(srcdir)/grub-core/tests/boot/kbsd.spec.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 64k -f 10 -o minfree=0,version=1 $@ $$TDIR && rm -rf $$TDIR + +knetbsd.miniroot-image.x86_64.img: knetbsd.image.x86_64 $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.x86_64 + $(OBJCOPY) --add-section=miniroot=$< $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.x86_64 $@ + +CLEANFILES += linux.init.i386 kfreebsd.init.i386 linux.init.x86_64 linux-initramfs.i386 linux-initramfs.x86_64 + +kfreebsd-mfsroot.i386.gz: kfreebsd-mfsroot.i386.img + gzip < $< > $@ + +bootcheck-kfreebsd-i386: kfreebsd-mfsroot.i386.gz $(GRUB_PAYLOADS_DIR)/kfreebsd.i386 $(GRUB_PAYLOADS_DIR)/kfreebsd_env.i386 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/mfsroot.gz=kfreebsd-mfsroot.i386.gz --files=/kfreebsd=$(GRUB_PAYLOADS_DIR)/kfreebsd.i386 --files=/kfreebsd_env=$(GRUB_PAYLOADS_DIR)/kfreebsd_env.i386 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +kfreebsd-mfsroot.x86_64.gz: kfreebsd-mfsroot.x86_64.img + gzip < $< > $@ + +bootcheck-kfreebsd-x86_64: kfreebsd-mfsroot.x86_64.gz $(GRUB_PAYLOADS_DIR)/kfreebsd.x86_64 $(GRUB_PAYLOADS_DIR)/kfreebsd_env.x86_64 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/mfsroot.gz=kfreebsd-mfsroot.x86_64.gz --files=/kfreebsd=$(GRUB_PAYLOADS_DIR)/kfreebsd.x86_64 --files=/kfreebsd_env=$(GRUB_PAYLOADS_DIR)/kfreebsd_env.x86_64 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +knetbsd.miniroot-image.i386.gz: knetbsd.miniroot-image.i386.img + gzip < $< > $@ + +bootcheck-knetbsd-i386: knetbsd.miniroot-image.i386.gz $(GRUB_PAYLOADS_DIR)/knetbsd.i386 $(srcdir)/grub-core/tests/boot/knetbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/miniroot.gz=knetbsd.miniroot-image.i386.gz --files=/knetbsd=$(GRUB_PAYLOADS_DIR)/knetbsd.i386 $(srcdir)/grub-core/tests/boot/knetbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kopenbsd-i386: kopenbsd.image.i386 $(GRUB_PAYLOADS_DIR)/kopenbsd.i386 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/ramdisk=kopenbsd.image.i386 --files=/kopenbsd=$(GRUB_PAYLOADS_DIR)/kopenbsd.i386 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kopenbsd-x86_64: kopenbsd.image.x86_64 $(GRUB_PAYLOADS_DIR)/kopenbsd.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/ramdisk=kopenbsd.image.x86_64 --files=/kopenbsd=$(GRUB_PAYLOADS_DIR)/kopenbsd.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +knetbsd.miniroot-image.x86_64.gz: knetbsd.miniroot-image.x86_64.img + gzip < $< > $@ + +bootcheck-knetbsd-x86_64: knetbsd.miniroot-image.x86_64.gz $(GRUB_PAYLOADS_DIR)/knetbsd.x86_64 $(srcdir)/grub-core/tests/boot/knetbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/miniroot.gz=knetbsd.miniroot-image.x86_64.gz --files=/knetbsd=$(GRUB_PAYLOADS_DIR)/knetbsd.x86_64 $(srcdir)/grub-core/tests/boot/knetbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux-i386: linux-initramfs.i386 $(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/initrd=linux-initramfs.i386 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux-x86_64: linux-initramfs.x86_64 $(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/initrd=linux-initramfs.x86_64 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux16-i386: linux-initramfs.i386 $(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/initrd=linux-initramfs.i386 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux16.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux16-x86_64: linux-initramfs.x86_64 $(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/initrd=linux-initramfs.x86_64 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux16.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-multiboot: multiboot.elf $(srcdir)/grub-core/tests/boot/multiboot.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/multiboot.elf=multiboot.elf $(srcdir)/grub-core/tests/boot/multiboot.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-multiboot2: multiboot2.elf $(srcdir)/grub-core/tests/boot/multiboot2.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/multiboot2.elf=multiboot2.elf $(srcdir)/grub-core/tests/boot/multiboot2.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kfreebsd-aout: kfreebsd.aout $(srcdir)/grub-core/tests/boot/kfreebsd-aout.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/kfreebsd.aout=kfreebsd.aout $(srcdir)/grub-core/tests/boot/kfreebsd-aout.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-pc-chainloader: pc-chainloader.bin $(srcdir)/grub-core/tests/boot/pc-chainloader.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/pc-chainloader.bin=pc-chainloader.bin $(srcdir)/grub-core/tests/boot/pc-chainloader.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-ntldr: ntldr.bin $(srcdir)/grub-core/tests/boot/ntldr.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/ntldr.bin=ntldr.bin $(srcdir)/grub-core/tests/boot/ntldr.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +BOOTCHECKS= + +if COND_i386_pc +#pc chainloader by definition is only for i386-pc +BOOTCHECKS += bootcheck-pc-chainloader +#ntldr and bootmgr require BIOS. +BOOTCHECKS += bootcheck-ntldr +#legacy protocol makes early BIOS calls. +BOOTCHECKS += bootcheck-linux16-i386 bootcheck-linux16-x86_64 +# Crashes early on non-BIOS +BOOTCHECKS += bootcheck-knetbsd-i386 +endif + +if !COND_i386_coreboot +# Crashes because memory at 0-0x1000 is occupied +BOOTCHECKS += bootcheck-knetbsd-x86_64 + +# Likewise and require ACPI. +if !COND_i386_multiboot +if !COND_i386_qemu +BOOTCHECKS += bootcheck-kfreebsd-x86_64 +BOOTCHECKS += bootcheck-kfreebsd-i386 +endif +endif +endif + +BOOTCHECKS += bootcheck-kfreebsd-aout + +BOOTCHECKS += bootcheck-kopenbsd-i386 bootcheck-kopenbsd-x86_64 + +BOOTCHECKS += bootcheck-multiboot bootcheck-multiboot2 + +BOOTCHECKS += bootcheck-linux-i386 bootcheck-linux-x86_64 + + +.PHONY: bootcheck-linux-i386 bootcheck-linux-x86_64 \ + bootcheck-kfreebsd-i386 bootcheck-kfreebsd-x86_64 \ + bootcheck-knetbsd-i386 bootcheck-knetbsd-x86_64 + +# Randomly generated +SUCCESSFUL_BOOT_STRING=3e49994fd5d82b7c9298d672d774080d +# tianocore cd access is very slow +BOOTCHECK_TIMEOUT=180 + +bootcheck: $(BOOTCHECKS) diff --git a/Makefile.util.def b/Makefile.util.def index 24cd25d9e..6b4949fd9 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -335,6 +335,7 @@ script = { enable = i386_pc; enable = x86_efi; enable = i386_qemu; + enable = i386_multiboot; enable = i386_coreboot; enable = powerpc_ieee1275; }; diff --git a/configure.ac b/configure.ac index dd2e82e3b..9fa460620 100644 --- a/configure.ac +++ b/configure.ac @@ -586,6 +586,12 @@ AC_ARG_ENABLE([efiemu], if test x"$enable_efiemu" = xno ; then efiemu_excuse="explicitly disabled" fi +if test x"$target_cpu" != xi386 ; then + efiemu_excuse="only available on i386" +fi +if test x"$platform" = xefi ; then + efiemu_excuse="not available on efi" +fi if test x"$efiemu_excuse" = x ; then AC_CACHE_CHECK([whether options required for efiemu work], grub_cv_cc_efiemu, [ CFLAGS="$CFLAGS -m64 -mcmodel=large -mno-red-zone -nostdlib" diff --git a/docs/grub.texi b/docs/grub.texi index f533a029c..4c96f254f 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -85,6 +85,7 @@ This edition documents version @value{VERSION}. * Interface:: The menu and the command-line * Commands:: The list of available builtin commands * Security:: Authentication and authorisation +* Supported kernels:: The list of supported kernels * Troubleshooting:: Error messages produced by GRUB * Invoking grub-install:: How to use the GRUB installer * Invoking grub-mkconfig:: Generate a GRUB configuration file @@ -2862,6 +2863,145 @@ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} commands. +@node Supported kernels +@chapter Supported boot targets + +X86 support is summarised in following table. ``Yes'' means that kernel works on the given platform, ``crashes'' means an early kernel crash which we hove will be fixed by concerned kernel developpers. ``no'' means GRUB doesn't load given kernel on a given platform. ``headless'' means that the kernel works but lacks console drivers (you can still use serial or network console). In case of ``no'' and ``crashes'' the reason is given in footnote. +@multitable @columnfractions .50 .22 .22 +@item @tab BIOS @tab Coreboot +@item BIOS chainloading @tab yes @tab no (1) +@item NTLDR @tab yes @tab no (1) +@item FreeBSD bootloader @tab yes @tab crashes (1) +@item 32-bit kFreeBSD @tab yes @tab crashes (2,6) +@item 64-bit kFreeBSD @tab yes @tab crashes (2,6) +@item 32-bit kNetBSD @tab yes @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab crashes (2) +@item 32-bit kOpenBSD @tab yes @tab yes +@item 64-bit kOpenBSD @tab yes @tab yes +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab yes @tab no (1) +@item 64-bit Linux (legacy protocol) @tab yes @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab yes @tab ? +@item 64-bit XNU @tab yes @tab ? +@item 32-bit EFI chainloader @tab no (3) @tab no (3) +@item 64-bit EFI chainloader @tab no (3) @tab no (3) +@item Appleloader @tab no (3) @tab no (3) +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab Multiboot @tab Qemu +@item BIOS chainloading @tab no (1) @tab no (1) +@item NTLDR @tab no (1) @tab no (1) +@item FreeBSD bootloader @tab crashes (1) @tab crashes (1) +@item 32-bit kFreeBSD @tab crashes (6) @tab crashes (6) +@item 64-bit kFreeBSD @tab crashes (6) @tab crashes (6) +@item 32-bit kNetBSD @tab crashes (1) @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab yes +@item 32-bit kOpenBSD @tab yes @tab yes +@item 64-bit kOpenBSD @tab yes @tab yes +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab ? @tab ? +@item 64-bit XNU @tab ? @tab ? +@item 32-bit EFI chainloader @tab no (3) @tab no (3) +@item 64-bit EFI chainloader @tab no (3) @tab no (3) +@item Appleloader @tab no (3) @tab no (3) +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab 32-bit EFI @tab 64-bit EFI +@item BIOS chainloading @tab no (1) @tab no (1) +@item NTLDR @tab no (1) @tab no (1) +@item FreeBSD bootloader @tab crashes (1) @tab crashes (1) +@item 32-bit kFreeBSD @tab headless @tab headless +@item 64-bit kFreeBSD @tab headless @tab headless +@item 32-bit kNetBSD @tab crashes (1) @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab yes +@item 32-bit kOpenBSD @tab headless @tab headless +@item 64-bit kOpenBSD @tab headless @tab headless +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab yes @tab yes +@item 64-bit XNU @tab yes (5) @tab yes +@item 32-bit EFI chainloader @tab yes @tab no (4) +@item 64-bit EFI chainloader @tab no (4) @tab yes +@item Appleloader @tab yes @tab yes +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab IEEE1275 +@item BIOS chainloading @tab no (1) +@item NTLDR @tab no (1) +@item FreeBSD bootloader @tab crashes (1) +@item 32-bit kFreeBSD @tab crashes (6) +@item 64-bit kFreeBSD @tab crashes (6) +@item 32-bit kNetBSD @tab crashes (1) +@item 64-bit kNetBSD @tab ? +@item 32-bit kOpenBSD @tab ? +@item 64-bit kOpenBSD @tab ? +@item Multiboot @tab ? +@item Multiboot2 @tab ? +@item 32-bit Linux (legacy protocol) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) +@item 32-bit Linux (modern protocol) @tab ? +@item 64-bit Linux (modern protocol) @tab ? +@item 32-bit XNU @tab ? +@item 64-bit XNU @tab ? +@item 32-bit EFI chainloader @tab no (3) +@item 64-bit EFI chainloader @tab no (3) +@item Appleloader @tab no (3) +@end multitable + +@enumerate +@item Requires BIOS +@item Crashes because the memory at 0x0-0x1000 isn't available +@item EFI only +@item 32-bit and 64-bit EFI have different structures and work in different CPU modes so it's not possible to chainload 32-bit bootloader on 64-bit platform and vice-versa +@item Some modules may need to be disabled +@item Requires ACPI +@end enumerate + +PowerPC and Sparc ports support only Linux. MIPS port supports Linux and multiboot2. + +@chapter Boot tests + +As you have seen in previous chapter the support matrix is pretty big and some of the configurations are only rarely used. To ensure the quality bootchecks are available for all x86 targets except EFI chainloader, Appleloader and XNU. All x86 platforms have bootcheck facility except ieee1275. Multiboot, multiboot2, BIOS chainloader, ntldr and freebsd-bootloader boot targets are tested only with a fake kernel images. Only Linux is tested among the payloads using Linux protocols. + +Following variables must be defined: + +@multitable @columnfractions .30 .65 +@item GRUB_PAYLOADS_DIR @tab directory containing the required kernels +@item GRUB_CBFSTOOL @tab cbfstoll from Coreboot package (for coreboot platform only) +@item GRUB_COREBOOT_ROM @tab empty Coreboot ROM +@item GRUB_QEMU_OPTS @tab additional options to be supplied to QEMU +@end multitable + +Required files are: + +@multitable @columnfractions .40 .55 +@item kfreebsd_env.i386 @tab 32-bit kFreeBSD device hints +@item kfreebsd.i386 @tab 32-bit FreeBSD kernel image +@item kfreebsd.x86_64, kfreebsd_env.x86_64 @tab same from 64-bit kFreeBSD +@item knetbsd.i386 @tab 32-bit NetBSD kernel image +@item knetbsd.miniroot.i386 @tab 32-bit kNetBSD miniroot.kmod. +@item knetbsd.x86_64, knetbsd.miniroot.x86_64 @tab same from 64-bit kNetBSD +@item kopenbsd.i386 @tab 32-bit OpenBSD kernel bsd.rd image +@item kopenbsd.x86_64 @tab same from 64-bit kOpenBSD +@item linux.i386 @tab 32-bit Linux +@item linux.x86_64 @tab 64-bit Linux +@end multitable + @node Troubleshooting @chapter Error messages produced by GRUB diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 773803544..61a0bb35a 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -78,11 +78,12 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/symbol.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/types.h - -if COND_i386_pc +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h + +if COND_i386_pc KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/biosdisk.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h @@ -96,9 +97,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_efi -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h @@ -106,63 +104,46 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_coreboot -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_multiboot -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_qemu -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_ieee1275 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h endif if COND_x86_64_efi -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_mips_yeeloong -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h @@ -180,17 +161,11 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h endif if COND_powerpc_ieee1275 -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h endif if COND_sparc64_ieee1275 -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h @@ -312,7 +287,6 @@ moddep.lst: kernel_syms.lst genmoddep.awk $(DEF_FILES) $(UND_FILES) | $(AWK) -f $(srcdir)/genmoddep.awk $(UND_FILES) > $@ \ || (rm -f $@; exit 1) -if COND_i386_pc if COND_ENABLE_EFIEMU efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF) -rm -f $@; \ @@ -355,5 +329,3 @@ efiemu64.o: efiemu64_c.o efiemu64_s.o $(TARGET_OBJ2ELEF) platform_DATA += efiemu32.o efiemu64.o CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_s.o endif -endif - diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 5961e8697..74fd1d3ac 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -166,7 +166,6 @@ kernel = { emu = kern/emu/mm.c; emu = kern/emu/time.c; - extra_dist = kern/i386/loader.S; extra_dist = kern/i386/realmode.S; extra_dist = kern/i386/pc/lzma_decode.S; extra_dist = kern/mips/cache_flush.S; @@ -362,6 +361,7 @@ module = { enable = x86_efi; enable = i386_ieee1275; enable = i386_coreboot; + enable = i386_multiboot; emu_condition = COND_GRUB_EMU_PCI; }; @@ -405,9 +405,13 @@ module = { i386 = commands/acpi.c; x86_efi = commands/efi/acpi.c; i386_pc = commands/i386/pc/acpi.c; + i386_coreboot = commands/i386/pc/acpi.c; + i386_multiboot = commands/i386/pc/acpi.c; enable = x86_efi; enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { @@ -766,19 +770,23 @@ module = { module = { name = efiemu; - i386_pc = efiemu/main.c; - i386_pc = efiemu/i386/loadcore32.c; - i386_pc = efiemu/i386/loadcore64.c; + common = efiemu/main.c; + common = efiemu/i386/loadcore32.c; + common = efiemu/i386/loadcore64.c; i386_pc = efiemu/i386/pc/cfgtables.c; - i386_pc = efiemu/mm.c; - i386_pc = efiemu/loadcore_common.c; - i386_pc = efiemu/symbols.c; - i386_pc = efiemu/loadcore32.c; - i386_pc = efiemu/loadcore64.c; - i386_pc = efiemu/prepare32.c; - i386_pc = efiemu/prepare64.c; - i386_pc = efiemu/pnvram.c; - i386_pc = efiemu/i386/coredetect.c; + i386_coreboot = efiemu/i386/pc/cfgtables.c; + i386_multiboot = efiemu/i386/pc/cfgtables.c; + i386_ieee1275 = efiemu/i386/nocfgtables.c; + i386_qemu = efiemu/i386/nocfgtables.c; + common = efiemu/mm.c; + common = efiemu/loadcore_common.c; + common = efiemu/symbols.c; + common = efiemu/loadcore32.c; + common = efiemu/loadcore64.c; + common = efiemu/prepare32.c; + common = efiemu/prepare64.c; + common = efiemu/pnvram.c; + common = efiemu/i386/coredetect.c; extra_dist = efiemu/prepare.c; extra_dist = efiemu/loadcore.c; @@ -786,6 +794,10 @@ module = { extra_dist = efiemu/runtime/efiemu.c; enable = i386_pc; + enable = i386_coreboot; + enable = i386_ieee1275; + enable = i386_multiboot; + enable = i386_qemu; }; module = { @@ -988,13 +1000,22 @@ module = { module = { name = relocator; - mips = lib/mips/relocator.c; - mips = lib/mips/relocator_asm.S; + common = lib/relocator.c; + x86 = lib/i386/relocator16.S; + x86 = lib/i386/relocator32.S; + x86 = lib/i386/relocator64.S; + i386 = lib/i386/relocator_asm.S; + x86_64 = lib/x86_64/relocator_asm.S; x86 = lib/i386/relocator.c; - x86 = lib/i386/relocator_asm.S; - x86 = lib/i386/relocator_backward.S; - extra_dist = lib/relocator.c; + ieee1275 = lib/ieee1275/relocator.c; + x86_efi = lib/efi/relocator.c; + mips = lib/mips/relocator_asm.S; + mips = lib/mips/relocator.c; + powerpc = lib/powerpc/relocator_asm.S; + powerpc = lib/powerpc/relocator.c; + enable = mips; + enable = powerpc; enable = x86; }; @@ -1023,28 +1044,19 @@ module = { module = { name = aout; common = loader/aout.c; - enable = i386_pc; - enable = i386_qemu; - enable = i386_coreboot; - enable = i386_multiboot; - enable = i386_ieee1275; + enable = x86; }; module = { name = bsd; - i386 = loader/i386/bsd.c; - i386 = loader/i386/bsd32.c; - i386 = loader/i386/bsd64.c; - i386 = loader/i386/bsd_helper.S; - i386 = loader/i386/bsd_trampoline.S; + x86 = loader/i386/bsd.c; + x86 = loader/i386/bsd32.c; + x86 = loader/i386/bsd64.c; extra_dist = loader/i386/bsdXX.c; extra_dist = loader/i386/bsd_pagetable.c; - enable = i386_pc; - enable = i386_qemu; - enable = i386_coreboot; - enable = i386_multiboot; + enable = x86; }; module = { @@ -1053,6 +1065,12 @@ module = { enable = i386_pc; }; +module = { + name = ntldr; + i386_pc = loader/i386/pc/ntldr.c; + enable = i386_pc; +}; + module = { name = multiboot2; cppflags = "-DGRUB_USE_MULTIBOOT2"; @@ -1073,11 +1091,7 @@ module = { module = { name = linux; - i386_noefi_noieee1275 = loader/i386/linux.c; - - x86_efi = loader/i386/efi/linux.c; - x86_64_efi = loader/i386/linux_trampoline.S; - i386_ieee1275 = loader/i386/ieee1275/linux.c; + x86 = loader/i386/linux.c; mips = loader/mips/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; @@ -1086,16 +1100,15 @@ module = { module = { name = xnu; - x86_efi_pc = loader/xnu_resume.c; - x86_efi_pc = loader/i386/xnu.c; - x86_efi_pc = loader/macho32.c; - x86_efi_pc = loader/macho64.c; - x86_efi_pc = loader/macho.c; - x86_efi_pc = loader/xnu.c; + x86 = loader/xnu_resume.c; + x86 = loader/i386/xnu.c; + x86 = loader/macho32.c; + x86 = loader/macho64.c; + x86 = loader/macho.c; + x86 = loader/xnu.c; extra_dist = loader/machoXX.c; - enable = i386_pc; - enable = x86_efi; + enable = x86; }; module = { @@ -1285,9 +1298,11 @@ module = { module = { name = vga_text; - x86 = term/i386/pc/vga_text.c; - x86 = term/i386/vga_common.c; - enable = x86; + common = term/i386/pc/vga_text.c; + common = term/i386/vga_common.c; + enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { diff --git a/grub-core/efiemu/i386/coredetect.c b/grub-core/efiemu/i386/coredetect.c index 828508dee..975c4aa5d 100644 --- a/grub-core/efiemu/i386/coredetect.c +++ b/grub-core/efiemu/i386/coredetect.c @@ -17,7 +17,6 @@ */ #include -#include #include #define cpuid(num,a,b,c,d) \ diff --git a/include/grub/i386/pc/efiemu.h b/grub-core/efiemu/i386/nocfgtables.c similarity index 75% rename from include/grub/i386/pc/efiemu.h rename to grub-core/efiemu/i386/nocfgtables.c index f269dd085..775f1d03a 100644 --- a/include/grub/i386/pc/efiemu.h +++ b/grub-core/efiemu/i386/nocfgtables.c @@ -1,3 +1,4 @@ +/* Register SMBIOS and ACPI tables. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. @@ -16,9 +17,14 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_EFI_EMU_HEADER -#define GRUB_MACHINE_EFI_EMU_HEADER 1 +#include +#include +#include +#include +#include -grub_err_t grub_machine_efiemu_init_tables (void); - -#endif +grub_err_t +grub_machine_efiemu_init_tables (void) +{ + return GRUB_ERR_NONE; +} diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c index 9c6b4e55e..9287d3a94 100644 --- a/grub-core/efiemu/i386/pc/cfgtables.c +++ b/grub-core/efiemu/i386/pc/cfgtables.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/grub-core/efiemu/loadcore.c b/grub-core/efiemu/loadcore.c index 4bf26ee44..edadd4580 100644 --- a/grub-core/efiemu/loadcore.c +++ b/grub-core/efiemu/loadcore.c @@ -22,7 +22,6 @@ #include #include #include -#include #include /* ELF symbols and their values */ diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c index b197a8b2c..ee78afe7d 100644 --- a/grub-core/efiemu/main.c +++ b/grub-core/efiemu/main.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -183,22 +182,6 @@ grub_cmd_efiemu_prepare (grub_command_t cmd __attribute__ ((unused)), - -int -grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key - __attribute__ ((unused))) -{ - /* Nothing to do here yet */ - return 1; -} - -int -grub_efiemu_finish_boot_services (void) -{ - /* Nothing to do here yet */ - return 1; -} - /* Load the runtime from the file FILENAME. */ static grub_err_t grub_efiemu_load_file (const char *filename) diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c index 4b293606f..de7d309be 100644 --- a/grub-core/efiemu/mm.c +++ b/grub-core/efiemu/mm.c @@ -323,6 +323,25 @@ grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, return 1; } +grub_err_t +grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version) +{ + int val = grub_efiemu_get_memory_map (memory_map_size, + memory_map, map_key, + descriptor_size, + descriptor_version); + if (val == 1) + return GRUB_ERR_NONE; + if (val == -1) + return grub_errno; + return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); +} + + /* Free everything */ grub_err_t grub_efiemu_mm_unload (void) diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 09849f174..02d785b9b 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -682,20 +682,3 @@ grub_dl_unload_unneeded (void) p = p->next; } } - -/* Unload all modules. */ -void -grub_dl_unload_all (void) -{ - while (grub_dl_head) - { - grub_dl_t p; - - grub_dl_unload_unneeded (); - - /* Force to decrement the ref count. This will purge pre-loaded - modules and manually inserted modules. */ - for (p = grub_dl_head; p; p = p->next) - p->ref_count--; - } -} diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index 126e40901..e80bc1f19 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -183,17 +183,6 @@ grub_halt (void) for (;;) ; } -int -grub_efi_exit_boot_services (grub_efi_uintn_t map_key) -{ - grub_efi_boot_services_t *b; - grub_efi_status_t status; - - b = grub_efi_system_table->boot_services; - status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key); - return status == GRUB_EFI_SUCCESS; -} - grub_err_t grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, grub_efi_uintn_t descriptor_size, @@ -760,26 +749,3 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) dp = (grub_efi_device_path_t *) ((char *) dp + len); } } - -int -grub_efi_finish_boot_services (void) -{ - grub_efi_uintn_t mmap_size = 0; - grub_efi_uintn_t map_key; - grub_efi_uintn_t desc_size; - grub_efi_uint32_t desc_version; - void *mmap_buf = 0; - - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) < 0) - return 0; - - mmap_buf = grub_malloc (mmap_size); - - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) - return 0; - - return grub_efi_exit_boot_services (map_key); -} - diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 2abd6325d..c845d7df1 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -49,6 +49,12 @@ static struct allocated_page *allocated_pages = 0; #define MIN_HEAP_SIZE 0x100000 #define MAX_HEAP_SIZE (1600 * 0x100000) +static void *finish_mmap_buf = 0; +static grub_efi_uintn_t finish_mmap_size = 0; +static grub_efi_uintn_t finish_key = 0; +static grub_efi_uintn_t finish_desc_size; +static grub_efi_uint32_t finish_desc_version; +int grub_efi_is_finished = 0; /* Allocate pages. Return the pointer to the first of allocated pages. */ void * @@ -140,6 +146,51 @@ grub_efi_free_pages (grub_efi_physical_address_t address, efi_call_2 (b->free_pages, address, pages); } +grub_err_t +grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) < 0) + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + + if (outbuf && *outbuf_size < finish_mmap_size) + return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); + + finish_mmap_buf = grub_malloc (finish_mmap_size); + if (!finish_mmap_buf) + return grub_errno; + + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) <= 0) + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + + b = grub_efi_system_table->boot_services; + status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, + finish_key); + if (status != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services"); + + grub_efi_is_finished = 1; + if (outbuf_size) + *outbuf_size = finish_mmap_size; + if (outbuf) + grub_memcpy (outbuf, finish_mmap_buf, finish_mmap_size); + if (map_key) + *map_key = finish_key; + if (efi_desc_size) + *efi_desc_size = finish_desc_size; + if (efi_desc_version) + *efi_desc_version = finish_desc_version; + + 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 @@ -154,6 +205,29 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t key; grub_efi_uint32_t version; + if (grub_efi_is_finished) + { + int ret = 1; + if (*memory_map_size < finish_mmap_size) + { + grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); + ret = 0; + } + else + { + grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); + ret = 1; + } + *memory_map_size = finish_mmap_size; + if (map_key) + *map_key = finish_key; + if (descriptor_size) + *descriptor_size = finish_desc_size; + if (descriptor_version) + *descriptor_version = finish_desc_version; + return ret; + } + /* Allow some parameters to be missing. */ if (! map_key) map_key = &key; diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index d9948a822..875a855ea 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -140,7 +140,7 @@ grub_elf32_load_phdrs (grub_elf_t elf) return GRUB_ERR_NONE; } -static grub_err_t +grub_err_t grub_elf32_phdr_iterate (grub_elf_t elf, int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf32_Phdr *, void *), void *hook_arg) @@ -326,7 +326,7 @@ grub_elf64_load_phdrs (grub_elf_t elf) return GRUB_ERR_NONE; } -static grub_err_t +grub_err_t grub_elf64_phdr_iterate (grub_elf_t elf, int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf64_Phdr *, void *), void *hook_arg) diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c index 0afbfd3af..7ee809c79 100644 --- a/grub-core/kern/i386/coreboot/init.c +++ b/grub-core/kern/i386/coreboot/init.c @@ -42,9 +42,6 @@ extern char _start[]; extern char _end[]; -grub_addr_t grub_os_area_addr; -grub_size_t grub_os_area_size; - grub_uint32_t grub_get_rtc (void) { @@ -103,20 +100,7 @@ grub_machine_init (void) } } - if (addr == GRUB_MEMORY_MACHINE_UPPER_START - || (addr >= GRUB_MEMORY_MACHINE_LOWER_SIZE - && addr <= GRUB_MEMORY_MACHINE_UPPER_START - && (addr + size > GRUB_MEMORY_MACHINE_UPPER_START))) - { - grub_size_t quarter = size >> 2; - - grub_os_area_addr = addr; - grub_os_area_size = size - quarter; - grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size), - quarter); - } - else - grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size); + grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size); return 0; } diff --git a/grub-core/kern/i386/coreboot/startup.S b/grub-core/kern/i386/coreboot/startup.S index bcc0d14ab..ec3a0e64b 100644 --- a/grub-core/kern/i386/coreboot/startup.S +++ b/grub-core/kern/i386/coreboot/startup.S @@ -85,7 +85,3 @@ codestart: */ #include "../realmode.S" -/* - * Routines needed by Linux and Multiboot loaders. - */ -#include "../loader.S" diff --git a/grub-core/kern/i386/ieee1275/startup.S b/grub-core/kern/i386/ieee1275/startup.S index c0a08a954..2a04753df 100644 --- a/grub-core/kern/i386/ieee1275/startup.S +++ b/grub-core/kern/i386/ieee1275/startup.S @@ -63,7 +63,3 @@ codestart: */ #include "../realmode.S" -/* - * Routines needed by Linux and Multiboot loaders. - */ -#include "../loader.S" diff --git a/grub-core/kern/i386/loader.S b/grub-core/kern/i386/loader.S deleted file mode 100644 index ed57c43ca..000000000 --- a/grub-core/kern/i386/loader.S +++ /dev/null @@ -1,120 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 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 . - */ - - -/* - * Note: These functions defined in this file may be called from C. - * Be careful of that you must not modify some registers. Quote - * from gcc-2.95.2/gcc/config/i386/i386.h: - - 1 for registers not available across function calls. - These must include the FIXED_REGISTERS and also any - registers that can be used without being saved. - The latter must include the registers where values are returned - and the register where structure-value addresses are passed. - Aside from that, you can include as many other registers as you like. - - ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg -{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } - */ - -/* - * Note: GRUB is compiled with the options -mrtd and -mregparm=3. - * So the first three arguments are passed in %eax, %edx, and %ecx, - * respectively, and if a function has a fixed number of arguments - * and the number if greater than three, the function must return - * with "ret $N" where N is ((the number of arguments) - 3) * 4. - */ - -/* - * This is the area for all of the special variables. - */ - - .p2align 2 /* force 4-byte alignment */ - -/* - * void grub_linux_boot_zimage (void) - */ -VARIABLE(grub_linux_prot_size) - .long 0 -VARIABLE(grub_linux_tmp_addr) - .long 0 -VARIABLE(grub_linux_real_addr) - .long 0 -VARIABLE(grub_linux_is_bzimage) - .long 0 - -FUNCTION(grub_linux16_real_boot) - /* Must be done before zImage copy. */ - call EXT_C(grub_dl_unload_all) - - movl EXT_C(grub_linux_is_bzimage), %ebx - test %ebx, %ebx - jne bzimage - - /* copy the kernel */ - movl EXT_C(grub_linux_prot_size), %ecx - addl $3, %ecx - shrl $2, %ecx - movl $GRUB_LINUX_BZIMAGE_ADDR, %esi - movl $GRUB_LINUX_ZIMAGE_ADDR, %edi - cld - rep - movsl - -bzimage: - movl EXT_C(grub_linux_real_addr), %ebx - - /* copy the real mode code */ - movl EXT_C(grub_linux_tmp_addr), %esi - movl %ebx, %edi - movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx - cld - rep - movsb - - /* change %ebx to the segment address */ - shrl $4, %ebx - movl %ebx, %eax - addl $0x20, %eax - movw %ax, linux_setup_seg - - /* XXX new stack pointer in safe area for calling functions */ - movl $0x4000, %esp - call EXT_C(grub_stop_floppy) - - /* final setup for linux boot */ - call prot_to_real - .code16 - - cli - movw %bx, %ss - movw $GRUB_LINUX_SETUP_STACK, %sp - - movw %bx, %ds - movw %bx, %es - movw %bx, %fs - movw %bx, %gs - - /* ljmp */ - .byte 0xea - .word 0 -linux_setup_seg: - .word 0 - .code32 - diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index 8cbc757b2..3e8819464 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -44,9 +44,6 @@ struct mem_region static struct mem_region mem_regions[MAX_REGIONS]; static int num_regions; -grub_addr_t grub_os_area_addr; -grub_size_t grub_os_area_size; - static char * make_install_device (void) { @@ -203,25 +200,9 @@ grub_machine_init (void) compact_mem_regions (); - /* Add the memory regions to free memory, except for the region starting - from 1MB. This region is partially used for loading OS images. - For now, 1/4 of this is added to free memory. */ for (i = 0; i < num_regions; i++) - if (mem_regions[i].addr == 0x100000) - { - grub_size_t quarter = mem_regions[i].size >> 2; - - grub_os_area_addr = mem_regions[i].addr; - grub_os_area_size = mem_regions[i].size - quarter; - grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size), - quarter); - } - else grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size); - if (! grub_os_area_addr) - grub_fatal ("no upper memory"); - grub_tsc_init (); } diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 761eb53fe..7ae901712 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -546,8 +546,6 @@ FUNCTION(grub_chainloader_real_boot) pushl %edx pushl %eax - call EXT_C(grub_dl_unload_all) - /* Turn off Gate A20 */ xorl %eax, %eax call EXT_C(grub_gate_a20) @@ -563,8 +561,6 @@ FUNCTION(grub_chainloader_real_boot) ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR .code32 -#include "../loader.S" - /* * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) * diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c index f2a998e78..0242da1ca 100644 --- a/grub-core/kern/i386/qemu/mmap.c +++ b/grub-core/kern/i386/qemu/mmap.c @@ -68,6 +68,11 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin GRUB_MACHINE_MEMORY_AVAILABLE)) return 1; + if (hook ((grub_addr_t) _end, + 0xa0000 - (grub_addr_t) _end, + GRUB_MACHINE_MEMORY_AVAILABLE)) + return 1; + if (hook (GRUB_MEMORY_MACHINE_UPPER, 0x100000 - GRUB_MEMORY_MACHINE_UPPER, GRUB_MACHINE_MEMORY_RESERVED)) diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 47324a662..8d9b5db78 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -65,6 +65,7 @@ #include #include #include +#include #ifdef MM_DEBUG # undef grub_malloc @@ -74,45 +75,9 @@ # undef grub_memalign #endif -/* Magic words. */ -#define GRUB_MM_FREE_MAGIC 0x2d3c2808 -#define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 - -typedef struct grub_mm_header -{ - struct grub_mm_header *next; - grub_size_t size; - grub_size_t magic; -#if GRUB_CPU_SIZEOF_VOID_P == 4 - char padding[4]; -#elif GRUB_CPU_SIZEOF_VOID_P == 8 - char padding[8]; -#else -# error "unknown word size" -#endif -} -*grub_mm_header_t; - -#if GRUB_CPU_SIZEOF_VOID_P == 4 -# define GRUB_MM_ALIGN_LOG2 4 -#elif GRUB_CPU_SIZEOF_VOID_P == 8 -# define GRUB_MM_ALIGN_LOG2 5 -#endif - -#define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) - -typedef struct grub_mm_region -{ - struct grub_mm_header *first; - struct grub_mm_region *next; - grub_addr_t addr; - grub_size_t size; -} -*grub_mm_region_t; - -static grub_mm_region_t base; +grub_mm_region_t grub_mm_base; /* Get a header from the pointer PTR, and set *P and *R to a pointer to the header and a pointer to its region, respectively. PTR must @@ -123,9 +88,9 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) if ((grub_addr_t) ptr & (GRUB_MM_ALIGN - 1)) grub_fatal ("unaligned pointer %p", ptr); - for (*r = base; *r; *r = (*r)->next) - if ((grub_addr_t) ptr > (*r)->addr - && (grub_addr_t) ptr <= (*r)->addr + (*r)->size) + for (*r = grub_mm_base; *r; *r = (*r)->next) + if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1) + && (grub_addr_t) ptr <= (grub_addr_t) ((*r) + 1) + (*r)->size) break; if (! *r) @@ -156,18 +121,18 @@ grub_mm_init_region (void *addr, grub_size_t size) if (size < GRUB_MM_ALIGN) return; - h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN); + h = (grub_mm_header_t) (r + 1); h->next = h; h->magic = GRUB_MM_FREE_MAGIC; h->size = (size >> GRUB_MM_ALIGN_LOG2); r->first = h; - r->addr = (grub_addr_t) h; + r->pre_size = (grub_addr_t) r - (grub_addr_t) addr; r->size = (h->size << GRUB_MM_ALIGN_LOG2); /* Find where to insert this region. Put a smaller one before bigger ones, to prevent fragmentation. */ - for (p = &base, q = *p; q; p = &(q->next), q = *p) + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) if (q->size > r->size) break; @@ -206,6 +171,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) if (p->size >= n + extra) { + extra += (p->size - extra - n) & (~(align - 1)); if (extra == 0 && p->size == n) { /* There is no special alignment requirement and memory block @@ -284,10 +250,10 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) r = p + extra + n; r->magic = GRUB_MM_FREE_MAGIC; r->size = p->size - extra - n; - r->next = p->next; + r->next = p; p->size = extra; - p->next = r; + q->next = r; p += extra; } @@ -318,13 +284,16 @@ grub_memalign (grub_size_t align, grub_size_t size) grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; int count = 0; + if (!grub_mm_base) + goto fail; + align = (align >> GRUB_MM_ALIGN_LOG2); if (align == 0) align = 1; again: - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { void *p; @@ -352,6 +321,7 @@ grub_memalign (grub_size_t align, grub_size_t size) break; } + fail: grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); return 0; } @@ -485,7 +455,7 @@ grub_mm_dump_free (void) { grub_mm_region_t r; - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { grub_mm_header_t p; @@ -512,13 +482,13 @@ grub_mm_dump (unsigned lineno) grub_mm_region_t r; grub_printf ("called at line %u\n", lineno); - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { grub_mm_header_t p; - for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1) - & (~(GRUB_MM_ALIGN - 1))); - (grub_addr_t) p < r->addr + r->size; + for (p = (grub_mm_header_t) ALIGN_UP ((grub_addr_t) (r + 1), + GRUB_MM_ALIGN); + (grub_addr_t) p < (grub_addr_t) (r+1) + r->size; p++) { switch (p->magic) diff --git a/grub-core/kern/powerpc/cache.S b/grub-core/kern/powerpc/cache.S index da982afa0..d85e68d42 100644 --- a/grub-core/kern/powerpc/cache.S +++ b/grub-core/kern/powerpc/cache.S @@ -1,7 +1,7 @@ /* cache.S - Flush the processor cache for a specific region. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2007 Free Software Foundation, Inc. + * Copyright (C) 2004,2007,2010 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 @@ -17,32 +17,10 @@ * along with GRUB. If not, see . */ -#define CACHE_LINE_BYTES 32 - .text .align 2 .globl grub_arch_sync_caches grub_arch_sync_caches: - /* `address' may not be CACHE_LINE_BYTES-aligned. */ - andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */ - add 4, 4, 6 /* Adjust `size' to compensate. */ - - /* Force the dcache lines to memory. */ - li 5, 0 -1: dcbst 5, 3 - addi 5, 5, CACHE_LINE_BYTES - cmpw 5, 4 - blt 1b - sync /* Force all dcbsts to complete. */ - - /* Invalidate the icache lines. */ - li 5, 0 -1: icbi 5, 3 - addi 5, 5, CACHE_LINE_BYTES - cmpw 5, 4 - blt 1b - sync /* Force all icbis to complete. */ - isync /* Discard partially executed instructions that were - loaded from the invalid icache. */ +#include "cache_flush.S" blr diff --git a/grub-core/kern/powerpc/cache_flush.S b/grub-core/kern/powerpc/cache_flush.S new file mode 100644 index 000000000..1410f78b1 --- /dev/null +++ b/grub-core/kern/powerpc/cache_flush.S @@ -0,0 +1,43 @@ +/* cache.S - Flush the processor cache for a specific region. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2007,2010 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 . + */ + +#undef CACHE_LINE_BYTES +#define CACHE_LINE_BYTES 32 + + /* `address' may not be CACHE_LINE_BYTES-aligned. */ + andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */ + add 4, 4, 6 /* Adjust `size' to compensate. */ + + /* Force the dcache lines to memory. */ + li 5, 0 +1: dcbst 5, 3 + addi 5, 5, CACHE_LINE_BYTES + cmpw 5, 4 + blt 1b + sync /* Force all dcbsts to complete. */ + + /* Invalidate the icache lines. */ + li 5, 0 +1: icbi 5, 3 + addi 5, 5, CACHE_LINE_BYTES + cmpw 5, 4 + blt 1b + sync /* Force all icbis to complete. */ + isync /* Discard partially executed instructions that were + loaded from the invalid icache. */ diff --git a/grub-core/lib/efi/relocator.c b/grub-core/lib/efi/relocator.c new file mode 100644 index 000000000..fc4de834b --- /dev/null +++ b/grub-core/lib/efi/relocator.c @@ -0,0 +1,104 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +unsigned +grub_relocator_firmware_get_max_events (void) +{ + grub_efi_uintn_t mmapsize = 0, descriptor_size = 0; + grub_efi_uint32_t descriptor_version = 0; + grub_efi_uintn_t key; + grub_efi_get_memory_map (&mmapsize, NULL, &key, &descriptor_size, + &descriptor_version); + /* Since grub_relocator_firmware_fill_events uses malloc + we need some reserve. Hence +10. */ + return 2 * (mmapsize / descriptor_size + 10); +} + +unsigned +grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) +{ + grub_efi_uintn_t mmapsize = 0, desc_size = 0; + grub_efi_uint32_t descriptor_version = 0; + grub_efi_memory_descriptor_t *descs = NULL; + grub_efi_uintn_t key; + int counter = 0; + grub_efi_memory_descriptor_t *desc; + + grub_efi_get_memory_map (&mmapsize, NULL, &key, &desc_size, + &descriptor_version); + descs = grub_malloc (mmapsize); + if (!descs) + return 0; + + grub_efi_get_memory_map (&mmapsize, descs, &key, &desc_size, + &descriptor_version); + + for (desc = descs; + (char *) desc < ((char *) descs + mmapsize); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + events[counter].type = REG_FIRMWARE_START; + events[counter].pos = desc->physical_start; + counter++; + events[counter].type = REG_FIRMWARE_END; + events[counter].pos = desc->physical_start + (desc->num_pages << 12); + counter++; + } + + return counter; +} + +int +grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size) +{ + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = start; + grub_efi_status_t status; + + if (grub_efi_is_finished) + return 1; + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_DATA, size >> 12, &address); + return (status == GRUB_EFI_SUCCESS); +} + +void +grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size) +{ + grub_efi_boot_services_t *b; + + if (grub_efi_is_finished) + return; + + b = grub_efi_system_table->boot_services; + efi_call_2 (b->free_pages, start, size >> 12); +} diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c index 453f73fdd..f06a6ef86 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -19,84 +19,248 @@ #include #include -#include #include #include +#include #include +#include -extern grub_uint8_t grub_relocator32_forward_start; -extern grub_uint8_t grub_relocator32_forward_end; -extern grub_uint8_t grub_relocator32_backward_start; -extern grub_uint8_t grub_relocator32_backward_end; +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; -extern grub_uint32_t grub_relocator32_backward_dest; -extern grub_uint32_t grub_relocator32_backward_size; -extern grub_addr_t grub_relocator32_backward_src; +extern void *grub_relocator_backward_dest; +extern void *grub_relocator_backward_src; +extern grub_size_t grub_relocator_backward_chunk_size; -extern grub_uint32_t grub_relocator32_forward_dest; -extern grub_uint32_t grub_relocator32_forward_size; -extern grub_addr_t grub_relocator32_forward_src; +extern void *grub_relocator_forward_dest; +extern void *grub_relocator_forward_src; +extern grub_size_t grub_relocator_forward_chunk_size; -extern grub_uint32_t grub_relocator32_forward_eax; -extern grub_uint32_t grub_relocator32_forward_ebx; -extern grub_uint32_t grub_relocator32_forward_ecx; -extern grub_uint32_t grub_relocator32_forward_edx; -extern grub_uint32_t grub_relocator32_forward_eip; -extern grub_uint32_t grub_relocator32_forward_esp; +extern grub_uint8_t grub_relocator16_start; +extern grub_uint8_t grub_relocator16_end; +extern grub_uint16_t grub_relocator16_cs; +extern grub_uint16_t grub_relocator16_ip; +extern grub_uint16_t grub_relocator16_ds; +extern grub_uint16_t grub_relocator16_es; +extern grub_uint16_t grub_relocator16_fs; +extern grub_uint16_t grub_relocator16_gs; +extern grub_uint16_t grub_relocator16_ss; +extern grub_uint16_t grub_relocator16_sp; +extern grub_uint32_t grub_relocator16_edx; -extern grub_uint32_t grub_relocator32_backward_eax; -extern grub_uint32_t grub_relocator32_backward_ebx; -extern grub_uint32_t grub_relocator32_backward_ecx; -extern grub_uint32_t grub_relocator32_backward_edx; -extern grub_uint32_t grub_relocator32_backward_eip; -extern grub_uint32_t grub_relocator32_backward_esp; +extern grub_uint8_t grub_relocator32_start; +extern grub_uint8_t grub_relocator32_end; +extern grub_uint32_t grub_relocator32_eax; +extern grub_uint32_t grub_relocator32_ebx; +extern grub_uint32_t grub_relocator32_ecx; +extern grub_uint32_t grub_relocator32_edx; +extern grub_uint32_t grub_relocator32_eip; +extern grub_uint32_t grub_relocator32_esp; +extern grub_uint32_t grub_relocator32_esi; -#define RELOCATOR_SIZEOF(x) (&grub_relocator32_##x##_end - &grub_relocator32_##x##_start) -#define RELOCATOR_ALIGN 16 -#define PREFIX(x) grub_relocator32_ ## x +extern grub_uint8_t grub_relocator64_start; +extern grub_uint8_t grub_relocator64_end; +extern grub_uint64_t grub_relocator64_rax; +extern grub_uint64_t grub_relocator64_rbx; +extern grub_uint64_t grub_relocator64_rcx; +extern grub_uint64_t grub_relocator64_rdx; +extern grub_uint64_t grub_relocator64_rip; +extern grub_uint64_t grub_relocator64_rip_addr; +extern grub_uint64_t grub_relocator64_rsp; +extern grub_uint64_t grub_relocator64_rsi; +extern grub_addr_t grub_relocator64_cr3; -static void -write_call_relocator_bw (void *ptr, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start) + +grub_size_t grub_relocator_align = 1; +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +#ifdef __x86_64__ +grub_size_t grub_relocator_jumper_size = 12; +#else +grub_size_t grub_relocator_jumper_size = 7; +#endif + +void +grub_cpu_relocator_init (void) { - grub_relocator32_backward_dest = dest; - grub_relocator32_backward_src = PTR_TO_UINT64 (src); - grub_relocator32_backward_size = size; - - grub_relocator32_backward_eax = state.eax; - grub_relocator32_backward_ebx = state.ebx; - grub_relocator32_backward_ecx = state.ecx; - grub_relocator32_backward_edx = state.edx; - grub_relocator32_backward_eip = state.eip; - grub_relocator32_backward_esp = state.esp; - - grub_memmove (ptr, - &grub_relocator32_backward_start, - RELOCATOR_SIZEOF (backward)); - ((void (*) (void)) ptr) (); + grub_relocator_forward_size = RELOCATOR_SIZEOF(_forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(_backward); } -static void -write_call_relocator_fw (void *ptr, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) { - - grub_relocator32_forward_dest = dest; - grub_relocator32_forward_src = PTR_TO_UINT64 (src); - grub_relocator32_forward_size = size; - - grub_relocator32_forward_eax = state.eax; - grub_relocator32_forward_ebx = state.ebx; - grub_relocator32_forward_ecx = state.ecx; - grub_relocator32_forward_edx = state.edx; - grub_relocator32_forward_eip = state.eip; - grub_relocator32_forward_esp = state.esp; - - grub_memmove (ptr, - &grub_relocator32_forward_start, - RELOCATOR_SIZEOF (forward)); - ((void (*) (void)) ptr) (); + grub_uint8_t *ptr; + ptr = rels; +#ifdef __x86_64__ + /* movq imm64, %rax (for relocator) */ + *(grub_uint8_t *) ptr = 0x48; + ptr++; + *(grub_uint8_t *) ptr = 0xb8; + ptr++; + *(grub_uint64_t *) ptr = addr; + ptr += sizeof (grub_uint64_t); +#else + /* movl imm32, %eax (for relocator) */ + *(grub_uint8_t *) ptr = 0xb8; + ptr++; + *(grub_uint32_t *) ptr = addr; + ptr += sizeof (grub_uint32_t); +#endif + /* jmp $eax/$rax */ + *(grub_uint8_t *) ptr = 0xff; + ptr++; + *(grub_uint8_t *) ptr = 0xe0; + ptr++; } -#include "../relocator.c" +void +grub_cpu_relocator_backward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + grub_relocator_backward_dest = dest; + grub_relocator_backward_src = src; + grub_relocator_backward_chunk_size = size; + + grub_memmove (ptr, + &grub_relocator_backward_start, + RELOCATOR_SIZEOF (_backward)); +} + +void +grub_cpu_relocator_forward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + grub_relocator_forward_dest = dest; + grub_relocator_forward_src = src; + grub_relocator_forward_chunk_size = size; + + grub_memmove (ptr, + &grub_relocator_forward_start, + RELOCATOR_SIZEOF (_forward)); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - RELOCATOR_SIZEOF (32)) + + 1, RELOCATOR_SIZEOF (32), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator32_eax = state.eax; + grub_relocator32_ebx = state.ebx; + grub_relocator32_ecx = state.ecx; + grub_relocator32_edx = state.edx; + grub_relocator32_eip = state.eip; + grub_relocator32_esp = state.esp; + grub_relocator32_esi = state.esi; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start, + RELOCATOR_SIZEOF (32)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +grub_err_t +grub_relocator16_boot (struct grub_relocator *rel, + struct grub_relocator16_state state) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + 0xa0000 - RELOCATOR_SIZEOF (16), + RELOCATOR_SIZEOF (16), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator16_cs = state.cs; + grub_relocator16_ip = state.ip; + + grub_relocator16_ds = state.ds; + grub_relocator16_es = state.es; + grub_relocator16_fs = state.fs; + grub_relocator16_gs = state.gs; + + grub_relocator16_ss = state.ss; + grub_relocator16_sp = state.sp; + + grub_relocator16_edx = state.edx; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start, + RELOCATOR_SIZEOF (16)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state, + grub_addr_t min_addr, grub_addr_t max_addr) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr, + max_addr - RELOCATOR_SIZEOF (64), + RELOCATOR_SIZEOF (64), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator64_rax = state.rax; + grub_relocator64_rbx = state.rbx; + grub_relocator64_rcx = state.rcx; + grub_relocator64_rdx = state.rdx; + grub_relocator64_rip = state.rip; + grub_relocator64_rsp = state.rsp; + grub_relocator64_rsi = state.rsi; + grub_relocator64_cr3 = state.cr3; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator64_start, + RELOCATOR_SIZEOF (64)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/i386/relocator16.S b/grub-core/lib/i386/relocator16.S new file mode 100644 index 000000000..c3768f4eb --- /dev/null +++ b/grub-core/lib/i386/relocator16.S @@ -0,0 +1,193 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 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 . + */ + +/* The code segment of the protected mode. */ +#define CODE_SEGMENT 0x08 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x10 + +#define PSEUDO_REAL_CSEG 0x18 + +#define PSEUDO_REAL_DSEG 0x20 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator16_start) + PREAMBLE + + movl %esi, %eax + movw %ax, (LOCAL (cs_base_bytes12) - LOCAL (base)) (RSI, 1) + shrl $16, %eax + movb %al, (LOCAL (cs_base_byte3) - LOCAL (base)) (RSI, 1) + + RELOAD_GDT + .code32 + /* Update other registers. */ + movl $DATA_SEGMENT, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + DISABLE_PAGING + +#ifdef __x86_64__ + /* Disable amd64. */ + movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx + rdmsr + andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax + wrmsr +#endif + + /* Turn off PAE. */ + movl %cr4, %eax + andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax + movl %eax, %cr4 + + /* Update other registers. */ + movl $PSEUDO_REAL_DSEG, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + movl %esi, %eax + shrl $4, %eax + movw %ax, (LOCAL (segment) - LOCAL (base)) (%esi, 1) + + /* jump to a 16 bit segment */ + ljmp $PSEUDO_REAL_CSEG, $(LOCAL (cont2) - LOCAL(base)) +LOCAL(cont2): + .code16 + + /* clear the PE bit of CR0 */ + movl %cr0, %eax + andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax + movl %eax, %cr0 + + /* flush prefetch queue, reload %cs */ + /* ljmp */ + .byte 0xea + .word LOCAL(cont3)-LOCAL(base) +LOCAL(segment): + .word 0 + +LOCAL(cont3): + /* we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_ds) + .word 0 + movw %ax, %ds + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_es) + .word 0 + movw %ax, %es + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_fs) + .word 0 + movw %ax, %fs + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_gs) + .word 0 + movw %ax, %gs + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_ss) + .word 0 + movw %ax, %ss + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_sp) + .word 0 + movw %ax, %ss + + /* movw imm32, %edx. */ + .byte 0x66, 0xba +VARIABLE(grub_relocator16_edx) + .long 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + /* ljmp */ + .byte 0xea +VARIABLE(grub_relocator16_ip) + .word 0 +VARIABLE(grub_relocator16_cs) + .word 0 + + .code32 + + /* GDT. Copied from loader/i386/linux.c. */ + .p2align 4 +LOCAL(gdt): + .word 0, 0 + .byte 0, 0, 0, 0 + + /* -- code segment -- + * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present + * type = 32bit code execute/read, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x9A, 0xCF, 0 + + /* -- data segment -- + * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present + * type = 32 bit data read/write, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0xCF, 0 + + /* -- 16 bit real mode CS -- + * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present + * type = 16 bit code execute/read only/conforming, DPL = 0 + */ + .word 0xFFFF +LOCAL(cs_base_bytes12): + .word 0 +LOCAL(cs_base_byte3): + .byte 0 + + .byte 0x9E, 0, 0 + + /* -- 16 bit real mode DS -- + * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present + * type = 16 bit data read/write, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0, 0 +LOCAL(gdt_end): + +VARIABLE(grub_relocator16_end) diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S new file mode 100644 index 000000000..b581305a5 --- /dev/null +++ b/grub-core/lib/i386/relocator32.S @@ -0,0 +1,120 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 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 . + */ + +/* The code segment of the protected mode. */ +#define CODE_SEGMENT 0x10 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x18 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator32_start) + PREAMBLE + + RELOAD_GDT + .code32 + /* Update other registers. */ + movl $DATA_SEGMENT, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + DISABLE_PAGING + +#ifdef __x86_64__ + /* Disable amd64. */ + movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx + rdmsr + andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax + wrmsr +#endif + + /* Turn off PAE. */ + movl %cr4, %eax + andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax + movl %eax, %cr4 + + jmp LOCAL(cont2) +LOCAL(cont2): + .code32 + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_esp) + .long 0 + + movl %eax, %esp + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_esi) + .long 0 + + movl %eax, %esi + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_eax) + .long 0 + + /* mov imm32, %ebx */ + .byte 0xbb +VARIABLE(grub_relocator32_ebx) + .long 0 + + /* mov imm32, %ecx */ + .byte 0xb9 +VARIABLE(grub_relocator32_ecx) + .long 0 + + /* mov imm32, %edx */ + .byte 0xba +VARIABLE(grub_relocator32_edx) + .long 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + .byte 0xea +VARIABLE(grub_relocator32_eip) + .long 0 + .word CODE_SEGMENT + + /* GDT. Copied from loader/i386/linux.c. */ + .p2align 4 +LOCAL(gdt): + /* NULL. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Reserved. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Code segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 + + /* Data segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 +LOCAL(gdt_end): + +VARIABLE(grub_relocator32_end) diff --git a/grub-core/lib/i386/relocator64.S b/grub-core/lib/i386/relocator64.S new file mode 100644 index 000000000..bb086418c --- /dev/null +++ b/grub-core/lib/i386/relocator64.S @@ -0,0 +1,160 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define CODE32_SEGMENT 0x18 +#define CODE_SEGMENT 0x08 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x10 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator64_start) + PREAMBLE +#ifndef __x86_64__ + DISABLE_PAGING + + /* Turn on PAE. */ + movl %cr4, %eax + orl $(GRUB_MEMORY_CPU_CR4_PAE_ON | GRUB_MEMORY_CPU_CR4_PSE_ON), %eax + movl %eax, %cr4 + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator64_cr3) + .long 0 + movl %eax, %cr3 + + /* Turn on amd64. */ + movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx + rdmsr + orl $GRUB_MEMORY_CPU_AMD64_MSR_ON, %eax + wrmsr + + /* Enable paging. */ + movl %cr0, %eax + orl $GRUB_MEMORY_CPU_CR0_PAGING_ON, %eax + movl %eax, %cr0 + + RELOAD_GDT +#else + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_cr3) + .quad 0 + movq %rax, %cr3 +#endif + + .code64 + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rsp) + .quad 0 + + movq %rax, %rsp + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rsi) + .quad 0 + + movq %rax, %rsi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rax) + .quad 0 + + /* mov imm64, %rbx */ + .byte 0x48 + .byte 0xbb +VARIABLE(grub_relocator64_rbx) + .quad 0 + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator64_rcx) + .quad 0 + + /* mov imm64, %rdx */ + .byte 0x48 + .byte 0xba +VARIABLE(grub_relocator64_rdx) + .quad 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + jmp *LOCAL(jump_addr) (%rip) + +LOCAL(jump_addr): +VARIABLE(grub_relocator64_rip) + .quad 0 + +#ifndef __x86_64__ + .p2align 4 +LOCAL(gdt): + /* NULL. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* 64-bit segment. */ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (1 << 5) /* 64-bit. */ | (0 << 6) \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + + /* Data segment*/ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x0 /* Type 0. */ | (0 << 4) /* Data. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (0 << 5) /* Data. */ | (0 << 6) \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + + /* Compatibility segment. */ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (0 << 5) /* 32-bit. */ | (1 << 6) /* 32-bit. */ \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + +LOCAL(gdt_end): +#endif + +VARIABLE(grub_relocator64_end) diff --git a/grub-core/lib/i386/relocator_asm.S b/grub-core/lib/i386/relocator_asm.S index 22490a3f8..f273586fe 100644 --- a/grub-core/lib/i386/relocator_asm.S +++ b/grub-core/lib/i386/relocator_asm.S @@ -19,232 +19,62 @@ #include #include -#ifdef BACKWARD -#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_backward_ ## x) -#else -#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_forward_ ## x) -#endif -#ifdef __x86_64__ -#define RAX %rax -#define RCX %rcx -#define RDI %rdi -#define RSI %rdi -#else -#define RAX %eax -#define RCX %ecx -#define RDI %edi -#define RSI %esi -#endif + .p2align 2 -/* The code segment of the protected mode. */ -#define CODE_SEGMENT 0x10 - -/* The data segment of the protected mode. */ -#define DATA_SEGMENT 0x18 - - .p2align 4 /* force 16-byte alignment */ - -RELOCATOR_VARIABLE(start) -#ifdef BACKWARD -LOCAL(base): -#endif - cli - -#ifndef __x86_64__ +VARIABLE(grub_relocator_backward_start) /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE(dest) +VARIABLE(grub_relocator_backward_dest) .long 0 movl %eax, %edi /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE(src) +VARIABLE(grub_relocator_backward_src) .long 0 movl %eax, %esi /* mov imm32, %ecx */ .byte 0xb9 -RELOCATOR_VARIABLE(size) +VARIABLE(grub_relocator_backward_chunk_size) .long 0 -#else - xorq %rax, %rax - - /* mov imm32, %eax */ - .byte 0xb8 -RELOCATOR_VARIABLE(dest) - .long 0 - movq %rax, %rdi - - /* mov imm64, %rax */ - .byte 0x48 - .byte 0xb8 -RELOCATOR_VARIABLE(src) - .long 0, 0 - movq %rax, %rsi - - xorq %rcx, %rcx - /* mov imm32, %ecx */ - .byte 0xb9 -RELOCATOR_VARIABLE(size) - .long 0 - -#endif - - mov RDI, RAX - -#ifdef BACKWARD - add RCX, RSI - add RCX, RDI -#endif - -#ifndef BACKWARD - add RCX, RAX -#endif - add $0x3, RCX - shr $2, RCX + + add %ecx, %esi + add %ecx, %edi -#ifdef BACKWARD - /* Backward movsl is implicitly off-by-four. compensate that. */ - sub $4, RSI - sub $4, RDI + /* Backward movsb is implicitly off-by-one. compensate that. */ + sub $1, %esi + sub $1, %edi /* Backward copy. */ std rep - movsl + movsb +VARIABLE(grub_relocator_backward_end) -#else - /* Forward copy. */ - cld - rep - movsl -#endif - - /* %rax contains now our new 'base'. */ - mov RAX, RSI - add $(LOCAL(cont0) - LOCAL(base)), RAX - jmp *RAX -LOCAL(cont0): - lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX - movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) - - lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX - mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1) - - /* Switch to compatibility mode. */ - - lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1) - - /* Update %cs. */ - ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) - -LOCAL(cont1): - .code32 - - /* Update other registers. */ - movl $DATA_SEGMENT, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %fs - movl %eax, %gs - movl %eax, %ss - - /* Disable paging. */ - movl %cr0, %eax - andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax - movl %eax, %cr0 - -#ifdef __x86_64__ - /* Disable amd64. */ - movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx - rdmsr - andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax - wrmsr -#endif - - /* Turn off PAE. */ - movl %cr4, %eax - andl $GRUB_MEMORY_CPU_CR4_PAE_ON, %eax - movl %eax, %cr4 - - jmp LOCAL(cont2) -LOCAL(cont2): - .code32 +VARIABLE(grub_relocator_forward_start) /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE (esp) +VARIABLE(grub_relocator_forward_dest) .long 0 + movl %eax, %edi - movl %eax, %esp - - /* mov imm32, %eax */ + /* mov imm32, %rax */ .byte 0xb8 -RELOCATOR_VARIABLE (eax) - .long 0 - - /* mov imm32, %ebx */ - .byte 0xbb -RELOCATOR_VARIABLE (ebx) +VARIABLE(grub_relocator_forward_src) .long 0 + movl %eax, %esi /* mov imm32, %ecx */ .byte 0xb9 -RELOCATOR_VARIABLE (ecx) +VARIABLE(grub_relocator_forward_chunk_size) .long 0 - /* mov imm32, %edx */ - .byte 0xba -RELOCATOR_VARIABLE (edx) - .long 0 - - /* Cleared direction flag is of no problem with any current - payload and makes this implementation easier. */ + /* Forward copy. */ cld - - .byte 0xea -RELOCATOR_VARIABLE (eip) - .long 0 - .word CODE_SEGMENT - - /* GDT. Copied from loader/i386/linux.c. */ - .p2align 4 -LOCAL(gdt): - /* NULL. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Reserved. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Code segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 - - /* Data segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - - .p2align 4 -LOCAL(gdtdesc): - .word 0x27 -LOCAL(gdt_addr): -#ifdef __x86_64__ - /* Filled by the code. */ - .quad 0 -#else - /* Filled by the code. */ - .long 0 -#endif - - .p2align 4 -LOCAL(jump_vector): - /* Jump location. Is filled by the code */ - .long 0 - .long CODE_SEGMENT - -#ifndef BACKWARD -LOCAL(base): -#endif - -RELOCATOR_VARIABLE(end) + rep + movsb +VARIABLE(grub_relocator_forward_end) diff --git a/grub-core/lib/i386/relocator_common.S b/grub-core/lib/i386/relocator_common.S new file mode 100644 index 000000000..bd5b53f95 --- /dev/null +++ b/grub-core/lib/i386/relocator_common.S @@ -0,0 +1,82 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 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 + +#ifdef __x86_64__ +#define RAX %rax +#define RSI %rsi +#else +#define RAX %eax +#define RSI %esi +#endif + + .macro DISABLE_PAGING +#ifdef GRUB_MACHINE_IEEE1275 +#endif + + movl %cr0, %eax + andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax + movl %eax, %cr0 + .endm + + .macro PREAMBLE +LOCAL(base): + /* %rax contains now our new 'base'. */ + mov RAX, RSI + + add $(LOCAL(cont0) - LOCAL(base)), RAX + jmp *RAX +LOCAL(cont0): + .endm + + .macro RELOAD_GDT + lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX + movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + + lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX + mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1) + + /* Switch to compatibility mode. */ + lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1) + + /* Update %cs. */ + ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + + .p2align 4 +LOCAL(gdtdesc): + .word LOCAL(gdt_end) - LOCAL(gdt) +LOCAL(gdt_addr): +#ifdef __x86_64__ + /* Filled by the code. */ + .quad 0 +#else + /* Filled by the code. */ + .long 0 +#endif + + .p2align 4 +LOCAL(jump_vector): + /* Jump location. Is filled by the code */ + .long 0 + .long CODE_SEGMENT + +LOCAL(cont1): + .endm diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c new file mode 100644 index 000000000..947346d46 --- /dev/null +++ b/grub-core/lib/ieee1275/relocator.c @@ -0,0 +1,95 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 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 + +unsigned +grub_relocator_firmware_get_max_events (void) +{ + int counter = 0; + auto int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t len __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))); + int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t len __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + counter++; + return 0; + } + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET)) + return 0; + grub_machine_mmap_iterate (count); + return 2 * counter; +} + +unsigned +grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) +{ + int counter = 0; + auto int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, + grub_uint32_t type); + int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, + grub_uint32_t type) + { + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) + return 0; + + if (addr < 0x180000) + { + len = addr + len - 0x180000; + addr = 0x180000; + } + } + + events[counter].type = REG_FIRMWARE_START; + events[counter].pos = addr; + counter++; + events[counter].type = REG_FIRMWARE_END; + events[counter].pos = addr + len; + counter++; + + return 0; + } + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET)) + return 0; + grub_machine_mmap_iterate (fill); + return counter; +} + +int +grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size) +{ + return (grub_claimmap (start, size) >= 0); +} + +void +grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size) +{ + grub_ieee1275_release (start, size); +} diff --git a/grub-core/lib/mips/relocator.c b/grub-core/lib/mips/relocator.c index 118ddbd6f..537b0af2c 100644 --- a/grub-core/lib/mips/relocator.c +++ b/grub-core/lib/mips/relocator.c @@ -25,26 +25,33 @@ #include #include +#include -/* Remark: doesn't work with source outside of 4G. - Use relocator64 in this case. - */ +/* Do we need mips64? */ -extern grub_uint8_t grub_relocator32_forward_start; -extern grub_uint8_t grub_relocator32_forward_end; -extern grub_uint8_t grub_relocator32_backward_start; -extern grub_uint8_t grub_relocator32_backward_end; +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; #define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) #define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) -#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator32_##x##_end \ - - &grub_relocator32_##x##_start) +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) #define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ - + REGW_SIZEOF * (31 + 3) + JUMP_SIZEOF) -#define RELOCATOR_ALIGN 16 + + REGW_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint32_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; -#define PREFIX(x) grub_relocator32_ ## x +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} static void write_reg (int regn, grub_uint32_t val, void **target) @@ -69,44 +76,74 @@ write_jump (int regn, void **target) *target = ((grub_uint32_t *) *target) + 1; } -static void -write_call_relocator_bw (void *ptr0, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + write_reg (1, addr, &rels); + write_jump (1, &rels); +} + +void +grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, + grub_size_t size) { void *ptr = ptr0; - int i; write_reg (8, (grub_uint32_t) src, &ptr); - write_reg (9, dest, &ptr); - write_reg (10, size, &ptr); - grub_memcpy (ptr, &grub_relocator32_backward_start, + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_backward_start, RELOCATOR_SRC_SIZEOF (backward)); - ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (backward); - for (i = 1; i < 32; i++) - write_reg (i, state.gpr[i], &ptr); - write_jump (state.jumpreg, &ptr); - grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); - grub_dprintf ("relocator", "Backward relocator: about to jump to %p\n", ptr0); - ((void (*) (void)) ptr0) (); } -static void -write_call_relocator_fw (void *ptr0, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, + grub_size_t size) { void *ptr = ptr0; - int i; write_reg (8, (grub_uint32_t) src, &ptr); - write_reg (9, dest, &ptr); - write_reg (10, size, &ptr); - grub_memcpy (ptr, &grub_relocator32_forward_start, + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_forward_start, RELOCATOR_SRC_SIZEOF (forward)); - ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (forward); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + grub_relocator_chunk_t ch; + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_addr_t vtarget; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptr = get_virtual_current_address (ch); for (i = 1; i < 32; i++) write_reg (i, state.gpr[i], &ptr); write_jump (state.jumpreg, &ptr); - grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); - grub_dprintf ("relocator", "Forward relocator: about to jump to %p\n", ptr0); - ((void (*) (void)) ptr0) (); -} -#include "../relocator.c" + vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), + stateset_size); + + err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/mips/relocator_asm.S b/grub-core/lib/mips/relocator_asm.S index ff4fa31e0..3408b59e1 100644 --- a/grub-core/lib/mips/relocator_asm.S +++ b/grub-core/lib/mips/relocator_asm.S @@ -20,39 +20,39 @@ .p2align 4 /* force 16-byte alignment */ -VARIABLE (grub_relocator32_forward_start) +VARIABLE (grub_relocator_forward_start) move $a0, $9 move $a1, $10 copycont1: lb $11,0($8) sb $11,0($9) - addiu $8, $8, 0x1 - addiu $9, $9, 0x1 - addiu $10, $10, 0xffff + addiu $8, $8, 1 + addiu $9, $9, 1 + addiu $10, $10, -1 bne $10, $0, copycont1 #include "../../kern/mips/cache_flush.S" -VARIABLE (grub_relocator32_forward_end) +VARIABLE (grub_relocator_forward_end) -VARIABLE (grub_relocator32_backward_start) +VARIABLE (grub_relocator_backward_start) move $a0, $9 move $a1, $10 addu $9, $9, $10 addu $8, $8, $10 /* Backward movsl is implicitly off-by-one. compensate that. */ - addiu $9, $9, 0xffff - addiu $8, $8, 0xffff + addiu $9, $9, -1 + addiu $8, $8, -1 copycont2: lb $11,0($8) sb $11,0($9) - addiu $8, $8, 0xffff - addiu $9, $9, 0xffff - addiu $10, 0xffff + addiu $8, $8, -1 + addiu $9, $9, -1 + addiu $10, $10, -1 bne $10, $0, copycont2 #include "../../kern/mips/cache_flush.S" -VARIABLE (grub_relocator32_backward_end) +VARIABLE (grub_relocator_backward_end) diff --git a/grub-core/lib/powerpc/relocator.c b/grub-core/lib/powerpc/relocator.c new file mode 100644 index 000000000..85dfbeaf3 --- /dev/null +++ b/grub-core/lib/powerpc/relocator.c @@ -0,0 +1,142 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; + +#define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint32_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; + +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} + +static void +write_reg (int regn, grub_uint32_t val, void **target) +{ + /* lis r, val >> 16 */ + *(grub_uint32_t *) *target = + ((0x3c00 | (regn << 5)) << 16) | (val >> 16); + *target = ((grub_uint32_t *) *target) + 1; + /* ori r, r, val & 0xffff. */ + *(grub_uint32_t *) *target = (((0x6000 | regn << 5 | regn) << 16) + | (val & 0xffff)); + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_jump (void **target) +{ + /* blr. */ + *(grub_uint32_t *) *target = 0x4e800020; + *target = ((grub_uint32_t *) *target) + 1; +} + +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + write_reg (GRUB_PPC_JUMP_REGISTER, addr, &rels); + write_jump (&rels); +} + +void +grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); +} + +void +grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 32 * REGW_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptr = get_virtual_current_address (ch); + for (i = 0; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (&ptr); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/powerpc/relocator_asm.S b/grub-core/lib/powerpc/relocator_asm.S new file mode 100644 index 000000000..355e9c8b4 --- /dev/null +++ b/grub-core/lib/powerpc/relocator_asm.S @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 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 + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE (grub_relocator_forward_start) + mr 3, 9 + mr 4, 10 + +copycont1: + lbz 11,0(8) + stb 11,0(9) + addi 8, 8, 0x1 + addi 9, 9, 0x1 + addi 10, 10, -1 + cmpwi 10, 0 + bne copycont1 + +#include "../../kern/powerpc/cache_flush.S" + +VARIABLE (grub_relocator_forward_end) + +VARIABLE (grub_relocator_backward_start) + mr 3, 9 + mr 4, 10 + + add 9, 9, 10 + add 8, 8, 10 + /* Backward movsl is implicitly off-by-one. compensate that. */ + addi 9, 9, -1 + addi 8, 8, -1 +copycont2: + lbz 11,0(8) + stb 11,0(9) + addi 8, 8, -1 + addi 9, 9, -1 + addi 10, 10, -1 + cmpwi 10, 0 + bne copycont2 + +#include "../../kern/powerpc/cache_flush.S" + +VARIABLE (grub_relocator_backward_end) diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index 6a5acc548..53acda52f 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2009, 2010 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 @@ -16,122 +16,1607 @@ * along with GRUB. If not, see . */ -#define MAX_OVERHEAD ((RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)) -#define PRE_REGION_SIZE (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) +#include +#include +#include +#include +#include +#include -void * -PREFIX (alloc) (grub_size_t size) +struct grub_relocator { - char *playground; + struct grub_relocator_chunk *chunks; + grub_phys_addr_t postchunks; + grub_phys_addr_t highestaddr; + grub_phys_addr_t highestnonpostaddr; + grub_size_t relocators_size; +}; - playground = grub_malloc (size + MAX_OVERHEAD); - if (!playground) - return 0; - - *(grub_size_t *) playground = size; - - return playground + PRE_REGION_SIZE; -} - -void * -PREFIX (realloc) (void *relocator, grub_size_t size) -{ - char *playground; - - if (!relocator) - return PREFIX (alloc) (size); - - playground = (char *) relocator - PRE_REGION_SIZE; - - playground = grub_realloc (playground, size + MAX_OVERHEAD); - if (!playground) - return 0; - - *(grub_size_t *) playground = size; - - return playground + PRE_REGION_SIZE; -} - -void -PREFIX(free) (void *relocator) -{ - if (relocator) - grub_free ((char *) relocator - PRE_REGION_SIZE); -} - -grub_err_t -PREFIX (boot) (void *relocator, grub_uint32_t dest, - struct grub_relocator32_state state) +struct grub_relocator_subchunk { + enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START, +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER +#endif + } type; + grub_mm_region_t reg; + grub_mm_header_t head; + grub_phys_addr_t start; grub_size_t size; - char *playground; + grub_size_t pre_size; + struct grub_relocator_extra_block *extra; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + struct grub_relocator_fw_leftover *pre, *post; +#endif +}; - playground = (char *) relocator - PRE_REGION_SIZE; - size = *(grub_size_t *) playground; +struct grub_relocator_chunk +{ + struct grub_relocator_chunk *next; + grub_phys_addr_t src; + void *srcv; + grub_phys_addr_t target; + grub_size_t size; + struct grub_relocator_subchunk *subchunks; + unsigned nsubchunks; +}; - grub_dprintf ("relocator", - "Relocator: source: %p, destination: 0x%x, size: 0x%lx\n", - relocator, (unsigned) dest, (unsigned long) size); +struct grub_relocator_extra_block +{ + struct grub_relocator_extra_block *next; + struct grub_relocator_extra_block **prev; + grub_phys_addr_t start; + grub_phys_addr_t end; +}; - /* Very unlikely condition: Relocator may risk overwrite itself. - Just move it a bit up. */ - if ((grub_addr_t) dest < (grub_addr_t) relocator - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) - && (grub_addr_t) dest + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - > (grub_addr_t) relocator) +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +struct grub_relocator_fw_leftover +{ + struct grub_relocator_fw_leftover *next; + struct grub_relocator_fw_leftover **prev; + grub_phys_addr_t quantstart; + grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8]; +}; + +struct grub_relocator_fw_leftover *leftovers; +#endif + +struct grub_relocator_extra_block *extra_blocks; + +void * +get_virtual_current_address (grub_relocator_chunk_t in) +{ + return in->srcv; +} + +grub_phys_addr_t +get_physical_target_address (grub_relocator_chunk_t in) +{ + return in->target; +} + +struct grub_relocator * +grub_relocator_new (void) +{ + struct grub_relocator *ret; + + grub_cpu_relocator_init (); + + ret = grub_zalloc (sizeof (struct grub_relocator)); + if (!ret) + return NULL; + + ret->postchunks = ~(grub_phys_addr_t) 0; + ret->relocators_size = grub_relocator_jumper_size; + grub_dprintf ("relocator", "relocators_size=%lu\n", + (unsigned long) ret->relocators_size); + return ret; +} + +#define DIGITSORT_BITS 8 +#define DIGITSORT_MASK ((1 << DIGITSORT_BITS) - 1) +#define BITS_IN_BYTE 8 + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static inline int +is_start (int type) +{ + return !(type & 1) && (type != COLLISION_START); +} + +static void +allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, + grub_mm_region_t *regancestor, grub_mm_header_t hancestor) +{ + grub_addr_t newreg_start, newreg_raw_start + = (grub_addr_t) rb + (addr - grub_vtop (rb)) + size; + grub_addr_t newreg_size, newreg_presize; + grub_mm_header_t new_header; + grub_mm_header_t hb = (grub_mm_header_t) (rb + 1); + + grub_dprintf ("relocator", "ra = %p, rb = %p\n", regancestor, rb); + + newreg_start = ALIGN_UP (newreg_raw_start, GRUB_MM_ALIGN); + newreg_presize = newreg_start - newreg_raw_start; + newreg_size = rb->size - (newreg_start - (grub_addr_t) rb); + if ((hb->size << GRUB_MM_ALIGN_LOG2) >= newreg_start + - (grub_addr_t) rb) { - void *relocator_new = ((grub_uint8_t *) relocator) - + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN); - grub_dprintf ("relocator", "Overwrite condition detected moving " - "relocator from %p to %p\n", relocator, relocator_new); - grub_memmove (relocator_new, relocator, - (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - + size - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)); - relocator = relocator_new; - } - - if ((grub_addr_t) dest >= (grub_addr_t) relocator) - { - int overhead; - overhead = dest - - ALIGN_UP (dest - RELOCATOR_SIZEOF (backward) - RELOCATOR_ALIGN, - RELOCATOR_ALIGN); - grub_dprintf ("relocator", - "Backward relocator: code %p, source: %p, " - "destination: 0x%x, size: 0x%lx\n", - (char *) relocator - overhead, - (char *) relocator - overhead, - (unsigned) dest - overhead, - (unsigned long) size + overhead); - - write_call_relocator_bw ((char *) relocator - overhead, - (char *) relocator - overhead, - dest - overhead, size + overhead, state); + grub_mm_header_t newhnext = hb->next; + grub_size_t newhsize = ((hb->size << GRUB_MM_ALIGN_LOG2) + - (newreg_start + - (grub_addr_t) rb)) >> GRUB_MM_ALIGN_LOG2; + new_header = (void *) (newreg_start + sizeof (*rb)); + if (newhnext == hb) + newhnext = new_header; + new_header->next = newhnext; + new_header->size = newhsize; + new_header->magic = GRUB_MM_FREE_MAGIC; } else { - int overhead; + new_header = hb->next; + if (new_header == hb) + new_header = (void *) (newreg_start + sizeof (*rb)); + } + { + struct grub_mm_header *newregfirst = rb->first; + struct grub_mm_region *newregnext = rb->next; + struct grub_mm_region *newreg = (void *) newreg_start; + hancestor->next = new_header; + if (newregfirst == hb) + newregfirst = new_header; + newreg->first = newregfirst; + newreg->next = newregnext; + newreg->pre_size = newreg_presize; + newreg->size = newreg_size; + *regancestor = newreg; + { + grub_mm_header_t h = newreg->first, hp = NULL; + do + { + if ((void *) h < (void *) (newreg + 1)) + grub_fatal ("Failed to adjust memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); + if ((void *) h == (void *) (newreg + 1)) + grub_dprintf ("relocator", + "Free start memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); - overhead = ALIGN_UP (dest + size, RELOCATOR_ALIGN) - + RELOCATOR_SIZEOF (forward) - (dest + size); - grub_dprintf ("relocator", - "Forward relocator: code %p, source: %p, " - "destination: 0x%x, size: 0x%lx\n", - (char *) relocator + size + overhead - - RELOCATOR_SIZEOF (forward), - relocator, (unsigned) dest, - (unsigned long) size + overhead); + hp = h; + h = h->next; + } + while (h != newreg->first); + } + } +} - write_call_relocator_fw ((char *) relocator + size + overhead - - RELOCATOR_SIZEOF (forward), - relocator, dest, size + overhead, state); +static void +allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, + grub_mm_header_t hb, grub_mm_header_t hbp, + grub_mm_region_t rb) +{ + struct grub_mm_header *foll = NULL; + grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb)); + + grub_dprintf ("relocator", "inreg paddr = 0x%lx, size = %lu," + " hb = %p, hbp = %p, rb = %p, vaddr = 0x%lx\n", + (unsigned long) paddr, (unsigned long) size, hb, hbp, + rb, (unsigned long) vaddr); + + if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN + <= (grub_addr_t) (hb + hb->size)) + { + foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN); + foll->magic = GRUB_MM_FREE_MAGIC; + foll->size = hb + hb->size - foll; + grub_dprintf ("relocator", "foll = %p, foll->size = %lu\n", foll, + (unsigned long) foll->size); } - /* Not reached. */ + if (vaddr - (grub_addr_t) hb >= sizeof (*hb)) + { + hb->size = ((vaddr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2); + if (foll) + { + foll->next = hb; + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + } + } + else + { + if (foll) + { + foll->next = hb->next; + } + else + foll = hb->next; + + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + if (rb->first == hb) + { + rb->first = (void *) (rb + 1); + } + } +} + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +static void +check_leftover (struct grub_relocator_fw_leftover *lo) +{ + unsigned i; + for (i = 0; i < sizeof (lo->freebytes); i++) + if (lo->freebytes[i] != 0xff) + return; + grub_relocator_firmware_free_region (lo->quantstart, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + *lo->prev = lo->next; + if (lo->next) + lo->next->prev = lo->prev; +} +#endif + +static void +free_subchunk (const struct grub_relocator_subchunk *subchu) +{ + switch (subchu->type) + { + case CHUNK_TYPE_REGION_START: + { + grub_mm_region_t r1, r2, *rp; + grub_mm_header_t h; + grub_size_t pre_size; + r1 = subchu->reg; + r2 = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) subchu->reg + + (grub_vtop (subchu->reg) + - subchu->start) + subchu->size, + GRUB_MM_ALIGN); + for (rp = &grub_mm_base; *rp && *rp != r2; rp = &((*rp)->next)); + pre_size = subchu->pre_size; + + if (*rp) + { + grub_mm_header_t h2, *hp; + r1->first = r2->first; + r1->next = r2->next; + r1->pre_size = pre_size; + r1->size = r2->size + (r2 - r1) * sizeof (*r2); + *rp = r1; + h = (grub_mm_header_t) (r1 + 1); + h->next = r2->first; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + for (hp = &r2->first, h2 = *hp; h2->next != r2->first; + hp = &(h2->next), h2 = *hp) + if (h2 == (grub_mm_header_t) (r2 + 1)) + break; + if (h2 == (grub_mm_header_t) (r2 + 1)) + { + h->size = h2->size + (h2 - h); + h->next = h2->next; + *hp = h; + if (hp == &r2->first) + { + for (h2 = r2->first; h2->next != r2->first; h2 = h2->next); + h2->next = h; + } + } + else + { + h2->next = h; + } + } + else + { + r1->pre_size = pre_size; + r1->size = (r2 - r1) * sizeof (*r2); + /* Find where to insert this region. + Put a smaller one before bigger ones, + to prevent fragmentation. */ + for (rp = &grub_mm_base; *rp; rp = &((*rp)->next)) + if ((*rp)->size > r1->size) + break; + r1->next = *rp; + *rp = r1->next; + h = (grub_mm_header_t) (r1 + 1); + r1->first = h; + h->next = h; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + } + for (r2 = grub_mm_base; r2; r2 = r2->next) + if ((grub_addr_t) r2 + r2->size == (grub_addr_t) r1) + break; + if (r2) + { + grub_mm_header_t hl2, hl, g; + g = (grub_mm_header_t) ((grub_addr_t) r2 + r2->size); + g->size = (grub_mm_header_t) r1 - g; + r2->size += r1->size; + for (hl = r2->first; hl->next != r2->first; hl = hl->next); + for (hl2 = r1->first; hl2->next != r1->first; hl2 = hl2->next); + hl2->next = r2->first; + r2->first = r1->first; + hl->next = r2->first; + *rp = (*rp)->next; + grub_free (g + 1); + } + break; + } + case CHUNK_TYPE_IN_REGION: + { + grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->head, + GRUB_MM_ALIGN); + h->size + = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) + - (subchu->start / GRUB_MM_ALIGN); + h->next = h; + h->magic = GRUB_MM_ALLOC_MAGIC; + grub_free (h + 1); + break; + } +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + case CHUNK_TYPE_LEFTOVER: + { + grub_addr_t fstart, fend; + fstart = ALIGN_UP (subchu->start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend = ALIGN_DOWN (subchu->start + subchu->size, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + if (fstart < fend) + grub_relocator_firmware_free_region (fstart, fend - fstart); +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (subchu->pre) + { + int off = subchu->start - fstart + - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (subchu->pre->freebytes + off / 8 + 1, + 0xff, sizeof (subchu->pre->freebytes) - off / 8 - 1); + subchu->pre->freebytes[off / 8] |= ~((1 << (off % 8)) - 1); + check_leftover (subchu->pre); + } + if (subchu->post) + { + int off = subchu->start + subchu->size - fend; + grub_memset (subchu->pre->freebytes, + 0xff, sizeof (subchu->pre->freebytes) - off / 8); + subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1); + check_leftover (subchu->post); + } +#endif + *subchu->extra->prev = subchu->extra->next; + grub_free (subchu->extra); + } + break; +#endif + } +} + +static int +malloc_in_range (struct grub_relocator *rel, + grub_addr_t start, grub_addr_t end, grub_addr_t align, + grub_size_t size, struct grub_relocator_chunk *res, + int from_low_priv, int collisioncheck) +{ + grub_mm_region_t r, *ra, base_saved; + struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t; + /* 128 is just in case of additional malloc (shouldn't happen). */ + unsigned maxevents = 2 + 128; + grub_mm_header_t p, pa; + unsigned *counter; + int nallocs = 0; + unsigned j, N = 0; + grub_addr_t target = 0; + + grub_dprintf ("relocator", + "trying to allocate in 0x%lx-0x%lx aligned 0x%lx size 0x%lx\n", + (unsigned long) start, (unsigned long) end, + (unsigned long) align, (unsigned long) size); + + start = ALIGN_UP (start, align); + end = ALIGN_DOWN (end - size, align) + size; + + if (end < start + size) + return 0; + + /* We have to avoid any allocations when filling scanline events. + Hence 2-stages. + */ + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%d: out of range pointer: %p\n", __LINE__, p); + maxevents += 2; + p = p->next; + } + while (p != r->first); + maxevents += 4; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + maxevents += 2; + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + maxevents += 2; + } + for (r = grub_mm_base; r; r = r->next) + maxevents += 2; + + maxevents += grub_relocator_firmware_get_max_events (); +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + int l = 0; + unsigned i; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + maxevents++; + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + maxevents++; + } + } +#endif + + events = grub_malloc (maxevents * sizeof (events[0])); + eventt = grub_malloc (maxevents * sizeof (events[0])); + counter = grub_malloc ((DIGITSORT_MASK + 2) * sizeof (counter[0])); + if (!events || !eventt || !counter) + { + grub_dprintf ("relocator", "events or counter allocation failed %d\n", + maxevents); + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + events[N].type = COLLISION_START; + events[N].pos = chunk->target; + N++; + events[N].type = COLLISION_END; + events[N].pos = chunk->target + chunk->size; + N++; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + for (r = grub_mm_base; r; r = r->next) + { + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) r - r->pre_size, + (unsigned long) (r + 1) + r->size); + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = (grub_addr_t) r - r->pre_size; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = (grub_addr_t) (r + 1) + r->size; + N++; + } + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + { + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) cur->start, (unsigned long) cur->end); + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = cur->start; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = cur->end; + N++; + } + } + + N += grub_relocator_firmware_fill_events (events + N); + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + unsigned i; + int l = 0; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + { + events[N].type = l ? REG_LEFTOVER_END : REG_LEFTOVER_START; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + { + events[N].type = REG_LEFTOVER_END; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + } + } +#endif +#endif + + /* No malloc from this point. */ + base_saved = grub_mm_base; + grub_mm_base = NULL; + + for (ra = &base_saved, r = *ra; r; ra = &(r->next), r = *ra) + { + int pre_added = 0; + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + grub_dprintf ("relocator", "free block %p+0x%lx\n", + p, (unsigned long) p->size); + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal (__FILE__":%d free magic broken at %p (0x%x)\n", + __LINE__, p, p->magic); + if (p == (grub_mm_header_t) (r + 1)) + { + pre_added = 1; + events[N].type = REG_BEG_START; + events[N].pos = grub_vtop (r) - r->pre_size; + events[N].reg = r; + events[N].regancestor = ra; + events[N].head = p; + events[N].hancestor = pa; + N++; + events[N].type = REG_BEG_END; + events[N].pos = grub_vtop (p + p->size) - sizeof (*r); + N++; + } + else + { + events[N].type = IN_REG_START; + events[N].pos = grub_vtop (p); + events[N].head = p; + events[N].hancestor = pa; + events[N].reg = r; + N++; + events[N].type = IN_REG_END; + events[N].pos = grub_vtop (p + p->size); + N++; + } + pa = p; + p = pa->next; + } + while (pa != r->first); + } + + /* Put ending events after starting events. */ + { + int st = 0, e = N / 2; + for (j = 0; j < N; j++) + if (is_start (events[j].type) || events[j].type == COLLISION_START) + eventt[st++] = events[j]; + else + eventt[e++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + + { + unsigned i; + for (i = 0; i < (BITS_IN_BYTE * sizeof (grub_addr_t) / DIGITSORT_BITS); + i++) + { + memset (counter, 0, (1 + (1 << DIGITSORT_BITS)) * sizeof (counter[0])); + for (j = 0; j < N; j++) + counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK) + 1]++; + for (j = 0; j <= DIGITSORT_MASK; j++) + counter[j+1] += counter[j]; + for (j = 0; j < N; j++) + eventt[counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK)]++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + retry: +#endif + + /* Now events are nicely sorted. */ + { + int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + int nlefto = 0; +#else + const int nlefto = 0; +#endif + grub_addr_t starta = 0; + int numstarted; + for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1); + from_low_priv ? j++ : j--) + { + int isinsidebefore, isinsideafter; + isinsidebefore = (!ncollisions && (nstarted || (((nlefto || nstartedfw) + && !nblockfw)))); + switch (events[j].type) + { +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + nstartedfw++; + break; + + case REG_FIRMWARE_END: + nstartedfw--; + break; + + case FIRMWARE_BLOCK_START: + nblockfw++; + break; + + case FIRMWARE_BLOCK_END: + nblockfw--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + nlefto++; + break; + + case REG_LEFTOVER_END: + nlefto--; + break; +#endif + + case COLLISION_START: + ncollisions++; + break; + + case COLLISION_END: + ncollisions--; + break; + + case IN_REG_START: + case REG_BEG_START: + nstarted++; + break; + + case IN_REG_END: + case REG_BEG_END: + nstarted--; + break; + } + isinsideafter = (!ncollisions && (nstarted || ((nlefto || nstartedfw) + && !nblockfw))); + if (!isinsidebefore && isinsideafter) + { + starta = from_low_priv ? ALIGN_UP (events[j].pos, align) + : ALIGN_DOWN (events[j].pos - size, align) + size; + numstarted = j; + } + if (isinsidebefore && !isinsideafter && from_low_priv) + { + target = starta; + if (target < start) + target = start; + if (target + size <= end && target + size <= events[j].pos) + /* Found an usable address. */ + goto found; + } + if (isinsidebefore && !isinsideafter && !from_low_priv) + { + target = starta - size; + if (target > end - size) + target = end - size; + if (target >= start && target >= events[j].pos) + goto found; + } + } + } + + grub_mm_base = base_saved; + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + + found: + { + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwb = 0, fwlefto = 0; +#endif + int last_start = 0; + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { + switch (typepre) + { + case CHUNK_TYPE_REGION_START: + allocate_regstart (alloc_start, alloc_end - alloc_start, + events[last_start].reg, + events[last_start].regancestor, + events[last_start].hancestor); + /* TODO: maintain a reverse lookup tree for hancestor. */ + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; + case CHUNK_TYPE_IN_REGION: + allocate_inreg (alloc_start, alloc_end - alloc_start, + events[last_start].head, + events[last_start].hancestor, + events[last_start].reg); + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + { + grub_addr_t fstart, fend; + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + grub_dprintf ("relocator", "requesting %lx-%lx\n", + (unsigned long) fstart, + (unsigned long) fend); + /* The failure here can be very expensive. */ + if (!grub_relocator_firmware_alloc_region (fstart, + fend - fstart)) + { + if (from_low_priv) + start = fend; + else + end = fstart; + goto retry; + } + break; + } +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case CHUNK_TYPE_LEFTOVER: + { + unsigned offstart = alloc_start + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + unsigned offend = alloc_end + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + struct grub_relocator_fw_leftover *lo + = events[last_start].leftover; + lo->freebytes[offstart / 8] + &= ((1 << (8 - (start % 8))) - 1); + grub_memset (lo->freebytes + (offstart + 7) / 8, 0, + offend / 8 - (offstart + 7) / 8); + lo->freebytes[offend / 8] &= ~((1 << (offend % 8)) - 1); + } + break; +#endif + } + nallocs++; + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + if (regbeg) + regbeg--; + else + inreg--; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + + } + } + + /* Malloc is available again. */ + grub_mm_base = base_saved; + + { + int last_start = 0; + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwlefto = 0, fwb = 0; +#endif + unsigned cural = 0; + int oom = 0; + res->subchunks = grub_malloc (sizeof (res->subchunks[0]) * nallocs); + if (!res->subchunks) + oom = 1; + res->nsubchunks = nallocs; + + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + struct grub_relocator_subchunk tofree; + struct grub_relocator_subchunk *curschu = &tofree; + if (!oom) + curschu = &res->subchunks[cural]; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { + grub_dprintf ("relocator", "subchunk 0x%lx-0x%lx, %d\n", + (unsigned long) alloc_start, + (unsigned long) alloc_end, typepre); + curschu->type = typepre; + curschu->start = alloc_start; + curschu->size = alloc_end - alloc_start; + if (typepre == CHUNK_TYPE_REGION_START + || typepre == CHUNK_TYPE_IN_REGION) + { + curschu->reg = events[last_start].reg; + curschu->head = events[last_start].head; + curschu->pre_size = alloc_start - events[j - 1].pos; + } + if (!oom && (typepre == CHUNK_TYPE_REGION_START +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + || typepre == CHUNK_TYPE_FIRMWARE +#endif + )) + { + struct grub_relocator_extra_block *ne; + ne = grub_malloc (sizeof (*ne)); + if (!ne) + { + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + } + else + { + ne->start = alloc_start; + ne->end = alloc_end; + ne->next = extra_blocks; + ne->prev = &extra_blocks; + if (extra_blocks) + extra_blocks->prev = &(ne->next); + extra_blocks = ne; + curschu->extra = ne; + } + } +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + if (!oom && typepre == CHUNK_TYPE_FIRMWARE) + { + grub_addr_t fstart, fend; + + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *lo1 = NULL; + struct grub_relocator_fw_leftover *lo2 = NULL; + if (fstart != alloc_start) + lo1 = grub_malloc (sizeof (*lo1)); + if (fend != alloc_end) + lo2 = grub_malloc (sizeof (*lo2)); + if ((!lo1 && fstart != alloc_start) + || (!lo2 && fend != alloc_end)) + { + struct grub_relocator_extra_block *ne; + grub_free (lo1); + grub_free (lo2); + lo1 = NULL; + lo2 = NULL; + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + ne = extra_blocks; + extra_blocks = extra_blocks->next; + grub_free (ne); + } + if (lo1) + { + lo1->quantstart = fstart; + grub_memset (lo1->freebytes, 0xff, + (alloc_start - fstart) / 8); + lo1->freebytes[(alloc_start - fstart) / 8] + = (1 << ((alloc_start - fstart) % 8)) - 1; + grub_memset (lo1->freebytes + + ((alloc_start - fstart) / 8) + 1, 0, + sizeof (lo1->freebytes) + - (alloc_start - fstart) / 8 - 1); + lo1->next = leftovers; + lo1->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo1->next; + leftovers = lo1; + } + if (lo2) + { + lo2->quantstart + = fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (lo2->freebytes, 0, + (alloc_end - lo2->quantstart) / 8); + lo2->freebytes[(alloc_end - lo2->quantstart) / 8] + = ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1); + grub_memset (lo2->freebytes + + ((alloc_end - lo2->quantstart) / 8) + + 1, 0, sizeof (lo2->freebytes) + - (alloc_end - lo2->quantstart) / 8 - 1); + lo2->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo2->next; + lo2->next = leftovers; + leftovers = lo2; + } + curschu->pre = lo1; + curschu->post = lo2; + } +#endif + } + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (typepre == CHUNK_TYPE_LEFTOVER) + { + curschu->pre = events[last_start].leftover; + curschu->post = events[last_start].leftover; + } +#endif + +#endif + if (!oom) + cural++; + else + free_subchunk (&tofree); + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + inreg = regbeg = 0; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + } + if (oom) + { + unsigned i; + for (i = 0; i < cural; i++) + free_subchunk (&res->subchunks[i]); + grub_free (res->subchunks); + grub_dprintf ("relocator", "allocation failed with out-of-memory\n"); + return 0; + } + } + + res->src = target; + res->size = size; + grub_dprintf ("relocator", "allocated: 0x%lx+0x%lx\n", (unsigned long) target, + (unsigned long) size); + + return 1; +} + +static void +adjust_limits (struct grub_relocator *rel, + grub_phys_addr_t *min_addr, grub_phys_addr_t *max_addr, + grub_phys_addr_t in_min, grub_phys_addr_t in_max) +{ + struct grub_relocator_chunk *chunk; + + *min_addr = 0; + *max_addr = rel->postchunks; + + /* Keep chunks in memory in the same order as they'll be after relocation. */ + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + if (chunk->target > in_max && chunk->src < *max_addr + && chunk->src < rel->postchunks) + *max_addr = chunk->src; + if (chunk->target + chunk->size <= in_min + && chunk->src + chunk->size > *min_addr + && chunk->src < rel->postchunks) + *min_addr = chunk->src + chunk->size; + } +} + +grub_err_t +grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t target, grub_size_t size) +{ + struct grub_relocator_chunk *chunk; + grub_phys_addr_t min_addr = 0, max_addr; + + if (target > ~size) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "address is out of range"); + + adjust_limits (rel, &min_addr, &max_addr, target, target); + + for (chunk = rel->chunks; chunk; chunk = chunk->next) + if ((chunk->target <= target && target < chunk->target + chunk->size) + || (target <= chunk->target && chunk->target < target + size)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "overlap detected"); + + chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!chunk) + return grub_errno; + + grub_dprintf ("relocator", + "min_addr = 0x%llx, max_addr = 0x%llx, target = 0x%llx\n", + (unsigned long long) min_addr, (unsigned long long) max_addr, + (unsigned long long) target); + + do + { + /* A trick to improve Linux allocation. */ +#if defined (__i386__) || defined (__x86_64__) + if (target < 0x100000) + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } +#endif + if (malloc_in_range (rel, target, max_addr, 1, size, chunk, 1, 0)) + break; + + if (malloc_in_range (rel, min_addr, target, 1, size, chunk, 0, 0)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } + + grub_dprintf ("relocator", "not allocated\n"); + grub_free (chunk); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + } + while (0); + + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) chunk->src, (unsigned long long) target); + + if (rel->highestaddr < target + size) + rel->highestaddr = target + size; + + if (rel->highestaddr < chunk->src + size) + rel->highestaddr = chunk->src + size; + + if (chunk->src < rel->postchunks) + { + if (rel->highestnonpostaddr < target + size) + rel->highestnonpostaddr = target + size; + + if (rel->highestnonpostaddr < chunk->src + size) + rel->highestnonpostaddr = chunk->src + size; + } + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + if (chunk->src < target) + rel->relocators_size += grub_relocator_backward_size; + if (chunk->src > target) + rel->relocators_size += grub_relocator_forward_size; + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + chunk->target = target; + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; +#ifdef DEBUG_RELOCATOR + { + grub_mm_region_t r; + grub_mm_header_t p; + grub_memset (chunk->srcv, 0xfa, chunk->size); + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal (__FILE__ ":%d: out of range pointer: %p\n", __LINE__, p); + p = p->next; + } + while (p != r->first); + } + } +#endif return GRUB_ERR_NONE; } + +grub_err_t +grub_relocator_alloc_chunk_align (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, + grub_size_t size, grub_size_t align, + int preference) +{ + grub_addr_t min_addr2 = 0, max_addr2; + struct grub_relocator_chunk *chunk; + + if (max_addr > ~size) + max_addr = ~size; + +#ifdef GRUB_MACHINE_PCBIOS + if (min_addr < 0x1000) + min_addr = 0x1000; +#endif + + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + + chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!chunk) + return grub_errno; + + if (malloc_in_range (rel, min_addr, max_addr, align, + size, chunk, + preference != GRUB_RELOCATOR_PREFERENCE_HIGH, 1)) + { + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) chunk->src, + (unsigned long long) chunk->src); + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + chunk->target = chunk->src; + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; + return GRUB_ERR_NONE; + } + + adjust_limits (rel, &min_addr2, &max_addr2, min_addr, max_addr); + grub_dprintf ("relocator", "Adjusted limits from %lx-%lx to %lx-%lx\n", + (unsigned long) min_addr, (unsigned long) max_addr, + (unsigned long) min_addr2, (unsigned long) max_addr2); + + do + { + if (malloc_in_range (rel, min_addr2, max_addr2, align, + size, chunk, 1, 1)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } + + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + } + while (0); + + { + int found = 0; + 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 sz, grub_uint32_t type) + { + grub_uint64_t candidate; + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + candidate = ALIGN_UP (addr, align); + if (candidate < min_addr) + candidate = ALIGN_UP (min_addr, align); + if (candidate + size > addr + sz + || candidate > ALIGN_DOWN (max_addr, align)) + return 0; + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + candidate = ALIGN_DOWN (min (addr + sz - size, max_addr), align); + if (!found || (preference == GRUB_RELOCATOR_PREFERENCE_HIGH + && candidate > chunk->target)) + chunk->target = candidate; + if (!found || (preference == GRUB_RELOCATOR_PREFERENCE_LOW + && candidate < chunk->target)) + chunk->target = candidate; + found = 1; + return 0; + } + + grub_machine_mmap_iterate (hook); + if (!found) + return grub_error (GRUB_ERR_BAD_OS, "couldn't find suitable memory target"); + } + while (1) + { + struct grub_relocator_chunk *chunk2; + for (chunk2 = rel->chunks; chunk2; chunk2 = chunk2->next) + if ((chunk2->target <= chunk->target + && chunk->target < chunk2->target + chunk2->size) + || (chunk2->target <= chunk->target + size + && chunk->target + size < chunk2->target + chunk2->size) + || (chunk->target <= chunk2->target && chunk2->target + < chunk->target + size) + || (chunk->target <= chunk2->target + chunk2->size + && chunk2->target + chunk2->size < chunk->target + size)) + { + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + chunk->target = ALIGN_DOWN (chunk2->target, align); + else + chunk->target = ALIGN_UP (chunk2->target + chunk2->size, align); + break; + } + if (!chunk2) + break; + } + + if (chunk->src < chunk->target) + rel->relocators_size += grub_relocator_backward_size; + if (chunk->src > chunk->target) + rel->relocators_size += grub_relocator_forward_size; + + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; +#ifdef DEBUG_RELOCATOR + { + grub_mm_region_t r; + grub_mm_header_t p; + + grub_memset (chunk->srcv, 0xfa, chunk->size); + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal (__FILE__ "%d: out of range pointer: %p\n", __LINE__, p); + p = p->next; + } + while (p != r->first); + } + } +#endif + return GRUB_ERR_NONE; +} + +void +grub_relocator_unload (struct grub_relocator *rel) +{ + struct grub_relocator_chunk *chunk, *next; + if (!rel) + return; + for (chunk = rel->chunks; chunk; chunk = next) + { + unsigned i; + for (i = 0; i < chunk->nsubchunks; i++) + free_subchunk (&chunk->subchunks[i]); + grub_unmap_memory (chunk->srcv, chunk->size); + next = chunk->next; + grub_free (chunk->subchunks); + grub_free (chunk); + } + grub_free (rel); +} + +grub_err_t +grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, + void **relstart, grub_size_t *relsize) +{ + grub_uint8_t *rels; + grub_uint8_t *rels0; + struct grub_relocator_chunk *sorted; + grub_size_t nchunks = 0; + unsigned j; + struct grub_relocator_chunk movers_chunk; + + grub_dprintf ("relocator", "Preparing relocs (size=%ld)\n", + (unsigned long) rel->relocators_size); + + if (!malloc_in_range (rel, 0, ~(grub_addr_t)0 - rel->relocators_size + 1, + grub_relocator_align, + rel->relocators_size, &movers_chunk, 1, 1)) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + rels = rels0 = grub_map_memory (movers_chunk.src, movers_chunk.size); + + if (relsize) + *relsize = rel->relocators_size; + + grub_dprintf ("relocator", "Relocs allocated at %p\n", movers_chunk.srcv); + + { + unsigned i; + grub_size_t count[257]; + struct grub_relocator_chunk *from, *to, *tmp; + + grub_memset (count, 0, sizeof (count)); + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + grub_dprintf ("relocator", "chunk %p->%p, 0x%lx\n", + (void *) chunk->src, (void *) chunk->target, + (unsigned long) chunk->size); + nchunks++; + count[(chunk->src & 0xff) + 1]++; + } + } + from = grub_malloc (nchunks * sizeof (sorted[0])); + to = grub_malloc (nchunks * sizeof (sorted[0])); + if (!from || !to) + { + grub_free (from); + grub_free (to); + return grub_errno; + } + + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + from[count[chunk->src & 0xff]++] = *chunk; + } + + for (i = 1; i < GRUB_CPU_SIZEOF_VOID_P; i++) + { + grub_memset (count, 0, sizeof (count)); + for (j = 0; j < nchunks; j++) + count[((from[j].src >> (8 * i)) & 0xff) + 1]++; + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + for (j = 0; j < nchunks; j++) + to[count[(from[j].src >> (8 * i)) & 0xff]++] = from[j]; + tmp = to; + to = from; + from = tmp; + } + sorted = from; + grub_free (to); + } + + for (j = 0; j < nchunks; j++) + { + grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n", + (void *) sorted[j].src, (void *) sorted[j].target, + (unsigned long) sorted[j].size); + if (sorted[j].src < sorted[j].target) + { + grub_cpu_relocator_backward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_backward_size; + } + if (sorted[j].src > sorted[j].target) + { + grub_cpu_relocator_forward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_forward_size; + } + if (sorted[j].src == sorted[j].target) + grub_arch_sync_caches (sorted[j].srcv, sorted[j].size); + } + grub_cpu_relocator_jumper ((void *) rels, (grub_addr_t) addr); + *relstart = rels0; + grub_free (sorted); + return GRUB_ERR_NONE; +} + +void +grub_mm_check_real (char *file, int line) +{ + grub_mm_region_t r; + grub_mm_header_t p, pa; + + for (r = grub_mm_base; r; r = r->next) + { + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%s:%d: out of range pointer: %p\n", file, line, p); + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal ("%s:%d free magic broken at %p (0x%x)\n", file, + line, p, p->magic); + pa = p; + p = pa->next; + } + while (pa != r->first); + } +} diff --git a/grub-core/lib/x86_64/relocator_asm.S b/grub-core/lib/x86_64/relocator_asm.S new file mode 100644 index 000000000..2ab6d8cb7 --- /dev/null +++ b/grub-core/lib/x86_64/relocator_asm.S @@ -0,0 +1,85 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + + .p2align 2 + +VARIABLE(grub_relocator_backward_start) + /* mov imm32, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_backward_dest) + .long 0, 0 + movq %rax, %rdi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_backward_src) + .long 0, 0 + movq %rax, %rsi + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator_backward_chunk_size) + .long 0, 0 + + add %rcx, %rsi + add %rcx, %rdi + + /* Backward movsb is implicitly off-by-one. compensate that. */ + sub $1, %rsi + sub $1, %rdi + + /* Backward copy. */ + std + + rep + movsb +VARIABLE(grub_relocator_backward_end) + + +VARIABLE(grub_relocator_forward_start) + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_forward_dest) + .long 0, 0 + movq %rax, %rdi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_forward_src) + .long 0, 0 + movq %rax, %rsi + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator_forward_chunk_size) + .long 0, 0 + + /* Forward copy. */ + cld + rep + movsb +VARIABLE(grub_relocator_forward_end) diff --git a/grub-core/loader/aout.c b/grub-core/loader/aout.c index 0254b6ae0..611960f92 100644 --- a/grub-core/loader/aout.c +++ b/grub-core/loader/aout.c @@ -39,9 +39,8 @@ grub_aout_get_type (union grub_aout_header *header) grub_err_t grub_aout_load (grub_file_t file, int offset, - grub_addr_t load_addr, - int load_size, - grub_addr_t bss_end_addr) + void *load_addr, + int load_size, grub_size_t bss_size) { if ((grub_file_seek (file, offset)) == (grub_off_t) - 1) return grub_errno; @@ -49,14 +48,13 @@ grub_aout_load (grub_file_t file, int offset, if (!load_size) load_size = file->size - offset; - grub_file_read (file, (void *) load_addr, load_size); + grub_file_read (file, load_addr, load_size); if (grub_errno) return grub_errno; - if (bss_end_addr) - grub_memset ((char *) load_addr + load_size, 0, - bss_end_addr - load_addr - load_size); + if (bss_size) + grub_memset ((char *) load_addr + load_size, 0, bss_size); return GRUB_ERR_NONE; } diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 3c7fe2fee..cfea3b6a1 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -17,10 +17,8 @@ */ #include -#include -#include +#include #include -#include #include #include #include @@ -35,30 +33,63 @@ #include #include #include +#include + #include #ifdef GRUB_MACHINE_PCBIOS #include #endif +#ifdef GRUB_MACHINE_EFI +#include +#define NETBSD_DEFAULT_VIDEO_MODE "800x600" +#else +#define NETBSD_DEFAULT_VIDEO_MODE "text" +#include +#endif +#include + #include #include #include +#include +#include #define ALIGN_DWORD(a) ALIGN_UP (a, 4) #define ALIGN_QWORD(a) ALIGN_UP (a, 8) #define ALIGN_VAR(a) ((is_64bit) ? (ALIGN_QWORD(a)) : (ALIGN_DWORD(a))) #define ALIGN_PAGE(a) ALIGN_UP (a, 4096) -#define MOD_BUF_ALLOC_UNIT 4096 - static int kernel_type = KERNEL_TYPE_NONE; static grub_dl_t my_mod; static grub_addr_t entry, entry_hi, kern_start, kern_end; +static void *kern_chunk_src; static grub_uint32_t bootflags; -static char *mod_buf; -static grub_uint32_t mod_buf_len, mod_buf_max, kern_end_mdofs; static int is_elf_kernel, is_64bit; -static char *netbsd_root = NULL; static grub_uint32_t openbsd_root; +struct grub_relocator *relocator = NULL; +static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk; + +struct bsd_tag +{ + struct bsd_tag *next; + grub_size_t len; + grub_uint32_t type; + union { + grub_uint8_t a; + grub_uint16_t b; + grub_uint32_t c; + } data[0]; +}; + +static struct bsd_tag *tags, *tags_last; + +struct netbsd_module +{ + struct netbsd_module *next; + struct grub_netbsd_btinfo_module mod; +}; + +static struct netbsd_module *netbsd_mods, *netbsd_mods_last; static const struct grub_arg_option freebsd_opts[] = { @@ -96,6 +127,8 @@ static const struct grub_arg_option openbsd_opts[] = {"single", 's', 0, N_("Boot into single mode."), 0, 0}, {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0}, {"root", 'r', 0, N_("Set root device."), "wdXY", ARG_TYPE_STRING}, + {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, + N_("Use serial console."), N_("comUNIT[,SPEED]"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -106,6 +139,7 @@ static const grub_uint32_t openbsd_flags[] = }; #define OPENBSD_ROOT_ARG (ARRAY_SIZE (openbsd_flags) - 1) +#define OPENBSD_SERIAL_ARG (ARRAY_SIZE (openbsd_flags)) static const struct grub_arg_option netbsd_opts[] = { @@ -122,6 +156,8 @@ static const struct grub_arg_option netbsd_opts[] = {"debug", 'x', 0, N_("Boot with debug messages."), 0, 0}, {"silent", 'z', 0, N_("Supress normal output (warnings remain)."), 0, 0}, {"root", 'r', 0, N_("Set root device."), N_("DEVICE"), ARG_TYPE_STRING}, + {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, + N_("Use serial console."), N_("[ADDR|comUNIT][,SPEED]"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -134,6 +170,7 @@ static const grub_uint32_t netbsd_flags[] = }; #define NETBSD_ROOT_ARG (ARRAY_SIZE (netbsd_flags) - 1) +#define NETBSD_SERIAL_ARG (ARRAY_SIZE (netbsd_flags)) static void grub_bsd_get_device (grub_uint32_t * biosdev, @@ -166,36 +203,42 @@ grub_bsd_get_device (grub_uint32_t * biosdev, } grub_err_t -grub_freebsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len) +grub_bsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len) { - if (mod_buf_max < mod_buf_len + len + 8) + struct bsd_tag *newtag; + + newtag = grub_malloc (len + sizeof (struct bsd_tag)); + if (!newtag) + return grub_errno; + newtag->len = len; + newtag->type = type; + newtag->next = NULL; + if (len) + grub_memcpy (newtag->data, data, len); + + if (kernel_type == KERNEL_TYPE_FREEBSD + && type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP)) { - char *new_buf; + struct bsd_tag *p; + for (p = tags; + p->type != (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND); + p = p->next); - do + if (p) { - mod_buf_max += MOD_BUF_ALLOC_UNIT; + newtag->next = p->next; + p->next = newtag; + if (newtag->next == NULL) + tags_last = newtag; + return GRUB_ERR_NONE; } - while (mod_buf_max < mod_buf_len + len + 8); - - new_buf = grub_malloc (mod_buf_max); - if (!new_buf) - return grub_errno; - - grub_memcpy (new_buf, mod_buf, mod_buf_len); - grub_free (mod_buf); - - mod_buf = new_buf; } - *((grub_uint32_t *) (mod_buf + mod_buf_len)) = type; - *((grub_uint32_t *) (mod_buf + mod_buf_len + 4)) = len; - mod_buf_len += 8; - - if (len) - grub_memcpy (mod_buf + mod_buf_len, data, len); - - mod_buf_len = ALIGN_VAR (mod_buf_len + len); + if (tags_last) + tags_last->next = newtag; + else + tags = newtag; + tags_last = newtag; return GRUB_ERR_NONE; } @@ -212,100 +255,133 @@ struct grub_e820_mmap #define GRUB_E820_NVS 4 #define GRUB_E820_EXEC_CODE 5 -static grub_err_t -grub_freebsd_add_mmap (void) +static void +generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf) { - grub_size_t len = 0; - struct grub_e820_mmap *mmap_buf = 0; - struct grub_e820_mmap *mmap = 0; - int isfirstrun = 1; + int count = 0; + struct grub_e820_mmap *mmap = buf; + struct grub_e820_mmap prev, cur; 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) { - /* FreeBSD assumes that first 64KiB are available. - Not always true but try to prevent panic somehow. */ - if (isfirstrun && addr != 0) + cur.addr = addr; + cur.size = size; + switch (type) { - if (mmap) - { - mmap->addr = 0; - mmap->size = (addr < 0x10000) ? addr : 0x10000; - mmap->type = GRUB_E820_RAM; - mmap++; - } - else - len += sizeof (struct grub_e820_mmap); - } - isfirstrun = 0; - if (mmap) - { - mmap->addr = addr; - mmap->size = size; - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - mmap->type = GRUB_E820_RAM; - break; + case GRUB_MACHINE_MEMORY_AVAILABLE: + cur.type = GRUB_E820_RAM; + break; #ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: - mmap->type = GRUB_E820_ACPI; - break; + case GRUB_MACHINE_MEMORY_ACPI: + cur.type = GRUB_E820_ACPI; + break; #endif #ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: - mmap->type = GRUB_E820_NVS; - break; + case GRUB_MACHINE_MEMORY_NVS: + cur.type = GRUB_E820_NVS; + break; #endif - default: + default: #ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: + case GRUB_MACHINE_MEMORY_CODE: #endif #ifdef GRUB_MACHINE_MEMORY_RESERVED - case GRUB_MACHINE_MEMORY_RESERVED: + case GRUB_MACHINE_MEMORY_RESERVED: #endif - mmap->type = GRUB_E820_RESERVED; - break; - } + cur.type = GRUB_E820_RESERVED; + break; + } - /* Merge regions if possible. */ - if (mmap != mmap_buf && mmap->type == mmap[-1].type && - mmap->addr == mmap[-1].addr + mmap[-1].size) - mmap[-1].size += mmap->size; - else - mmap++; + /* Merge regions if possible. */ + if (count && cur.type == prev.type && cur.addr == prev.addr + prev.size) + { + prev.size += cur.size; + if (mmap) + mmap[-1] = prev; } else - len += sizeof (struct grub_e820_mmap); + { + if (mmap) + *mmap++ = cur; + prev = cur; + count++; + } + + if (kernel_type == KERNEL_TYPE_OPENBSD && prev.addr < 0x100000 + && prev.addr + prev.size > 0x100000) + { + cur.addr = 0x100000; + cur.size = prev.addr + prev.size - 0x100000; + cur.type = prev.type; + prev.size = 0x100000 - prev.addr; + if (mmap) + { + mmap[-1] = prev; + mmap[0] = cur; + mmap++; + } + prev = cur; + count++; + } return 0; } grub_mmap_iterate (hook); - mmap_buf = mmap = grub_malloc (len); - if (! mmap) + + if (len) + *len = count * sizeof (struct grub_e820_mmap); + *cnt = count; + + return; +} + +static grub_err_t +grub_bsd_add_mmap (void) +{ + grub_size_t len, cnt; + void *buf = NULL, *buf0; + + generate_e820_mmap (&len, &cnt, buf); + + if (kernel_type == KERNEL_TYPE_NETBSD) + len += sizeof (grub_uint32_t); + + if (kernel_type == KERNEL_TYPE_OPENBSD) + len += sizeof (struct grub_e820_mmap); + + buf = grub_malloc (len); + if (!buf) return grub_errno; - isfirstrun = 1; - grub_mmap_iterate (hook); + buf0 = buf; + if (kernel_type == KERNEL_TYPE_NETBSD) + { + *(grub_uint32_t *) buf = cnt; + buf = ((grub_uint32_t *) buf + 1); + } - len = (mmap - mmap_buf) * sizeof (struct grub_e820_mmap); - int i; - for (i = 0; i < mmap - mmap_buf; i++) - grub_dprintf ("bsd", "smap %d, %d:%llx - %llx\n", i, - mmap_buf[i].type, - (unsigned long long) mmap_buf[i].addr, - (unsigned long long) mmap_buf[i].size); + generate_e820_mmap (NULL, &cnt, buf); - grub_dprintf ("bsd", "%d entries in smap\n", mmap - mmap_buf); - grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_SMAP, mmap_buf, len); + if (kernel_type == KERNEL_TYPE_OPENBSD) + grub_memset ((grub_uint8_t *) buf + len - sizeof (struct grub_e820_mmap), 0, + sizeof (struct grub_e820_mmap)); - grub_free (mmap_buf); + grub_dprintf ("bsd", "%u entries in smap\n", (unsigned) cnt); + if (kernel_type == KERNEL_TYPE_NETBSD) + grub_bsd_add_meta (NETBSD_BTINFO_MEMMAP, buf0, len); + else if (kernel_type == KERNEL_TYPE_OPENBSD) + grub_bsd_add_meta (OPENBSD_BOOTARG_MMAP, buf0, len); + else + grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_SMAP, buf0, len); + + grub_free (buf0); return grub_errno; } @@ -323,29 +399,22 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, if (grub_strcmp (type, "/boot/zfs/zpool.cache") == 0) name = "/boot/zfs/zpool.cache"; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_NAME, name, - grub_strlen (name) + 1)) + if (grub_bsd_add_meta (FREEBSD_MODINFO_NAME, name, grub_strlen (name) + 1)) return grub_errno; if (is_64bit) { grub_uint64_t addr64 = addr, size64 = size; - if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type, - grub_strlen (type) + 1)) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, - sizeof (addr64))) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, - sizeof (size64)))) + if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1) + || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, sizeof (addr64)) + || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, sizeof (size64))) return grub_errno; } else { - if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type, - grub_strlen (type) + 1)) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, - sizeof (addr))) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size, - sizeof (size)))) + if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1) + || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, sizeof (addr)) + || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size, sizeof (size))) return grub_errno; } @@ -372,7 +441,7 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, } *p = 0; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n)) + if (grub_bsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n)) return grub_errno; } } @@ -383,27 +452,23 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, static void grub_freebsd_list_modules (void) { - grub_uint32_t pos = 0; + struct bsd_tag *tag; grub_printf (" %-18s %-18s%14s%14s\n", "name", "type", "addr", "size"); - while (pos < mod_buf_len) - { - grub_uint32_t type, size; - type = *((grub_uint32_t *) (mod_buf + pos)); - size = *((grub_uint32_t *) (mod_buf + pos + 4)); - pos += 8; - switch (type) + for (tag = tags; tag; tag = tag->next) + { + switch (tag->type) { case FREEBSD_MODINFO_NAME: case FREEBSD_MODINFO_TYPE: - grub_printf (" %-18s", mod_buf + pos); + grub_printf (" %-18s", (char *) tag->data); break; case FREEBSD_MODINFO_ADDR: { - grub_addr_t addr; + grub_uint32_t addr; - addr = *((grub_addr_t *) (mod_buf + pos)); + addr = *((grub_uint32_t *) tag->data); grub_printf (" 0x%08x", addr); break; } @@ -411,41 +476,93 @@ grub_freebsd_list_modules (void) { grub_uint32_t len; - len = *((grub_uint32_t *) (mod_buf + pos)); + len = *((grub_uint32_t *) tag->data); grub_printf (" 0x%08x\n", len); } } - - pos = ALIGN_VAR (pos + size); } } +static grub_err_t +grub_netbsd_add_meta_module (char *filename, grub_uint32_t type, + grub_addr_t addr, grub_uint32_t size) +{ + char *name; + struct netbsd_module *mod; + name = grub_strrchr (filename, '/'); + + if (name) + name++; + else + name = filename; + + mod = grub_zalloc (sizeof (*mod)); + if (!mod) + return grub_errno; + + grub_strncpy (mod->mod.name, name, sizeof (mod->mod.name) - 1); + mod->mod.addr = addr; + mod->mod.type = type; + mod->mod.size = size; + + if (netbsd_mods_last) + netbsd_mods_last->next = mod; + else + netbsd_mods = mod; + netbsd_mods_last = mod; + + return GRUB_ERR_NONE; +} + +static void +grub_netbsd_list_modules (void) +{ + struct netbsd_module *mod; + + grub_printf (" %-18s%14s%14s%14s\n", "name", "type", "addr", "size"); + + for (mod = netbsd_mods; mod; mod = mod->next) + grub_printf (" %-18s 0x%08x 0x%08x 0x%08x", mod->mod.name, + mod->mod.type, mod->mod.addr, mod->mod.size); +} + /* This function would be here but it's under different license. */ #include "bsd_pagetable.c" -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - static grub_err_t grub_freebsd_boot (void) { struct grub_freebsd_bootinfo bi; - char *p; + grub_uint8_t *p, *p0; + grub_addr_t p_target; + grub_size_t p_size = 0; grub_uint32_t bootdev, biosdev, unit, slice, part; + grub_err_t err; + grub_size_t tag_buf_len = 0; auto int iterate_env (struct grub_env_var *var); int iterate_env (struct grub_env_var *var) { if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1])) { - grub_strcpy (p, &var->name[sizeof("kFreeBSD.") - 1]); - p += grub_strlen (p); + grub_strcpy ((char *) p, &var->name[sizeof("kFreeBSD.") - 1]); + p += grub_strlen ((char *) p); *(p++) = '='; - grub_strcpy (p, var->value); - p += grub_strlen (p) + 1; + grub_strcpy ((char *) p, var->value); + p += grub_strlen ((char *) p) + 1; + } + + return 0; + } + + auto int iterate_env_count (struct grub_env_var *var); + int iterate_env_count (struct grub_env_var *var) + { + if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1])) + { + p_size += grub_strlen (&var->name[sizeof("kFreeBSD.") - 1]); + p_size++; + p_size += grub_strlen (var->value) + 1; } return 0; @@ -461,41 +578,102 @@ grub_freebsd_boot (void) bi.boot_device = biosdev; - p = (char *) kern_end; + p_size = 0; + grub_env_iterate (iterate_env_count); + + if (p_size) + p_size = ALIGN_PAGE (kern_end + p_size + 1) - kern_end; + + if (is_elf_kernel) + { + struct bsd_tag *tag; + + err = grub_bsd_add_mmap (); + if (err) + return err; + + err = grub_bsd_add_meta (FREEBSD_MODINFO_END, 0, 0); + if (err) + return err; + + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct freebsd_tag_header) + + tag->len); + p_size = ALIGN_PAGE (kern_end + p_size + tag_buf_len) - kern_end; + } + + if (is_64bit) + p_size += 4096 * 3; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_end, p_size); + if (err) + return err; + p = get_virtual_current_address (ch); + } + p_target = kern_end; + p0 = p; + kern_end += p_size; grub_env_iterate (iterate_env); - if (p != (char *) kern_end) + if (p != p0) { *(p++) = 0; - bi.environment = kern_end; - kern_end = ALIGN_PAGE ((grub_uint32_t) p); + bi.environment = p_target; } if (is_elf_kernel) { - grub_addr_t md_ofs; - int ofs; + grub_uint8_t *p_tag = p; + struct bsd_tag *tag; + + for (tag = tags; tag; tag = tag->next) + { + struct freebsd_tag_header *head + = (struct freebsd_tag_header *) p_tag; + head->type = tag->type; + head->len = tag->len; + p_tag += sizeof (struct freebsd_tag_header); + switch (tag->type) + { + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_HOWTO: + if (is_64bit) + *(grub_uint64_t *) p_tag = bootflags; + else + *(grub_uint32_t *) p_tag = bootflags; + break; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_END, 0, 0)) - return grub_errno; + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP: + if (is_64bit) + *(grub_uint64_t *) p_tag = bi.environment; + else + *(grub_uint32_t *) p_tag = bi.environment; + break; - grub_memcpy ((char *) kern_end, mod_buf, mod_buf_len); - bi.tags = kern_end; + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND: + if (is_64bit) + *(grub_uint64_t *) p_tag = kern_end; + else + *(grub_uint32_t *) p_tag = kern_end; + break; - kern_end = ALIGN_PAGE (kern_end + mod_buf_len); + default: + grub_memcpy (p_tag, tag->data, tag->len); + break; + } + p_tag += tag->len; + p_tag = ALIGN_VAR (p_tag - p) + p; + } - if (is_64bit) - kern_end += 4096 * 4; + bi.tags = (p - p0) + p_target; - md_ofs = bi.tags + kern_end_mdofs; - ofs = (is_64bit) ? 16 : 12; - *((grub_uint32_t *) md_ofs) = kern_end; - md_ofs -= ofs; - *((grub_uint32_t *) md_ofs) = bi.environment; - md_ofs -= ofs; - *((grub_uint32_t *) md_ofs) = bootflags; + p = (ALIGN_PAGE ((p_tag - p0) + p_target) - p_target) + p0; } bi.kern_end = kern_end; @@ -504,53 +682,81 @@ grub_freebsd_boot (void) if (is_64bit) { - grub_uint32_t *gdt; - grub_uint8_t *trampoline; - void (*launch_trampoline) (grub_addr_t entry_lo, ...) - __attribute__ ((cdecl, regparm (0))); + struct grub_relocator64_state state; grub_uint8_t *pagetable; + grub_uint32_t *stack; + grub_addr_t stack_target; - struct gdt_descriptor *gdtdesc; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x10000, 0x90000, + 3 * sizeof (grub_uint32_t) + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } - pagetable = (grub_uint8_t *) (kern_end - 16384); - fill_bsd64_pagetable (pagetable); +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - /* Create GDT. */ - gdt = (grub_uint32_t *) (kern_end - 4096); - gdt[0] = 0; - gdt[1] = 0; - gdt[2] = 0; - gdt[3] = 0x00209800; - gdt[4] = 0; - gdt[5] = 0x00008000; + pagetable = p; + fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target); - /* Create GDT descriptor. */ - gdtdesc = (struct gdt_descriptor *) (kern_end - 4096 + 24); - gdtdesc->limit = 24; - gdtdesc->base = gdt; + state.cr3 = (pagetable - p0) + p_target; + state.rsp = stack_target; + state.rip = (((grub_uint64_t) entry_hi) << 32) | entry; - /* Prepare trampoline. */ - trampoline = (grub_uint8_t *) (kern_end - 4096 + 24 - + sizeof (struct gdt_descriptor)); - launch_trampoline = (void __attribute__ ((cdecl, regparm (0))) - (*) (grub_addr_t entry_lo, ...)) trampoline; - grub_bsd64_trampoline_gdt = (grub_uint32_t) gdtdesc; - grub_bsd64_trampoline_selfjump - = (grub_uint32_t) (trampoline + 6 - + ((grub_uint8_t *) &grub_bsd64_trampoline_selfjump - - &grub_bsd64_trampoline_start)); - - /* Copy trampoline. */ - grub_memcpy (trampoline, &grub_bsd64_trampoline_start, - &grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start); - - /* Launch trampoline. */ - launch_trampoline (entry, entry_hi, pagetable, bi.tags, - kern_end); + stack[0] = entry; + stack[1] = bi.tags; + stack[2] = kern_end; + return grub_relocator64_boot (relocator, state, 0, 0x40000000); } else - grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev, - 0, 0, 0, &bi, bi.tags, kern_end); + { + struct grub_relocator32_state state; + grub_uint32_t *stack; + grub_addr_t stack_target; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x10000, 0x90000, + 9 * sizeof (grub_uint32_t) + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } + +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif + + grub_memcpy (&stack[9], &bi, sizeof (bi)); + state.eip = entry; + state.esp = stack_target; + stack[0] = entry; /* "Return" address. */ + stack[1] = bootflags | FREEBSD_RB_BOOTINFO; + stack[2] = bootdev; + stack[3] = 0; + stack[4] = 0; + stack[5] = 0; + stack[6] = stack_target + 9 * sizeof (grub_uint32_t); + stack[7] = bi.tags; + stack[8] = kern_end; + return grub_relocator32_boot (relocator, state); + } /* Not reached. */ return GRUB_ERR_NONE; @@ -559,180 +765,314 @@ grub_freebsd_boot (void) static grub_err_t grub_openbsd_boot (void) { - char *buf = (char *) GRUB_BSD_TEMP_BUFFER; - struct grub_openbsd_bios_mmap *pm; - struct grub_openbsd_bootargs *pa; + grub_uint32_t *stack; + struct grub_relocator32_state state; + void *curarg, *buf0, *arg0; + grub_addr_t buf_target; + grub_err_t err; + grub_size_t tag_buf_len; - 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) - { - pm->addr = addr; - pm->len = size; + err = grub_bsd_add_mmap (); + if (err) + return err; - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - pm->type = OPENBSD_MMAP_AVAILABLE; - break; + { + struct bsd_tag *tag; + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct grub_openbsd_bootargs) + + tag->len); + } - case GRUB_MACHINE_MEMORY_ACPI: - pm->type = OPENBSD_MMAP_ACPI; - break; + buf_target = GRUB_BSD_TEMP_BUFFER - 9 * sizeof (grub_uint32_t); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, buf_target, + tag_buf_len + + sizeof (struct grub_openbsd_bootargs) + + 9 * sizeof (grub_uint32_t)); + if (err) + return err; + buf0 = get_virtual_current_address (ch); + } - case GRUB_MACHINE_MEMORY_NVS: - pm->type = OPENBSD_MMAP_NVS; - break; + stack = (grub_uint32_t *) buf0; + arg0 = curarg = stack + 9; - default: - pm->type = OPENBSD_MMAP_RESERVED; - break; - } - pm++; + { + struct bsd_tag *tag; + struct grub_openbsd_bootargs *head; - return 0; - } - - pa = (struct grub_openbsd_bootargs *) buf; - - pa->ba_type = OPENBSD_BOOTARG_MMAP; - pm = (struct grub_openbsd_bios_mmap *) (pa + 1); - grub_mmap_iterate (hook); - - /* Memory map terminator. */ - pm->addr = 0; - pm->len = 0; - pm->type = 0; - pm++; - - pa->ba_size = (char *) pm - (char *) pa; - pa->ba_next = (struct grub_openbsd_bootargs *) pm; - pa = pa->ba_next; - pa->ba_type = OPENBSD_BOOTARG_END; - pa++; + for (tag = tags; tag; tag = tag->next) + { + head = curarg; + head->ba_type = tag->type; + head->ba_size = tag->len + sizeof (*head); + curarg = head + 1; + grub_memcpy (curarg, tag->data, tag->len); + curarg = (grub_uint8_t *) curarg + tag->len; + head->ba_next = (grub_uint8_t *) curarg - (grub_uint8_t *) buf0 + + buf_target; + } + head = curarg; + head->ba_type = OPENBSD_BOOTARG_END; + head->ba_size = 0; + head->ba_next = 0; + } grub_video_set_mode ("text", 0, 0); - grub_unix_real_boot (entry, bootflags, openbsd_root, OPENBSD_BOOTARG_APIVER, - 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), - (grub_uint32_t) (grub_mmap_get_lower () >> 10), - (char *) pa - buf, buf); +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - /* Not reached. */ - return GRUB_ERR_NONE; + state.eip = entry; + state.esp = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target; + stack[0] = entry; + stack[1] = bootflags; + stack[2] = openbsd_root; + stack[3] = OPENBSD_BOOTARG_APIVER; + stack[4] = 0; + stack[5] = grub_mmap_get_upper () >> 10; + stack[6] = grub_mmap_get_lower () >> 10; + stack[7] = (grub_uint8_t *) curarg - (grub_uint8_t *) arg0; + stack[8] = ((grub_uint8_t *) arg0 - (grub_uint8_t *) buf0) + buf_target; + + return grub_relocator32_boot (relocator, state); +} + +static grub_err_t +grub_netbsd_setup_video (void) +{ + struct grub_video_mode_info mode_info; + void *framebuffer; + const char *modevar; + struct grub_netbsd_btinfo_framebuf params; + grub_err_t err; + grub_video_driver_id_t driv_id; + + modevar = grub_env_get ("gfxpayload"); + + /* Now all graphical modes are acceptable. + May change in future if we have modes without framebuffer. */ + if (modevar && *modevar != 0) + { + char *tmp; + tmp = grub_xasprintf ("%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; + err = grub_video_set_mode (tmp, 0, 0); + grub_free (tmp); + } + else + err = grub_video_set_mode (NETBSD_DEFAULT_VIDEO_MODE, 0, 0); + + if (err) + return err; + + driv_id = grub_video_get_driver_id (); + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + + if (err) + return err; + + params.width = mode_info.width; + params.height = mode_info.height; + params.bpp = mode_info.bpp; + params.pitch = mode_info.pitch; + params.flags = 0; + + params.fbaddr = (grub_addr_t) framebuffer; + + params.red_mask_size = mode_info.red_mask_size; + params.red_field_pos = mode_info.red_field_pos; + params.green_mask_size = mode_info.green_mask_size; + params.green_field_pos = mode_info.green_field_pos; + params.blue_mask_size = mode_info.blue_mask_size; + params.blue_field_pos = mode_info.blue_field_pos; + +#ifdef GRUB_MACHINE_PCBIOS + /* VESA packed modes may come with zeroed mask sizes, which need + to be set here according to DAC Palette width. If we don't, + this results in Linux displaying a black screen. */ + if (mode_info.bpp <= 8 && driv_id == GRUB_VIDEO_DRIVER_VBE) + { + struct grub_vbe_info_block controller_info; + int status; + int width = 8; + + status = grub_vbe_bios_get_controller_info (&controller_info); + + if (status == GRUB_VBE_STATUS_OK && + (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)) + status = grub_vbe_bios_set_dac_palette_width (&width); + + if (status != GRUB_VBE_STATUS_OK) + /* 6 is default after mode reset. */ + width = 6; + + params.red_mask_size = params.green_mask_size + = params.blue_mask_size = width; + } +#endif + + err = grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, ¶ms, sizeof (params)); + return err; +} + +static grub_err_t +grub_netbsd_add_modules (void) +{ + struct netbsd_module *mod; + unsigned modcnt = 0; + struct grub_netbsd_btinfo_modules *mods; + unsigned i; + grub_err_t err; + + for (mod = netbsd_mods; mod; mod = mod->next) + modcnt++; + + mods = grub_malloc (sizeof (*mods) + sizeof (mods->mods[0]) * modcnt); + if (!mods) + return grub_errno; + + mods->num = modcnt; + mods->last_addr = kern_end; + for (mod = netbsd_mods, i = 0; mod; i++, mod = mod->next) + mods->mods[i] = mod->mod; + + err = grub_bsd_add_meta (NETBSD_BTINFO_MODULES, mods, + sizeof (*mods) + sizeof (mods->mods[0]) * modcnt); + grub_free (mods); + return err; } static grub_err_t grub_netbsd_boot (void) { struct grub_netbsd_bootinfo *bootinfo; - int count = 0; - struct grub_netbsd_btinfo_mmap_header *mmap; - struct grub_netbsd_btinfo_mmap_entry *pm; - void *curarg; + void *curarg, *arg0; + grub_addr_t arg_target, stack_target; + grub_uint32_t *stack; + grub_err_t err; + struct grub_relocator32_state state; + grub_size_t tag_buf_len = 0; + int tag_count = 0; + + err = grub_bsd_add_mmap (); + if (err) + return err; + + err = grub_netbsd_setup_video (); + if (err) + { + grub_print_error (); + grub_printf ("Booting however\n"); + grub_errno = GRUB_ERR_NONE; + } + + err = grub_netbsd_add_modules (); + if (err) + return err; - auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) { - count++; - return 0; - } - - 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) - { - pm->addr = addr; - pm->len = size; - - switch (type) + struct bsd_tag *tag; + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) { - case GRUB_MACHINE_MEMORY_AVAILABLE: - pm->type = NETBSD_MMAP_AVAILABLE; - break; - - case GRUB_MACHINE_MEMORY_ACPI: - pm->type = NETBSD_MMAP_ACPI; - break; - - case GRUB_MACHINE_MEMORY_NVS: - pm->type = NETBSD_MMAP_NVS; - break; - - default: - pm->type = NETBSD_MMAP_RESERVED; - break; + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct grub_netbsd_btinfo_common) + + tag->len); + tag_count++; } - pm++; - - return 0; } - grub_mmap_iterate (count_hook); + arg_target = kern_end; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + arg_target, tag_buf_len + + sizeof (struct grub_netbsd_bootinfo) + + tag_count * sizeof (grub_uint32_t)); + if (err) + return err; + curarg = get_virtual_current_address (ch); + } - if (kern_end + sizeof (struct grub_netbsd_btinfo_rootdevice) - + sizeof (struct grub_netbsd_bootinfo) - + sizeof (struct grub_netbsd_btinfo_mmap_header) - + count * sizeof (struct grub_netbsd_btinfo_mmap_entry) - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + arg0 = curarg; + bootinfo = (void *) ((grub_uint8_t *) arg0 + tag_buf_len); - curarg = mmap = (struct grub_netbsd_btinfo_mmap_header *) kern_end; - pm = (struct grub_netbsd_btinfo_mmap_entry *) (mmap + 1); + { + struct bsd_tag *tag; + unsigned i; - grub_mmap_iterate (fill_hook); - mmap->common.type = NETBSD_BTINFO_MEMMAP; - mmap->common.len = (char *) pm - (char *) mmap; - mmap->count = count; - curarg = pm; + bootinfo->bi_count = tag_count; + for (tag = tags, i = 0; tag; i++, tag = tag->next) + { + struct grub_netbsd_btinfo_common *head = curarg; + bootinfo->bi_data[i] = ((grub_uint8_t *) curarg - (grub_uint8_t *) arg0) + + arg_target; + head->type = tag->type; + head->len = tag->len + sizeof (*head); + curarg = head + 1; + grub_memcpy (curarg, tag->data, tag->len); + curarg = (grub_uint8_t *) curarg + tag->len; + } + } - if (netbsd_root) - { - struct grub_netbsd_btinfo_rootdevice *rootdev; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x10000, 0x90000, + 7 * sizeof (grub_uint32_t), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } - rootdev = (struct grub_netbsd_btinfo_rootdevice *) curarg; +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - rootdev->common.len = sizeof (struct grub_netbsd_btinfo_rootdevice); - rootdev->common.type = NETBSD_BTINFO_ROOTDEVICE; - grub_strncpy (rootdev->devname, netbsd_root, sizeof (rootdev->devname)); + state.eip = entry; + state.esp = stack_target; + stack[0] = entry; + stack[1] = bootflags; + stack[2] = 0; + stack[3] = ((grub_uint8_t *) bootinfo - (grub_uint8_t *) arg0) + arg_target; + stack[4] = 0; + stack[5] = grub_mmap_get_upper () >> 10; + stack[6] = grub_mmap_get_lower () >> 10; - bootinfo = (struct grub_netbsd_bootinfo *) (rootdev + 1); - bootinfo->bi_count = 2; - bootinfo->bi_data[0] = mmap; - bootinfo->bi_data[1] = rootdev; - } - else - { - bootinfo = (struct grub_netbsd_bootinfo *) curarg; - bootinfo->bi_count = 1; - bootinfo->bi_data[0] = mmap; - } - - grub_video_set_mode ("text", 0, 0); - - grub_unix_real_boot (entry, bootflags, 0, bootinfo, - 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), - (grub_uint32_t) (grub_mmap_get_lower () >> 10)); - - /* Not reached. */ - return GRUB_ERR_NONE; + return grub_relocator32_boot (relocator, state); } static grub_err_t grub_bsd_unload (void) { - if (mod_buf) + struct bsd_tag *tag, *next; + for (tag = tags; tag; tag = next) { - grub_free (mod_buf); - mod_buf = 0; - mod_buf_max = 0; + next = tag->next; + grub_free (tag); } + tags = NULL; + tags_last = NULL; kernel_type = KERNEL_TYPE_NONE; grub_dl_unref (my_mod); - grub_free (netbsd_root); - netbsd_root = NULL; + grub_relocator_unload (relocator); + relocator = NULL; return GRUB_ERR_NONE; } @@ -740,9 +1080,11 @@ grub_bsd_unload (void) static grub_err_t grub_bsd_load_aout (grub_file_t file) { - grub_addr_t load_addr, bss_end_addr; + grub_addr_t load_addr, load_end; int ofs, align_page; union grub_aout_header ah; + grub_err_t err; + grub_size_t bss_size; if ((grub_file_seek (file, 0)) == (grub_off_t) - 1) return grub_errno; @@ -772,7 +1114,7 @@ grub_bsd_load_aout (grub_file_t file) return grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); kern_start = load_addr; - kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data; + load_end = kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data; if (align_page) kern_end = ALIGN_PAGE (kern_end); @@ -782,13 +1124,45 @@ grub_bsd_load_aout (grub_file_t file) if (align_page) kern_end = ALIGN_PAGE (kern_end); - bss_end_addr = kern_end; + bss_size = kern_end - load_end; } else - bss_end_addr = 0; + bss_size = 0; - return grub_aout_load (file, ofs, load_addr, - ah.aout32.a_text + ah.aout32.a_data, bss_end_addr); + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_start, kern_end - kern_start); + if (err) + return err; + kern_chunk_src = get_virtual_current_address (ch); + } + + return grub_aout_load (file, ofs, kern_chunk_src, + ah.aout32.a_text + ah.aout32.a_data, + bss_size); +} + +static int NESTED_FUNC_ATTR +grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)), + Elf32_Phdr *phdr, void *arg __attribute__ ((unused))) +{ + Elf32_Addr paddr; + + if (phdr->p_type != PT_LOAD + && phdr->p_type != PT_DYNAMIC) + return 0; + + paddr = phdr->p_paddr & 0xFFFFFF; + + if (paddr < kern_start) + kern_start = paddr; + + if (paddr + phdr->p_memsz > kern_end) + kern_end = paddr + phdr->p_memsz; + + return 0; } static grub_err_t @@ -807,20 +1181,30 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load) phdr->p_paddr &= 0xFFFFFF; paddr = phdr->p_paddr; - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", - paddr); + *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src); - if ((!kern_start) || (paddr < kern_start)) + return GRUB_ERR_NONE; +} + +static int NESTED_FUNC_ATTR +grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)), + Elf64_Phdr *phdr, void *arg __attribute__ ((unused))) +{ + Elf64_Addr paddr; + + if (phdr->p_type != PT_LOAD + && phdr->p_type != PT_DYNAMIC) + return 0; + + paddr = phdr->p_paddr & 0xffffff; + + if (paddr < kern_start) kern_start = paddr; if (paddr + phdr->p_memsz > kern_end) kern_end = paddr + phdr->p_memsz; - *addr = paddr; - - return GRUB_ERR_NONE; + return 0; } static grub_err_t @@ -838,18 +1222,7 @@ grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load) *do_load = 1; paddr = phdr->p_paddr & 0xffffff; - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", - paddr); - - if ((!kern_start) || (paddr < kern_start)) - kern_start = paddr; - - if (paddr + phdr->p_memsz > kern_end) - kern_end = paddr + phdr->p_memsz; - - *addr = paddr; + *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src); return GRUB_ERR_NONE; } @@ -857,12 +1230,33 @@ grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load) static grub_err_t grub_bsd_load_elf (grub_elf_t elf) { - kern_start = kern_end = 0; + grub_err_t err; + + kern_end = 0; + kern_start = ~0; if (grub_elf_is_elf32 (elf)) { + grub_relocator_chunk_t ch; + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; - return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + err = grub_elf32_phdr_iterate (elf, grub_bsd_elf32_size_hook, NULL); + if (err) + return err; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_start, kern_end - kern_start); + if (err) + return err; + + kern_chunk_src = get_virtual_current_address (ch); + + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + if (err) + return err; + if (kernel_type != KERNEL_TYPE_OPENBSD) + return GRUB_ERR_NONE; + return grub_openbsd_find_ramdisk32 (elf->file, kern_start, + kern_chunk_src, &openbsd_ramdisk); } else if (grub_elf_is_elf64 (elf)) { @@ -882,7 +1276,30 @@ grub_bsd_load_elf (grub_elf_t elf) entry = elf->ehdr.ehdr64.e_entry & 0x0fffffff; entry_hi = 0; } - return grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0); + + err = grub_elf64_phdr_iterate (elf, grub_bsd_elf64_size_hook, NULL); + if (err) + return err; + + grub_dprintf ("bsd", "kern_start = %lx, kern_end = %lx\n", + (unsigned long) kern_start, (unsigned long) kern_end); + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, + kern_end - kern_start); + if (err) + return err; + kern_chunk_src = get_virtual_current_address (ch); + } + + err = grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0); + if (err) + return err; + if (kernel_type != KERNEL_TYPE_OPENBSD) + return GRUB_ERR_NONE; + return grub_openbsd_find_ramdisk64 (elf->file, kern_start, + kern_chunk_src, &openbsd_ramdisk); } else return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); @@ -898,6 +1315,8 @@ grub_bsd_load (int argc, char *argv[]) grub_loader_unset (); + grub_memset (&openbsd_ramdisk, 0, sizeof (openbsd_ramdisk)); + if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); @@ -908,6 +1327,8 @@ grub_bsd_load (int argc, char *argv[]) if (!file) goto fail; + relocator = grub_relocator_new (); + elf = grub_elf_file (file); if (elf) { @@ -923,6 +1344,8 @@ grub_bsd_load (int argc, char *argv[]) grub_file_close (file); } + kern_end = ALIGN_PAGE (kern_end); + fail: if (grub_errno != GRUB_ERR_NONE) @@ -975,34 +1398,28 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) return grub_errno; if (is_64bit) - err = grub_freebsd_load_elf_meta64 (file, &kern_end); + err = grub_freebsd_load_elf_meta64 (relocator, file, &kern_end); else - err = grub_freebsd_load_elf_meta32 (file, &kern_end); + err = grub_freebsd_load_elf_meta32 (relocator, file, &kern_end); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_HOWTO, &data, 4); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_HOWTO, &data, 4); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP, &data, len); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_KERNEND, &data, len); - if (err) - return err; - - kern_end_mdofs = mod_buf_len - len; - - err = grub_freebsd_add_mmap (); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_KERNEND, &data, len); if (err) return err; } - grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1); + grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 0); } return grub_errno; @@ -1039,9 +1456,54 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) else bootdev = 0; + if (cmd->state[OPENBSD_SERIAL_ARG].set) + { + struct grub_openbsd_bootarg_console serial; + char *ptr; + unsigned port = 0; + unsigned speed = 9600; + + grub_memset (&serial, 0, sizeof (serial)); + + if (cmd->state[OPENBSD_SERIAL_ARG].arg) + { + ptr = cmd->state[OPENBSD_SERIAL_ARG].arg; + if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only com0-com3 are supported"); + ptr += sizeof ("com") - 1; + port = grub_strtoul (ptr, &ptr, 0); + if (port >= 4) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only com0-com3 are supported"); + if (*ptr == ',') + { + ptr++; + speed = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + } + } + + serial.device = (GRUB_OPENBSD_COM_MAJOR << 8) | port; + serial.speed = speed; + + grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial)); + bootflags |= OPENBSD_RB_SERCONS; + } + else + { + struct grub_openbsd_bootarg_console serial; + + grub_memset (&serial, 0, sizeof (serial)); + serial.device = (GRUB_OPENBSD_VGA_MAJOR << 8); + grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial)); + bootflags &= ~OPENBSD_RB_SERCONS; + } + if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { - grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1); + grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 0); openbsd_root = bootdev; } @@ -1051,14 +1513,93 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) static grub_err_t grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[]) { + grub_err_t err; kernel_type = KERNEL_TYPE_NETBSD; bootflags = grub_bsd_parse_flags (cmd->state, netbsd_flags); if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { - grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 1); + if (is_elf_kernel) + { + grub_file_t file; + + file = grub_gzfile_open (argv[0], 1); + if (! file) + return grub_errno; + + if (is_64bit) + err = grub_netbsd_load_elf_meta64 (relocator, file, &kern_end); + else + err = grub_netbsd_load_elf_meta32 (relocator, file, &kern_end); + if (err) + return err; + } + + { + char bootpath[GRUB_NETBSD_MAX_BOOTPATH_LEN]; + char *name; + name = grub_strrchr (argv[0], '/'); + if (name) + name++; + else + name = argv[0]; + grub_memset (bootpath, 0, sizeof (bootpath)); + grub_strncpy (bootpath, name, sizeof (bootpath) - 1); + grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath)); + } + if (cmd->state[NETBSD_ROOT_ARG].set) - netbsd_root = grub_strdup (cmd->state[NETBSD_ROOT_ARG].arg); + { + char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN]; + grub_memset (root, 0, sizeof (root)); + grub_strncpy (root, cmd->state[NETBSD_ROOT_ARG].arg, + sizeof (root) - 1); + grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root)); + } + if (cmd->state[NETBSD_SERIAL_ARG].set) + { + struct grub_netbsd_btinfo_serial serial; + char *ptr; + + grub_memset (&serial, 0, sizeof (serial)); + grub_strcpy (serial.devname, "com"); + + if (cmd->state[NETBSD_SERIAL_ARG].arg) + { + ptr = cmd->state[NETBSD_SERIAL_ARG].arg; + if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0) + { + ptr += sizeof ("com") - 1; + serial.addr + = grub_ns8250_hw_get_port (grub_strtoul (ptr, &ptr, 0)); + } + else + serial.addr = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + + if (*ptr == ',') + { + ptr++; + serial.speed = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + } + } + + grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &serial, sizeof (serial)); + } + else + { + struct grub_netbsd_btinfo_serial cons; + + grub_memset (&cons, 0, sizeof (cons)); + grub_strcpy (cons.devname, "pc"); + + grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &cons, sizeof (cons)); + } + + grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 0); } return grub_errno; @@ -1167,18 +1708,14 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; - grub_err_t err; int modargc; char **modargv; char *type; - - if (kernel_type == KERNEL_TYPE_NONE) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "you need to load the kernel first"); + grub_err_t err; + void *src; if (kernel_type != KERNEL_TYPE_FREEBSD) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "only FreeBSD supports module"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no FreeBSD loaded"); if (!is_elf_kernel) return grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -1195,13 +1732,17 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), if ((!file) || (!file->size)) goto fail; - if (kern_end + file->size > grub_os_area_addr + grub_os_area_size) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "not enough memory for the module"); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, + file->size); + if (err) goto fail; - } + src = get_virtual_current_address (ch); + } - grub_file_read (file, (void *) kern_end, file->size); + + grub_file_read (file, src, file->size); if (grub_errno) goto fail; @@ -1231,6 +1772,73 @@ fail: return grub_errno; } +static grub_err_t +grub_netbsd_module_load (char *filename, grub_uint32_t type) +{ + grub_file_t file = 0; + void *src; + grub_err_t err; + + file = grub_gzfile_open (filename, 1); + if ((!file) || (!file->size)) + goto fail; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, + file->size); + if (err) + goto fail; + + src = get_virtual_current_address (ch); + } + + grub_file_read (file, src, file->size); + if (grub_errno) + goto fail; + + err = grub_netbsd_add_meta_module (filename, type, kern_end, file->size); + + if (err) + goto fail; + + kern_end = ALIGN_PAGE (kern_end + file->size); + +fail: + if (file) + grub_file_close (file); + + return grub_errno; +} + +static grub_err_t +grub_cmd_netbsd_module (grub_command_t cmd, + int argc, char *argv[]) +{ + grub_uint32_t type; + + if (kernel_type != KERNEL_TYPE_NETBSD) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no NetBSD loaded"); + + if (!is_elf_kernel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only ELF kernel supports module"); + + /* List the current modules if no parameter. */ + if (!argc) + { + grub_netbsd_list_modules (); + return 0; + } + + if (grub_strcmp (cmd->name, "knetbsd_module_elf") == 0) + type = GRUB_NETBSD_MODULE_ELF; + else + type = GRUB_NETBSD_MODULE_RAW; + + return grub_netbsd_module_load (argv[0], type); +} + static grub_err_t grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -1267,18 +1875,65 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), } if (is_64bit) - err = grub_freebsd_load_elfmodule_obj64 (file, argc, argv, &kern_end); + err = grub_freebsd_load_elfmodule_obj64 (relocator, file, + argc, argv, &kern_end); else - err = grub_freebsd_load_elfmodule32 (file, argc, argv, &kern_end); + err = grub_freebsd_load_elfmodule32 (relocator, file, + argc, argv, &kern_end); grub_file_close (file); return err; } +static grub_err_t +grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), + int argc, char *args[]) +{ + grub_file_t file; + grub_size_t size; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + if (kernel_type != KERNEL_TYPE_OPENBSD) + return grub_error (GRUB_ERR_BAD_OS, "no kOpenBSD loaded"); + + if (!openbsd_ramdisk.max_size) + return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk"); + + file = grub_gzfile_open (args[0], 1); + if (! file) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "couldn't load ramdisk"); + + size = grub_file_size (file); + + if (size > openbsd_ramdisk.max_size) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD supports ramdisk only" + " up to %u bytes, however you supplied a %u bytes one", + openbsd_ramdisk.max_size, size); + } + + if (grub_file_read (file, openbsd_ramdisk.target, size) + != (grub_ssize_t) (size)) + { + grub_file_close (file); + grub_error_push (); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); + } + grub_memset (openbsd_ramdisk.target + size, 0, + openbsd_ramdisk.max_size - size); + *openbsd_ramdisk.size = ALIGN_UP (size, 512); + + return GRUB_ERR_NONE; +} static grub_extcmd_t cmd_freebsd, cmd_openbsd, cmd_netbsd; static grub_command_t cmd_freebsd_loadenv, cmd_freebsd_module; -static grub_command_t cmd_freebsd_module_elf; +static grub_command_t cmd_netbsd_module, cmd_freebsd_module_elf; +static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; GRUB_MOD_INIT (bsd) { @@ -1300,10 +1955,20 @@ GRUB_MOD_INIT (bsd) cmd_freebsd_module = grub_register_command ("kfreebsd_module", grub_cmd_freebsd_module, 0, N_("Load FreeBSD kernel module.")); + cmd_netbsd_module = + grub_register_command ("knetbsd_module", grub_cmd_netbsd_module, + 0, N_("Load NetBSD kernel module.")); + cmd_netbsd_module_elf = + grub_register_command ("knetbsd_module_elf", grub_cmd_netbsd_module, + 0, N_("Load NetBSD kernel module (ELF).")); cmd_freebsd_module_elf = grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf, 0, N_("Load FreeBSD kernel module (ELF).")); + cmd_openbsd_ramdisk = grub_register_command ("kopenbsd_ramdisk", + grub_cmd_openbsd_ramdisk, 0, + "Load kOpenBSD ramdisk. "); + my_mod = mod; } @@ -1315,12 +1980,10 @@ GRUB_MOD_FINI (bsd) grub_unregister_command (cmd_freebsd_loadenv); grub_unregister_command (cmd_freebsd_module); + grub_unregister_command (cmd_netbsd_module); grub_unregister_command (cmd_freebsd_module_elf); + grub_unregister_command (cmd_netbsd_module_elf); + grub_unregister_command (cmd_openbsd_ramdisk); - if (mod_buf) - { - grub_free (mod_buf); - mod_buf = 0; - mod_buf_max = 0; - } + grub_bsd_unload (); } diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index cd5ba85dc..073f01da2 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -1,22 +1,18 @@ #include -#include +#include #include #include #include -#include +#include #define ALIGN_PAGE(a) ALIGN_UP (a, 4096) static inline grub_err_t load (grub_file_t file, void *where, grub_off_t off, grub_size_t size) { - if (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); if (grub_file_seek (file, off) == (grub_off_t) -1) return grub_errno; - if (grub_file_read (file, where, size) - != (grub_ssize_t) size) + if (grub_file_read (file, where, size) != (grub_ssize_t) size) { if (grub_errno) return grub_errno; @@ -75,7 +71,8 @@ read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr) platforms. So I keep both versions. */ #if OBJSYM grub_err_t -SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, +SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; @@ -83,6 +80,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, char *shdr = 0; grub_addr_t curload, module; grub_err_t err; + grub_size_t chunk_size = 0; + void *chunk_src; err = read_headers (file, &e, &shdr); if (err) @@ -90,6 +89,29 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, curload = module = ALIGN_PAGE (*kern_end); + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + if (s->sh_size == 0) + continue; + + if (s->sh_addralign) + chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign) + - *kern_end; + + chunk_size += s->sh_size; + } + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + module, chunk_size); + if (err) + return err; + chunk_src = get_virtual_current_address (ch); + } + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) @@ -109,15 +131,14 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, { default: case SHT_PROGBITS: - err = load (file, UINT_TO_PTR (curload), s->sh_offset, s->sh_size); + err = load (file, (grub_uint8_t *) chunk_src + curload - *kern_end, + s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: - if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); - grub_memset (UINT_TO_PTR (curload), 0, s->sh_size); + grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0, + s->sh_size); break; } curload += s->sh_size; @@ -129,13 +150,13 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, argc - 1, argv + 1, module, curload - module); if (! err) - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA - | FREEBSD_MODINFOMD_ELFHDR, - &e, sizeof (e)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA + | FREEBSD_MODINFOMD_ELFHDR, + &e, sizeof (e)); if (! err) - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA - | FREEBSD_MODINFOMD_SHDR, - shdr, e.e_shnum * e.e_shentsize); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA + | FREEBSD_MODINFOMD_SHDR, + shdr, e.e_shnum * e.e_shentsize); return err; } @@ -143,7 +164,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, #else grub_err_t -SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], +SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; @@ -151,6 +173,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], char *shdr = 0; grub_addr_t curload, module; grub_err_t err; + grub_size_t chunk_size = 0; + void *chunk_src; err = read_headers (file, &e, &shdr); if (err) @@ -158,6 +182,30 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], curload = module = ALIGN_PAGE (*kern_end); + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + if (s->sh_size == 0) + continue; + + if (! (s->sh_flags & SHF_ALLOC)) + continue; + if (chunk_size < s->sh_addr + s->sh_size) + chunk_size = s->sh_addr + s->sh_size; + } + + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + module, chunk_size); + if (err) + return err; + + chunk_src = get_virtual_current_address (ch); + } + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) @@ -176,17 +224,15 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], { default: case SHT_PROGBITS: - err = load (file, UINT_TO_PTR (module + s->sh_addr), + err = load (file, (grub_uint8_t *) chunk_src + module + + s->sh_addr - *kern_end, s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: - if (module + s->sh_addr + s->sh_size - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); - grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size); + grub_memset ((grub_uint8_t *) chunk_src + module + + s->sh_addr - *kern_end, 0, s->sh_size); break; } if (curload < module + s->sh_addr + s->sh_size) @@ -212,32 +258,36 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE, argc - 1, argv + 1, module, curload - module); - return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end); + return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, kern_end); } #endif grub_err_t -SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) +SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end) { grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; char *shdr = 0; unsigned symoff, stroff, symsize, strsize; - grub_addr_t curload; grub_freebsd_addr_t symstart, symend, symentsize, dynamic; Elf_Sym *sym; + void *sym_chunk; + grub_uint8_t *curload; + grub_freebsd_addr_t symtarget; const char *str; unsigned i; + grub_size_t chunk_size; err = read_headers (file, &e, &shdr); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_ELFHDR, &e, - sizeof (e)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_ELFHDR, &e, + sizeof (e)); if (err) return err; @@ -256,19 +306,31 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) stroff = s->sh_offset; strsize = s->sh_size; - if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for kernel symbols"); + chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t)) + + 2 * sizeof (grub_freebsd_addr_t); - symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); - *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize; + symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + symtarget, chunk_size); + if (err) + return err; + sym_chunk = get_virtual_current_address (ch); + } + + symstart = symtarget; + symend = symstart + chunk_size; + + curload = sym_chunk; + *((grub_freebsd_addr_t *) curload) = symsize; curload += sizeof (grub_freebsd_addr_t); + if (grub_file_seek (file, symoff) == (grub_off_t) -1) return grub_errno; - sym = (Elf_Sym *) UINT_TO_PTR (curload); - if (grub_file_read (file, UINT_TO_PTR (curload), symsize) != - (grub_ssize_t) symsize) + sym = (Elf_Sym *) curload; + if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); @@ -276,21 +338,17 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) } curload += symsize; - *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize; + *((grub_freebsd_addr_t *) curload) = strsize; curload += sizeof (grub_freebsd_addr_t); if (grub_file_seek (file, stroff) == (grub_off_t) -1) return grub_errno; - str = (char *) UINT_TO_PTR (curload); - if (grub_file_read (file, UINT_TO_PTR (curload), strsize) - != (grub_ssize_t) strsize) + str = (char *) curload; + if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } - curload += strsize; - curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t)); - symend = curload; for (i = 0; i * symentsize < symsize; @@ -305,25 +363,258 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) { dynamic = sym->st_value; grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic); - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_DYNAMIC, &dynamic, - sizeof (dynamic)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_DYNAMIC, &dynamic, + sizeof (dynamic)); if (err) return err; } - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_SSYM, &symstart, - sizeof (symstart)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_SSYM, &symstart, + sizeof (symstart)); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_ESYM, &symend, - sizeof (symend)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_ESYM, &symend, + sizeof (symend)); if (err) return err; - *kern_end = ALIGN_PAGE (curload); + + *kern_end = ALIGN_PAGE (symend); return GRUB_ERR_NONE; } + +grub_err_t +SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end) +{ + grub_err_t err; + Elf_Ehdr e; + Elf_Shdr *s, *symsh, *strsh; + char *shdr; + unsigned symsize, strsize; + Elf_Sym *sym; + void *sym_chunk; + grub_uint8_t *curload; + const char *str; + grub_size_t chunk_size; + Elf_Ehdr *e2; + struct grub_netbsd_btinfo_symtab symtab; + grub_addr_t symtarget; + + err = read_headers (file, &e, &shdr); + if (err) + return err; + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + if (s >= (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize)) + return GRUB_ERR_NONE; + symsize = s->sh_size; + symsh = s; + s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); + strsize = s->sh_size; + strsh = s; + + chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + + ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t)) + + sizeof (e) + e.e_shnum * e.e_shentsize; + + symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + symtarget, chunk_size); + if (err) + return err; + sym_chunk = get_virtual_current_address (ch); + } + + symtab.nsyms = 1; + symtab.ssyms = symtarget; + symtab.esyms = symtarget + chunk_size; + + curload = sym_chunk; + + e2 = (Elf_Ehdr *) curload; + grub_memcpy (curload, &e, sizeof (e)); + e2->e_phoff = 0; + e2->e_phnum = 0; + e2->e_phentsize = 0; + e2->e_shstrndx = 0; + e2->e_shoff = sizeof (e); + + curload += sizeof (e); + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + Elf_Shdr *s2; + s2 = (Elf_Shdr *) curload; + grub_memcpy (curload, s, e.e_shentsize); + if (s == symsh) + s2->sh_offset = sizeof (e) + e.e_shnum * e.e_shentsize; + else if (s == strsh) + s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + + sizeof (e) + e.e_shnum * e.e_shentsize; + else + s2->sh_offset = 0; + s2->sh_addr = s2->sh_offset; + curload += e.e_shentsize; + } + + if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1) + return grub_errno; + sym = (Elf_Sym *) curload; + if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) + { + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)); + + if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1) + return grub_errno; + str = (char *) curload; + if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) + { + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB, + &symtab, + sizeof (symtab)); + if (err) + return err; + + *kern_end = ALIGN_PAGE (symtarget + chunk_size); + + return GRUB_ERR_NONE; +} + +grub_err_t +SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc) +{ + unsigned symoff, stroff, symsize, strsize, symentsize; + + { + grub_err_t err; + Elf_Ehdr e; + Elf_Shdr *s; + char *shdr; + + err = read_headers (file, &e, &shdr); + if (err) + return err; + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize)) + { + grub_free (shdr); + return GRUB_ERR_NONE; + } + + symsize = s->sh_size; + symentsize = s->sh_entsize; + symoff = s->sh_offset; + + s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); + stroff = s->sh_offset; + strsize = s->sh_size; + grub_free (shdr); + } + { + Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL; + unsigned i; + char *strs; + + syms = grub_malloc (symsize); + if (!syms) + return grub_errno; + + if (grub_file_seek (file, symoff) == (grub_off_t) -1) + { + grub_free (syms); + return grub_errno; + } + if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize) + { + grub_free (syms); + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + strs = grub_malloc (strsize); + if (!strs) + { + grub_free (syms); + return grub_errno; + } + + if (grub_file_seek (file, stroff) == (grub_off_t) -1) + return grub_errno; + if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize) + { + grub_free (syms); + grub_free (strs); + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + for (i = 0, sym = syms; i < symsize / symentsize; + i++, sym = (Elf_Sym *) ((char *) sym + symentsize)) + { + if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT) + continue; + if (!sym->st_name) + continue; + if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0) + imagesym = sym; + if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0) + sizesym = sym; + if (imagesym && sizesym) + break; + } + if (!imagesym || !sizesym) + { + grub_free (syms); + grub_free (strs); + return GRUB_ERR_NONE; + } + if (sizeof (*desc->size) != sizesym->st_size) + { + grub_free (syms); + grub_free (strs); + return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size"); + } + desc->max_size = imagesym->st_size; + desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start + + (grub_uint8_t *) kern_chunk_src; + desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start + + (grub_uint8_t *) kern_chunk_src); + grub_free (syms); + grub_free (strs); + + return GRUB_ERR_NONE; + } +} diff --git a/grub-core/loader/i386/bsd_pagetable.c b/grub-core/loader/i386/bsd_pagetable.c index 0fd393707..13348cc83 100644 --- a/grub-core/loader/i386/bsd_pagetable.c +++ b/grub-core/loader/i386/bsd_pagetable.c @@ -50,9 +50,10 @@ static void -fill_bsd64_pagetable (grub_uint8_t *target) +fill_bsd64_pagetable (grub_uint8_t *src, grub_addr_t target) { grub_uint64_t *pt2, *pt3, *pt4; + grub_addr_t pt2t, pt3t, pt4t; int i; #define PG_V 0x001 @@ -60,11 +61,15 @@ fill_bsd64_pagetable (grub_uint8_t *target) #define PG_U 0x004 #define PG_PS 0x080 - pt4 = (grub_uint64_t *) target; - pt3 = (grub_uint64_t *) (target + 4096); - pt2 = (grub_uint64_t *) (target + 8192); + pt4 = (grub_uint64_t *) src; + pt3 = (grub_uint64_t *) (src + 4096); + pt2 = (grub_uint64_t *) (src + 8192); - grub_memset ((char *) target, 0, 4096 * 3); + pt4t = target; + pt3t = target + 4096; + pt2t = target + 8192; + + grub_memset (src, 0, 4096 * 3); /* * This is kinda brutal, but every single 1GB VM memory segment points to @@ -74,11 +79,11 @@ fill_bsd64_pagetable (grub_uint8_t *target) for (i = 0; i < 512; i++) { /* Each slot of the level 4 pages points to the same level 3 page */ - pt4[i] = (grub_addr_t) &pt3[0]; + pt4[i] = (grub_addr_t) pt3t; pt4[i] |= PG_V | PG_RW | PG_U; /* Each slot of the level 3 pages points to the same level 2 page */ - pt3[i] = (grub_addr_t) &pt2[0]; + pt3[i] = (grub_addr_t) pt2t; pt3[i] |= PG_V | PG_RW | PG_U; /* The level 2 page slots are mapped with 2MB pages for 1GB. */ diff --git a/grub-core/loader/i386/bsd_trampoline.S b/grub-core/loader/i386/bsd_trampoline.S deleted file mode 100644 index a568fff4d..000000000 --- a/grub-core/loader/i386/bsd_trampoline.S +++ /dev/null @@ -1,124 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (c) 2003 Peter Wemm - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -/* Based on the code from FreeBSD originally distributed under the - following terms: */ - -/*- - * Copyright (c) 2003 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - -#define MSR_EFER 0xc0000080 -#define EFER_LME 0x00000100 -#define CR4_PAE 0x00000020 -#define CR4_PSE 0x00000010 -#define CR0_PG 0x80000000 - -#include - - .p2align 2 - - .code32 - - -VARIABLE(grub_bsd64_trampoline_start) - - /* Discard `grub_unix_real_boot' return address. */ - popl %eax - - /* entry */ - popl %edi - - /* entry_hi */ - popl %esi - - cli - - /* Turn on EFER.LME. */ - movl $MSR_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Turn on PAE. */ - movl %cr4, %eax - orl $(CR4_PAE | CR4_PSE), %eax - movl %eax, %cr4 - - /* Set %cr3 for PT4. */ - popl %eax - movl %eax, %cr3 - - /* Push a dummy return address. */ - pushl %eax - - /* Turn on paging (implicitly sets EFER.LMA). */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Now we're in compatibility mode. set %cs for long mode. */ - /* lgdt */ - .byte 0x0f - .byte 0x01 - .byte 0x15 -VARIABLE (grub_bsd64_trampoline_gdt) - .long 0x0 - - /* ljmp */ - .byte 0xea -VARIABLE (grub_bsd64_trampoline_selfjump) - .long 0x0 - .word 0x08 - - .code64 - -bsd64_longmode: - /* We're still running V=P, jump to entry point. */ - movl %esi, %eax - salq $32, %rax - orq %rdi, %rax - pushq %rax - ret -VARIABLE(grub_bsd64_trampoline_end) diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c deleted file mode 100644 index d37feb983..000000000 --- a/grub-core/loader/i386/efi/linux.c +++ /dev/null @@ -1,945 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GRUB_LINUX_CL_OFFSET 0x1000 -#define GRUB_LINUX_CL_END_OFFSET 0x2000 - -#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ - ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) - -static grub_dl_t my_mod; - -static grub_size_t linux_mem_size; -static int loaded; -static void *real_mode_mem; -static void *prot_mode_mem; -static void *initrd_mem; -static grub_efi_uintn_t real_mode_pages; -static grub_efi_uintn_t prot_mode_pages; -static grub_efi_uintn_t initrd_pages; -static void *mmap_buf; - -static grub_uint8_t gdt[] __attribute__ ((aligned(16))) = - { - /* NULL. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Reserved. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Code segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, - /* Data segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - }; - -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct gdt_descriptor gdt_desc = - { - sizeof (gdt) - 1, - gdt - }; - -struct idt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct idt_descriptor idt_desc = - { - 0, - 0 - }; - -static inline grub_size_t -page_align (grub_size_t size) -{ - return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); -} - -/* Find the optimal number of pages for the memory map. Is it better to - move this code to efi/mm.c? */ -static grub_efi_uintn_t -find_mmap_size (void) -{ - static grub_efi_uintn_t mmap_size = 0; - - if (mmap_size != 0) - return mmap_size; - - mmap_size = (1 << 12); - while (1) - { - int ret; - grub_efi_memory_descriptor_t *mmap; - grub_efi_uintn_t desc_size; - - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); - grub_free (mmap); - - if (ret < 0) - grub_fatal ("cannot get memory map"); - else if (ret > 0) - break; - - mmap_size += (1 << 12); - } - - /* Increase the size a bit for safety, because GRUB allocates more on - later, and EFI itself may allocate more. */ - mmap_size += (1 << 12); - - return page_align (mmap_size); -} - -static void -free_pages (void) -{ - if (real_mode_mem) - { - grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages); - real_mode_mem = 0; - } - - if (prot_mode_mem) - { - grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages); - prot_mode_mem = 0; - } - - if (initrd_mem) - { - grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); - initrd_mem = 0; - } -} - -/* Allocate pages for the real mode code and the protected mode code - for linux as well as a memory map buffer. */ -static int -allocate_pages (grub_size_t prot_size) -{ - grub_efi_uintn_t desc_size; - grub_efi_memory_descriptor_t *mmap, *mmap_end; - grub_efi_uintn_t mmap_size, tmp_mmap_size; - grub_efi_memory_descriptor_t *desc; - grub_size_t real_size; - - /* Make sure that each size is aligned to a page boundary. */ - real_size = GRUB_LINUX_CL_END_OFFSET; - prot_size = page_align (prot_size); - mmap_size = find_mmap_size (); - - grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", - (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size); - - /* Calculate the number of pages; Combine the real mode code with - the memory map buffer for simplicity. */ - real_mode_pages = ((real_size + mmap_size) >> 12); - prot_mode_pages = (prot_size >> 12); - - /* Initialize the memory pointers with NULL for convenience. */ - real_mode_mem = 0; - prot_mode_mem = 0; - - /* Read the memory map temporarily, to find free space. */ - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - tmp_mmap_size = mmap_size; - 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); - - /* First, find free pages for the real mode code - and the memory map buffer. */ - for (desc = mmap; - desc < mmap_end; - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - /* Probably it is better to put the real mode code in the traditional - space for safety. */ - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->physical_start <= 0x90000 - && desc->num_pages >= real_mode_pages) - { - grub_efi_physical_address_t physical_end; - grub_efi_physical_address_t addr; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > 0x90000) - physical_end = 0x90000; - - grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", - (unsigned) desc->physical_start, - (unsigned) physical_end); - addr = physical_end - real_size - mmap_size; - if (addr < 0x10000) - continue; - - grub_dprintf ("linux", "trying to allocate %u pages at %lx\n", - (unsigned) real_mode_pages, (unsigned long) addr); - real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages); - if (! real_mode_mem) - grub_fatal ("cannot allocate pages"); - - desc->num_pages -= real_mode_pages; - break; - } - } - - if (! real_mode_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); - goto fail; - } - - mmap_buf = (void *) ((char *) real_mode_mem + real_size); - - /* Next, find free pages for the protected mode code. */ - /* XXX what happens if anything is using this address? */ - prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1); - if (! prot_mode_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, - "cannot allocate protected mode pages"); - goto fail; - } - - grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " - "prot_mode_mem = %lx, prot_mode_pages = %x\n", - (unsigned long) real_mode_mem, (unsigned) real_mode_pages, - (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); - - grub_free (mmap); - return 1; - - fail: - grub_free (mmap); - free_pages (); - return 0; -} - -static void -grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, - grub_uint64_t start, grub_uint64_t size, - grub_uint32_t type) -{ - int n = *e820_num; - - if (n >= GRUB_E820_MAX_ENTRY) - grub_fatal ("Too many e820 memory map entries"); - - if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) && - (e820_map[n - 1].type == type)) - e820_map[n - 1].size += size; - else - { - e820_map[n].addr = start; - e820_map[n].size = size; - e820_map[n].type = type; - (*e820_num)++; - } -} - -static grub_err_t -grub_linux_setup_video (struct linux_kernel_params *params) -{ - struct grub_video_mode_info mode_info; - void *framebuffer; - grub_err_t err; - - err = grub_video_get_info_and_fini (&mode_info, &framebuffer); - - if (err) - return err; - - params->lfb_width = mode_info.width; - params->lfb_height = mode_info.height; - params->lfb_depth = mode_info.bpp; - params->lfb_line_len = mode_info.pitch; - - params->lfb_base = (grub_size_t) framebuffer; - params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, - 65536); - - params->red_mask_size = mode_info.red_mask_size; - params->red_field_pos = mode_info.red_field_pos; - params->green_mask_size = mode_info.green_mask_size; - params->green_field_pos = mode_info.green_field_pos; - params->blue_mask_size = mode_info.blue_mask_size; - params->blue_field_pos = mode_info.blue_field_pos; - params->reserved_mask_size = mode_info.reserved_mask_size; - params->reserved_field_pos = mode_info.reserved_field_pos; - - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - -#ifdef GRUB_MACHINE_PCBIOS - /* VESA packed modes may come with zeroed mask sizes, which need - to be set here according to DAC Palette width. If we don't, - this results in Linux displaying a black screen. */ - if (mode_info.bpp <= 8) - { - struct grub_vbe_info_block controller_info; - int status; - int width = 8; - - status = grub_vbe_bios_get_controller_info (&controller_info); - - if (status == GRUB_VBE_STATUS_OK && - (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)) - status = grub_vbe_bios_set_dac_palette_width (&width); - - if (status != GRUB_VBE_STATUS_OK) - /* 6 is default after mode reset. */ - width = 6; - - params->red_mask_size = params->green_mask_size - = params->blue_mask_size = width; - params->reserved_mask_size = 0; - } -#endif - - return 0; -} - -#ifdef __x86_64__ -extern grub_uint8_t grub_linux_trampoline_start[]; -extern grub_uint8_t grub_linux_trampoline_end[]; -#endif - -static grub_err_t -grub_linux_boot (void) -{ - struct linux_kernel_params *params; - grub_efi_uintn_t mmap_size; - grub_efi_uintn_t map_key; - grub_efi_uintn_t desc_size; - grub_efi_uint32_t desc_version; - int e820_num; - const char *modevar; - char *tmp; - grub_err_t err; - - params = real_mode_mem; - - grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n", - (unsigned) params->code32_start, - (unsigned long) &(idt_desc.limit), - (unsigned long) &(gdt_desc.limit)); - grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n", - (unsigned) idt_desc.limit, (unsigned long) idt_desc.base, - (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base); - - 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) - { - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RAM); - break; - -#ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_ACPI); - break; -#endif - -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_NVS); - break; -#endif - -#ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_EXEC_CODE); - break; -#endif - - default: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RESERVED); - } - return 0; - } - - e820_num = 0; - grub_mmap_iterate (hook); - params->mmap_size = e820_num; - - grub_dprintf ("linux", "Trampoline at %p. code32=%x, real_mode_mem=%p\n", - ((char *) prot_mode_mem + (prot_mode_pages << 12)), - (unsigned) params->code32_start, real_mode_mem); - - modevar = grub_env_get ("gfxpayload"); - - /* Now all graphical modes are acceptable. - May change in future if we have modes without framebuffer. */ - if (modevar && *modevar != 0) - { - tmp = grub_xasprintf ("%s;auto", modevar); - if (! tmp) - return grub_errno; - err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); - grub_free (tmp); - } - else - err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); - - if (!err) - err = grub_linux_setup_video (params); - - if (err) - { - grub_print_error (); - grub_printf ("Booting however\n"); - grub_errno = GRUB_ERR_NONE; - } - - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) - grub_fatal ("cannot get memory map"); - - if (! grub_efi_exit_boot_services (map_key)) - grub_fatal ("cannot exit boot services"); - - /* Note that no boot services are available from here. */ - - /* Pass EFI parameters. */ - if (grub_le_to_cpu16 (params->version) >= 0x0206) - { - params->v0206.efi_mem_desc_size = desc_size; - params->v0206.efi_mem_desc_version = desc_version; - params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf; - params->v0206.efi_mmap_size = mmap_size; -#ifdef __x86_64__ - params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32); -#endif - } - else if (grub_le_to_cpu16 (params->version) >= 0x0204) - { - params->v0204.efi_mem_desc_size = desc_size; - params->v0204.efi_mem_desc_version = desc_version; - params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf; - params->v0204.efi_mmap_size = mmap_size; - } - -#ifdef __x86_64__ - - grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12), - grub_linux_trampoline_start, - grub_linux_trampoline_end - grub_linux_trampoline_start); - - ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem - + (prot_mode_pages << 12))) - (params->code32_start, real_mode_mem); - -#else - - /* Hardware interrupts are not safe any longer. */ - asm volatile ("cli" : : ); - - /* Load the IDT and the GDT for the bootstrap. */ - asm volatile ("lidt %0" : : "m" (idt_desc)); - asm volatile ("lgdt %0" : : "m" (gdt_desc)); - - /* Pass parameters. */ - asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start)); - asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem)); - - asm volatile ("xorl %%ebx, %%ebx" : : ); - - /* Enter Linux. */ - asm volatile ("jmp *%%ecx" : : ); - -#endif - - /* Never reach here. */ - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux_unload (void) -{ - free_pages (); - grub_dl_unref (my_mod); - loaded = 0; - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - struct linux_kernel_header lh; - struct linux_kernel_params *params; - grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; - grub_ssize_t len; - int i; - char *dest; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) - { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); - goto fail; - } - - if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) - { - grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); - goto fail; - } - - if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) - { - grub_error (GRUB_ERR_BAD_OS, "too many setup sectors"); - goto fail; - } - - /* EFI support is quite new, so reject old versions. */ - if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) - || grub_le_to_cpu16 (lh.version) < 0x0203) - { - grub_error (GRUB_ERR_BAD_OS, "too old version"); - goto fail; - } - - /* I'm not sure how to support zImage on EFI. */ - if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL)) - { - grub_error (GRUB_ERR_BAD_OS, "zImage is not supported"); - goto fail; - } - - setup_sects = lh.setup_sects; - - /* If SETUP_SECTS is not set, set it to the default (4). */ - if (! setup_sects) - setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - - real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - if (! allocate_pages (prot_size)) - goto fail; - - params = (struct linux_kernel_params *) real_mode_mem; - grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET); - grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1); - - params->ps_mouse = params->padding10 = 0; - - len = 0x400 - sizeof (lh); - if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - - params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4); - - params->cl_magic = GRUB_LINUX_CL_MAGIC; - params->cl_offset = 0x1000; - params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000; - params->ramdisk_image = 0; - params->ramdisk_size = 0; - - params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET; - params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP; - - /* These are not needed to be precise, because Linux uses these values - only to raise an error when the decompression code cannot find good - space. */ - params->ext_mem = ((32 * 0x100000) >> 10); - params->alt_mem = ((32 * 0x100000) >> 10); - - { - grub_term_output_t term; - int found = 0; - FOR_ACTIVE_TERM_OUTPUTS(term) - if (grub_strcmp (term->name, "vga_text") == 0 - || grub_strcmp (term->name, "console") == 0) - { - grub_uint16_t pos = grub_term_getxy (term); - params->video_cursor_x = pos >> 8; - params->video_cursor_y = pos & 0xff; - params->video_width = grub_term_width (term); - params->video_height = grub_term_height (term); - found = 1; - break; - } - if (!found) - { - params->video_cursor_x = 0; - params->video_cursor_y = 0; - params->video_width = 80; - params->video_height = 25; - } - } - params->video_page = 0; /* ??? */ - params->video_mode = grub_efi_system_table->con_out->mode->mode; - params->video_ega_bx = 0; - params->have_vga = 0; - params->font_size = 16; /* XXX */ - - 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; -#ifdef __x86_64__ - params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) 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; - } - -#if 0 - /* The structure is zeroed already. */ - - /* No VBE on EFI. */ - params->lfb_width = 0; - params->lfb_height = 0; - params->lfb_depth = 0; - params->lfb_base = 0; - params->lfb_size = 0; - params->lfb_line_len = 0; - params->red_mask_size = 0; - params->red_field_pos = 0; - params->green_mask_size = 0; - params->green_field_pos = 0; - params->blue_mask_size = 0; - params->blue_field_pos = 0; - params->reserved_mask_size = 0; - params->reserved_field_pos = 0; - params->vesapm_segment = 0; - params->vesapm_offset = 0; - params->lfb_pages = 0; - params->vesa_attrib = 0; - - /* No APM on EFI. */ - params->apm_version = 0; - params->apm_code_segment = 0; - params->apm_entry = 0; - params->apm_16bit_code_segment = 0; - params->apm_data_segment = 0; - params->apm_flags = 0; - params->apm_code_len = 0; - params->apm_data_len = 0; - - /* XXX is there any way to use SpeedStep on EFI? */ - params->ist_signature = 0; - params->ist_command = 0; - params->ist_event = 0; - params->ist_perf_level = 0; - - /* Let the kernel probe the information. */ - grub_memset (params->hd0_drive_info, 0, sizeof (params->hd0_drive_info)); - grub_memset (params->hd1_drive_info, 0, sizeof (params->hd1_drive_info)); - - /* No MCA on EFI. */ - params->rom_config_len = 0; - - /* No need to fake the BIOS's memory map. */ - params->mmap_size = 0; - - /* Let the kernel probe the information. */ - params->ps_mouse = 0; - - /* Clear padding for future compatibility. */ - grub_memset (params->padding1, 0, sizeof (params->padding1)); - grub_memset (params->padding2, 0, sizeof (params->padding2)); - grub_memset (params->padding3, 0, sizeof (params->padding3)); - grub_memset (params->padding4, 0, sizeof (params->padding4)); - grub_memset (params->padding5, 0, sizeof (params->padding5)); - grub_memset (params->padding6, 0, sizeof (params->padding6)); - grub_memset (params->padding7, 0, sizeof (params->padding7)); - grub_memset (params->padding8, 0, sizeof (params->padding8)); - grub_memset (params->padding9, 0, sizeof (params->padding9)); - -#endif - - /* The other EFI parameters are filled when booting. */ - - grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); - - /* XXX there is no way to know if the kernel really supports EFI. */ - grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", - (unsigned) real_size, (unsigned) prot_size); - - /* Detect explicitly specified memory size, if any. */ - linux_mem_size = 0; - for (i = 1; i < argc; i++) - if (grub_memcmp (argv[i], "mem=", 4) == 0) - { - char *val = argv[i] + 4; - - linux_mem_size = grub_strtoul (val, &val, 0); - - if (grub_errno) - { - grub_errno = GRUB_ERR_NONE; - linux_mem_size = 0; - } - else - { - int shift = 0; - - switch (grub_tolower (val[0])) - { - case 'g': - shift += 10; - case 'm': - shift += 10; - case 'k': - shift += 10; - default: - break; - } - - /* Check an overflow. */ - if (linux_mem_size > (~0UL >> shift)) - linux_mem_size = 0; - else - linux_mem_size <<= shift; - } - } - else if (grub_memcmp (argv[i], "video=efifb", 11) == 0) - { - if (params->have_vga) - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - } - - /* Specify the boot file. */ - dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET, - "BOOT_IMAGE="); - dest = grub_stpcpy (dest, argv[0]); - - /* Copy kernel parameters. */ - for (i = 1; - i < argc - && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem - + GRUB_LINUX_CL_END_OFFSET); - i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } - - len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - - if (grub_errno == GRUB_ERR_NONE) - { - grub_loader_set (grub_linux_boot, grub_linux_unload, 0); - loaded = 1; - } - - fail: - - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_dl_unref (my_mod); - loaded = 0; - } - - return grub_errno; -} - -static grub_err_t -grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - grub_ssize_t size; - grub_addr_t addr_min, addr_max; - grub_addr_t addr; - grub_efi_uintn_t mmap_size; - grub_efi_memory_descriptor_t *desc; - grub_efi_uintn_t desc_size; - struct linux_kernel_header *lh; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } - - if (! loaded) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - size = grub_file_size (file); - initrd_pages = (page_align (size) >> 12); - - lh = (struct linux_kernel_header *) real_mode_mem; - - addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10); - if (linux_mem_size != 0 && linux_mem_size < addr_max) - addr_max = linux_mem_size; - - /* Linux 2.3.xx has a bug in the memory range check, so avoid - the last page. - Linux 2.2.xx has a bug in the memory range check, which is - worse than that of Linux 2.3.xx, so avoid the last 64kb. */ - addr_max -= 0x10000; - - /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) - + page_align (size); - - /* 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) - grub_fatal ("cannot get memory map"); - - addr = 0; - for (desc = mmap_buf; - desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->num_pages >= initrd_pages) - { - grub_efi_physical_address_t physical_end; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > addr_max) - physical_end = addr_max; - - if (physical_end < page_align (size)) - continue; - - physical_end -= page_align (size); - - if ((physical_end >= addr_min) && - (physical_end >= desc->physical_start) && - (physical_end > addr)) - addr = physical_end; - } - } - - if (addr == 0) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available"); - goto fail; - } - - initrd_mem = grub_efi_allocate_pages (addr, initrd_pages); - if (! initrd_mem) - grub_fatal ("cannot allocate pages"); - - if (grub_file_read (file, initrd_mem, size) != size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - - grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", - (unsigned) addr, (unsigned) size); - - lh->ramdisk_image = addr; - lh->ramdisk_size = size; - lh->root_dev = 0x0100; /* XXX */ - - fail: - if (file) - grub_file_close (file); - - return grub_errno; -} - -static grub_command_t cmd_linux, cmd_initrd; - -GRUB_MOD_INIT(linux) -{ - cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, N_("Load Linux.")); - cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, N_("Load initrd.")); - my_mod = mod; -} - -GRUB_MOD_FINI(linux) -{ - grub_unregister_command (cmd_linux); - grub_unregister_command (cmd_initrd); -} diff --git a/grub-core/loader/i386/ieee1275/linux.c b/grub-core/loader/i386/ieee1275/linux.c deleted file mode 100644 index 9f7556ffa..000000000 --- a/grub-core/loader/i386/ieee1275/linux.c +++ /dev/null @@ -1,311 +0,0 @@ -/* linux.c - boot Linux zImage or bzImage */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000 -#define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000 -#define GRUB_OFW_LINUX_INITRD_ADDR 0x800000 - -#define GRUB_OFW_LINUX_CL_OFFSET 0x1e00 -#define GRUB_OFW_LINUX_CL_LENGTH 0x100 - -static grub_dl_t my_mod; - -static grub_size_t kernel_size; -static char *kernel_addr, *kernel_cmdline; -static grub_size_t initrd_size; - -static grub_err_t -grub_linux_unload (void) -{ - grub_free (kernel_cmdline); - grub_free (kernel_addr); - kernel_cmdline = 0; - kernel_addr = 0; - initrd_size = 0; - - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -/* -static int -grub_ieee1275_debug (void) -{ - struct enter_args - { - struct grub_ieee1275_common_hdr common; - } - args; - - INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0); - - if (IEEE1275_CALL_ENTRY_FN (&args) == -1) - return -1; - - return 0; -} -*/ - -static grub_err_t -grub_linux_boot (void) -{ - struct linux_kernel_params *params; - struct linux_kernel_header *lh; - char *prot_code; - char *bootpath; - grub_ssize_t len; - - bootpath = grub_env_get ("root"); - if (bootpath) - grub_ieee1275_set_property (grub_ieee1275_chosen, - "bootpath", bootpath, - grub_strlen (bootpath) + 1, - &len); - - params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR; - lh = (struct linux_kernel_header *) params; - - grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET); - - params->alt_mem = grub_mmap_get_upper () >> 10; - params->ext_mem = params->alt_mem; - - lh->cmd_line_ptr = (char *) - (GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET); - - params->cl_magic = GRUB_LINUX_CL_MAGIC; - params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET; - - { - grub_term_output_t term; - int found = 0; - FOR_ACTIVE_TERM_OUTPUTS(term) - if (grub_strcmp (term->name, "ofconsole") == 0) - { - grub_uint16_t pos = grub_term_getxy (term); - params->video_cursor_x = pos >> 8; - params->video_cursor_y = pos & 0xff; - params->video_width = grub_term_width (term); - params->video_height = grub_term_height (term); - found = 1; - break; - } - if (!found) - { - params->video_cursor_x = 0; - params->video_cursor_y = 0; - params->video_width = 80; - params->video_height = 25; - } - } - - params->font_size = 16; - - params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; - params->ofw_num_items = 1; - params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; - params->ofw_idt = 0; - - if (initrd_size) - { - lh->type_of_loader = 1; - lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR; - lh->ramdisk_size = initrd_size; - } - - if (kernel_cmdline) - grub_strcpy (lh->cmd_line_ptr, kernel_cmdline); - - prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR; - grub_memcpy (prot_code, kernel_addr, kernel_size); - - asm volatile ("movl %0, %%esi" : : "m" (params)); - asm volatile ("movl %%esi, %%esp" : : ); - asm volatile ("movl %0, %%ecx" : : "m" (prot_code)); - asm volatile ("xorl %%ebx, %%ebx" : : ); - asm volatile ("jmp *%%ecx" : : ); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - struct linux_kernel_header lh; - grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; - int i; - char *dest; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) - { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); - goto fail; - } - - if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) || - (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE))) - { - grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); - goto fail; - } - - setup_sects = lh.setup_sects; - if (! setup_sects) - setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - - real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - grub_dprintf ("linux", "Linux-%s, setup=0x%x, size=0x%x\n", - "bzImage", real_size, prot_size); - - grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); - if (grub_errno) - goto fail; - - kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH); - if (! kernel_cmdline) - goto fail; - - dest = kernel_cmdline; - for (i = 1; - i < argc - && dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline - + GRUB_OFW_LINUX_CL_LENGTH); - i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } - - kernel_addr = grub_malloc (prot_size); - if (! kernel_addr) - goto fail; - - kernel_size = prot_size; - if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size) - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - - if (grub_errno == GRUB_ERR_NONE) - grub_loader_set (grub_linux_boot, grub_linux_unload, 1); - -fail: - - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (kernel_cmdline); - grub_free (kernel_addr); - kernel_cmdline = 0; - kernel_addr = 0; - - grub_dl_unref (my_mod); - } - - return grub_errno; -} - -static grub_err_t -grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } - - if (! kernel_addr) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - initrd_size = grub_file_size (file); - if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR, - initrd_size) != (int) initrd_size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - -fail: - if (file) - grub_file_close (file); - - return grub_errno; -} - -static grub_command_t cmd_linux, cmd_initrd; - -GRUB_MOD_INIT(linux) -{ - cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, N_("Load Linux.")); - cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, N_("Load initrd.")); - my_mod = mod; -} - -GRUB_MOD_FINI(linux) -{ - grub_unregister_command (cmd_linux); - grub_unregister_command (cmd_initrd); -} diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index d3d935182..debcdb71f 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -32,9 +32,23 @@ #include #include #include +#include +#include + +#ifdef GRUB_MACHINE_EFI +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "800x600" +#elif defined (GRUB_MACHINE_IEEE1275) +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "text" +#else #include #include -#include +#define HAS_VGA_TEXT 1 +#define DEFAULT_VIDEO_MODE "text" +#endif #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -44,36 +58,24 @@ static grub_dl_t my_mod; static grub_size_t linux_mem_size; static int loaded; static void *real_mode_mem; +static grub_addr_t real_mode_target; static void *prot_mode_mem; +static grub_addr_t prot_mode_target; static void *initrd_mem; +static grub_addr_t initrd_mem_target; static grub_uint32_t real_mode_pages; static grub_uint32_t prot_mode_pages; static grub_uint32_t initrd_pages; +static struct grub_relocator *relocator = NULL; +static void *efi_mmap_buf; +#ifdef GRUB_MACHINE_EFI +static grub_efi_uintn_t efi_mmap_size; +#else +static const grub_size_t efi_mmap_size = 0; +#endif -static grub_uint8_t gdt[] __attribute__ ((aligned(16))) = - { - /* NULL. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Reserved. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Code segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, - /* Data segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - }; - -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct gdt_descriptor gdt_desc = - { - sizeof (gdt) - 1, - gdt - }; - +/* FIXME */ +#if 0 struct idt_descriptor { grub_uint16_t limit; @@ -85,6 +87,7 @@ static struct idt_descriptor idt_desc = 0, 0 }; +#endif #ifdef GRUB_MACHINE_PCBIOS struct linux_vesafb_res @@ -261,6 +264,48 @@ page_align (grub_size_t size) return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); } +#ifdef GRUB_MACHINE_EFI +/* Find the optimal number of pages for the memory map. Is it better to + move this code to efi/mm.c? */ +static grub_efi_uintn_t +find_efi_mmap_size (void) +{ + static grub_efi_uintn_t mmap_size = 0; + + if (mmap_size != 0) + return mmap_size; + + mmap_size = (1 << 12); + while (1) + { + int ret; + grub_efi_memory_descriptor_t *mmap; + grub_efi_uintn_t desc_size; + + mmap = grub_malloc (mmap_size); + if (! mmap) + return 0; + + ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); + grub_free (mmap); + + if (ret < 0) + grub_fatal ("cannot get memory map"); + else if (ret > 0) + break; + + mmap_size += (1 << 12); + } + + /* Increase the size a bit for safety, because GRUB allocates more on + later, and EFI itself may allocate more. */ + mmap_size += (1 << 12); + + return page_align (mmap_size); +} + +#endif + /* Find the optimal number of pages for the memory map. */ static grub_size_t find_mmap_size (void) @@ -290,32 +335,47 @@ find_mmap_size (void) static void free_pages (void) { + grub_relocator_unload (relocator); + relocator = NULL; real_mode_mem = prot_mode_mem = initrd_mem = 0; + real_mode_target = prot_mode_target = initrd_mem_target = 0; } /* Allocate pages for the real mode code and the protected mode code for linux as well as a memory map buffer. */ -static int +static grub_err_t allocate_pages (grub_size_t prot_size) { grub_size_t real_size, mmap_size; + grub_err_t err; /* Make sure that each size is aligned to a page boundary. */ real_size = GRUB_LINUX_CL_END_OFFSET; prot_size = page_align (prot_size); mmap_size = find_mmap_size (); +#ifdef GRUB_MACHINE_EFI + efi_mmap_size = find_efi_mmap_size (); +#endif + grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size); /* Calculate the number of pages; Combine the real mode code with the memory map buffer for simplicity. */ - real_mode_pages = ((real_size + mmap_size) >> 12); + real_mode_pages = ((real_size + mmap_size + efi_mmap_size) >> 12); prot_mode_pages = (prot_size >> 12); /* Initialize the memory pointers with NULL for convenience. */ free_pages (); + relocator = grub_relocator_new (); + if (!relocator) + { + err = grub_errno; + goto fail; + } + /* FIXME: Should request low memory from the heap when this feature is implemented. */ @@ -336,35 +396,55 @@ allocate_pages (grub_size_t prot_size) if (addr + size > 0x90000) size = 0x90000 - addr; - if (real_size + mmap_size > size) + if (real_size + mmap_size + efi_mmap_size > size) return 0; - real_mode_mem = - (void *) (grub_size_t) ((addr + size) - (real_size + mmap_size)); + real_mode_target = ((addr + size) - (real_size + mmap_size + efi_mmap_size)); return 1; } return 0; } grub_mmap_iterate (hook); - if (! real_mode_mem) + if (! real_mode_target) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); + err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); goto fail; } - prot_mode_mem = (void *) 0x100000; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + real_mode_target, + (real_size + mmap_size + + efi_mmap_size)); + if (err) + goto fail; + real_mode_mem = get_virtual_current_address (ch); + } + efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size; + + prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + prot_mode_target, prot_size); + if (err) + goto fail; + prot_mode_mem = get_virtual_current_address (ch); + } grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " "prot_mode_mem = %lx, prot_mode_pages = %x\n", (unsigned long) real_mode_mem, (unsigned) real_mode_pages, (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); - return 1; + return GRUB_ERR_NONE; fail: free_pages (); - return 0; + return err; } static void @@ -389,7 +469,7 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, } } -static int +static grub_err_t grub_linux_setup_video (struct linux_kernel_params *params) { struct grub_video_mode_info mode_info; @@ -448,14 +528,9 @@ grub_linux_setup_video (struct linux_kernel_params *params) } #endif - return 0; + return GRUB_ERR_NONE; } -#ifdef __x86_64__ -extern grub_uint8_t grub_linux_trampoline_start[]; -extern grub_uint8_t grub_linux_trampoline_end[]; -#endif - static grub_err_t grub_linux_boot (void) { @@ -463,16 +538,26 @@ grub_linux_boot (void) int e820_num; grub_err_t err = 0; char *modevar, *tmp; + struct grub_relocator32_state state; params = real_mode_mem; - grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n", - (unsigned) params->code32_start, - (unsigned long) &(idt_desc.limit), - (unsigned long) &(gdt_desc.limit)); - grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n", - (unsigned) idt_desc.limit, (unsigned long) idt_desc.base, - (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base); +#ifdef GRUB_MACHINE_IEEE1275 + { + char *bootpath; + grub_ssize_t len; + + bootpath = grub_env_get ("root"); + if (bootpath) + grub_ieee1275_set_property (grub_ieee1275_chosen, + "bootpath", bootpath, + grub_strlen (bootpath) + 1, + &len); + } +#endif + + grub_dprintf ("linux", "code32_start = %x\n", + (unsigned) params->code32_start); 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) @@ -522,14 +607,14 @@ grub_linux_boot (void) May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { - tmp = grub_xasprintf ("%s;text", modevar); + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_errno; err = grub_video_set_mode (tmp, 0, 0); grub_free (tmp); } else - err = grub_video_set_mode ("text", 0, 0); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); if (err) { @@ -548,23 +633,34 @@ grub_linux_boot (void) } else { +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; - params->video_width = 80; - params->video_height = 25; + params->video_mode = 0x3; +#else + params->have_vga = 0; + params->video_mode = 0; + params->video_width = 0; + params->video_height = 0; +#endif } /* Initialize these last, because terminal position could be affected by printfs above. */ +#ifndef GRUB_MACHINE_IEEE1275 if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) +#endif { grub_term_output_t term; int found = 0; FOR_ACTIVE_TERM_OUTPUTS(term) if (grub_strcmp (term->name, "vga_text") == 0 - || grub_strcmp (term->name, "console") == 0) + || grub_strcmp (term->name, "console") == 0 + || grub_strcmp (term->name, "ofconsole") == 0) { grub_uint16_t pos = grub_term_getxy (term); params->video_cursor_x = pos >> 8; params->video_cursor_y = pos & 0xff; + params->video_width = grub_term_width (term); + params->video_height = grub_term_height (term); found = 1; break; } @@ -572,34 +668,59 @@ grub_linux_boot (void) { params->video_cursor_x = 0; params->video_cursor_y = 0; + params->video_width = 80; + params->video_height = 25; } } -#ifdef __x86_64__ - - grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12), - grub_linux_trampoline_start, - grub_linux_trampoline_end - grub_linux_trampoline_start); - - ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem - + (prot_mode_pages << 12))) - (params->code32_start, real_mode_mem); -#else - - /* Hardware interrupts are not safe any longer. */ - asm volatile ("cli" : : ); - - /* Load the IDT and the GDT for the bootstrap. */ - asm volatile ("lidt %0" : : "m" (idt_desc)); - asm volatile ("lgdt %0" : : "m" (gdt_desc)); - - /* Enter Linux. */ - asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem), "g" (params->code32_start)); - +#ifdef GRUB_MACHINE_IEEE1275 + { + params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; + params->ofw_num_items = 1; + params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; + params->ofw_idt = 0; + } #endif - /* Never reach here. */ - return GRUB_ERR_NONE; +#ifdef GRUB_MACHINE_EFI + { + grub_efi_uintn_t efi_desc_size; + grub_efi_uint32_t efi_desc_version; + err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, + &efi_desc_size, &efi_desc_version); + if (err) + return err; + + /* Note that no boot services are available from here. */ + + /* Pass EFI parameters. */ + if (grub_le_to_cpu16 (params->version) >= 0x0206) + { + params->v0206.efi_mem_desc_size = efi_desc_size; + params->v0206.efi_mem_desc_version = efi_desc_version; + params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf; + params->v0206.efi_mmap_size = efi_mmap_size; +#ifdef __x86_64__ + params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) efi_mmap_buf >> 32); +#endif + } + else if (grub_le_to_cpu16 (params->version) >= 0x0204) + { + params->v0204.efi_mem_desc_size = efi_desc_size; + params->v0204.efi_mem_desc_version = efi_desc_version; + params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf; + params->v0204.efi_mmap_size = efi_mmap_size; + } + } +#endif + + /* FIXME. */ + /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ + state.ebx = 0; + state.esi = real_mode_target; + state.esp = real_mode_target; + state.eip = params->code32_start; + return grub_relocator32_boot (relocator, state); } static grub_err_t @@ -685,7 +806,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), real_size = setup_sects << GRUB_DISK_SECTOR_BITS; prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - if (! allocate_pages (prot_size)) + if (allocate_pages (prot_size)) goto fail; params = (struct linux_kernel_params *) real_mode_mem; @@ -708,7 +829,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), params->cl_magic = GRUB_LINUX_CL_MAGIC; params->cl_offset = 0x1000; - params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000; + params->cmd_line_ptr = real_mode_target + 0x1000; params->ramdisk_image = 0; params->ramdisk_size = 0; @@ -724,14 +845,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Ignored by Linux. */ params->video_page = 0; - /* Must be non-zero even in text mode, or Linux will think there's no VGA. */ - params->video_mode = 0x3; - /* Only used when `video_mode == 0x7', otherwise ignored. */ params->video_ega_bx = 0; params->font_size = 16; /* XXX */ +#ifdef GRUB_MACHINE_EFI + 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; +#ifdef __x86_64__ + params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) 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; + } +#endif + /* The other parameters are filled when booting. */ grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); @@ -888,7 +1022,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) + if (grub_file_read (file, prot_mode_mem, len) != len) grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) @@ -920,6 +1054,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_ssize_t size; grub_addr_t addr_min, addr_max; grub_addr_t addr; + grub_err_t err; struct linux_kernel_header *lh; if (argc == 0) @@ -967,12 +1102,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), addr_max -= 0x10000; /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) + addr_min = (grub_addr_t) prot_mode_target + ((prot_mode_pages * 3) << 12) + page_align (size); - if (addr_max > grub_os_area_addr + grub_os_area_size) - addr_max = grub_os_area_addr + grub_os_area_size; - /* Put the initrd as high as possible, 4KiB aligned. */ addr = (addr_max - size) & ~0xFFF; @@ -982,7 +1114,16 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - initrd_mem = (void *) addr; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + addr_min, addr, size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH); + if (err) + return err; + initrd_mem = get_virtual_current_address (ch); + initrd_mem_target = get_physical_target_address (ch); + } if (grub_file_read (file, initrd_mem, size) != size) { @@ -993,7 +1134,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", (unsigned) addr, (unsigned) size); - lh->ramdisk_image = addr; + lh->ramdisk_image = initrd_mem_target; lh->ramdisk_size = size; lh->root_dev = 0x0100; /* XXX */ diff --git a/grub-core/loader/i386/linux_trampoline.S b/grub-core/loader/i386/linux_trampoline.S deleted file mode 100644 index 4acea7b11..000000000 --- a/grub-core/loader/i386/linux_trampoline.S +++ /dev/null @@ -1,129 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include - - - .p2align 4 /* force 16-byte alignment */ -VARIABLE(grub_linux_trampoline_start) - cli - /* %rdi contains protected memory start and %rsi - contains real memory start. */ - - mov %rsi, %rbx - - call base -base: - pop %rsi - -#ifdef APPLE_CC - lea (cont1 - base) (%esi, 1), %rax - mov %eax, (jump_vector - base) (%esi, 1) - - lea (gdt - base) (%esi, 1), %rax - mov %rax, (gdtaddr - base) (%esi, 1) - - /* Switch to compatibility mode. */ - - lidt (idtdesc - base) (%esi, 1) - lgdt (gdtdesc - base) (%esi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%esi, 1) -#else - lea (cont1 - base) (%rsi, 1), %rax - mov %eax, (jump_vector - base) (%rsi, 1) - - lea (gdt - base) (%rsi, 1), %rax - mov %rax, (gdtaddr - base) (%rsi, 1) - - /* Switch to compatibility mode. */ - - lidt (idtdesc - base) (%rsi, 1) - lgdt (gdtdesc - base) (%rsi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%rsi, 1) -#endif - -cont1: - .code32 - - /* Update other registers. */ - mov $0x18, %eax - mov %eax, %ds - mov %eax, %es - mov %eax, %fs - mov %eax, %gs - mov %eax, %ss - - /* Disable paging. */ - mov %cr0, %eax - and $0x7fffffff, %eax - mov %eax, %cr0 - - /* Disable amd64. */ - mov $0xc0000080, %ecx - rdmsr - and $0xfffffeff, %eax - wrmsr - - /* Turn off PAE. */ - movl %cr4, %eax - and $0xffffffcf, %eax - mov %eax, %cr4 - - jmp cont2 -cont2: - .code32 - - mov %ebx, %esi - - jmp *%edi - - /* GDT. */ - .p2align 4 -gdt: - /* NULL. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Reserved. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Code segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 - - /* Data segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - -gdtdesc: - .word 31 -gdtaddr: - .quad gdt - -idtdesc: - .word 0 -idtaddr: - .quad 0 - - .p2align 4 -jump_vector: - /* Jump location. Is filled by the code */ - .long 0 - .long 0x10 -VARIABLE(grub_linux_trampoline_end) diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index d984e4e4e..bf17863cf 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -22,7 +22,6 @@ #include #endif #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include @@ -52,6 +52,10 @@ static unsigned modcnt; static char *cmdline = NULL; static grub_uint32_t bootdev; static int bootdev_set; +static grub_size_t elf_sec_num, elf_sec_entsize; +static unsigned elf_sec_shstrndx; +static void *elf_sections; + grub_err_t grub_multiboot_load (grub_file_t file) @@ -103,25 +107,24 @@ grub_multiboot_load (grub_file_t file) int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; + void *source; + grub_relocator_chunk_t ch; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; - grub_multiboot_payload_dest = header->load_addr; - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (! grub_multiboot_payload_orig) + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, header->load_addr, + code_size); + if (err) { + grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); - return grub_errno; + return err; } + source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { @@ -129,7 +132,7 @@ grub_multiboot_load (grub_file_t file) return grub_errno; } - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); @@ -137,11 +140,10 @@ grub_multiboot_load (grub_file_t file) } if (header->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + grub_memset ((grub_uint32_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; - } else { @@ -184,13 +186,14 @@ grub_multiboot_load (grub_file_t file) return err; } -grub_size_t +static grub_size_t grub_multiboot_get_mbi_size (void) { return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + + elf_sec_entsize * elf_sec_num + 256 * sizeof (struct multiboot_color); } @@ -309,20 +312,32 @@ retrieve_video_parameters (struct multiboot_info *mbi, } grub_err_t -grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, - grub_size_t bufsize) +grub_multiboot_make_mbi (grub_uint32_t *target) { - grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; - grub_uint32_t ptrdest = dest + buf_off; struct multiboot_info *mbi; struct multiboot_mod_list *modlist; unsigned i; struct module *cur; grub_size_t mmap_size; - grub_err_t err; + grub_uint8_t *ptrorig; + grub_addr_t ptrdest; - if (bufsize < grub_multiboot_get_mbi_size ()) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + grub_err_t err; + grub_size_t bufsize; + grub_relocator_chunk_t ch; + + bufsize = grub_multiboot_get_mbi_size (); + + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, 0xffffffff - bufsize, + bufsize, 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + ptrorig = get_virtual_current_address (ch); + ptrdest = (grub_addr_t) get_virtual_current_address (ch); + + *target = ptrdest; mbi = (struct multiboot_info *) ptrorig; ptrorig += sizeof (*mbi); @@ -386,6 +401,17 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } + if (elf_sec_num) + { + mbi->u.elf_sec.addr = ptrdest; + grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num); + mbi->u.elf_sec.num = elf_sec_num; + mbi->u.elf_sec.size = elf_sec_entsize; + mbi->u.elf_sec.shndx = elf_sec_shstrndx; + + mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; + } + err = retrieve_video_parameters (mbi, ptrorig, ptrdest); if (err) { @@ -396,6 +422,16 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, return GRUB_ERR_NONE; } +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data) +{ + elf_sec_num = num; + elf_sec_shstrndx = shndx; + elf_sec_entsize = entsize; + elf_sections = data; +} + void grub_multiboot_free_mbi (void) { @@ -416,6 +452,11 @@ grub_multiboot_free_mbi (void) } modules = NULL; modules_last = NULL; + + grub_free (elf_sections); + elf_sections = NULL; + elf_sec_entsize = 0; + elf_sec_num = 0; } grub_err_t diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 04bc66661..82640d77d 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #define GRUB_LINUX_CL_OFFSET 0x9000 @@ -41,22 +42,35 @@ static grub_dl_t my_mod; static grub_size_t linux_mem_size; static int loaded; +static struct grub_relocator *relocator = NULL; +static grub_addr_t grub_linux_real_target; +static char *grub_linux_real_chunk; +static grub_size_t grub_linux16_prot_size; + +static grub_err_t +grub_linux16_boot (void) +{ + grub_uint16_t segment; + struct grub_relocator16_state state; + + segment = grub_linux_real_target >> 4; + state.gs = state.fs = state.es = state.ds = state.ss = segment; + state.sp = GRUB_LINUX_SETUP_STACK; + state.cs = segment + 0x20; + state.ip = 0; + + grub_video_set_mode ("text", 0, 0); + + return grub_relocator16_boot (relocator, state); +} static grub_err_t grub_linux_unload (void) { grub_dl_unref (my_mod); loaded = 0; - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux16_boot (void) -{ - grub_video_set_mode ("text", 0, 0); - grub_linux16_real_boot (); - - /* Not reached. */ + grub_relocator_unload (relocator); + relocator = NULL; return GRUB_ERR_NONE; } @@ -67,10 +81,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_kernel_header lh; grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; + grub_size_t real_size; grub_ssize_t len; int i; char *dest; + char *grub_linux_prot_chunk; + int grub_linux_is_bzimage; + grub_addr_t grub_linux_prot_target; + grub_err_t err; grub_dl_ref (my_mod); @@ -84,14 +102,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! file) goto fail; - if ((grub_size_t) grub_file_size (file) > grub_os_area_size) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "too big kernel (0x%x > 0x%x)", - (grub_size_t) grub_file_size (file), - grub_os_area_size); - goto fail; - } - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); @@ -121,12 +131,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; /* Put the real mode part at as a high location as possible. */ - grub_linux_real_addr - = (char *) UINT_TO_PTR (grub_mmap_get_lower () - - GRUB_LINUX_SETUP_MOVE_SIZE); + grub_linux_real_target = grub_mmap_get_lower () + - GRUB_LINUX_SETUP_MOVE_SIZE; /* But it must not exceed the traditional area. */ - if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR) - grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR; + if (grub_linux_real_target > GRUB_LINUX_OLD_REAL_MODE_ADDR) + grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR; if (grub_le_to_cpu16 (lh.version) >= 0x0201) { @@ -135,7 +144,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } if (grub_le_to_cpu16 (lh.version) >= 0x0202) - lh.cmd_line_ptr = grub_linux_real_addr + GRUB_LINUX_CL_OFFSET; + lh.cmd_line_ptr = grub_linux_real_target + GRUB_LINUX_CL_OFFSET; else { lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC); @@ -151,7 +160,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR; + grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR; } /* If SETUP_SECTS is not set, set it to the default (4). */ @@ -159,32 +168,36 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - grub_linux_tmp_addr = (char *) GRUB_LINUX_BZIMAGE_ADDR + prot_size; + grub_linux16_prot_size = grub_file_size (file) + - real_size - GRUB_DISK_SECTOR_SIZE; if (! grub_linux_is_bzimage - && ((char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size > grub_linux_real_addr)) + && GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size + > grub_linux_real_target) { grub_error (GRUB_ERR_BAD_OS, "too big zImage (0x%x > 0x%x), use bzImage instead", - (char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size, - (grub_size_t) grub_linux_real_addr); + (char *) GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size, + (grub_size_t) grub_linux_real_target); goto fail; } - if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE - > (char *) UINT_TO_PTR (grub_mmap_get_lower ())) + if (grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE + > grub_mmap_get_lower ()) { grub_error (GRUB_ERR_OUT_OF_RANGE, "too small lower memory (0x%x > 0x%x)", - grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE, + grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE, (int) grub_mmap_get_lower ()); goto fail; } - grub_dprintf ("linux", "Linux-%s, setup=0x%x, size=0x%x\n", - grub_linux_is_bzimage ? "bzImage" : "zImage", - real_size, prot_size); + grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", + grub_linux_is_bzimage ? "bzImage" : "zImage", real_size, + grub_linux16_prot_size); + + relocator = grub_relocator_new (); + if (!relocator) + goto fail; for (i = 1; i < argc; i++) if (grub_memcmp (argv[i], "vga=", 4) == 0) @@ -242,11 +255,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_linux_real_target, + GRUB_LINUX_SETUP_MOVE_SIZE); + if (err) + return err; + grub_linux_real_chunk = get_virtual_current_address (ch); + } + /* Put the real mode code at the temporary address. */ - grub_memmove (grub_linux_tmp_addr, &lh, sizeof (lh)); + grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh)); len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); - if (grub_file_read (file, grub_linux_tmp_addr + sizeof (lh), len) != len) + if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; @@ -255,21 +278,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) || grub_le_to_cpu16 (lh.version) < 0x0200) /* Clear the heap space. */ - grub_memset (grub_linux_tmp_addr + grub_memset (grub_linux_real_chunk + ((setup_sects + 1) << GRUB_DISK_SECTOR_BITS), 0, ((GRUB_LINUX_MAX_SETUP_SECTS - setup_sects - 1) << GRUB_DISK_SECTOR_BITS)); /* Specify the boot file. */ - dest = grub_stpcpy (grub_linux_tmp_addr + GRUB_LINUX_CL_OFFSET, + dest = grub_stpcpy (grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET, "BOOT_IMAGE="); dest = grub_stpcpy (dest, argv[0]); /* Copy kernel parameters. */ for (i = 1; i < argc - && dest + grub_strlen (argv[i]) + 1 < (grub_linux_tmp_addr + && dest + grub_strlen (argv[i]) + 1 < (grub_linux_real_chunk + GRUB_LINUX_CL_END_OFFSET); i++) { @@ -277,14 +300,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), dest = grub_stpcpy (dest, argv[i]); } - len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) + if (grub_linux_is_bzimage) + grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; + else + grub_linux_prot_target = GRUB_LINUX_ZIMAGE_ADDR; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_linux_prot_target, + grub_linux16_prot_size); + if (err) + return err; + grub_linux_prot_chunk = get_virtual_current_address (ch); + } + + len = grub_linux16_prot_size; + if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size) + != (grub_ssize_t) grub_linux16_prot_size) grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) { - grub_linux_prot_size = prot_size; - grub_loader_set (grub_linux16_boot, grub_linux_unload, 1); + grub_loader_set (grub_linux16_boot, grub_linux_unload, 0); loaded = 1; } @@ -297,6 +334,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), { grub_dl_unref (my_mod); loaded = 0; + grub_relocator_unload (relocator); } return grub_errno; @@ -308,8 +346,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - grub_addr_t addr_max, addr_min, addr; + grub_addr_t addr_max, addr_min; struct linux_kernel_header *lh; + grub_uint8_t *initrd_chunk; + grub_addr_t initrd_addr; + grub_err_t err; if (argc == 0) { @@ -323,7 +364,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - lh = (struct linux_kernel_header *) grub_linux_tmp_addr; + lh = (struct linux_kernel_header *) grub_linux_real_chunk; if (!(lh->header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) && grub_le_to_cpu16 (lh->version) >= 0x0200)) @@ -355,10 +396,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), worse than that of Linux 2.3.xx, so avoid the last 64kb. */ addr_max -= 0x10000; - if (addr_max > grub_os_area_addr + grub_os_area_size) - addr_max = grub_os_area_addr + grub_os_area_size; - - addr_min = (grub_addr_t) grub_linux_tmp_addr + GRUB_LINUX_CL_END_OFFSET; + addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size; file = grub_file_open (argv[0]); if (!file) @@ -366,22 +404,25 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), size = grub_file_size (file); - /* Put the initrd as high as possible, 4KiB aligned. */ - addr = (addr_max - size) & ~0xFFF; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + addr_min, addr_max - size, + size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH); + if (err) + return err; + initrd_chunk = get_virtual_current_address (ch); + initrd_addr = get_physical_target_address (ch); + } - if (addr < addr_min) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big"); - goto fail; - } - - if (grub_file_read (file, (void *) addr, size) != size) + if (grub_file_read (file, initrd_chunk, size) != size) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } - lh->ramdisk_image = addr; + lh->ramdisk_image = initrd_addr; lh->ramdisk_size = size; fail: diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c new file mode 100644 index 000000000..0c33a0680 --- /dev/null +++ b/grub-core/loader/i386/pc/ntldr.c @@ -0,0 +1,157 @@ +/* chainloader.c - boot another boot loader */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2007,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; +static struct grub_relocator *rel; +static grub_uint32_t edx = 0xffffffff; + +#define GRUB_NTLDR_SEGMENT 0x2000 + +static grub_err_t +grub_ntldr_boot (void) +{ + struct grub_relocator16_state state = { + .cs = GRUB_NTLDR_SEGMENT, + .ip = 0, + .ds = 0, + .es = 0, + .fs = 0, + .gs = 0, + .ss = 0, + .sp = 0x7c00, + .edx = edx + }; + grub_video_set_mode ("text", 0, 0); + + return grub_relocator16_boot (rel, state); +} + +static grub_err_t +grub_ntldr_unload (void) +{ + grub_relocator_unload (rel); + rel = NULL; + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + void *bs, *ntldr; + grub_size_t ntldrsize; + grub_device_t dev; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); + + grub_dl_ref (my_mod); + + rel = grub_relocator_new (); + if (!rel) + goto fail; + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, + GRUB_DISK_SECTOR_SIZE); + if (err) + goto fail; + bs = get_virtual_current_address (ch); + } + + edx = grub_get_root_biosnumber (); + dev = grub_device_open (0); + + if (dev && dev->disk) + { + err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs); + if (err) + { + grub_device_close (dev); + goto fail; + } + } + + if (dev) + grub_device_close (dev); + + ntldrsize = grub_file_size (file); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_NTLDR_SEGMENT << 4, + ntldrsize); + if (err) + goto fail; + ntldr = get_virtual_current_address (ch); + } + + if (grub_file_read (file, ntldr, ntldrsize) + != (grub_ssize_t) ntldrsize) + goto fail; + + grub_loader_set (grub_ntldr_boot, grub_ntldr_unload, 1); + return GRUB_ERR_NONE; + + fail: + + if (file) + grub_file_close (file); + + grub_ntldr_unload (); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(ntldr) +{ + cmd = grub_register_command ("ntldr", grub_cmd_ntldr, + 0, N_("Load NTLDR or BootMGR.")); + my_mod = mod; +} + +GRUB_MOD_FINI(ntldr) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 5f18d744b..643a895e8 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -41,7 +41,6 @@ #define DEFAULT_VIDEO_MODE "auto" char grub_xnu_cmdline[1024]; -grub_uint32_t grub_xnu_heap_will_be_at; grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack; /* Aliases set for some tables. */ @@ -124,6 +123,7 @@ static grub_uint64_t guessfsb (void) { const grub_uint64_t sane_value = 100000000; +#ifndef GRUB_MACHINE_IEEE1275 grub_uint32_t manufacturer[3], max_cpuid, capabilities, msrlow; grub_uint64_t start_tsc; grub_uint64_t end_tsc; @@ -209,6 +209,9 @@ guessfsb (void) return grub_divmod64 (2000 * tsc_ticks_per_ms, ((msrlow >> 7) & 0x3e) + ((msrlow >> 14) & 1), 0); +#else + return sane_value; +#endif } struct property_descriptor @@ -840,8 +843,7 @@ grub_xnu_boot_resume (void) state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; - return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, - state); + return grub_relocator32_boot (grub_xnu_relocator, state); } /* Setup video for xnu. */ @@ -883,6 +885,18 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); if (grub_xnu_bitmap) + { + if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) + err = grub_video_bitmap_create_scaled (&bitmap, + mode_info.width, + mode_info.height, + grub_xnu_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + else + bitmap = grub_xnu_bitmap; + } + + if (bitmap) { if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) err = grub_video_bitmap_create_scaled (&bitmap, @@ -940,18 +954,18 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) grub_err_t grub_xnu_boot (void) { - struct grub_xnu_boot_params *bootparams_relloc; - grub_off_t bootparams_relloc_off; - grub_off_t mmap_relloc_off; + struct grub_xnu_boot_params *bootparams; + grub_addr_t bootparams_target; grub_err_t err; grub_efi_uintn_t memory_map_size = 0; grub_efi_memory_descriptor_t *memory_map; + grub_addr_t memory_map_target; grub_efi_uintn_t map_key = 0; grub_efi_uintn_t descriptor_size = 0; grub_efi_uint32_t descriptor_version = 0; grub_uint64_t firstruntimepage, lastruntimepage; grub_uint64_t curruntimepage; - void *devtree; + grub_addr_t devtree_target; grub_size_t devtreelen; int i; struct grub_relocator32_state state; @@ -995,26 +1009,25 @@ grub_xnu_boot (void) } /* Relocate the boot parameters to heap. */ - bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc)); - if (! bootparams_relloc) - return grub_errno; - bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc - - (grub_uint8_t *) grub_xnu_heap_start; + err = grub_xnu_heap_malloc (sizeof (*bootparams), + (void **) &bootparams, &bootparams_target); + if (err) + return err; /* Set video. */ - err = grub_xnu_set_video (bootparams_relloc); + err = grub_xnu_set_video (bootparams); if (err != GRUB_ERR_NONE) { grub_print_error (); grub_errno = GRUB_ERR_NONE; grub_printf ("Booting in blind mode\n"); - bootparams_relloc->lfb_mode = 0; - bootparams_relloc->lfb_width = 0; - bootparams_relloc->lfb_height = 0; - bootparams_relloc->lfb_depth = 0; - bootparams_relloc->lfb_line_len = 0; - bootparams_relloc->lfb_base = 0; + bootparams->lfb_mode = 0; + bootparams->lfb_width = 0; + bootparams->lfb_height = 0; + bootparams->lfb_depth = 0; + bootparams->lfb_line_len = 0; + bootparams->lfb_base = 0; } if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, @@ -1025,38 +1038,30 @@ grub_xnu_boot (void) /* We will do few allocations later. Reserve some space for possible memory map growth. */ memory_map_size += 20 * descriptor_size; - memory_map = grub_xnu_heap_malloc (memory_map_size); - if (! memory_map) - return grub_errno; - mmap_relloc_off = (grub_uint8_t *) memory_map - - (grub_uint8_t *) grub_xnu_heap_start; - - err = grub_xnu_writetree_toheap (&devtree, &devtreelen); + err = grub_xnu_heap_malloc (memory_map_size, + (void **) &memory_map, &memory_map_target); if (err) return err; - bootparams_relloc = (struct grub_xnu_boot_params *) - (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start); - grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline, - sizeof (bootparams_relloc->cmdline)); + err = grub_xnu_writetree_toheap (&devtree_target, &devtreelen); + if (err) + return err; - bootparams_relloc->devtree - = ((grub_uint8_t *) devtree - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; - bootparams_relloc->devtreelen = devtreelen; + grub_memcpy (bootparams->cmdline, grub_xnu_cmdline, + sizeof (bootparams->cmdline)); - memory_map = (grub_efi_memory_descriptor_t *) - ((grub_uint8_t *) grub_xnu_heap_start + mmap_relloc_off); + bootparams->devtree = devtree_target; + bootparams->devtreelen = devtreelen; - if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, - &map_key, &descriptor_size, - &descriptor_version) <= 0) - return grub_errno; + err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map, + &map_key, &descriptor_size, + &descriptor_version); + if (err) + return err; - bootparams_relloc->efi_system_table - = PTR_TO_UINT32 (grub_autoefi_system_table); + bootparams->efi_system_table = PTR_TO_UINT32 (grub_autoefi_system_table); - firstruntimepage = (((grub_addr_t) grub_xnu_heap_will_be_at + firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1) / GRUB_XNU_PAGESIZE) + 20; curruntimepage = firstruntimepage; @@ -1077,7 +1082,7 @@ grub_xnu_boot (void) <= PTR_TO_UINT64 (grub_autoefi_system_table) && curdesc->physical_start + (curdesc->num_pages << 12) > PTR_TO_UINT64 (grub_autoefi_system_table)) - bootparams_relloc->efi_system_table + bootparams->efi_system_table = PTR_TO_UINT64 (grub_autoefi_system_table) - curdesc->physical_start + curdesc->virtual_start; if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit) @@ -1087,28 +1092,25 @@ grub_xnu_boot (void) lastruntimepage = curruntimepage; - bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off; - bootparams_relloc->efi_mmap_size = memory_map_size; - bootparams_relloc->efi_mem_desc_size = descriptor_size; - bootparams_relloc->efi_mem_desc_version = descriptor_version; + bootparams->efi_mmap = memory_map_target; + bootparams->efi_mmap_size = memory_map_size; + bootparams->efi_mem_desc_size = descriptor_size; + bootparams->efi_mem_desc_version = descriptor_version; - bootparams_relloc->heap_start = grub_xnu_heap_will_be_at; - bootparams_relloc->heap_size = grub_xnu_heap_size; - bootparams_relloc->efi_runtime_first_page = firstruntimepage; + bootparams->heap_start = grub_xnu_heap_target_start; + bootparams->heap_size = grub_xnu_heap_size; + bootparams->efi_runtime_first_page = firstruntimepage; - bootparams_relloc->efi_runtime_npages = lastruntimepage - firstruntimepage; - bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8; + bootparams->efi_runtime_npages = lastruntimepage - firstruntimepage; + bootparams->efi_uintnbits = SIZEOF_OF_UINTN * 8; - bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR; - bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; + bootparams->verminor = GRUB_XNU_BOOTARGS_VERMINOR; + bootparams->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; /* Parameters for asm helper. */ - grub_xnu_stack = bootparams_relloc->heap_start - + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE; - grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at; - - if (! grub_autoefi_exit_boot_services (map_key)) - return grub_error (GRUB_ERR_IO, "can't exit boot services"); + grub_xnu_stack = bootparams->heap_start + + bootparams->heap_size + GRUB_XNU_PAGESIZE; + grub_xnu_arg1 = bootparams_target; grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, descriptor_version,memory_map); @@ -1116,8 +1118,7 @@ grub_xnu_boot (void) state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; state.esp = grub_xnu_stack; - return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, - state); + return grub_relocator32_boot (grub_xnu_relocator, state); } static grub_command_t cmd_devprop_load; diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 64497f466..018cfdcc5 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -33,15 +32,13 @@ #include #include -#define ELF32_LOADMASK (0x00000000UL) -#define ELF64_LOADMASK (0x0000000000000000ULL) - static grub_dl_t my_mod; static int loaded; static grub_size_t linux_size; +static struct grub_relocator *relocator; static grub_uint8_t *playground; static grub_addr_t target_addr, entry_addr; static int linux_argc; @@ -60,15 +57,7 @@ grub_linux_boot (void) state.gpr[5] = target_addr + argv_off; state.gpr[6] = target_addr + envp_off; state.jumpreg = 1; - grub_relocator32_boot (playground, target_addr, state); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux_release_mem (void) -{ - grub_relocator32_free (playground); + grub_relocator32_boot (relocator, state); return GRUB_ERR_NONE; } @@ -76,14 +65,12 @@ grub_linux_release_mem (void) static grub_err_t grub_linux_unload (void) { - grub_err_t err; - - err = grub_linux_release_mem (); + grub_relocator_unload (relocator); grub_dl_unref (my_mod); loaded = 0; - return err; + return GRUB_ERR_NONE; } static grub_err_t @@ -91,9 +78,10 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) { Elf32_Addr base; int extraoff; + grub_err_t err; /* Linux's entry point incorrectly contains a virtual address. */ - entry_addr = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; + entry_addr = elf->ehdr.ehdr32.e_entry; linux_size = grub_elf32_size (elf, &base); if (linux_size == 0) @@ -105,10 +93,20 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) extraoff = linux_size; linux_size += extra_size; - playground = grub_relocator32_alloc (linux_size); - if (!playground) + relocator = grub_relocator_new (); + if (!relocator) return grub_errno; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + target_addr & 0x1fffffff, + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + } + *extra_mem = playground + extraoff; /* Now load the segments into the area we claimed. */ @@ -135,9 +133,10 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) { Elf64_Addr base; int extraoff; + grub_err_t err; /* Linux's entry point incorrectly contains a virtual address. */ - entry_addr = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; + entry_addr = elf->ehdr.ehdr64.e_entry; linux_size = grub_elf64_size (elf, &base); if (linux_size == 0) @@ -149,10 +148,20 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) extraoff = linux_size; linux_size += extra_size; - playground = grub_relocator32_alloc (linux_size); - if (!playground) + relocator = grub_relocator_new (); + if (!relocator) return grub_errno; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + target_addr & 0x1fffffff, + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + } + *extra_mem = playground + extraoff; /* Now load the segments into the area we claimed. */ @@ -322,7 +331,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - grub_size_t overhead; + void *initrd_src; + grub_addr_t initrd_dest; + grub_err_t err; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); @@ -339,19 +350,25 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), size = grub_file_size (file); - overhead = ALIGN_UP (target_addr + linux_size + 0x10000, 0x10000) - - (target_addr + linux_size); + { + grub_relocator_chunk_t ch; - playground = grub_relocator32_realloc (playground, - linux_size + overhead + size); + err = grub_relocator_alloc_chunk_align (relocator, &ch, + target_addr + linux_size + 0x10000, + (0xffffffff - size) + 1, + size, 0x10000, + GRUB_RELOCATOR_PREFERENCE_NONE); - if (!playground) - { - grub_file_close (file); - return grub_errno; - } + if (err) + { + grub_file_close (file); + return err; + } + initrd_src = get_virtual_current_address (ch); + initrd_dest = get_physical_target_address (ch) | 0x80000000; + } - if (grub_file_read (file, playground + linux_size + overhead, size) != size) + if (grub_file_read (file, initrd_src, size) != size) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); grub_file_close (file); @@ -361,7 +378,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_snprintf ((char *) playground + rd_addr_arg_off, sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", - (unsigned long long) target_addr + linux_size + overhead); + (unsigned long long) initrd_dest); ((grub_uint32_t *) (playground + argv_off))[linux_argc] = target_addr + rd_addr_arg_off; linux_argc++; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index b4ea8bf21..1de1def86 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -29,9 +29,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -50,18 +50,14 @@ #include #endif +struct grub_relocator *grub_multiboot_relocator = NULL; +grub_uint32_t grub_multiboot_payload_eip; #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) #define DEFAULT_VIDEO_MODE "text" #else #define DEFAULT_VIDEO_MODE "auto" #endif -grub_size_t grub_multiboot_alloc_mbi; - -char *grub_multiboot_payload_orig; -grub_addr_t grub_multiboot_payload_dest; -grub_size_t grub_multiboot_pure_size; -grub_uint32_t grub_multiboot_payload_eip; static int accepts_video; static int accepts_ega_text; static int console_required; @@ -119,45 +115,23 @@ grub_multiboot_set_video_mode (void) static grub_err_t grub_multiboot_boot (void) { - grub_size_t mbi_size; grub_err_t err; struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE; state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip; - mbi_size = grub_multiboot_get_mbi_size (); - if (grub_multiboot_alloc_mbi < mbi_size) - { - grub_multiboot_payload_orig - = grub_relocator32_realloc (grub_multiboot_payload_orig, - grub_multiboot_pure_size + mbi_size); - if (!grub_multiboot_payload_orig) - return grub_errno; - grub_multiboot_alloc_mbi = mbi_size; - } + err = grub_multiboot_make_mbi (&state.MULTIBOOT_MBI_REGISTER); -#ifdef GRUB_USE_MULTIBOOT2 - state.MULTIBOOT_MBI_REGISTER = ALIGN_UP (grub_multiboot_payload_dest - + grub_multiboot_pure_size, - MULTIBOOT_TAG_ALIGN); -#else - state.MULTIBOOT_MBI_REGISTER = grub_multiboot_payload_dest - + grub_multiboot_pure_size; -#endif - err = grub_multiboot_make_mbi (grub_multiboot_payload_orig, - grub_multiboot_payload_dest, - grub_multiboot_pure_size, mbi_size); if (err) return err; #ifdef GRUB_MACHINE_EFI - if (! grub_efi_finish_boot_services ()) - grub_fatal ("cannot exit boot services"); + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; #endif - grub_relocator32_boot (grub_multiboot_payload_orig, - grub_multiboot_payload_dest, - state); + grub_relocator32_boot (grub_multiboot_relocator, state); /* Not reached. */ return GRUB_ERR_NONE; @@ -168,11 +142,9 @@ grub_multiboot_unload (void) { grub_multiboot_free_mbi (); - grub_relocator32_free (grub_multiboot_payload_orig); + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = NULL; - grub_multiboot_alloc_mbi = 0; - - grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); return GRUB_ERR_NONE; @@ -262,8 +234,11 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), /* Skip filename. */ grub_multiboot_init_mbi (argc - 1, argv + 1); - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_payload_orig = NULL; + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = grub_relocator_new (); + + if (!grub_multiboot_relocator) + goto fail; err = grub_multiboot_load (file); if (err) @@ -279,8 +254,8 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), if (grub_errno != GRUB_ERR_NONE) { - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_free_mbi (); + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = NULL; grub_dl_unref (my_mod); } @@ -293,7 +268,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - char *module = 0; + void *module = NULL; + grub_addr_t target; grub_err_t err; int nounzip = 0; @@ -310,7 +286,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - if (!grub_multiboot_payload_orig) + if (!grub_multiboot_relocator) return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the multiboot kernel first"); @@ -322,15 +298,22 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), return grub_errno; size = grub_file_size (file); - module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); - if (! module) - { - grub_file_close (file); - return grub_errno; - } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, (0xffffffff - size) + 1, + size, MULTIBOOT_MOD_ALIGN, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_file_close (file); + return err; + } + module = get_virtual_current_address (ch); + target = (grub_addr_t) get_virtual_current_address (ch); + } - err = grub_multiboot_add_module ((grub_addr_t) module, size, - argc - 1, argv + 1); + err = grub_multiboot_add_module (target, size, argc - 1, argv + 1); if (err) { grub_file_close (file); diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 78b7c542c..0c29fe9c2 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -51,9 +51,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) { Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer; char *phdr_base; - int lowest_segment = -1, highest_segment = -1; int i; - grub_size_t code_size; if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX) return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); @@ -87,55 +85,45 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) phdr_base = (char *) buffer + ehdr->e_phoff; #define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize)) - for (i = 0; i < ehdr->e_phnum; i++) - if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0) - { - /* Beware that segment 0 isn't necessarily loadable */ - if (lowest_segment == -1 - || phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr) - lowest_segment = i; - if (highest_segment == -1 - || phdr(i)->p_paddr > phdr(highest_segment)->p_paddr) - highest_segment = i; - } - - if (lowest_segment == -1) - return grub_error (GRUB_ERR_BAD_OS, "ELF contains no loadable segments"); - - code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr; - grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr; - - grub_multiboot_pure_size += code_size; - - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (!grub_multiboot_payload_orig) - return grub_errno; - /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) { - if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0) + if (phdr(i)->p_type == PT_LOAD) { - char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (long) (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr)); + grub_err_t err; + void *source; grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n", i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr); - if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) - == (grub_off_t) -1) - return grub_error (GRUB_ERR_BAD_OS, - "invalid offset in program header"); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, phdr(i)->p_paddr, + phdr(i)->p_memsz); + if (err) + { + grub_dprintf ("multiboot_loader", "Error loading phdr %d\n", i); + return err; + } + source = get_virtual_current_address (ch); + } - if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz) - != (grub_ssize_t) phdr(i)->p_filesz) - return grub_error (GRUB_ERR_BAD_OS, - "couldn't read segment from file"); + if (phdr(i)->p_filesz != 0) + { + if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) + == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + + if (grub_file_read (file, source, phdr(i)->p_filesz) + != (grub_ssize_t) phdr(i)->p_filesz) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + } if (phdr(i)->p_filesz < phdr(i)->p_memsz) - grub_memset (load_this_module_at + phdr(i)->p_filesz, 0, + grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0, phdr(i)->p_memsz - phdr(i)->p_filesz); } } @@ -144,14 +132,87 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) if (phdr(i)->p_vaddr <= ehdr->e_entry && phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry) { - grub_multiboot_payload_eip = grub_multiboot_payload_dest - + (ehdr->e_entry - phdr(i)->p_vaddr) + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr); + grub_multiboot_payload_eip = (ehdr->e_entry - phdr(i)->p_vaddr) + + phdr(i)->p_paddr; break; } if (i == ehdr->e_phnum) return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment"); +#if defined (__i386__) || defined (__x86_64__) + +#elif defined (__mips) + grub_multiboot_payload_eip |= 0x80000000; +#else +#error Please complete this +#endif + + if (ehdr->e_shnum) + { + grub_uint8_t *shdr, *shdrptr; + + shdr = grub_malloc (ehdr->e_shnum * ehdr->e_shentsize); + if (!shdr) + return grub_errno; + + if (grub_file_seek (file, ehdr->e_shoff) == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset to section headers"); + + if (grub_file_read (file, shdr, ehdr->e_shnum * ehdr->e_shentsize) + != (grub_ssize_t) ehdr->e_shnum * ehdr->e_shentsize) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read sections headers from file"); + + for (shdrptr = shdr, i = 0; i < ehdr->e_shnum; + shdrptr += ehdr->e_shentsize, i++) + { + Elf_Shdr *sh = (Elf_Shdr *) shdrptr; + void *src; + grub_addr_t target; + grub_err_t err; + + /* This section is a loaded section, + so we don't care. */ + if (sh->sh_addr != 0) + continue; + + /* This section is empty, so we don't care. */ + if (sh->sh_size == 0) + continue; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, + &ch, 0, + (0xffffffff - sh->sh_size) + + 1, sh->sh_size, + sh->sh_addralign, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i); + return err; + } + src = get_virtual_current_address (ch); + target = get_physical_target_address (ch); + } + + if (grub_file_seek (file, sh->sh_offset) == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in section header"); + + if (grub_file_read (file, src, sh->sh_size) + != (grub_ssize_t) sh->sh_size) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + sh->sh_addr = target; + } + grub_multiboot_add_elfsyms (ehdr->e_shnum, ehdr->e_shentsize, + ehdr->e_shstrndx, shdr); + } + #undef phdr return grub_errno; diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 3ad6a6c4a..f453dcc6a 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -55,6 +55,19 @@ static unsigned modcnt; static char *cmdline = NULL; static int bootdev_set; static grub_uint32_t biosdev, slice, part; +static grub_size_t elf_sec_num, elf_sec_entsize; +static unsigned elf_sec_shstrndx; +static void *elf_sections; + +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data) +{ + elf_sec_num = num; + elf_sec_shstrndx = shndx; + elf_sec_entsize = entsize; + elf_sections = data; +} grub_err_t grub_multiboot_load (grub_file_t file) @@ -190,25 +203,24 @@ grub_multiboot_load (grub_file_t file) int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); grub_size_t code_size; + void *source; + grub_relocator_chunk_t ch; if (addr_tag->bss_end_addr) code_size = (addr_tag->bss_end_addr - addr_tag->load_addr); else code_size = load_size; - grub_multiboot_payload_dest = addr_tag->load_addr; - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (! grub_multiboot_payload_orig) + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, addr_tag->load_addr, + code_size); + if (err) { + grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); - return grub_errno; + return err; } + source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { @@ -216,7 +228,7 @@ grub_multiboot_load (grub_file_t file) return grub_errno; } - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); @@ -224,7 +236,7 @@ grub_multiboot_load (grub_file_t file) } if (addr_tag->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + grub_memset ((grub_uint32_t *) source + load_size, 0, addr_tag->bss_end_addr - addr_tag->load_addr - load_size); } else @@ -252,7 +264,7 @@ grub_multiboot_load (grub_file_t file) return err; } -grub_size_t +static grub_size_t grub_multiboot_get_mbi_size (void) { return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) @@ -263,6 +275,8 @@ grub_multiboot_get_mbi_size (void) + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + sizeof (struct multiboot_tag_basic_meminfo) + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) + + sizeof (struct multiboot_tag_elf_sections) + + elf_sec_entsize * elf_sec_num + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)) + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; @@ -456,18 +470,34 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) } grub_err_t -grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, - grub_size_t bufsize) +grub_multiboot_make_mbi (grub_uint32_t *target) { grub_uint8_t *ptrorig; - grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off - + (ALIGN_UP (dest + buf_off, MULTIBOOT_TAG_ALIGN) - (dest + buf_off)); + grub_uint8_t *mbistart; grub_err_t err; + grub_size_t bufsize; + grub_relocator_chunk_t ch; - if (bufsize < grub_multiboot_get_mbi_size ()) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + bufsize = grub_multiboot_get_mbi_size (); - ptrorig = mbistart + 2 * sizeof (grub_uint32_t); + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, 0xffffffff - bufsize, + bufsize, 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptrorig = get_virtual_current_address (ch); +#if defined (__i386__) || defined (__x86_64__) + *target = get_physical_target_address (ch); +#elif defined (__mips) + *target = get_physical_target_address (ch) | 0x80000000; +#else +#error Please complete this +#endif + + mbistart = ptrorig; + ptrorig += 2 * sizeof (grub_uint32_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; @@ -508,6 +538,19 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } + { + struct multiboot_tag_elf_sections *tag + = (struct multiboot_tag_elf_sections *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS; + tag->size = sizeof (struct multiboot_tag_elf_sections) + + elf_sec_entsize * elf_sec_num; + grub_memcpy (tag->sections, elf_sections, elf_sec_entsize * elf_sec_num); + tag->num = elf_sec_num; + tag->entsize = elf_sec_entsize; + tag->shndx = elf_sec_shstrndx; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + { struct multiboot_tag_basic_meminfo *tag = (struct multiboot_tag_basic_meminfo *) ptrorig; diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 6b17a47ad..351d050e5 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c index f55b4fa2a..948729a5d 100644 --- a/grub-core/loader/sparc64/ieee1275/linux.c +++ b/grub-core/loader/sparc64/ieee1275/linux.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index 8f1d0c641..17f850018 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -40,45 +40,30 @@ static int driverspackagenum = 0; static int driversnum = 0; int grub_xnu_is_64bit = 0; -void *grub_xnu_heap_start = 0; +grub_addr_t grub_xnu_heap_target_start = 0; grub_size_t grub_xnu_heap_size = 0; - -/* Allocate heap by 32MB-blocks. */ -#define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000 +struct grub_relocator *grub_xnu_relocator; static grub_err_t grub_xnu_register_memory (char *prefix, int *suffix, - void *addr, grub_size_t size); -void * -grub_xnu_heap_malloc (int size) + grub_addr_t addr, grub_size_t size); +grub_err_t +grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target) { - void *val; - int oldblknum, newblknum; + grub_err_t err; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, + grub_xnu_heap_target_start + + grub_xnu_heap_size, size); + if (err) + return err; - /* The page after the heap is used for stack. Ensure it's usable. */ - if (grub_xnu_heap_size) - oldblknum = (grub_xnu_heap_size + GRUB_XNU_PAGESIZE - + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK; - else - oldblknum = 0; - newblknum = (grub_xnu_heap_size + size + GRUB_XNU_PAGESIZE - + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK; - if (oldblknum != newblknum) - { - /* FIXME: instruct realloc to allocate at 1MB if possible once - advanced mm is ready. */ - grub_xnu_heap_start - = XNU_RELOCATOR (realloc) (grub_xnu_heap_start, - newblknum - * GRUB_XNU_HEAP_ALLOC_BLOCK); - if (!grub_xnu_heap_start) - return NULL; - } - - val = (grub_uint8_t *) grub_xnu_heap_start + grub_xnu_heap_size; + *src = get_virtual_current_address (ch); + *target = grub_xnu_heap_target_start + grub_xnu_heap_size; grub_xnu_heap_size += size; - grub_dprintf ("xnu", "val=%p\n", val); - return val; + grub_dprintf ("xnu", "val=%p\n", *src); + return GRUB_ERR_NONE; } /* Make sure next block of the heap will be aligned. @@ -87,11 +72,9 @@ grub_xnu_heap_malloc (int size) grub_err_t grub_xnu_align_heap (int align) { - int align_overhead = align - grub_xnu_heap_size % align; - if (align_overhead == align) - return GRUB_ERR_NONE; - if (! grub_xnu_heap_malloc (align_overhead)) - return grub_errno; + grub_xnu_heap_size + = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align) + - grub_xnu_heap_target_start; return GRUB_ERR_NONE; } @@ -207,13 +190,14 @@ grub_xnu_writetree_toheap_real (void *curptr, } grub_err_t -grub_xnu_writetree_toheap (void **start, grub_size_t *size) +grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) { struct grub_xnu_devtree_key *chosen; struct grub_xnu_devtree_key *memorymap; struct grub_xnu_devtree_key *driverkey; struct grub_xnu_extdesc *extdesc; grub_err_t err; + void *src; err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) @@ -244,16 +228,17 @@ grub_xnu_writetree_toheap (void **start, grub_size_t *size) /* Allocate the space based on the size with dummy value. */ *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/"); - *start = grub_xnu_heap_malloc (*size + GRUB_XNU_PAGESIZE - - *size % GRUB_XNU_PAGESIZE); + err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE), + &src, target); + if (err) + return err; /* Put real data in the dummy. */ - extdesc->addr = (grub_uint8_t *) *start - (grub_uint8_t *) grub_xnu_heap_start - + grub_xnu_heap_will_be_at; + extdesc->addr = *target; extdesc->size = (grub_uint32_t) *size; /* Write the tree to heap. */ - grub_xnu_writetree_toheap_real (*start, grub_xnu_devtree_root, "/"); + grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/"); return GRUB_ERR_NONE; } @@ -338,8 +323,9 @@ grub_xnu_unload (void) /* Free loaded image. */ driversnum = 0; driverspackagenum = 0; - grub_free (grub_xnu_heap_start); - grub_xnu_heap_start = 0; + grub_relocator_unload (grub_xnu_relocator); + grub_xnu_relocator = NULL; + grub_xnu_heap_target_start = 0; grub_xnu_heap_size = 0; grub_xnu_unlock (); return GRUB_ERR_NONE; @@ -354,6 +340,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_uint32_t startcode, endcode; int i; char *ptr, *loadaddr; + grub_addr_t loadaddr_target; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); @@ -381,15 +368,18 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", (unsigned long) endcode, (unsigned long) startcode); - loadaddr = grub_xnu_heap_malloc (endcode - startcode); - grub_xnu_heap_will_be_at = startcode; + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) + return grub_errno; + grub_xnu_heap_target_start = startcode; + err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + &loadaddr_target); - if (! loadaddr) + if (err) { grub_macho_close (macho); grub_xnu_unload (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough memory to load kernel"); + return err; } /* Load kernel. */ @@ -452,6 +442,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_uint64_t startcode, endcode; int i; char *ptr, *loadaddr; + grub_addr_t loadaddr_target; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); @@ -482,15 +473,18 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", (unsigned long) endcode, (unsigned long) startcode); - loadaddr = grub_xnu_heap_malloc (endcode - startcode); - grub_xnu_heap_will_be_at = startcode; + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) + return grub_errno; + grub_xnu_heap_target_start = startcode; + err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + &loadaddr_target); - if (! loadaddr) + if (err) { grub_macho_close (macho); grub_xnu_unload (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough memory to load kernel"); + return err; } /* Load kernel. */ @@ -548,7 +542,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), and increment SUFFIX. */ static grub_err_t grub_xnu_register_memory (char *prefix, int *suffix, - void *addr, grub_size_t size) + grub_addr_t addr, grub_size_t size) { struct grub_xnu_devtree_key *chosen; struct grub_xnu_devtree_key *memorymap; @@ -585,8 +579,7 @@ grub_xnu_register_memory (char *prefix, int *suffix, = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc)); if (! driverkey->data) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension"); - extdesc->addr = grub_xnu_heap_will_be_at + - ((grub_uint8_t *) addr - (grub_uint8_t *) grub_xnu_heap_start); + extdesc->addr = addr; extdesc->size = (grub_uint32_t) size; return GRUB_ERR_NONE; } @@ -628,7 +621,8 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) grub_file_t infoplist; struct grub_xnu_extheader *exthead; int neededspace = sizeof (*exthead); - grub_uint8_t *buf; + grub_uint8_t *buf, *buf0; + grub_addr_t buf_target; grub_size_t infoplistsize = 0, machosize = 0; char *name, *nameend; int namelen; @@ -683,7 +677,10 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) return err; - buf = grub_xnu_heap_malloc (neededspace); + err = grub_xnu_heap_malloc (neededspace, (void **) &buf0, &buf_target); + if (err) + return err; + buf = buf0; exthead = (struct grub_xnu_extheader *) buf; grub_memset (exthead, 0, sizeof (*exthead)); @@ -692,8 +689,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the binary. */ if (macho) { - exthead->binaryaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->binaryaddr = buf_target + (buf - buf0); exthead->binarysize = machosize; if (grub_xnu_is_64bit) err = grub_macho_readfile64 (macho, buf); @@ -712,8 +708,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the plist. */ if (infoplist) { - exthead->infoplistaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->infoplistaddr = buf_target + (buf - buf0); exthead->infoplistsize = infoplistsize + 1; if (grub_file_read (infoplist, buf, infoplistsize) != (grub_ssize_t) (infoplistsize)) @@ -729,15 +724,14 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) } grub_errno = GRUB_ERR_NONE; - exthead->nameaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->nameaddr = (buf - buf0) + buf_target; exthead->namesize = namelen + 1; grub_memcpy (buf, name, namelen); buf[namelen] = 0; buf += namelen + 1; /* Announce to kernel */ - return grub_xnu_register_memory ("Driver-", &driversnum, exthead, + return grub_xnu_register_memory ("Driver-", &driversnum, buf_target, neededspace); } @@ -748,6 +742,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file; void *loadto; + grub_addr_t loadto_target; grub_err_t err; grub_off_t readoff = 0; grub_ssize_t readlen = -1; @@ -836,11 +831,11 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), return err; } - loadto = grub_xnu_heap_malloc (readlen); - if (! loadto) + err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target); + if (err) { grub_file_close (file); - return grub_errno; + return err; } /* Read the file. */ @@ -855,7 +850,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), /* Pass it to kernel. */ return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum, - loadto, readlen); + loadto_target, readlen); } static grub_err_t @@ -864,6 +859,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file; void *loadto; + grub_addr_t loadto_target; grub_err_t err; grub_size_t size; @@ -884,9 +880,9 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), size = grub_file_size (file); - loadto = grub_xnu_heap_malloc (size); - if (! loadto) - return grub_errno; + err = grub_xnu_heap_malloc (size, &loadto, &loadto_target); + if (err) + return err; if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size)) { @@ -894,7 +890,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } - return grub_xnu_register_memory ("RAMDisk", 0, loadto, size); + return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size); } /* Returns true if the kext should be loaded according to plist diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index e6620e7b7..6aebc1f34 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -45,10 +45,12 @@ grub_xnu_resume (char *imagename) grub_file_t file; grub_size_t total_header_size; struct grub_xnu_hibernate_header hibhead; - grub_uint8_t *buf; - + void *code; + void *image; grub_uint32_t codedest; grub_uint32_t codesize; + grub_addr_t target_image; + grub_err_t err; file = grub_file_open (imagename); if (! file) @@ -94,18 +96,44 @@ grub_xnu_resume (char *imagename) /* Try to allocate necessary space. FIXME: mm isn't good enough yet to handle huge allocations. */ - grub_xnu_hibernate_image = buf = XNU_RELOCATOR (alloc) (hibhead.image_size - + codesize - + GRUB_XNU_PAGESIZE); - if (! buf) + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) { grub_file_close (file); return grub_errno; } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, codedest, + codesize + GRUB_XNU_PAGESIZE); + if (err) + { + grub_file_close (file); + return err; + } + code = get_virtual_current_address (ch); + } + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_xnu_relocator, &ch, 0, + (0xffffffff - hibhead.image_size) + 1, + hibhead.image_size, + GRUB_XNU_PAGESIZE, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_file_close (file); + return err; + } + image = get_virtual_current_address (ch); + target_image = get_physical_target_address (ch); + } + /* Read code part. */ if (grub_file_seek (file, total_header_size) == (grub_off_t) -1 - || grub_file_read (file, buf, codesize) + || grub_file_read (file, code, codesize) != (grub_ssize_t) codesize) { grub_file_close (file); @@ -114,8 +142,7 @@ grub_xnu_resume (char *imagename) /* Read image. */ if (grub_file_seek (file, 0) == (grub_off_t) -1 - || grub_file_read (file, buf + codesize + GRUB_XNU_PAGESIZE, - hibhead.image_size) + || grub_file_read (file, image, hibhead.image_size) != (grub_ssize_t) hibhead.image_size) { grub_file_close (file); @@ -124,12 +151,11 @@ grub_xnu_resume (char *imagename) grub_file_close (file); /* Setup variables needed by asm helper. */ - grub_xnu_heap_will_be_at = codedest; - grub_xnu_heap_start = buf; - grub_xnu_heap_size = codesize + GRUB_XNU_PAGESIZE + hibhead.image_size; + grub_xnu_heap_target_start = codedest; + grub_xnu_heap_size = target_image + hibhead.image_size - codedest; grub_xnu_stack = (codedest + hibhead.stack); grub_xnu_entry_point = (codedest + hibhead.entry_point); - grub_xnu_arg1 = codedest + codesize + GRUB_XNU_PAGESIZE; + grub_xnu_arg1 = target_image; grub_dprintf ("xnu", "entry point 0x%x\n", codedest + hibhead.entry_point); grub_dprintf ("xnu", "image at 0x%x\n", diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index dca002910..6027d0ab3 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -79,6 +79,9 @@ grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), grub_efi_simple_text_output_interface_t *o; unsigned i, j; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; /* For now, do not try to use a surrogate pair. */ @@ -107,6 +110,9 @@ grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) grub_efi_input_key_t key; grub_efi_status_t status; + if (grub_efi_is_finished) + return 0; + if (read_key >= 0) return 1; @@ -204,6 +210,9 @@ grub_console_getkey (struct grub_term_input *term) grub_efi_status_t status; int key; + if (grub_efi_is_finished) + return 0; + if (read_key >= 0) { key = read_key; @@ -236,7 +245,8 @@ grub_console_getwh (struct grub_term_output *term __attribute__ ((unused))) grub_efi_uintn_t columns, rows; o = grub_efi_system_table->con_out; - if (efi_call_4 (o->query_mode, o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS) + if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode, + &columns, &rows) != GRUB_EFI_SUCCESS) { /* Why does this fail? */ columns = 80; @@ -251,6 +261,9 @@ grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return 0; + o = grub_efi_system_table->con_out; return ((o->mode->cursor_column << 8) | o->mode->cursor_row); } @@ -261,6 +274,9 @@ grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; efi_call_3 (o->set_cursor_position, o, x, y); } @@ -271,6 +287,9 @@ grub_console_cls (struct grub_term_output *term __attribute__ ((unused))) grub_efi_simple_text_output_interface_t *o; grub_efi_int32_t orig_attr; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; orig_attr = o->mode->attribute; efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK); @@ -284,6 +303,9 @@ grub_console_setcolorstate (struct grub_term_output *term, { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; switch (state) { @@ -307,6 +329,9 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; efi_call_2 (o->enable_cursor, o, on); } diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c index 315d3527f..f3a804d53 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -227,6 +227,16 @@ grub_ns8250_init (void) } } +/* Return the port number for the UNITth serial device. */ +grub_port_t +grub_ns8250_hw_get_port (const unsigned int unit) +{ + if (unit < GRUB_SERIAL_PORT_NUM) + return serial_hw_io_addr[unit]; + else + return 0; +} + char * grub_serial_ns8250_add_port (grub_port_t port) { diff --git a/grub-core/tests/boot/kbsd.init-i386.S b/grub-core/tests/boot/kbsd.init-i386.S new file mode 100644 index 000000000..7011c79ff --- /dev/null +++ b/grub-core/tests/boot/kbsd.init-i386.S @@ -0,0 +1,125 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 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 . + */ + +#ifdef TARGET_NETBSD +#define SYSCALL_RESET 208 +#elif defined (TARGET_OPENBSD) +#define SYSCALL_RESET 55 +#else +#error unknown target +#endif + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH 165 +#define SYSCALL_INT 0x80 +#define SYSCALL_ARCH_IOPL 2 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x800 + +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movl $SYSCALL_OPEN, %eax + pushl $FLAGS_NONE + pushl $MODE_RDRW + leal device, %ebx + pushl %ebx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + movl %eax, %ecx + + /* write. */ + movl $SYSCALL_WRITE, %eax + pushl $(messageend-message) + leal message, %ebx + pushl %ebx + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + + /* IOPL. */ + movl $SYSCALL_ARCH, %eax + pushl $iopl_arg + pushl $SYSCALL_ARCH_IOPL + pushl $0 + int $SYSCALL_INT + addl $12, %esp + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + pushl $0 + pushl $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC) + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + pushl $1 + pushl $0 + int $SYSCALL_INT + .section ".fini", "ax" +1: jmp 1b + .section ".text", "ax" +1: jmp 1b + /* This section is needed for NetBSD to identify the binary. */ + .section ".note.netbsd.ident", "a" + .long 0x7 + .long 0x4 + .long 0x1 + .ascii "NetBSD" + .byte 0 + .data +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long 3 diff --git a/grub-core/tests/boot/kbsd.init-x86_64.S b/grub-core/tests/boot/kbsd.init-x86_64.S new file mode 100644 index 000000000..81f810e2c --- /dev/null +++ b/grub-core/tests/boot/kbsd.init-x86_64.S @@ -0,0 +1,111 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#ifdef TARGET_NETBSD +#define SYSCALL_RESET 208 +#elif defined (TARGET_OPENBSD) +#define SYSCALL_RESET 55 +#else +#error unknown target +#endif +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH 165 +#define SYSCALL_INT 0x80 +#define SYSCALL_ARCH_IOPL 2 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x800 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movq $SYSCALL_OPEN, %rax + leaq device, %rdi + movq $MODE_RDRW, %rsi + movq $FLAGS_NONE, %rdx + syscall + movq %rax, %rdi + + /* write. */ + movq $SYSCALL_WRITE, %rax + movq $(messageend-message), %rdx + leaq message, %rsi + syscall + + /* IOPL. */ + movq $SYSCALL_ARCH, %rax + movq $SYSCALL_ARCH_IOPL, %rdi + leaq iopl_arg, %rsi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC), %rdi + movq $0, %rsi + syscall + + /* exit (1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall + .section ".fini", "ax" +1: jmp 1b + .section ".text", "ax" +1: jmp 1b + /* This section is needed for NetBSD to identify the binary. */ + .section ".note.netbsd.ident", "a" + .long 0x7 + .long 0x4 + .long 0x1 + .ascii "NetBSD" + .byte 0 + .data +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long 3 diff --git a/grub-core/tests/boot/kbsd.spec.txt b/grub-core/tests/boot/kbsd.spec.txt new file mode 100644 index 000000000..af171bc56 --- /dev/null +++ b/grub-core/tests/boot/kbsd.spec.txt @@ -0,0 +1,3 @@ +. type=dir + dev type=dir + console type=char device=0 mode=666 gid=0 uid=0 diff --git a/grub-core/tests/boot/kernel-8086.S b/grub-core/tests/boot/kernel-8086.S new file mode 100644 index 000000000..20040dabc --- /dev/null +++ b/grub-core/tests/boot/kernel-8086.S @@ -0,0 +1,69 @@ + +#define SHUTDOWN_PORT 0x8900 + + .text + .globl _start +_start: +base: + .code16 + jmp cont + +portmsg: + xorw %ax, %ax +1: + movb 0(%si), %al + test %ax, %ax + jz 1f + outb %al, %dx + incw %si + jmp 1b +1: + ret + +serialmsg: +1: + movb 0(%si), %bl + testb %bl, %bl + jz 1f + movw $0x3fd, %dx +2: + inb %dx, %al + testb $0x20, %al + jz 2b + + movw $0x3f8, %dx + movb %bl, %al + outb %al, %dx + incw %si + jmp 1b +1: + ret + +cont: +#ifdef TARGET_NTLDR + movw $0x2000, %ax +#elif defined (TARGET_CHAINLOADER) + xorw %ax, %ax +#else +#error unsupported target +#endif + movw %ax, %ds + lea message, %si + call serialmsg + lea shutdown, %si + movw $SHUTDOWN_PORT, %dx + call portmsg + +1: + hlt + jmp 1b + +shutdown: + .ascii "Shutdown" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" + .byte 0 + + . = base + 510 + .short 0xaa55 \ No newline at end of file diff --git a/grub-core/tests/boot/kernel-i386.S b/grub-core/tests/boot/kernel-i386.S new file mode 100644 index 000000000..904b0d4c7 --- /dev/null +++ b/grub-core/tests/boot/kernel-i386.S @@ -0,0 +1,89 @@ +#define ASM_FILE 1 +#ifdef TARGET_MULTIBOOT2 +#include +#elif defined (TARGET_MULTIBOOT) +#include +#endif + +#define SHUTDOWN_PORT 0x8900 + + .text + /* Align 32 bits boundary. */ + .align 8 + +#ifdef TARGET_MULTIBOOT2 + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long MULTIBOOT2_HEADER_MAGIC + /* ISA: i386 */ + .long MULTIBOOT_ARCHITECTURE_I386 + /* Header length. */ + .long multiboot_header_end - multiboot_header + /* checksum */ + .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header)) + .short MULTIBOOT_HEADER_TAG_END + .short 0 + .long 8 +multiboot_header_end: +#elif defined (TARGET_MULTIBOOT) + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long MULTIBOOT_HEADER_MAGIC + /* flags */ + .long 0 + /* checksum */ + .long -MULTIBOOT_HEADER_MAGIC +#endif + + .global start +portmsg: + xorl %eax, %eax +1: + movb 0(%esi), %al + test %eax, %eax + jz 1f + outb %al, %dx + incl %esi + jmp 1b +1: + ret + +serialmsg: +1: + movb 0(%esi), %bl + testb %bl, %bl + jz 1f + movw $0x3fd, %dx +2: + inb %dx, %al + testb $0x20, %al + jz 2b + + movw $0x3f8, %dx + movb %bl, %al + outb %al, %dx + incl %esi + jmp 1b +1: + ret + + .globl _start +_start: + lea message, %esi + call serialmsg + lea shutdown, %esi + movw $SHUTDOWN_PORT, %dx + call portmsg + +1: + hlt + jmp 1b + +shutdown: + .ascii "Shutdown" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" + .byte 0 diff --git a/grub-core/tests/boot/kfreebsd-aout.cfg b/grub-core/tests/boot/kfreebsd-aout.cfg new file mode 100644 index 000000000..31e34b4ee --- /dev/null +++ b/grub-core/tests/boot/kfreebsd-aout.cfg @@ -0,0 +1,4 @@ +kfreebsd /kfreebsd.aout +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kfreebsd.cfg b/grub-core/tests/boot/kfreebsd.cfg new file mode 100644 index 000000000..f28ee7998 --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.cfg @@ -0,0 +1,8 @@ +kfreebsd /kfreebsd -hv +kfreebsd_loadenv /kfreebsd_env +kfreebsd_module /mfsroot.gz type=mfs_root +set kFreeBSD.hw.hasbrokenint12=1 +fakebios +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kfreebsd.init-i386.S b/grub-core/tests/boot/kfreebsd.init-i386.S new file mode 100644 index 000000000..12c94a036 --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.init-i386.S @@ -0,0 +1,114 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 55 +#define SYSCALL_FSYNC 95 +#define SYSCALL_ARCH 165 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH_IOPL 4 +#define SYSCALL_INT 0x80 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x4000 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movl $SYSCALL_OPEN, %eax + pushl $FLAGS_NONE + pushl $MODE_RDRW + leal device, %ebx + pushl %ebx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + movl %eax, %ecx + + /* write. */ + movl $SYSCALL_WRITE, %eax + pushl $(messageend-message) + leal message, %ebx + pushl %ebx + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + + /* fsync. */ + movl $SYSCALL_FSYNC, %eax + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* IOPL. */ + movl $SYSCALL_ARCH, %eax + pushl $iopl_arg + pushl $SYSCALL_ARCH_IOPL + pushl $0 + int $SYSCALL_INT + addl $12, %esp + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + pushl $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC) + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + pushl $1 + pushl $0 + int $SYSCALL_INT +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long SHUTDOWN_PORT + .long 1 + .long 1 diff --git a/grub-core/tests/boot/kfreebsd.init-x86_64.S b/grub-core/tests/boot/kfreebsd.init-x86_64.S new file mode 100644 index 000000000..0a9ff511e --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.init-x86_64.S @@ -0,0 +1,98 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_ARCH 165 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 55 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH_IOPL 4 +#define SYSCALL_FSYNC 95 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x4000 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movq $SYSCALL_OPEN, %rax + leaq device, %rdi + movq $MODE_RDRW, %rsi + movq $FLAGS_NONE, %rdx + syscall + movq %rax, %rdi + + /* write. */ + leaq message, %rsi + movq $SYSCALL_WRITE, %rax + movq $(messageend - message), %rdx + syscall + + /* fsync. */ + movq $SYSCALL_FSYNC, %rax + syscall + + /* IOPL. */ + movq $SYSCALL_ARCH, %rax + movq $SYSCALL_ARCH_IOPL, %rdi + leaq iopl_arg, %rsi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC), %rdi + syscall + + /* exit (1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long SHUTDOWN_PORT + .long 1 + .long 1 diff --git a/grub-core/tests/boot/knetbsd.cfg b/grub-core/tests/boot/knetbsd.cfg new file mode 100644 index 000000000..f88a846e1 --- /dev/null +++ b/grub-core/tests/boot/knetbsd.cfg @@ -0,0 +1,5 @@ +knetbsd /knetbsd -h +knetbsd_module_elf /miniroot.gz +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kopenbsd.cfg b/grub-core/tests/boot/kopenbsd.cfg new file mode 100644 index 000000000..132bec4b6 --- /dev/null +++ b/grub-core/tests/boot/kopenbsd.cfg @@ -0,0 +1,5 @@ +kopenbsd /kopenbsd -h +kopenbsd_ramdisk /ramdisk +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kopenbsdlabel.txt b/grub-core/tests/boot/kopenbsdlabel.txt new file mode 100644 index 000000000..bb141133b --- /dev/null +++ b/grub-core/tests/boot/kopenbsdlabel.txt @@ -0,0 +1,3 @@ +# size offset fstype [fsize bsize bps/cpg] + a: 256 0 4.2BSD 0 0 1 + c: 256 0 unused 0 0 # "raw" part, don't edit diff --git a/grub-core/tests/boot/linux.cfg b/grub-core/tests/boot/linux.cfg new file mode 100644 index 000000000..f5bf6ac7d --- /dev/null +++ b/grub-core/tests/boot/linux.cfg @@ -0,0 +1,5 @@ +linux /linux console=ttyS0 root=/dev/ram0 +initrd /initrd +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/linux.init-i386.S b/grub-core/tests/boot/linux.init-i386.S new file mode 100644 index 000000000..5b0088e00 --- /dev/null +++ b/grub-core/tests/boot/linux.init-i386.S @@ -0,0 +1,79 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 88 +#define SYSCALL_IOPL 110 +#define SYSCALL_EXIT 1 +#define SYSCALL_INT 0x80 + +#define STDOUT 1 +#define SHUTDOWN_MAGIC1 0xfee1dead +#define SHUTDOWN_MAGIC2 0x28121969 +#define SHUTDOWN_MAGIC3 0x4321fedc + +#define SHUTDOWN_PORT 0x8900 + + .text + .global start, _start +_start: +start: + /* write. */ + movl $SYSCALL_WRITE, %eax + movl $STDOUT, %ebx + leal message, %ecx + movl $(messageend-message), %edx + int $SYSCALL_INT + + movl $SYSCALL_IOPL, %eax + movl $3, %ebx + int $SYSCALL_INT + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + movl $SHUTDOWN_MAGIC1, %ebx + movl $SHUTDOWN_MAGIC2, %ecx + movl $SHUTDOWN_MAGIC3, %edx + int $SYSCALL_INT + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + movl $1, %ebx + int $SYSCALL_INT + .data +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: diff --git a/grub-core/tests/boot/linux.init-x86_64.S b/grub-core/tests/boot/linux.init-x86_64.S new file mode 100644 index 000000000..fc32dfd91 --- /dev/null +++ b/grub-core/tests/boot/linux.init-x86_64.S @@ -0,0 +1,78 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define SYSCALL_WRITE 1 +#define SYSCALL_RESET 169 +#define SYSCALL_IOPL 172 +#define SYSCALL_EXIT 60 + +#define STDOUT 1 +#define SHUTDOWN_MAGIC1 0xfee1dead +#define SHUTDOWN_MAGIC2 0x28121969 +#define SHUTDOWN_MAGIC3 0x4321fedc + +#define SHUTDOWN_PORT 0x8900 + + .text + .global start, _start +_start: +start: + /* write. */ + movq $SYSCALL_WRITE, %rax + movq $STDOUT, %rdi + leaq message, %rsi + movq $(messageend-message), %rdx + syscall + + movq $SYSCALL_IOPL, %rax + movq $3, %rdi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $SHUTDOWN_MAGIC1, %rdi + movq $SHUTDOWN_MAGIC2, %rsi + movq $SHUTDOWN_MAGIC3, %rdx + syscall + + /* exit(1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall + .data +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: diff --git a/grub-core/tests/boot/linux16.cfg b/grub-core/tests/boot/linux16.cfg new file mode 100644 index 000000000..d7fbf961c --- /dev/null +++ b/grub-core/tests/boot/linux16.cfg @@ -0,0 +1,5 @@ +linux16 /linux console=ttyS0 root=/dev/ram0 +initrd16 /initrd +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/multiboot.cfg b/grub-core/tests/boot/multiboot.cfg new file mode 100644 index 000000000..0942ec67c --- /dev/null +++ b/grub-core/tests/boot/multiboot.cfg @@ -0,0 +1,4 @@ +multiboot /multiboot.elf +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/multiboot2.cfg b/grub-core/tests/boot/multiboot2.cfg new file mode 100644 index 000000000..2bec9e6d1 --- /dev/null +++ b/grub-core/tests/boot/multiboot2.cfg @@ -0,0 +1,4 @@ +multiboot2 /multiboot2.elf +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/ntldr.cfg b/grub-core/tests/boot/ntldr.cfg new file mode 100644 index 000000000..cd438a4bc --- /dev/null +++ b/grub-core/tests/boot/ntldr.cfg @@ -0,0 +1,4 @@ +ntldr /ntldr.bin +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/pc-chainloader.cfg b/grub-core/tests/boot/pc-chainloader.cfg new file mode 100644 index 000000000..1e80a5b96 --- /dev/null +++ b/grub-core/tests/boot/pc-chainloader.cfg @@ -0,0 +1,4 @@ +chainloader /pc-chainloader.bin +boot +# Shouln't happen +halt diff --git a/include/grub/aout.h b/include/grub/aout.h index f962a97b3..10d7dde61 100644 --- a/include/grub/aout.h +++ b/include/grub/aout.h @@ -120,8 +120,8 @@ union grub_aout_header int EXPORT_FUNC(grub_aout_get_type) (union grub_aout_header *header); grub_err_t EXPORT_FUNC(grub_aout_load) (grub_file_t file, int offset, - grub_addr_t load_addr, int load_size, - grub_addr_t bss_end_addr); + void *load_addr, int load_size, + grub_size_t bss_size); #endif diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h index 5ae4b3a21..740be3249 100644 --- a/include/grub/autoefi.h +++ b/include/grub/autoefi.h @@ -50,6 +50,7 @@ static inline grub_err_t grub_autoefi_prepare (void) # define SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x)) # define SIZEOF_OF_UINTN sizeof (grub_efi_uintn_t) # define SYSTEM_TABLE(x) (grub_efi_system_table->x) +# define grub_autoefi_finish_boot_services grub_efi_finish_boot_services # define EFI_PRESENT 1 #else # include @@ -72,6 +73,7 @@ static inline grub_err_t grub_autoefi_prepare (void) # 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 +# define grub_autoefi_finish_boot_services grub_efiemu_finish_boot_services # define EFI_PRESENT 1 #endif diff --git a/include/grub/dl.h b/include/grub/dl.h index 9db610467..afc4af41a 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -101,7 +101,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); void grub_dl_unload_unneeded (void); -void grub_dl_unload_all (void); int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); extern grub_dl_t EXPORT_VAR(grub_dl_head); diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 5852a476f..e9c57dd11 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -53,8 +53,10 @@ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); grub_efi_device_path_t * EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); -int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key); -int EXPORT_FUNC (grub_efi_finish_boot_services) (void); +grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version); grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, grub_efi_uintn_t descriptor_size, grub_efi_uint32_t descriptor_version, @@ -70,4 +72,6 @@ void grub_efi_set_prefix (void); extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +extern int EXPORT_VAR(grub_efi_is_finished); + #endif /* ! GRUB_EFI_EFI_HEADER */ diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 3980d32cd..56d4ea8ee 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -217,13 +217,20 @@ int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t *map_key, grub_efi_uintn_t *descriptor_size, grub_efi_uint32_t *descriptor_version); + + +grub_err_t +grub_efiemu_finish_boot_services (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_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); int grub_efiemu_sizeof_uintn_t (void); -int grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key); -int grub_efiemu_finish_boot_services (void); grub_err_t grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper); #define GRUB_EFIEMU_MEMORY_AVAILABLE 1 @@ -283,4 +290,6 @@ grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, __attribute__ ((unused)), grub_efi_memory_descriptor_t *virtual_map); +grub_err_t grub_machine_efiemu_init_tables (void); + #endif /* ! GRUB_EFI_EMU_HEADER */ diff --git a/include/grub/elfload.h b/include/grub/elfload.h index 77ee41675..83fb9128a 100644 --- a/include/grub/elfload.h +++ b/include/grub/elfload.h @@ -54,5 +54,13 @@ int grub_elf_is_elf64 (grub_elf_t); grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *); grub_err_t grub_elf64_load (grub_elf_t, grub_elf64_load_hook_t, grub_addr_t *, grub_size_t *); +grub_err_t +grub_elf32_phdr_iterate (grub_elf_t elf, + int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf32_Phdr *, void *), + void *hook_arg); +grub_err_t +grub_elf64_phdr_iterate (grub_elf_t elf, + int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf64_Phdr *, void *), + void *hook_arg); #endif /* ! GRUB_ELFLOAD_HEADER */ diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h index 4d55f04fb..53008cdaf 100644 --- a/include/grub/i386/bsd.h +++ b/include/grub/i386/bsd.h @@ -20,6 +20,8 @@ #define GRUB_BSD_CPU_HEADER 1 #include +#include + #include #include #include @@ -27,7 +29,6 @@ #include #include - enum bsd_kernel_types { KERNEL_TYPE_NONE, @@ -65,35 +66,55 @@ struct grub_freebsd_bootinfo grub_uint32_t tags; } __attribute__ ((packed)); -struct grub_openbsd_bios_mmap +struct freebsd_tag_header { - grub_uint64_t addr; - grub_uint64_t len; -#define OPENBSD_MMAP_AVAILABLE 1 -#define OPENBSD_MMAP_RESERVED 2 -#define OPENBSD_MMAP_ACPI 3 -#define OPENBSD_MMAP_NVS 4 grub_uint32_t type; + grub_uint32_t len; }; -void grub_unix_real_boot (grub_addr_t entry, ...) - __attribute__ ((cdecl,noreturn)); -grub_err_t grub_freebsd_load_elfmodule32 (grub_file_t file, int argc, +grub_err_t grub_freebsd_load_elfmodule32 (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elfmodule_obj64 (grub_file_t file, int argc, +grub_err_t grub_freebsd_load_elfmodule_obj64 (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elf_meta32 (grub_file_t file, +grub_err_t grub_freebsd_load_elf_meta32 (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elf_meta64 (grub_file_t file, +grub_err_t grub_freebsd_load_elf_meta64 (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end); -grub_err_t grub_freebsd_add_meta (grub_uint32_t type, void *data, - grub_uint32_t len); +grub_err_t grub_netbsd_load_elf_meta32 (struct grub_relocator *relocator, + grub_file_t file, + grub_addr_t *kern_end); +grub_err_t grub_netbsd_load_elf_meta64 (struct grub_relocator *relocator, + grub_file_t file, + grub_addr_t *kern_end); + +grub_err_t grub_bsd_add_meta (grub_uint32_t type, + void *data, grub_uint32_t len); grub_err_t grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, grub_addr_t addr, grub_uint32_t size); +struct grub_openbsd_ramdisk_descriptor +{ + grub_size_t max_size; + grub_uint8_t *target; + grub_uint32_t *size; +}; + +grub_err_t grub_openbsd_find_ramdisk32 (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc); +grub_err_t grub_openbsd_find_ramdisk64 (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc); + extern grub_uint8_t grub_bsd64_trampoline_start, grub_bsd64_trampoline_end; extern grub_uint32_t grub_bsd64_trampoline_selfjump; extern grub_uint32_t grub_bsd64_trampoline_gdt; diff --git a/include/grub/i386/coreboot/loader.h b/include/grub/i386/coreboot/loader.h deleted file mode 100644 index d3f36bba5..000000000 --- a/include/grub/i386/coreboot/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/efi/loader.h b/include/grub/i386/efi/loader.h deleted file mode 100644 index 222dae82d..000000000 --- a/include/grub/i386/efi/loader.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,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 . - */ - -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index f02a722d6..63f99db62 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -124,7 +124,7 @@ struct linux_kernel_header grub_uint32_t bootsect_kludge; /* obsolete */ grub_uint16_t heap_end_ptr; /* Free memory after setup end */ grub_uint16_t pad1; /* Unused */ - char *cmd_line_ptr; /* Points to the kernel command line */ + grub_uint32_t cmd_line_ptr; /* Points to the kernel command line */ grub_uint32_t initrd_addr_max; /* Highest address for initrd */ } __attribute__ ((packed)); diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h deleted file mode 100644 index 05954b6db..000000000 --- a/include/grub/i386/loader.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_LOADER_CPU_HEADER -#define GRUB_LOADER_CPU_HEADER 1 - -#include -#include -#include - -extern grub_addr_t EXPORT_VAR(grub_os_area_addr); -extern grub_size_t EXPORT_VAR(grub_os_area_size); - -#ifdef GRUB_MACHINE_PCBIOS -extern grub_uint32_t EXPORT_VAR(grub_linux_prot_size); -extern char *EXPORT_VAR(grub_linux_tmp_addr); -extern char *EXPORT_VAR(grub_linux_real_addr); -extern grub_int32_t EXPORT_VAR(grub_linux_is_bzimage); -grub_err_t EXPORT_FUNC(grub_linux16_real_boot) (void); -#endif - -#endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h index 466947cc6..4f9a3c916 100644 --- a/include/grub/i386/memory.h +++ b/include/grub/i386/memory.h @@ -22,9 +22,34 @@ /* The flag for protected mode. */ #define GRUB_MEMORY_CPU_CR0_PE_ON 0x1 -#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000040 +#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000020 +#define GRUB_MEMORY_CPU_CR4_PSE_ON 0x00000010 #define GRUB_MEMORY_CPU_CR0_PAGING_ON 0x80000000 #define GRUB_MEMORY_CPU_AMD64_MSR 0xc0000080 #define GRUB_MEMORY_CPU_AMD64_MSR_ON 0x00000100 +#ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return (grub_phys_addr_t) a; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) a; +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + +#endif + #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h index 1c711fad4..a1b94883d 100644 --- a/include/grub/i386/multiboot.h +++ b/include/grub/i386/multiboot.h @@ -19,11 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -extern grub_uint32_t grub_multiboot_payload_eip; -extern char *grub_multiboot_payload_orig; -extern grub_addr_t grub_multiboot_payload_dest; -extern grub_size_t grub_multiboot_payload_size; - #define MULTIBOOT_INITIAL_STATE { .eax = MULTIBOOT_BOOTLOADER_MAGIC, \ .ecx = 0, \ .edx = 0, \ diff --git a/include/grub/i386/multiboot/loader.h b/include/grub/i386/multiboot/loader.h deleted file mode 100644 index 1c725be19..000000000 --- a/include/grub/i386/multiboot/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/netbsd_bootinfo.h b/include/grub/i386/netbsd_bootinfo.h index 776ecf3b0..fd429a251 100644 --- a/include/grub/i386/netbsd_bootinfo.h +++ b/include/grub/i386/netbsd_bootinfo.h @@ -49,64 +49,90 @@ #include - #define NETBSD_BTINFO_BOOTPATH 0 #define NETBSD_BTINFO_ROOTDEVICE 1 -#define NETBSD_BTINFO_BOOTDISK 3 +#define NETBSD_BTINFO_CONSOLE 6 +#define NETBSD_BTINFO_SYMTAB 8 #define NETBSD_BTINFO_MEMMAP 9 +#define NETBSD_BTINFO_MODULES 11 +#define NETBSD_BTINFO_FRAMEBUF 12 + +struct grub_netbsd_bootinfo +{ + grub_uint32_t bi_count; + grub_uint32_t bi_data[0]; +}; struct grub_netbsd_btinfo_common { - int len; - int type; -}; - -struct grub_netbsd_btinfo_mmap_header -{ - struct grub_netbsd_btinfo_common common; - grub_uint32_t count; -}; - -struct grub_netbsd_btinfo_mmap_entry -{ - grub_uint64_t addr; - grub_uint64_t len; -#define NETBSD_MMAP_AVAILABLE 1 -#define NETBSD_MMAP_RESERVED 2 -#define NETBSD_MMAP_ACPI 3 -#define NETBSD_MMAP_NVS 4 + grub_uint32_t len; grub_uint32_t type; }; -struct grub_netbsd_btinfo_bootpath -{ - struct grub_netbsd_btinfo_common common; - char bootpath[80]; -}; - -struct grub_netbsd_btinfo_rootdevice -{ - struct grub_netbsd_btinfo_common common; - char devname[16]; -}; +#define GRUB_NETBSD_MAX_BOOTPATH_LEN 80 struct grub_netbsd_btinfo_bootdisk { - struct grub_netbsd_btinfo_common common; - int labelsector; /* label valid if != -1 */ + grub_uint32_t labelsector; /* label valid if != 0xffffffff */ struct { grub_uint16_t type, checksum; char packname[16]; } label; - int biosdev; - int partition; + grub_uint32_t biosdev; + grub_uint32_t partition; }; -struct grub_netbsd_bootinfo +struct grub_netbsd_btinfo_symtab { - grub_uint32_t bi_count; - void *bi_data[1]; + grub_uint32_t nsyms; + grub_uint32_t ssyms; + grub_uint32_t esyms; }; + +struct grub_netbsd_btinfo_serial +{ + char devname[16]; + grub_uint32_t addr; + grub_uint32_t speed; +}; + +struct grub_netbsd_btinfo_modules +{ + grub_uint32_t num; + grub_uint32_t last_addr; + struct grub_netbsd_btinfo_module + { + char name[80]; +#define GRUB_NETBSD_MODULE_RAW 0 +#define GRUB_NETBSD_MODULE_ELF 1 + grub_uint32_t type; + grub_uint32_t size; + grub_uint32_t addr; + } mods[0]; +}; + +struct grub_netbsd_btinfo_framebuf +{ + grub_uint64_t fbaddr; + grub_uint32_t flags; + grub_uint32_t width; + grub_uint32_t height; + grub_uint16_t pitch; + grub_uint8_t bpp; + + grub_uint8_t red_mask_size; + grub_uint8_t green_mask_size; + grub_uint8_t blue_mask_size; + + grub_uint8_t red_field_pos; + grub_uint8_t green_field_pos; + grub_uint8_t blue_field_pos; + + grub_uint8_t reserved[16]; +}; + +#define GRUB_NETBSD_MAX_ROOTDEVICE_LEN 16 + #endif diff --git a/include/grub/i386/openbsd_bootarg.h b/include/grub/i386/openbsd_bootarg.h index ccbe1ca12..935dfc0c8 100644 --- a/include/grub/i386/openbsd_bootarg.h +++ b/include/grub/i386/openbsd_bootarg.h @@ -61,12 +61,22 @@ #define OPENBSD_BOOTARG_END -1 #define OPENBSD_BOOTARG_MMAP 0 +#define OPENBSD_BOOTARG_CONSOLE 5 struct grub_openbsd_bootargs { - int ba_type; - int ba_size; - struct grub_openbsd_bootargs *ba_next; + grub_uint32_t ba_type; + grub_uint32_t ba_size; + grub_uint32_t ba_next; } __attribute__ ((packed)); +struct grub_openbsd_bootarg_console +{ + grub_uint32_t device; + grub_uint32_t speed; +}; + +#define GRUB_OPENBSD_COM_MAJOR 8 +#define GRUB_OPENBSD_VGA_MAJOR 12 + #endif diff --git a/include/grub/i386/pc/loader.h b/include/grub/i386/pc/loader.h index 3e031413b..bfbcaac5a 100644 --- a/include/grub/i386/pc/loader.h +++ b/include/grub/i386/pc/loader.h @@ -20,7 +20,6 @@ #define GRUB_LOADER_MACHINE_HEADER 1 #include -#include /* This is an asm part of the chainloader. */ void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); diff --git a/include/grub/i386/qemu/loader.h b/include/grub/i386/qemu/loader.h deleted file mode 100644 index d3f36bba5..000000000 --- a/include/grub/i386/qemu/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index ef7fe23aa..891235f9b 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -21,6 +21,7 @@ #include #include +#include struct grub_relocator32_state { @@ -30,12 +31,42 @@ struct grub_relocator32_state grub_uint32_t ecx; grub_uint32_t edx; grub_uint32_t eip; + grub_uint32_t esi; }; -void *grub_relocator32_alloc (grub_size_t size); -grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, +struct grub_relocator16_state +{ + grub_uint16_t cs; + grub_uint16_t ds; + grub_uint16_t es; + grub_uint16_t fs; + grub_uint16_t gs; + grub_uint16_t ss; + grub_uint16_t sp; + grub_uint16_t ip; + grub_uint32_t edx; +}; + +struct grub_relocator64_state +{ + grub_uint64_t rsp; + grub_uint64_t rax; + grub_uint64_t rbx; + grub_uint64_t rcx; + grub_uint64_t rdx; + grub_uint64_t rip; + grub_uint64_t rsi; + grub_addr_t cr3; +}; + +grub_err_t grub_relocator16_boot (struct grub_relocator *rel, + struct grub_relocator16_state state); + +grub_err_t grub_relocator32_boot (struct grub_relocator *rel, struct grub_relocator32_state state); -void *grub_relocator32_realloc (void *relocator, grub_size_t size); -void grub_relocator32_free (void *relocator); + +grub_err_t grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state, + grub_addr_t min_addr, grub_addr_t max_addr); #endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/i386/xnu.h b/include/grub/i386/xnu.h index 2fa2639c1..386c8b9e0 100644 --- a/include/grub/i386/xnu.h +++ b/include/grub/i386/xnu.h @@ -115,5 +115,4 @@ extern grub_uint32_t grub_xnu_arg1; extern char grub_xnu_cmdline[1024]; grub_err_t grub_xnu_boot (void); grub_err_t grub_cpu_xnu_fill_devicetree (void); -extern grub_uint32_t grub_xnu_heap_will_be_at; #endif diff --git a/include/grub/mips/memory.h b/include/grub/mips/memory.h new file mode 100644 index 000000000..e51bcc1f2 --- /dev/null +++ b/include/grub/mips/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/mips/multiboot.h b/include/grub/mips/multiboot.h index a27229efe..4aebf29e7 100644 --- a/include/grub/mips/multiboot.h +++ b/include/grub/mips/multiboot.h @@ -19,11 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -extern grub_uint32_t grub_multiboot_payload_eip; -extern char *grub_multiboot_payload_orig; -extern grub_addr_t grub_multiboot_payload_dest; -extern grub_size_t grub_multiboot_payload_size; - #define MULTIBOOT_INITIAL_STATE { .gpr[4] = MULTIBOOT_BOOTLOADER_MAGIC, \ .jumpreg = 1 } #define MULTIBOOT_ENTRY_REGISTER gpr[1] diff --git a/include/grub/mips/relocator.h b/include/grub/mips/relocator.h index 838ef832f..67b0a4c43 100644 --- a/include/grub/mips/relocator.h +++ b/include/grub/mips/relocator.h @@ -21,6 +21,7 @@ #include #include +#include struct grub_relocator32_state { @@ -30,10 +31,8 @@ struct grub_relocator32_state int jumpreg; }; -void *grub_relocator32_alloc (grub_size_t size); -grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, - struct grub_relocator32_state state); -void *grub_relocator32_realloc (void *relocator, grub_size_t size); -void grub_relocator32_free (void *relocator); +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state); #endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/mips/yeeloong/loader.h b/include/grub/mips/yeeloong/loader.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/include/grub/mips/yeeloong/memory.h b/include/grub/mips/yeeloong/memory.h index 922db2404..e7e995283 100644 --- a/include/grub/mips/yeeloong/memory.h +++ b/include/grub/mips/yeeloong/memory.h @@ -31,7 +31,6 @@ #define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 #define GRUB_ARCH_HIGHMEMPSTART 0x10000000 - #define GRUB_MACHINE_MEMORY_AVAILABLE 1 #define GRUB_MACHINE_MEMORY_MAX_TYPE 1 /* This one is special: it's used internally but is never reported @@ -40,6 +39,27 @@ #define GRUB_MACHINE_MEMORY_RESERVED GRUB_MACHINE_MEMORY_HOLE #ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return ((grub_phys_addr_t) a) & 0x1fffffff; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) (a | 0x80000000); +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); diff --git a/include/grub/misc.h b/include/grub/misc.h index 8bf8c82b4..e98d3d559 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -43,6 +43,8 @@ #define ALIGN_UP(addr, align) \ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) +#define ALIGN_DOWN(addr, align) \ + ((addr) & ~((typeof (addr)) align - 1)) #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } diff --git a/include/grub/mm.h b/include/grub/mm.h index 38dd39646..cc115907a 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -35,6 +35,9 @@ void EXPORT_FUNC(grub_free) (void *ptr); void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); +void grub_mm_check_real (char *file, int line); +#define GRUB_MM_CHECK grub_mm_check_real (__FILE__, __LINE__); + /* For debugging. */ #if defined(MM_DEBUG) && !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) /* Set this variable to 1 when you want to trace all memory function calls. */ diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h new file mode 100644 index 000000000..c2c4cb151 --- /dev/null +++ b/include/grub/mm_private.h @@ -0,0 +1,64 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MM_PRIVATE_H +#define GRUB_MM_PRIVATE_H 1 + +#include + +/* Magic words. */ +#define GRUB_MM_FREE_MAGIC 0x2d3c2808 +#define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 + +typedef struct grub_mm_header +{ + struct grub_mm_header *next; + grub_size_t size; + grub_size_t magic; +#if GRUB_CPU_SIZEOF_VOID_P == 4 + char padding[4]; +#elif GRUB_CPU_SIZEOF_VOID_P == 8 + char padding[8]; +#else +# error "unknown word size" +#endif +} +*grub_mm_header_t; + +#if GRUB_CPU_SIZEOF_VOID_P == 4 +# define GRUB_MM_ALIGN_LOG2 4 +#elif GRUB_CPU_SIZEOF_VOID_P == 8 +# define GRUB_MM_ALIGN_LOG2 5 +#endif + +#define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) + +typedef struct grub_mm_region +{ + struct grub_mm_header *first; + struct grub_mm_region *next; + grub_size_t pre_size; + grub_size_t size; +} +*grub_mm_region_t; + +#ifndef GRUB_MACHINE_EMU +extern grub_mm_region_t EXPORT_VAR (grub_mm_base); +#endif + +#endif diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 63947d1bc..cbc58b2ee 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -34,17 +34,21 @@ #include #include +extern struct grub_relocator *grub_multiboot_relocator; + void grub_multiboot (int argc, char *argv[]); void grub_module (int argc, char *argv[]); -grub_size_t grub_multiboot_get_mbi_size (void); -grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, - grub_off_t buf_off, grub_size_t bufsize); +void grub_multiboot_set_accepts_video (int val); +grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target); void grub_multiboot_free_mbi (void); grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]); grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, int argc, char *argv[]); void grub_multiboot_set_bootdev (void); +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data); grub_uint32_t grub_get_multiboot_mmap_count (void); grub_err_t grub_multiboot_set_video_mode (void); @@ -70,5 +74,7 @@ grub_err_t grub_multiboot_load_elf (grub_file_t file, void *buffer); extern grub_size_t grub_multiboot_pure_size; extern grub_size_t grub_multiboot_alloc_mbi; +extern grub_uint32_t grub_multiboot_payload_eip; + #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/grub/ns8250.h b/include/grub/ns8250.h index f8b9c3a8c..7947ba9c9 100644 --- a/include/grub/ns8250.h +++ b/include/grub/ns8250.h @@ -70,4 +70,11 @@ /* Turn on DTR, RTS, and OUT2. */ #define UART_ENABLE_OUT2 0x08 +#ifndef ASM_FILE +#include + +grub_port_t +grub_ns8250_hw_get_port (const unsigned int unit); +#endif + #endif /* ! GRUB_SERIAL_MACHINE_HEADER */ diff --git a/include/grub/offsets.h b/include/grub/offsets.h index ae0b2557e..7763e488c 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -123,12 +123,16 @@ #define GRUB_KERNEL_I386_COREBOOT_DATA_END 0x42 #define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR 0x8200 +#define GRUB_KERNEL_I386_MULTIBOOT_PREFIX GRUB_KERNEL_I386_COREBOOT_PREFIX +#define GRUB_KERNEL_I386_MULTIBOOT_DATA_END GRUB_KERNEL_I386_COREBOOT_DATA_END + #define GRUB_KERNEL_I386_IEEE1275_PREFIX 0x2 #define GRUB_KERNEL_I386_IEEE1275_DATA_END 0x42 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 #define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 #define GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN 0x1 +#define GRUB_KERNEL_I386_MULTIBOOT_MOD_ALIGN GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN /* Non-zero value is only needed for PowerMacs. */ #define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0 diff --git a/include/grub/powerpc/ieee1275/loader.h b/include/grub/powerpc/ieee1275/loader.h deleted file mode 100644 index 606bfcd0b..000000000 --- a/include/grub/powerpc/ieee1275/loader.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,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 . - */ - -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 - -/* The symbol shared between the normal mode and rescue mode - loader. */ -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); - -void grub_linux_init (void); -void grub_linux_fini (void); -void grub_linux_normal_init (void); -void grub_linux_normal_fini (void); - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/grub-core/loader/i386/bsd_helper.S b/include/grub/powerpc/memory.h similarity index 53% rename from grub-core/loader/i386/bsd_helper.S rename to include/grub/powerpc/memory.h index 25aee3a80..b748f33c5 100644 --- a/grub-core/loader/i386/bsd_helper.S +++ b/include/grub/powerpc/memory.h @@ -1,6 +1,7 @@ +/* memory.h - describe the memory map */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,30 +17,31 @@ * along with GRUB. If not, see . */ -#include +#ifndef GRUB_MEMORY_CPU_HEADER +#define GRUB_MEMORY_CPU_HEADER 1 - .p2align 2 +#ifndef ASM_FILE +typedef grub_addr_t grub_phys_addr_t; - .code32 +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return (grub_phys_addr_t) a; +} -/* - * Use cdecl calling convention for *BSD kernels. - */ +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) a; +} -FUNCTION(grub_unix_real_boot) +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} - /* Interrupts should be disabled. */ - cli +#endif - /* Discard `grub_unix_real_boot' return address. */ - popl %eax - - /* Fetch `entry' address ... */ - popl %eax - - /* - * ... and put our return address in its place. The kernel will - * ignore it, but it expects %esp to point to it. - */ - call *%eax +#endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/i386/ieee1275/loader.h b/include/grub/powerpc/relocator.h similarity index 62% rename from include/grub/i386/ieee1275/loader.h rename to include/grub/powerpc/relocator.h index 20df2e1d6..c2780bbca 100644 --- a/include/grub/i386/ieee1275/loader.h +++ b/include/grub/powerpc/relocator.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2009,2010 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 @@ -16,14 +16,22 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 #include -#include -#include +#include +#include -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); +#define GRUB_PPC_JUMP_REGISTER 31 -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +struct grub_relocator32_state +{ + grub_uint32_t gpr[32]; +}; + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/relocator.h b/include/grub/relocator.h new file mode 100644 index 000000000..653a00eba --- /dev/null +++ b/include/grub/relocator.h @@ -0,0 +1,58 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_RELOCATOR_HEADER +#define GRUB_RELOCATOR_HEADER 1 + +#include +#include +#include +#include + +struct grub_relocator; +struct grub_relocator_chunk; +typedef const struct grub_relocator_chunk *grub_relocator_chunk_t; + +struct grub_relocator *grub_relocator_new (void); + +grub_err_t +grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t target, grub_size_t size); + +void * +get_virtual_current_address (grub_relocator_chunk_t in); +grub_phys_addr_t +get_physical_target_address (grub_relocator_chunk_t in); + +grub_err_t +grub_relocator_alloc_chunk_align (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, + grub_size_t size, grub_size_t align, + int preference); + +#define GRUB_RELOCATOR_PREFERENCE_NONE 0 +#define GRUB_RELOCATOR_PREFERENCE_LOW 1 +#define GRUB_RELOCATOR_PREFERENCE_HIGH 2 + +void +grub_relocator_unload (struct grub_relocator *rel); + +#endif diff --git a/include/grub/relocator_private.h b/include/grub/relocator_private.h new file mode 100644 index 000000000..1c563cb64 --- /dev/null +++ b/include/grub/relocator_private.h @@ -0,0 +1,113 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_RELOCATOR_PRIVATE_HEADER +#define GRUB_RELOCATOR_PRIVATE_HEADER 1 + +#include +#include +#include + +extern grub_size_t grub_relocator_align; +extern grub_size_t grub_relocator_forward_size; +extern grub_size_t grub_relocator_backward_size; +extern grub_size_t grub_relocator_jumper_size; + +void +grub_cpu_relocator_init (void); +grub_err_t +grub_relocator_prepare_relocs (struct grub_relocator *rel, + grub_addr_t addr, + void **relstart, grub_size_t *relsize); +void grub_cpu_relocator_forward (void *rels, void *src, void *tgt, + grub_size_t size); +void grub_cpu_relocator_backward (void *rels, void *src, void *tgt, + grub_size_t size); +void grub_cpu_relocator_jumper (void *rels, grub_addr_t addr); + +/* Remark: GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG = 1 or 2 + aren't supported. */ +#ifdef GRUB_MACHINE_IEEE1275 +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1 +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 0 +#elif defined (GRUB_MACHINE_EFI) +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1 +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 12 +#else +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 0 +#endif + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS && GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG != 0 +#define GRUB_RELOCATOR_HAVE_LEFTOVERS 1 +#else +#define GRUB_RELOCATOR_HAVE_LEFTOVERS 0 +#endif + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT (1 << GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG) +#endif + +struct grub_relocator_mmap_event +{ + enum { + IN_REG_START = 0, + IN_REG_END = 1, + REG_BEG_START = 2, + REG_BEG_END = REG_BEG_START | 1, +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + REG_FIRMWARE_START = 4, + REG_FIRMWARE_END = REG_FIRMWARE_START | 1, + /* To track the regions already in heap. */ + FIRMWARE_BLOCK_START = 6, + FIRMWARE_BLOCK_END = FIRMWARE_BLOCK_START | 1, +#endif +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + REG_LEFTOVER_START = 8, + REG_LEFTOVER_END = REG_LEFTOVER_START | 1, +#endif + COLLISION_START = 10, + COLLISION_END = COLLISION_START | 1 + } type; + grub_phys_addr_t pos; + union + { + struct + { + grub_mm_region_t reg; + grub_mm_header_t hancestor; + grub_mm_region_t *regancestor; + grub_mm_header_t head; + }; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + struct grub_relocator_fw_leftover *leftover; +#endif + }; +}; + +/* Return 0 on failure, 1 on success. The failure here + can be very time-expensive, so please make sure fill events is accurate. */ +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS +int grub_relocator_firmware_alloc_region (grub_phys_addr_t start, + grub_size_t size); +unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events); +unsigned grub_relocator_firmware_get_max_events (void); +void grub_relocator_firmware_free_region (grub_phys_addr_t start, + grub_size_t size); +#endif + +#endif diff --git a/include/grub/sparc64/ieee1275/loader.h b/include/grub/sparc64/ieee1275/loader.h deleted file mode 100644 index 12bb2a69b..000000000 --- a/include/grub/sparc64/ieee1275/loader.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 - -/* The symbol shared between the normal mode and rescue mode - loader. */ -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/include/grub/x86_64/memory.h b/include/grub/x86_64/memory.h new file mode 100644 index 000000000..27fcd2534 --- /dev/null +++ b/include/grub/x86_64/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/xnu.h b/include/grub/xnu.h index 6089aad34..076aeb5ed 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -87,7 +87,7 @@ extern struct grub_xnu_devtree_key *grub_xnu_devtree_root; void grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur); -grub_err_t grub_xnu_writetree_toheap (void **start, grub_size_t *size); +grub_err_t grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size); struct grub_xnu_devtree_key *grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name); @@ -102,14 +102,15 @@ grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, int maxrecursion); grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, int maxrecursion); -void *grub_xnu_heap_malloc (int size); +grub_err_t grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target); grub_err_t grub_xnu_fill_devicetree (void); -extern grub_uint32_t grub_xnu_heap_real_start; +extern struct grub_relocator *grub_xnu_relocator; + extern grub_size_t grub_xnu_heap_size; -extern void *grub_xnu_heap_start; extern struct grub_video_bitmap *grub_xnu_bitmap; typedef enum {GRUB_XNU_BITMAP_CENTER, GRUB_XNU_BITMAP_STRETCH} grub_xnu_bitmap_mode_t; extern grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; extern int grub_xnu_is_64bit; +extern grub_addr_t grub_xnu_heap_target_start; #endif diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index 3f25fe7bb..e21cc95f4 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -44,7 +44,9 @@ Run GRUB script in a Qemu instance. -v, --version print the version information and exit --boot=[fd|hd|cd] boot method for Qemu instance --modules=MODULES pre-load specified modules MODULES + --qemu=FILE Name of qemu binary --qemu-opts=OPTIONS extra options to pass to Qemu instance + --files=FILES add files to the image $0 runs input GRUB script or SOURCE file in a Qemu instance and prints its output. @@ -53,6 +55,9 @@ Report bugs to . EOF } +boot=hd +qemu=qemu-system-i386 + # Check the arguments. for option in "$@"; do case "$option" in @@ -65,14 +70,21 @@ for option in "$@"; do --modules=*) ms=`echo "$option" | sed -e 's/--modules=//' -e 's/,/ /g'` modules="$modules $ms" ;; + --files=*) + fls=`echo "$option" | sed -e 's/--files=//' -e 's/,/ /g'` + files="$files $fls" ;; + --qemu=*) + qemu=`echo "$option" | sed -e 's/--qemu=//' -e 's/,/ /g'`;; --qemu-opts=*) qs=`echo "$option" | sed -e 's/--qemu-opts=//'` qemuopts="$qemuopts $qs" ;; --boot=*) dev=`echo "$option" | sed -e 's/--boot=//'` - if [ "$dev" = "fd" ] ; then bootdev=a; - elif [ "$dev" = "hd" ] ; then bootdev=c; - elif [ "$dev" = "cd" ] ; then bootdev=d; + if [ "$dev" = "fd" ] ; then boot=fd; + elif [ "$dev" = "hd" ] ; then boot=hd; + elif [ "$dev" = "cd" ] ; then boot=cd; + elif [ "$dev" = "qemu" ] ; then boot=qemu; + elif [ "$dev" = "coreboot" ] ; then boot=coreboot; else echo "Unrecognized boot method \`$dev'" 1>&2 usage @@ -100,10 +112,6 @@ if [ "x${source}" = x ] ; then source=${tmpfile} fi -if [ "x${bootdev}" = x ] ; then - bootdev=c # default is boot as disk image -fi - cfgfile=`mktemp` cat <${cfgfile} grubshell=yes @@ -113,6 +121,8 @@ terminal_input serial terminal_output serial EOF +rom_directory=`mktemp -d` + for mod in ${modules} do echo "insmod ${mod}" >> ${cfgfile} @@ -124,23 +134,44 @@ halt EOF isofile=`mktemp` -sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage \ - --override-directory=${builddir}/grub-core --output=${isofile} \ - boot/grub/grub.cfg=${cfgfile} \ - /boot/grub/testcase.cfg=${source} >/dev/null 2>&1 +sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} --override-directory=${builddir}/grub-core \ + --rom-directory="${rom_directory}" \ + /boot/grub/grub.cfg=${cfgfile} /boot/grub/testcase.cfg=${source} \ + ${files} >/dev/null 2>&1 +if [ x$boot = xhd ]; then + device=hda + bootdev="-boot c" +fi +if [ x$boot = xcd ]; then + device=cdrom + bootdev="-boot d" +fi +if [ x$boot = xfd ]; then + device=fda + bootdev="-boot a" +fi -hdafile=`mktemp` -cp ${isofile} ${hdafile} +if [ x$boot = xqemu ]; then + bootdev="-bios ${rom_directory}/qemu.img" + device=cdrom +fi -fdafile=`mktemp` -cp ${isofile} ${fdafile} +if [ x$boot = xcoreboot ]; then + imgfile=`mktemp` + cp "${GRUB_COREBOOT_ROM}" "${imgfile}" + "${GRUB_CBFSTOOL}" "${imgfile}" add-payload "${rom_directory}/coreboot.elf" fallback/payload + bootdev="-bios ${imgfile}" + device=cdrom +fi -outfile=`mktemp` -qemu-system-i386 ${qemuopts} -nographic -hda ${hdafile} -fda ${fdafile} -cdrom ${isofile} -boot ${bootdev} | tr -d "\r" >${outfile} +${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" +rm -f "${isofile}" "${imgfile}" +rm -rf "${rom_directory}" +if [ x$boot = xcoreboot ]; then + rm -f "${imgfile}" +fi -cat $outfile - -rm -f ${tmpfile} ${outfile} ${cfgfile} ${isofile} ${hdafile} ${fdafile} +rm -f "${tmpfile}" "${cfgfile}" exit 0 diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index c46f0700f..38c530b91 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -106,8 +106,8 @@ struct image_target_desc image_targets[] = .bigendian = 0, .id = IMAGE_COREBOOT, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, - .data_end = GRUB_KERNEL_I386_COREBOOT_DATA_END, + .prefix = GRUB_KERNEL_I386_MULTIBOOT_PREFIX, + .data_end = GRUB_KERNEL_I386_MULTIBOOT_DATA_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD,