Index: boot/Makefile.build
===================================================================
--- boot/Makefile.build	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/Makefile.build	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -37,5 +37,5 @@
 
 AFLAGS = --fatal-warnings
-LDFLAGS = -Wl,--fatal-warnings,--warn-common
+LDFLAGS = -Wl,--fatal-warnings,--warn-common $(EXTRA_LDFLAGS)
 
 COMMON_CFLAGS = $(INCLUDES) -O$(OPTIMIZATION) -imacros $(CONFIG_HEADER) \
Index: boot/Makefile.grub
===================================================================
--- boot/Makefile.grub	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/Makefile.grub	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -64,7 +64,12 @@
 endif
 
+ifeq ($(GRUB_LOADER),multiboot)
 	for module in $(COMPONENTS) ; do \
 		cp "$$module" $(BOOT)/ ; \
 	done
+endif
+ifeq ($(GRUB_LOADER),chainloader)
+	cp "$(BOOT_OUTPUT)" $(BOOT)/
+endif
 
 	echo "set default=0" > $(BOOT_CONFIG)
@@ -83,4 +88,5 @@
 
 	echo "menuentry 'HelenOS $(RELEASE)' --class helenos --class os {" >> $(BOOT_CONFIG)
+ifeq ($(GRUB_LOADER),multiboot)
 	for module in $(MODULES) ; do \
 		echo "	echo 'Loading $$module'" >> $(BOOT_CONFIG) ; \
@@ -91,4 +97,10 @@
 		fi \
 	done
+endif
+ifeq ($(GRUB_LOADER),chainloader)
+	echo "	echo 'Loading $(BOOT_OUTPUT)'" >> $(BOOT_CONFIG)
+	echo "	chainloader /boot/$(BOOT_OUTPUT)" >> $(BOOT_CONFIG)
+	echo "	boot" >> $(BOOT_CONFIG)
+endif
 	echo "}" >> $(BOOT_CONFIG)
 
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/arch/amd64/Makefile.inc	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -74,2 +74,3 @@
 BUILD = Makefile.empty
 POSTBUILD = Makefile.grub
+GRUB_LOADER = multiboot
Index: boot/arch/arm64/Makefile.inc
===================================================================
--- boot/arch/arm64/Makefile.inc	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/Makefile.inc	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2015 Petr Pavlu
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+BOOT_OUTPUT = image.boot
+POST_OUTPUT = $(ROOT_PATH)/image.iso
+POSTBUILD = Makefile.grub
+GRUB_LOADER = chainloader
+
+BFD_NAME = elf64-littleaarch64
+# Request binary BFD output. The ARM64 port manually prepares the .text
+# section to look as a PE file than can be loaded on EFI systems.
+BFD_OUTPUT = binary
+BFD_ARCH = aarch64
+
+BITS = 64
+ENDIANESS = LE
+
+# UEFI binaries should be relocatable, the EFI boot service LoadImage() will
+# rebase the boot file using the .reloc information in the image if it cannot
+# load the binary at its preferred address. The ARM64 port does not provide this
+# information in its PE file (that would require manually creating it) but
+# instead the boot code is compiled with the -fpic option and the bootloader
+# relocates itself at runtime.
+#
+# N.B. The UEFI guarantees for AArch64 that during boot time the primary
+# processor is in the execution mode that has unaligned access enabled. The
+# -mstrict-align option is therefore not needed.
+EXTRA_CFLAGS = -fpic -fvisibility=hidden
+EXTRA_LDFLAGS = -Wl,-shared
+
+SOURCES = \
+	arch/$(BARCH)/src/asm.S \
+	arch/$(BARCH)/src/main.c \
+	arch/$(BARCH)/src/relocate.c \
+	$(COMPS).o \
+	genarch/src/efi.c \
+	generic/src/gzip.c \
+	generic/src/inflate.c \
+	generic/src/kernel.c \
+	generic/src/memstr.c \
+	generic/src/payload.c \
+	generic/src/printf.c \
+	generic/src/printf_core.c \
+	generic/src/str.c \
+	generic/src/tar.c \
+	generic/src/version.c \
+	generic/src/vprintf.c
Index: boot/arch/arm64/_link.ld.in
===================================================================
--- boot/arch/arm64/_link.ld.in	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/_link.ld.in	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,33 @@
+#include <arch/arch.h>
+
+ENTRY(start)
+
+SECTIONS {
+	. = 0x0;
+	.text : {
+		HIDDEN(loader_start = .);
+		*(BOOTSTRAP);
+		*(.text);
+	}
+	.dynamic : { *(.dynamic); }
+	.rela.got : { *(.rela.got); }
+	.hash : { *(.hash); }
+	.dynsym : { *(.dynsym); }
+	.dynstr : { *(.dynstr); }
+	. = 0x8000;
+	.data : {
+		*(.data*);      /* initialized data */
+		*(.rodata*);
+		*(.bss);        /* uninitialized static variables */
+		*(COMMON);      /* global variables */
+		*(.got .got.plt);
+		HIDDEN(loader_end = .);
+		HIDDEN(payload_start = .);
+		*(.payload);
+		HIDDEN(payload_end = .);
+	}
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: boot/arch/arm64/include/arch/arch.h
===================================================================
--- boot/arch/arm64/include/arch/arch.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/arch.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Various ARM64-specific macros.
+ */
+
+#ifndef BOOT_arm64_ARCH_H
+#define BOOT_arm64_ARCH_H
+
+#define PAGE_WIDTH  12
+#define PAGE_SIZE   (1 << PAGE_WIDTH)
+
+#define BOOT_OFFSET  0x80000
+#ifndef __ASSEMBLER__
+#define KA2PA(x)  (((uintptr_t) (x)) - UINT64_C(0xffffffff80000000))
+#endif
+
+#endif
+
+/** @}
+ */
Index: boot/arch/arm64/include/arch/asm.h
===================================================================
--- boot/arch/arm64/include/arch/asm.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/asm.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Functions implemented in assembly.
+ */
+
+#ifndef BOOT_arm64_ASM_H
+#define BOOT_arm64_ASM_H
+
+/** Jump to the kernel entry point.
+ *
+ * @param entry    Kernel entry point.
+ * @param bootinfo Structure holding information about loaded tasks.
+ */
+extern void jump_to_kernel(void *entry, void *bootinfo)
+    __attribute__((noreturn));
+
+#endif
+
+/** @}
+ */
Index: boot/arch/arm64/include/arch/barrier.h
===================================================================
--- boot/arch/arm64/include/arch/barrier.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/barrier.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,1 @@
+../../../../../kernel/arch/arm64/include/arch/barrier.h
Index: boot/arch/arm64/include/arch/boot.h
===================================================================
--- boot/arch/arm64/include/arch/boot.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/boot.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,1 @@
+../../../../../kernel/arch/arm64/include/arch/boot/boot.h
Index: boot/arch/arm64/include/arch/main.h
===================================================================
--- boot/arch/arm64/include/arch/main.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/main.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Boot related declarations.
+ */
+
+#ifndef BOOT_arm64_MAIN_H
+#define BOOT_arm64_MAIN_H
+
+#include <genarch/efi.h>
+
+extern efi_status_t bootstrap(void *efi_handle_in,
+    efi_system_table_t *efi_system_table_in, void *load_address);
+
+#endif
+
+/** @}
+ */
Index: boot/arch/arm64/include/arch/regutils.h
===================================================================
--- boot/arch/arm64/include/arch/regutils.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/regutils.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,1 @@
+../../../../../kernel/arch/arm64/include/arch/regutils.h
Index: boot/arch/arm64/include/arch/relocate.h
===================================================================
--- boot/arch/arm64/include/arch/relocate.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/relocate.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Image self-relocation support.
+ */
+
+#ifndef BOOT_arm64_RELOCATE_H
+#define BOOT_arm64_RELOCATE_H
+
+#include <abi/elf.h>
+#include <genarch/efi.h>
+#include <stdint.h>
+
+extern efi_status_t self_relocate(uintptr_t base, const elf_dyn_t *dyn);
+
+#endif
+
+/** @}
+ */
Index: boot/arch/arm64/include/arch/types.h
===================================================================
--- boot/arch/arm64/include/arch/types.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/include/arch/types.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Definitions of basic types like #uintptr_t.
+ */
+
+#ifndef BOOT_arm64_TYPES_H
+#define BOOT_arm64_TYPES_H
+
+#include <_bits/all.h>
+
+#include <arch/boot.h>
+#define task_t utask_t
+
+#endif
+
+/** @}
+ */
Index: boot/arch/arm64/src/asm.S
===================================================================
--- boot/arch/arm64/src/asm.S	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/src/asm.S	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <abi/asmtool.h>
+#include <arch/arch.h>
+#include <arch/regutils.h>
+
+.section BOOTSTRAP
+
+/* MS-DOS stub */
+msdos_stub:
+	.ascii "MZ"                     /* MS-DOS signature */
+	.space 0x3a                     /* Ignore fields up to byte at 0x3c */
+	.long pe_header - msdos_stub    /* Offset to the PE header */
+
+/* Portable Executable header */
+pe_header:
+	/* PE signature */
+	.ascii "PE\x0\x0"
+
+	/* COFF File Header */
+	.short 0xaa64                   /* Machine = IMAGE_FILE_MACHINE_ARM64 */
+	.short 1                        /* Number of sections */
+	.long 0                         /* Time date stamp */
+	.long 0                         /* Pointer to symbol table */
+	.long 0                         /* Number of symbols */
+	.short sec_table - opt_header   /* Size of optional header */
+	/* Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE |
+	 *   IMAGE_FILE_LARGE_ADDRESS_AWARE */
+	.short 0x22
+
+	/* Optional header standard fields */
+opt_header:
+	.short 0x20b                    /* Magic = PE32+ */
+	.byte 0                         /* Major linker version */
+	.byte 0                         /* Minor linker version */
+	.long payload_end - msdos_stub  /* Size of code */
+	.long 0                         /* Size of initialized data */
+	.long 0                         /* Size of uninitialized data */
+	.long start - msdos_stub        /* Address of entry point */
+	.long start - msdos_stub        /* Base of code */
+
+	/* Optional header Windows-specific fields */
+	.quad 0                         /* Image base */
+	.long 4                         /* Section alignment */
+	.long 4                         /* File alignment */
+	.short 0                        /* Major operating system version */
+	.short 0                        /* Minor operating system version */
+	.short 0                        /* Major image version */
+	.short 0                        /* Minor image version */
+	.short 0                        /* Major subsystem version */
+	.short 0                        /* Minor subsystem version */
+	.long 0                         /* Win32 version value */
+	.long payload_end - msdos_stub  /* Size of image */
+	.long start - msdos_stub        /* Size of headers */
+	.long 0                         /* Checksum */
+	.short 10                       /* Subsystem = EFI application */
+	.short 0                        /* DLL characteristics */
+	.quad 0                         /* Size of stack reserve */
+	.quad 0                         /* Size of stack commit */
+	.quad 0                         /* Size of heap reserve */
+	.quad 0                         /* Size of heap commit */
+	.long 0                         /* Loader flags */
+	.long 0                         /* Number of RVA and sizes */
+
+sec_table:
+        .ascii ".text\x0\x0\x0"         /* Name */
+	.long payload_end - start       /* Virtual size */
+	.long start - msdos_stub        /* Virtual address */
+	.long payload_end - start       /* Size of raw data */
+	.long start - msdos_stub        /* Pointer to raw data */
+	.long 0                         /* Pointer to relocations */
+	.long 0                         /* Pointer to line numbers */
+	.short 0                        /* Number of relocations */
+	.short 0                        /* Number of line numbers */
+	/* Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE |
+	 *   IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE */
+	.long 0xe0000020
+
+SYMBOL(start)
+	.hidden start
+
+	/*
+	 * Parameters:
+	 * x0 is the image handle.
+	 * x1 is a pointer to the UEFI system table.
+	 */
+
+	/*
+	 * Stay on the UEFI stack. Its size is at least 128 kB, plenty for this
+	 * boot loader.
+	 */
+	stp x29, x30, [sp, #-32]!
+	mov x29, sp
+	stp x0, x1, [sp, #16]
+
+	/*
+	 * Self-relocate the image. Pass a load address of the image (x0) and a
+	 * pointer to the dynamic array (x1).
+	 */
+	adr x0, msdos_stub
+	adrp x1, _DYNAMIC
+	add x1, x1, #:lo12:_DYNAMIC
+	bl self_relocate
+	cbnz x0, 0f
+
+	/*
+	 * Pass the image handle (x0), a pointer to the UEFI system table (x1),
+	 * and the image load address (x2) to the boostrap function.
+	 */
+	ldp x0, x1, [sp, #16]
+	adr x2, msdos_stub
+	bl bootstrap
+
+0:
+	ldp x29, x30, [sp], #32
+	ret
+
+FUNCTION_BEGIN(halt)
+	.hidden halt
+
+	b halt
+FUNCTION_END(halt)
+
+FUNCTION_BEGIN(jump_to_kernel)
+	.hidden jump_to_kernel
+
+	/*
+	 * Parameters:
+	 * x0 is kernel entry point.
+	 * x1 is pointer to the bootinfo structure.
+	 */
+
+	/* Disable MMU (removes the identity mapping provided by UEFI). */
+	mrs x2, sctlr_el1
+	bic x2, x2, #SCTLR_M_FLAG
+	msr sctlr_el1, x2
+	isb
+
+	br x0
+FUNCTION_END(jump_to_kernel)
Index: boot/arch/arm64/src/main.c
===================================================================
--- boot/arch/arm64/src/main.c	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/src/main.c	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2015 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Bootstrap.
+ */
+
+#include <stddef.h>
+#include <align.h>
+#include <arch/arch.h>
+#include <arch/asm.h>
+#include <arch/barrier.h>
+#include <arch/main.h>
+#include <arch/regutils.h>
+#include <arch/types.h>
+#include <errno.h>
+#include <inflate.h>
+#include <kernel.h>
+#include <macros.h>
+#include <memstr.h>
+#include <payload.h>
+#include <printf.h>
+#include <putchar.h>
+#include <str.h>
+#include <version.h>
+
+static efi_system_table_t *efi_system_table;
+
+/** Translate given UEFI memory type to the bootinfo memory type.
+ *
+ * @param type UEFI memory type.
+ */
+static memtype_t get_memtype(uint32_t type)
+{
+	switch (type) {
+	case EFI_RESERVED:
+	case EFI_RUNTIME_SERVICES_CODE:
+	case EFI_RUNTIME_SERVICES_DATA:
+	case EFI_UNUSABLE_MEMORY:
+	case EFI_ACPI_MEMORY_NVS:
+	case EFI_MEMORY_MAPPED_IO:
+	case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+	case EFI_PAL_CODE:
+		return MEMTYPE_UNUSABLE;
+	case EFI_LOADER_CODE:
+	case EFI_LOADER_DATA:
+	case EFI_BOOT_SERVICES_CODE:
+	case EFI_BOOT_SERVICES_DATA:
+	case EFI_CONVENTIONAL_MEMORY:
+	case EFI_PERSISTENT_MEMORY:
+		return MEMTYPE_AVAILABLE;
+	case EFI_ACPI_RECLAIM_MEMORY:
+		return MEMTYPE_ACPI_RECLAIM;
+	}
+
+	return MEMTYPE_UNUSABLE;
+}
+
+/** Send a byte to the UEFI console output.
+ *
+ * @param byte Byte to send.
+ */
+static void scons_sendb(uint8_t byte)
+{
+	int16_t out[2] = { byte, '\0' };
+	efi_system_table->cons_out->output_string(efi_system_table->cons_out,
+	    out);
+}
+
+/** Display a character.
+ *
+ * @param ch Character to display.
+ */
+void putwchar(wchar_t ch)
+{
+	if (ch == '\n')
+		scons_sendb('\r');
+
+	if (ascii_check(ch))
+		scons_sendb((uint8_t) ch);
+	else
+		scons_sendb('?');
+}
+
+efi_status_t bootstrap(void *efi_handle_in,
+    efi_system_table_t *efi_system_table_in, void *load_address)
+{
+	efi_status_t status;
+	uint64_t current_el;
+	uint64_t memmap = 0;
+	sysarg_t memmap_size;
+	sysarg_t memmap_key;
+	sysarg_t memmap_descriptor_size;
+	uint32_t memmap_descriptor_version;
+	uint64_t alloc_addr = 0;
+	sysarg_t alloc_pages = 0;
+
+	/*
+	 * Bootinfo structure is dynamically allocated in the ARM64 port. It is
+	 * placed directly after the inflated components. This assures that if
+	 * the kernel identity maps the first gigabyte of the main memory in the
+	 * kernel/upper address space then it can access the bootinfo because
+	 * the inflated components and bootinfo can always fit in this area.
+	 */
+	bootinfo_t *bootinfo;
+
+	efi_system_table = efi_system_table_in;
+
+	version_print();
+
+	printf("Boot loader: %p -> %p\n", loader_start, loader_end);
+	printf("\nMemory statistics\n");
+	printf(" %p|%p: loader\n", load_address, load_address);
+	printf(" %p|%p: UEFI system table\n", efi_system_table_in,
+	    efi_system_table_in);
+
+	/* Validate the exception level. */
+	current_el = CurrentEL_read();
+	if (current_el != CURRENT_EL_EL1) {
+		printf("Error: Unexpected CurrentEL value %0#18" PRIx64 ".\n",
+		    current_el);
+		status = EFI_UNSUPPORTED;
+		goto fail;
+	}
+
+	/* Obtain memory map. */
+	status = efi_get_memory_map(efi_system_table, &memmap_size,
+	    (efi_v1_memdesc_t **) &memmap, &memmap_key, &memmap_descriptor_size,
+	    &memmap_descriptor_version);
+	if (status != EFI_SUCCESS) {
+		printf("Error: Unable to obtain initial memory map, status "
+		    "code: %" PRIx64 ".\n", status);
+		goto fail;
+	}
+
+	/* Find start of usable RAM. */
+	uint64_t memory_base = (uint64_t) -1;
+	for (sysarg_t i = 0; i < memmap_size / memmap_descriptor_size; i++) {
+		efi_v1_memdesc_t *desc = (void *) memmap +
+		    (i * memmap_descriptor_size);
+		if (get_memtype(desc->type) != MEMTYPE_AVAILABLE ||
+		    !(desc->attribute & EFI_MEMORY_WB))
+			continue;
+
+		if (desc->phys_start < memory_base)
+			memory_base = desc->phys_start;
+	}
+
+	/* Deallocate memory holding the map. */
+	efi_system_table->boot_services->free_pool((void *) memmap);
+	memmap = 0;
+
+	if (memory_base == (uint64_t) -1) {
+		printf("Error: Memory map does not contain any usable RAM.\n");
+		status = EFI_UNSUPPORTED;
+		goto fail;
+	}
+
+	/*
+	 * Check that everything is aligned on a 4kB boundary and the kernel can
+	 * be placed by the decompression code at a correct address.
+	 */
+
+	/* Statically check PAGE_SIZE and BOOT_OFFSET. */
+#if PAGE_SIZE != 4096
+#error Unsupported PAGE_SIZE
+#endif
+#if !IS_ALIGNED(BOOT_OFFSET, PAGE_SIZE)
+#error Unsupported BOOT_OFFSET
+#endif
+	/*
+	 * Dynamically check the memory base. The condition should be always
+	 * true because UEFI guarantees each physical/virtual address in the
+	 * memory map is aligned on a 4kB boundary.
+	 */
+	if (!IS_ALIGNED(memory_base, PAGE_SIZE)) {
+		printf("Error: Start of usable RAM (%p) is not aligned on a "
+		    "4kB boundary.\n", (void *) memory_base);
+		status = EFI_UNSUPPORTED;
+		goto fail;
+	}
+
+	/*
+	 * Calculate where the components (including the kernel) will get
+	 * placed.
+	 */
+	uint64_t decompress_base = memory_base + BOOT_OFFSET;
+	printf(" %p|%p: kernel entry point\n", (void *) decompress_base,
+	    (void *) decompress_base);
+
+	/*
+	 * Allocate memory for the decompressed components and for the bootinfo.
+	 */
+	uint64_t component_pages =
+	    ALIGN_UP(payload_unpacked_size(), EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+	uint64_t bootinfo_pages = ALIGN_UP(sizeof(*bootinfo), EFI_PAGE_SIZE) /
+	    EFI_PAGE_SIZE;
+	alloc_pages = component_pages + bootinfo_pages;
+	alloc_addr = decompress_base;
+	status = efi_system_table->boot_services->allocate_pages(
+	    EFI_ALLOCATE_ADDRESS, EFI_LOADER_CODE, alloc_pages, &alloc_addr);
+	if (status != EFI_SUCCESS) {
+		printf("Error: Unable to allocate memory for inflated "
+		    "components and bootinfo, status code: %" PRIx64 ".\n",
+		    status);
+		goto fail;
+	}
+
+	bootinfo = (void *) alloc_addr + component_pages * EFI_PAGE_SIZE;
+	printf(" %p|%p: boot info structure\n", bootinfo, bootinfo);
+	memset(bootinfo, 0, sizeof(*bootinfo));
+
+	/* Decompress the components. */
+	uint8_t *kernel_dest = (uint8_t *) alloc_addr;
+	uint8_t *ram_end = kernel_dest + component_pages * EFI_PAGE_SIZE;
+
+	extract_payload(&bootinfo->taskmap, kernel_dest, ram_end,
+	    (uintptr_t) kernel_dest, ensure_visibility);
+
+	/* Get final memory map. */
+	status = efi_get_memory_map(efi_system_table, &memmap_size,
+	    (efi_v1_memdesc_t **) &memmap, &memmap_key, &memmap_descriptor_size,
+	    &memmap_descriptor_version);
+	if (status != EFI_SUCCESS) {
+		printf("Error: Unable to obtain final memory map, status code: "
+		    "%" PRIx64 ".\n", status);
+		goto fail;
+	}
+
+	/* Convert the UEFI memory map to the bootinfo representation. */
+	size_t cnt = 0;
+	memtype_t current_type = MEMTYPE_UNUSABLE;
+	void *current_start = 0;
+	size_t current_size = 0;
+	sysarg_t memmap_items_count = memmap_size / memmap_descriptor_size;
+	for (sysarg_t i = 0; i < memmap_items_count; i++) {
+		efi_v1_memdesc_t *desc = (void *) memmap +
+		    (i * memmap_descriptor_size);
+
+		/* Get type of the new area. */
+		memtype_t type;
+		if (!(desc->attribute & EFI_MEMORY_WB))
+			type = MEMTYPE_UNUSABLE;
+		else
+			type = get_memtype(desc->type);
+
+		/* Try to merge the new area with the previous one. */
+		if (type == current_type &&
+		    (uint64_t)current_start + current_size == desc->phys_start) {
+			current_size += desc->pages * EFI_PAGE_SIZE;
+			if (i != memmap_items_count - 1)
+				continue;
+		}
+
+		/* Record the previous area. */
+		if (current_type != MEMTYPE_UNUSABLE) {
+			if (cnt >= MEMMAP_MAX_RECORDS) {
+				printf("Error: Too many usable memory "
+				    "areas.\n");
+				status = EFI_UNSUPPORTED;
+				goto fail;
+			}
+			bootinfo->memmap.zones[cnt].type = current_type;
+			bootinfo->memmap.zones[cnt].start = current_start;
+			bootinfo->memmap.zones[cnt].size = current_size;
+			cnt++;
+		}
+
+		/* Remember the new area. */
+		current_type = type;
+		current_start = (void *) desc->phys_start;
+		current_size = desc->pages * EFI_PAGE_SIZE;
+	}
+	bootinfo->memmap.cnt = cnt;
+
+	uintptr_t entry = check_kernel_translated((void *) decompress_base,
+	    BOOT_OFFSET);
+
+	printf("Booting the kernel...\n");
+
+	/* Exit boot services. This is a point of no return. */
+	efi_system_table->boot_services->exit_boot_services(efi_handle_in,
+	    memmap_key);
+
+	entry = memory_base + KA2PA(entry);
+	jump_to_kernel((void *) entry, bootinfo);
+
+fail:
+	if (memmap != 0)
+		efi_system_table->boot_services->free_pool((void *) memmap);
+
+	if (alloc_addr != 0)
+		efi_system_table->boot_services->free_pages(alloc_addr,
+		    alloc_pages);
+
+	return status;
+}
+
+/** @}
+ */
Index: boot/arch/arm64/src/relocate.c
===================================================================
--- boot/arch/arm64/src/relocate.c	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
+++ boot/arch/arm64/src/relocate.c	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Petr Pavlu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup boot_arm64
+ * @{
+ */
+/** @file
+ * @brief Image self-relocation support.
+ */
+
+#include <arch/relocate.h>
+#include <printf.h>
+
+/** Self-relocate the bootloader.
+ *
+ * Note: This code is responsible for self-relocating the bootloader when it is
+ * started. As such, it is required that it is written in a way that it itself
+ * does not need any dynamic relocation.
+ */
+efi_status_t self_relocate(uintptr_t base, const elf_dyn_t *dyn)
+{
+	const elf_rela_t *rela = NULL;
+	uint64_t relasz = 0;
+	uint64_t relaent = 0;
+
+	/* Parse the dynamic array. */
+	while (dyn->d_tag != DT_NULL) {
+		switch (dyn->d_tag) {
+		case DT_RELA:
+			rela = (const elf_rela_t *) (base + dyn->d_un.d_ptr);
+			break;
+		case DT_RELASZ:
+			relasz = dyn->d_un.d_val;
+			break;
+		case DT_RELAENT:
+			relaent = dyn->d_un.d_val;
+			break;
+		}
+		dyn++;
+	}
+
+	/* Validate obtained information. */
+	if (rela == NULL)
+		return EFI_SUCCESS;
+	if (relaent == 0 || relasz % relaent != 0)
+		return EFI_UNSUPPORTED;
+
+	/* Process relocations in the image. */
+	while (relasz > 0) {
+		switch (ELF_R_TYPE(rela->r_info)) {
+		case R_AARCH64_RELATIVE:
+			*(uint64_t *) (base + rela->r_offset) =
+			    base + rela->r_addend;
+			break;
+		default:
+			return EFI_UNSUPPORTED;
+		}
+
+		rela = (const elf_rela_t *) ((const char *) rela + relaent);
+		relasz -= relaent;
+	}
+	return EFI_SUCCESS;
+}
+
+/** @}
+ */
Index: boot/doc/doxygroups.h
===================================================================
--- boot/doc/doxygroups.h	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/doc/doxygroups.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -11,2 +11,6 @@
  *     @ingroup boot
  */
+
+/**    @addtogroup boot_arm64 arm64
+ *     @ingroup boot
+ */
Index: boot/genarch/include/genarch/efi.h
===================================================================
--- boot/genarch/include/genarch/efi.h	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/genarch/include/genarch/efi.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -32,4 +32,12 @@
 #include <arch/types.h>
 
+#define EFI_SUCCESS  0
+#define EFI_ERROR(code) (((sysarg_t) 1 << (sizeof(sysarg_t) * 8 - 1)) | (code))
+#define EFI_LOAD_ERROR  EFI_ERROR(1)
+#define EFI_UNSUPPORTED  EFI_ERROR(3)
+#define EFI_BUFFER_TOO_SMALL  EFI_ERROR(5)
+
+typedef uint64_t efi_status_t;
+
 typedef struct {
 	uint64_t signature;
@@ -56,24 +64,9 @@
 } efi_guid_t;
 
-typedef struct {
-	efi_guid_t guid;
-	void *table;
-} efi_configuration_table_t;
-
-typedef struct {
-	efi_table_header_t hdr;
-	char *fw_vendor;
-	uint32_t fw_revision;
-	void *cons_in_handle;
-	void *cons_in;
-	void *cons_out_handle;
-	void *cons_out;
-	void *cons_err_handle;
-	void *cons_err;
-	void *runtime_services;
-	void *boot_services;
-	sysarg_t conf_table_entries;
-	efi_configuration_table_t *conf_table;
-} efi_system_table_t;
+typedef enum {
+	EFI_ALLOCATE_ANY_PAGES,
+	EFI_ALLOCATE_MAX_ADDRESS,
+	EFI_ALLOCATE_ADDRESS
+} efi_allocate_type_t;
 
 typedef enum {
@@ -91,6 +84,20 @@
 	EFI_MEMORY_MAPPED_IO,
 	EFI_MEMORY_MAPPED_IO_PORT_SPACE,
-	EFI_PAL_CODE
+	EFI_PAL_CODE,
+	EFI_PERSISTENT_MEMORY
 } efi_memory_type_t;
+
+#define EFI_MEMORY_UC             UINT64_C(0x0000000000000001)
+#define EFI_MEMORY_WC             UINT64_C(0x0000000000000002)
+#define EFI_MEMORY_WT             UINT64_C(0x0000000000000004)
+#define EFI_MEMORY_WB             UINT64_C(0x0000000000000008)
+#define EFI_MEMORY_UCE            UINT64_C(0x0000000000000010)
+#define EFI_MEMORY_WP             UINT64_C(0x0000000000001000)
+#define EFI_MEMORY_RP             UINT64_C(0x0000000000002000)
+#define EFI_MEMORY_XP             UINT64_C(0x0000000000004000)
+#define EFI_MEMORY_NV             UINT64_C(0x0000000000008000)
+#define EFI_MEMORY_MORE_RELIABLE  UINT64_C(0x0000000000010000)
+#define EFI_MEMORY_RO             UINT64_C(0x0000000000020000)
+#define EFI_MEMORY_RUNTIME        UINT64_C(0x8000000000000000)
 
 typedef struct {
@@ -102,7 +109,94 @@
 } efi_v1_memdesc_t;
 
+typedef struct {
+	efi_guid_t guid;
+	void *table;
+} efi_configuration_table_t;
+
+typedef struct efi_simple_text_output_protocol {
+	void *reset;
+	efi_status_t (*output_string)(struct efi_simple_text_output_protocol *,
+	    int16_t *);
+	void *test_string;
+	void *query_mode;
+	void *set_mode;
+	void *set_attribute;
+	void *clear_screen;
+	void *set_cursor_position;
+	void *enable_cursor;
+	void *mode;
+} efi_simple_text_output_protocol_t;
+
+typedef struct {
+	efi_table_header_t hdr;
+	void *raise_TPL;
+	void *restore_TPL;
+	efi_status_t (*allocate_pages)(efi_allocate_type_t, efi_memory_type_t,
+	    sysarg_t, uint64_t *);
+	efi_status_t (*free_pages)(uint64_t, sysarg_t);
+	efi_status_t (*get_memory_map)(sysarg_t *, efi_v1_memdesc_t *,
+	    sysarg_t *, sysarg_t *, uint32_t *);
+	efi_status_t (*allocate_pool)(efi_memory_type_t, sysarg_t, void **);
+	efi_status_t (*free_pool)(void *);
+	void *create_event;
+	void *set_timer;
+	void *wait_for_event;
+	void *signal_event;
+	void *close_event;
+	void *check_event;
+	void *install_protocol_interface;
+	void *reinstall_protocol_interface;
+	void *uninstall_protocol_interface;
+	void *handle_protocol;
+	void *reserved;
+	void *register_protocol_notify;
+	void *locate_handle;
+	void *locate_device_path;
+	void *install_configuration_table;
+	void *load_image;
+	void *start_image;
+	void *exit;
+	void *unload_image;
+	efi_status_t (*exit_boot_services)(void *, sysarg_t);
+	void *get_next_monotonic_count;
+	void *stall;
+	void *set_watchdog_timer;
+	void *connect_controller;
+	void *disconnect_controller;
+	void *open_protocol;
+	void *close_protocol;
+	void *open_protocol_information;
+	void *protocols_per_handle;
+	void *locate_handle_buffer;
+	void *locate_protocol;
+	void *install_multiple_protocol_interfaces;
+	void *uninstall_multiple_protocol_intefaces;
+	void *calculate_crc32;
+	void *copy_mem;
+	void *set_mem;
+	void *create_event_ex;
+} efi_boot_services_t;
+
+typedef struct {
+	efi_table_header_t hdr;
+	char *fw_vendor;
+	uint32_t fw_revision;
+	void *cons_in_handle;
+	void *cons_in;
+	void *cons_out_handle;
+	efi_simple_text_output_protocol_t *cons_out;
+	void *cons_err_handle;
+	efi_simple_text_output_protocol_t *cons_err;
+	void *runtime_services;
+	efi_boot_services_t *boot_services;
+	sysarg_t conf_table_entries;
+	efi_configuration_table_t *conf_table;
+} efi_system_table_t;
+
 #define EFI_PAGE_SIZE	4096
 
 extern void *efi_vendor_table_find(efi_system_table_t *, efi_guid_t);
+extern efi_status_t efi_get_memory_map(efi_system_table_t *, sysarg_t *,
+    efi_v1_memdesc_t **, sysarg_t *, sysarg_t *, uint32_t *);
 
 #endif
Index: boot/genarch/src/efi.c
===================================================================
--- boot/genarch/src/efi.c	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/genarch/src/efi.c	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -42,2 +42,30 @@
 	return NULL;
 }
+
+efi_status_t efi_get_memory_map(efi_system_table_t *st,
+    sysarg_t *memory_map_size, efi_v1_memdesc_t **memory_map, sysarg_t *map_key,
+    sysarg_t *descriptor_size, uint32_t *descriptor_version)
+{
+	efi_status_t status;
+
+	*memory_map_size = 8 * sizeof(**memory_map);
+
+	do {
+		/* Allocate space for the memory map. */
+		status = st->boot_services->allocate_pool(EFI_LOADER_DATA,
+		    *memory_map_size, (void **) memory_map);
+		if (status != EFI_SUCCESS)
+			return status;
+
+		/* Try to obtain the map. */
+		status = st->boot_services->get_memory_map(memory_map_size,
+		    *memory_map, map_key, descriptor_size, descriptor_version);
+		if (status == EFI_SUCCESS)
+			return status;
+
+		/* An error occurred, release the allocated memory. */
+		st->boot_services->free_pool(*memory_map);
+	} while (status == EFI_BUFFER_TOO_SMALL);
+
+	return status;
+}
Index: boot/generic/include/align.h
===================================================================
--- boot/generic/include/align.h	(revision b1478ff612ef2495ebdd19ef6fb0fdb79a3c794e)
+++ boot/generic/include/align.h	(revision 84176f3d26c423111021bb2b97b70bf0076fb9f4)
@@ -49,4 +49,11 @@
 #define ALIGN_UP(s, a)  (((s) + ((a) - 1)) & ~((a) - 1))
 
+/** Check alignment.
+ *
+ * @param s Address or size to be checked for alignment.
+ * @param a Size of alignment, must be a power of 2.
+ */
+#define IS_ALIGNED(s, a)  (ALIGN_UP((s), (a)) == (s))
+
 #endif
 
