ARTIFACTS_PATH ?= bin
IMAGE_NAME ?= CappuccinOS.iso
ISO_PARTITION_TYPE ?= GPT
MODE ?= release
ARCH ?= x86_64
MEMORY ?= 512M
# In MB
ISO_SIZE ?= 512
QEMU_OPTS ?= 
MKSQUASHFS_OPTS ?= 
GDB ?= 
CPUS ?= 1
# FAT type
ESP_BITS ?= 32
EXPORT_SYMBOLS = true

ISO_PATH = ${ARTIFACTS_PATH}/iso_root
INITRAMFS_PATH = ${ARTIFACTS_PATH}/initramfs
IMAGE_PATH = ${ARTIFACTS_PATH}/${IMAGE_NAME}
CARGO_OPTS = --target=src/arch/${ARCH}/${ARCH}-unknown-none.json
QEMU_OPTS += -m ${MEMORY} -drive id=hd0,format=raw,file=${IMAGE_PATH}
LIMINE_BOOT_VARIATION = X64
LIMINE_BRANCH = v8.x-binary

KERNEL_FILE = target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf

ifeq (${MODE},release)
	CARGO_OPTS += --release
endif

ifneq (${CPUS},1)
	QEMU_OPTS += -smp ${CPUS}
endif

ifneq (${GDB},)
	QEMU_OPTS += -s -S
endif

ifeq (${ARCH},riscv64)
	LIMINE_BOOT_VARIATION := RISCV64
	UEFI := true
endif

ifeq (${ARCH},aarch64)
	LIMINE_BOOT_VARIATION := AA64
	UEFI := true
endif

ifneq (${UEFI},)
	RUN_OPTS := ovmf-${ARCH}
	ifeq (${ARCH},riscv64)
		QEMU_OPTS += -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-riscv64/OVMF.fd -M virt
	else ifeq (${ARCH},aarch64)
		QEMU_OPTS += -M virt -bios ovmf/ovmf-${ARCH}/OVMF.fd
	else
		QEMU_OPTS += -bios ovmf/ovmf-${ARCH}/OVMF.fd
	endif
endif

.PHONY: all build

all: build

build: prepare-bin-files compile-bootloader compile-binaries run-scripts compile-initramfs build-iso

check: 
		cargo check

prepare-bin-files:
		# Remove ISO and everything in the bin directory
		rm -f ${IMAGE_PATH}
		rm -rf ${ARTIFACTS_PATH}/*

		# Make bin/ bin/iso_root and bin/initramfs
		mkdir -p ${ARTIFACTS_PATH}
		mkdir -p ${ISO_PATH}
		mkdir -p ${INITRAMFS_PATH}
		mkdir -p ${ARTIFACTS_PATH}/mnt

copy-initramfs-files:
		echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt
		echo "Second file for testing" > ${INITRAMFS_PATH}/example2.txt
		mkdir -p ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/
		mkdir ${INITRAMFS_PATH}/mnt/
		echo "Nexted file reads!!" > ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/yeah.txt

compile-initramfs: copy-initramfs-files
		# Make squashfs without compression temporaily so I can get it working before I have to write a gzip driver
		mksquashfs ${INITRAMFS_PATH} ${ARTIFACTS_PATH}/initramfs.img ${MKSQUASHFS_OPTS}

run-scripts:
		# Place the build ID into the binary so it can be read at runtime
		@HASH=$$(md5sum ${KERNEL_FILE} | cut -c1-12) && \
		sed -i "s/__BUILD_ID__/$${HASH}/" ${KERNEL_FILE}

ifeq (${EXPORT_SYMBOLS},true)
		nm ${KERNEL_FILE} > scripts/symbols.table
		@if [ ! -d "scripts/rustc_demangle" ]; then \
			git clone "https://github.com/juls0730/rustc_demangle.py" "scripts/rustc_demangle"; \
		fi
		python scripts/demangle-symbols.py
		mv scripts/symbols.table ${INITRAMFS_PATH}/
endif

		python scripts/font.py
		mv scripts/font.psf ${INITRAMFS_PATH}/

		#python scripts/initramfs-test.py 100 ${INITRAMFS_PATH}/

copy-iso-files:
		# Limine files
		mkdir -p ${ISO_PATH}/boot/limine
		mkdir -p ${ISO_PATH}/EFI/BOOT

		mkdir -p ${ISO_PATH}/mnt

		cp -v limine.conf limine/limine-bios.sys ${ISO_PATH}/boot/limine
		cp -v limine/BOOT${LIMINE_BOOT_VARIATION}.EFI ${ISO_PATH}/EFI/BOOT/

		# OS files
		cp -v target/${ARCH}-unknown-none/${MODE}/CappuccinOS.elf ${ISO_PATH}/boot
		cp -v ${ARTIFACTS_PATH}/initramfs.img ${ISO_PATH}/boot

		# Application files
		mkdir -p ${ISO_PATH}/bin
		basename -s .rs src/bin/*.rs | xargs -I {} \
			cp target/${ARCH}-unknown-none/${MODE}/{}.elf ${ISO_PATH}/bin/{}

		touch ${ISO_PATH}/example.txt
		echo "Hello World from the hard drive" > ${ISO_PATH}/example.txt

partition-iso: copy-iso-files
		# Make empty ISO of 64M in size
		dd if=/dev/zero of=${IMAGE_PATH} bs=1M count=0 seek=${ISO_SIZE}
ifeq (${ISO_PARTITION_TYPE},GPT)
		parted -s ${IMAGE_PATH} mklabel gpt
		parted -s ${IMAGE_PATH} mkpart ESP fat${ESP_BITS} 2048s 262144s

else
		parted -s ${IMAGE_PATH} mklabel msdos
		parted -s ${IMAGE_PATH} mkpart primary fat${ESP_BITS} 2048s 262144s
endif

		# Make ISO with 1 partition starting at sector 2048 that is 32768 sectors, or 16MiB, in size
		# Then a second partition spanning the rest of the disk
		parted -s ${IMAGE_PATH} mkpart primary 262145s 100%
		parted -s ${IMAGE_PATH} set 1 esp on

build-iso: partition-iso copy-initramfs-files
ifeq (${ARCH},x86_64)
		# Install the Limine bootloader for bios installs
		./limine/limine bios-install ${IMAGE_PATH}
endif

		sudo losetup -Pf --show ${IMAGE_PATH} > loopback_dev
		sudo mkfs.fat -F ${ESP_BITS} `cat loopback_dev`p1
		sudo mount `cat loopback_dev`p1 ${ARTIFACTS_PATH}/mnt
		sudo cp -r ${ISO_PATH}/* ${ARTIFACTS_PATH}/mnt
		sync
		sudo umount ${ARTIFACTS_PATH}/mnt
		sudo losetup -d `cat loopback_dev`
		rm -rf loopback_dev

# TODO: do something better for the directory checking maybe
compile-bootloader:
	@if [ ! -d "limine" ]; then \
		echo "Cloning Limine into limine/..."; \
		git clone https://github.com/limine-bootloader/limine.git --branch=${LIMINE_BRANCH} --depth=1; \
	fi
		make -C limine

compile-binaries:
		cargo build ${CARGO_OPTS}

ovmf-x86_64: ovmf
	mkdir -p ovmf/ovmf-x86_64
	@if [ ! -d "ovmf/ovmf-x86_64/OVMF.fd" ]; then \
		cd ovmf/ovmf-x86_64 && curl -Lo OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd; \
	fi

ovmf-riscv64: ovmf
	mkdir -p ovmf/ovmf-riscv64
	@if [ ! -d "ovmf/ovmf-riscv64/OVMF.fd" ]; then \
		cd ovmf/ovmf-riscv64 && curl -o OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASERISCV64_VIRT_CODE.fd; \
	fi

ovmf-aarch64:
	mkdir -p ovmf/ovmf-aarch64
	@if [ ! -d "ovmf/ovmf-aarch64/OVMF.fd" ]; then \
		cd ovmf/ovmf-aarch64 && curl -o OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASEAARCH64_QEMU_EFI.fd; \
	fi

# In debug mode, open a terminal and run this command:
# gdb target/x86_64-unknown-none/debug/CappuccinOS.elf -ex "target remote :1234"

run: build ${RUN_OPTS} run-${ARCH}

run-x86_64:
	tmux new-session -d -s qemu 'qemu-system-x86_64 ${QEMU_OPTS}'

run-riscv64:
	qemu-system-riscv64 ${QEMU_OPTS} -cpu rv64 -device ramfb -device qemu-xhci -device usb-kbd -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd0

run-aarch64:
	qemu-system-aarch64 ${QEMU_OPTS} -cpu cortex-a72 -device ramfb -device qemu-xhci -device usb-kbd -boot d

line-count:
		cloc --quiet --exclude-dir=bin --include-lang=Rust --csv src/ | tail -n 1 | awk -F, '{print $$5}'
clean:
		cargo clean
		rm -rf ${ARTIFACTS_PATH}
		make clean -C limine