aboutsummaryrefslogtreecommitdiff
path: root/Makefile
blob: 442dfae978400e2bc7bd1ee3e5d102d1f7b13683 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
ARCH=$(shell uname -m)
MEMORY ?= 128
NET_QEMU_TAP ?= linux-qemu-test
NET_BRIDGE ?= br0
NET_HWADDR ?= 66:66:66:66:66:66
KEYMAP ?= i386/qwertz/de-latin1
LINUX_LOCAL ?=
DEFCONFIG ?= n
NO_MODULES ?= n
USE_GDB ?= n

THIS_DIR=$(realpath .)

DL_DIR=$(THIS_DIR)/dl
BUILD_DIR=$(THIS_DIR)/build
ROOTFS_DIR=$(THIS_DIR)/rootfs
CFG_DIR=$(THIS_DIR)/config
SCRIPT_DIR=$(THIS_DIR)/scripts
SKEL_DIR=$(THIS_DIR)/skeleton

INITRD_TARGET=$(THIS_DIR)/initramfs.cpio.gz

LINUX_DL_PREFIX=https://cdn.kernel.org/pub/linux/kernel/v5.x
LINUX_DL_BASENAME=linux
LINUX_DL_VERSION=5.10.67
LINUX_DL_SUFFIX=tar.xz
LINUX_DL_URL=$(LINUX_DL_PREFIX)/$(LINUX_DL_BASENAME)-$(LINUX_DL_VERSION).$(LINUX_DL_SUFFIX)
LINUX_DL_FILE=$(DL_DIR)/$(LINUX_DL_BASENAME)-$(LINUX_DL_VERSION).$(LINUX_DL_SUFFIX)
LINUX_BUILD_DIR=$(BUILD_DIR)/$(LINUX_DL_BASENAME)-$(LINUX_DL_VERSION)
LINUX_TARGET=$(LINUX_BUILD_DIR)/vmlinux
LINUX_INSTALL_PREFIX=$(ROOTFS_DIR)/usr
LINUX_INSTALLED_MODULES=$(LINUX_INSTALL_PREFIX)/lib/modules
LINUX_INSTALLED_HEADERS=$(LINUX_INSTALL_PREFIX)/include/linux

MUSL_DL_PREFIX=https://www.musl-libc.org/releases
MUSL_DL_BASENAME=musl
MUSL_DL_VERSION=1.2.2
MUSL_DL_SUFFIX=tar.gz
MUSL_DL_URL=$(MUSL_DL_PREFIX)/$(MUSL_DL_BASENAME)-$(MUSL_DL_VERSION).$(MUSL_DL_SUFFIX)
MUSL_DL_FILE=$(DL_DIR)/$(MUSL_DL_BASENAME)-$(MUSL_DL_VERSION).$(MUSL_DL_SUFFIX)
MUSL_BUILD_DIR=$(BUILD_DIR)/$(MUSL_DL_BASENAME)-$(MUSL_DL_VERSION)
MUSL_TARGET=$(MUSL_BUILD_DIR)/lib/libc.so

BUSYBOX_DL_PREFIX=https://busybox.net/downloads
BUSYBOX_DL_BASENAME=busybox
BUSYBOX_DL_VERSION=1.34.0
BUSYBOX_DL_SUFFIX=tar.bz2
BUSYBOX_DL_URL=$(BUSYBOX_DL_PREFIX)/$(BUSYBOX_DL_BASENAME)-$(BUSYBOX_DL_VERSION).$(BUSYBOX_DL_SUFFIX)
BUSYBOX_DL_FILE=$(DL_DIR)/$(BUSYBOX_DL_BASENAME)-$(BUSYBOX_DL_VERSION).$(BUSYBOX_DL_SUFFIX)
BUSYBOX_BUILD_DIR=$(BUILD_DIR)/$(BUSYBOX_DL_BASENAME)-$(BUSYBOX_DL_VERSION)
BUSYBOX_CFLAGS=-I'$(ROOTFS_DIR)/usr/include' -specs '$(MUSL_BUILD_DIR)/lib/musl-gcc.specs'
BUSYBOX_LDFLAGS=-L$(ROOTFS_DIR)/lib
BUSYBOX_TARGET=$(BUSYBOX_BUILD_DIR)/busybox

all: pre dl extract build image
	@echo 'Finished.'

$(DL_DIR):
	mkdir -p '$@'
$(BUILD_DIR):
	mkdir -p '$@'
$(ROOTFS_DIR):
	mkdir -p '$@'
$(LINUX_BUILD_DIR):
	mkdir -p '$@'
$(MUSL_BUILD_DIR):
	mkdir -p '$@'
$(BUSYBOX_BUILD_DIR):
	mkdir -p '$@'

pre: $(DL_DIR) $(BUILD_DIR) $(ROOTFS_DIR) $(LINUX_BUILD_DIR) $(MUSL_BUILD_DIR) $(BUSYBOX_BUILD_DIR)

$(LINUX_DL_FILE):
ifeq ($(LINUX_LOCAL),)
	wget '$(LINUX_DL_URL)' -O '$@' || (rm -f '$(LINUX_DL_FILE)' && false)
	touch -a -m '$(LINUX_DL_FILE)'
endif

$(MUSL_DL_FILE):
	wget '$(MUSL_DL_URL)' -O '$@' || (rm -f '$(MUSL_DL_FILE)' && false)
	touch -a -m '$(MUSL_DL_FILE)'

$(BUSYBOX_DL_FILE):
	wget '$(BUSYBOX_DL_URL)' -O '$@' || (rm -f '$(BUSYBOX_DL_FILE)' && false)
	touch -a -m '$(BUSYBOX_DL_FILE)'

dl: pre $(LINUX_DL_FILE) $(MUSL_DL_FILE) $(BUSYBOX_DL_FILE)

$(LINUX_BUILD_DIR)/Makefile: $(LINUX_DL_FILE)
ifeq ($(LINUX_LOCAL),)
	tar --strip-components=1 -C '$(LINUX_BUILD_DIR)' -xvf '$(LINUX_DL_FILE)' >/dev/null || (rm -rf '$(LINUX_BUILD_DIR)' && false)
	touch -a -m '$(LINUX_BUILD_DIR)/Makefile'
else
	rmdir '$(LINUX_BUILD_DIR)'
	ln -s '$(LINUX_LOCAL)' '$(LINUX_BUILD_DIR)'
endif

$(MUSL_BUILD_DIR)/Makefile: $(MUSL_DL_FILE)
	tar --strip-components=1 -C '$(MUSL_BUILD_DIR)' -xvzf '$(MUSL_DL_FILE)' >/dev/null || (rm -rf '$(MUSL_BUILD_DIR)' && false)
	touch -a -m '$(MUSL_BUILD_DIR)/Makefile'

$(BUSYBOX_BUILD_DIR)/Makefile: $(BUSYBOX_DL_FILE)
	tar --strip-components=1 -C '$(BUSYBOX_BUILD_DIR)' -xvjf '$(BUSYBOX_DL_FILE)' >/dev/null || (rm -rf '$(BUSYBOX_BUILD_DIR)' && false)
	touch -a -m '$(BUSYBOX_BUILD_DIR)/Makefile'

extract: dl $(LINUX_BUILD_DIR)/Makefile $(MUSL_BUILD_DIR)/Makefile $(BUSYBOX_BUILD_DIR)/Makefile

$(LINUX_TARGET): $(LINUX_BUILD_DIR)/Makefile
	cp -v '$(CFG_DIR)/linux.config' '$(LINUX_BUILD_DIR)/.config'
ifneq ($(DEFCONFIG),y)
	$(MAKE) -C '$(LINUX_BUILD_DIR)' oldconfig
else
	$(MAKE) -C '$(LINUX_BUILD_DIR)' x86_64_defconfig
endif
	-$(MAKE) -C '$(LINUX_BUILD_DIR)' kvm_guest.config
	$(MAKE) -C '$(LINUX_BUILD_DIR)' ARCH='$(ARCH)' bzImage

$(LINUX_INSTALLED_MODULES): $(LINUX_TARGET)
ifneq ($(NO_MODULES),y)
	$(MAKE) -C '$(LINUX_BUILD_DIR)' ARCH='$(ARCH)' INSTALL_MOD_PATH='$(ROOTFS_DIR)/usr' modules
	$(MAKE) -C '$(LINUX_BUILD_DIR)' ARCH='$(ARCH)' INSTALL_MOD_PATH='$(ROOTFS_DIR)/usr' modules_install
endif

$(LINUX_INSTALLED_HEADERS): $(LINUX_TARGET)
	$(MAKE) -C '$(LINUX_BUILD_DIR)' ARCH='$(ARCH)' INSTALL_HDR_PATH='$(ROOTFS_DIR)/usr' headers_install

$(MUSL_TARGET): $(LINUX_INSTALLED_HEADERS)
	rm -f $(MUSL_TARGET)
	cd '$(MUSL_BUILD_DIR)' && (test -r ./config.mak || ./configure --prefix='$(ROOTFS_DIR)/usr' --enable-wrapper=yes)
	$(MAKE) -C '$(MUSL_BUILD_DIR)' ARCH='$(ARCH)' V=1 all
	$(MAKE) -C '$(MUSL_BUILD_DIR)' ARCH='$(ARCH)' install
	test -e '$(ROOTFS_DIR)/lib' || ln -sr '$(ROOTFS_DIR)/usr/lib' '$(ROOTFS_DIR)/lib'
	test -e '$(ROOTFS_DIR)/lib/ld-musl-$(ARCH).so.1' || ln -sr '$(ROOTFS_DIR)/lib/libc.so' '$(ROOTFS_DIR)/lib/ld-musl-$(ARCH).so.1'
	rm '$(ROOTFS_DIR)/usr/bin/musl-gcc' '$(ROOTFS_DIR)/lib/musl-gcc.specs'

$(BUSYBOX_TARGET): $(MUSL_TARGET) $(LINUX_INSTALLED_HEADERS)
	cp -v '$(CFG_DIR)/busybox.config' '$(BUSYBOX_BUILD_DIR)/.config'
ifneq ($(DEFCONFIG),y)
	$(MAKE) -C '$(BUSYBOX_BUILD_DIR)' oldconfig
else
	$(MAKE) -C '$(BUSYBOX_BUILD_DIR)' defconfig
endif
	test -r '$(MUSL_BUILD_DIR)/lib/musl-gcc.specs'
	sed -i 's,^\(CONFIG_EXTRA_CFLAGS[ ]*=\).*,\1"$(BUSYBOX_CFLAGS)",g'   '$(BUSYBOX_BUILD_DIR)/.config'
	sed -i 's,^\(CONFIG_EXTRA_LDFLAGS[ ]*=\).*,\1"$(BUSYBOX_LDFLAGS)",g' '$(BUSYBOX_BUILD_DIR)/.config'
	sed -i 's,^\(CONFIG_PREFIX[ ]*=\).*,\1"$(ROOTFS_DIR)",g'             '$(BUSYBOX_BUILD_DIR)/.config'
	$(MAKE) -C '$(BUSYBOX_BUILD_DIR)' ARCH='$(ARCH)' V=1 all
	$(MAKE) -C '$(BUSYBOX_BUILD_DIR)' ARCH='$(ARCH)' install

build: extract $(LINUX_TARGET) $(LINUX_INSTALLED_MODULES) $(MUSL_TARGET) $(BUSYBOX_TARGET)

$(INITRD_TARGET): $(LINUX_TARGET) $(LINUX_INSTALLED_MODULES) $(MUSL_TARGET) $(BUSYBOX_TARGET)
	cp -rfvTp '$(SKEL_DIR)'           '$(ROOTFS_DIR)'
	cd '$(ROOTFS_DIR)' && find . -print0 | cpio --owner 0:0 --null -ov --format=newc | gzip -9 > '$(INITRD_TARGET)'

image: build $(INITRD_TARGET)

force-remove:
	rm -f $(LINUX_TARGET) $(MUSL_TARGET) $(BUSYBOX_TARGET)
	rm -rf $(LINUX_INSTALLED_HEADERS) $(LINUX_INSTALLED_MODULES)
	rm -f '$(INITRD_TARGET)'

image-rebuild: force-remove
	rm -rf '$(ROOTFS_DIR)'
	$(MAKE) image

image-repack:
	rm -f '$(INITRD_TARGET)'
	$(MAKE) image

net:
	sudo ip tuntap add $(NET_QEMU_TAP) mode tap
	sudo ip link set dev $(NET_QEMU_TAP) up
	sudo ip link set dev $(NET_QEMU_TAP) master $(NET_BRIDGE)

net-clean:
	sudo ip link delete $(NET_QEMU_TAP)

ifeq ($(USE_GDB),y)
QEMU_ARGS += -s -S
endif

qemu-gdb-connect:
	gdb -s '$(LINUX_BUILD_DIR)/vmlinux' -x ./qemu-gdb.cmds

qemu: image
	qemu-system-$(ARCH) -kernel '$(LINUX_BUILD_DIR)/arch/$(ARCH)/boot/bzImage' -initrd '$(INITRD_TARGET)' \
		-enable-kvm -m $(MEMORY) -vga qxl -display sdl \
		-append 'nokaslr keymap=$(KEYMAP)' $(QEMU_ARGS)

qemu-console: image
	qemu-system-$(ARCH) -kernel '$(LINUX_BUILD_DIR)/arch/$(ARCH)/boot/bzImage' -initrd '$(INITRD_TARGET)' \
		-enable-kvm -m $(MEMORY) -curses \
		-append 'nokaslr keymap=$(KEYMAP)' $(QEMU_ARGS)

qemu-serial: image
	qemu-system-$(ARCH) -kernel '$(LINUX_BUILD_DIR)/arch/$(ARCH)/boot/bzImage' -initrd '$(INITRD_TARGET)' \
		-enable-kvm -m $(MEMORY) -nographic \
		-append 'nokaslr console=ttyS0 keymap=$(KEYMAP)' $(QEMU_ARGS)

qemu-serial-net: image
	qemu-system-$(ARCH) -kernel '$(LINUX_BUILD_DIR)/arch/$(ARCH)/boot/bzImage' -initrd '$(INITRD_TARGET)' \
		-enable-kvm -m $(MEMORY) -nographic \
		-net nic,macaddr=$(NET_HWADDR) -net tap,ifname=$(NET_QEMU_TAP),br=$(NET_BRIDGE),script=no,downscript=no \
		-append 'nokaslr net console=ttyS0 keymap=$(KEYMAP)' \
		$(QEMU_ARGS)

qemu-net: image
	qemu-system-$(ARCH) -kernel '$(LINUX_BUILD_DIR)/arch/$(ARCH)/boot/bzImage' -initrd '$(INITRD_TARGET)' \
		-enable-kvm -m $(MEMORY) -vga qxl -display sdl \
		-net nic,macaddr=$(NET_HWADDR) -net tap,ifname=$(NET_QEMU_TAP),br=$(NET_BRIDGE),script=no,downscript=no \
		-append 'nokaslr net keymap=$(KEYMAP)' $(QEMU_ARGS)

define HELP_PREFIX
	@printf '%*s%-10s - %s\n' '20' '$1' '' '$2'
endef

define HELP_PREFIX_OPTS
	@printf '%*s%-10s - %s\n' '30' '$1' '' '$2'
endef

help:
	@echo 'Available Makefile targets are:'
	$(call HELP_PREFIX,all,do all steps required for a working bzImage/initramfs)
	$(call HELP_PREFIX,pre,all pre requirements)
	$(call HELP_PREFIX,dl,download all sources)
	$(call HELP_PREFIX,extract,extract all sources)
	$(call HELP_PREFIX,build,build LinuxKernel/musl/BusyBox)
	$(call HELP_PREFIX,force-remove,remove linux/musl/busybox and initramfs targets)
	$(call HELP_PREFIX,image,create initramfs cpio archive)
	$(call HELP_PREFIX,image-rebuild,force recreation of rootfs)
	$(call HELP_PREFIX,image-repack,force initramfs cpio archive recreation)
	$(call HELP_PREFIX,net,prepare your network bridge for use with QEMU)
	$(call HELP_PREFIX,net-clean,undo `make net`)
	$(call HELP_PREFIX,qemu,test your kernel/initramfs combination with QEMU)
	$(call HELP_PREFIX,qemu-console,test your kernel/initramfs combination with [n]curses QEMU)
	$(call HELP_PREFIX,qemu-serial,test your kernel/initramfs combination using a serial console with QEMU)
	$(call HELP_PREFIX,qemu-serial-net,test your kernel/initramfs combination using a serial console and network support with QEMU)
	$(call HELP_PREFIX,qemu-net,test your kernel/initramfs combination with QEMU and network support through TAP)
	@echo
	@echo -e '\tAdditional make options:'
	$(call HELP_PREFIX_OPTS,USE_GDB=$(USE_GDB),start QEMU with debugging capabilities enabled)
	$(call HELP_PREFIX_OPTS,NO_MODULES=$(NO_MODULES),neither build nor install kernel modules)
	$(call HELP_PREFIX_OPTS,MEMORY=$(MEMORY),set the RAM size for QEMU in MBytes)
	$(call HELP_PREFIX_OPTS,NET_QEMU_TAP=$(NET_QEMU_TAP),set the ifname which QEMU will use as TAP device (run `make net` before))
	$(call HELP_PREFIX_OPTS,NET_BRIDGE=$(NET_BRIDGE),set your host network bridge interface)
	$(call HELP_PREFIX_OPTS,NET_HWADDR=$(NET_HWADDR),set mac address for the qemu guest)
	$(call HELP_PREFIX_OPTS,KEYMAP=$(KEYMAP),set a keymap which the init script tries to load)
	$(call HELP_PREFIX_OPTS,LINUX_LOCAL=$(LINUX_LOCAL),set a custom linux source directory)
	$(call HELP_PREFIX_OPTS,DEFCONFIG=$(DEFCONFIG),use linux `make defconfig` instead of `make oldconfig`)

.PHONY: all pre dl extract build image image-rebuild image-repack net qemu qemu-console qemu-serial qemu-serial-net qemu-net help