HOST ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH ?= ##DEFAULT_ARCH##
MODE ?= debug
SMP ?= 4

QEMU ?= ##QEMU##
GDB ?= ##GDB##
FDISK ?= ##FDISK##

QEMU_ARGS ?= -machine q35 -drive id=disk,file=build/boot.img,format=raw,if=none \
	-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 \
	-netdev user,id=mynet0,net=192.168.1.0/24,dhcpstart=192.168.1.16 -device e1000e,netdev=mynet0 \
	-no-reboot -no-shutdown

ifeq ($(HOST),darwin)
QEMU_ACCEL ?= -accel tcg
else ifeq ($(HOST),linux)
QEMU_ACCEL ?= -accel kvm
endif

QEMU_ARGS += $(QEMU_ACCEL)

ifneq ($(DEBUG_TRAPS),)
QEMU_ARGS += -d cpu_reset,int,guest_errors -D build/qemu.log
endif

ifneq ($(SMP),)
QEMU_ARGS += -smp $(SMP)
endif

ifeq ($(MODE),debug)
MODE := dev
endif

COMMA := ,

CARGO_FLAGS := --profile $(MODE) --features $(FEATURES)$(if $(SMP),$(COMMA)smp,)

.PHONY: run
run: build
	$(QEMU) $(QEMU_ARGS) -display none -serial mon:stdio

.PHONY: srun
srun: build
	$(QEMU) $(QEMU_ARGS) -display none -S -s -serial mon:stdio

.PHONY: clean
clean:
	-mv build/fs.img .
	-rm -rf build
	-mkdir build
	-mv fs.img build

.PHONY: clean-all
clean-all: clean
	-rm Makefile

.PHONY: debug
debug:
	-RUST_GDB=$(GDB) rust-gdb --symbols=build/kernel.sym \
		-iex 'source pretty-print.py' \
		-iex 'set pagination off' \
		-iex 'set output-radix 16' \
		-iex 'set print asm-demangle on' \
		-iex 'set print pretty on' \
		-iex 'target remote:1234'
	-killall $(QEMU)

.PHONY: tmux-debug
tmux-debug:
	tmux new-session -s gbos-debug -d
	-tmux split-window -t gbos-debug -hf
	-tmux send-keys -t gbos-debug:1.1 'make srun' C-m
	-tmux send-keys -t gbos-debug:1.2 'make debug' C-m C-m
	-tmux attach -t gbos-debug
	tmux kill-session -t gbos-debug

.PHONY: kernel
kernel:
	cargo build $(CARGO_FLAGS)

build/kernel.sym: kernel
	cargo objcopy $(CARGO_FLAGS) -- --only-keep-debug build/kernel.sym

build/mbr.bin: kernel
	cargo objcopy $(CARGO_FLAGS) -- -O binary -j .mbr build/mbr.bin

build/stage1.bin: kernel
	cargo objcopy $(CARGO_FLAGS) -- -O binary -j .stage1 build/stage1.bin

build/kernel.bin: kernel
	cargo objcopy $(CARGO_FLAGS) -- -O binary --strip-debug \
		-R .mbr -R .stage1 build/kernel.bin

build/fs.img: init_script.sh
	sh script/build-img.sh

build/boot.img: build/mbr.bin build/stage1.bin build/kernel.bin build/fs.img
	dd if=build/mbr.bin of=build/boot.img bs=512 count=1 conv=notrunc 2> /dev/null
	dd if=build/stage1.bin of=build/boot.img bs=512 seek=1 conv=notrunc 2> /dev/null
	dd if=build/kernel.bin of=build/boot.img bs=4096 seek=1 conv=notrunc 2> /dev/null
	dd if=build/fs.img of=build/boot.img bs=$(shell expr 4 \* 1024 \* 1024) \
		seek=1 conv=notrunc 2> /dev/null
	sh -c 'echo n; echo; echo; echo 8192; echo; echo a; echo w' \
		| $(FDISK) build/boot.img 2> /dev/null > /dev/null

.PHONY: build
build: build/boot.img build/kernel.sym
