IA64 support.

* Makefile.util.def (libgrubmods.a): Add grub-core/kern/ia64/dl_helper.c
	* configure.ac: Add ia64-efi target.
	Probe for __ia64_trampoline, __udivsi3, __umoddi3, __udivdi3,
	__divsi3, __modsi3, __umodsi3, __moddi3 and __divdi3 symbols.
	* gentpl.py: Add ia64_efi platform.
	Rename x86_efi to efi and Add ia64-efi. All users updated.
	* grub-core/Makefile.am: Set KERNEL_HEADER_FILES for ia64-efi.
	* grub-core/Makefile.core.def (kernel.img): Add compile flags for ia64.
	Remove kern/generic/rtc_get_time_ms.c on EFI.
	Add kern/ia64/efi/startup.S, kern/ia64/efi/init.c, kern/ia64/dl.c,
	kern/ia64/dl_helper.c on ia64-efi.
	Add kern/emu/cache.c on emu.
	(linux): Use on loader/ia64/efi/linux.c on ia64.
	* grub-core/gensymlist.sh (grub_register_exported_symbols): Check
	whether symbol is a function.
	* grub-core/kern/dl.c [GRUB_MACHINE_EMU]: Include sys/mman.h.
	(grub_symbol): New field 'isfunc'.
	(grub_dl_resolve_symbol): Return whole symbol rather than just address.
	(grub_dl_register_symbol): New argument 'isfunc'. All users updated.
	(grub_dl_load_segments): Place all sections into the same region.
	[__ia64__]: Create trampolines and got.
	[GRUB_MACHINE_EMU]: Call mprotect.
	(grub_dl_resolve_symbols): Resolve symbol type as well.
	[__ia64__]: Create function descriptors.
	* grub-core/kern/efi/efi.c (grub_get_rtc): Renamed to ...
	(grub_rtc_get_time_ms): ... this. Expressions simplified.
	(grub_get_rtc): New function.
	* grub-core/kern/emu/cache.c [__ia64__]: New file.
	* grub-core/kern/emu/cache.S: Renamed to ...
	* grub-core/kern/emu/cache_s.S: ... this.
	[__ia64__]: Add a nop.
	* grub-core/kern/emu/full.c (grub_arch_dl_get_tramp_got_size)
	[__ia64__]: New function.
	* grub-core/kern/emu/lite.c [__ia64__]: Include ../ia64/dl.c.
	* grub-core/kern/ia64/dl.c: New file.
	* grub-core/kern/ia64/dl_helper.c: Likewise.
	* grub-core/kern/ia64/efi/init.c: New file.
	* grub-core/kern/ia64/efi/startup.S: Likewise.
	* grub-core/lib/efi/halt.c [__ia64__]: Don't try acpi.
	* grub-core/lib/ia64/longjmp.S: New file (from glibc).
	* grub-core/lib/ia64/setjmp.S: Likewise (from glibc).
	* grub-core/lib/setjmp.S [__ia64__]: Include ./ia64/setjmp.S.
	* grub-core/loader/ia64/efi/linux.c: New file.
	* include/grub/dl.h (GRUB_MOD_NAME): Redefined using C rather than asm.
	(GRUB_MOD_DEP): Likewise.
	(grub_dl) [__ia64__]: New fields got and tramp.
	(grub_dl): New field 'base'.
	(grub_dl_register_symbol): New argument isfunc. All users updated.
	(GRUB_IA64_DL_TRAMP_ALIGN): New definition.
	(GRUB_IA64_DL_TRAMP_SIZE): Likewise.
	(GRUB_IA64_DL_GOT_ALIGN): Likewise.
	(grub_ia64_dl_get_tramp_got_size): New proto.
	(GRUB_ARCH_DL_TRAMP_ALIGN) [__ia64__]: Likewise
	(GRUB_ARCH_DL_GOT_ALIGN) [__ia64__]: Likewise
	(grub_arch_dl_get_tramp_got_size) [__ia64__]: Likewise
	* include/grub/efi/api.h: Skip call wrappers on ia64.
	* include/grub/efi/pe32.h (GRUB_PE32_MACHINE_IA64): New definition.
	* include/grub/efi/time.h (GRUB_TICKS_PER_SECOND): Change to 1000.
	* include/grub/elf.h (ELF_ST_INFO): New definition.
	* include/grub/ia64/efi/kernel.h: New file.
	* include/grub/ia64/efi/memory.h: Likewise.
	* include/grub/ia64/efi/time.h: Likewise.
	* include/grub/ia64/kernel.h: Likewise.
	* include/grub/ia64/setjmp.h: Likewise (from glibc).
	* include/grub/ia64/time.h: New file.
	* include/grub/ia64/types.h: Likewise.
	* include/grub/libgcc.h (__udivsi3, __umodsi3, __umoddi3, __udivdi3,
	__moddi3, __divdi3, __divsi3, __modsi3, __ia64_trampoline):
	New protos.
	* include/grub/offsets.h (GRUB_KERNEL_IA64_EFI_PREFIX): New definition.
	(GRUB_KERNEL_IA64_EFI_PREFIX_END): Likewise.
	* include/grub/types.h (PRIxGRUB_ADDR): Likewise.
	* util/grub-mkimage.c (image_target_desc): New field pe_target.
	All users updated.
	(EFI64_HEADER_SIZE): New definition. All users updated.
	(image_targets): Add ia64-efi.
	* util/grub-mkimagexx.c (relocate_symbols): New arguments jumpers and
	jumpers_addr. All users updated.
	Create function descriptors.
	(count_funcs): New function.
	(unaligned_uint32): New struct.
	(MASK20): New definition.
	(MASK19): Likewise.
	(MASKF21): Likewise.
	(add_value_to_slot_20b): New function.
	(add_value_to_slot_21_real): Likewise.
	(add_value_to_slot_21): Likewise.
	(ia64_kernel_trampoline): New struct.
	(nopm): New variable.
	(jump): Likewise.
	(make_trampoline): New function.
	(relocate_addresses): Handle ia64.
	(make_reloc_section): Likewise.
	(load_image): Likewise.

	Also-By: Robert Millan <rmh.grub@aybabtu.com>

	Also-By: Vladimir Serbinenko <phcoder@gmail.com>
This commit is contained in:
Tristan Gingold 2011-05-15 11:22:59 +02:00 committed by Vladimir 'phcoder' Serbinenko
commit 32297d5ff7
39 changed files with 2526 additions and 124 deletions

101
ChangeLog
View file

@ -1,3 +1,104 @@
2011-05-15 Tristan Gingold <gingold@free.fr>
2011-05-15 Robert Millan <rmh.grub@aybabtu.com>
2011-05-15 Vladimir Serbinenko <phcoder@gmail.com>
IA64 support.
* Makefile.util.def (libgrubmods.a): Add grub-core/kern/ia64/dl_helper.c
* configure.ac: Add ia64-efi target.
Probe for __ia64_trampoline, __udivsi3, __umoddi3, __udivdi3,
__divsi3, __modsi3, __umodsi3, __moddi3 and __divdi3 symbols.
* gentpl.py: Add ia64_efi platform.
Rename x86_efi to efi and Add ia64-efi. All users updated.
* grub-core/Makefile.am: Set KERNEL_HEADER_FILES for ia64-efi.
* grub-core/Makefile.core.def (kernel.img): Add compile flags for ia64.
Remove kern/generic/rtc_get_time_ms.c on EFI.
Add kern/ia64/efi/startup.S, kern/ia64/efi/init.c, kern/ia64/dl.c,
kern/ia64/dl_helper.c on ia64-efi.
Add kern/emu/cache.c on emu.
(linux): Use on loader/ia64/efi/linux.c on ia64.
* grub-core/gensymlist.sh (grub_register_exported_symbols): Check
whether symbol is a function.
* grub-core/kern/dl.c [GRUB_MACHINE_EMU]: Include sys/mman.h.
(grub_symbol): New field 'isfunc'.
(grub_dl_resolve_symbol): Return whole symbol rather than just address.
(grub_dl_register_symbol): New argument 'isfunc'. All users updated.
(grub_dl_load_segments): Place all sections into the same region.
[__ia64__]: Create trampolines and got.
[GRUB_MACHINE_EMU]: Call mprotect.
(grub_dl_resolve_symbols): Resolve symbol type as well.
[__ia64__]: Create function descriptors.
* grub-core/kern/efi/efi.c (grub_get_rtc): Renamed to ...
(grub_rtc_get_time_ms): ... this. Expressions simplified.
(grub_get_rtc): New function.
* grub-core/kern/emu/cache.c [__ia64__]: New file.
* grub-core/kern/emu/cache.S: Renamed to ...
* grub-core/kern/emu/cache_s.S: ... this.
[__ia64__]: Add a nop.
* grub-core/kern/emu/full.c (grub_arch_dl_get_tramp_got_size)
[__ia64__]: New function.
* grub-core/kern/emu/lite.c [__ia64__]: Include ../ia64/dl.c.
* grub-core/kern/ia64/dl.c: New file.
* grub-core/kern/ia64/dl_helper.c: Likewise.
* grub-core/kern/ia64/efi/init.c: New file.
* grub-core/kern/ia64/efi/startup.S: Likewise.
* grub-core/lib/efi/halt.c [__ia64__]: Don't try acpi.
* grub-core/lib/ia64/longjmp.S: New file (from glibc).
* grub-core/lib/ia64/setjmp.S: Likewise (from glibc).
* grub-core/lib/setjmp.S [__ia64__]: Include ./ia64/setjmp.S.
* grub-core/loader/ia64/efi/linux.c: New file.
* include/grub/dl.h (GRUB_MOD_NAME): Redefined using C rather than asm.
(GRUB_MOD_DEP): Likewise.
(grub_dl) [__ia64__]: New fields got and tramp.
(grub_dl): New field 'base'.
(grub_dl_register_symbol): New argument isfunc. All users updated.
(GRUB_IA64_DL_TRAMP_ALIGN): New definition.
(GRUB_IA64_DL_TRAMP_SIZE): Likewise.
(GRUB_IA64_DL_GOT_ALIGN): Likewise.
(grub_ia64_dl_get_tramp_got_size): New proto.
(GRUB_ARCH_DL_TRAMP_ALIGN) [__ia64__]: Likewise
(GRUB_ARCH_DL_GOT_ALIGN) [__ia64__]: Likewise
(grub_arch_dl_get_tramp_got_size) [__ia64__]: Likewise
* include/grub/efi/api.h: Skip call wrappers on ia64.
* include/grub/efi/pe32.h (GRUB_PE32_MACHINE_IA64): New definition.
* include/grub/efi/time.h (GRUB_TICKS_PER_SECOND): Change to 1000.
* include/grub/elf.h (ELF_ST_INFO): New definition.
* include/grub/ia64/efi/kernel.h: New file.
* include/grub/ia64/efi/memory.h: Likewise.
* include/grub/ia64/efi/time.h: Likewise.
* include/grub/ia64/kernel.h: Likewise.
* include/grub/ia64/setjmp.h: Likewise (from glibc).
* include/grub/ia64/time.h: New file.
* include/grub/ia64/types.h: Likewise.
* include/grub/libgcc.h (__udivsi3, __umodsi3, __umoddi3, __udivdi3,
__moddi3, __divdi3, __divsi3, __modsi3, __ia64_trampoline):
New protos.
* include/grub/offsets.h (GRUB_KERNEL_IA64_EFI_PREFIX): New definition.
(GRUB_KERNEL_IA64_EFI_PREFIX_END): Likewise.
* include/grub/types.h (PRIxGRUB_ADDR): Likewise.
* util/grub-mkimage.c (image_target_desc): New field pe_target.
All users updated.
(EFI64_HEADER_SIZE): New definition. All users updated.
(image_targets): Add ia64-efi.
* util/grub-mkimagexx.c (relocate_symbols): New arguments jumpers and
jumpers_addr. All users updated.
Create function descriptors.
(count_funcs): New function.
(unaligned_uint32): New struct.
(MASK20): New definition.
(MASK19): Likewise.
(MASKF21): Likewise.
(add_value_to_slot_20b): New function.
(add_value_to_slot_21_real): Likewise.
(add_value_to_slot_21): Likewise.
(ia64_kernel_trampoline): New struct.
(nopm): New variable.
(jump): Likewise.
(make_trampoline): New function.
(relocate_addresses): Handle ia64.
(make_reloc_section): Likewise.
(load_image): Likewise.
2011-05-15 Vladimir Serbinenko <phcoder@gmail.com> 2011-05-15 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/fs/btrfs.c (grub_btrfs_read_logical): Silence spurious * grub-core/fs/btrfs.c (grub_btrfs_read_logical): Silence spurious

View file

@ -100,6 +100,7 @@ library = {
common = grub-core/script/script.c; common = grub-core/script/script.c;
common = grub-core/script/argv.c; common = grub-core/script/argv.c;
common = grub-core/io/gzio.c; common = grub-core/io/gzio.c;
common = grub-core/kern/ia64/dl_helper.c;
}; };
program = { program = {
@ -383,7 +384,8 @@ script = {
x86 = util/grub-mkrescue.in; x86 = util/grub-mkrescue.in;
powerpc_ieee1275 = util/powerpc/ieee1275/grub-mkrescue.in; powerpc_ieee1275 = util/powerpc/ieee1275/grub-mkrescue.in;
enable = i386_pc; enable = i386_pc;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
enable = i386_qemu; enable = i386_qemu;
enable = i386_multiboot; enable = i386_multiboot;
enable = i386_coreboot; enable = i386_coreboot;

View file

@ -97,6 +97,7 @@ if test "x$with_platform" = x; then
powerpc64-*) platform=ieee1275 ;; powerpc64-*) platform=ieee1275 ;;
sparc64-*) platform=ieee1275 ;; sparc64-*) platform=ieee1275 ;;
mips-*) platform=loongson ;; mips-*) platform=loongson ;;
ia64-*) platform=efi ;;
*) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;; *) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;;
esac esac
else else
@ -122,6 +123,7 @@ case "$target_cpu"-"$platform" in
i386-qemu) ;; i386-qemu) ;;
powerpc-ieee1275) ;; powerpc-ieee1275) ;;
sparc64-ieee1275) ;; sparc64-ieee1275) ;;
ia64-efi) ;;
mips-qemu-mips) ;; mips-qemu-mips) ;;
mips-yeeloong) platform=loongson ;; mips-yeeloong) platform=loongson ;;
mips-fuloong) platform=loongson ;; mips-fuloong) platform=loongson ;;
@ -592,7 +594,7 @@ CFLAGS="$CFLAGS -Wl,--defsym,abort=main"
fi fi
# Check for libgcc symbols # Check for libgcc symbols
AC_CHECK_FUNCS(__bswapsi2 __bswapdi2 __ashldi3 __ashrdi3 __lshrdi3 __trampoline_setup __ucmpdi2 _restgpr_14_x) AC_CHECK_FUNCS(__bswapsi2 __bswapdi2 __ashldi3 __ashrdi3 __lshrdi3 __trampoline_setup __ucmpdi2 _restgpr_14_x __ia64_trampoline __udivsi3 __umoddi3 __udivdi3 __divsi3 __modsi3 __umodsi3 __moddi3 __divdi3)
if test "x$TARGET_APPLE_CC" = x1 ; then if test "x$TARGET_APPLE_CC" = x1 ; then
CFLAGS="$TARGET_CFLAGS -nostdlib" CFLAGS="$TARGET_CFLAGS -nostdlib"
@ -947,6 +949,7 @@ AC_SUBST(NEED_REGISTER_FRAME_INFO)
AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) AM_CONDITIONAL([COND_emu], [test x$platform = xemu])
AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc])
AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi])
AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi])
AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu]) AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu])
AM_CONDITIONAL([COND_i386_ieee1275], [test x$target_cpu = xi386 -a x$platform = xieee1275]) AM_CONDITIONAL([COND_i386_ieee1275], [test x$target_cpu = xi386 -a x$platform = xieee1275])
AM_CONDITIONAL([COND_i386_coreboot], [test x$target_cpu = xi386 -a x$platform = xcoreboot]) AM_CONDITIONAL([COND_i386_coreboot], [test x$target_cpu = xi386 -a x$platform = xcoreboot])

View file

@ -7,7 +7,7 @@
GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"i386_multiboot", "i386_ieee1275", "x86_64_efi", "i386_multiboot", "i386_ieee1275", "x86_64_efi",
"mips_loongson", "sparc64_ieee1275", "mips_loongson", "sparc64_ieee1275",
"powerpc_ieee1275" ] "powerpc_ieee1275", "ia64_efi" ]
GROUPS = {} GROUPS = {}
@ -22,7 +22,7 @@ GROUPS["sparc64"] = [ "sparc64_ieee1275" ]
GROUPS["powerpc"] = [ "powerpc_ieee1275" ] GROUPS["powerpc"] = [ "powerpc_ieee1275" ]
# Groups based on firmware # Groups based on firmware
GROUPS["x86_efi"] = [ "i386_efi", "x86_64_efi" ] GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi" ]
GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
# emu is a special case so many core functionality isn't needed on this platform # emu is a special case so many core functionality isn't needed on this platform

View file

@ -125,6 +125,12 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h
endif endif
if COND_ia64_efi
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
endif
if COND_mips_loongson if COND_mips_loongson
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h

View file

@ -18,8 +18,14 @@ kernel = {
nostrip = emu; nostrip = emu;
emu_ldflags = '-Wl,-r,-d'; emu_ldflags = '-Wl,-r,-d';
x86_efi_ldflags = '-Wl,-r,-d'; i386_efi_ldflags = '-Wl,-r,-d';
x86_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; i386_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment';
x86_64_efi_ldflags = '-Wl,-r,-d';
x86_64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment';
ia64_efi_cflags = '-fno-builtin -fpic -minline-int-divide-max-throughput';
ia64_efi_ldflags = '-Wl,-r,-d';
ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment';
i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200'; i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200';
@ -77,7 +83,6 @@ kernel = {
noemu_nodist = symlist.c; noemu_nodist = symlist.c;
i386_pc = kern/generic/rtc_get_time_ms.c; i386_pc = kern/generic/rtc_get_time_ms.c;
x86_efi = kern/generic/rtc_get_time_ms.c;
i386_qemu = kern/generic/rtc_get_time_ms.c; i386_qemu = kern/generic/rtc_get_time_ms.c;
i386_coreboot = kern/generic/rtc_get_time_ms.c; i386_coreboot = kern/generic/rtc_get_time_ms.c;
i386_multiboot = kern/generic/rtc_get_time_ms.c; i386_multiboot = kern/generic/rtc_get_time_ms.c;
@ -105,18 +110,24 @@ kernel = {
x86 = kern/i386/pit.c; x86 = kern/i386/pit.c;
x86_efi = disk/efi/efidisk.c; efi = disk/efi/efidisk.c;
x86_efi = kern/efi/efi.c; efi = kern/efi/efi.c;
x86_efi = kern/efi/init.c; efi = kern/efi/init.c;
x86_efi = kern/efi/mm.c; efi = kern/efi/mm.c;
x86_efi = kern/i386/efi/init.c; efi = term/efi/console.c;
x86_efi = term/efi/console.c;
i386_efi = kern/i386/tsc.c; i386_efi = kern/i386/tsc.c;
i386_efi = kern/i386/efi/init.c;
x86_64_efi = kern/i386/tsc.c; x86_64_efi = kern/i386/tsc.c;
x86_64_efi = kern/x86_64/dl.c; x86_64_efi = kern/x86_64/dl.c;
x86_64_efi = kern/x86_64/efi/callwrap.S; x86_64_efi = kern/x86_64/efi/callwrap.S;
x86_64_efi = kern/i386/efi/init.c;
ia64_efi = kern/ia64/efi/startup.S;
ia64_efi = kern/ia64/efi/init.c;
ia64_efi = kern/ia64/dl.c;
ia64_efi = kern/ia64/dl_helper.c;
i386_pc = kern/i386/pc/init.c; i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c; i386_pc = kern/i386/pc/mmap.c;
@ -163,7 +174,7 @@ kernel = {
emu = disk/host.c; emu = disk/host.c;
emu = gnulib/progname.c; emu = gnulib/progname.c;
emu = gnulib/error.c; emu = gnulib/error.c;
emu = kern/emu/cache.S; emu = kern/emu/cache_s.S;
emu = kern/emu/console.c; emu = kern/emu/console.c;
emu = kern/emu/getroot.c; emu = kern/emu/getroot.c;
emu = kern/emu/hostdisk.c; emu = kern/emu/hostdisk.c;
@ -172,6 +183,7 @@ kernel = {
emu = kern/emu/misc.c; emu = kern/emu/misc.c;
emu = kern/emu/mm.c; emu = kern/emu/mm.c;
emu = kern/emu/time.c; emu = kern/emu/time.c;
emu = kern/emu/cache.c;
videoinkernel = term/gfxterm.c; videoinkernel = term/gfxterm.c;
videoinkernel = font/font.c; videoinkernel = font/font.c;
@ -410,7 +422,8 @@ module = {
enable = emu; enable = emu;
enable = i386_pc; enable = i386_pc;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
enable = i386_ieee1275; enable = i386_ieee1275;
enable = i386_coreboot; enable = i386_coreboot;
enable = i386_multiboot; enable = i386_multiboot;
@ -449,12 +462,12 @@ module = {
name = acpi; name = acpi;
common = commands/acpi.c; common = commands/acpi.c;
x86_efi = commands/efi/acpi.c; efi = commands/efi/acpi.c;
i386_pc = commands/i386/pc/acpi.c; i386_pc = commands/i386/pc/acpi.c;
i386_coreboot = commands/i386/pc/acpi.c; i386_coreboot = commands/i386/pc/acpi.c;
i386_multiboot = commands/i386/pc/acpi.c; i386_multiboot = commands/i386/pc/acpi.c;
enable = x86_efi; enable = efi;
enable = i386_pc; enable = i386_pc;
enable = i386_coreboot; enable = i386_coreboot;
enable = i386_multiboot; enable = i386_multiboot;
@ -555,8 +568,9 @@ module = {
module = { module = {
name = fixvideo; name = fixvideo;
x86_efi = commands/efi/fixvideo.c; common = commands/efi/fixvideo.c;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
}; };
module = { module = {
@ -571,11 +585,12 @@ module = {
i386_pc = commands/acpihalt.c; i386_pc = commands/acpihalt.c;
i386_coreboot = commands/acpihalt.c; i386_coreboot = commands/acpihalt.c;
i386_multiboot = commands/acpihalt.c; i386_multiboot = commands/acpihalt.c;
x86_efi = commands/acpihalt.c; i386_efi = commands/acpihalt.c;
x86_64_efi = commands/acpihalt.c;
i386_multiboot = lib/i386/halt.c; i386_multiboot = lib/i386/halt.c;
i386_coreboot = lib/i386/halt.c; i386_coreboot = lib/i386/halt.c;
i386_qemu = lib/i386/halt.c; i386_qemu = lib/i386/halt.c;
x86_efi = lib/efi/halt.c; efi = lib/efi/halt.c;
ieee1275 = lib/ieee1275/halt.c; ieee1275 = lib/ieee1275/halt.c;
emu = lib/emu/halt.c; emu = lib/emu/halt.c;
}; };
@ -610,8 +625,9 @@ module = {
module = { module = {
name = loadbios; name = loadbios;
x86_efi = commands/efi/loadbios.c; common = commands/efi/loadbios.c;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
}; };
module = { module = {
@ -1106,7 +1122,7 @@ module = {
x86_64 = lib/x86_64/relocator_asm.S; x86_64 = lib/x86_64/relocator_asm.S;
x86 = lib/i386/relocator.c; x86 = lib/i386/relocator.c;
ieee1275 = lib/ieee1275/relocator.c; ieee1275 = lib/ieee1275/relocator.c;
x86_efi = lib/efi/relocator.c; efi = lib/efi/relocator.c;
mips = lib/mips/relocator_asm.S; mips = lib/mips/relocator_asm.S;
mips = lib/mips/relocator.c; mips = lib/mips/relocator.c;
powerpc = lib/powerpc/relocator_asm.S; powerpc = lib/powerpc/relocator_asm.S;
@ -1123,7 +1139,7 @@ module = {
module = { module = {
name = datetime; name = datetime;
cmos = lib/cmos_datetime.c; cmos = lib/cmos_datetime.c;
x86_efi = lib/efi/datetime.c; efi = lib/efi/datetime.c;
sparc64_ieee1275 = lib/ieee1275/datetime.c; sparc64_ieee1275 = lib/ieee1275/datetime.c;
powerpc_ieee1275 = lib/ieee1275/datetime.c; powerpc_ieee1275 = lib/ieee1275/datetime.c;
enable = noemu; enable = noemu;
@ -1195,6 +1211,7 @@ module = {
mips = loader/mips/linux.c; mips = loader/mips/linux.c;
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
ia64_efi = loader/ia64/efi/linux.c;
common = lib/cmdline.c; common = lib/cmdline.c;
enable = noemu; enable = noemu;
}; };
@ -1214,16 +1231,17 @@ module = {
module = { module = {
name = appleldr; name = appleldr;
x86_efi = loader/efi/appleloader.c; common = loader/efi/appleloader.c;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
}; };
module = { module = {
name = chain; name = chain;
x86_efi = loader/efi/chainloader.c; efi = loader/efi/chainloader.c;
i386_pc = loader/i386/pc/chainloader.c; i386_pc = loader/i386/pc/chainloader.c;
enable = i386_pc; enable = i386_pc;
enable = x86_efi; enable = efi;
}; };
module = { module = {
@ -1235,11 +1253,12 @@ module = {
i386_pc = mmap/i386/pc/mmap.c; i386_pc = mmap/i386/pc/mmap.c;
i386_pc = mmap/i386/pc/mmap_helper.S; i386_pc = mmap/i386/pc/mmap_helper.S;
x86_efi = mmap/efi/mmap.c; efi = mmap/efi/mmap.c;
mips_loongson = mmap/mips/loongson/uppermem.c; mips_loongson = mmap/mips/loongson/uppermem.c;
enable = x86; enable = x86;
enable = ia64_efi;
enable = mips_loongson; enable = mips_loongson;
}; };
@ -1424,14 +1443,15 @@ module = {
module = { module = {
name = efi_gop; name = efi_gop;
x86_efi = video/efi_gop.c; efi = video/efi_gop.c;
enable = x86_efi; enable = efi;
}; };
module = { module = {
name = efi_uga; name = efi_uga;
x86_efi = video/efi_uga.c; efi = video/efi_uga.c;
enable = x86_efi; enable = i386_efi;
enable = x86_64_efi;
}; };
module = { module = {

View file

@ -47,7 +47,7 @@ grub_register_exported_symbols (void)
EOF EOF
cat <<EOF cat <<EOF
struct symtab { const char *name; void *addr; }; struct symtab { const char *name; void *addr; int isfunc; };
struct symtab *p; struct symtab *p;
static struct symtab tab[] = static struct symtab tab[] =
{ {
@ -56,16 +56,16 @@ EOF
(while read LINE; do echo $LINE; done) \ (while read LINE; do echo $LINE; done) \
| grep -v '^#' \ | grep -v '^#' \
| sed -n \ | sed -n \
-e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/ {"\1", \1},/;p;}' \ -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/ {"\1", \1, 1},/;p;}' \
-e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/ {"\1", \&\1},/;p;}' \ -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/ {"\1", \&\1, 0},/;p;}' \
| sort -u | sort -u
cat <<EOF cat <<EOF
{0, 0} {0, 0, 0}
}; };
COMPILE_TIME_ASSERT (sizeof (tab) > sizeof (tab[0])); COMPILE_TIME_ASSERT (sizeof (tab) > sizeof (tab[0]));
for (p = tab; p->name; p++) for (p = tab; p->name; p++)
grub_dl_register_symbol (p->name, p->addr, 0); grub_dl_register_symbol (p->name, p->addr, p->isfunc, 0);
} }
EOF EOF

View file

@ -37,6 +37,10 @@
#define GRUB_MODULES_MACHINE_READONLY #define GRUB_MODULES_MACHINE_READONLY
#endif #endif
#ifdef GRUB_MACHINE_EMU
#include <sys/mman.h>
#endif
grub_dl_t grub_dl_head = 0; grub_dl_t grub_dl_head = 0;
@ -86,6 +90,7 @@ struct grub_symbol
struct grub_symbol *next; struct grub_symbol *next;
const char *name; const char *name;
void *addr; void *addr;
int isfunc;
grub_dl_t mod; /* The module to which this symbol belongs. */ grub_dl_t mod; /* The module to which this symbol belongs. */
}; };
typedef struct grub_symbol *grub_symbol_t; typedef struct grub_symbol *grub_symbol_t;
@ -110,21 +115,22 @@ grub_symbol_hash (const char *s)
/* Resolve the symbol name NAME and return the address. /* Resolve the symbol name NAME and return the address.
Return NULL, if not found. */ Return NULL, if not found. */
static void * static grub_symbol_t
grub_dl_resolve_symbol (const char *name) grub_dl_resolve_symbol (const char *name)
{ {
grub_symbol_t sym; grub_symbol_t sym;
for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next) for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
if (grub_strcmp (sym->name, name) == 0) if (grub_strcmp (sym->name, name) == 0)
return sym->addr; return sym;
return 0; return 0;
} }
/* Register a symbol with the name NAME and the address ADDR. */ /* Register a symbol with the name NAME and the address ADDR. */
grub_err_t grub_err_t
grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod) grub_dl_register_symbol (const char *name, void *addr, int isfunc,
grub_dl_t mod)
{ {
grub_symbol_t sym; grub_symbol_t sym;
unsigned k; unsigned k;
@ -147,6 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
sym->addr = addr; sym->addr = addr;
sym->mod = mod; sym->mod = mod;
sym->isfunc = isfunc;
k = grub_symbol_hash (name); k = grub_symbol_hash (name);
sym->next = grub_symtab[k]; sym->next = grub_symtab[k];
@ -225,6 +232,48 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{ {
unsigned i; unsigned i;
Elf_Shdr *s; Elf_Shdr *s;
grub_size_t tsize = 0, talign = 1;
#ifdef __ia64__
grub_size_t tramp;
grub_size_t got;
#endif
char *ptr;
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
{
tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
if (talign < s->sh_addralign)
talign = s->sh_addralign;
}
#ifdef __ia64__
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
tramp *= GRUB_IA64_DL_TRAMP_SIZE;
got *= sizeof (grub_uint64_t);
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
talign = GRUB_ARCH_DL_TRAMP_ALIGN;
tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
if (talign < GRUB_ARCH_DL_GOT_ALIGN)
talign = GRUB_ARCH_DL_GOT_ALIGN;
#endif
#ifdef GRUB_MACHINE_EMU
if (talign < 8192 * 16)
talign = 8192 * 16;
tsize = ALIGN_UP (tsize, 8192 * 16);
#endif
mod->base = grub_memalign (talign, tsize);
if (!mod->base)
return grub_errno;
ptr = mod->base;
#ifdef GRUB_MACHINE_EMU
mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
i < e->e_shnum; i < e->e_shnum;
@ -242,12 +291,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{ {
void *addr; void *addr;
addr = grub_memalign (s->sh_addralign, s->sh_size); ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
if (! addr) addr = ptr;
{ ptr += s->sh_size;
grub_free (seg);
return grub_errno;
}
switch (s->sh_type) switch (s->sh_type)
{ {
@ -270,6 +316,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->segment = seg; mod->segment = seg;
} }
} }
#ifdef __ia64__
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
mod->tramp = ptr;
ptr += tramp;
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
mod->got = ptr;
ptr += got;
#endif
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
@ -320,17 +374,20 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
/* Resolve a global symbol. */ /* Resolve a global symbol. */
if (sym->st_name != 0 && sym->st_shndx == 0) if (sym->st_name != 0 && sym->st_shndx == 0)
{ {
sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name); grub_symbol_t nsym = grub_dl_resolve_symbol (name);
if (! sym->st_value) if (! nsym)
return grub_error (GRUB_ERR_BAD_MODULE, return grub_error (GRUB_ERR_BAD_MODULE,
"symbol not found: `%s'", name); "symbol not found: `%s'", name);
sym->st_value = (Elf_Addr) nsym->addr;
if (nsym->isfunc)
sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
} }
else else
{ {
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx); sym->st_shndx);
if (bind != STB_LOCAL) if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
return grub_errno; return grub_errno;
} }
break; break;
@ -338,10 +395,21 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
case STT_FUNC: case STT_FUNC:
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx); sym->st_shndx);
if (bind != STB_LOCAL) #ifdef __ia64__
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) {
/* FIXME: free descriptor once it's not used anymore. */
char **desc;
desc = grub_malloc (2 * sizeof (char *));
if (!desc)
return grub_errno;
desc[0] = (void *) sym->st_value;
desc[1] = mod->base;
sym->st_value = (grub_addr_t) desc;
}
#endif
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
return grub_errno; return grub_errno;
if (grub_strcmp (name, "grub_mod_init") == 0) if (grub_strcmp (name, "grub_mod_init") == 0)
mod->init = (void (*) (grub_dl_t)) sym->st_value; mod->init = (void (*) (grub_dl_t)) sym->st_value;
else if (grub_strcmp (name, "grub_mod_fini") == 0) else if (grub_strcmp (name, "grub_mod_fini") == 0)

View file

@ -24,6 +24,7 @@
#include <grub/efi/console_control.h> #include <grub/efi/console_control.h>
#include <grub/efi/pe32.h> #include <grub/efi/pe32.h>
#include <grub/machine/time.h> #include <grub/machine/time.h>
#include <grub/time.h>
#include <grub/term.h> #include <grub/term.h>
#include <grub/kernel.h> #include <grub/kernel.h>
#include <grub/mm.h> #include <grub/mm.h>
@ -193,8 +194,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed"); return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
} }
grub_uint32_t grub_uint64_t
grub_get_rtc (void) grub_rtc_get_time_ms (void)
{ {
grub_efi_time_t time; grub_efi_time_t time;
grub_efi_runtime_services_t *r; grub_efi_runtime_services_t *r;
@ -204,9 +205,14 @@ grub_get_rtc (void)
/* What is possible in this case? */ /* What is possible in this case? */
return 0; return 0;
return (((time.minute * 60 + time.second) * 1000 return ((time.minute * 60 + time.second) * 1000
+ time.nanosecond / 1000000) + time.nanosecond / 1000000);
* GRUB_TICKS_PER_SECOND / 1000); }
grub_uint32_t
grub_get_rtc (void)
{
return grub_rtc_get_time_ms ();
} }
/* Search the mods section from the PE32/PE32+ image. This code uses /* Search the mods section from the PE32/PE32+ image. This code uses

View file

@ -0,0 +1,13 @@
#if defined(__ia64__)
#include <grub/cache.h>
void __clear_cache (char *beg, char *end);
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
__clear_cache (address, (char *) address + len);
}
#endif

View file

@ -23,6 +23,7 @@ FUNCTION (grub_arch_sync_caches)
.set macro .set macro
#elif defined(__powerpc__) #elif defined(__powerpc__)
#include "../powerpc/cache.S" #include "../powerpc/cache.S"
#elif defined(__ia64__)
#else #else
#error "No target cpu type is defined" #error "No target cpu type is defined"
#endif #endif

View file

@ -50,6 +50,15 @@ grub_emu_init (void)
grub_no_autoload = 1; grub_no_autoload = 1;
} }
#ifdef __ia64__
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
grub_size_t *tramp, grub_size_t *got)
{
*tramp = 0;
*got = 0;
}
#endif
#ifdef GRUB_LINKER_HAVE_INIT #ifdef GRUB_LINKER_HAVE_INIT
void void
grub_arch_dl_init_linker (void) grub_arch_dl_init_linker (void)

View file

@ -15,6 +15,8 @@
#include "../mips/dl.c" #include "../mips/dl.c"
#elif defined(__powerpc__) #elif defined(__powerpc__)
#include "../powerpc/dl.c" #include "../powerpc/dl.c"
#elif defined(__ia64__)
#include "../ia64/dl.c"
#else #else
#error "No target cpu type is defined" #error "No target cpu type is defined"
#endif #endif

276
grub-core/kern/ia64/dl.c Normal file
View file

@ -0,0 +1,276 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/mm.h>
/* Check if EHDR is a valid ELF header. */
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
if (e->e_ident[EI_CLASS] != ELFCLASS64
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|| e->e_machine != EM_IA_64)
return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
return GRUB_ERR_NONE;
}
#define MASK20 ((1 << 20) - 1)
#define MASK19 ((1 << 19) - 1)
struct unaligned_uint32
{
grub_uint32_t val;
} __attribute__ ((packed));
static void
add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
| (p->val & ~(MASK20 << 2)));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
| (p->val & ~(MASK20 << 3)));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
| (p->val & ~(MASK20 << 4)));
break;
}
}
#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) )
static grub_uint32_t
add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
{
grub_uint32_t high, mid, low, c;
low = (a & 0x00007f);
mid = (a & 0x7fc000) >> 7;
high = (a & 0x003e00) << 7;
c = (low | mid | high) + value;
return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
}
static void
add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4));
break;
}
}
static grub_uint8_t nopm[5] =
{
/* [MLX] nop.m 0x0 */
0x05, 0x00, 0x00, 0x00, 0x01
};
static grub_uint8_t jump[0x20] =
{
/* ld8 r16=[r15],8 */
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
/* mov r14=r1;; */
0xe0, 0x00, 0x04, 0x00, 0x42, 0x00,
/* nop.i 0x0 */
0x00, 0x00, 0x04, 0x00,
/* ld8 r1=[r15] */
0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,
/* mov b6=r16 */
0x60, 0x80, 0x04, 0x80, 0x03, 0x00,
/* br.few b6;; */
0x60, 0x00, 0x80, 0x00
};
struct ia64_trampoline
{
/* nop.m */
grub_uint8_t nop[5];
/* movl r15 = addr*/
grub_uint8_t addr_hi[6];
grub_uint8_t e0;
grub_uint8_t addr_lo[4];
grub_uint8_t jump[0x20];
};
static void
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
{
COMPILE_TIME_ASSERT (sizeof (struct ia64_trampoline)
== GRUB_IA64_DL_TRAMP_SIZE);
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
tr->addr_hi[1] = (addr >> 24) & 0xff;
tr->addr_hi[2] = (addr >> 32) & 0xff;
tr->addr_hi[3] = (addr >> 40) & 0xff;
tr->addr_hi[4] = (addr >> 48) & 0xff;
tr->addr_hi[5] = (addr >> 56) & 0xff;
tr->e0 = 0xe0;
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
| ((addr & 0x200000) >> 17));
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
grub_memcpy (tr->jump, jump, sizeof (tr->jump));
}
/* Relocate symbols. */
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf_Ehdr *e = ehdr;
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
grub_uint64_t *gp, *gpptr;
struct ia64_trampoline *tr;
gp = (grub_uint64_t *) mod->base;
gpptr = (grub_uint64_t *) mod->got;
tr = mod->tramp;
/* Find a symbol table. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
entsize = s->sh_entsize;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
grub_dl_segment_t seg;
/* Find the target segment. */
for (seg = mod->segment; seg; seg = seg->next)
if (seg->section == s->sh_info)
break;
if (seg)
{
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
grub_addr_t addr;
Elf_Sym *sym;
grub_uint64_t value;
if (seg->size < (rel->r_offset & ~3))
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr = (grub_addr_t) seg->addr + rel->r_offset;
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
/* On the PPC the value does not have an explicit
addend, add it. */
value = sym->st_value + rel->r_addend;
switch (ELF_R_TYPE (rel->r_info))
{
case R_IA64_PCREL21B:
{
grub_uint64_t noff;
make_trampoline (tr, value);
noff = ((char *) tr - (char *) (addr & ~3)) >> 4;
tr++;
if (noff & ~MASK19)
return grub_error (GRUB_ERR_BAD_OS,
"trampoline offset too big (%lx)", noff);
add_value_to_slot_20b (addr, noff);
}
break;
case R_IA64_SEGREL64LSB:
*(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr;
break;
case R_IA64_FPTR64LSB:
case R_IA64_DIR64LSB:
*(grub_uint64_t *) addr += value;
break;
case R_IA64_PCREL64LSB:
*(grub_uint64_t *) addr += value - addr;
break;
case R_IA64_GPREL22:
add_value_to_slot_21 (addr, value - (grub_addr_t) gp);
break;
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
value = *(grub_uint64_t *) sym->st_value + rel->r_addend;
case R_IA64_LTOFF_FPTR22:
*gpptr = value;
add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
gpptr++;
break;
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
case R_IA64_LDXMOV:
break;
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"this relocation (0x%x) is not implemented yet",
ELF_R_TYPE (rel->r_info));
}
}
}
}
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,73 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/mm.h>
void
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got)
{
const Elf_Ehdr *e = ehdr;
grub_size_t cntt = 0, cntg = 0;;
const Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return;
entsize = s->sh_entsize;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max; rel++)
switch (ELF_R_TYPE (rel->r_info))
{
case R_IA64_PCREL21B:
cntt++;
break;
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
cntg++;
break;
}
}
*tramp = cntt;
*got = cntg;
}

View file

@ -0,0 +1,60 @@
/* init.c - initialize an ia64-based EFI system */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/cache.h>
#include <grub/kernel.h>
#include <grub/efi/efi.h>
void
grub_machine_init (void)
{
grub_efi_init ();
grub_install_get_time_ms (grub_rtc_get_time_ms);
}
void
grub_machine_fini (void)
{
grub_efi_fini ();
}
void
grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
/* Cache line length is at least 32. */
grub_uint64_t a = (grub_uint64_t)address & ~0x1f;
/* Flush data. */
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
asm volatile ("fc.i %0" : : "r" (a));
/* Sync and serialize. Maybe extra. */
asm volatile (";; sync.i;; srlz.i;;");
}

View file

@ -0,0 +1,54 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <grub/symbol.h>
#include <grub/offsets.h>
.text
.psr abi64
.psr lsb
.lsb
.global _start
.proc _start
_start:
alloc loc0=ar.pfs,2,4,0,0
mov loc1=rp
addl loc2=@gprel(grub_efi_image_handle),gp
addl loc3=@gprel(grub_efi_system_table),gp
;;
st8 [loc2]=in0
st8 [loc3]=in1
br.call.sptk.few rp=grub_main
;;
mov ar.pfs=loc0
mov rp=loc1
;;
br.ret.sptk.few rp
.endp _start
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
.byte 0
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END

View file

@ -28,7 +28,9 @@ void
grub_halt (void) grub_halt (void)
{ {
grub_machine_fini (); grub_machine_fini ();
#ifndef __ia64__
grub_acpi_halt (); grub_acpi_halt ();
#endif
efi_call_4 (grub_efi_system_table->runtime_services->reset_system, efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL);

View file

@ -0,0 +1,162 @@
/* Copyright (C) 1999, 2000, 2001, 2002, 2008 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
Note that __sigsetjmp() did NOT flush the register stack. Instead,
we do it here since __longjmp() is usually much less frequently
invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp()
didn't (and wouldn't be able to) save ar.rnat either. This is a problem
because if we're not careful, we could end up loading random NaT bits.
There are two cases:
(i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp)
ar.rnat contains the desired bits---preserve ar.rnat
across loadrs and write to ar.bspstore
(ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp)
The desired ar.rnat is stored in
ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those
bits into ar.rnat after setting ar.bspstore. */
# define pPos p6 /* is rotate count positive? */
# define pNeg p7 /* is rotate count negative? */
/* __longjmp(__jmp_buf buf, int val) */
.text
.global longjmp
.proc longjmp
longjmp:
alloc r8=ar.pfs,2,1,0,0
mov r27=ar.rsc
add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr
;;
ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr
mov r10=ar.bsp
and r11=~0x3,r27 // clear ar.rsc.mode
;;
flushrs // flush dirty regs to backing store (must be first in insn grp)
ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp
sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf
;;
ld8 r25=[r2] // r25 <- jmpbuf.ar_unat
extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
;;
cmp.lt pNeg,pPos=r8,r0
mov r2=in0
;;
(pPos) mov r16=r8
(pNeg) add r16=64,r8
(pPos) sub r17=64,r8
(pNeg) sub r17=r0,r8
;;
mov ar.rsc=r11 // put RSE in enforced lazy mode
shr.u r8=r25,r16
add r3=8,in0 // r3 <- &jmpbuf.r1
shl r9=r25,r17
;;
or r25=r8,r9
;;
mov r26=ar.rnat
mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12)
;;
ld8.fill.nta sp=[r2],16 // r12 (sp)
ld8.fill.nta gp=[r3],16 // r1 (gp)
dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
;;
ld8.nta r16=[r2],16 // caller's unat
ld8.nta r17=[r3],16 // fpsr
;;
ld8.fill.nta r4=[r2],16 // r4
ld8.fill.nta r5=[r3],16 // r5 (gp)
cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
;;
ld8.fill.nta r6=[r2],16 // r6
ld8.fill.nta r7=[r3],16 // r7
;;
mov ar.unat=r16 // restore caller's unat
mov ar.fpsr=r17 // restore fpsr
;;
ld8.nta r16=[r2],16 // b0
ld8.nta r17=[r3],16 // b1
;;
(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
mov ar.bspstore=r23 // restore ar.bspstore
;;
ld8.nta r18=[r2],16 // b2
ld8.nta r19=[r3],16 // b3
;;
ld8.nta r20=[r2],16 // b4
ld8.nta r21=[r3],16 // b5
;;
ld8.nta r11=[r2],16 // ar.pfs
ld8.nta r22=[r3],56 // ar.lc
;;
ld8.nta r24=[r2],32 // pr
mov b0=r16
;;
ldf.fill.nta f2=[r2],32
ldf.fill.nta f3=[r3],32
mov b1=r17
;;
ldf.fill.nta f4=[r2],32
ldf.fill.nta f5=[r3],32
mov b2=r18
;;
ldf.fill.nta f16=[r2],32
ldf.fill.nta f17=[r3],32
mov b3=r19
;;
ldf.fill.nta f18=[r2],32
ldf.fill.nta f19=[r3],32
mov b4=r20
;;
ldf.fill.nta f20=[r2],32
ldf.fill.nta f21=[r3],32
mov b5=r21
;;
ldf.fill.nta f22=[r2],32
ldf.fill.nta f23=[r3],32
mov ar.lc=r22
;;
ldf.fill.nta f24=[r2],32
ldf.fill.nta f25=[r3],32
cmp.eq p8,p9=0,in1
;;
ldf.fill.nta f26=[r2],32
ldf.fill.nta f27=[r3],32
mov ar.pfs=r11
;;
ldf.fill.nta f28=[r2],32
ldf.fill.nta f29=[r3],32
;;
ldf.fill.nta f30=[r2]
ldf.fill.nta f31=[r3]
(p8) mov r8=1
mov ar.rnat=r26 // restore ar.rnat
;;
mov ar.rsc=r27 // restore ar.rsc
(p9) mov r8=in1
invala // virt. -> phys. regnum mapping may change
mov pr=r24,-1
br.ret.dptk.few rp
.endp longjmp

171
grub-core/lib/ia64/setjmp.S Normal file
View file

@ -0,0 +1,171 @@
/* Copyright (C) 1999, 2000, 2001, 2002, 2008 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
The layout of the jmp_buf is as follows. This is subject to change
and user-code should never depend on the particular layout of
jmp_buf!
offset: description:
------- ------------
0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS)
0x008 r1 (gp)
0x010 caller's unat
0x018 fpsr
0x020 r4
0x028 r5
0x030 r6
0x038 r7
0x040 rp (b0)
0x048 b1
0x050 b2
0x058 b3
0x060 b4
0x068 b5
0x070 ar.pfs
0x078 ar.lc
0x080 pr
0x088 ar.bsp ; unchangeable (see __longjmp.S)
0x090 ar.unat
0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat)
0x0a0 f2
0x0b0 f3
0x0c0 f4
0x0d0 f5
0x0e0 f16
0x0f0 f17
0x100 f18
0x110 f19
0x120 f20
0x130 f21
0x130 f22
0x140 f23
0x150 f24
0x160 f25
0x170 f26
0x180 f27
0x190 f28
0x1a0 f29
0x1b0 f30
0x1c0 f31 */
/* The following two entry points are the traditional entry points: */
.text
.global setjmp
.proc setjmp
setjmp:
alloc r8=ar.pfs,2,0,0,0
mov in1=1
br.cond.sptk.many __sigsetjmp
.endp setjmp
/* __sigsetjmp(__jmp_buf buf, int savemask) */
.proc __sigsetjmp
__sigsetjmp:
//.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
alloc loc1=ar.pfs,2,2,2,0
mov r16=ar.unat
;;
mov r17=ar.fpsr
mov r2=in0
add r3=8,in0
;;
st8.spill.nta [r2]=sp,16 // r12 (sp)
st8.spill.nta [r3]=gp,16 // r1 (gp)
;;
st8.nta [r2]=r16,16 // save caller's unat
st8.nta [r3]=r17,16 // save fpsr
add r8=0xa0,in0
;;
st8.spill.nta [r2]=r4,16 // r4
st8.spill.nta [r3]=r5,16 // r5
add r9=0xb0,in0
;;
stf.spill.nta [r8]=f2,32
stf.spill.nta [r9]=f3,32
mov loc0=rp
.body
;;
stf.spill.nta [r8]=f4,32
stf.spill.nta [r9]=f5,32
mov r17=b1
;;
stf.spill.nta [r8]=f16,32
stf.spill.nta [r9]=f17,32
mov r18=b2
;;
stf.spill.nta [r8]=f18,32
stf.spill.nta [r9]=f19,32
mov r19=b3
;;
stf.spill.nta [r8]=f20,32
stf.spill.nta [r9]=f21,32
mov r20=b4
;;
stf.spill.nta [r8]=f22,32
stf.spill.nta [r9]=f23,32
mov r21=b5
;;
stf.spill.nta [r8]=f24,32
stf.spill.nta [r9]=f25,32
mov r22=ar.lc
;;
stf.spill.nta [r8]=f26,32
stf.spill.nta [r9]=f27,32
mov r24=pr
;;
stf.spill.nta [r8]=f28,32
stf.spill.nta [r9]=f29,32
;;
stf.spill.nta [r8]=f30
stf.spill.nta [r9]=f31
st8.spill.nta [r2]=r6,16 // r6
st8.spill.nta [r3]=r7,16 // r7
;;
mov r23=ar.bsp
mov r25=ar.unat
mov out0=in0
st8.nta [r2]=loc0,16 // b0
st8.nta [r3]=r17,16 // b1
mov out1=in1
;;
st8.nta [r2]=r18,16 // b2
st8.nta [r3]=r19,16 // b3
;;
st8.nta [r2]=r20,16 // b4
st8.nta [r3]=r21,16 // b5
;;
st8.nta [r2]=loc1,16 // ar.pfs
st8.nta [r3]=r22,16 // ar.lc
;;
st8.nta [r2]=r24,16 // pr
st8.nta [r3]=r23,16 // ar.bsp
;;
st8.nta [r2]=r25 // ar.unat
st8.nta [r3]=in0 // &__jmp_buf
mov r8=0
mov rp=loc0
mov ar.pfs=loc1
br.ret.sptk.many rp
.endp __sigsetjmp

View file

@ -8,6 +8,8 @@
#include "./mips/setjmp.S" #include "./mips/setjmp.S"
#elif defined(__powerpc__) #elif defined(__powerpc__)
#include "./powerpc/setjmp.S" #include "./powerpc/setjmp.S"
#elif defined(__ia64__)
#include "./ia64/setjmp.S"
#else #else
#error "Unknwon target cpu type" #error "Unknown target cpu type"
#endif #endif

View file

@ -0,0 +1,795 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008,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 <http://www.gnu.org/licenses/>.
*/
#include <grub/loader.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/types.h>
#include <grub/command.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/cache.h>
#include <grub/kernel.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/elf.h>
#define ALIGN_MIN (256*1024*1024)
#define GRUB_ELF_SEARCH 1024
#define BOOT_PARAM_SIZE 16384
struct ia64_boot_param
{
grub_uint64_t command_line; /* physical address of command line. */
grub_uint64_t efi_systab; /* physical address of EFI system table */
grub_uint64_t efi_memmap; /* physical address of EFI memory map */
grub_uint64_t efi_memmap_size; /* size of EFI memory map */
grub_uint64_t efi_memdesc_size; /* size of an EFI memory map descriptor */
grub_uint32_t efi_memdesc_version; /* memory descriptor version */
struct
{
grub_uint16_t num_cols; /* number of columns on console output dev */
grub_uint16_t num_rows; /* number of rows on console output device */
grub_uint16_t orig_x; /* cursor's x position */
grub_uint16_t orig_y; /* cursor's y position */
} console_info;
grub_uint64_t fpswa; /* physical address of the fpswa interface */
grub_uint64_t initrd_start;
grub_uint64_t initrd_size;
grub_uint64_t domain_start; /* boot domain address. */
grub_uint64_t domain_size; /* how big is the boot domain */
grub_uint64_t payloads_chain;
grub_uint64_t payloads_nbr;
};
struct ia64_boot_payload
{
grub_uint64_t start;
grub_uint64_t length;
/* Payload command line */
grub_uint64_t cmdline;
grub_uint64_t next;
};
typedef struct
{
grub_uint32_t revision;
grub_uint32_t reserved;
void *fpswa;
} fpswa_interface_t;
static fpswa_interface_t *fpswa;
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
static grub_dl_t my_mod;
static int loaded;
/* Kernel base and size. */
static void *kernel_mem;
static grub_efi_uintn_t kernel_pages;
static grub_uint64_t entry;
/* Initrd base and size. */
static void *initrd_mem;
static grub_efi_uintn_t initrd_pages;
static grub_efi_uintn_t initrd_size;
static struct ia64_boot_param *boot_param;
static grub_efi_uintn_t boot_param_pages;
static struct ia64_boot_payload *last_payload = NULL;
/* Can linux kernel be relocated ? */
#define RELOCATE_OFF 0 /* No. */
#define RELOCATE_ON 1 /* Yes. */
#define RELOCATE_FORCE 2 /* Always - used to debug. */
static int relocate = RELOCATE_OFF;
static inline grub_size_t
page_align (grub_size_t size)
{
return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
}
static void
query_fpswa (void)
{
grub_efi_handle_t fpswa_image;
grub_efi_boot_services_t *bs;
grub_efi_status_t status;
grub_efi_uintn_t size;
static const grub_efi_guid_t fpswa_protocol =
{ 0xc41b6531, 0x97b9, 0x11d3,
{0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
if (fpswa != NULL)
return;
size = sizeof(grub_efi_handle_t);
bs = grub_efi_system_table->boot_services;
status = bs->locate_handle (GRUB_EFI_BY_PROTOCOL,
(void *)&fpswa_protocol,
NULL, &size, &fpswa_image);
if (status != GRUB_EFI_SUCCESS)
{
grub_printf("Could not locate FPSWA driver\n");
return;
}
status = bs->handle_protocol (fpswa_image,
(void *)&fpswa_protocol, (void *)&fpswa);
if (status != GRUB_EFI_SUCCESS)
{
grub_printf ("Fpswa protocol not able find the interface\n");
return;
}
}
/* 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 (kernel_mem)
{
grub_efi_free_pages ((grub_addr_t) kernel_mem, kernel_pages);
kernel_mem = 0;
}
if (initrd_mem)
{
grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
initrd_mem = 0;
}
if (boot_param)
{
struct ia64_boot_payload *payload;
struct ia64_boot_payload *next_payload;
/* Free payloads. */
payload = (struct ia64_boot_payload *)boot_param->payloads_chain;
while (payload != 0)
{
next_payload = (struct ia64_boot_payload *)payload->next;
grub_efi_free_pages
(payload->start, page_align (payload->length) >> 12);
grub_efi_free_pages ((grub_efi_physical_address_t)payload, 1);
payload = next_payload;
}
/* Free bootparam. */
grub_efi_free_pages ((grub_efi_physical_address_t)boot_param,
boot_param_pages);
boot_param = 0;
}
}
static void *
allocate_pages (grub_uint64_t align, grub_uint64_t size_pages,
grub_uint64_t nobase)
{
grub_uint64_t 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;
void *mem = NULL;
size = size_pages << 12;
mmap_size = find_mmap_size ();
/* 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))
{
grub_uint64_t start, end;
grub_uint64_t aligned_start;
if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
continue;
start = desc->physical_start;
end = start + (desc->num_pages << 12);
/* Align is a power of 2. */
aligned_start = (start + align - 1) & ~(align - 1);
if (aligned_start + size > end)
continue;
if (aligned_start == nobase)
aligned_start += align;
if (aligned_start + size > end)
continue;
mem = grub_efi_allocate_pages (aligned_start, size_pages);
if (! mem)
grub_fatal ("cannot allocate pages");
break;
}
if (! mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
goto fail;
}
grub_free (mmap);
return mem;
fail:
grub_free (mmap);
free_pages ();
return 0;
}
static void
set_boot_param_console (void)
{
grub_efi_simple_text_output_interface_t *conout;
grub_efi_uintn_t cols, rows;
conout = grub_efi_system_table->con_out;
if (conout->query_mode (conout, conout->mode->mode, &cols, &rows)
!= GRUB_EFI_SUCCESS)
return;
grub_dprintf("linux",
"Console info: cols=%lu rows=%lu x=%u y=%u\n",
cols, rows,
conout->mode->cursor_column, conout->mode->cursor_row);
boot_param->console_info.num_cols = cols;
boot_param->console_info.num_rows = rows;
boot_param->console_info.orig_x = conout->mode->cursor_column;
boot_param->console_info.orig_y = conout->mode->cursor_row;
}
static grub_err_t
grub_linux_boot (void)
{
grub_efi_uintn_t mmap_size;
grub_efi_uintn_t map_key;
grub_efi_uintn_t desc_size;
grub_efi_uint32_t desc_version;
grub_efi_memory_descriptor_t *mmap_buf;
grub_err_t err;
/* FPSWA. */
query_fpswa ();
boot_param->fpswa = (grub_uint64_t)fpswa;
/* Initrd. */
boot_param->initrd_start = (grub_uint64_t)initrd_mem;
boot_param->initrd_size = (grub_uint64_t)initrd_size;
set_boot_param_console ();
grub_printf ("Jump to %016lx\n", entry);
grub_machine_fini ();
/* MDT.
Must be done after grub_machine_fini because map_key is used by
exit_boot_services. */
mmap_size = find_mmap_size ();
mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12);
if (! mmap_buf)
grub_fatal ("cannot allocate memory map");
err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key,
&desc_size, &desc_version);
if (err)
return err;
boot_param->efi_memmap = (grub_uint64_t)mmap_buf;
boot_param->efi_memmap_size = mmap_size;
boot_param->efi_memdesc_size = desc_size;
boot_param->efi_memdesc_version = desc_version;
/* See you next boot. */
asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(entry),"r"(boot_param));
/* 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_load_elf64 (grub_file_t file, void *buffer)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer;
Elf64_Phdr *phdr;
int i;
grub_uint64_t low_addr;
grub_uint64_t high_addr;
grub_uint64_t align;
grub_uint64_t reloc_offset;
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class");
if (ehdr->e_ident[EI_MAG0] != ELFMAG0
|| ehdr->e_ident[EI_MAG1] != ELFMAG1
|| ehdr->e_ident[EI_MAG2] != ELFMAG2
|| ehdr->e_ident[EI_MAG3] != ELFMAG3
|| ehdr->e_version != EV_CURRENT
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_machine != EM_IA_64)
return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found");
if (ehdr->e_type != ET_EXEC)
return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type");
/* FIXME: Should we support program headers at strange locations? */
if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_ELF_SEARCH)
return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
entry = ehdr->e_entry;
/* Compute low, high and align addresses. */
low_addr = ~0UL;
high_addr = 0;
align = 0;
for (i = 0; i < ehdr->e_phnum; i++)
{
phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
+ i * ehdr->e_phentsize);
if (phdr->p_type == PT_LOAD)
{
if (phdr->p_paddr < low_addr)
low_addr = phdr->p_paddr;
if (phdr->p_paddr + phdr->p_memsz > high_addr)
high_addr = phdr->p_paddr + phdr->p_memsz;
if (phdr->p_align > align)
align = phdr->p_align;
}
}
if (align < ALIGN_MIN)
align = ALIGN_MIN;
if (high_addr == 0)
return grub_error (GRUB_ERR_BAD_OS, "no program entries");
kernel_pages = page_align (high_addr - low_addr) >> 12;
if (relocate != RELOCATE_FORCE)
{
kernel_mem = grub_efi_allocate_pages (low_addr, kernel_pages);
reloc_offset = 0;
}
/* Try to relocate. */
if (! kernel_mem && relocate != RELOCATE_OFF)
{
kernel_mem = allocate_pages (align, kernel_pages, low_addr);
if (kernel_mem)
{
reloc_offset = (grub_uint64_t)kernel_mem - low_addr;
grub_printf (" Relocated at %p (offset=%016lx)\n",
kernel_mem, reloc_offset);
entry += reloc_offset;
}
}
if (! kernel_mem)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"cannot allocate memory for OS");
/* Load every loadable segment in memory. */
for (i = 0; i < ehdr->e_phnum; i++)
{
phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff
+ i * ehdr->e_phentsize);
if (phdr->p_type == PT_LOAD)
{
grub_printf (" [paddr=%lx load=%lx memsz=%08lx "
"off=%lx flags=%x]\n",
phdr->p_paddr, phdr->p_paddr + reloc_offset,
phdr->p_memsz, phdr->p_offset, phdr->p_flags);
if (grub_file_seek (file, phdr->p_offset) == (grub_off_t)-1)
return grub_error (GRUB_ERR_BAD_OS,
"invalid offset in program header");
if (grub_file_read (file, (void *)(phdr->p_paddr + reloc_offset),
phdr->p_filesz)
!= (grub_ssize_t) phdr->p_filesz)
return grub_error (GRUB_ERR_BAD_OS,
"couldn't read segment from file");
if (phdr->p_filesz < phdr->p_memsz)
grub_memset
((char *)(phdr->p_paddr + reloc_offset + phdr->p_filesz),
0, phdr->p_memsz - phdr->p_filesz);
/* Sync caches if necessary. */
if (phdr->p_flags & PF_X)
grub_arch_sync_caches
((void *)(phdr->p_paddr + reloc_offset), phdr->p_memsz);
}
}
loaded = 1;
return 0;
}
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
char buffer[GRUB_ELF_SEARCH];
char *cmdline, *p;
grub_ssize_t len;
int i;
grub_dl_ref (my_mod);
grub_loader_unset ();
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified");
goto fail;
}
file = grub_file_open (argv[0]);
if (! file)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
goto fail;
}
len = grub_file_read (file, buffer, sizeof (buffer));
if (len < (grub_ssize_t)sizeof (Elf64_Ehdr))
{
grub_error (GRUB_ERR_BAD_OS, "File too small");
goto fail;
}
grub_printf ("Loading linux: %s\n", argv[0]);
if (grub_load_elf64 (file, buffer))
goto fail;
len = sizeof("BOOT_IMAGE=") + 8;
for (i = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
len += sizeof (struct ia64_boot_param) + 256; /* Room for extensions. */
boot_param_pages = page_align (len) >> 12;
boot_param = grub_efi_allocate_pages (0, boot_param_pages);
if (boot_param == 0)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY,
"cannot allocate memory for bootparams");
goto fail;
}
grub_memset (boot_param, 0, len);
cmdline = ((char *)(boot_param + 1)) + 256;
/* Build cmdline. */
p = grub_stpcpy (cmdline, "BOOT_IMAGE");
for (i = 0; i < argc; i++)
{
*p++ = ' ';
p = grub_stpcpy (p, argv[i]);
}
cmdline[10] = '=';
boot_param->command_line = (grub_uint64_t) cmdline;
boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table;
grub_errno = GRUB_ERR_NONE;
grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
fail:
if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
grub_efi_free_pages ((grub_efi_physical_address_t) boot_param,
boot_param_pages);
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 filename 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;
grub_printf ("Loading initrd: %s\n",argv[0]);
initrd_size = grub_file_size (file);
initrd_pages = (page_align (initrd_size) >> 12);
initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
if (! initrd_mem)
grub_fatal ("cannot allocate pages");
grub_printf (" [addr=0x%lx, size=0x%lx]\n",
(grub_uint64_t)initrd_mem, initrd_size);
if (grub_file_read (file, initrd_mem, initrd_size)
!= (grub_ssize_t)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_err_t
grub_cmd_payload (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
grub_ssize_t size, len = 0;
char *base = 0, *cmdline = 0, *p;
struct ia64_boot_payload *payload = NULL;
int i;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified");
goto fail;
}
if (!boot_param)
{
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);
base = grub_efi_allocate_pages (0, page_align (size) >> 12);
if (! base)
goto fail;
grub_printf ("Payload %s [addr=%lx + %lx]\n",
argv[0], (grub_uint64_t)base, size);
if (grub_file_read (file, base, size) != size)
{
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
goto fail;
}
len = sizeof (struct ia64_boot_payload);
for (i = 0; i < argc; i++)
len += grub_strlen (argv[i]) + 1;
if (len > 4096)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "payload command line too long");
goto fail;
}
payload = grub_efi_allocate_pages (0, 1);
if (! payload)
goto fail;
p = (char *)(payload + 1);
payload->start = (grub_uint64_t)base;
payload->length = size;
payload->cmdline = (grub_uint64_t)p;
payload->next = 0;
if (last_payload)
last_payload->next = (grub_uint64_t)payload;
else
{
last_payload = payload;
boot_param->payloads_chain = (grub_uint64_t)payload;
}
boot_param->payloads_nbr++;
/* Copy command line. */
for (i = 0; i < argc; i++)
{
p = grub_stpcpy (p, argv[i]);
*(p++) = ' ';
}
/* Remove the space after the last word. */
*(--p) = '\0';
fail:
if (file)
grub_file_close (file);
if (grub_errno != GRUB_ERR_NONE)
{
grub_free (base);
grub_free (cmdline);
}
return grub_errno;
}
static grub_err_t
grub_cmd_relocate (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
static const char * const vals[] = { "off", "on", "force"};
unsigned int i;
if (argc == 0)
{
grub_printf ("relocate is %s\n", vals[relocate]);
return GRUB_ERR_NONE;
}
else if (argc == 1)
{
if (kernel_mem != NULL)
grub_printf ("Warning: kernel already loaded!\n");
for (i = 0; i < sizeof (vals)/sizeof(vals[0]); i++)
if (grub_strcmp (argv[0], vals[i]) == 0)
{
relocate = i;
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown relocate value");
}
else
{
return grub_error (GRUB_ERR_BAD_ARGUMENT, "accept 0 or 1 argument");
}
}
static grub_err_t
grub_cmd_fpswa (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[] __attribute__((unused)))
{
if (argc != 0)
{
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Arguments not expected");
}
query_fpswa ();
if (fpswa == NULL)
grub_printf ("No FPSWA loaded\n");
else
grub_printf ("FPSWA revision: %x\n", fpswa->revision);
return GRUB_ERR_NONE;
}
static grub_command_t cmd_linux, cmd_initrd, cmd_payload, cmd_relocate, cmd_fpswa;
GRUB_MOD_INIT(linux)
{
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
"FILE [ARGS...]", "Load Linux.");
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
"FILE", "Load initrd.");
cmd_payload = grub_register_command ("payload", grub_cmd_payload,
"FILE [ARGS...]",
"Load an additional file.");
cmd_relocate = grub_register_command ("relocate", grub_cmd_relocate,
"[on|off|force]",
"Set relocate feature.");
cmd_fpswa = grub_register_command ("fpswa", grub_cmd_fpswa,
"", "Display FPSWA version.");
my_mod = mod;
}
GRUB_MOD_FINI(linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
grub_unregister_command (cmd_payload);
grub_unregister_command (cmd_relocate);
grub_unregister_command (cmd_fpswa);
}

View file

@ -54,21 +54,6 @@ static void \
grub_mod_fini (void) grub_mod_fini (void)
#endif #endif
#ifdef APPLE_CC
#define GRUB_MOD_NAME(name) \
static char grub_modname[] __attribute__ ((section ("_modname, _modname"), used)) = #name;
#define GRUB_MOD_DEP(name) \
__asm__ (".section _moddeps, _moddeps\n.asciz \"" #name "\"\n")
#else
#define GRUB_MOD_NAME(name) \
__asm__ (".section .modname\n.asciz \"" #name "\"\n")
#define GRUB_MOD_DEP(name) \
__asm__ (".section .moddeps\n.asciz \"" #name "\"\n")
#endif
#endif #endif
#ifndef ASM_FILE #ifndef ASM_FILE
@ -85,6 +70,15 @@ __asm__ (".section .moddeps\n.asciz \"" #name "\"\n")
#endif #endif
#endif #endif
#ifndef ASM_FILE
#define GRUB_MOD_DEP(name) \
static const char grub_module_depend_##name[] \
__attribute__((section(GRUB_MOD_SECTION(moddeps)), __used__)) = #name
#define GRUB_MOD_NAME(name) \
static const char grub_module_name_##name[] \
__attribute__((section(GRUB_MOD_SECTION(modname)), __used__)) = #name
#endif
/* Me, Vladimir Serbinenko, hereby I add this module check as per new /* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only. GNU module policy. Note that this license check is informative only.
Modules have to be licensed under GPLv3 or GPLv3+ (optionally Modules have to be licensed under GPLv3 or GPLv3+ (optionally
@ -139,6 +133,11 @@ struct grub_dl
Elf_Sym *symtab; Elf_Sym *symtab;
void (*init) (struct grub_dl *mod); void (*init) (struct grub_dl *mod);
void (*fini) (void); void (*fini) (void);
#ifdef __ia64__
void *got;
void *tramp;
#endif
void *base;
struct grub_dl *next; struct grub_dl *next;
}; };
typedef struct grub_dl *grub_dl_t; typedef struct grub_dl *grub_dl_t;
@ -156,7 +155,7 @@ extern grub_dl_t EXPORT_VAR(grub_dl_head);
grub_dl_t EXPORT_FUNC(grub_dl_get) (const char *name); grub_dl_t EXPORT_FUNC(grub_dl_get) (const char *name);
grub_err_t grub_dl_register_symbol (const char *name, void *addr, grub_err_t grub_dl_register_symbol (const char *name, void *addr,
grub_dl_t mod); int isfunc, grub_dl_t mod);
grub_err_t grub_arch_dl_check_header (void *ehdr); grub_err_t grub_arch_dl_check_header (void *ehdr);
grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr); grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr);
@ -166,6 +165,20 @@ grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr);
void grub_arch_dl_init_linker (void); void grub_arch_dl_init_linker (void);
#endif #endif
#define GRUB_IA64_DL_TRAMP_ALIGN 16
#define GRUB_IA64_DL_TRAMP_SIZE 48
#define GRUB_IA64_DL_GOT_ALIGN 16
void
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got);
#ifdef __ia64__
#define GRUB_ARCH_DL_TRAMP_ALIGN 16
#define GRUB_ARCH_DL_GOT_ALIGN 16
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
#endif
#endif #endif
#endif /* ! GRUB_DL_H */ #endif /* ! GRUB_DL_H */

View file

@ -1234,7 +1234,7 @@ struct grub_efi_block_io
}; };
typedef struct grub_efi_block_io grub_efi_block_io_t; typedef struct grub_efi_block_io grub_efi_block_io_t;
#if GRUB_TARGET_SIZEOF_VOID_P == 4 #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__)
#define efi_call_0(func) func() #define efi_call_0(func) func()
#define efi_call_1(func, a) func(a) #define efi_call_1(func, a) func(a)

View file

@ -64,6 +64,7 @@ struct grub_pe32_coff_header
}; };
#define GRUB_PE32_MACHINE_I386 0x14c #define GRUB_PE32_MACHINE_I386 0x14c
#define GRUB_PE32_MACHINE_IA64 0x200
#define GRUB_PE32_MACHINE_X86_64 0x8664 #define GRUB_PE32_MACHINE_X86_64 0x8664
#define GRUB_PE32_RELOCS_STRIPPED 0x0001 #define GRUB_PE32_RELOCS_STRIPPED 0x0001

View file

@ -21,8 +21,7 @@
#include <grub/symbol.h> #include <grub/symbol.h>
/* This is destined to overflow when one hour passes by. */ #define GRUB_TICKS_PER_SECOND 1000
#define GRUB_TICKS_PER_SECOND ((1UL << 31) / 60 / 60 * 2)
/* Return the real time in ticks. */ /* Return the real time in ticks. */
grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void);

View file

@ -2348,6 +2348,8 @@ typedef Elf32_Xword Elf_Xword;
#define ELF_ST_BIND(val) ELF32_ST_BIND(val) #define ELF_ST_BIND(val) ELF32_ST_BIND(val)
#define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) #define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
#define ELF_ST_INFO(a,b) ELF32_ST_INFO(a,b)
#define ELF_R_SYM(val) ELF32_R_SYM(val) #define ELF_R_SYM(val) ELF32_R_SYM(val)
#define ELF_R_TYPE(val) ELF32_R_TYPE(val) #define ELF_R_TYPE(val) ELF32_R_TYPE(val)
#define ELF_R_INFO(sym, type) ELF32_R_INFO(sym, type) #define ELF_R_INFO(sym, type) ELF32_R_INFO(sym, type)
@ -2369,6 +2371,7 @@ typedef Elf64_Xword Elf_Xword;
#define ELF_ST_BIND(val) ELF64_ST_BIND (val) #define ELF_ST_BIND(val) ELF64_ST_BIND (val)
#define ELF_ST_TYPE(val) ELF64_ST_TYPE (val) #define ELF_ST_TYPE(val) ELF64_ST_TYPE (val)
#define ELF_ST_INFO(a,b) ELF64_ST_INFO(a,b)
#define ELF_R_SYM(val) ELF64_R_SYM(val) #define ELF_R_SYM(val) ELF64_R_SYM(val)
#define ELF_R_TYPE(val) ELF64_R_TYPE(val) #define ELF_R_TYPE(val) ELF64_R_TYPE(val)
#define ELF_R_INFO(sym, type) ELF64_R_INFO(sym, type) #define ELF_R_INFO(sym, type) ELF64_R_INFO(sym, type)

View file

@ -0,0 +1,34 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2007,2008,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 <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_MACHINE_KERNEL_HEADER
#define GRUB_MACHINE_KERNEL_HEADER 1
/* The offset of GRUB_PREFIX. */
#define GRUB_KERNEL_MACHINE_PREFIX 0x8
/* End of the data section. */
#define GRUB_KERNEL_MACHINE_DATA_END 0x50
#ifndef ASM_FILE
/* The prefix which points to the directory where GRUB modules and its
configuration file are located. */
extern char grub_prefix[];
#endif
#endif /* ! GRUB_MACHINE_KERNEL_HEADER */

View file

@ -0,0 +1 @@
#include <grub/efi/memory.h>

View file

@ -0,0 +1,23 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_MACHINE_TIME_HEADER
#define GRUB_MACHINE_TIME_HEADER 1
#include <grub/efi/time.h>
#endif /* ! GRUB_MACHINE_TIME_HEADER */

View file

@ -0,0 +1,25 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_CPU_KERNEL_HEADER
#define GRUB_CPU_KERNEL_HEADER 1
#define GRUB_MOD_ALIGN 0x1
#define GRUB_MOD_GAP 0x0
#endif /* ! GRUB_CPU_KERNEL_HEADER */

View file

@ -0,0 +1,28 @@
/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version.
Copyright (C) 1999, 2000, 2008 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* User code must not depend on the internal representation of jmp_buf. */
#define _JBLEN 70
/* the __jmp_buf element type should be __float80 per ABI... */
typedef long grub_jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */
int grub_setjmp (grub_jmp_buf env);
void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));

28
include/grub/ia64/time.h Normal file
View file

@ -0,0 +1,28 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KERNEL_CPU_TIME_HEADER
#define KERNEL_CPU_TIME_HEADER 1
static __inline void
grub_cpu_idle (void)
{
/* FIXME: not implemented */
}
#endif /* ! KERNEL_CPU_TIME_HEADER */

32
include/grub/ia64/types.h Normal file
View file

@ -0,0 +1,32 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_TYPES_CPU_HEADER
#define GRUB_TYPES_CPU_HEADER 1
/* The size of void *. */
#define GRUB_TARGET_SIZEOF_VOID_P 8
/* The size of long. */
#define GRUB_TARGET_SIZEOF_LONG 8
/* ia64 is little-endian (usually). */
#undef GRUB_TARGET_WORDS_BIGENDIAN
#endif /* ! GRUB_TYPES_CPU_HEADER */

View file

@ -39,6 +39,34 @@ void EXPORT_FUNC (__bswapsi2) (void);
# ifdef HAVE___BSWAPDI2 # ifdef HAVE___BSWAPDI2
void EXPORT_FUNC (__bswapdi2) (void); void EXPORT_FUNC (__bswapdi2) (void);
# endif # endif
# ifdef HAVE___UDIVSI3
void EXPORT_FUNC (__udivsi3) (void);
# endif
# ifdef HAVE___UMODSI3
void EXPORT_FUNC (__umodsi3) (void);
# endif
# ifdef HAVE___UMODDI3
void EXPORT_FUNC (__umoddi3) (void);
# endif
# ifdef HAVE___UDIVDI3
void EXPORT_FUNC (__udivdi3) (void);
# endif
# ifdef HAVE___MODDI3
void EXPORT_FUNC (__moddi3) (void);
# endif
# ifdef HAVE___DIVDI3
void EXPORT_FUNC (__divdi3) (void);
# endif
# ifdef HAVE___DIVSI3
void EXPORT_FUNC (__divsi3) (void);
# endif
# ifdef HAVE___MODSI3
void EXPORT_FUNC (__modsi3) (void);
# endif
#endif
# ifdef HAVE___IA64_TRAMPOLINE
void EXPORT_FUNC (__ia64_trampoline) (void);
# endif # endif
#ifdef HAVE___TRAMPOLINE_SETUP #ifdef HAVE___TRAMPOLINE_SETUP

View file

@ -117,6 +117,12 @@
/* End of the data section. */ /* End of the data section. */
#define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50 #define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50
/* The offset of GRUB_PREFIX. */
#define GRUB_KERNEL_IA64_EFI_PREFIX 0x50
/* End of the data section. */
#define GRUB_KERNEL_IA64_EFI_PREFIX_END 0xa0
/* The offset of GRUB_PREFIX. */ /* The offset of GRUB_PREFIX. */
#define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 #define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8

View file

@ -99,9 +99,11 @@ typedef grub_int64_t grub_ssize_t;
# if GRUB_CPU_SIZEOF_LONG == 8 # if GRUB_CPU_SIZEOF_LONG == 8
# define PRIxGRUB_SIZE "lx" # define PRIxGRUB_SIZE "lx"
# define PRIxGRUB_ADDR "lx"
# define PRIuGRUB_SIZE "lu" # define PRIuGRUB_SIZE "lu"
# else # else
# define PRIxGRUB_SIZE "llx" # define PRIxGRUB_SIZE "llx"
# define PRIxGRUB_ADDR "llx"
# define PRIuGRUB_SIZE "llu" # define PRIuGRUB_SIZE "llu"
# endif # endif
#else #else
@ -110,6 +112,7 @@ typedef grub_uint32_t grub_size_t;
typedef grub_int32_t grub_ssize_t; typedef grub_int32_t grub_ssize_t;
# define PRIxGRUB_SIZE "x" # define PRIxGRUB_SIZE "x"
# define PRIxGRUB_ADDR "x"
# define PRIuGRUB_SIZE "u" # define PRIuGRUB_SIZE "u"
#endif #endif

View file

@ -30,6 +30,7 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/offsets.h> #include <grub/offsets.h>
#include <grub/crypto.h> #include <grub/crypto.h>
#include <grub/dl.h>
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
@ -88,8 +89,16 @@ struct image_target_desc
grub_uint64_t link_addr; grub_uint64_t link_addr;
unsigned mod_gap, mod_align; unsigned mod_gap, mod_align;
grub_compression_t default_compression; grub_compression_t default_compression;
grub_uint16_t pe_target;
}; };
#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \
+ GRUB_PE32_SIGNATURE_SIZE \
+ sizeof (struct grub_pe32_coff_header) \
+ sizeof (struct grub_pe64_optional_header) \
+ 4 * sizeof (struct grub_pe32_section_table), \
GRUB_PE32_SECTION_ALIGNMENT)
struct image_target_desc image_targets[] = struct image_target_desc image_targets[] =
{ {
{ {
@ -198,6 +207,8 @@ struct image_target_desc image_targets[] =
GRUB_PE32_SECTION_ALIGNMENT), GRUB_PE32_SECTION_ALIGNMENT),
.install_dos_part = TARGET_NO_FIELD, .install_dos_part = TARGET_NO_FIELD,
.install_bsd_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD,
.pe_target = GRUB_PE32_MACHINE_I386,
.elf_target = EM_386,
}, },
{ {
.dirname = "i386-ieee1275", .dirname = "i386-ieee1275",
@ -255,14 +266,11 @@ struct image_target_desc image_targets[] =
.kernel_image_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD,
.compressed_size = TARGET_NO_FIELD, .compressed_size = TARGET_NO_FIELD,
.section_align = GRUB_PE32_SECTION_ALIGNMENT, .section_align = GRUB_PE32_SECTION_ALIGNMENT,
.vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE .vaddr_offset = EFI64_HEADER_SIZE,
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe64_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT),
.install_dos_part = TARGET_NO_FIELD, .install_dos_part = TARGET_NO_FIELD,
.install_bsd_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD,
.pe_target = GRUB_PE32_MACHINE_X86_64,
.elf_target = EM_X86_64,
}, },
{ {
.dirname = "mips-loongson", .dirname = "mips-loongson",
@ -392,6 +400,26 @@ struct image_target_desc image_targets[] =
.install_bsd_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD,
.link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
}, },
{
.dirname = "ia64-efi",
.names = {"ia64-efi", NULL},
.voidp_sizeof = 8,
.bigendian = 0,
.id = IMAGE_EFI,
.flags = PLATFORM_FLAGS_NONE,
.prefix = GRUB_KERNEL_IA64_EFI_PREFIX,
.prefix_end = GRUB_KERNEL_IA64_EFI_PREFIX_END,
.raw_size = 0,
.total_module_size = TARGET_NO_FIELD,
.kernel_image_size = TARGET_NO_FIELD,
.compressed_size = TARGET_NO_FIELD,
.section_align = GRUB_PE32_SECTION_ALIGNMENT,
.vaddr_offset = EFI64_HEADER_SIZE,
.install_dos_part = TARGET_NO_FIELD,
.install_bsd_part = TARGET_NO_FIELD,
.pe_target = GRUB_PE32_MACHINE_IA64,
.elf_target = EM_IA_64,
},
}; };
#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) #define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
@ -939,12 +967,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
+ 4 * sizeof (struct grub_pe32_section_table), + 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT); GRUB_PE32_SECTION_ALIGNMENT);
else else
header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE header_size = EFI64_HEADER_SIZE;
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe64_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT);
reloc_addr = ALIGN_UP (header_size + core_size, reloc_addr = ALIGN_UP (header_size + core_size,
image_target->section_align); image_target->section_align);
@ -965,10 +988,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
/* The COFF file header. */ /* The COFF file header. */
c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE
+ GRUB_PE32_SIGNATURE_SIZE); + GRUB_PE32_SIGNATURE_SIZE);
if (image_target->voidp_sizeof == 4) c->machine = grub_host_to_target16 (image_target->pe_target);
c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_I386);
else
c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_X86_64);
c->num_sections = grub_host_to_target16 (4); c->num_sections = grub_host_to_target16 (4);
c->time = grub_host_to_target32 (time (0)); c->time = grub_host_to_target32 (time (0));

View file

@ -56,6 +56,7 @@ static Elf_Addr
SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
void *jumpers, Elf_Addr jumpers_addr,
struct image_target_desc *image_target) struct image_target_desc *image_target)
{ {
Elf_Word symtab_size, sym_size, num_syms; Elf_Word symtab_size, sym_size, num_syms;
@ -65,6 +66,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Word i; Elf_Word i;
Elf_Shdr *strtab_section; Elf_Shdr *strtab_section;
const char *strtab; const char *strtab;
grub_uint64_t *jptr = jumpers;
strtab_section strtab_section
= (Elf_Shdr *) ((char *) sections = (Elf_Shdr *) ((char *) sections
@ -101,9 +103,19 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
else if (index >= num_sections) else if (index >= num_sections)
grub_util_error ("section %d does not exist", index); grub_util_error ("section %d does not exist", index);
sym->st_value = (grub_target_to_host32 (sym->st_value) sym->st_value = (grub_target_to_host (sym->st_value)
+ section_addresses[index]); + section_addresses[index]);
grub_util_info ("locating %s at 0x%x", name, sym->st_value);
if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
== STT_FUNC)
{
*jptr = sym->st_value;
sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
jptr++;
*jptr = 0;
jptr++;
}
grub_util_info ("locating %s at 0x%x", name, sym->st_value, section_addresses[index]);
if (! start_address) if (! start_address)
if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
@ -134,6 +146,152 @@ SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset); return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset);
} }
static Elf_Addr
SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
struct image_target_desc *image_target)
{
Elf_Word symtab_size, sym_size, num_syms;
Elf_Off symtab_offset;
Elf_Addr start_address = 0;
Elf_Sym *sym;
Elf_Word i;
int ret = 0;
symtab_size = grub_target_to_host (symtab_section->sh_size);
sym_size = grub_target_to_host (symtab_section->sh_entsize);
symtab_offset = grub_target_to_host (symtab_section->sh_offset);
num_syms = symtab_size / sym_size;
for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
i < num_syms;
i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
ret++;
return ret;
}
#ifdef MKIMAGE_ELF64
struct unaligned_uint32
{
grub_uint32_t val;
} __attribute__ ((packed));
#define MASK20 ((1 << 20) - 1)
#define MASK19 ((1 << 19) - 1)
static void
add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
| (p->val & ~(MASK20 << 2)));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
| (p->val & ~(MASK20 << 3)));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
| (p->val & ~(MASK20 << 4)));
break;
}
}
#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) )
static grub_uint32_t
add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
{
grub_uint32_t high, mid, low, c;
low = (a & 0x00007f);
mid = (a & 0x7fc000) >> 7;
high = (a & 0x003e00) << 7;
c = (low | mid | high) + value;
return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
}
static void
add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4));
break;
}
}
struct ia64_kernel_trampoline
{
/* nop.m */
grub_uint8_t nop[5];
/* movl r15 = addr*/
grub_uint8_t addr_hi[6];
grub_uint8_t e0;
grub_uint8_t addr_lo[4];
grub_uint8_t jump[0x20];
};
static grub_uint8_t nopm[5] =
{
/* [MLX] nop.m 0x0 */
0x05, 0x00, 0x00, 0x00, 0x01
};
static grub_uint8_t jump[0x20] =
{
/* [MMI] add r15=r15,r1;; */
0x0b, 0x78, 0x3c, 0x02, 0x00, 0x20,
/* ld8 r16=[r15],8 */
0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0,
/* mov r14=r1;; */
0x01, 0x08, 0x00, 0x84,
/* [MIB] ld8 r1=[r15] */
0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,
/* mov b6=r16 */
0x60, 0x80, 0x04, 0x80, 0x03, 0x00,
/* br.few b6;; */
0x60, 0x00, 0x80, 0x00
};
static void
make_trampoline (struct ia64_kernel_trampoline *tr, grub_uint64_t addr)
{
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
tr->addr_hi[1] = (addr >> 24) & 0xff;
tr->addr_hi[2] = (addr >> 32) & 0xff;
tr->addr_hi[3] = (addr >> 40) & 0xff;
tr->addr_hi[4] = (addr >> 48) & 0xff;
tr->addr_hi[5] = (addr >> 56) & 0xff;
tr->e0 = 0xe0;
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
| ((addr & 0x200000) >> 17));
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
grub_memcpy (tr->jump, jump, sizeof (tr->jump));
}
#endif
/* Deal with relocation information. This function relocates addresses /* Deal with relocation information. This function relocates addresses
within the virtual address space starting from 0. So only relative within the virtual address space starting from 0. So only relative
addresses can be fully resolved. Absolute addresses must be relocated addresses can be fully resolved. Absolute addresses must be relocated
@ -142,10 +300,15 @@ static void
SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Addr *section_addresses, Elf_Addr *section_addresses,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab, struct image_target_desc *image_target) const char *strtab,
char *pe_target, Elf_Addr tramp_off,
Elf_Addr got_off,
struct image_target_desc *image_target)
{ {
Elf_Half i; Elf_Half i;
Elf_Shdr *s; Elf_Shdr *s;
struct ia64_kernel_trampoline *tr = (void *) (pe_target + tramp_off);
grub_uint64_t *gpptr = (void *) (pe_target + got_off);
for (i = 0, s = sections; for (i = 0, s = sections;
i < num_sections; i < num_sections;
@ -200,7 +363,9 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
r->r_addend : 0; r->r_addend : 0;
if (image_target->voidp_sizeof == 4) switch (image_target->elf_target)
{
case EM_386:
switch (ELF_R_TYPE (info)) switch (ELF_R_TYPE (info))
{ {
case R_386_NONE: case R_386_NONE:
@ -224,11 +389,12 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
*target, offset); *target, offset);
break; break;
default: default:
grub_util_error ("unknown relocation type %d", grub_util_error ("unknown relocation type 0x%x",
ELF_R_TYPE (info)); ELF_R_TYPE (info));
break; break;
} }
else break;
case EM_X86_64:
switch (ELF_R_TYPE (info)) switch (ELF_R_TYPE (info))
{ {
@ -270,6 +436,85 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
ELF_R_TYPE (info)); ELF_R_TYPE (info));
break; break;
} }
break;
#ifdef MKIMAGE_ELF64
case EM_IA_64:
switch (ELF_R_TYPE (info))
{
case R_IA64_PCREL21B:
{
grub_uint64_t noff;
make_trampoline (tr, addend + sym_addr);
noff = ((char *) tr - (char *) pe_target
- target_section_addr - (offset & ~3)) >> 4;
tr++;
if (noff & ~MASK19)
grub_util_error ("trampoline offset too big (%lx)",
noff);
add_value_to_slot_20b ((grub_addr_t) target, noff);
}
break;
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
{
Elf_Sym *sym;
sym = (Elf_Sym *) ((char *) e
+ grub_target_to_host32 (symtab_section->sh_offset)
+ ELF_R_SYM (info) * grub_target_to_host32 (symtab_section->sh_entsize));
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
+ sym->st_value
- image_target->vaddr_offset));
}
case R_IA64_LTOFF_FPTR22:
*gpptr = grub_host_to_target64 (addend + sym_addr);
add_value_to_slot_21 ((grub_addr_t) target,
(char *) gpptr - (char *) pe_target
+ image_target->vaddr_offset);
gpptr++;
break;
case R_IA64_GPREL22:
add_value_to_slot_21 ((grub_addr_t) target,
addend + sym_addr);
break;
case R_IA64_PCREL64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr
- target_section_addr - offset
- image_target->vaddr_offset);
break;
case R_IA64_SEGREL64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr - target_section_addr);
break;
case R_IA64_DIR64LSB:
case R_IA64_FPTR64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr);
grub_util_info ("relocating a direct entry to 0x%"
PRIxGRUB_UINT64_T " at the offset 0x%x",
*target, offset);
break;
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
case R_IA64_LDXMOV:
break;
default:
grub_util_error ("unknown relocation type 0x%x",
ELF_R_TYPE (info));
break;
}
break;
#endif
default:
grub_util_error ("unknown architecture type %d",
image_target->elf_target);
}
} }
} }
} }
@ -312,7 +557,7 @@ SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
b->block_size += 2; b->block_size += 2;
} }
} }
else if (b->block_size & (8 - 1)) else while (b->block_size & (8 - 1))
{ {
/* If not aligned with a 32-bit boundary, add /* If not aligned with a 32-bit boundary, add
a padding entry. */ a padding entry. */
@ -374,9 +619,11 @@ static Elf_Addr
SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
Elf_Addr *section_addresses, Elf_Shdr *sections, Elf_Addr *section_addresses, Elf_Shdr *sections,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab, struct image_target_desc *image_target) const char *strtab,
Elf_Addr jumpers, grub_size_t njumpers,
struct image_target_desc *image_target)
{ {
Elf_Half i; unsigned i;
Elf_Shdr *s; Elf_Shdr *s;
struct fixup_block_list *lst, *lst0; struct fixup_block_list *lst, *lst0;
Elf_Addr current_address = 0; Elf_Addr current_address = 0;
@ -384,8 +631,7 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
memset (lst, 0, sizeof (*lst) + 2 * 0x1000); memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
for (i = 0, s = sections; for (i = 0, s = sections; i < num_sections;
i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) ||
(s->sh_type == grub_cpu_to_le32 (SHT_RELA))) (s->sh_type == grub_cpu_to_le32 (SHT_RELA)))
@ -417,8 +663,9 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
info = grub_le_to_cpu32 (r->r_info); info = grub_le_to_cpu32 (r->r_info);
/* Necessary to relocate only absolute addresses. */ /* Necessary to relocate only absolute addresses. */
if (image_target->voidp_sizeof == 4) switch (image_target->elf_target)
{ {
case EM_386:
if (ELF_R_TYPE (info) == R_386_32) if (ELF_R_TYPE (info) == R_386_32)
{ {
Elf_Addr addr; Elf_Addr addr;
@ -431,9 +678,8 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
addr, 0, current_address, addr, 0, current_address,
image_target); image_target);
} }
} break;
else case EM_X86_64:
{
if ((ELF_R_TYPE (info) == R_X86_64_32) || if ((ELF_R_TYPE (info) == R_X86_64_32) ||
(ELF_R_TYPE (info) == R_X86_64_32S)) (ELF_R_TYPE (info) == R_X86_64_32S))
{ {
@ -452,10 +698,57 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
0, current_address, 0, current_address,
image_target); image_target);
} }
break;
case EM_IA_64:
switch (ELF_R_TYPE (info))
{
case R_IA64_PCREL64LSB:
case R_IA64_LDXMOV:
case R_IA64_PCREL21B:
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
case R_IA64_GPREL22:
case R_IA64_SEGREL64LSB:
break;
case R_IA64_FPTR64LSB:
case R_IA64_DIR64LSB:
#if 1
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info ("adding a relocation entry for 0x%llx", addr);
current_address
= SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_DIR64,
addr,
0, current_address,
image_target);
}
#endif
break;
default:
grub_util_error ("unknown relocation type 0x%x",
ELF_R_TYPE (info));
break;
}
break;
default:
grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
} }
} }
} }
if (image_target->elf_target == EM_IA_64)
for (i = 0; i < njumpers; i++)
current_address = SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_DIR64,
jumpers + 8 * i,
0, current_address,
image_target);
current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
{ {
@ -617,7 +910,10 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
Elf_Off section_offset; Elf_Off section_offset;
Elf_Half section_entsize; Elf_Half section_entsize;
grub_size_t kernel_size; grub_size_t kernel_size;
grub_size_t ia64jmp_off = 0, ia64_toff = 0, ia64_got_off = 0;
unsigned ia64jmpnum = 0;
Elf_Shdr *symtab_section; Elf_Shdr *symtab_section;
grub_size_t got = 0;
*start = 0; *start = 0;
@ -696,23 +992,31 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
break; break;
} }
#ifdef MKIMAGE_ELF64
if (image_target->elf_target == EM_IA_64)
{
grub_size_t tramp;
*kernel_sz = ALIGN_UP (*kernel_sz, 16);
grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
tramp *= sizeof (struct ia64_kernel_trampoline);
ia64_toff = *kernel_sz;
*kernel_sz += ALIGN_UP (tramp, 16);
ia64jmp_off = *kernel_sz;
ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
image_target);
*kernel_sz += 16 * ia64jmpnum;
ia64_got_off = *kernel_sz;
*kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16);
}
#endif
if (! symtab_section) if (! symtab_section)
grub_util_error ("no symbol table"); grub_util_error ("no symbol table");
*start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
section_vaddresses, section_entsize,
num_sections, image_target);
if (*start == 0)
grub_util_error ("start symbol is not defined");
/* Resolve addresses in the virtual address space. */
SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize,
num_sections, strtab, image_target);
*reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
section_vaddresses, sections,
section_entsize, num_sections,
strtab, image_target);
} }
else else
{ {
@ -722,6 +1026,34 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
out_img = xmalloc (*kernel_sz + total_module_size); out_img = xmalloc (*kernel_sz + total_module_size);
if (image_target->id == IMAGE_EFI)
{
*start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
section_vaddresses, section_entsize,
num_sections,
(char *) out_img + ia64jmp_off,
ia64jmp_off
+ image_target->vaddr_offset,
image_target);
if (*start == 0)
grub_util_error ("start symbol is not defined");
/* Resolve addresses in the virtual address space. */
SUFFIX (relocate_addresses) (e, sections, section_addresses,
section_entsize,
num_sections, strtab,
out_img, ia64_toff, ia64_got_off,
image_target);
*reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
section_vaddresses, sections,
section_entsize, num_sections,
strtab, ia64jmp_off
+ image_target->vaddr_offset,
2 * ia64jmpnum + got,
image_target);
}
for (i = 0, s = sections; for (i = 0, s = sections;
i < num_sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))