Index: boot/generic/include/byteorder.h
===================================================================
--- boot/generic/include/byteorder.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/include/byteorder.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/include/gzip.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 174156fd1cf321a6363777352073d05829467b2f)
+++ boot/generic/include/inflate.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/include/payload.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/include/tar.h	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/src/gzip.c	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 174156fd1cf321a6363777352073d05829467b2f)
+++ boot/generic/src/inflate.c	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/src/payload.c	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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 d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
+++ boot/generic/src/tar.c	(revision d4eba6d776758cf1fb2f6c2a27ccd1ffb585d964)
@@ -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;
+}
