Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/Makefile	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -134,5 +134,5 @@
 
 clean_dist:
-	rm -f $(INITRD).img $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE) $(COMPS).o $(COMPS)_desc.o $(COMPS).zip $(LINK)
+	rm -f $(INITRD).img $(COMPS).o $(COMPS).tar $(LINK)
 	find $(USPACE_PATH)/dist -mindepth 1 -maxdepth 1 -type f -exec rm \{\} \;
 	rm -f $(USPACE_PATH)/dist/app/*
Index: boot/Makefile.build
===================================================================
--- boot/Makefile.build	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/Makefile.build	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -98,18 +98,15 @@
 depend: $(PRE_DEPEND)
 
-$(COMPS).s: $(COMPS).zip
-	unzip -p $< $@ > $@
+%.gz: %
+	gzip -n -k -f $<
 
-$(COMPS).h: $(COMPS).zip
-	unzip -p $< $@ > $@
+$(COMPS).tar: $(addsuffix .gz, $(COMPONENTS))
+	tar --mtime='2032-01-01 00:00:00' --group=0 --owner=0 --no-acls --no-selinux --no-xattrs --format=ustar --transform 's/.*\///g' -cvf $@ $^
 
-$(COMPS)_desc.c: $(COMPS).zip
-	unzip -p $< $@ > $@
-
-$(COMPONENTS_DEFLATE): $(COMPS).zip
-	unzip -p $< $@ > $@
-
-$(COMPS).zip: $(COMPONENTS)
-	$(MKARRAY) --deflate $(COMPS) $(COMP) "$(AS_PROLOG)" ".section .components, \"a\"" $^
+$(COMPS).o: $(COMPS).tar
+	# Create empty object file.
+	$(CC) -x c -c -o $@.new $(DEFS) $(CFLAGS) - </dev/null
+	# Add .payload section to it.
+	$(OBJCOPY) --add-section '.payload'=$< $@.new $@
 
 include Makefile.initrd
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/Makefile.common	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -260,5 +260,4 @@
 	$(INITRD).img
 
-COMPONENTS_DEFLATE := $(addsuffix .deflate,$(notdir $(COMPONENTS)))
 
 LINK = arch/$(BARCH)/_link.ld
Index: boot/arch/arm32/Makefile.inc
===================================================================
--- boot/arch/arm32/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/arm32/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -96,6 +96,5 @@
 	arch/$(BARCH)/src/mm.c \
 	arch/$(BARCH)/src/putchar.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	genarch/src/division.c \
 	generic/src/memstr.c \
@@ -105,5 +104,6 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
+	generic/src/inflate.c \
+	generic/src/gzip.c \
+	generic/src/tar.c \
+	generic/src/payload.c
Index: boot/arch/arm32/_link.ld.in
===================================================================
--- boot/arch/arm32/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/arm32/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -6,4 +6,5 @@
 	. = BOOT_BASE;
 	.text : {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(.text);
@@ -11,5 +12,4 @@
 	. = BOOT_BASE + 0x8000;
 	.data : {
-		bdata_start = .;
 		*(BOOTPT);      /* bootstrap page table */
 		*(BOOTSTACK);   /* bootstrap stack */
@@ -23,7 +23,9 @@
 		*(.bss);        /* uninitialized static variables */
 		*(COMMON);      /* global variables */
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
-	bdata_end = .;
 
 	/DISCARD/ : {
Index: boot/arch/arm32/include/arch/types.h
===================================================================
--- boot/arch/arm32/include/arch/types.h	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/arm32/include/arch/types.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -54,4 +54,8 @@
 	size_t cnt;
 	task_t tasks[TASKMAP_MAX_RECORDS];
+} taskmap_t;
+
+typedef struct {
+	taskmap_t taskmap;
 } bootinfo_t;
 
Index: boot/arch/arm32/src/main.c
===================================================================
--- boot/arch/arm32/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/arm32/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -49,12 +49,7 @@
 #include <inflate.h>
 #include <arch/cp15.h>
-#include "../../components.h"
+#include <payload.h>
 
-#define TOP2ADDR(top)  (((void *) PA2KA(BOOT_OFFSET)) + (top))
-
-extern void *bdata_start;
-extern void *bdata_end;
-
-static inline void clean_dcache_poc(void *address, size_t size)
+static void clean_dcache_poc(void *address, size_t size)
 {
 	const uintptr_t addr = (uintptr_t) address;
@@ -91,5 +86,5 @@
 	version_print();
 
-	printf("Boot data: %p -> %p\n", &bdata_start, &bdata_end);
+	printf("Boot loader: %p -> %p\n", loader_start, loader_end);
 	printf("\nMemory statistics\n");
 	printf(" %p|%p: bootstrap stack\n", &boot_stack, &boot_stack);
@@ -99,55 +94,10 @@
 	    (void *) PA2KA(BOOT_OFFSET), (void *) BOOT_OFFSET);
 
-	for (size_t i = 0; i < COMPONENTS; i++) {
-		printf(" %p|%p: %s image (%u/%u bytes)\n", components[i].addr,
-		    components[i].addr, components[i].name, components[i].inflated,
-		    components[i].size);
-	}
+	// FIXME: Use the correct value.
+	uint8_t *kernel_dest = (uint8_t *) BOOT_OFFSET;
+	uint8_t *ram_end = kernel_dest + (1 << 24);
 
-	void *dest[COMPONENTS];
-	size_t top = 0;
-	size_t cnt = 0;
-	bootinfo.cnt = 0;
-	for (size_t i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
-
-		if (i > 0) {
-			bootinfo.tasks[bootinfo.cnt].addr = TOP2ADDR(top);
-			bootinfo.tasks[bootinfo.cnt].size = components[i].inflated;
-
-			str_cpy(bootinfo.tasks[bootinfo.cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo.cnt++;
-		}
-
-		dest[i] = TOP2ADDR(top);
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	printf("\nInflating components ... ");
-
-	for (size_t i = cnt; i > 0; i--) {
-		void *tail = components[i - 1].addr + components[i - 1].size;
-		if (tail >= dest[i - 1]) {
-			printf("\n%s: Image too large to fit (%p >= %p), halting.\n",
-			    components[i].name, tail, dest[i - 1]);
-			halt();
-		}
-
-		printf("%s ", components[i - 1].name);
-
-		int err = inflate(components[i - 1].addr, components[i - 1].size,
-		    dest[i - 1], components[i - 1].inflated);
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d\n", components[i - 1].name, err);
-			halt();
-		}
-		/* Make sure data are in the memory, ICache will need them */
-		clean_dcache_poc(dest[i - 1], components[i - 1].inflated);
-	}
-
-	printf(".\n");
+	extract_payload(&bootinfo.taskmap, kernel_dest, ram_end,
+	    PA2KA(kernel_dest), clean_dcache_poc);
 
 	/* Flush PT too. We need this if we disable caches later */
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ia64/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -48,6 +48,5 @@
 	arch/$(BARCH)/src/pal_asm.S \
 	arch/$(BARCH)/src/putchar.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	genarch/src/efi.c \
 	genarch/src/division.c \
@@ -59,5 +58,8 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
+	generic/src/inflate.c \
+	generic/src/tar.c \
+	generic/src/gzip.c \
+	generic/src/payload.c
 
 ifeq ($(MACHINE),ski)
@@ -97,4 +99,2 @@
 	platform/ski
 endif
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
Index: boot/arch/ia64/_link.ld.in
===================================================================
--- boot/arch/ia64/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ia64/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -4,4 +4,5 @@
 SECTIONS {
 	.boot 0x4400000: AT (0x4400000) {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(.text);
@@ -16,5 +17,8 @@
 		*(.bss);                /* uninitialized static variables */
 		*(COMMON);
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
 
Index: boot/arch/ia64/include/arch/types.h
===================================================================
--- boot/arch/ia64/include/arch/types.h	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ia64/include/arch/types.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -40,10 +40,10 @@
 	size_t size;
 	char name[BOOTINFO_TASK_NAME_BUFLEN];
-} binit_task_t;
+} task_t;
 
 typedef struct {
 	size_t cnt;
-	binit_task_t tasks[TASKMAP_MAX_RECORDS];
-} binit_t;
+	task_t tasks[TASKMAP_MAX_RECORDS];
+} taskmap_t;
 
 typedef struct {
@@ -54,5 +54,5 @@
 
 typedef struct {
-	binit_t taskmap;
+	taskmap_t taskmap;
 
 	memmap_item_t memmap[MEMMAP_ITEMS];
Index: boot/arch/ia64/src/main.c
===================================================================
--- boot/arch/ia64/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ia64/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -43,6 +43,5 @@
 #include <str.h>
 #include <errno.h>
-#include <inflate.h>
-#include "../../components.h"
+#include <payload.h>
 
 #define DEFAULT_MEMORY_BASE		0x4000000ULL
@@ -150,4 +149,5 @@
 	version_print();
 
+	printf("Boot loader: %p -> %p\n", loader_start, loader_end);
 	printf(" %p|%p: boot info structure\n", &bootinfo, &bootinfo);
 	printf(" %p|%p: kernel entry point\n",
@@ -156,67 +156,30 @@
 	    (void *) LOADER_ADDRESS, (void *) LOADER_ADDRESS);
 
-	size_t i;
-	for (i = 0; i < COMPONENTS; i++)
-		printf(" %p|%p: %s image (%zu/%zu bytes)\n", components[i].addr,
-		    components[i].addr, components[i].name,
-		    components[i].inflated, components[i].size);
-
-	void *dest[COMPONENTS];
-	size_t top = KERNEL_ADDRESS;
-	size_t cnt = 0;
-	bootinfo.taskmap.cnt = 0;
-	for (i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
-
-		if (i > 0) {
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].addr =
-			    (void *) top;
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].size =
-			    components[i].inflated;
-
-			str_cpy(bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo.taskmap.cnt++;
-		}
-
-		dest[i] = (void *) top;
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	printf("\nInflating components ... ");
-
-	/*
-	 * We will use the next available address for a copy of each component to
-	 * make sure that inflate() works with disjunctive memory regions.
-	 */
-	top = ALIGN_UP(top, PAGE_SIZE);
-
-	for (i = cnt; i > 0; i--) {
-		printf("%s ", components[i - 1].name);
-
-		/*
-		 * Copy the component to a location which is guaranteed not to
-		 * overlap with the destination for inflate().
-		 */
-		memmove((void *) top, components[i - 1].addr, components[i - 1].size);
-
-		int err = inflate((void *) top, components[i - 1].size,
-		    dest[i - 1], components[i - 1].inflated);
-
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d, halting.\n",
-			    components[i - 1].name, err);
-			halt();
-		}
-	}
-
-	printf(".\n");
-
 	read_efi_memmap();
 	read_sal_configuration();
 	read_pal_configuration();
 
+	uint8_t *kernel_start = (uint8_t *) KERNEL_ADDRESS;
+	uint8_t *ram_end = NULL;
+
+	/* Find the end of the memory area occupied by the kernel. */
+	for (unsigned i = 0; i < bootinfo.memmap_items; i++) {
+		memmap_item_t m = bootinfo.memmap[i];
+		if (m.type == MEMMAP_FREE_MEM &&
+		    m.base <= (uintptr_t) kernel_start &&
+		    m.base + m.size > (uintptr_t) kernel_start) {
+			ram_end = (uint8_t *) (m.base + m.size);
+		}
+	}
+
+	if (ram_end == NULL) {
+		printf("Memory map doesn't contain usable area at kernel's address.\n");
+		halt();
+	}
+
+	// FIXME: Correct kernel's logical address.
+	extract_payload(&bootinfo.taskmap, kernel_start, ram_end,
+	    (uintptr_t) kernel_start, NULL);
+
 	printf("Booting the kernel ...\n");
 	jump_to_kernel(&bootinfo);
Index: boot/arch/mips32/Makefile.inc
===================================================================
--- boot/arch/mips32/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/mips32/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -76,6 +76,5 @@
 	arch/$(BARCH)/src/main.c \
 	arch/$(BARCH)/src/putchar.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	genarch/src/division.c \
 	genarch/src/multiplication.c \
@@ -86,5 +85,6 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
+	generic/src/inflate.c \
+	generic/src/gzip.c \
+	generic/src/tar.c \
+	generic/src/payload.c
Index: boot/arch/mips32/_link.ld.in
===================================================================
--- boot/arch/mips32/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/mips32/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -8,4 +8,5 @@
 #endif
 	.text : {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(.text);
@@ -21,5 +22,8 @@
 		*(.bss);        /* uninitialized static variables */
 		*(COMMON);      /* global variables */
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
 
Index: boot/arch/mips32/include/arch/types.h
===================================================================
--- boot/arch/mips32/include/arch/types.h	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/mips32/include/arch/types.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -46,10 +46,14 @@
 
 typedef struct {
+	size_t cnt;
+	task_t tasks[TASKMAP_MAX_RECORDS];
+} taskmap_t;
+
+typedef struct {
 #if defined(MACHINE_lmalta) || defined(MACHINE_bmalta)
 	uint32_t sdram_size;
 #endif
 	uint32_t cpumap;
-	size_t cnt;
-	task_t tasks[TASKMAP_MAX_RECORDS];
+	taskmap_t taskmap;
 } bootinfo_t;
 
Index: boot/arch/mips32/src/asm.S
===================================================================
--- boot/arch/mips32/src/asm.S	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/mips32/src/asm.S	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -147,10 +147,4 @@
 
 FUNCTION_BEGIN(jump_to_kernel)
-	/*
-	 * TODO:
-	 *
-	 * Make sure that the I-cache, D-cache and memory are mutually
-	 * coherent before passing control to the copied code.
-	 */
 	j $a0
 	nop
Index: boot/arch/mips32/src/main.c
===================================================================
--- boot/arch/mips32/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/mips32/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -39,8 +39,5 @@
 #include <str.h>
 #include <errno.h>
-#include <inflate.h>
-#include "../../components.h"
-
-#define TOP2ADDR(top)  (((void *) PA2KA(BOOT_OFFSET)) + (top))
+#include <payload.h>
 
 static bootinfo_t *bootinfo = (bootinfo_t *) PA2KA(BOOTINFO_OFFSET);
@@ -63,65 +60,18 @@
 	    (void *) PA2KA(LOADER_OFFSET), (void *) LOADER_OFFSET);
 
-	size_t i;
-	for (i = 0; i < COMPONENTS; i++)
-		printf(" %p|%p: %s image (%zu/%zu bytes)\n", components[i].addr,
-		    (uintptr_t) components[i].addr >= PA2KSEG(0) ?
-		    (void *) KSEG2PA(components[i].addr) :
-		    (void *) KA2PA(components[i].addr),
-		    components[i].name, components[i].inflated,
-		    components[i].size);
+	uint8_t *kernel_start = (uint8_t *) PA2KA(BOOT_OFFSET);
+	// FIXME: Use the correct value.
+	uint8_t *ram_end = kernel_start + (1 << 24);
 
-	void *dest[COMPONENTS];
-	size_t top = 0;
-	size_t cnt = 0;
-	bootinfo->cnt = 0;
-	for (i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
+	// TODO: Make sure that the I-cache, D-cache and memory are coherent.
+	//       (i.e. provide the clear_cache callback)
 
-		if (i > 0) {
-			bootinfo->tasks[bootinfo->cnt].addr = TOP2ADDR(top);
-			bootinfo->tasks[bootinfo->cnt].size = components[i].inflated;
-
-			str_cpy(bootinfo->tasks[bootinfo->cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo->cnt++;
-		}
-
-		dest[i] = TOP2ADDR(top);
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	printf("\nInflating components ... ");
-
-	for (i = cnt; i > 0; i--) {
-#ifdef MACHINE_msim
-		void *tail = dest[i - 1] + components[i].inflated;
-		if (tail >= ((void *) PA2KA(LOADER_OFFSET))) {
-			printf("\n%s: Image too large to fit (%p >= %p), halting.\n",
-			    components[i].name, tail, (void *) PA2KA(LOADER_OFFSET));
-			halt();
-		}
-#endif
-
-		printf("%s ", components[i - 1].name);
-
-		int err = inflate(components[i - 1].addr, components[i - 1].size,
-		    dest[i - 1], components[i - 1].inflated);
-
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d, halting.\n",
-			    components[i - 1].name, err);
-			halt();
-		}
-	}
-
-	printf(".\n");
+	extract_payload(&bootinfo->taskmap, kernel_start, ram_end,
+	    (uintptr_t) kernel_start, NULL);
 
 	printf("Copying CPU map ... \n");
 
 	bootinfo->cpumap = 0;
-	for (i = 0; i < CPUMAP_MAX_RECORDS; i++) {
+	for (int i = 0; i < CPUMAP_MAX_RECORDS; i++) {
 		if (cpumap[i] != 0)
 			bootinfo->cpumap |= (1 << i);
Index: boot/arch/ppc32/Makefile.inc
===================================================================
--- boot/arch/ppc32/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ppc32/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -61,6 +61,5 @@
 	arch/$(BARCH)/src/main.c \
 	arch/$(BARCH)/src/ofw.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	genarch/src/ofw.c \
 	genarch/src/ofw_tree.c \
@@ -74,5 +73,6 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
+	generic/src/inflate.c \
+	generic/src/gzip.c \
+	generic/src/tar.c \
+	generic/src/payload.c
Index: boot/arch/ppc32/_link.ld.in
===================================================================
--- boot/arch/ppc32/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ppc32/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -4,4 +4,5 @@
 	. = 0x08000000;
 	.text : {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(REALMODE);
@@ -18,5 +19,8 @@
 		*(.bss);        /* uninitialized static variables */
 		*(COMMON);      /* global variables */
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
 
Index: boot/arch/ppc32/src/main.c
===================================================================
--- boot/arch/ppc32/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/ppc32/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -41,6 +41,5 @@
 #include <str.h>
 #include <errno.h>
-#include <inflate.h>
-#include "../../components.h"
+#include <payload.h>
 
 #define BALLOC_MAX_SIZE  131072
@@ -74,35 +73,8 @@
 	    (void *) LOADER_ADDRESS, loader_address_pa);
 
-	size_t i;
-	for (i = 0; i < COMPONENTS; i++)
-		printf(" %p|%p: %s image (%zu/%zu bytes)\n", components[i].addr,
-		    ofw_translate(components[i].addr), components[i].name,
-		    components[i].inflated, components[i].size);
+	size_t uncompressed_size = payload_uncompressed_size();
+	printf("Payload uncompressed size: %d bytes\n", uncompressed_size);
 
-	size_t dest[COMPONENTS];
-	size_t top = 0;
-	size_t cnt = 0;
-	bootinfo.taskmap.cnt = 0;
-	for (i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
-
-		if (i > 0) {
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].addr =
-			    (void *) PA2KA(top);
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].size =
-			    components[i].inflated;
-
-			str_cpy(bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo.taskmap.cnt++;
-		}
-
-		dest[i] = top;
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	if (top >= (size_t) loader_address_pa) {
+	if (uncompressed_size >= (size_t) loader_address_pa) {
 		printf("Inflated components overlap loader area.\n");
 		printf("The boot image is too large. Halting.\n");
@@ -118,9 +90,9 @@
 	void *inflate_base;
 	void *inflate_base_pa;
-	ofw_alloc("inflate area", &inflate_base, &inflate_base_pa, top,
-	    loader_address_pa);
+	ofw_alloc("inflate area", &inflate_base, &inflate_base_pa,
+	    uncompressed_size, loader_address_pa);
 	printf(" %p|%p: inflate area\n", inflate_base, inflate_base_pa);
 
-	uintptr_t balloc_start = ALIGN_UP(top, PAGE_SIZE);
+	uintptr_t balloc_start = ALIGN_UP(uncompressed_size, PAGE_SIZE);
 	size_t pages = (balloc_start + ALIGN_UP(BALLOC_MAX_SIZE, PAGE_SIZE)) >>
 	    PAGE_WIDTH;
@@ -135,20 +107,7 @@
 	check_overlap("translate table", transtable_pa, pages);
 
-	printf("\nInflating components ... ");
-
-	for (i = cnt; i > 0; i--) {
-		printf("%s ", components[i - 1].name);
-
-		int err = inflate(components[i - 1].addr, components[i - 1].size,
-		    inflate_base + dest[i - 1], components[i - 1].inflated);
-
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d, halting.\n",
-			    components[i - 1].name, err);
-			halt();
-		}
-	}
-
-	printf(".\n");
+	/* Inflate components. */
+	extract_payload(&bootinfo.taskmap, inflate_base,
+	    inflate_base + uncompressed_size, PA2KA(0), NULL);
 
 	printf("Setting up boot allocator ...\n");
@@ -163,5 +122,5 @@
 
 	printf("Setting up translate table ...\n");
-	for (i = 0; i < pages; i++) {
+	for (size_t i = 0; i < pages; i++) {
 		uintptr_t off = i << PAGE_WIDTH;
 		void *phys;
Index: boot/arch/riscv64/Makefile.inc
===================================================================
--- boot/arch/riscv64/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/riscv64/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -41,6 +41,5 @@
 	arch/$(BARCH)/src/ucb.c \
 	arch/$(BARCH)/src/putchar.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	generic/src/memstr.c \
 	generic/src/printf_core.c \
@@ -49,5 +48,6 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
+	generic/src/inflate.c \
+	generic/src/gzip.c \
+	generic/src/tar.c \
+	generic/src/payload.c
Index: boot/arch/riscv64/_link.ld.in
===================================================================
--- boot/arch/riscv64/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/riscv64/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -7,4 +7,5 @@
 
 	.text : {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(.text);
@@ -35,5 +36,8 @@
 		*(.bss);        /* uninitialized static variables */
 		*(COMMON);      /* global variables */
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
 
Index: boot/arch/riscv64/src/main.c
===================================================================
--- boot/arch/riscv64/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/riscv64/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -41,6 +41,5 @@
 #include <str.h>
 #include <halt.h>
-#include <inflate.h>
-#include "../../components.h"
+#include <payload.h>
 
 static bootinfo_t bootinfo;
@@ -69,72 +68,23 @@
 	printf(" %p: boot info structure\n", &bootinfo);
 
-	uintptr_t top = BOOT_OFFSET;
+	uint8_t *load_addr = (uint8_t *) BOOT_OFFSET;
+	uintptr_t kernel_addr = PA2KA(load_addr);
 
-	for (size_t i = 0; i < COMPONENTS; i++) {
-		printf(" %p: %s image (%zu/%zu bytes)\n", components[i].addr,
-		    components[i].name, components[i].inflated,
-		    components[i].size);
+	printf(" %p: inflate area\n", load_addr);
+	printf(" %p: kernel entry point\n", (void *) kernel_addr);
 
-		uintptr_t tail = (uintptr_t) components[i].addr +
-		    components[i].size;
-		if (tail > top) {
-			printf("\n%s: Image too large to fit (%p >= %p), halting.\n",
-			    components[i].name, (void *) tail, (void *) top);
-			halt();
+	/* Find the end of the memory zone containing the load address. */
+	uint8_t *end = NULL;
+	for (size_t i = 0; i < bootinfo.memmap.cnt; i++) {
+		memzone_t z = bootinfo.memmap.zones[i];
+
+		if (z.start <= (void *) load_addr &&
+		    z.start + z.size > (void *) load_addr) {
+			end = z.start + z.size;
 		}
 	}
 
-	printf(" %p: inflate area\n", (void *) top);
-
-	void *kernel_entry = NULL;
-	void *dest[COMPONENTS];
-	size_t cnt = 0;
-	bootinfo.taskmap.cnt = 0;
-
-	for (size_t i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
-
-		if (i > 0) {
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].addr =
-			    (void *) PA2KA(top);
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].size =
-			    components[i].inflated;
-
-			str_cpy(bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo.taskmap.cnt++;
-		} else
-			kernel_entry = (void *) PA2KA(top);
-
-		dest[i] = (void *) top;
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	printf(" %p: kernel entry point\n", kernel_entry);
-
-	if (top >= bootinfo.physmem_start + bootinfo.memmap.total) {
-		printf("Not enough physical memory available.\n");
-		printf("The boot image is too large. Halting.\n");
-		halt();
-	}
-
-	printf("\nInflating components ... ");
-
-	for (size_t i = cnt; i > 0; i--) {
-		printf("%s ", components[i - 1].name);
-
-		int err = inflate(components[i - 1].addr, components[i - 1].size,
-		    dest[i - 1], components[i - 1].inflated);
-
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d, halting.\n",
-			    components[i - 1].name, err);
-			halt();
-		}
-	}
-
-	printf(".\n");
+	// TODO: Cache-coherence callback?
+	extract_payload(&bootinfo.taskmap, load_addr, end, kernel_addr, NULL);
 
 	printf("Booting the kernel...\n");
Index: boot/arch/sparc64/Makefile.inc
===================================================================
--- boot/arch/sparc64/Makefile.inc	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/sparc64/Makefile.inc	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -59,6 +59,5 @@
 	arch/$(BARCH)/src/main.c \
 	arch/$(BARCH)/src/ofw.c \
-	$(COMPS).s \
-	$(COMPS)_desc.c \
+	$(COMPS).o \
 	genarch/src/ofw.c \
 	genarch/src/ofw_tree.c \
@@ -70,5 +69,6 @@
 	generic/src/str.c \
 	generic/src/version.c \
-	generic/src/inflate.c
-
-PRE_DEPEND = $(COMPS).s $(COMPS).h $(COMPS)_desc.c $(COMPONENTS_DEFLATE)
+	generic/src/inflate.c \
+	generic/src/gzip.c \
+	generic/src/tar.c \
+	generic/src/payload.c
Index: boot/arch/sparc64/_link.ld.in
===================================================================
--- boot/arch/sparc64/_link.ld.in	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/sparc64/_link.ld.in	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -4,4 +4,5 @@
 	. = 0x4000;
 	.boot : {
+		loader_start = .;
 		*(BOOTSTRAP);
 		*(.text);
@@ -15,5 +16,8 @@
 		*(.bss);        /* uninitialized static variables */
 		*(COMMON);      /* global variables */
-		*(.components);
+		loader_end = .;
+		payload_start = .;
+		*(.payload);
+		payload_end = .;
 	}
 
Index: boot/arch/sparc64/src/main.c
===================================================================
--- boot/arch/sparc64/src/main.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/arch/sparc64/src/main.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -42,6 +42,5 @@
 #include <str.h>
 #include <errno.h>
-#include <inflate.h>
-#include "../../components.h"
+#include <payload.h>
 
 /* The lowest ID (read from the VER register) of some US3 CPU model */
@@ -217,64 +216,23 @@
 	    (void *) LOADER_ADDRESS, (void *) loader_address_pa);
 
-	size_t i;
-	for (i = 0; i < COMPONENTS; i++)
-		printf(" %p|%p: %s image (%zu/%zu bytes)\n", components[i].addr,
-		    ofw_translate(components[i].addr), components[i].name,
-		    components[i].inflated, components[i].size);
-
-	void *dest[COMPONENTS];
-	size_t top = KERNEL_ADDRESS;
-	size_t cnt = 0;
-	bootinfo.taskmap.cnt = 0;
-	for (i = 0; i < min(COMPONENTS, TASKMAP_MAX_RECORDS); i++) {
-		top = ALIGN_UP(top, PAGE_SIZE);
-
-		if (i > 0) {
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].addr =
-			    (void *) top;
-			bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].size =
-			    components[i].inflated;
-
-			str_cpy(bootinfo.taskmap.tasks[bootinfo.taskmap.cnt].name,
-			    BOOTINFO_TASK_NAME_BUFLEN, components[i].name);
-
-			bootinfo.taskmap.cnt++;
-		}
-
-		dest[i] = (void *) top;
-		top += components[i].inflated;
-		cnt++;
-	}
-
-	printf("\nInflating components ... ");
-
-	for (i = cnt; i > 0; i--) {
-		printf("%s ", components[i - 1].name);
-
-		/*
-		 * At this point, we claim and map the physical memory that we
-		 * are going to use. We should be safe in case of the virtual
-		 * address space because the OpenFirmware, according to its
-		 * SPARC binding, should restrict its use of virtual memory to
-		 * addresses from [0xffd00000; 0xffefffff] and [0xfe000000;
-		 * 0xfeffffff].
-		 */
-		ofw_claim_phys(bootinfo.physmem_start + dest[i - 1],
-		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE));
-
-		ofw_map(bootinfo.physmem_start + dest[i - 1], dest[i - 1],
-		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE), -1);
-
-		int err = inflate(components[i - 1].addr, components[i - 1].size,
-		    dest[i - 1], components[i - 1].inflated);
-
-		if (err != EOK) {
-			printf("\n%s: Inflating error %d, halting.\n",
-			    components[i - 1].name, err);
-			halt();
-		}
-	}
-
-	printf(".\n");
+	/*
+	 * At this point, we claim and map the physical memory that we
+	 * are going to use. We should be safe in case of the virtual
+	 * address space because the OpenFirmware, according to its
+	 * SPARC binding, should restrict its use of virtual memory to
+	 * addresses from [0xffd00000; 0xffefffff] and [0xfe000000;
+	 * 0xfeffffff].
+	 */
+
+	size_t sz = ALIGN_UP(payload_uncompressed_size(), PAGE_SIZE);
+	ofw_claim_phys((void *) (bootinfo.physmem_start + KERNEL_ADDRESS), sz);
+	ofw_map((void *) (bootinfo.physmem_start + KERNEL_ADDRESS),
+	    (void *) KERNEL_ADDRESS, sz, -1);
+
+	/* Extract components. */
+
+	// TODO: Cache-coherence callback?
+	extract_payload(&bootinfo.taskmap, (void *) KERNEL_ADDRESS,
+	    (void *) KERNEL_ADDRESS + sz, KERNEL_ADDRESS, NULL);
 
 	/*
@@ -283,5 +241,5 @@
 	 */
 	printf("Setting up boot allocator ...\n");
-	void *balloc_base = (void *) ALIGN_UP(top, PAGE_SIZE);
+	void *balloc_base = (void *) KERNEL_ADDRESS + sz;
 	ofw_claim_phys(bootinfo.physmem_start + balloc_base, BALLOC_MAX_SIZE);
 	ofw_map(bootinfo.physmem_start + balloc_base, balloc_base,
Index: boot/generic/include/byteorder.h
===================================================================
--- boot/generic/include/byteorder.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/include/byteorder.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2005 Jakub Jermar
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_BYTEORDER_H_
+#define LIBC_BYTEORDER_H_
+
+#include <stdint.h>
+
+#if !(defined(__BE__) ^ defined(__LE__))
+#error The architecture must be either big-endian or little-endian.
+#endif
+
+#ifdef __BE__
+
+#define uint16_t_le2host(n)  (uint16_t_byteorder_swap(n))
+#define uint32_t_le2host(n)  (uint32_t_byteorder_swap(n))
+#define uint64_t_le2host(n)  (uint64_t_byteorder_swap(n))
+
+#define uint16_t_be2host(n)  (n)
+#define uint32_t_be2host(n)  (n)
+#define uint64_t_be2host(n)  (n)
+
+#define host2uint16_t_le(n)  (uint16_t_byteorder_swap(n))
+#define host2uint32_t_le(n)  (uint32_t_byteorder_swap(n))
+#define host2uint64_t_le(n)  (uint64_t_byteorder_swap(n))
+
+#define host2uint16_t_be(n)  (n)
+#define host2uint32_t_be(n)  (n)
+#define host2uint64_t_be(n)  (n)
+
+#else
+
+#define uint16_t_le2host(n)  (n)
+#define uint32_t_le2host(n)  (n)
+#define uint64_t_le2host(n)  (n)
+
+#define uint16_t_be2host(n)  (uint16_t_byteorder_swap(n))
+#define uint32_t_be2host(n)  (uint32_t_byteorder_swap(n))
+#define uint64_t_be2host(n)  (uint64_t_byteorder_swap(n))
+
+#define host2uint16_t_le(n)  (n)
+#define host2uint32_t_le(n)  (n)
+#define host2uint64_t_le(n)  (n)
+
+#define host2uint16_t_be(n)  (uint16_t_byteorder_swap(n))
+#define host2uint32_t_be(n)  (uint32_t_byteorder_swap(n))
+#define host2uint64_t_be(n)  (uint64_t_byteorder_swap(n))
+
+#endif
+
+#define htons(n)  host2uint16_t_be((n))
+#define htonl(n)  host2uint32_t_be((n))
+#define ntohs(n)  uint16_t_be2host((n))
+#define ntohl(n)  uint32_t_be2host((n))
+
+#define uint8_t_be2host(n)  (n)
+#define uint8_t_le2host(n)  (n)
+#define host2uint8_t_be(n)  (n)
+#define host2uint8_t_le(n)  (n)
+#define host2uint8_t_le(n)  (n)
+
+#define  int8_t_le2host(n)  uint8_t_le2host(n)
+#define int16_t_le2host(n) uint16_t_le2host(n)
+#define int32_t_le2host(n) uint32_t_le2host(n)
+#define int64_t_le2host(n) uint64_t_le2host(n)
+
+#define  int8_t_be2host(n)  uint8_t_be2host(n)
+#define int16_t_be2host(n) uint16_t_be2host(n)
+#define int32_t_be2host(n) uint32_t_be2host(n)
+#define int64_t_be2host(n) uint64_t_be2host(n)
+
+#define  host2int8_t_le(n)  host2uint8_t_le(n)
+#define host2int16_t_le(n) host2uint16_t_le(n)
+#define host2int32_t_le(n) host2uint32_t_le(n)
+#define host2int64_t_le(n) host2uint64_t_le(n)
+
+#define  host2int8_t_be(n)  host2uint8_t_be(n)
+#define host2int16_t_be(n) host2uint16_t_be(n)
+#define host2int32_t_be(n) host2uint32_t_be(n)
+#define host2int64_t_be(n) host2uint64_t_be(n)
+
+static inline uint64_t uint64_t_byteorder_swap(uint64_t n)
+{
+	return ((n & 0xff) << 56) |
+	    ((n & 0xff00) << 40) |
+	    ((n & 0xff0000) << 24) |
+	    ((n & 0xff000000LL) << 8) |
+	    ((n & 0xff00000000LL) >> 8) |
+	    ((n & 0xff0000000000LL) >> 24) |
+	    ((n & 0xff000000000000LL) >> 40) |
+	    ((n & 0xff00000000000000LL) >> 56);
+}
+
+static inline uint32_t uint32_t_byteorder_swap(uint32_t n)
+{
+	return ((n & 0xff) << 24) |
+	    ((n & 0xff00) << 8) |
+	    ((n & 0xff0000) >> 8) |
+	    ((n & 0xff000000) >> 24);
+}
+
+static inline uint16_t uint16_t_byteorder_swap(uint16_t n)
+{
+	return ((n & 0xff) << 8) |
+	    ((n & 0xff00) >> 8);
+}
+
+#endif
+
+/** @}
+ */
Index: boot/generic/include/gzip.h
===================================================================
--- boot/generic/include/gzip.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/include/gzip.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Martin Decky
+ * 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.
+ */
+
+#ifndef LIBCOMPRESS_GZIP_H_
+#define LIBCOMPRESS_GZIP_H_
+
+#include <stddef.h>
+size_t gzip_size(const void *, size_t);
+extern int gzip_expand(const void *, size_t, void *, size_t);
+
+#endif
Index: boot/generic/include/inflate.h
===================================================================
--- boot/generic/include/inflate.h	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/generic/include/inflate.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -32,5 +32,5 @@
 #include <stddef.h>
 
-extern int inflate(void *, size_t, void *, size_t);
+extern int inflate(const void *, size_t, void *, size_t);
 
 #endif
Index: boot/generic/include/payload.h
===================================================================
--- boot/generic/include/payload.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/include/payload.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Jiří Zárevúcky
+ * 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.
+ */
+
+#ifndef BOOT_PAYLOAD_H_
+#define BOOT_PAYLOAD_H_
+
+#include <arch/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+extern uint8_t payload_start[];
+extern uint8_t payload_end[];
+
+extern uint8_t loader_start[];
+extern uint8_t loader_end[];
+
+size_t payload_uncompressed_size(void);
+void extract_payload(taskmap_t *, uint8_t *, uint8_t *, uintptr_t,
+    void (*)(void *, size_t));
+
+#endif
Index: boot/generic/include/tar.h
===================================================================
--- boot/generic/include/tar.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/include/tar.h	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * 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 libuntar
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TAR_H_
+#define TAR_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define TAR_BLOCK_SIZE 512
+
+typedef struct tar_header_raw {
+	char filename[100];
+	char permissions[8];
+	char owner[8];
+	char group[8];
+	char size[12];
+	char modification_time[12];
+	char checksum[8];
+	char type;
+	char name[100];
+	char ustar_magic[6];
+	char ustar_version[2];
+	char ustar_owner_name[32];
+	char ustar_group_name[32];
+	char ustar_device_major[8];
+	char ustar_device_minor[8];
+	char ustar_prefix[155];
+	char ignored[12];
+} tar_header_raw_t;
+
+_Static_assert(sizeof(tar_header_raw_t) == TAR_BLOCK_SIZE, "Wrong size for tar header.");
+
+enum {
+	TAR_TYPE_NORMAL = '0',
+	TAR_TYPE_DIRECTORY = '5',
+};
+
+typedef struct {
+	const uint8_t *ptr;
+	size_t length;
+	size_t next;
+} tar_t;
+
+bool tar_info(const uint8_t *, const uint8_t *, const char **, size_t *);
+
+#endif
+
+/** @}
+ */
Index: boot/generic/src/gzip.c
===================================================================
--- boot/generic/src/gzip.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/src/gzip.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2014 Martin Decky
+ * 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.
+ */
+
+// XXX: This file is a duplicate of the same in uspace/lib/compress
+
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <memstr.h>
+#include <byteorder.h>
+#include <gzip.h>
+#include <inflate.h>
+
+#define GZIP_ID1  UINT8_C(0x1f)
+#define GZIP_ID2  UINT8_C(0x8b)
+
+#define GZIP_METHOD_DEFLATE  UINT8_C(0x08)
+
+#define GZIP_FLAGS_MASK     UINT8_C(0x1f)
+#define GZIP_FLAG_FHCRC     UINT8_C(1 << 1)
+#define GZIP_FLAG_FEXTRA    UINT8_C(1 << 2)
+#define GZIP_FLAG_FNAME     UINT8_C(1 << 3)
+#define GZIP_FLAG_FCOMMENT  UINT8_C(1 << 4)
+
+typedef struct {
+	uint8_t id1;
+	uint8_t id2;
+	uint8_t method;
+	uint8_t flags;
+	uint32_t mtime;
+	uint8_t extra_flags;
+	uint8_t os;
+} __attribute__((packed)) gzip_header_t;
+
+typedef struct {
+	uint32_t crc32;
+	uint32_t size;
+} __attribute__((packed)) gzip_footer_t;
+
+size_t gzip_size(const void *src, size_t srclen)
+{
+	gzip_header_t header;
+	gzip_footer_t footer;
+
+	if ((srclen < sizeof(header)) || (srclen < sizeof(footer)))
+		return 0;
+
+	memcpy(&header, src, sizeof(header));
+	memcpy(&footer, src + srclen - sizeof(footer), sizeof(footer));
+
+	if ((header.id1 != GZIP_ID1) ||
+	    (header.id2 != GZIP_ID2) ||
+	    (header.method != GZIP_METHOD_DEFLATE) ||
+	    ((header.flags & (~GZIP_FLAGS_MASK)) != 0))
+		return 0;
+
+	return uint32_t_le2host(footer.size);
+}
+
+/** Expand GZIP compressed data
+ *
+ * The routine allocates the output buffer based
+ * on the size encoded in the input stream. This
+ * effectively limits the size of the uncompressed
+ * data to 4 GiB (expanding input streams that actually
+ * encode more data will always fail).
+ *
+ * So far, no CRC is perfomed.
+ *
+ * @param[in]  src     Source data buffer.
+ * @param[in]  srclen  Source buffer size (bytes).
+ * @param[out] dest    Destination data buffer.
+ * @param[out] destlen Destination buffer size (bytes).
+ *
+ * @return EOK on success.
+ * @return ENOENT on distance too large.
+ * @return EINVAL on invalid Huffman code, invalid deflate data,
+ *                   invalid compression method or invalid stream.
+ * @return ELIMIT on input buffer overrun.
+ * @return ENOMEM on output buffer overrun.
+ *
+ */
+int gzip_expand(const void *src, size_t srclen, void *dest, size_t destlen)
+{
+	gzip_header_t header;
+	gzip_footer_t footer;
+
+	if ((srclen < sizeof(header)) || (srclen < sizeof(footer)))
+		return EINVAL;
+
+	/* Decode header and footer */
+
+	memcpy(&header, src, sizeof(header));
+	memcpy(&footer, src + srclen - sizeof(footer), sizeof(footer));
+
+	if ((header.id1 != GZIP_ID1) ||
+	    (header.id2 != GZIP_ID2) ||
+	    (header.method != GZIP_METHOD_DEFLATE) ||
+	    ((header.flags & (~GZIP_FLAGS_MASK)) != 0))
+		return EINVAL;
+
+	if (destlen != uint32_t_le2host(footer.size))
+		return EINVAL;
+
+	/* Ignore extra metadata */
+
+	const void *stream = src + sizeof(header);
+	size_t stream_length = srclen - sizeof(header) - sizeof(footer);
+
+	if ((header.flags & GZIP_FLAG_FEXTRA) != 0) {
+		uint16_t extra_length;
+
+		if (stream_length < sizeof(extra_length))
+			return EINVAL;
+
+		memcpy(&extra_length, stream, sizeof(extra_length));
+		stream += sizeof(extra_length);
+		stream_length -= sizeof(extra_length);
+
+		if (stream_length < extra_length)
+			return EINVAL;
+
+		stream += extra_length;
+		stream_length -= extra_length;
+	}
+
+	if ((header.flags & GZIP_FLAG_FNAME) != 0) {
+		while (*((uint8_t *) stream) != 0) {
+			if (stream_length == 0)
+				return EINVAL;
+
+			stream++;
+			stream_length--;
+		}
+
+		if (stream_length == 0)
+			return EINVAL;
+
+		stream++;
+		stream_length--;
+	}
+
+	if ((header.flags & GZIP_FLAG_FCOMMENT) != 0) {
+		while (*((uint8_t *) stream) != 0) {
+			if (stream_length == 0)
+				return EINVAL;
+
+			stream++;
+			stream_length--;
+		}
+
+		if (stream_length == 0)
+			return EINVAL;
+
+		stream++;
+		stream_length--;
+	}
+
+	if ((header.flags & GZIP_FLAG_FHCRC) != 0) {
+		if (stream_length < 2)
+			return EINVAL;
+
+		stream += 2;
+		stream_length -= 2;
+	}
+
+	/* Inflate the data */
+	return inflate(stream, stream_length, dest, destlen);
+}
Index: boot/generic/src/inflate.c
===================================================================
--- boot/generic/src/inflate.c	(revision df8eababb31187582db57d47cd83f7ecfb4f1ee9)
+++ boot/generic/src/inflate.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -104,5 +104,5 @@
 	size_t destcnt;   /**< Position in the output buffer */
 
-	uint8_t *src;     /**< Input buffer */
+	const uint8_t *src;     /**< Input buffer */
 	size_t srclen;    /**< Input buffer size */
 	size_t srccnt;    /**< Position in the input buffer */
@@ -319,5 +319,5 @@
     uint16_t *symbol)
 {
-	/* Decoded bits */
+	/* Decode bits */
 	uint16_t code = 0;
 
@@ -331,5 +331,7 @@
 	size_t index = 0;
 
-	size_t len;  /* Current number of bits in the code */
+	/* Current number of bits in the code */
+	size_t len;
+
 	for (len = 1; len <= MAX_HUFFMAN_BIT; len++) {
 		/* Get next bit */
@@ -625,5 +627,5 @@
  *
  */
-int inflate(void *src, size_t srclen, void *dest, size_t destlen)
+int inflate(const void *src, size_t srclen, void *dest, size_t destlen)
 {
 	/* Initialize the state */
@@ -634,5 +636,5 @@
 	state.destcnt = 0;
 
-	state.src = (uint8_t *) src;
+	state.src = (const uint8_t *) src;
 	state.srclen = srclen;
 	state.srccnt = 0;
Index: boot/generic/src/payload.c
===================================================================
--- boot/generic/src/payload.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/src/payload.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2007 Michal Kebrt
+ * Copyright (c) 2018 Jiří Zárevúcky
+ * 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 <payload.h>
+
+#include <align.h>
+#include <printf.h>
+#include <arch/arch.h>
+#include <tar.h>
+#include <gzip.h>
+#include <stdbool.h>
+#include <memstr.h>
+#include <errno.h>
+#include <str.h>
+#include <halt.h>
+
+static void basename(char *s)
+{
+	char *last = s;
+
+	while (*s) {
+		if (*s == '.')
+			last = s;
+
+		s++;
+	}
+
+	if (*last == '.')
+		*last = '\0';
+}
+
+static bool overlaps(uint8_t *start1, uint8_t *end1,
+    uint8_t *start2, uint8_t *end2)
+{
+	return !(end1 <= start2 || end2 <= start1);
+}
+
+static bool extract_component(uint8_t **cstart, uint8_t *cend,
+    uint8_t *ustart, uint8_t *uend, uintptr_t actual_ustart,
+    void (*clear_cache)(void *, size_t), task_t *task)
+{
+	const char *name;
+	const uint8_t *data;
+	size_t compressed_size;
+	size_t uncompressed_size;
+
+	if (!tar_info(*cstart, cend, &name, &compressed_size))
+		return false;
+
+	data = *cstart + TAR_BLOCK_SIZE;
+	*cstart += TAR_BLOCK_SIZE + ALIGN_UP(compressed_size, TAR_BLOCK_SIZE);
+
+	uncompressed_size = gzip_size(data, compressed_size);
+
+	/* Components must be page-aligned. */
+	uint8_t *new_ustart = (uint8_t *) ALIGN_UP((uintptr_t) ustart, PAGE_SIZE);
+	actual_ustart += new_ustart - ustart;
+	ustart = new_ustart;
+	uint8_t *comp_end = ustart + uncompressed_size;
+
+	/* Check limits and overlap. */
+	if (overlaps(ustart, comp_end, loader_start, loader_end)) {
+		/* Move the component after bootloader. */
+		printf("%s would overlap bootloader, moving to %p.\n", name, loader_end);
+		uint8_t *new_ustart = (uint8_t *) ALIGN_UP((uintptr_t) loader_end, PAGE_SIZE);
+		actual_ustart += new_ustart - ustart;
+		ustart = new_ustart;
+		comp_end = ustart + uncompressed_size;
+	}
+
+	if (comp_end > uend) {
+		printf("Not enough available memory for remaining components"
+		    " (at least %zd more required).\n", comp_end - uend);
+		halt();
+	}
+
+	printf(" %p|%p: %s image (%zu/%zu bytes)\n", (void *) actual_ustart,
+	    ustart, name, uncompressed_size, compressed_size);
+
+	if (task) {
+		task->addr = (void *) actual_ustart;
+		task->size = uncompressed_size;
+		str_cpy(task->name, BOOTINFO_TASK_NAME_BUFLEN, name);
+		/* Remove .gz extension */
+		basename(task->name);
+	}
+
+	int rc = gzip_expand(data, compressed_size, ustart, uncompressed_size);
+	if (rc != EOK) {
+		printf("\n%s: Inflating error %d\n", name, rc);
+		halt();
+	}
+
+	if (clear_cache)
+		clear_cache(ustart, uncompressed_size);
+	return true;
+}
+
+/* @return Bytes needed for uncompressed payload. */
+size_t payload_uncompressed_size(void)
+{
+	size_t sz = 0;
+	uint8_t *start = payload_start;
+	const char *name;
+	size_t compressed_size;
+
+	while (tar_info(start, payload_end, &name, &compressed_size)) {
+		sz = ALIGN_UP(sz, PAGE_SIZE);
+		sz += gzip_size(start + TAR_BLOCK_SIZE, compressed_size);
+
+		start += TAR_BLOCK_SIZE +
+		    ALIGN_UP(compressed_size, TAR_BLOCK_SIZE);
+	}
+
+	return sz;
+}
+
+/**
+ * Extract the payload (kernel, loader, init binaries and the initrd image).
+ *
+ * @param bootinfo      Pointer to the structure where the actual placement
+ *                      of components is recorded.
+ *
+ * @param kernel_dest   Address of the kernel in the bootloader's address space.
+ *                      Kernel is the only part of the payload that has a fixed
+ *                      location and cannot be moved. If the kernel doesn't fit
+ *                      or would overlap bootloader, bootloader halts.
+ *
+ * @param mem_end       End of usable contiguous memory.
+ *                      The caller guarantees that the entire area between
+ *                      kernel_start and mem_end is free and safe to write to,
+ *                      save possibly for the interval [loader_start, loader_end).
+ *                      All components are placed in this area. If there is not
+ *                      enough space for all components, bootloader halts.
+ *
+ * @param kernel_start  Address the kernel will have in the kernel's own
+ *                      address space.
+ *
+ * @param clear_cache   Caller-provided function for assuring cache coherence,
+ *                      whatever that means for a given platform. May be NULL.
+ */
+void extract_payload(taskmap_t *tmap, uint8_t *kernel_dest, uint8_t *mem_end,
+    uintptr_t kernel_start, void (*clear_cache)(void *, size_t))
+{
+	task_t task;
+	memset(&task, 0, sizeof(task));
+
+	printf("Boot loader: %p -> %p\n", loader_start, loader_end);
+	printf("Payload: %p -> %p\n", payload_start, payload_end);
+	printf("Kernel load address: %p\n", kernel_dest);
+	printf("Kernel start: %p\n", (void *) kernel_start);
+	printf("RAM end: %p (%zd bytes available)\n", mem_end,
+	    mem_end - kernel_dest);
+
+	size_t payload_size = payload_end - payload_start;
+	uint8_t *real_payload_start;
+	uint8_t *real_payload_end;
+
+	if (overlaps(kernel_dest, mem_end, payload_start, payload_end)) {
+		/*
+		 * First, move the payload to the very end of available memory,
+		 * to make space for the decompressed data.
+		 */
+		real_payload_start = (uint8_t *) ALIGN_DOWN((uintptr_t)(mem_end - payload_size), PAGE_SIZE);
+		real_payload_end = real_payload_start + payload_size;
+		memmove(real_payload_start, payload_start, payload_size);
+
+		printf("Moved payload: %p -> %p\n", real_payload_start, real_payload_end);
+	} else {
+		real_payload_start = payload_start;
+		real_payload_end = payload_end;
+	}
+
+	printf("\nInflating components ... \n");
+
+	uint8_t *end = mem_end;
+
+	if (real_payload_end > kernel_dest && real_payload_start < mem_end)
+		end = real_payload_start;
+
+	/* Kernel is always first. */
+	if (!extract_component(&real_payload_start, real_payload_end,
+	    kernel_dest, end, kernel_start, clear_cache, &task)) {
+		printf("There is no kernel.\n");
+		halt();
+	}
+
+	if ((uintptr_t) task.addr != kernel_start) {
+		printf("Couldn't load kernel at the requested address.\n");
+		halt();
+	}
+
+	tmap->cnt = 0;
+
+	for (int i = 0; i <= TASKMAP_MAX_RECORDS; i++) {
+		/*
+		 * `task` holds the location and size of the previous component.
+		 */
+		uintptr_t actual_dest =
+		    ALIGN_UP((uintptr_t) task.addr + task.size, PAGE_SIZE);
+		uint8_t *dest = kernel_dest + (actual_dest - kernel_start);
+
+		if (real_payload_end > dest && real_payload_start < mem_end)
+			end = real_payload_start;
+
+		if (!extract_component(&real_payload_start, real_payload_end,
+		    dest, end, actual_dest, clear_cache, &task))
+			break;
+
+		if (i >= TASKMAP_MAX_RECORDS) {
+			printf("More components than the maximum of %d.\n",
+			    TASKMAP_MAX_RECORDS);
+			halt();
+		}
+
+		tmap->tasks[i] = task;
+		tmap->cnt = i + 1;
+	}
+
+	printf("Done.\n");
+}
Index: boot/generic/src/tar.c
===================================================================
--- boot/generic/src/tar.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
+++ boot/generic/src/tar.c	(revision 63a045c41ff533abb66be65fc068415be77ad7df)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Jiří Zárevúcky
+ * 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 <align.h>
+#include <tar.h>
+
+static int _digit_val(char c)
+{
+	if (c >= '0' && c <= '9') {
+		return c - '0';
+	}
+	if (c >= 'a' && c <= 'z') {
+		return c - 'a' + 10;
+	}
+	if (c >= 'A' && c <= 'Z') {
+		return c - 'A' + 10;
+	}
+
+	// TODO: error message
+	return 0;
+}
+
+static int64_t _parse_size(const char *s, size_t len, int base)
+{
+	int64_t val = 0;
+
+	for (size_t i = 0; i < len; i++) {
+		if (*s == 0)
+			return val;
+
+		if (*s == ' ') {
+			s++;
+			continue;
+		}
+
+		if ((INT64_MAX - 64) / base <= val) {
+			// TODO: error message
+			return INT64_MAX;
+		}
+
+		val *= base;
+		val += _digit_val(*s);
+		s++;
+	}
+
+	return val;
+}
+
+bool tar_info(const uint8_t *start, const uint8_t *end,
+    const char **name, size_t *length)
+{
+	if (end - start < TAR_BLOCK_SIZE) {
+		// TODO: error message
+		return false;
+	}
+
+	const tar_header_raw_t *h = (const tar_header_raw_t *) start;
+	if (h->filename[0] == '\0')
+		return false;
+
+	ptrdiff_t len = _parse_size(h->size, sizeof(h->size), 8);
+
+	if (end - start < TAR_BLOCK_SIZE + len) {
+		// TODO: error message
+		return false;
+	}
+
+	*name = h->filename;
+	*length = len;
+	return true;
+}
