summaryrefslogtreecommitdiffstats
path: root/usr
diff options
context:
space:
mode:
authorAdrian Betschart <adrian.betschart@cinemaone.ch>2026-09-11 17:13:14 +0200
committerAlex Deucher <alexander.deucher@amd.com>2026-10-01 17:18:05 -0400
commit106b4a2a78b2a2f14885604891957b84bba502db (patch)
tree5d40eef2428fb1a4791ab46a4b19091a5910eac2 /usr
downloadlinux-stable-106b4a2a78b2a2f14885604891957b84bba502db.tar.gz
linux-stable-106b4a2a78b2a2f14885604891957b84bba502db.zip
drm/amd/display: Try RGB before YCbCr 4:4:4 in stream validationgrafted
amdgpu_dm_create_validate_stream_for_sink() walks encoding_order[] and uses the first encoding that validates. YCbCr 4:4:4 is listed before RGB, so an HDMI sink that advertises 4:4:4 gets YCbCr 4:4:4 whenever the "color format" property is left at AUTO, even though RGB fits the same link. That contradicts the documented AUTO behaviour for HDMI in enum drm_connector_color_format (RGB, falling back to YCbCr 4:2:0 only when the bandwidth is not available or the mode is 4:2:0-only), which the amdgpu implementation of the property also describes. It also leaves the "Broadcast RGB" property without effect on such sinks, since the quantization range it selects only applies to RGB output. Try RGB first. The mask still holds every encoding the sink supports, so a mode that cannot carry RGB falls back exactly as before. For reference, v7.2 picked RGB here unless YCbCr 4:4:4 was forced through debugfs, while earlier kernels picked YCbCr 4:4:4 for any HDMI sink that advertised it. Fixes: 0b0ff65d3ca1 ("drm/amd/display: Refactor stream validation") Suggested-by: Adolfo Rodrigues <adolfotregosa@gmail.com> Assisted-by: Claude Code:claude-fable-5-1 Signed-off-by: Adrian Betschart <adrian.betschart@cinemaone.ch> Reviewed-by: Fangzhi Zuo <jerry.zuo@amd.com> Tested-by: Adolfo Rodrigues <adolfotregosa@gmail.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit 7de432bc753133764dc40d37f9388da56de251e7)
Diffstat (limited to 'usr')
-rw-r--r--usr/.gitignore4
-rw-r--r--usr/Kconfig229
-rw-r--r--usr/Makefile85
-rw-r--r--usr/default_cpio_list6
-rw-r--r--usr/dummy-include/endian.h0
-rw-r--r--usr/dummy-include/limits.h8
-rw-r--r--usr/dummy-include/netinet/if_ether.h0
-rw-r--r--usr/dummy-include/netinet/in.h0
-rw-r--r--usr/dummy-include/stddef.h13
-rw-r--r--usr/dummy-include/stdint.h17
-rw-r--r--usr/dummy-include/string.h12
-rw-r--r--usr/dummy-include/sys/ioctl.h0
-rw-r--r--usr/dummy-include/sys/socket.h12
-rw-r--r--usr/dummy-include/sys/time.h3
-rw-r--r--usr/dummy-include/sys/types.h0
-rw-r--r--usr/dummy-include/time.h0
-rw-r--r--usr/dummy-include/unistd.h0
-rw-r--r--usr/gen_init_cpio.c781
-rwxr-xr-xusr/gen_initramfs.sh250
-rw-r--r--usr/include/.gitignore2
-rw-r--r--usr/include/Makefile188
-rwxr-xr-xusr/include/headers_check.pl96
-rw-r--r--usr/initramfs_data.S36
23 files changed, 1742 insertions, 0 deletions
diff --git a/usr/.gitignore b/usr/.gitignore
new file mode 100644
index 000000000..8996e7a88
--- /dev/null
+++ b/usr/.gitignore
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+/gen_init_cpio
+/initramfs_data.cpio
+/initramfs_inc_data
diff --git a/usr/Kconfig b/usr/Kconfig
new file mode 100644
index 000000000..9279a2893
--- /dev/null
+++ b/usr/Kconfig
@@ -0,0 +1,229 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Configuration for initramfs
+#
+
+config INITRAMFS_SOURCE
+ string "Initramfs source file(s)"
+ default ""
+ help
+ This can be either a single cpio archive with a .cpio suffix or a
+ space-separated list of directories and files for building the
+ initramfs image. A cpio archive should contain a filesystem archive
+ to be used as an initramfs image. Directories should contain a
+ filesystem layout to be included in the initramfs image. Files
+ should contain entries according to the format described by the
+ "usr/gen_init_cpio" program in the kernel tree.
+
+ When multiple directories and files are specified then the
+ initramfs image will be the aggregate of all of them.
+
+ See <file:Documentation/driver-api/early-userspace/early_userspace_support.rst> for more details.
+
+ If you are not sure, leave it blank.
+
+config INITRAMFS_FORCE
+ bool "Ignore the initramfs passed by the bootloader"
+ depends on CMDLINE_EXTEND || CMDLINE_FORCE
+ help
+ This option causes the kernel to ignore the initramfs image
+ (or initrd image) passed to it by the bootloader. This is
+ analogous to CMDLINE_FORCE, which is found on some architectures,
+ and is useful if you cannot or don't want to change the image
+ your bootloader passes to the kernel.
+
+config INITRAMFS_ROOT_UID
+ int "User ID to map to 0 (user root)"
+ depends on INITRAMFS_SOURCE!=""
+ default "0"
+ help
+ If INITRAMFS_SOURCE points to a directory, files owned by this UID
+ (-1 = current user) will be owned by root in the resulting image.
+
+ If you are not sure, leave it set to "0".
+
+config INITRAMFS_ROOT_GID
+ int "Group ID to map to 0 (group root)"
+ depends on INITRAMFS_SOURCE!=""
+ default "0"
+ help
+ If INITRAMFS_SOURCE points to a directory, files owned by this GID
+ (-1 = current group) will be owned by root in the resulting image.
+
+ If you are not sure, leave it set to "0".
+
+config RD_GZIP
+ bool "Support initial ramdisk/ramfs compressed using gzip"
+ default y
+ select DECOMPRESS_GZIP
+ help
+ Support loading of a gzip encoded initial ramdisk or cpio buffer.
+ If unsure, say Y.
+
+config RD_BZIP2
+ bool "Support initial ramdisk/ramfs compressed using bzip2"
+ default y
+ select DECOMPRESS_BZIP2
+ help
+ Support loading of a bzip2 encoded initial ramdisk or cpio buffer
+ If unsure, say N.
+
+config RD_LZMA
+ bool "Support initial ramdisk/ramfs compressed using LZMA"
+ default y
+ select DECOMPRESS_LZMA
+ help
+ Support loading of a LZMA encoded initial ramdisk or cpio buffer
+ If unsure, say N.
+
+config RD_XZ
+ bool "Support initial ramdisk/ramfs compressed using XZ"
+ default y
+ select DECOMPRESS_XZ
+ help
+ Support loading of a XZ encoded initial ramdisk or cpio buffer.
+ If unsure, say N.
+
+config RD_LZO
+ bool "Support initial ramdisk/ramfs compressed using LZO"
+ default y
+ select DECOMPRESS_LZO
+ help
+ Support loading of a LZO encoded initial ramdisk or cpio buffer
+ If unsure, say N.
+
+config RD_LZ4
+ bool "Support initial ramdisk/ramfs compressed using LZ4"
+ default y
+ select DECOMPRESS_LZ4
+ help
+ Support loading of a LZ4 encoded initial ramdisk or cpio buffer
+ If unsure, say N.
+
+config RD_ZSTD
+ bool "Support initial ramdisk/ramfs compressed using ZSTD"
+ default y
+ select DECOMPRESS_ZSTD
+ help
+ Support loading of a ZSTD encoded initial ramdisk or cpio buffer.
+ If unsure, say N.
+
+choice
+ prompt "Built-in initramfs compression mode"
+ depends on INITRAMFS_SOURCE != ""
+ help
+ This option allows you to decide by which algorithm the builtin
+ initramfs will be compressed. Several compression algorithms are
+ available, which differ in efficiency, compression and
+ decompression speed. Compression speed is only relevant
+ when building a kernel. Decompression speed is relevant at
+ each boot. Also the memory usage during decompression may become
+ relevant on memory constrained systems. This is usually based on the
+ dictionary size of the algorithm with algorithms like XZ and LZMA
+ featuring large dictionary sizes.
+
+ High compression options are mostly useful for users who are
+ low on RAM, since it reduces the memory consumption during
+ boot.
+
+ Keep in mind that your build system needs to provide the appropriate
+ compression tool to compress the generated initram cpio file for
+ embedding.
+
+ If in doubt, select 'None'
+
+config INITRAMFS_COMPRESSION_GZIP
+ bool "Gzip"
+ depends on RD_GZIP
+ help
+ Use the old and well tested gzip compression algorithm. Gzip provides
+ a good balance between compression ratio and decompression speed and
+ has a reasonable compression speed. It is also more likely to be
+ supported by your build system as the gzip tool is present by default
+ on most distros.
+
+config INITRAMFS_COMPRESSION_BZIP2
+ bool "Bzip2"
+ depends on RD_BZIP2
+ help
+ It's compression ratio and speed is intermediate. Decompression speed
+ is slowest among the choices. The initramfs size is about 10% smaller
+ with bzip2, in comparison to gzip. Bzip2 uses a large amount of
+ memory. For modern kernels you will need at least 8MB RAM or more for
+ booting.
+
+ If you choose this, keep in mind that you need to have the bzip2 tool
+ available to be able to compress the initram.
+
+config INITRAMFS_COMPRESSION_LZMA
+ bool "LZMA"
+ depends on RD_LZMA
+ help
+ This algorithm's compression ratio is best but has a large dictionary
+ size which might cause issues in memory constrained systems.
+ Decompression speed is between the other choices. Compression is
+ slowest. The initramfs size is about 33% smaller with LZMA in
+ comparison to gzip.
+
+ If you choose this, keep in mind that you may need to install the xz
+ or lzma tools to be able to compress the initram.
+
+config INITRAMFS_COMPRESSION_XZ
+ bool "XZ"
+ depends on RD_XZ
+ help
+ XZ uses the LZMA2 algorithm and has a large dictionary which may cause
+ problems on memory constrained systems. The initramfs size is about
+ 30% smaller with XZ in comparison to gzip. Decompression speed is
+ better than that of bzip2 but worse than gzip and LZO. Compression is
+ slow.
+
+ If you choose this, keep in mind that you may need to install the xz
+ tool to be able to compress the initram.
+
+config INITRAMFS_COMPRESSION_LZO
+ bool "LZO"
+ depends on RD_LZO
+ help
+ Its compression ratio is the second poorest amongst the choices. The
+ kernel size is about 10% bigger than gzip. Despite that, its
+ decompression speed is the second fastest and its compression speed
+ is quite fast too.
+
+ If you choose this, keep in mind that you may need to install the lzop
+ tool to be able to compress the initram.
+
+config INITRAMFS_COMPRESSION_LZ4
+ bool "LZ4"
+ depends on RD_LZ4
+ help
+ It's compression ratio is the poorest amongst the choices. The kernel
+ size is about 15% bigger than gzip; however its decompression speed
+ is the fastest.
+
+ If you choose this, keep in mind that most distros don't provide lz4
+ by default which could cause a build failure.
+
+config INITRAMFS_COMPRESSION_ZSTD
+ bool "ZSTD"
+ depends on RD_ZSTD
+ help
+ ZSTD is a compression algorithm targeting intermediate compression
+ with fast decompression speed. It will compress better than GZIP and
+ decompress around the same speed as LZO, but slower than LZ4.
+
+ If you choose this, keep in mind that you may need to install the zstd
+ tool to be able to compress the initram.
+
+config INITRAMFS_COMPRESSION_NONE
+ bool "None"
+ help
+ Do not compress the built-in initramfs at all. This may sound wasteful
+ in space, but, you should be aware that the built-in initramfs will be
+ compressed at a later stage anyways along with the rest of the kernel,
+ on those architectures that support this. However, not compressing the
+ initramfs may lead to slightly higher memory consumption during a
+ short time at boot, while both the cpio image and the unpacked
+ filesystem image will be present in memory simultaneously
+
+endchoice
diff --git a/usr/Makefile b/usr/Makefile
new file mode 100644
index 000000000..e8f42478a
--- /dev/null
+++ b/usr/Makefile
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# kbuild file for usr/ - including initramfs image
+#
+
+compress-y := copy
+compress-$(CONFIG_INITRAMFS_COMPRESSION_GZIP) := gzip
+compress-$(CONFIG_INITRAMFS_COMPRESSION_BZIP2) := bzip2
+compress-$(CONFIG_INITRAMFS_COMPRESSION_LZMA) := lzma
+compress-$(CONFIG_INITRAMFS_COMPRESSION_XZ) := xzmisc
+compress-$(CONFIG_INITRAMFS_COMPRESSION_LZO) := lzo
+compress-$(CONFIG_INITRAMFS_COMPRESSION_LZ4) := lz4
+compress-$(CONFIG_INITRAMFS_COMPRESSION_ZSTD) := zstd
+
+obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o
+
+$(obj)/initramfs_data.o: $(obj)/initramfs_inc_data
+
+hostprogs := gen_init_cpio
+
+ramfs-input := $(CONFIG_INITRAMFS_SOURCE)
+cpio-data :=
+
+# If CONFIG_INITRAMFS_SOURCE is empty, generate a small initramfs with the
+# default contents.
+ifeq ($(ramfs-input),)
+ramfs-input := $(src)/default_cpio_list
+endif
+
+ifeq ($(words $(ramfs-input)),1)
+
+# If CONFIG_INITRAMFS_SOURCE specifies a single file, and it is suffixed with
+# .cpio, use it directly as an initramfs.
+ifneq ($(filter %.cpio,$(ramfs-input)),)
+cpio-data := $(ramfs-input)
+endif
+
+# If CONFIG_INITRAMFS_SOURCE specifies a single file, and it is suffixed with
+# .cpio.*, use it directly as an initramfs, and avoid double compression.
+ifeq ($(words $(subst .cpio.,$(space),$(ramfs-input))),2)
+cpio-data := $(ramfs-input)
+compress-y := copy
+endif
+
+endif
+
+# For other cases, generate the initramfs cpio archive based on the contents
+# specified by CONFIG_INITRAMFS_SOURCE.
+ifeq ($(cpio-data),)
+
+cpio-data := $(obj)/initramfs_data.cpio
+
+# .initramfs_data.cpio.d is used to identify all files included
+# in initramfs and to detect if any files are added/removed.
+# Removed files are identified by directory timestamp being updated
+# The dependency list is generated by gen_initramfs.sh -l
+-include $(obj)/.initramfs_data.cpio.d
+
+# do not try to update files included in initramfs
+$(deps_initramfs): ;
+
+quiet_cmd_initfs = GEN $@
+ cmd_initfs = \
+ $(CONFIG_SHELL) $< -o $@ -l $(obj)/.initramfs_data.cpio.d \
+ $(addprefix -u , $(CONFIG_INITRAMFS_ROOT_UID)) \
+ $(addprefix -g , $(CONFIG_INITRAMFS_ROOT_GID)) \
+ $(if $(KBUILD_BUILD_TIMESTAMP), -d "$(KBUILD_BUILD_TIMESTAMP)") \
+ $(ramfs-input)
+
+# We rebuild initramfs_data.cpio if:
+# 1) Any included file is newer than initramfs_data.cpio
+# 2) There are changes in which files are included (added or deleted)
+# 3) If gen_init_cpio are newer than initramfs_data.cpio
+# 4) Arguments to gen_initramfs.sh changes
+$(obj)/initramfs_data.cpio: $(src)/gen_initramfs.sh $(obj)/gen_init_cpio $(deps_initramfs) FORCE
+ $(call if_changed,initfs)
+
+endif
+
+$(obj)/initramfs_inc_data: $(cpio-data) FORCE
+ $(call if_changed,$(compress-y))
+
+targets += initramfs_data.cpio initramfs_inc_data
+
+subdir-$(CONFIG_UAPI_HEADER_TEST) += include
diff --git a/usr/default_cpio_list b/usr/default_cpio_list
new file mode 100644
index 000000000..37b386406
--- /dev/null
+++ b/usr/default_cpio_list
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# This is a very simple, default initramfs
+
+dir /dev 0755 0 0
+nod /dev/console 0600 0 0 c 5 1
+dir /root 0700 0 0
diff --git a/usr/dummy-include/endian.h b/usr/dummy-include/endian.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/endian.h
diff --git a/usr/dummy-include/limits.h b/usr/dummy-include/limits.h
new file mode 100644
index 000000000..49b17c10c
--- /dev/null
+++ b/usr/dummy-include/limits.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DUMMY_LIMITS_H
+#define _DUMMY_LIMITS_H
+
+#define INT_MAX ((int)(~0U >> 1))
+#define INT_MIN (-INT_MAX - 1)
+
+#endif /* _DUMMY_LIMITS_H */
diff --git a/usr/dummy-include/netinet/if_ether.h b/usr/dummy-include/netinet/if_ether.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/netinet/if_ether.h
diff --git a/usr/dummy-include/netinet/in.h b/usr/dummy-include/netinet/in.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/netinet/in.h
diff --git a/usr/dummy-include/stddef.h b/usr/dummy-include/stddef.h
new file mode 100644
index 000000000..525489daf
--- /dev/null
+++ b/usr/dummy-include/stddef.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DUMMY_STDDEF_H
+#define _DUMMY_STDDEF_H
+
+#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
+
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+#endif /* _DUMMY_STDDEF_H */
diff --git a/usr/dummy-include/stdint.h b/usr/dummy-include/stdint.h
new file mode 100644
index 000000000..93b1962fd
--- /dev/null
+++ b/usr/dummy-include/stdint.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DUMMY_STDINT_H
+#define _DUMMY_STDINT_H
+
+#include <linux/types.h>
+
+typedef __u64 uint64_t;
+typedef __u32 uint32_t;
+typedef __u16 uint16_t;
+typedef __u8 uint8_t;
+
+typedef __s64 int64_t;
+typedef __s32 int32_t;
+typedef __s16 int16_t;
+typedef __s8 int8_t;
+
+#endif /* _DUMMY_STDINT_H */
diff --git a/usr/dummy-include/string.h b/usr/dummy-include/string.h
new file mode 100644
index 000000000..e059808d3
--- /dev/null
+++ b/usr/dummy-include/string.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DUMMY_STRING_H
+#define _DUMMY_STRING_H
+
+#include <stddef.h>
+
+#define memset(_s, _c, _n) __builtin_memset(_s, _c, _n)
+#define memcpy(_dest, _src, _n) __builtin_memcpy(_dest, _src, _n)
+
+#define strlen(_s) __builtin_strlen(_s)
+
+#endif /* _DUMMY_STRING_H */
diff --git a/usr/dummy-include/sys/ioctl.h b/usr/dummy-include/sys/ioctl.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/sys/ioctl.h
diff --git a/usr/dummy-include/sys/socket.h b/usr/dummy-include/sys/socket.h
new file mode 100644
index 000000000..748751f9e
--- /dev/null
+++ b/usr/dummy-include/sys/socket.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DUMMY_SYS_SOCKET_H
+#define _DUMMY_SYS_SOCKET_H
+
+#include <linux/socket.h>
+
+struct sockaddr {
+ __kernel_sa_family_t sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+#endif /* _DUMMY_SYS_SOCKET_H */
diff --git a/usr/dummy-include/sys/time.h b/usr/dummy-include/sys/time.h
new file mode 100644
index 000000000..9817b8afb
--- /dev/null
+++ b/usr/dummy-include/sys/time.h
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/time.h>
diff --git a/usr/dummy-include/sys/types.h b/usr/dummy-include/sys/types.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/sys/types.h
diff --git a/usr/dummy-include/time.h b/usr/dummy-include/time.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/time.h
diff --git a/usr/dummy-include/unistd.h b/usr/dummy-include/unistd.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/usr/dummy-include/unistd.h
diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c
new file mode 100644
index 000000000..b7296edc6
--- /dev/null
+++ b/usr/gen_init_cpio.c
@@ -0,0 +1,781 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+/*
+ * Original work by Jeff Garzik
+ *
+ * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
+ * Hard link support by Luciano Rocha
+ */
+
+#define xstr(s) #s
+#define str(s) xstr(s)
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CPIO_HDR_LEN 110
+#define CPIO_TRAILER "TRAILER!!!"
+#define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align))
+
+/* zero-padding the filename field for data alignment is limited by PATH_MAX */
+static char padding[PATH_MAX];
+static unsigned int offset;
+static unsigned int ino = 721;
+static time_t default_mtime;
+static bool do_file_mtime;
+static bool do_csum = false;
+static int outfd = STDOUT_FILENO;
+static unsigned int dalign;
+
+struct file_handler {
+ const char *type;
+ int (*handler)(const char *line);
+};
+
+static int push_buf(const char *name, size_t name_len)
+{
+ ssize_t len;
+
+ len = write(outfd, name, name_len);
+ if (len != name_len)
+ return -1;
+
+ offset += name_len;
+ return 0;
+}
+
+static int push_pad(size_t padlen)
+{
+ ssize_t len = 0;
+
+ if (!padlen)
+ return 0;
+
+ if (padlen < sizeof(padding))
+ len = write(outfd, padding, padlen);
+ if (len != padlen)
+ return -1;
+
+ offset += padlen;
+ return 0;
+}
+
+static int push_rest(const char *name, size_t name_len)
+{
+ ssize_t len;
+
+ len = write(outfd, name, name_len);
+ if (len != name_len)
+ return -1;
+
+ offset += name_len;
+
+ return push_pad(padlen(name_len + CPIO_HDR_LEN, 4));
+}
+
+static int cpio_trailer(void)
+{
+ int len;
+ unsigned int namesize = sizeof(CPIO_TRAILER);
+
+ len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ 0, /* ino */
+ 0, /* mode */
+ (long) 0, /* uid */
+ (long) 0, /* gid */
+ 1, /* nlink */
+ (long) 0, /* mtime */
+ 0, /* filesize */
+ 0, /* major */
+ 0, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ offset += len;
+
+ if (len != CPIO_HDR_LEN ||
+ push_rest(CPIO_TRAILER, namesize) < 0 ||
+ push_pad(padlen(offset, 512)) < 0)
+ return -1;
+
+ if (fsync(outfd) < 0 && errno != EINVAL)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mkslink(const char *name, const char *target,
+ unsigned int mode, uid_t uid, gid_t gid)
+{
+ int len;
+ unsigned int namesize, targetsize = strlen(target) + 1;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+
+ len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ S_IFLNK | mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ targetsize, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ offset += len;
+
+ if (len != CPIO_HDR_LEN ||
+ push_buf(name, namesize) < 0 ||
+ push_pad(padlen(offset, 4)) < 0 ||
+ push_buf(target, targetsize) < 0 ||
+ push_pad(padlen(offset, 4)) < 0)
+ return -1;
+
+ return 0;
+
+}
+
+static int cpio_mkslink_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char target[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized dir format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mkslink(name, target, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkgeneric(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid)
+{
+ int len;
+ unsigned int namesize;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+
+ len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 2, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ offset += len;
+
+ if (len != CPIO_HDR_LEN ||
+ push_rest(name, namesize) < 0)
+ return -1;
+
+ return 0;
+}
+
+enum generic_types {
+ GT_DIR,
+ GT_PIPE,
+ GT_SOCK
+};
+
+struct generic_type {
+ const char *type;
+ mode_t mode;
+};
+
+static const struct generic_type generic_type_table[] = {
+ [GT_DIR] = {
+ .type = "dir",
+ .mode = S_IFDIR
+ },
+ [GT_PIPE] = {
+ .type = "pipe",
+ .mode = S_IFIFO
+ },
+ [GT_SOCK] = {
+ .type = "sock",
+ .mode = S_IFSOCK
+ }
+};
+
+static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int rc = -1;
+
+ if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
+ fprintf(stderr, "Unrecognized %s format '%s'",
+ line, generic_type_table[gt].type);
+ goto fail;
+ }
+ mode |= generic_type_table[gt].mode;
+ rc = cpio_mkgeneric(name, mode, uid, gid);
+ fail:
+ return rc;
+}
+
+static int cpio_mkdir_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_DIR);
+}
+
+static int cpio_mkpipe_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_PIPE);
+}
+
+static int cpio_mksock_line(const char *line)
+{
+ return cpio_mkgeneric_line(line, GT_SOCK);
+}
+
+static int cpio_mknod(const char *name, unsigned int mode,
+ uid_t uid, gid_t gid, char dev_type,
+ unsigned int maj, unsigned int min)
+{
+ int len;
+ unsigned int namesize;
+
+ if (dev_type == 'b')
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+
+ len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08X%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino++, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ 1, /* nlink */
+ (long) default_mtime, /* mtime */
+ 0, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ maj, /* rmajor */
+ min, /* rminor */
+ namesize, /* namesize */
+ 0); /* chksum */
+ offset += len;
+
+ if (len != CPIO_HDR_LEN ||
+ push_rest(name, namesize) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mknod_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ char dev_type;
+ unsigned int maj;
+ unsigned int min;
+ int rc = -1;
+
+ if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
+ name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
+ fprintf(stderr, "Unrecognized nod format '%s'", line);
+ goto fail;
+ }
+ rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
+ fail:
+ return rc;
+}
+
+static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
+{
+ while (size) {
+ unsigned char filebuf[65536];
+ ssize_t this_read;
+ size_t i, this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(fd, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size)
+ return -1;
+
+ for (i = 0; i < this_read; i++)
+ *csum += filebuf[i];
+
+ size -= this_read;
+ }
+ /* seek back to the start for data segment I/O */
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int cpio_mkfile(const char *name, const char *location,
+ unsigned int mode, uid_t uid, gid_t gid,
+ unsigned int nlinks)
+{
+ struct stat buf;
+ unsigned long size;
+ int file, retval, len;
+ int rc = -1;
+ time_t mtime;
+ int namesize, namepadlen;
+ unsigned int i;
+ uint32_t csum = 0;
+ ssize_t this_read;
+
+ mode |= S_IFREG;
+
+ file = open (location, O_RDONLY);
+ if (file < 0) {
+ fprintf (stderr, "File %s could not be opened for reading\n", location);
+ goto error;
+ }
+
+ retval = fstat(file, &buf);
+ if (retval) {
+ fprintf(stderr, "File %s could not be stat()'ed\n", location);
+ goto error;
+ }
+
+ if (do_file_mtime) {
+ mtime = default_mtime;
+ } else {
+ mtime = buf.st_mtime;
+ if (mtime > 0xffffffff) {
+ fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
+ location);
+ mtime = 0xffffffff;
+ }
+
+ if (mtime < 0) {
+ fprintf(stderr, "%s: Timestamp negative, clipping.\n",
+ location);
+ mtime = 0;
+ }
+ }
+
+ if (buf.st_size > 0xffffffff) {
+ fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
+ location);
+ goto error;
+ }
+
+ if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
+ fprintf(stderr, "Failed to checksum file %s\n", location);
+ goto error;
+ }
+
+ size = 0;
+ namepadlen = 0;
+ for (i = 1; i <= nlinks; i++) {
+ if (name[0] == '/')
+ name++;
+ namesize = strlen(name) + 1;
+
+ /* data goes on last link, after any alignment padding */
+ if (i == nlinks)
+ size = buf.st_size;
+
+ if (dalign && size > dalign) {
+ namepadlen = padlen(offset + CPIO_HDR_LEN + namesize,
+ dalign);
+ if (namesize + namepadlen > PATH_MAX) {
+ fprintf(stderr,
+ "%s: best-effort alignment %u missed\n",
+ name, dalign);
+ namepadlen = 0;
+ }
+ }
+
+ len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
+ "%08lX%08X%08X%08X%08X%08X%08X",
+ do_csum ? "070702" : "070701", /* magic */
+ ino, /* ino */
+ mode, /* mode */
+ (long) uid, /* uid */
+ (long) gid, /* gid */
+ nlinks, /* nlink */
+ (long) mtime, /* mtime */
+ size, /* filesize */
+ 3, /* major */
+ 1, /* minor */
+ 0, /* rmajor */
+ 0, /* rminor */
+ namesize + namepadlen, /* namesize */
+ size ? csum : 0); /* chksum */
+ offset += len;
+
+ if (len != CPIO_HDR_LEN ||
+ push_buf(name, namesize) < 0 ||
+ push_pad(namepadlen ? namepadlen : padlen(offset, 4)) < 0)
+ goto error;
+
+ if (size) {
+ this_read = copy_file_range(file, NULL, outfd, NULL, size, 0);
+ if (this_read > 0) {
+ if (this_read > size)
+ goto error;
+ offset += this_read;
+ size -= this_read;
+ }
+ /* short or failed copy falls back to read/write... */
+ }
+
+ while (size) {
+ unsigned char filebuf[65536];
+ size_t this_size = MIN(size, sizeof(filebuf));
+
+ this_read = read(file, filebuf, this_size);
+ if (this_read <= 0 || this_read > this_size) {
+ fprintf(stderr, "Can not read %s file\n", location);
+ goto error;
+ }
+
+ if (write(outfd, filebuf, this_read) != this_read) {
+ fprintf(stderr, "writing filebuf failed\n");
+ goto error;
+ }
+ offset += this_read;
+ size -= this_read;
+ }
+ if (push_pad(padlen(offset, 4)) < 0)
+ goto error;
+
+ name += namesize;
+ }
+ ino++;
+ rc = 0;
+
+error:
+ if (file >= 0)
+ close(file);
+ return rc;
+}
+
+static char *cpio_replace_env(char *new_location)
+{
+ char expanded[PATH_MAX + 1];
+ char *start, *end, *var;
+
+ while ((start = strstr(new_location, "${")) &&
+ (end = strchr(start + 2, '}'))) {
+ *start = *end = 0;
+ var = getenv(start + 2);
+ snprintf(expanded, sizeof expanded, "%s%s%s",
+ new_location, var ? var : "", end + 1);
+ strcpy(new_location, expanded);
+ }
+
+ return new_location;
+}
+
+static int cpio_mkfile_line(const char *line)
+{
+ char name[PATH_MAX + 1];
+ char *dname = NULL; /* malloc'ed buffer for hard links */
+ char location[PATH_MAX + 1];
+ unsigned int mode;
+ int uid;
+ int gid;
+ int nlinks = 1;
+ int end = 0, dname_len = 0;
+ int rc = -1;
+
+ if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
+ "s %o %d %d %n",
+ name, location, &mode, &uid, &gid, &end)) {
+ fprintf(stderr, "Unrecognized file format '%s'", line);
+ goto fail;
+ }
+ if (end && isgraph(line[end])) {
+ int len;
+ int nend;
+
+ dname = malloc(strlen(line));
+ if (!dname) {
+ fprintf (stderr, "out of memory (%d)\n", dname_len);
+ goto fail;
+ }
+
+ dname_len = strlen(name) + 1;
+ memcpy(dname, name, dname_len);
+
+ do {
+ nend = 0;
+ if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
+ name, &nend) < 1)
+ break;
+ len = strlen(name) + 1;
+ memcpy(dname + dname_len, name, len);
+ dname_len += len;
+ nlinks++;
+ end += nend;
+ } while (isgraph(line[end]));
+ } else {
+ dname = name;
+ }
+ rc = cpio_mkfile(dname, cpio_replace_env(location),
+ mode, uid, gid, nlinks);
+ fail:
+ if (dname_len) free(dname);
+ return rc;
+}
+
+static void usage(const char *prog)
+{
+ fprintf(stderr, "Usage:\n"
+ "\t%s [-t <timestamp>] [-c] [-o <output_file>] [-a <data_align>] <cpio_list>\n"
+ "\n"
+ "<cpio_list> is a file containing newline separated entries that\n"
+ "describe the files to be included in the initramfs archive:\n"
+ "\n"
+ "# a comment\n"
+ "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
+ "dir <name> <mode> <uid> <gid>\n"
+ "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
+ "slink <name> <target> <mode> <uid> <gid>\n"
+ "pipe <name> <mode> <uid> <gid>\n"
+ "sock <name> <mode> <uid> <gid>\n"
+ "\n"
+ "<name> name of the file/dir/nod/etc in the archive\n"
+ "<location> location of the file in the current filesystem\n"
+ " expands shell variables quoted with ${}\n"
+ "<target> link target\n"
+ "<mode> mode/permissions of the file\n"
+ "<uid> user id (0=root)\n"
+ "<gid> group id (0=root)\n"
+ "<dev_type> device type (b=block, c=character)\n"
+ "<maj> major number of nod\n"
+ "<min> minor number of nod\n"
+ "<hard links> space separated list of other links to file\n"
+ "\n"
+ "example:\n"
+ "# A simple initramfs\n"
+ "dir /dev 0755 0 0\n"
+ "nod /dev/console 0600 0 0 c 5 1\n"
+ "dir /root 0700 0 0\n"
+ "dir /sbin 0755 0 0\n"
+ "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+ "\n"
+ "<timestamp> is time in seconds since Epoch that will be used\n"
+ "as mtime for symlinks, directories, regular and special files.\n"
+ "The default is to use the current time for all files, but\n"
+ "preserve modification time for regular files.\n"
+ "-c: calculate and store 32-bit checksums for file data.\n"
+ "<output_file>: write cpio to this file instead of stdout\n"
+ "<data_align>: attempt to align file data by zero-padding the\n"
+ "filename field up to data_align. Must be a multiple of 4.\n"
+ "Alignment is best-effort; PATH_MAX limits filename padding.\n",
+ prog);
+}
+
+static const struct file_handler file_handler_table[] = {
+ {
+ .type = "file",
+ .handler = cpio_mkfile_line,
+ }, {
+ .type = "nod",
+ .handler = cpio_mknod_line,
+ }, {
+ .type = "dir",
+ .handler = cpio_mkdir_line,
+ }, {
+ .type = "slink",
+ .handler = cpio_mkslink_line,
+ }, {
+ .type = "pipe",
+ .handler = cpio_mkpipe_line,
+ }, {
+ .type = "sock",
+ .handler = cpio_mksock_line,
+ }, {
+ .type = NULL,
+ .handler = NULL,
+ }
+};
+
+#define LINE_SIZE (2 * PATH_MAX + 50)
+
+int main (int argc, char *argv[])
+{
+ FILE *cpio_list;
+ char line[LINE_SIZE];
+ char *args, *type;
+ int ec = 0;
+ int line_nr = 0;
+ const char *filename;
+
+ default_mtime = time(NULL);
+ while (1) {
+ int opt = getopt(argc, argv, "t:cho:a:");
+ char *invalid;
+
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 't':
+ default_mtime = strtol(optarg, &invalid, 10);
+ if (!*optarg || *invalid) {
+ fprintf(stderr, "Invalid timestamp: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ do_file_mtime = true;
+ break;
+ case 'c':
+ do_csum = true;
+ break;
+ case 'o':
+ outfd = open(optarg,
+ O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC,
+ 0600);
+ if (outfd < 0) {
+ fprintf(stderr, "failed to open %s\n", optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'a':
+ dalign = strtoul(optarg, &invalid, 10);
+ if (!*optarg || *invalid || (dalign & 3)) {
+ fprintf(stderr, "Invalid data_align: %s\n",
+ optarg);
+ usage(argv[0]);
+ exit(1);
+ }
+ break;
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ exit(opt == 'h' ? 0 : 1);
+ }
+ }
+
+ /*
+ * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
+ * representation that exceeds 8 chars and breaks the cpio header
+ * specification. Negative timestamps similarly exceed 8 chars.
+ */
+ if (default_mtime > 0xffffffff || default_mtime < 0) {
+ fprintf(stderr, "ERROR: Timestamp out of range for cpio format\n");
+ exit(1);
+ }
+
+ if (argc - optind != 1) {
+ usage(argv[0]);
+ exit(1);
+ }
+ filename = argv[optind];
+ if (!strcmp(filename, "-"))
+ cpio_list = stdin;
+ else if (!(cpio_list = fopen(filename, "r"))) {
+ fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
+ filename, strerror(errno));
+ usage(argv[0]);
+ exit(1);
+ }
+
+ while (fgets(line, LINE_SIZE, cpio_list)) {
+ int type_idx;
+ size_t slen = strlen(line);
+
+ line_nr++;
+
+ if ('#' == *line) {
+ /* comment - skip to next line */
+ continue;
+ }
+
+ if (! (type = strtok(line, " \t"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ break;
+ }
+
+ if ('\n' == *type) {
+ /* a blank line */
+ continue;
+ }
+
+ if (slen == strlen(type)) {
+ /* must be an empty line */
+ continue;
+ }
+
+ if (! (args = strtok(NULL, "\n"))) {
+ fprintf(stderr,
+ "ERROR: incorrect format, newline required line %d: '%s'\n",
+ line_nr, line);
+ ec = -1;
+ }
+
+ for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
+ int rc;
+ if (! strcmp(line, file_handler_table[type_idx].type)) {
+ if ((rc = file_handler_table[type_idx].handler(args))) {
+ ec = rc;
+ fprintf(stderr, " line %d\n", line_nr);
+ }
+ break;
+ }
+ }
+
+ if (NULL == file_handler_table[type_idx].type) {
+ fprintf(stderr, "unknown file type line %d: '%s'\n",
+ line_nr, line);
+ }
+ }
+ if (ec == 0)
+ ec = cpio_trailer();
+
+ exit(ec);
+}
diff --git a/usr/gen_initramfs.sh b/usr/gen_initramfs.sh
new file mode 100755
index 000000000..7eba2fddf
--- /dev/null
+++ b/usr/gen_initramfs.sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
+#
+# Released under the terms of the GNU GPL
+#
+# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
+# the cpio archive.
+# This script assumes that gen_init_cpio is located in usr/ directory
+
+# error out on errors
+set -e
+
+usage() {
+cat << EOF
+Usage:
+$0 [-o <file>] [-l <dep_list>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
+ -o <file> Create initramfs file named <file> by using gen_init_cpio
+ -l <dep_list> Create dependency list named <dep_list>
+ -u <uid> User ID to map to user ID 0 (root).
+ <uid> is only meaningful if <cpio_source> is a
+ directory. "squash" forces all files to uid 0.
+ -g <gid> Group ID to map to group ID 0 (root).
+ <gid> is only meaningful if <cpio_source> is a
+ directory. "squash" forces all files to gid 0.
+ -d <date> Use date for all file mtime values
+ <cpio_source> File list or directory for cpio archive.
+ If <cpio_source> is a .cpio file it will be used
+ as direct input to initramfs.
+
+All options except -o and -l may be repeated and are interpreted
+sequentially and immediately. -u and -g states are preserved across
+<cpio_source> options so an explicit "-u 0 -g 0" is required
+to reset the root/group mapping.
+EOF
+}
+
+# awk style field access
+# $1 - field number; rest is argument string
+field() {
+ shift $1 ; echo $1
+}
+
+filetype() {
+ local argv1="$1"
+
+ # symlink test must come before file test
+ if [ -L "${argv1}" ]; then
+ echo "slink"
+ elif [ -f "${argv1}" ]; then
+ echo "file"
+ elif [ -d "${argv1}" ]; then
+ echo "dir"
+ elif [ -b "${argv1}" -o -c "${argv1}" ]; then
+ echo "nod"
+ elif [ -p "${argv1}" ]; then
+ echo "pipe"
+ elif [ -S "${argv1}" ]; then
+ echo "sock"
+ else
+ echo "invalid"
+ fi
+ return 0
+}
+
+print_mtime() {
+ local my_mtime="0"
+
+ if [ -e "$1" ]; then
+ my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
+ fi
+
+ echo "# Last modified: ${my_mtime}" >> $cpio_list
+ echo "" >> $cpio_list
+}
+
+list_parse() {
+ if [ -z "$dep_list" -o -L "$1" ]; then
+ return
+ fi
+ echo "$1" | sed 's/:/\\:/g; s/$/ \\/' >> $dep_list
+}
+
+# for each file print a line in following format
+# <filetype> <name> <path to file> <octal mode> <uid> <gid>
+# for links, devices etc the format differs. See gen_init_cpio for details
+parse() {
+ local location="$1"
+ local name="/${location#${srcdir}}"
+ # change '//' into '/'
+ name=$(echo "$name" | sed -e 's://*:/:g')
+ local mode="$2"
+ local uid="$3"
+ local gid="$4"
+ local ftype=$(filetype "${location}")
+ # remap uid/gid to 0 if necessary
+ [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
+ [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
+ local str="${mode} ${uid} ${gid}"
+
+ [ "${ftype}" = "invalid" ] && return 0
+ [ "${location}" = "${srcdir}" ] && return 0
+
+ case "${ftype}" in
+ "file")
+ str="${ftype} ${name} ${location} ${str}"
+ ;;
+ "nod")
+ local dev="`LC_ALL=C ls -l "${location}"`"
+ local maj=`field 5 ${dev}`
+ local min=`field 6 ${dev}`
+ maj=${maj%,}
+
+ [ -b "${location}" ] && dev="b" || dev="c"
+
+ str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
+ ;;
+ "slink")
+ local target=`readlink "${location}"`
+ str="${ftype} ${name} ${target} ${str}"
+ ;;
+ *)
+ str="${ftype} ${name} ${str}"
+ ;;
+ esac
+
+ echo "${str}" >> $cpio_list
+
+ return 0
+}
+
+unknown_option() {
+ printf "ERROR: unknown option \"$arg\"\n" >&2
+ printf "If the filename validly begins with '-', " >&2
+ printf "then it must be prefixed\n" >&2
+ printf "by './' so that it won't be interpreted as an option." >&2
+ printf "\n" >&2
+ usage >&2
+ exit 1
+}
+
+header() {
+ printf "\n#####################\n# $1\n" >> $cpio_list
+}
+
+# process one directory (incl sub-directories)
+dir_filelist() {
+ header "$1"
+
+ srcdir=$(echo "$1" | sed -e 's://*:/:g')
+ dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LC_ALL=C sort)
+
+ # If $dirlist is only one line, then the directory is empty
+ if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+ print_mtime "$1"
+
+ echo "${dirlist}" | \
+ while read x; do
+ list_parse $x
+ parse $x
+ done
+ fi
+}
+
+input_file() {
+ source="$1"
+ if [ -f "$1" ]; then
+ # If a regular file is specified, assume it is in
+ # gen_init_cpio format
+ header "$1"
+ print_mtime "$1" >> $cpio_list
+ cat "$1" >> $cpio_list
+ if [ -n "$dep_list" ]; then
+ echo "$1 \\" >> $dep_list
+ cat "$1" | while read type dir file perm ; do
+ if [ "$type" = "file" ]; then
+ echo "$file \\" >> $dep_list
+ fi
+ done
+ fi
+ elif [ -d "$1" ]; then
+ # If a directory is specified then add all files in it to fs
+ dir_filelist "$1"
+ else
+ echo " ${prog}: Cannot open '$1'" >&2
+ exit 1
+ fi
+}
+
+prog=$0
+root_uid=0
+root_gid=0
+dep_list=
+timestamp=
+cpio_list=$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)
+# gen_init_cpio writes to stdout by default
+output=""
+
+trap "rm -f $cpio_list" EXIT
+
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ "-l") # files included in initramfs - used by kbuild
+ dep_list="$1"
+ echo "deps_initramfs := \\" > $dep_list
+ shift
+ ;;
+ "-o") # generate cpio image named $1
+ output="-o $1"
+ shift
+ ;;
+ "-u") # map $1 to uid=0 (root)
+ root_uid="$1"
+ [ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
+ shift
+ ;;
+ "-g") # map $1 to gid=0 (root)
+ root_gid="$1"
+ [ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
+ shift
+ ;;
+ "-d") # date for file mtimes
+ timestamp="$(date -d"$1" +%s || :)"
+ if test -n "$timestamp"; then
+ timestamp="-t $timestamp"
+ fi
+ shift
+ ;;
+ "-h")
+ usage
+ exit 0
+ ;;
+ *)
+ case "$arg" in
+ "-"*)
+ unknown_option
+ ;;
+ *) # input file/dir - process it
+ input_file "$arg"
+ ;;
+ esac
+ ;;
+ esac
+done
+
+# If output_file is set we will generate cpio archive
+# we are careful to delete tmp files
+usr/gen_init_cpio $output $timestamp $cpio_list
diff --git a/usr/include/.gitignore b/usr/include/.gitignore
new file mode 100644
index 000000000..17b0ba1bd
--- /dev/null
+++ b/usr/include/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+/*/
diff --git a/usr/include/Makefile b/usr/include/Makefile
new file mode 100644
index 000000000..ee69dd9d9
--- /dev/null
+++ b/usr/include/Makefile
@@ -0,0 +1,188 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Unlike the kernel space, exported headers are written in standard C.
+# - Forbid C++ style comments
+# - Use '__inline__', '__asm__' instead of 'inline', 'asm'
+#
+# -std=c90 (equivalent to -ansi) catches the violation of those.
+# We cannot go as far as adding -Wpedantic since it emits too many warnings.
+UAPI_CFLAGS := -std=c90 -Werror=implicit-function-declaration
+UAPI_ARCH := $(or $(HEADER_ARCH),$(SRCARCH))
+
+override c_flags = $(KBUILD_USERCFLAGS) $(UAPI_CFLAGS) -Wp,-MMD,$(depfile)
+cxx_flags = $(filter-out -Wmissing-prototypes -Wstrict-prototypes -std=%, $(KBUILD_USERCFLAGS)) -std=c++98
+
+# The following are excluded for now because they fail to build.
+#
+# Do not add a new header to the blacklist without legitimate reason.
+# Please consider to fix the header first.
+#
+# Sorted alphabetically.
+no-header-test += asm/ucontext.h
+no-header-test += drm/vmwgfx_drm.h
+no-header-test += linux/am437x-vpfe.h
+no-header-test += linux/coda.h
+no-header-test += linux/cyclades.h
+no-header-test += linux/errqueue.h
+no-header-test += linux/hdlc/ioctl.h
+no-header-test += linux/ivtv.h
+no-header-test += linux/matroxfb.h
+no-header-test += linux/omap3isp.h
+no-header-test += linux/omapfb.h
+no-header-test += linux/patchkey.h
+no-header-test += linux/phonet.h
+no-header-test += linux/sctp.h
+no-header-test += linux/sysctl.h
+no-header-test += linux/usb/audio.h
+no-header-test += linux/v4l2-mediabus.h
+no-header-test += linux/v4l2-subdev.h
+no-header-test += linux/videodev2.h
+no-header-test += linux/vm_sockets.h
+no-header-test += sound/asequencer.h
+no-header-test += sound/asoc.h
+no-header-test += sound/asound.h
+no-header-test += sound/compress_offload.h
+no-header-test += sound/emu10k1.h
+no-header-test += sound/sfnt_info.h
+no-header-test += xen/evtchn.h
+no-header-test += xen/gntdev.h
+no-header-test += xen/privcmd.h
+
+# More headers are broken in some architectures
+
+ifneq ($(filter arc openrisc xtensa nios2, $(UAPI_ARCH)),)
+no-header-test += linux/bpf_perf_event.h
+endif
+
+ifeq ($(UAPI_ARCH),sparc)
+no-header-test += asm/uctx.h
+no-header-test += asm/fbio.h
+endif
+
+# asm-generic/*.h is used by asm/*.h, and should not be included directly
+no-header-test += asm-generic/%
+
+# The following are not compatible with C++.
+#
+# Do not add a new header to the list without legitimate reason.
+# Please consider to fix the header first.
+#
+# Sorted alphabetically.
+no-header-test-cxx += linux/auto_dev-ioctl.h
+no-header-test-cxx += linux/map_to_14segment.h
+no-header-test-cxx += linux/map_to_7segment.h
+no-header-test-cxx += linux/netfilter/xt_sctp.h
+no-header-test-cxx += linux/target_core_user.h
+no-header-test-cxx += linux/vhost.h
+no-header-test-cxx += linux/vhost_types.h
+no-header-test-cxx += linux/virtio_net.h
+no-header-test-cxx += linux/virtio_ring.h
+no-header-test-cxx += scsi/fc/fc_els.h
+
+ifeq ($(UAPI_ARCH),x86)
+no-header-test-cxx += asm/elf.h
+endif
+
+# The following are using libc header and types.
+#
+# Do not add a new header to the list without legitimate reason.
+# Please consider to fix the header first.
+#
+# Sorted alphabetically.
+uses-libc += linux/a.out.h
+uses-libc += linux/atmbr2684.h
+uses-libc += linux/auto_dev-ioctl.h
+uses-libc += linux/auto_fs.h
+uses-libc += linux/auto_fs4.h
+uses-libc += linux/btrfs_tree.h
+uses-libc += linux/cec-funcs.h
+uses-libc += linux/cec.h
+uses-libc += linux/dvb/dmx.h
+uses-libc += linux/dvb/video.h
+uses-libc += linux/ethtool.h
+uses-libc += linux/ethtool_netlink.h
+uses-libc += linux/fuse.h
+uses-libc += linux/gsmmux.h
+uses-libc += linux/icmp.h
+uses-libc += linux/idxd.h
+uses-libc += linux/if.h
+uses-libc += linux/if_arp.h
+uses-libc += linux/if_bonding.h
+uses-libc += linux/if_pppox.h
+uses-libc += linux/if_tunnel.h
+uses-libc += linux/input.h
+uses-libc += linux/ip6_tunnel.h
+uses-libc += linux/joystick.h
+uses-libc += linux/llc.h
+uses-libc += linux/mctp.h
+uses-libc += linux/mdio.h
+uses-libc += linux/mii.h
+uses-libc += linux/mptcp.h
+uses-libc += linux/netdevice.h
+uses-libc += linux/netfilter/xt_RATEEST.h
+uses-libc += linux/netfilter/xt_hashlimit.h
+uses-libc += linux/netfilter/xt_physdev.h
+uses-libc += linux/netfilter/xt_rateest.h
+uses-libc += linux/netfilter_arp/arp_tables.h
+uses-libc += linux/netfilter_arp/arpt_mangle.h
+uses-libc += linux/netfilter_bridge.h
+uses-libc += linux/netfilter_bridge/ebtables.h
+uses-libc += linux/netfilter_ipv4.h
+uses-libc += linux/netfilter_ipv4/ip_tables.h
+uses-libc += linux/netfilter_ipv6.h
+uses-libc += linux/netfilter_ipv6/ip6_tables.h
+uses-libc += linux/route.h
+uses-libc += linux/shm.h
+uses-libc += linux/soundcard.h
+uses-libc += linux/string.h
+uses-libc += linux/tipc_config.h
+uses-libc += linux/uhid.h
+uses-libc += linux/uinput.h
+uses-libc += linux/vhost.h
+uses-libc += linux/vhost_types.h
+uses-libc += linux/virtio_ring.h
+uses-libc += linux/wireless.h
+uses-libc += regulator/regulator.h
+uses-libc += scsi/fc/fc_els.h
+
+ifeq ($(UAPI_ARCH),hexagon)
+uses-libc += asm/sigcontext.h
+endif
+
+ifeq ($(UAPI_ARCH),nios2)
+uses-libc += asm/ptrace.h
+endif
+
+ifeq ($(UAPI_ARCH),s390)
+uses-libc += asm/chpid.h
+uses-libc += asm/chsc.h
+endif
+
+always-y := $(patsubst $(obj)/%.h,%.hdrtest, $(shell find $(obj) -name '*.h' 2>/dev/null))
+
+# $(cc-option) forces '-x c' which breaks '-x c++' detection.
+cc-can-compile-cxx := $(call try-run,$(CC) $(CLANG_FLAGS) -c -x c++ /dev/null -o "$$TMP", 1)
+
+target-libc = $(filter $(uses-libc), $*.h)
+target-can-compile = $(filter-out $(no-header-test), $*.h)
+target-can-compile-cxx = $(and $(cc-can-compile-cxx), $(target-can-compile), $(filter-out $(no-header-test-cxx), $*.h))
+
+hdrtest-flags = -fsyntax-only -Werror \
+ -nostdinc -I $(obj) $(if $(target-libc), -I $(srctree)/usr/dummy-include)
+
+# Include the header twice to detect missing include guard.
+quiet_cmd_hdrtest = HDRTEST $<
+ cmd_hdrtest = \
+ $(CC) $(c_flags) $(hdrtest-flags) -x c /dev/null \
+ $(if $(target-can-compile), -include $< -include $<); \
+ $(if $(target-can-compile-cxx), \
+ $(CC) $(cxx_flags) $(hdrtest-flags) -x c++ /dev/null -include $<;) \
+ $(PERL) $(src)/headers_check.pl $(obj) $<; \
+ touch $@
+
+$(obj)/%.hdrtest: $(obj)/%.h $(src)/headers_check.pl FORCE
+ $(call if_changed_dep,hdrtest)
+
+# Since GNU Make 4.3, $(patsubst $(obj)/%/,%,$(wildcard $(obj)/*/)) works.
+# To support older Make versions, use a somewhat tedious way.
+clean-files += $(filter-out Makefile headers_check.pl, $(notdir $(wildcard $(obj)/*)))
diff --git a/usr/include/headers_check.pl b/usr/include/headers_check.pl
new file mode 100755
index 000000000..6cd6eb652
--- /dev/null
+++ b/usr/include/headers_check.pl
@@ -0,0 +1,96 @@
+#!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
+# headers_check.pl execute a number of trivial consistency checks
+#
+# Usage: headers_check.pl dir [files...]
+# dir: dir to look for included files
+# files: list of files to check
+#
+# The script reads the supplied files line by line and:
+#
+# 1) for each include statement it checks if the
+# included file actually exists.
+# Only include files located in asm* and linux* are checked.
+# The rest are assumed to be system include files.
+#
+# 2) It is checked that prototypes does not use "extern"
+#
+# 3) Check for leaked CONFIG_ symbols
+
+use warnings;
+use strict;
+use File::Basename;
+
+my ($dir, @files) = @ARGV;
+
+my $ret = 0;
+my $line;
+my $lineno = 0;
+my $filename;
+
+foreach my $file (@files) {
+ $filename = $file;
+
+ open(my $fh, '<', $filename)
+ or die "$filename: $!\n";
+ $lineno = 0;
+ while ($line = <$fh>) {
+ $lineno++;
+ &check_include();
+ &check_asm_types();
+ &check_declarations();
+ }
+ close $fh;
+}
+exit $ret;
+
+sub check_include
+{
+ if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
+ my $inc = $1;
+ my $found;
+ $found = stat($dir . "/" . $inc);
+ if (!$found) {
+ printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
+ $ret = 1;
+ }
+ }
+}
+
+sub check_declarations
+{
+ # soundcard.h is what it is
+ if ($line =~ m/^void seqbuf_dump\(void\);/) {
+ return;
+ }
+ # drm headers are being C++ friendly
+ if ($line =~ m/^extern "C"/) {
+ return;
+ }
+ if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
+ printf STDERR "$filename:$lineno: " .
+ "userspace cannot reference function or " .
+ "variable defined in the kernel\n";
+ $ret = 1;
+ }
+}
+
+my $linux_asm_types;
+sub check_asm_types
+{
+ if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
+ return;
+ }
+ if ($lineno == 1) {
+ $linux_asm_types = 0;
+ } elsif ($linux_asm_types >= 1) {
+ return;
+ }
+ if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
+ $linux_asm_types = 1;
+ printf STDERR "$filename:$lineno: " .
+ "include of <linux/types.h> is preferred over <asm/types.h>\n";
+ $ret = 1;
+ }
+}
diff --git a/usr/initramfs_data.S b/usr/initramfs_data.S
new file mode 100644
index 000000000..e92fb59b3
--- /dev/null
+++ b/usr/initramfs_data.S
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ initramfs_data includes the compressed binary that is the
+ filesystem used for early user space.
+ Note: Older versions of "as" (prior to binutils 2.11.90.0.23
+ released on 2001-07-14) did not support .incbin.
+ If you are forced to use older binutils than that then the
+ following trick can be applied to create the resulting binary:
+
+
+ ld -m elf_i386 --format binary --oformat elf32-i386 -r \
+ -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
+ ld -m elf_i386 -r -o built-in.a initramfs_data.o
+
+ For including the .init.ramfs sections, see include/asm-generic/vmlinux.lds.
+
+ The above example is for i386 - the parameters vary from architectures.
+ Eventually look up LDFLAGS_BLOB in an older version of the
+ arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
+
+ Using .incbin has the advantage over ld that the correct flags are set
+ in the ELF header, as required by certain architectures.
+*/
+
+.section .init.ramfs,"a"
+__irf_start:
+.incbin "usr/initramfs_inc_data"
+__irf_end:
+.section .init.ramfs.info,"a"
+.globl __initramfs_size
+__initramfs_size:
+#ifdef CONFIG_64BIT
+ .quad __irf_end - __irf_start
+#else
+ .long __irf_end - __irf_start
+#endif