CROSS_COMPILE ?= riscv64-unknown-linux-gnu-
ARCH := riscv

LINUX_SRC ?= /home/bjlab/zhangyan/ysyx-workbench/linux-stable
BUILD_DIR := $(CURDIR)/build
LINUX_OUT := $(BUILD_DIR)/linux
LINUX_FRAGMENT_GEN := $(BUILD_DIR)/linux-npc.generated.fragment

INIT_SRCS := $(CURDIR)/start.S $(CURDIR)/init.c
HELLO_SRCS := $(CURDIR)/hello_stage1.c
HELLO_BIN := $(BUILD_DIR)/hello
INIT_BIN := $(BUILD_DIR)/init
INITRAMFS_LIST := $(CURDIR)/initramfs.list
MUSL_DYN_SRCS := $(CURDIR)/musl_dyn_init.c
MUSL_DYN_BIN := $(BUILD_DIR)/musl-dyn-init
MUSL_DYN_INITRAMFS_LIST := $(CURDIR)/musl-dyn-initramfs.list
SOFTBOX_SRCS := $(CURDIR)/softbox_init.c
SOFTBOX_BIN := $(BUILD_DIR)/softbox-init
DEBIAN_STAGE2_SRCS := $(CURDIR)/debian_stage2.c
DEBIAN_STAGE2_BIN := $(BUILD_DIR)/debian-stage2
SOFTBOX_INITRAMFS_LIST := $(CURDIR)/softbox-initramfs.list
SOFTBOX_SUPPORT_FILES := $(CURDIR)/softbox-issue.txt \
	$(CURDIR)/softbox-os-release.txt \
	$(CURDIR)/softbox-debian-version.txt \
	$(CURDIR)/softbox-hostname.txt \
	$(CURDIR)/softbox-init.rc \
	$(CURDIR)/softbox-passwd.txt \
	$(CURDIR)/softbox-group.txt \
	$(CURDIR)/softbox-motd.txt \
	$(CURDIR)/softbox-profile.sh \
	$(CURDIR)/softbox-fstab.txt \
	$(CURDIR)/softbox-inittab.txt
LINUX_FRAGMENT := $(CURDIR)/linux-npc.fragment
LINUX_IMAGE := $(LINUX_OUT)/arch/riscv/boot/Image
LINUX_CONFIG_BASE ?= allnoconfig
ROOTFS_MODE ?= hello
INITRAMFS_LIST_OVERRIDE ?=
KERNEL_CMDLINE ?= earlycon=sbi keep_bootcon console=hvc0 rdinit=/init loglevel=4

BUSYBOX_SRC ?= /home/bjlab/zhangyan/ysyx-workbench/npc/busybox-src
BUSYBOX_MINI_CONFIG := $(CURDIR)/busybox-min.config
BUSYBOX_INITRAMFS_LIST := $(CURDIR)/busybox-initramfs.list
BUSYBOX_INIT_SCRIPT := $(CURDIR)/busybox-init.sh
BUSYBOX_BIN := $(BUILD_DIR)/busybox
BUSYBOX_CROSS_COMPILE ?= /home/bjlab/zhangyan/toolchains/riscv32-ilp32d--musl--stable-2024.05-1/bin/riscv32-buildroot-linux-musl-
MUSL_CROSS_COMPILE ?= /home/bjlab/zhangyan/toolchains/riscv32-ilp32d--musl--stable-2024.05-1/bin/riscv32-linux-
NOLIBC_SELFTESTS ?= $(LINUX_SRC)/tools/testing/selftests/nolibc
NOLIBC_SYSROOT_DIR := $(NOLIBC_SELFTESTS)/sysroot/riscv/include
NOLIBC_CC ?= riscv64-unknown-elf-gcc
NOLIBC_GCC_INCLUDE := $(shell $(NOLIBC_CC) -print-file-name=include)

INIT_CFLAGS := -march=rv32im_zicsr_zifencei -mabi=ilp32 -nostdlib -nostartfiles \
	-ffreestanding -fno-pic -static -Os
INIT_LDFLAGS := -Wl,-e,_start -Wl,-static
RV32_LINUX_CFLAGS := -march=rv32im_zicsr_zifencei -mabi=ilp32
MUSL_DYN_CFLAGS := -O2
SOFTBOX_CFLAGS := -march=rv32im_zicsr_zifencei -mabi=ilp32 -Os \
	-fno-ident -fno-asynchronous-unwind-tables -fno-stack-protector \
	-ffreestanding -fno-builtin \
	-nostdlib -nostdinc -static \
	-isystem $(NOLIBC_GCC_INCLUDE) \
	-I $(NOLIBC_SYSROOT_DIR) -include $(NOLIBC_SYSROOT_DIR)/nolibc.h

LINUX_MAKE := $(MAKE) -C $(LINUX_SRC) O=$(LINUX_OUT) ARCH=$(ARCH) \
	CROSS_COMPILE=$(CROSS_COMPILE)

ROOTFS_SOURCE := $(strip $(if $(INITRAMFS_LIST_OVERRIDE),$(INITRAMFS_LIST_OVERRIDE),\
	$(if $(filter softbox,$(ROOTFS_MODE)),$(SOFTBOX_INITRAMFS_LIST),\
	$(if $(filter busybox,$(ROOTFS_MODE)),$(BUSYBOX_INITRAMFS_LIST),\
	$(if $(filter musl-dyn,$(ROOTFS_MODE)),$(MUSL_DYN_INITRAMFS_LIST),\
	$(INITRAMFS_LIST))))))
ROOTFS_DEPS := $(if $(filter softbox,$(ROOTFS_MODE)),$(SOFTBOX_BIN) $(HELLO_BIN) $(DEBIAN_STAGE2_BIN) $(SOFTBOX_INITRAMFS_LIST) $(SOFTBOX_SUPPORT_FILES),\
	$(if $(filter busybox,$(ROOTFS_MODE)),$(BUSYBOX_BIN) $(HELLO_BIN) $(INIT_BIN),\
	$(if $(filter musl-dyn,$(ROOTFS_MODE)),$(MUSL_DYN_BIN),\
	$(HELLO_BIN) $(INIT_BIN))))

.PHONY: all hello init busybox softbox busybox-config image image-hello image-busybox \
	image-musl-dyn image-softbox image-softbox-sbin-init kernel-config clean FORCE

all: image

$(BUILD_DIR):
	mkdir -p $@

$(LINUX_OUT):
	mkdir -p $@

hello: $(HELLO_BIN)

init: $(INIT_BIN)

busybox: $(BUSYBOX_BIN)

softbox: $(SOFTBOX_BIN)

debian-stage2: $(DEBIAN_STAGE2_BIN)

$(HELLO_BIN): $(HELLO_SRCS) $(BUILD_DIR)/.nolibc-sysroot.stamp | $(BUILD_DIR)
	$(NOLIBC_CC) $(SOFTBOX_CFLAGS) -o $@ $< -lgcc

$(INIT_BIN): $(INIT_SRCS) | $(BUILD_DIR)
	$(CROSS_COMPILE)gcc $(INIT_CFLAGS) $(INIT_LDFLAGS) -o $@ $(INIT_SRCS)

$(MUSL_DYN_BIN): $(MUSL_DYN_SRCS) | $(BUILD_DIR)
	$(MUSL_CROSS_COMPILE)gcc $(MUSL_DYN_CFLAGS) -o $@ $<

$(BUILD_DIR)/.nolibc-sysroot.stamp: | $(BUILD_DIR)
	$(MAKE) -C $(NOLIBC_SELFTESTS) ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- CC=$(NOLIBC_CC) sysroot
	touch $@

$(SOFTBOX_BIN): $(SOFTBOX_SRCS) $(BUILD_DIR)/.nolibc-sysroot.stamp | $(BUILD_DIR)
	$(NOLIBC_CC) $(SOFTBOX_CFLAGS) -o $@ $< -lgcc

$(DEBIAN_STAGE2_BIN): $(DEBIAN_STAGE2_SRCS) $(BUILD_DIR)/.nolibc-sysroot.stamp | $(BUILD_DIR)
	$(NOLIBC_CC) $(SOFTBOX_CFLAGS) -o $@ $< -lgcc

$(BUSYBOX_BIN): $(BUSYBOX_MINI_CONFIG) | $(BUILD_DIR)
	$(MAKE) -C $(BUSYBOX_SRC) distclean
	$(MAKE) -C $(BUSYBOX_SRC) allnoconfig
	while IFS= read -r line; do \
		test -n "$$line" || continue; \
		sym="$${line%%=*}"; \
		val="$${line#*=}"; \
		sed -i \
			-e "s/^# $$sym is not set/$$sym=$$val/" \
			-e "s/^$$sym=.*/$$sym=$$val/" \
			$(BUSYBOX_SRC)/.config; \
	done < $(BUSYBOX_MINI_CONFIG)
	cd $(BUSYBOX_SRC) && yes "" | $(MAKE) oldconfig
	$(MAKE) -C $(BUSYBOX_SRC) -j$$(nproc) ARCH=$(ARCH) CROSS_COMPILE=$(BUSYBOX_CROSS_COMPILE)
	cp $(BUSYBOX_SRC)/busybox $@

$(LINUX_FRAGMENT_GEN): $(LINUX_FRAGMENT) $(CURDIR)/Makefile FORCE | $(BUILD_DIR)
	sed -e '/^CONFIG_INITRAMFS_SOURCE=/d' \
	    -e '/^CONFIG_CMDLINE=/d' $< > $@
	printf 'CONFIG_INITRAMFS_SOURCE="%s"\n' "$(ROOTFS_SOURCE)" >> $@
	printf 'CONFIG_CMDLINE="%s"\n' "$(KERNEL_CMDLINE)" >> $@

FORCE:

kernel-config: $(ROOTFS_DEPS) $(LINUX_FRAGMENT_GEN) | $(LINUX_OUT)
ifeq ($(LINUX_CONFIG_BASE),allnoconfig)
	env KCONFIG_ALLCONFIG=$(LINUX_FRAGMENT_GEN) $(LINUX_MAKE) allnoconfig
else
	$(LINUX_MAKE) $(LINUX_CONFIG_BASE)
	$(LINUX_SRC)/scripts/kconfig/merge_config.sh -m -O $(LINUX_OUT) \
		$(LINUX_OUT)/.config $(LINUX_FRAGMENT_GEN)
	$(LINUX_MAKE) olddefconfig
endif

image: kernel-config
	$(LINUX_MAKE) -j$$(nproc) Image

image-hello:
	$(MAKE) ROOTFS_MODE=hello image

image-busybox:
	$(MAKE) ROOTFS_MODE=busybox image

image-musl-dyn:
	$(MAKE) ROOTFS_MODE=musl-dyn image

image-softbox:
	$(MAKE) ROOTFS_MODE=softbox image

image-softbox-sbin-init:
	$(MAKE) ROOTFS_MODE=softbox \
		KERNEL_CMDLINE="earlycon=sbi keep_bootcon console=hvc0 rdinit=/sbin/init loglevel=4" \
		image

clean:
	rm -rf $(BUILD_DIR)
