1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0+
3#
4# Create an initrd directory if one does not already exist.
5#
6# Copyright (C) IBM Corporation, 2013
7#
8# Author: Connor Shu <Connor.Shu@ibm.com>
9
10D=tools/testing/selftests/rcutorture
11
12# Prerequisite checks
13[ -z "$D" ] && echo >&2 "No argument supplied" && exit 1
14if [ ! -d "$D" ]; then
15    echo >&2 "$D does not exist: Malformed kernel source tree?"
16    exit 1
17fi
18if [ -s "$D/initrd/init" ]; then
19    echo "$D/initrd/init already exists, no need to create it"
20    exit 0
21fi
22
23T=${TMPDIR-/tmp}/mkinitrd.sh.$$
24trap 'rm -rf $T' 0 2
25mkdir $T
26
27cat > $T/init << '__EOF___'
28#!/bin/sh
29# Run in userspace a few milliseconds every second.  This helps to
30# exercise the NO_HZ_FULL portions of RCU.  The 192 instances of "a" was
31# empirically shown to give a nice multi-millisecond burst of user-mode
32# execution on a 2GHz CPU, as desired.  Modern CPUs will vary from a
33# couple of milliseconds up to perhaps 100 milliseconds, which is an
34# acceptable range.
35#
36# Why not calibrate an exact delay?  Because within this initrd, we
37# are restricted to Bourne-shell builtins, which as far as I know do not
38# provide any means of obtaining a fine-grained timestamp.
39
40a4="a a a a"
41a16="$a4 $a4 $a4 $a4"
42a64="$a16 $a16 $a16 $a16"
43a192="$a64 $a64 $a64"
44while :
45do
46	q=
47	for i in $a192
48	do
49		q="$q $i"
50	done
51	sleep 1
52done
53__EOF___
54
55# Try using dracut to create initrd
56if command -v dracut >/dev/null 2>&1
57then
58	echo Creating $D/initrd using dracut.
59	# Filesystem creation
60	dracut --force --no-hostonly --no-hostonly-cmdline --module "base" $T/initramfs.img
61	cd $D
62	mkdir -p initrd
63	cd initrd
64	zcat $T/initramfs.img | cpio -id
65	cp $T/init init
66	chmod +x init
67	echo Done creating $D/initrd using dracut
68	exit 0
69fi
70
71# No dracut, so create a C-language initrd/init program and statically
72# link it.  This results in a very small initrd, but might be a bit less
73# future-proof than dracut.
74echo "Could not find dracut, attempting C initrd"
75cd $D
76mkdir -p initrd
77cd initrd
78cat > init.c << '___EOF___'
79#ifndef NOLIBC
80#include <unistd.h>
81#include <sys/time.h>
82#endif
83
84volatile unsigned long delaycount;
85
86int main(int argc, int argv[])
87{
88	int i;
89	struct timeval tv;
90	struct timeval tvb;
91
92	for (;;) {
93		sleep(1);
94		/* Need some userspace time. */
95		if (gettimeofday(&tvb, NULL))
96			continue;
97		do {
98			for (i = 0; i < 1000 * 100; i++)
99				delaycount = i * i;
100			if (gettimeofday(&tv, NULL))
101				break;
102			tv.tv_sec -= tvb.tv_sec;
103			if (tv.tv_sec > 1)
104				break;
105			tv.tv_usec += tv.tv_sec * 1000 * 1000;
106			tv.tv_usec -= tvb.tv_usec;
107		} while (tv.tv_usec < 1000);
108	}
109	return 0;
110}
111___EOF___
112
113# build using nolibc on supported archs (smaller executable) and fall
114# back to regular glibc on other ones.
115if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \
116           "||__ARM_EABI__||__aarch64__\nyes\n#endif" \
117   | ${CROSS_COMPILE}gcc -E -nostdlib -xc - \
118   | grep -q '^yes'; then
119	# architecture supported by nolibc
120        ${CROSS_COMPILE}gcc -fno-asynchronous-unwind-tables -fno-ident \
121		-nostdlib -include ../../../../include/nolibc/nolibc.h \
122		-lgcc -s -static -Os -o init init.c
123else
124	${CROSS_COMPILE}gcc -s -static -Os -o init init.c
125fi
126
127rm init.c
128echo "Done creating a statically linked C-language initrd"
129
130exit 0
131