mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
Kernel: the passive-open half of TCP. tcp_listen claims a port, inbound
SYNs to it are completed by the receive path, and the finished
connections queue in a backlog until tcp_accept collects them. Accepted
connections run the same stream state machine as active opens, so
tcp_send/tcp_recv/tcp_close work on them unchanged. sys_listen and
sys_accept expose this through the BSD socket API, with sys_accept
returning a fresh descriptor and leaving the listener available for the
next caller. The built-in sshd and httpd predate this and are still
answered inline from the receive path; the role they use is now named
TCP_ROLE_SERVICE to keep that distinction explicit.
GUI: a Network Monitor app. Interface configuration and link state, a
rolling dual-line chart of receive and transmit rates sampled from the
NIC counters on a fixed 2 Hz cadence (so it reads in packets per half
second no matter how often the compositor repaints), byte and packet
totals, and the TCP engine's connection table with each connection's real
state and direction, scrollable when it outgrows the window.
Two bugs the monitor made visible, both fixed:
- Served HTTP connections were never closed. The response advertises
"Connection: close" but the engine left the connection ESTABLISHED
forever, so the 32-entry table filled up and the server stopped
answering after 32 requests. The service path now sends its FIN after
the response and lingers in TIME_WAIT until the reaper takes it. 40
sequential requests through a 32-slot table now yield 39 successes
where the 33rd onwards previously failed permanently.
- tcp_close gave up in FIN_WAIT2 after 500 ms and freed the slot, so a
peer whose own FIN arrived later got an RST instead of an ACK. It now
falls into TIME_WAIT instead, and TIME_WAIT acknowledges a first FIN
rather than only a retransmitted one. Expired TIME_WAIT entries are
also reaped from tcp_get_connections_count, so a table that sees no
further connections still empties out.
Verified on x86_64 against real peers, checked packet by packet in a
capture: a host client connected to `tcpserve 9000` in the guest and got
its reply -- SYN/SYN-ACK/ACK with a random ISN, 30-byte request, 43-byte
reply, and a clean four-way close whose final ACK is correct even when
the peer's FIN arrives 1.2 s late. Zero bad checksums throughout. The
monitor was screenshotted under live load showing connections moving
through TIME_WAIT and being reclaimed. Builds clean on x86_64, aarch64
and armv8i.
Known limit: 32 connection slots with a 2 s TIME_WAIT linger means
sustained rates much above ~16 requests/second can transiently exhaust
the table; it recovers on its own as entries expire.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
542 lines
21 KiB
Makefile
542 lines
21 KiB
Makefile
# =============================================================================
|
|
# SUB-OS Master Multi-Architecture Linux-Style Makefile
|
|
# Supports: x86_64, aarch64, armv8i
|
|
# Features: Linux Kconfig TUI (make configure / make menuconfig), dynamic Kbuild
|
|
# =============================================================================
|
|
|
|
-include .config
|
|
|
|
# Architecture Selection (Default: x86_64)
|
|
ifdef CONFIG_ARCH
|
|
ARCH ?= $(CONFIG_ARCH)
|
|
else
|
|
ARCH ?= x86_64
|
|
endif
|
|
|
|
BUILD_DIR = build
|
|
BOOT_DIR = boot
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Toolchain & Architecture Flags
|
|
# -----------------------------------------------------------------------------
|
|
ifeq ($(ARCH), x86_64)
|
|
CROSS_COMPILE ?= x86_64-elf-
|
|
CC = $(CROSS_COMPILE)gcc
|
|
LD = $(CROSS_COMPILE)ld
|
|
OBJCOPY = $(CROSS_COMPILE)objcopy
|
|
ASM = nasm
|
|
|
|
CFLAGS = -ffreestanding \
|
|
-fno-pie \
|
|
-fno-pic \
|
|
-mno-red-zone \
|
|
-mno-mmx \
|
|
-mno-sse \
|
|
-mno-sse2 \
|
|
-mcmodel=kernel \
|
|
-Wall \
|
|
-Wextra \
|
|
-Wno-unused-function \
|
|
-Wno-unused-parameter \
|
|
$(if $(CONFIG_OPTIMIZATION),$(CONFIG_OPTIMIZATION),-O2) \
|
|
-Iinclude \
|
|
-D__x86_64__
|
|
|
|
ASMFLAGS_ELF = -f elf64
|
|
ASMFLAGS_BOOT = -f bin -I$(BOOT_DIR)/
|
|
LDFLAGS = -nostdlib -no-pie -T linker.ld
|
|
|
|
ARCH_C_SRCS = $(shell find arch/x86_64 -name '*.c' 2>/dev/null)
|
|
ARCH_ASM_SRCS = $(shell find arch/x86_64 -name '*.asm' 2>/dev/null)
|
|
ENTRY_OBJ = $(BUILD_DIR)/arch/x86_64/boot/entry.o
|
|
IMAGE = SUB-OS.img
|
|
TARGET = $(IMAGE)
|
|
QEMU_CMD = qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 -serial stdio -display none
|
|
|
|
else ifneq ($(filter $(ARCH), aarch64 arm64),)
|
|
CROSS_COMPILE ?= aarch64-linux-gnu-
|
|
CC = $(CROSS_COMPILE)gcc
|
|
LD = $(CROSS_COMPILE)ld
|
|
OBJCOPY = $(CROSS_COMPILE)objcopy
|
|
AS = $(CROSS_COMPILE)as
|
|
|
|
CFLAGS = -ffreestanding \
|
|
-fno-pie \
|
|
-fno-pic \
|
|
-Wall \
|
|
-Wextra \
|
|
-Wno-unused-function \
|
|
-Wno-unused-parameter \
|
|
-mno-outline-atomics \
|
|
$(if $(CONFIG_OPTIMIZATION),$(CONFIG_OPTIMIZATION),-O2) \
|
|
-Iinclude \
|
|
-D__aarch64__ \
|
|
-march=armv8-a
|
|
|
|
LDFLAGS = -nostdlib -no-pie -T arch/aarch64/linker.ld
|
|
|
|
ARCH_C_SRCS = $(shell find arch/aarch64 -name '*.c' 2>/dev/null)
|
|
ARCH_S_SRCS = $(shell find arch/aarch64 -name '*.S' 2>/dev/null)
|
|
ENTRY_OBJ = $(BUILD_DIR)/arch/aarch64/boot/entry.o
|
|
TARGET = $(BUILD_DIR)/kernel.elf
|
|
QEMU_CMD = qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf
|
|
|
|
else ifneq ($(filter $(ARCH), armv8i armv81 arm32 arm armv7 armv7-a armv7a aarch32),)
|
|
CROSS_COMPILE ?= arm-linux-gnueabihf-
|
|
CC = $(CROSS_COMPILE)gcc
|
|
LD = $(CROSS_COMPILE)ld
|
|
OBJCOPY = $(CROSS_COMPILE)objcopy
|
|
AS = $(CROSS_COMPILE)as
|
|
|
|
CFLAGS = -ffreestanding \
|
|
-fno-pie \
|
|
-fno-pic \
|
|
-Wall \
|
|
-Wextra \
|
|
-Wno-unused-function \
|
|
-Wno-unused-parameter \
|
|
$(if $(CONFIG_OPTIMIZATION),$(CONFIG_OPTIMIZATION),-O2) \
|
|
-Iinclude \
|
|
-D__arm__ \
|
|
-D__armv8i__ \
|
|
-mcpu=cortex-a15 \
|
|
-mfpu=neon-vfpv4 \
|
|
-mfloat-abi=hard \
|
|
-marm
|
|
|
|
LDFLAGS = -nostdlib -no-pie -T arch/armv8i/linker.ld
|
|
|
|
ARCH_C_SRCS = $(shell find arch/armv8i -name '*.c' 2>/dev/null)
|
|
ARCH_S_SRCS = $(shell find arch/armv8i -name '*.S' 2>/dev/null)
|
|
ENTRY_OBJ = $(BUILD_DIR)/arch/armv8i/boot/entry.o
|
|
TARGET = $(BUILD_DIR)/kernel.elf
|
|
QEMU_CMD = qemu-system-arm -M virt -cpu cortex-a15 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf
|
|
|
|
else
|
|
$(error Unsupported Architecture '$(ARCH)'. Supported: x86_64, aarch64, armv8i)
|
|
endif
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Linux-Style Configurable Kernel Subsystems (Kbuild-Style)
|
|
# -----------------------------------------------------------------------------
|
|
CORE_SRCS = kernel/main.c kernel/task.c kernel/sync.c kernel/timer.c kernel/printk.c \
|
|
kernel/panic.c kernel/trace.c kernel/sched.c kernel/cron.c kernel/syscall.c \
|
|
kernel/syslog.c kernel/module.c kernel/kobject.c kernel/metrics.c kernel/namespace.c \
|
|
kernel/signal.c kernel/workqueue.c kernel/tsc.c kernel/vt_art.c \
|
|
kernel/sub/sub_runtime.c kernel/sub/sub_vm.c kernel/nt/ob.c kernel/nt/reg.c kernel/nt/io.c \
|
|
kernel/wait.c kernel/futex.c kernel/rcu.c kernel/ktest.c kernel/time/ktime.c \
|
|
kernel/elf.c kernel/exec.c \
|
|
lib/string.c lib/vsprintf.c lib/bitmap.c lib/rbtree.c lib/kfifo.c lib/hashtable.c lib/font8x8.c \
|
|
init/cmdline.c init/service.c init/bootlogo.c init/logo_data.c usr/initramfs.c block/block.c block/elevator.c \
|
|
ipc/sem.c ipc/shm.c ipc/shm_posix.c ipc/pipe.c ipc/ipc.c ipc/msg.c \
|
|
crypto/sha256.c crypto/md5.c crypto/crc32.c crypto/prng.c sound/beep.c
|
|
|
|
# If no .config exists, default all core options to y
|
|
ifeq ($(wildcard .config),)
|
|
CONFIG_MM_PMM = y
|
|
CONFIG_MM_SLAB = y
|
|
CONFIG_MM_VMA = y
|
|
CONFIG_FS_VFS = y
|
|
CONFIG_FS_FAT32 = y
|
|
CONFIG_FS_EXT2 = y
|
|
CONFIG_FS_SYSFS = y
|
|
CONFIG_DRV_RAMDISK = y
|
|
CONFIG_DRV_AHCI = y
|
|
CONFIG_DRV_NVME = y
|
|
CONFIG_DRV_ATA = y
|
|
CONFIG_DRV_VIRTIO_BLK = y
|
|
CONFIG_NET_STACK = y
|
|
CONFIG_NET_FILTER = y
|
|
CONFIG_NET_HTTPD = y
|
|
CONFIG_NET_SSHD = y
|
|
CONFIG_DRV_E1000 = y
|
|
CONFIG_DRV_RTL8139 = y
|
|
CONFIG_DRV_VIRTIO_NET = y
|
|
CONFIG_DRV_PTY = y
|
|
CONFIG_DRV_VIRTIO_RNG = y
|
|
CONFIG_DRV_CANVAS_2D = y
|
|
CONFIG_DRV_BOCHS_VBE = y
|
|
CONFIG_DRV_SOUND_HDA = y
|
|
CONFIG_DRV_SOUND_AC97 = y
|
|
CONFIG_DRV_USB_XHCI = y
|
|
CONFIG_DRV_HWMON = y
|
|
CONFIG_SECURITY_LSM = y
|
|
CONFIG_SECURITY_KEYRING = y
|
|
CONFIG_BPF_VM = y
|
|
CONFIG_IO_URING = y
|
|
CONFIG_USERLAND_LAZYBOX = y
|
|
endif
|
|
|
|
CONFIG_SRCS-y := $(CORE_SRCS)
|
|
|
|
ifeq ($(CONFIG_MM_PMM), y)
|
|
CONFIG_SRCS-y += mm/pmm.c mm/kmalloc.c mm/page_cache.c
|
|
endif
|
|
ifeq ($(CONFIG_MM_SLAB), y)
|
|
CONFIG_SRCS-y += mm/slab.c
|
|
endif
|
|
ifeq ($(CONFIG_MM_VMA), y)
|
|
CONFIG_SRCS-y += mm/vma.c
|
|
endif
|
|
|
|
ifeq ($(CONFIG_BPF_VM), y)
|
|
CONFIG_SRCS-y += kernel/bpf.c
|
|
endif
|
|
ifeq ($(CONFIG_IO_URING), y)
|
|
CONFIG_SRCS-y += io_uring/io_uring.c
|
|
endif
|
|
ifeq ($(CONFIG_SECURITY_LSM), y)
|
|
CONFIG_SRCS-y += security/lsm.c security/auth.c
|
|
endif
|
|
ifeq ($(CONFIG_SECURITY_KEYRING), y)
|
|
CONFIG_SRCS-y += certs/x509.c
|
|
endif
|
|
|
|
# Filesystems
|
|
ifeq ($(CONFIG_FS_VFS), y)
|
|
CONFIG_SRCS-y += fs/vfs.c fs/ramfs.c fs/devfs.c fs/procfs.c
|
|
endif
|
|
ifeq ($(CONFIG_FS_FAT32), y)
|
|
CONFIG_SRCS-y += fs/fat32.c
|
|
endif
|
|
ifeq ($(CONFIG_FS_EXT2), y)
|
|
CONFIG_SRCS-y += fs/ext2.c
|
|
endif
|
|
ifeq ($(CONFIG_FS_SYSFS), y)
|
|
CONFIG_SRCS-y += fs/sysfs.c
|
|
endif
|
|
|
|
# Storage Drivers
|
|
ifeq ($(CONFIG_DRV_RAMDISK), y)
|
|
CONFIG_SRCS-y += drivers/block/ramdisk.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_AHCI), y)
|
|
CONFIG_SRCS-y += drivers/block/ahci.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_NVME), y)
|
|
CONFIG_SRCS-y += drivers/block/nvme.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_ATA), y)
|
|
CONFIG_SRCS-y += drivers/block/ata.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_VIRTIO_BLK), y)
|
|
CONFIG_SRCS-y += drivers/virtio/virtio_blk.c virt/virtio.c virt/hypervisor.c
|
|
endif
|
|
|
|
# Network Subsystem
|
|
ifeq ($(CONFIG_NET_STACK), y)
|
|
CONFIG_SRCS-y += net/core/net.c net/core/socket.c net/ipv4/tcp.c net/ipv4/udp.c net/ipv4/dhcp.c net/ipv4/dns.c net/ipv4/dns_cache.c
|
|
endif
|
|
ifeq ($(CONFIG_NET_FILTER), y)
|
|
CONFIG_SRCS-y += net/filter.c
|
|
endif
|
|
ifeq ($(CONFIG_NET_HTTPD), y)
|
|
CONFIG_SRCS-y += net/httpd.c
|
|
endif
|
|
ifeq ($(CONFIG_NET_SSHD), y)
|
|
CONFIG_SRCS-y += net/ssh.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_E1000), y)
|
|
CONFIG_SRCS-y += drivers/net/e1000.c drivers/pci/pci.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_RTL8139), y)
|
|
CONFIG_SRCS-y += drivers/net/rtl8139.c drivers/pci/pci.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_VIRTIO_NET), y)
|
|
CONFIG_SRCS-y += drivers/virtio/virtio_net.c virt/virtio.c
|
|
endif
|
|
|
|
# Character, Audio, Video Drivers
|
|
ifeq ($(CONFIG_DRV_PTY), y)
|
|
CONFIG_SRCS-y += drivers/char/pty.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_VIRTIO_RNG), y)
|
|
CONFIG_SRCS-y += drivers/char/virtio_rng.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_USB_XHCI), y)
|
|
CONFIG_SRCS-y += drivers/usb/xhci.c drivers/usb/usb.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_HWMON), y)
|
|
CONFIG_SRCS-y += drivers/hwmon/coretemp.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_CANVAS_2D), y)
|
|
CONFIG_SRCS-y += drivers/video/canvas.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_BOCHS_VBE), y)
|
|
CONFIG_SRCS-y += drivers/video/bochs.c drivers/video/fb.c drivers/video/fbcon.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_SOUND_HDA), y)
|
|
CONFIG_SRCS-y += sound/hda.c sound/sound.c sound/pcm.c sound/tts.c sound/melody.c
|
|
endif
|
|
ifeq ($(CONFIG_DRV_SOUND_AC97), y)
|
|
CONFIG_SRCS-y += sound/ac97.c sound/sound.c sound/pcm.c
|
|
endif
|
|
|
|
# Common Input/Display/Power/GPU/Networking Drivers
|
|
CONFIG_SRCS-y += drivers/char/tty.c drivers/char/keyboard.c drivers/char/serial.c drivers/char/vga.c \
|
|
drivers/input/mouse.c drivers/power/acpi.c drivers/power/cpufreq.c drivers/rtc/rtc.c drivers/sound/speaker.c \
|
|
drivers/net/e1000e.c drivers/virtio/virtio_gpu.c drivers/virtio/virtio_input.c \
|
|
drivers/timer/hpet.c drivers/char/lpt.c drivers/char/nvram.c
|
|
|
|
# Userland & GUI Desktop Subsystem
|
|
ifeq ($(CONFIG_USERLAND_LAZYBOX), y)
|
|
CONFIG_SRCS-y += userland/lazybox/lazybox.c userland/lazybox/shell.c userland/lazybox/sh.c userland/lazybox/nano.c userland/lazybox/snake.c userland/lazybox/tree.c userland/lazybox/coreutils.c
|
|
endif
|
|
|
|
CONFIG_SRCS-y += gui/gui.c gui/gui_gfx.c gui/gui_cursor.c gui/gui_wm.c gui/gui_desktop.c gui/gui_apps.c \
|
|
gui/gui_widgets.c gui/gui_icons.c gui/gui_dialog.c gui/gui_apps_ext.c gui/gui_terminal.c \
|
|
gui/gui_app_sorry.c gui/gui_app_netmon.c
|
|
|
|
# Deduplicate
|
|
CONFIG_SRCS-y := $(sort $(CONFIG_SRCS-y))
|
|
|
|
# Rust & C++ Layer Configuration
|
|
ifeq ($(ARCH), x86_64)
|
|
RUSTC ?= rustc
|
|
RUST_SRCS = $(shell find rust/src -name '*.rs' 2>/dev/null)
|
|
RUST_LIB = $(BUILD_DIR)/rust/librust_kernel.a
|
|
CXX ?= g++
|
|
CXXFLAGS = -ffreestanding -fno-pie -fno-pic -mno-red-zone -mno-mmx -mno-sse -mno-sse2 \
|
|
-mcmodel=kernel -Wall -Wextra -Wno-unused-function -Wno-unused-parameter \
|
|
$(if $(CONFIG_OPTIMIZATION),$(CONFIG_OPTIMIZATION),-O2) -Iinclude -D__x86_64__ \
|
|
-std=c++17 -fno-exceptions -fno-rtti -fno-threadsafe-statics -fno-use-cxa-atexit
|
|
CPP_SRCS = $(shell find kernel/cpp -name '*.cpp' 2>/dev/null)
|
|
CPP_OBJS = $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(CPP_SRCS))
|
|
ALL_C_SRCS = $(ARCH_C_SRCS) $(CONFIG_SRCS-y)
|
|
C_OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(ALL_C_SRCS))
|
|
ASM_OBJS = $(patsubst %.asm, $(BUILD_DIR)/%.o, $(ARCH_ASM_SRCS))
|
|
|
|
# Userland /sbin/init, linked separately and carried inside the kernel image.
|
|
INIT_SRC = userland/init/init.c
|
|
INIT_LD = userland/init/user.ld
|
|
INIT_OBJ = $(BUILD_DIR)/userland/init/init.o
|
|
INIT_ELF = $(BUILD_DIR)/userland/init/init.elf
|
|
INIT_BLOB_SRC = $(BUILD_DIR)/usr/init_blob.c
|
|
INIT_BLOB_OBJ = $(BUILD_DIR)/usr/init_blob.o
|
|
|
|
OTHER_OBJS = $(filter-out $(ENTRY_OBJ), $(ASM_OBJS) $(C_OBJS)) $(CPP_OBJS) $(INIT_BLOB_OBJ) $(RUST_LIB)
|
|
else
|
|
CONFIG_SRCS-y += rust/rust_fallback.c kernel/cpp/cpp_fallback.c
|
|
ALL_C_SRCS = $(ARCH_C_SRCS) $(CONFIG_SRCS-y)
|
|
C_OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(ALL_C_SRCS))
|
|
S_OBJS = $(patsubst %.S, $(BUILD_DIR)/%.o, $(ARCH_S_SRCS))
|
|
OTHER_OBJS = $(filter-out $(ENTRY_OBJ), $(S_OBJS) $(C_OBJS))
|
|
endif
|
|
|
|
# Generated dependency files, one per object. The include lives at the very
|
|
# end of this file: a .d file's first rule would otherwise become make's
|
|
# default goal and turn a bare `make` into a no-op.
|
|
DEPS = $(C_OBJS:.o=.d) $(CPP_OBJS:.o=.d) $(S_OBJS:.o=.d)
|
|
|
|
.DEFAULT_GOAL := all
|
|
|
|
.PHONY: all clean run run-headless run-fullscreen run-vnc run-server debug info configure menuconfig config tui nconfig defconfig x86_64_defconfig aarch64_defconfig armv8_defconfig armv8i_defconfig armv81_defconfig arm32_defconfig qemu help
|
|
|
|
all: $(TARGET)
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Configuration Targets (Linux Kconfig TUI Configurator)
|
|
# -----------------------------------------------------------------------------
|
|
configure menuconfig config tui nconfig:
|
|
@python3 scripts/kconfig/menuconfig.py
|
|
|
|
defconfig:
|
|
@python3 scripts/kconfig/menuconfig.py --defconfig $(ARCH)
|
|
|
|
x86_64_defconfig:
|
|
@python3 scripts/kconfig/menuconfig.py --x86_64
|
|
|
|
aarch64_defconfig:
|
|
@python3 scripts/kconfig/menuconfig.py --aarch64
|
|
|
|
armv8_defconfig armv8i_defconfig armv81_defconfig arm32_defconfig:
|
|
@python3 scripts/kconfig/menuconfig.py --armv8i
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Compilation Rules
|
|
# -----------------------------------------------------------------------------
|
|
# Header dependency tracking: without this a header change leaves stale objects
|
|
# behind, and a struct layout edit silently corrupts every unrebuilt caller.
|
|
DEPFLAGS = -MMD -MP
|
|
|
|
# C Source Files
|
|
$(BUILD_DIR)/%.o: %.c include/config/autoconf.h
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
|
|
|
# C++ Source Files
|
|
$(BUILD_DIR)/%.o: %.cpp include/config/autoconf.h
|
|
@mkdir -p $(dir $@)
|
|
$(CXX) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
|
|
|
|
# x86_64 NASM Assembly Files
|
|
$(BUILD_DIR)/%.o: %.asm
|
|
@mkdir -p $(dir $@)
|
|
$(ASM) $(ASMFLAGS_ELF) $< -o $@
|
|
|
|
# ARM/AArch64 GNU Assembly Files (.S)
|
|
$(BUILD_DIR)/%.o: %.S
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
|
|
|
# Userland Program Compilation
|
|
#
|
|
# /sbin/init is a separate freestanding executable, not kernel code: it is
|
|
# linked at the user base from userland/user.ld and must never see the kernel's
|
|
# -mcmodel=kernel, which cannot reach the user half of the address space.
|
|
USER_CFLAGS = -ffreestanding -nostdlib -fno-pie -fno-pic -mno-red-zone \
|
|
-mcmodel=large -mno-sse -mno-mmx -mno-sse2 \
|
|
-Wall -Wextra -Wno-unused-function \
|
|
$(if $(CONFIG_OPTIMIZATION),$(CONFIG_OPTIMIZATION),-O2)
|
|
|
|
$(INIT_OBJ): $(INIT_SRC)
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(USER_CFLAGS) -c $< -o $@
|
|
|
|
$(INIT_ELF): $(INIT_OBJ) $(INIT_LD)
|
|
@mkdir -p $(dir $@)
|
|
$(LD) -nostdlib -no-pie -T $(INIT_LD) -o $@ $(INIT_OBJ)
|
|
@echo "=== [Userland init linked: $@] ==="
|
|
|
|
$(INIT_BLOB_SRC): $(INIT_ELF) scripts/mkblob.py
|
|
@mkdir -p $(dir $@)
|
|
@python3 scripts/mkblob.py $(INIT_ELF) $@ subos_init_elf
|
|
|
|
$(INIT_BLOB_OBJ): $(INIT_BLOB_SRC) include/config/autoconf.h
|
|
@mkdir -p $(dir $@)
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
# Rust Source Compilation
|
|
$(RUST_LIB): rust/src/lib.rs $(RUST_SRCS)
|
|
@mkdir -p $(dir $@)
|
|
$(RUSTC) --crate-type staticlib -C panic=abort -C relocation-model=static -C opt-level=2 -C no-redzone=y -o $@ rust/src/lib.rs
|
|
|
|
|
|
# Header Generation Fallback
|
|
include/config/autoconf.h:
|
|
@mkdir -p include/config
|
|
@if [ ! -f .config ]; then python3 scripts/kconfig/menuconfig.py --defconfig $(ARCH); fi
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Link & Image Assembly
|
|
# -----------------------------------------------------------------------------
|
|
$(BUILD_DIR)/boot/boot.bin: $(BOOT_DIR)/boot.asm | $(BUILD_DIR)/boot
|
|
$(ASM) $(ASMFLAGS_BOOT) $< -o $@
|
|
|
|
$(BUILD_DIR)/boot/stage2.bin: $(BOOT_DIR)/stage2.asm $(BOOT_DIR)/gdt.asm | $(BUILD_DIR)/boot
|
|
$(ASM) $(ASMFLAGS_BOOT) $< -o $@
|
|
|
|
$(BUILD_DIR)/boot:
|
|
mkdir -p $(BUILD_DIR)/boot
|
|
|
|
LIBGCC ?= $(shell $(CC) $(CFLAGS) -print-libgcc-file-name 2>/dev/null)
|
|
|
|
$(BUILD_DIR)/kernel.elf: $(ENTRY_OBJ) $(OTHER_OBJS)
|
|
$(LD) $(LDFLAGS) -o $@ $(ENTRY_OBJ) $(OTHER_OBJS) $(LIBGCC)
|
|
@echo "=== [Kernel ELF Linked: $@ (Architecture: $(ARCH))] ==="
|
|
|
|
$(BUILD_DIR)/kernel.bin: $(BUILD_DIR)/kernel.elf
|
|
$(OBJCOPY) -O binary $< $@
|
|
|
|
$(IMAGE): $(BUILD_DIR)/boot/boot.bin $(BUILD_DIR)/boot/stage2.bin $(BUILD_DIR)/kernel.bin
|
|
dd if=/dev/zero of=$@ bs=512 count=2880 status=none
|
|
dd if=$(BUILD_DIR)/boot/boot.bin of=$@ bs=512 conv=notrunc status=none
|
|
dd if=$(BUILD_DIR)/boot/stage2.bin of=$@ bs=512 seek=1 conv=notrunc status=none
|
|
dd if=$(BUILD_DIR)/kernel.bin of=$@ bs=512 seek=16 conv=notrunc status=none
|
|
@echo "=== [SUB-OS x86_64 Disk Image Built: $@ (Size: $$(du -h $@ | cut -f1))] ==="
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Execution & Emulation Targets
|
|
# -----------------------------------------------------------------------------
|
|
# -vga std gives the Bochs VBE adapter the kernel drives. vgamem_mb is raised
|
|
# because a 1280x720 32-bit framebuffer needs more than the 8 MB default.
|
|
QEMU_VGA = -device VGA,vgamem_mb=64
|
|
|
|
# `make run` boots straight into the SUB-OS Graphical Desktop Environment. The
|
|
# guest window scales with zoom-to-fit; pass `nogui`/`text` on the kernel
|
|
# command line for the emergency TTY. Use `make run-headless` for serial only.
|
|
run qemu: $(TARGET)
|
|
ifeq ($(ARCH), x86_64)
|
|
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) -m 512M \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 $(QEMU_VGA) -display gtk,zoom-to-fit=on -serial stdio
|
|
else ifneq ($(filter $(ARCH), aarch64 arm64),)
|
|
qemu-system-aarch64 -M virt -cpu cortex-a57 -m 256M -kernel $(BUILD_DIR)/kernel.elf -device virtio-gpu-pci -serial stdio
|
|
else
|
|
qemu-system-arm -M virt -cpu cortex-a15 -m 256M -kernel $(BUILD_DIR)/kernel.elf -device virtio-gpu-pci -serial stdio
|
|
endif
|
|
|
|
# Headless: no graphical window, kernel console on the serial line only. Boot
|
|
# with `nogui` on the kernel command line to reach the TTY in this mode.
|
|
run-headless: $(TARGET)
|
|
$(QEMU_CMD)
|
|
|
|
# Fullscreen without distortion: zoom-to-fit scales the guest while preserving
|
|
# its aspect ratio, letterboxing rather than stretching on a wider panel.
|
|
run-fullscreen: $(TARGET)
|
|
ifeq ($(ARCH), x86_64)
|
|
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 $(QEMU_VGA) \
|
|
-display gtk,zoom-to-fit=on,show-cursor=on -full-screen -serial stdio
|
|
else
|
|
@echo "run-fullscreen targets x86_64 only"
|
|
endif
|
|
|
|
run-vnc: $(TARGET)
|
|
ifeq ($(ARCH), x86_64)
|
|
@echo "=== [QEMU VNC Server running at localhost:5900 (VNC Display :0)] ==="
|
|
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 $(QEMU_VGA) -vnc :0 -serial stdio
|
|
else
|
|
@echo "=== [QEMU VNC Server running at localhost:5900 (VNC Display :0)] ==="
|
|
qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -kernel $(BUILD_DIR)/kernel.elf -device virtio-gpu-pci -vnc :0 -serial stdio
|
|
endif
|
|
|
|
run-server: $(IMAGE)
|
|
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 -serial stdio -display none
|
|
|
|
debug: $(TARGET)
|
|
ifeq ($(ARCH), x86_64)
|
|
qemu-system-x86_64 -drive format=raw,file=$(IMAGE) \
|
|
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \
|
|
-device e1000,netdev=net0 -serial stdio -s -S
|
|
else ifneq ($(filter $(ARCH), aarch64 arm64),)
|
|
qemu-system-aarch64 -M virt -cpu cortex-a57 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf -s -S
|
|
else
|
|
qemu-system-arm -M virt -cpu cortex-a15 -m 128M -nographic -kernel $(BUILD_DIR)/kernel.elf -s -S
|
|
endif
|
|
|
|
info:
|
|
@echo "Target Architecture: $(ARCH)"
|
|
@echo "Cross Compiler: $(CROSS_COMPILE)"
|
|
@echo "Compiled Sources: $(words $(ALL_C_SRCS)) C files"
|
|
@echo "Target Binary: $(TARGET)"
|
|
|
|
help:
|
|
@echo "SUB-OS Kernel Build System (Linux-Style Kconfig)"
|
|
@echo "=================================================="
|
|
@echo " make configure - Launch interactive Linux-style TUI Configurator"
|
|
@echo " make menuconfig - Alias for make configure"
|
|
@echo " make defconfig - Reset to default configuration for active ARCH"
|
|
@echo " make x86_64_defconfig - Load x86_64 default configuration"
|
|
@echo " make aarch64_defconfig- Load AArch64 default configuration"
|
|
@echo " make armv8i_defconfig - Load ARMv8i (32-bit ARM) default configuration"
|
|
@echo " make all [ARCH=...] - Compile kernel image for selected architecture"
|
|
@echo " make run [ARCH=...] - Boot into the SUB-OS Graphical Desktop in QEMU"
|
|
@echo " make run-headless - Boot in QEMU with serial console only (no window)"
|
|
@echo " make run-fullscreen - Boot the desktop in a full-screen QEMU window"
|
|
@echo " make run-vnc - Boot the desktop and expose it over VNC :0"
|
|
@echo " make clean - Remove all compiled objects and disk images"
|
|
@echo " make info - Display build configuration and source metrics"
|
|
|
|
clean:
|
|
rm -rf $(BUILD_DIR) $(IMAGE)
|
|
|
|
-include $(DEPS)
|