CROSS ?= aarch64-linux-gnu-

SRC_DIR := src
BUILD_DIR := build
BOOT_DIR := boot

CC := $(CROSS)gcc
LD := $(CROSS)ld
OBJCOPY := $(CROSS)objcopy
HOSTCC ?= cc

CFLAGS := -Wall -Wextra -O2 -ffreestanding -nostdlib -nostartfiles -mgeneral-regs-only -mstrict-align
LDFLAGS := -nostdlib -T $(SRC_DIR)/link.ld

C_SRC := \
	$(SRC_DIR)/kernel.c \
	$(SRC_DIR)/drivers/led.c \
	$(SRC_DIR)/drivers/mailbox.c \
	$(SRC_DIR)/drivers/rpi/rpi_disk.c \
	$(SRC_DIR)/drivers/timer.c \
	$(SRC_DIR)/drivers/uart.c \
	$(SRC_DIR)/kernel/sched.c \
	$(SRC_DIR)/kernel/shell.c \
	$(SRC_DIR)/kernel/tasks.c \
	$(SRC_DIR)/programs/disk/disk_program.c \
	$(SRC_DIR)/programs/disk/mbr.c
S_SRC := $(SRC_DIR)/boot.S
OBJ := $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(C_SRC)) \
	$(patsubst $(SRC_DIR)/%.S,$(BUILD_DIR)/%.o,$(S_SRC))
KERNEL_ELF := $(BUILD_DIR)/kernel8.elf
KERNEL_IMG := $(BOOT_DIR)/kernel8.img
DISK_IMG := tests/disk.img
DISK_SIZE_MIB := 64
DISK_FIRST_LBA := 2048
DISK_LABEL := ALQUIST

.PHONY: all clean qemu test-disk-image test-mbr check-disk-tools

all: $(KERNEL_IMG)

$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(BOOT_DIR):
	mkdir -p $(BOOT_DIR)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S | $(BUILD_DIR)
	mkdir -p $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
	mkdir -p $(dir $@)
	$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

$(KERNEL_ELF): $(OBJ) $(SRC_DIR)/link.ld | $(BUILD_DIR)
	$(LD) $(LDFLAGS) $(OBJ) -o $@

$(KERNEL_IMG): $(KERNEL_ELF) | $(BOOT_DIR)
	$(OBJCOPY) -O binary $< $@

clean:
	rm -rf $(BUILD_DIR)
	rm -f $(KERNEL_IMG)
	rm -f tests/mbr_tests
	rm -f $(DISK_IMG)

qemu: clean
	$(MAKE) BUILD_DIR=build/qemu BOOT_DIR=build/qemu/boot CPPFLAGS=-DQEMU_RASPI4 build/qemu/boot/kernel8.img
	timeout -k 1s 12s qemu-system-aarch64 -M raspi4b -cpu cortex-a72 -m 2G -nographic -monitor none -serial stdio -kernel build/qemu/boot/kernel8.img </dev/null; code=$$?; test $$code -eq 0 -o $$code -eq 124

check-disk-tools:
	@command -v truncate >/dev/null || { echo "missing truncate"; exit 1; }
	@command -v sfdisk >/dev/null || { echo "missing sfdisk"; exit 1; }
	@command -v mkfs.fat >/dev/null || { echo "missing mkfs.fat; install dosfstools"; exit 1; }
	@command -v fdisk >/dev/null || { echo "missing fdisk"; exit 1; }

$(DISK_IMG): | check-disk-tools
	rm -f $(DISK_IMG)
	truncate -s $(DISK_SIZE_MIB)M $(DISK_IMG)
	printf 'label: dos\nunit: sectors\n\n$(DISK_FIRST_LBA),,c,*\n' | sfdisk $(DISK_IMG)
	mkfs.fat -F 32 -n $(DISK_LABEL) --offset $(DISK_FIRST_LBA) $(DISK_IMG)
	fdisk -l $(DISK_IMG)

test-disk-image: $(DISK_IMG)

test-mbr:
	$(HOSTCC) -Wall -Wextra -O2 tests/mbr_tests.c src/programs/disk/mbr.c -o tests/mbr_tests
	./tests/mbr_tests
