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