Makefile (4809B)
1 # seed-kernel — minimal OS that satisfies docs/OS.md Tier 1/2. 2 3 ARCH ?= aarch64 4 ifeq ($(origin CC),default) 5 CC := clang 6 endif 7 ifeq ($(origin LD),default) 8 LD := ld.lld 9 endif 10 ifeq ($(origin OBJCOPY),default) 11 OBJCOPY := llvm-objcopy 12 endif 13 ifeq ($(strip $(OBJCOPY)),) 14 OBJCOPY := llvm-objcopy 15 endif 16 OUT := build 17 ARCHDIR := arch/$(ARCH) 18 KOBJS := $(OUT)/kasm.o $(OUT)/kernel.o $(OUT)/mmu.o $(OUT)/mem.o 19 KIMAGE := $(OUT)/kernel.elf 20 KBIN := $(OUT)/Image 21 USER := $(OUT)/init 22 USER_FORK := $(OUT)/forktest 23 USER_CHILD := $(OUT)/child 24 INITRAMFS := $(OUT)/initramfs.cpio 25 INITRAMFS_FORK := $(OUT)/initramfs-fork.cpio 26 # Block-device images for the seed kernel's virtio-blk transport. 27 # in*.img: cpio newc archive padded to a 512-byte multiple (read-only). 28 # out.img: pre-allocated 256 MiB sparse file the kernel writes SEEDFS into. 29 IN_IMG := $(OUT)/in.img 30 IN_IMG_FORK := $(OUT)/in-fork.img 31 OUT_IMG_SIZE := 268435456 32 33 CFLAGS_COMMON := -nostdlib -ffreestanding -fno-stack-protector \ 34 -fno-pic -static -Wall -Wextra -O2 \ 35 -fno-asynchronous-unwind-tables -fno-unwind-tables 36 KCFLAGS := $(CFLAGS_COMMON) -I$(ARCHDIR) 37 38 ifeq ($(ARCH),aarch64) 39 KCFLAGS += -target aarch64-unknown-elf -mcmodel=large -mgeneral-regs-only 40 USER_ARCH_CFLAGS := -target aarch64-unknown-elf -mcmodel=large -mgeneral-regs-only 41 LDFLAGS_ARCH := -m aarch64elf 42 EXTRA_ARCH_TARGETS := 43 else ifeq ($(ARCH),amd64) 44 KCFLAGS += -target x86_64-unknown-elf -mcmodel=large -mno-red-zone -mno-sse -mno-mmx 45 USER_ARCH_CFLAGS := -target x86_64-unknown-elf -mcmodel=large -mno-red-zone -mno-sse -mno-mmx 46 LDFLAGS_ARCH := -m elf_x86_64 47 EXTRA_ARCH_TARGETS := 48 else ifeq ($(ARCH),riscv64) 49 KCFLAGS += -target riscv64-unknown-elf -march=rv64imac_zicsr_zifencei -mabi=lp64 -mcmodel=medany -mno-relax -msmall-data-limit=0 50 USER_ARCH_CFLAGS := -target riscv64-unknown-elf -march=rv64imac_zicsr_zifencei -mabi=lp64 -mcmodel=medany -mno-relax -msmall-data-limit=0 51 LDFLAGS_ARCH := -m elf64lriscv 52 EXTRA_ARCH_TARGETS := 53 else 54 $(error seed-kernel backend '$(ARCH)' is unknown; use ARCH=aarch64, amd64, or riscv64) 55 endif 56 57 .PHONY: all clean kernel user initramfs 58 all: $(KBIN) $(EXTRA_ARCH_TARGETS) $(INITRAMFS) $(INITRAMFS_FORK) $(IN_IMG) $(IN_IMG_FORK) 59 60 $(OUT): 61 mkdir -p $(OUT) 62 63 $(OUT)/kasm.o: $(ARCHDIR)/kernel.S | $(OUT) 64 $(CC) $(KCFLAGS) -c -o $@ $< 65 66 $(OUT)/kernel.o: kernel.c $(ARCHDIR)/arch.h | $(OUT) 67 $(CC) $(KCFLAGS) -c -o $@ $< 68 69 $(OUT)/mmu.o: $(ARCHDIR)/mmu.c $(ARCHDIR)/arch.h | $(OUT) 70 $(CC) $(KCFLAGS) -c -o $@ $< 71 72 # Shared mem helpers (memcpy/memset/memmove/memcmp). Lives in 73 # tcc/cc/mem.c so the tcc-built and gcc-built kernels link the same 74 # implementation; tcc lowers some struct copies to memmove() that gcc 75 # inlines, so the kernel needs all three regardless of the compiler. 76 $(OUT)/mem.o: ../tcc/cc/mem.c | $(OUT) 77 $(CC) $(KCFLAGS) -c -o $@ $< 78 79 $(KIMAGE): $(KOBJS) $(ARCHDIR)/kernel.lds 80 $(LD) $(LDFLAGS_ARCH) -nostdlib -static -T $(ARCHDIR)/kernel.lds -o $@ $(KOBJS) 81 82 # Strip ELF down to a flat binary that QEMU's -kernel can load. 83 $(KBIN): $(KIMAGE) 84 $(OBJCOPY) -O binary $< $@ 85 86 $(OUT)/init.o: user/hello.c | $(OUT) 87 $(CC) $(CFLAGS_COMMON) $(USER_ARCH_CFLAGS) -c -o $@ $< 88 89 $(OUT)/forktest.o: user/forktest.c | $(OUT) 90 $(CC) $(CFLAGS_COMMON) $(USER_ARCH_CFLAGS) -c -o $@ $< 91 92 $(OUT)/child.o: user/child.c | $(OUT) 93 $(CC) $(CFLAGS_COMMON) $(USER_ARCH_CFLAGS) -c -o $@ $< 94 95 $(USER): $(OUT)/init.o user/user.lds 96 $(LD) $(LDFLAGS_ARCH) -nostdlib -static -T user/user.lds -o $@ $(OUT)/init.o 97 98 $(USER_FORK): $(OUT)/forktest.o user/user.lds 99 $(LD) $(LDFLAGS_ARCH) -nostdlib -static -T user/user.lds -o $@ $(OUT)/forktest.o 100 101 $(USER_CHILD): $(OUT)/child.o user/user.lds 102 $(LD) $(LDFLAGS_ARCH) -nostdlib -static -T user/user.lds -o $@ $(OUT)/child.o 103 104 $(INITRAMFS): $(USER) 105 cd $(OUT) && printf 'init\n' | cpio -o -H newc > initramfs.cpio 106 107 # Tier 2 demo cpio: /init is the fork driver, /child the program it execs. 108 $(INITRAMFS_FORK): $(USER_FORK) $(USER_CHILD) 109 rm -rf $(OUT)/fork-stage && mkdir -p $(OUT)/fork-stage 110 cp $(USER_FORK) $(OUT)/fork-stage/init 111 cp $(USER_CHILD) $(OUT)/fork-stage/child 112 cd $(OUT)/fork-stage && printf 'init\nchild\n' | cpio -o -H newc > ../initramfs-fork.cpio 113 114 # Pad an arbitrary cpio archive up to the next 512-byte multiple so QEMU's 115 # virtio-blk transport sees a whole-sector device. 116 $(IN_IMG): $(INITRAMFS) 117 cp $(INITRAMFS) $@.tmp 118 sz=$$(wc -c < $@.tmp); \ 119 pad=$$(( (512 - sz % 512) % 512 )); \ 120 if [ $$pad -gt 0 ]; then \ 121 head -c $$pad /dev/zero >> $@.tmp; \ 122 fi 123 mv $@.tmp $@ 124 125 $(IN_IMG_FORK): $(INITRAMFS_FORK) 126 cp $(INITRAMFS_FORK) $@.tmp 127 sz=$$(wc -c < $@.tmp); \ 128 pad=$$(( (512 - sz % 512) % 512 )); \ 129 if [ $$pad -gt 0 ]; then \ 130 head -c $$pad /dev/zero >> $@.tmp; \ 131 fi 132 mv $@.tmp $@ 133 134 kernel: $(KBIN) 135 user: $(USER) 136 initramfs: $(INITRAMFS) 137 138 clean: 139 rm -rf $(OUT)