From 8c09ccef6687b22f5be443137d787ff777b31089 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Sun, 25 Oct 2026 08:27:09 +0100 Subject: [PATCH] feat: add support for aarch64 timer/interrupts, port MontaukOS userspace --- .gitignore | 7 + GNUmakefile | 38 +- docs/porting.md | 55 ++- kernel/GNUmakefile | 4 +- kernel/src/ACPI/AcpiShutdown.cpp | 35 +- kernel/src/ACPI/FADT.cpp | 2 + kernel/src/ACPI/FADT.hpp | 8 + kernel/src/Api/BuildNo.hpp | 2 +- kernel/src/Api/Power.hpp | 3 + kernel/src/Arch/Cpu.hpp | 5 + kernel/src/Arch/Platform.hpp | 4 + kernel/src/Arch/aarch64/Cpu.hpp | 15 + kernel/src/Arch/aarch64/Gic.hpp | 40 ++ kernel/src/Arch/aarch64/Interrupts.cpp | 391 ++++++++++++++++-- kernel/src/Arch/aarch64/PerCpu.hpp | 2 + kernel/src/Arch/aarch64/Platform.cpp | 63 ++- kernel/src/Arch/aarch64/Timer.cpp | 103 ++++- kernel/src/Arch/x86_64/Cpu.hpp | 3 + kernel/src/Arch/x86_64/Platform.cpp | 4 + kernel/src/Drivers/USB/Xhci.cpp | 26 +- kernel/src/Efi/UEFI.hpp | 13 +- kernel/src/Sched/ElfLoader.cpp | 2 + kernel/src/Sched/Scheduler.cpp | 1 + programs/GNUmakefile | 77 ++-- programs/include/gui/framebuffer.hpp | 18 +- programs/include/libc/montauk.h | 62 +++ programs/include/libc/setjmp.h | 6 +- programs/include/montauk/syscall.h | 77 +++- programs/lib/libc/Makefile | 35 +- programs/lib/libc/arch/setjmp-aarch64.S | 49 +++ .../libc/{setjmp.S => arch/setjmp-x86_64.S} | 0 programs/lib/libc/crt/crt1.c | 23 ++ programs/lib/libc/libc.c | 51 +++ programs/lib/libjpeg/Makefile | 16 +- programs/lib/libjpeg/libjpeg.a | Bin 330174 -> 330174 bytes programs/lib/libjpeg/obj/stb_image_impl.o | Bin 329536 -> 329536 bytes programs/lib/libjpegwrite/Makefile | 16 +- programs/lib/libjpegwrite/libjpegwrite.a | Bin 134104 -> 134104 bytes .../libjpegwrite/obj/stb_image_write_impl.o | Bin 133600 -> 133600 bytes programs/lib/tls/Makefile | 22 +- programs/lib/tls/libtls.a | Bin 114598 -> 121646 bytes programs/lib/tls/obj/tls.o | Bin 114152 -> 121200 bytes programs/link.ld | 5 +- programs/mk/arch.mk | 43 ++ programs/src/2048/Makefile | 15 +- programs/src/audio/Makefile | 15 +- programs/src/bluetooth/Makefile | 15 +- programs/src/calculator/Makefile | 15 +- programs/src/capabilities/Makefile | 13 +- programs/src/charmap/Makefile | 15 +- programs/src/crashpad/Makefile | 13 +- programs/src/desktop/Makefile | 16 +- programs/src/devexplorer/Makefile | 15 +- programs/src/dialogs/Makefile | 24 +- programs/src/disks/Makefile | 15 +- programs/src/display/Makefile | 13 +- programs/src/fetch/Makefile | 16 +- programs/src/files/Makefile | 13 +- programs/src/fontpreview/Makefile | 14 +- programs/src/imageviewer/Makefile | 14 +- programs/src/installer/Makefile | 15 +- programs/src/keyboard/Makefile | 12 +- programs/src/libloader/Makefile | 21 +- programs/src/login/Makefile | 14 +- programs/src/lua/Makefile | 23 +- programs/src/mandelbrot/Makefile | 15 +- programs/src/music/Makefile | 15 +- programs/src/network/Makefile | 13 +- programs/src/paint/Makefile | 15 +- programs/src/pdfviewer/Makefile | 19 +- programs/src/powermgr/Makefile | 15 +- programs/src/printctl/Makefile | 18 +- programs/src/printd/Makefile | 14 +- programs/src/printers/Makefile | 13 +- programs/src/procmgr/Makefile | 15 +- programs/src/rtlsdr/Makefile | 10 +- programs/src/screenshot/Makefile | 12 +- programs/src/sdr/Makefile | 12 +- programs/src/settings/Makefile | 12 +- programs/src/shell/Makefile | 18 +- programs/src/spreadsheet/Makefile | 17 +- programs/src/sshd/Makefile | 10 +- programs/src/sshserver/Makefile | 10 +- programs/src/syslog/Makefile | 15 +- programs/src/tcc/Makefile | 25 +- programs/src/terminal/Makefile | 15 +- programs/src/texteditor/Makefile | 17 +- programs/src/timezone/Makefile | 13 +- programs/src/video/Makefile | 15 +- programs/src/weather/Makefile | 14 +- programs/src/wiki/Makefile | 16 +- programs/src/wikipedia/Makefile | 14 +- programs/src/wordprocessor/Makefile | 15 +- scripts/copy_fonts.sh | 2 +- scripts/copy_icons.sh | 2 +- scripts/install_apps.sh | 3 +- toolchain/README.md | 28 +- toolchain/build-montauk-toolchain.sh | 132 ++++-- toolchain/files/aarch64-montauk.h | 43 ++ .../binutils-2.43.1-montauk-aarch64.patch | 35 ++ .../patches/gcc-14.2.0-montauk-aarch64.patch | 40 ++ 101 files changed, 1720 insertions(+), 629 deletions(-) create mode 100644 kernel/src/Arch/aarch64/Gic.hpp create mode 100644 programs/lib/libc/arch/setjmp-aarch64.S rename programs/lib/libc/{setjmp.S => arch/setjmp-x86_64.S} (100%) create mode 100644 programs/mk/arch.mk create mode 100644 toolchain/files/aarch64-montauk.h create mode 100644 toolchain/patches/binutils-2.43.1-montauk-aarch64.patch create mode 100644 toolchain/patches/gcc-14.2.0-montauk-aarch64.patch diff --git a/.gitignore b/.gitignore index 146337c..d88c9c7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,14 @@ toolchain/local/ toolchain/build/ toolchain/src/ toolchain/sysroot/ +toolchain/sysroot-*/ programs/bin/ +# Non-x86 userspace builds (programs/mk/arch.mk) +programs/bin-*/ +programs/obj-*/ +programs/src/*/obj-*/ +programs/lib/*/obj-*/ +programs/lib/*/build-*/ programs/obj/ programs/src/*/obj/ programs/libs/*/obj/ diff --git a/GNUmakefile b/GNUmakefile index f2c0906..afb66b8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,12 +10,15 @@ QEMUFLAGS := -smp 4 -m 2G -d int -D qemu.log -no-reboot override IMAGE_NAME := montauk-$(ARCH) -# Userspace exists only for x86_64 so far: other architectures get a -# ramdisk holding just the boot files. +# KERNEL_ONLY=1 builds a ramdisk holding just the boot files (no +# userspace), for bringing up a kernel on a new architecture. +KERNEL_ONLY ?= 0 + +# programs/ builds x86_64 into bin/, other architectures into bin-/. ifeq ($(ARCH),x86_64) - KERNEL_ONLY ?= 0 + PROGRAMS_BIN := programs/bin else - KERNEL_ONLY ?= 1 + PROGRAMS_BIN := programs/bin-$(ARCH) endif override EFI_LOADER_x86_64 := BOOTX64.EFI @@ -23,6 +26,13 @@ override EFI_LOADER_aarch64 := BOOTAA64.EFI override EFI_LOADER_riscv64 := BOOTRISCV64.EFI override EFI_LOADER_loongarch64 := BOOTLOONGARCH64.EFI +# The host strip handles x86_64 images; other targets use their toolchain's. +ifeq ($(ARCH),x86_64) + STRIP := strip +else + STRIP := toolchain/local/bin/$(ARCH)-montauk-strip +endif + # AArch64 UEFI firmware for QEMU (Debian/Ubuntu: qemu-efi-aarch64). AARCH64_EFI_FIRMWARE ?= /usr/share/qemu-efi-aarch64/QEMU_EFI.fd @@ -227,12 +237,12 @@ ramdisk: limine/limine kernel rm -rf .kernel-only-root else ramdisk: limine/limine kernel programs - mkdir -p programs/bin/boot/limine - cp -v limine/$(EFI_LOADER_$(ARCH)) programs/bin/boot/limine/ - cp -v limine.conf programs/bin/boot/limine/ - cp -v kernel/bin-$(ARCH)/kernel programs/bin/boot/ - rm -f programs/bin/boot/ramdisk.tar - ./scripts/mkramdisk.sh programs/bin ramdisk.tar + mkdir -p $(PROGRAMS_BIN)/boot/limine + cp -v limine/$(EFI_LOADER_$(ARCH)) $(PROGRAMS_BIN)/boot/limine/ + cp -v limine.conf $(PROGRAMS_BIN)/boot/limine/ + cp -v kernel/bin-$(ARCH)/kernel $(PROGRAMS_BIN)/boot/ + rm -f $(PROGRAMS_BIN)/boot/ramdisk.tar + ./scripts/mkramdisk.sh $(PROGRAMS_BIN) ramdisk.tar endif $(IMAGE_NAME).iso: limine/limine kernel ramdisk @@ -292,8 +302,8 @@ release: limine/limine kernel ramdisk rm -rf iso_root .release-tmp mkdir -p iso_root/boot cp kernel/bin-$(ARCH)/kernel iso_root/boot/ - strip iso_root/boot/kernel - cp -r programs/bin .release-tmp + $(STRIP) iso_root/boot/kernel + cp -r $(PROGRAMS_BIN) .release-tmp # A release ISO ships only in-tree apps, so drop any out-of-tree port bundles # that happen to be staged in programs/bin/apps (each carries a .port marker). # Pass RELEASE_WITH_PORTS=1 to deliberately cut a ports-included image. @@ -317,11 +327,11 @@ ifeq ($(RELEASE_WITHOUT_SDK),1) .release-tmp/sdk/libexec .release-tmp/sdk/x86_64-montauk endif rm -f $(addprefix .release-tmp/os/,$(RELEASE_EXCLUDE_PROGRAMS)) - find .release-tmp -name '*.elf' -exec strip {} + + find .release-tmp -name '*.elf' -exec $(STRIP) {} + # The ramdisk carries its own copy of the kernel at 0:/boot/kernel -- that is # the image the Installer lays down on the target disk -- and it is not named # *.elf, so the find above misses it. Unstripped it is ~6 MB against ~0.7 MB. - strip .release-tmp/boot/kernel + $(STRIP) .release-tmp/boot/kernel ./scripts/mkramdisk.sh .release-tmp iso_root/boot/ramdisk.tar rm -rf .release-tmp mkdir -p iso_root/boot/limine diff --git a/docs/porting.md b/docs/porting.md index b24eea2..5e53c83 100644 --- a/docs/porting.md +++ b/docs/porting.md @@ -105,29 +105,64 @@ dispatch table (`ArchIrqDispatch`), panic-frame printing, and: between them (device space on ARM). MAIR: 0 Normal WB, 1 Normal NC (`MapWC`), 2 Device-nGnRE (`MapMMIO`). +- GICv2 (`Interrupts.cpp`, from the MADT): IRQ slots map onto INTIDs -- + `IRQ_TIMER` onto the generic timer's PPI, the MSI slots (24-45) onto the + SPIs of a GICv2m MSI frame (`ComposeMsi`), the IPI slots onto SGIs 0/1. + Interrupts are completed (EOI) before the handler runs, as on x86; a + level-triggered source drops its line first in an ack hook. +- Generic timer tick (`Timer.cpp`): the EL1 virtual timer at + `CNTFRQ_EL0`, its PPI from the GTDT, re-armed from the ack hook. +- PSCI `SYSTEM_RESET` / `SYSTEM_OFF` (`Arch::Reboot` / `Arch::PowerOff`) + through the conduit the FADT's ARM_BOOT_ARCH names. Hardware-reduced + ACPI has no PM1 block, so `AcpiShutdown` leaves power-off to the port. +- `Arch::SyncInstructionCache` after the ELF loader writes code: ARM + instruction fetch does not snoop data writes (QEMU hides this; real + cores do not). EL0 may maintain caches itself (`SCTLR_EL1.UCI`). + Not yet written (each is marked `TODO(aarch64)`): -- GIC driver: SPI routing, SGIs for IPIs, MSIs via ITS/GICv2m - (`ComposeMsi` returns false, so drivers fall back to INTx/polling). IRQs - reach `ArchIrqException`, which only logs them. -- Generic timer tick (`Arch::Timer::InitializeBsp` returns false). Boot - currently stops in the first driver that waits on `GetMilliseconds()` - (xHCI port power-up). -- Secondary CPU start-up, PSCI reset and suspend. +- Secondary CPU start-up (`Smp::BootAPs`). +- PCI INTx: the PC interrupt lines (slots 1-23) have no ARM meaning, so + `RouteLegacyIrq` refuses them. Routing a PCI pin needs its `_PRT` + entry and a GSI-based routing call; until then PCI drivers use MSI + (GICv2m) or polling. + +The generic kernel is compiled `-fsigned-char` for AArch64: it was written +for x86's signed plain `char`. Building it needs `clang` and `ld.lld`; without a system `ld.lld` the kernel makefile uses the one rustup ships (`~/.rustup/toolchains/*/lib/rustlib/*/bin/gcc-ld/ld.lld`), and `KERNEL_LD=` -overrides both. `make run ARCH=aarch64` boots a kernel-only image (userspace -is x86_64-only so far) on QEMU `virt` with a GICv2 and Cortex-A72 cores, the +overrides both. `make run ARCH=aarch64` boots the full image (desktop, apps, +USB keyboard and mouse) on QEMU `virt` with a GICv2 and Cortex-A72 cores, the Raspberry Pi 4/400's configuration; it needs `qemu-system-aarch64` and -`qemu-efi-aarch64`. +`qemu-efi-aarch64`, and the userspace compiler +(`./toolchain/build-montauk-toolchain.sh aarch64`). `KERNEL_ONLY=1` builds an +image without userspace. The kernel console is mirrored to the serial port the ACPI SPCR table names (PL011, SBSA UART, 16550 or the BCM2835 mini UART; `Drivers/Serial/Uart.cpp`), including the log written before the port was found. On QEMU that is `-serial stdio`. +## Userspace + +The programs are architecture-neutral C/C++ built by `-montauk-gcc` +(see `toolchain/README.md`). `programs/mk/arch.mk` holds everything +architecture-specific in the build: the toolchain prefix, FP/SIMD flag sets +(`ARCH_FP_FLAGS` for GUI apps, `ARCH_NOFP_FLAGS` for system programs) and the +output layout. x86_64 keeps `bin/`, `obj/` and libraries next to their +sources; other architectures build beside them into `bin-/`, +`obj-/` and `lib//build-/`, so both can be built from one +tree. The few architecture-specific sources are the raw system-call +wrappers (`#if defined(__x86_64__)` / `__aarch64__` blocks in +`montauk/syscall.h`, `libc/montauk.h`, `lib/libc/libc.c` and +`lib/libc/crt/crt1.c`), `lib/libc/arch/setjmp-.S` and the scanout +store fence in `gui/framebuffer.hpp`. + +Not built for AArch64: tcc (it generates x86 code), the on-OS SDK and the +Rust programs (their `x86_64-unknown-montauk` target). + ## Adding another architecture 1. Create `kernel/src/Arch//` with the six inline headers listed above diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile index e3564c5..18f1502 100644 --- a/kernel/GNUmakefile +++ b/kernel/GNUmakefile @@ -153,8 +153,10 @@ ifeq ($(ARCH),aarch64) override CXX += \ -target aarch64-unknown-none endif + # Plain char is signed on x86; the generic kernel is written for that. override SHARED_FLAGS += \ - -mgeneral-regs-only + -mgeneral-regs-only \ + -fsigned-char override LDFLAGS += \ -Wl,-m,aarch64elf endif diff --git a/kernel/src/ACPI/AcpiShutdown.cpp b/kernel/src/ACPI/AcpiShutdown.cpp index d3990f5..b62f1dd 100644 --- a/kernel/src/ACPI/AcpiShutdown.cpp +++ b/kernel/src/ACPI/AcpiShutdown.cpp @@ -38,8 +38,24 @@ namespace Hal { return; } - // Map and parse the DSDT to find \_S5_ auto* dsdt = (void*)Memory::HHDM(fadt.DsdtAddress); + + AML::InitializeInterpreter(dsdt, xsdt); + + if (AML::GetInterpreter().IsInitialized()) { + AcpiDevices::DeviceList devices{}; + AcpiDevices::EnumerateAll(devices); + } + + AcpiSleep::Initialize(xsdt); + + // Hardware-reduced ACPI (ARM) has no PM1 registers: the + // architecture powers off instead (Arch::PowerOff). + if ((fadt.Flags & FADT::FlagHardwareReduced) || fadt.PM1aControlBlock == 0) { + KernelLogStream(INFO, "ACPI") << "No PM1 control block - ACPI S5 shutdown unavailable"; + return; + } + AML::S5Object s5 = AML::FindS5(dsdt); if (!s5.Valid) { @@ -55,23 +71,6 @@ namespace Hal { KernelLogStream(OK, "ACPI") << "ACPI shutdown initialized (PM1a=" << base::hex << (uint64_t)g_pm1aControlBlock << " SLP_TYPa=" << (uint64_t)g_slpTypA << ")"; - - // Initialize the full AML interpreter with the DSDT. - // This loads the entire DSDT namespace, enabling device enumeration, - // method evaluation, and field I/O for the rest of the kernel. - AML::InitializeInterpreter(dsdt, xsdt); - - // Enumerate ACPI devices now that the namespace is loaded - if (AML::GetInterpreter().IsInitialized()) { - AcpiDevices::DeviceList devices{}; - AcpiDevices::EnumerateAll(devices); - } - - // Initialize S3 suspend support (reads FACS and \_S3_ from namespace) - AcpiSleep::Initialize(xsdt); - - // Note: ACPI event handling (SCI, power button) is initialized - // from Main.cpp after the APIC subsystem is ready. } bool IsAvailable() { diff --git a/kernel/src/ACPI/FADT.cpp b/kernel/src/ACPI/FADT.cpp index 97dd57e..59ae9fe 100644 --- a/kernel/src/ACPI/FADT.cpp +++ b/kernel/src/ACPI/FADT.cpp @@ -107,6 +107,8 @@ namespace Hal { result.AcpiEnable = fadt->AcpiEnable; result.AcpiDisable = fadt->AcpiDisable; result.Flags = fadt->Flags; + result.ArmBootArchFlags = fadt->Header.Length >= offsetof(Table, ArmBootArchFlags) + 2 + ? fadt->ArmBootArchFlags : 0; result.Valid = true; KernelLogStream(INFO, "FADT") << "DSDT at " << base::hex << result.DsdtAddress; diff --git a/kernel/src/ACPI/FADT.hpp b/kernel/src/ACPI/FADT.hpp index d7d6692..1977f3a 100644 --- a/kernel/src/ACPI/FADT.hpp +++ b/kernel/src/ACPI/FADT.hpp @@ -69,6 +69,13 @@ namespace Hal { uint8_t X_GPE1Block[12]; } __attribute__((packed)); + // FADT Flags + constexpr uint32_t FlagHardwareReduced = 1u << 20; + + // ARM_BOOT_ARCH flags (ACPI 5.1+) + constexpr uint16_t ArmBootPsciCompliant = 1u << 0; + constexpr uint16_t ArmBootPsciUseHvc = 1u << 1; + struct ParsedFADT { uint64_t DsdtAddress; uint64_t FacsAddress; @@ -91,6 +98,7 @@ namespace Hal { uint8_t AcpiEnable; uint8_t AcpiDisable; uint32_t Flags; + uint16_t ArmBootArchFlags; // 0 when the table predates the field bool Valid; }; diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 0a5fc31..084f2b1 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 29 +#define MONTAUK_BUILD_NUMBER 37 diff --git a/kernel/src/Api/Power.hpp b/kernel/src/Api/Power.hpp index d170117..b31cfd0 100644 --- a/kernel/src/Api/Power.hpp +++ b/kernel/src/Api/Power.hpp @@ -73,6 +73,9 @@ namespace montauk::abi { Hal::AcpiShutdown::Shutdown(); } + /* Hardware-reduced platforms (PSCI on ARM) */ + Arch::PowerOff(); + /* Fallback: EFI ResetSystem */ if (Efi::g_ResetSystem) { Memory::VMM::ActivateKernelAddressSpace(); diff --git a/kernel/src/Arch/Cpu.hpp b/kernel/src/Arch/Cpu.hpp index 55b83be..0556960 100644 --- a/kernel/src/Arch/Cpu.hpp +++ b/kernel/src/Arch/Cpu.hpp @@ -79,6 +79,11 @@ namespace Arch { // Write back and invalidate all CPU caches (before power state changes). inline void WritebackInvalidateCaches(); + // Make instructions just written to [address, address+size) (any + // mapping of them) visible to instruction fetch on every CPU. A no-op + // where instruction fetch snoops data writes (x86). + inline void SyncInstructionCache(const void* address, uint64_t size); + // Invalidate this CPU's translation for one virtual page. inline void FlushTlbPage(uint64_t virtualAddress); diff --git a/kernel/src/Arch/Platform.hpp b/kernel/src/Arch/Platform.hpp index 2a421fd..d9fc818 100644 --- a/kernel/src/Arch/Platform.hpp +++ b/kernel/src/Arch/Platform.hpp @@ -51,4 +51,8 @@ namespace Arch { // ResetSystem). Never returns. [[noreturn]] void Reboot(); + // Switch the machine off where ACPI S5 does not apply (hardware-reduced + // ACPI: ARM's PSCI SYSTEM_OFF). Returns if the platform cannot. + void PowerOff(); + } diff --git a/kernel/src/Arch/aarch64/Cpu.hpp b/kernel/src/Arch/aarch64/Cpu.hpp index da0475c..cceef3f 100644 --- a/kernel/src/Arch/aarch64/Cpu.hpp +++ b/kernel/src/Arch/aarch64/Cpu.hpp @@ -93,6 +93,21 @@ namespace Arch { } // The TLBI operand is VA[55:12] in bits [43:0]; the bits above are RES0. + // Clean the data cache to the point of unification, then invalidate + // the whole instruction cache: invalidating by address would only + // reach the alias it names on an aliasing (VIPT) instruction cache. + inline void SyncInstructionCache(const void* address, uint64_t size) { + uint64_t ctr; + asm volatile("mrs %0, ctr_el0" : "=r"(ctr)); + uint64_t line = 4ULL << ((ctr >> 16) & 0xF); // DminLine + uint64_t start = (uint64_t)address & ~(line - 1); + uint64_t end = (uint64_t)address + size; + for (uint64_t p = start; p < end; p += line) { + asm volatile("dc cvau, %0" :: "r"(p) : "memory"); + } + asm volatile("dsb ish\n\tic ialluis\n\tdsb ish\n\tisb" ::: "memory"); + } + inline void FlushTlbPage(uint64_t virtualAddress) { asm volatile("dsb ishst\n\ttlbi vaae1is, %0\n\tdsb ish\n\tisb" :: "r"((virtualAddress >> 12) & ((1ULL << 44) - 1)) : "memory"); diff --git a/kernel/src/Arch/aarch64/Gic.hpp b/kernel/src/Arch/aarch64/Gic.hpp new file mode 100644 index 0000000..51457ac --- /dev/null +++ b/kernel/src/Arch/aarch64/Gic.hpp @@ -0,0 +1,40 @@ +/* + * Gic.hpp + * aarch64 GICv2 interrupt controller (private to the port) + * Copyright (c) 2026 Daniel Hammer +*/ + +#pragma once +#include +#include + +namespace Arch::Gic { + + // Bring up the distributor and the calling CPU's interface from the + // ACPI MADT. Returns false when no usable GIC is described. + bool Initialize(Hal::ACPI::CommonSDTHeader* xsdt); + + bool IsInitialized(); + + // The XSDT Initialize was given (for the other ACPI tables the port reads). + Hal::ACPI::CommonSDTHeader* CurrentXsdt(); + + // Per-CPU part of Initialize, for secondary CPUs. + void InitializeCpuInterface(); + + // Map a private peripheral interrupt (16-31) onto an IRQ slot and enable + // it on the calling CPU. + void RoutePpi(uint32_t intid, uint8_t irq, bool edgeTriggered); + + // Called for an IRQ slot after the interrupt is acknowledged and before + // it is completed (EOI): level-triggered sources deassert here. + using AckHook = void (*)(); + void SetAckHook(uint8_t irq, AckHook hook); + + // The calling CPU's target bit, as the distributor sees it. + uint8_t CurrentTargetMask(); + + // Find an ACPI table in the XSDT by signature. + Hal::ACPI::CommonSDTHeader* FindTable(Hal::ACPI::CommonSDTHeader* xsdt, const char* signature); + +} diff --git a/kernel/src/Arch/aarch64/Interrupts.cpp b/kernel/src/Arch/aarch64/Interrupts.cpp index 256fcda..e0f52c4 100644 --- a/kernel/src/Arch/aarch64/Interrupts.cpp +++ b/kernel/src/Arch/aarch64/Interrupts.cpp @@ -1,63 +1,400 @@ /* * Interrupts.cpp - * aarch64 IRQ slot dispatch (implements Arch/Interrupts.hpp) + * aarch64 GICv2 driver and IRQ slot dispatch (implements Arch/Interrupts.hpp) * Copyright (c) 2026 Daniel Hammer */ #include +#include +#include +#include +#include #include #include -// IRQ slots are delivered by the interrupt controller driver (GICv2/v3, -// not written yet), which maps INTIDs onto slots and calls ArchIrqDispatch -// from the IRQ exception vector after acknowledging the interrupt. +// IRQ slots map onto GIC interrupt IDs (INTIDs): +// IRQ_TIMER the generic timer's PPI (Timer.cpp routes it) +// 24-45 (MSI slots) SPIs of the GICv2m MSI frame, one per slot +// IRQ_TLB_SHOOTDOWN, +// IRQ_RESCHEDULE SGIs 0 and 1 +// The PC platform lines (1-23) have no ARM equivalent; RouteLegacyIrq +// refuses them and drivers fall back to MSI or polling. + +using namespace Kt; namespace Arch { + // Distributor registers + static constexpr uint32_t GICD_CTLR = 0x000; + static constexpr uint32_t GICD_TYPER = 0x004; + static constexpr uint32_t GICD_ISENABLER = 0x100; + static constexpr uint32_t GICD_ICENABLER = 0x180; + static constexpr uint32_t GICD_ICPENDR = 0x280; + static constexpr uint32_t GICD_ICACTIVER = 0x380; + static constexpr uint32_t GICD_IPRIORITYR = 0x400; + static constexpr uint32_t GICD_ITARGETSR = 0x800; + static constexpr uint32_t GICD_ICFGR = 0xC00; + static constexpr uint32_t GICD_SGIR = 0xF00; + + // CPU interface registers + static constexpr uint32_t GICC_CTLR = 0x00; + static constexpr uint32_t GICC_PMR = 0x04; + static constexpr uint32_t GICC_BPR = 0x08; + static constexpr uint32_t GICC_IAR = 0x0C; + static constexpr uint32_t GICC_EOIR = 0x10; + + // GICv2m MSI frame registers + static constexpr uint32_t V2M_MSI_TYPER = 0x008; + static constexpr uint32_t V2M_MSI_SETSPI_NS = 0x040; + + static constexpr uint32_t SpuriousIntid = 1020; + static constexpr uint32_t MaxIntids = 1020; + static constexpr uint8_t DefaultPriority = 0xA0; + static constexpr uint8_t NoSlot = 0xFF; + + static constexpr uint8_t FirstMsiSlot = 24; + static constexpr uint8_t LastMsiSlot = 45; + + // MADT interrupt-controller structures (ACPI 6.x) + static constexpr uint8_t MadtGicc = 0x0B; + static constexpr uint8_t MadtGicd = 0x0C; + static constexpr uint8_t MadtGicMsiFrame = 0x0D; + + struct MadtEntry { + uint8_t Type; + uint8_t Length; + } __attribute__((packed)); + + struct MadtGiccEntry { + MadtEntry Header; + uint16_t Reserved; + uint32_t CpuInterfaceNumber; + uint32_t AcpiProcessorUid; + uint32_t Flags; + uint32_t ParkingProtocolVersion; + uint32_t PerformanceInterruptGsiv; + uint64_t ParkedAddress; + uint64_t PhysicalBaseAddress; // GICC + uint64_t Gicv; + uint64_t Gich; + uint32_t VgicMaintenanceInterrupt; + uint64_t GicrBaseAddress; + uint64_t Mpidr; + } __attribute__((packed)); + + struct MadtGicdEntry { + MadtEntry Header; + uint16_t Reserved; + uint32_t GicId; + uint64_t PhysicalBaseAddress; + uint32_t SystemVectorBase; + uint8_t GicVersion; + } __attribute__((packed)); + + struct MadtMsiFrameEntry { + MadtEntry Header; + uint16_t Reserved; + uint32_t FrameId; + uint64_t PhysicalBaseAddress; + uint32_t Flags; // bit 0: SpiCount/SpiBase override TYPER + uint16_t SpiCount; + uint16_t SpiBase; + } __attribute__((packed)); + + static constexpr uint32_t MadtHeaderSize = 44; // SDT header + LAPIC address + flags + static IrqHandler g_irqHandlers[IRQ_COUNT] = {}; + static Gic::AckHook g_ackHooks[IRQ_COUNT] = {}; + static uint8_t g_intidToSlot[MaxIntids]; + static uint32_t g_slotToIntid[IRQ_COUNT]; + + static volatile uint8_t* g_gicd = nullptr; + static volatile uint8_t* g_gicc = nullptr; + static uint32_t g_intidCount = 0; + + static Hal::ACPI::CommonSDTHeader* g_xsdt = nullptr; + + static uint64_t g_msiFramePhys = 0; + static uint32_t g_msiSpiBase = 0; + static uint32_t g_msiSpiCount = 0; + + static inline uint32_t GicdRead(uint32_t reg) { + return *(volatile uint32_t*)(g_gicd + reg); + } + + static inline void GicdWrite(uint32_t reg, uint32_t value) { + *(volatile uint32_t*)(g_gicd + reg) = value; + } + + static inline void GicdWrite8(uint32_t reg, uint8_t value) { + *(volatile uint8_t*)(g_gicd + reg) = value; + } + + static inline uint8_t GicdRead8(uint32_t reg) { + return *(volatile uint8_t*)(g_gicd + reg); + } + + static inline uint32_t GiccRead(uint32_t reg) { + return *(volatile uint32_t*)(g_gicc + reg); + } + + static inline void GiccWrite(uint32_t reg, uint32_t value) { + *(volatile uint32_t*)(g_gicc + reg) = value; + } + + static volatile uint8_t* MapRegisters(uint64_t phys, uint64_t size) { + for (uint64_t offset = 0; offset < size; offset += 0x1000) { + Memory::VMM::g_paging->MapMMIO(phys + offset, Memory::HHDM(phys + offset)); + } + return (volatile uint8_t*)Memory::HHDM(phys); + } + + static void SetConfig(uint32_t intid, bool edgeTriggered) { + uint32_t reg = GICD_ICFGR + (intid / 16) * 4; + uint32_t shift = (intid % 16) * 2 + 1; + uint32_t value = GicdRead(reg); + if (edgeTriggered) value |= 1u << shift; + else value &= ~(1u << shift); + GicdWrite(reg, value); + } + + static void EnableIntid(uint32_t intid) { + GicdWrite(GICD_ISENABLER + (intid / 32) * 4, 1u << (intid % 32)); + } + + static void Bind(uint32_t intid, uint8_t irq) { + if (intid >= MaxIntids || irq >= IRQ_COUNT) return; + g_intidToSlot[intid] = irq; + g_slotToIntid[irq] = intid; + } + + // Route a shared peripheral interrupt to the boot CPU and unmask it. + static void RouteSpi(uint32_t intid, uint8_t irq, bool edgeTriggered) { + if (intid < 32 || intid >= g_intidCount) return; + Bind(intid, irq); + GicdWrite8(GICD_IPRIORITYR + intid, DefaultPriority); + GicdWrite8(GICD_ITARGETSR + intid, Smp::GetCpuData(0)->arch.gicTargetMask); + SetConfig(intid, edgeTriggered); + EnableIntid(intid); + } + + namespace Gic { + + Hal::ACPI::CommonSDTHeader* FindTable(Hal::ACPI::CommonSDTHeader* xsdt, const char* signature) { + if (xsdt == nullptr) return nullptr; + uint32_t count = (xsdt->Length - sizeof(Hal::ACPI::CommonSDTHeader)) / 8; + auto* entries = (uint64_t*)((uint64_t)xsdt + sizeof(Hal::ACPI::CommonSDTHeader)); + for (uint32_t i = 0; i < count; i++) { + auto* header = (Hal::ACPI::CommonSDTHeader*)Memory::HHDM(entries[i]); + if (header->Signature[0] == signature[0] && header->Signature[1] == signature[1] + && header->Signature[2] == signature[2] && header->Signature[3] == signature[3]) { + return header; + } + } + return nullptr; + } + + // ITARGETSR0-7 are banked: each byte reads back the reading CPU's + // own interface bit. + uint8_t CurrentTargetMask() { + uint32_t value = GicdRead(GICD_ITARGETSR); + return (uint8_t)(value | value >> 8 | value >> 16 | value >> 24); + } + + void InitializeCpuInterface() { + // SGIs and PPIs are banked per CPU: disable the PPIs until a + // driver routes one, keep the SGIs (IPIs) enabled. + GicdWrite(GICD_ICENABLER, 0xFFFF0000u); + GicdWrite(GICD_ISENABLER, 0x0000FFFFu); + GicdWrite(GICD_ICPENDR, 0xFFFFFFFFu); + for (uint32_t intid = 0; intid < 32; intid++) { + GicdWrite8(GICD_IPRIORITYR + intid, DefaultPriority); + } + + GiccWrite(GICC_PMR, 0xF0); + GiccWrite(GICC_BPR, 0); + GiccWrite(GICC_CTLR, 1); + + auto* cpu = Smp::GetCurrentCpuData(); + cpu->arch.gicTargetMask = CurrentTargetMask(); + } + + void RoutePpi(uint32_t intid, uint8_t irq, bool edgeTriggered) { + if (intid < 16 || intid >= 32) return; + Bind(intid, irq); + SetConfig(intid, edgeTriggered); + EnableIntid(intid); + } + + void SetAckHook(uint8_t irq, AckHook hook) { + if (irq < IRQ_COUNT) g_ackHooks[irq] = hook; + } + + bool IsInitialized() { + return g_gicc != nullptr; + } + + Hal::ACPI::CommonSDTHeader* CurrentXsdt() { + return g_xsdt; + } + + bool Initialize(Hal::ACPI::CommonSDTHeader* xsdt) { + g_xsdt = xsdt; + auto* madt = FindTable(xsdt, "APIC"); + if (madt == nullptr) { + KernelLogStream(ERROR, "GIC") << "No MADT"; + return false; + } + + uint64_t gicdPhys = 0, giccPhys = 0; + uint8_t version = 0; + auto* cursor = (uint8_t*)madt + MadtHeaderSize; + auto* end = (uint8_t*)madt + madt->Length; + while (cursor + sizeof(MadtEntry) <= end) { + auto* entry = (MadtEntry*)cursor; + if (entry->Length < sizeof(MadtEntry)) break; + + if (entry->Type == MadtGicd) { + auto* gicd = (MadtGicdEntry*)entry; + gicdPhys = gicd->PhysicalBaseAddress; + version = gicd->GicVersion; + } else if (entry->Type == MadtGicc && giccPhys == 0) { + giccPhys = ((MadtGiccEntry*)entry)->PhysicalBaseAddress; + } else if (entry->Type == MadtGicMsiFrame && g_msiFramePhys == 0) { + auto* frame = (MadtMsiFrameEntry*)entry; + g_msiFramePhys = frame->PhysicalBaseAddress; + if (frame->Flags & 1) { + g_msiSpiBase = frame->SpiBase; + g_msiSpiCount = frame->SpiCount; + } + } + cursor += entry->Length; + } + + // Version 0 means "infer from the hardware"; 1 and 2 share a + // programming model. + if (gicdPhys == 0 || giccPhys == 0 || version > 2) { + KernelLogStream(ERROR, "GIC") << "No GICv2 in the MADT (version " + << base::dec << (uint64_t)version << ")"; + return false; + } + + for (uint32_t i = 0; i < MaxIntids; i++) g_intidToSlot[i] = NoSlot; + for (int i = 0; i < IRQ_COUNT; i++) g_slotToIntid[i] = SpuriousIntid; + Bind(0, IRQ_TLB_SHOOTDOWN); + Bind(1, IRQ_RESCHEDULE); + + g_gicd = MapRegisters(gicdPhys, 0x1000); + g_gicc = MapRegisters(giccPhys, 0x2000); + + g_intidCount = ((GicdRead(GICD_TYPER) & 0x1F) + 1) * 32; + if (g_intidCount > MaxIntids) g_intidCount = MaxIntids; + + // Distributor: everything masked, idle, level-triggered and + // aimed at no CPU until RouteSpi claims it. + GicdWrite(GICD_CTLR, 0); + for (uint32_t intid = 32; intid < g_intidCount; intid += 32) { + GicdWrite(GICD_ICENABLER + (intid / 32) * 4, 0xFFFFFFFFu); + GicdWrite(GICD_ICPENDR + (intid / 32) * 4, 0xFFFFFFFFu); + GicdWrite(GICD_ICACTIVER + (intid / 32) * 4, 0xFFFFFFFFu); + } + for (uint32_t intid = 32; intid < g_intidCount; intid++) { + GicdWrite8(GICD_IPRIORITYR + intid, DefaultPriority); + GicdWrite8(GICD_ITARGETSR + intid, 0); + } + for (uint32_t intid = 32; intid < g_intidCount; intid += 16) { + GicdWrite(GICD_ICFGR + (intid / 16) * 4, 0); + } + GicdWrite(GICD_CTLR, 1); + + InitializeCpuInterface(); + + if (g_msiFramePhys != 0) { + volatile uint8_t* frame = MapRegisters(g_msiFramePhys, 0x1000); + if (g_msiSpiCount == 0) { + uint32_t typer = *(volatile uint32_t*)(frame + V2M_MSI_TYPER); + g_msiSpiBase = (typer >> 16) & 0x3FF; + g_msiSpiCount = typer & 0x3FF; + } + } + + KernelLogStream(OK, "GIC") << "GICv2: distributor 0x" << base::hex << gicdPhys + << ", CPU interface 0x" << giccPhys << ", " << base::dec + << (uint64_t)g_intidCount << " interrupt IDs"; + if (g_msiSpiCount != 0) { + KernelLogStream(OK, "GIC") << "GICv2m MSI frame 0x" << base::hex << g_msiFramePhys + << ": SPIs " << base::dec << (uint64_t)g_msiSpiBase << "-" + << (uint64_t)(g_msiSpiBase + g_msiSpiCount - 1); + } + return true; + } + + } void RegisterIrqHandler(uint8_t irq, IrqHandler handler) { if (irq >= IRQ_COUNT) return; g_irqHandlers[irq] = handler; - Kt::KernelLogStream(Kt::DEBUG, "IRQ") << "Registered handler for IRQ " + KernelLogStream(DEBUG, "IRQ") << "Registered handler for IRQ " << base::dec << (uint64_t)irq; } - // TODO(aarch64): GIC SPI routing (ACPI MADT GICD / interrupt overrides). + // TODO(aarch64): PCI INTx needs the pin's _PRT GSI and a GSI-based + // routing call (RouteSpi with level/polarity); drivers poll until then. void RouteLegacyIrq(uint8_t irq) { - Kt::KernelLogStream(Kt::WARNING, "IRQ") << "aarch64: cannot route IRQ " - << base::dec << (uint64_t)irq << " (no GIC driver)"; + KernelLogStream(WARNING, "IRQ") << "aarch64: no PC interrupt line " + << base::dec << (uint64_t)irq << " to route"; } void EnableLegacyIrq(uint8_t irq) { RouteLegacyIrq(irq); } - // TODO(aarch64): GICv3 ITS / GICv2m doorbell. - bool ComposeMsi(uint8_t, MsiMessage&) { - return false; + bool ComposeMsi(uint8_t irq, MsiMessage& out) { + if (g_gicd == nullptr || irq < FirstMsiSlot || irq > LastMsiSlot) return false; + uint32_t index = irq - FirstMsiSlot; + if (index >= g_msiSpiCount) return false; + + uint32_t spi = g_msiSpiBase + index; + if (g_slotToIntid[irq] != spi) { + RouteSpi(spi, irq, true); + } + out = MsiMessage{ g_msiFramePhys + V2M_MSI_SETSPI_NS, spi }; + return true; } - // TODO(aarch64): GIC software-generated interrupts. - bool SendIpi(int, uint8_t) { - return false; + bool SendIpi(int cpuIndex, uint8_t irq) { + if (g_gicd == nullptr) return false; + auto* cpu = Smp::GetCpuData(cpuIndex); + if (cpu == nullptr || cpu->arch.gicTargetMask == 0) return false; + uint32_t sgi = g_slotToIntid[irq]; + if (sgi >= 16) return false; + + // Make the IPI's memory effects visible before it is raised. + asm volatile("dsb ishst" ::: "memory"); + GicdWrite(GICD_SGIR, ((uint32_t)cpu->arch.gicTargetMask << 16) | sgi); + return true; } } -// IRQ exception vector (Vectors.S). -// TODO(aarch64): acknowledge through the GIC CPU interface, translate the -// INTID to a slot and call ArchIrqDispatch. -extern "C" void ArchIrqException(void*, bool) { - static bool reported = false; - if (!reported) { - reported = true; - Kt::KernelLogStream(Kt::WARNING, "IRQ") << "aarch64: IRQ taken with no interrupt controller driver"; - } -} +// IRQ exception vector (Vectors.S). As on x86, the interrupt is completed +// BEFORE the handler runs: the handler may context-switch away and not +// come back here for a long time, and an un-EOId interrupt would hold this +// CPU's running priority up (no further ticks). Level-triggered sources +// get the chance to drop their line first through an ack hook. +extern "C" void ArchIrqException(void*, bool fromUser) { + using namespace Arch; + uint32_t iar = GiccRead(GICC_IAR); + uint32_t intid = iar & 0x3FF; + if (intid >= SpuriousIntid) return; -extern "C" void ArchIrqDispatch(uint64_t irq, bool fromUser) { - if (irq < Arch::IRQ_COUNT && Arch::g_irqHandlers[irq] != nullptr) { - Arch::g_irqHandlers[irq]((uint8_t)irq, fromUser); + uint8_t irq = g_intidToSlot[intid]; + if (irq != NoSlot && g_ackHooks[irq] != nullptr) { + g_ackHooks[irq](); + } + GiccWrite(GICC_EOIR, iar); + + if (irq != NoSlot && g_irqHandlers[irq] != nullptr) { + g_irqHandlers[irq](irq, fromUser); } } diff --git a/kernel/src/Arch/aarch64/PerCpu.hpp b/kernel/src/Arch/aarch64/PerCpu.hpp index 8514e10..393298a 100644 --- a/kernel/src/Arch/aarch64/PerCpu.hpp +++ b/kernel/src/Arch/aarch64/PerCpu.hpp @@ -17,6 +17,8 @@ namespace Arch { struct CpuState { uint64_t mpidr; // MPIDR_EL1 affinity of this CPU + uint8_t gicTargetMask; // GICv2 CPU-interface bit (SGI/SPI targets) + uint64_t timerPeriod; // tick period in counter ticks, 0 = stopped }; // TPIDR_EL1 holds the CpuData pointer (zeroed in EarlyInitialize until diff --git a/kernel/src/Arch/aarch64/Platform.cpp b/kernel/src/Arch/aarch64/Platform.cpp index d56cb14..f9cf83c 100644 --- a/kernel/src/Arch/aarch64/Platform.cpp +++ b/kernel/src/Arch/aarch64/Platform.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -18,6 +20,42 @@ namespace Arch { // SCTLR_EL1.WXN: writable memory is execute-never static constexpr uint64_t SctlrWxn = 1ULL << 19; + // SCTLR_EL1.UCT/UCI: EL0 may read CTR_EL0 and clean/invalidate caches + // by address (what __builtin___clear_cache needs for generated code). + static constexpr uint64_t SctlrUct = 1ULL << 15; + static constexpr uint64_t SctlrUci = 1ULL << 26; + + // PSCI 0.2+ function IDs (SMC32 calling convention) + static constexpr uint64_t PsciSystemOff = 0x84000008; + static constexpr uint64_t PsciSystemReset = 0x84000009; + + // How the firmware takes PSCI calls, from the FADT's ARM_BOOT_ARCH. + enum class PsciConduit { None, Smc, Hvc }; + static PsciConduit g_psci = PsciConduit::None; + + static uint64_t PsciCall(uint64_t function) { + register uint64_t x0 asm("x0") = function; + register uint64_t x1 asm("x1") = 0; + register uint64_t x2 asm("x2") = 0; + register uint64_t x3 asm("x3") = 0; + if (g_psci == PsciConduit::Hvc) { + asm volatile("hvc #0" : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3) :: "memory"); + } else if (g_psci == PsciConduit::Smc) { + asm volatile("smc #0" : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3) :: "memory"); + } + return x0; + } + + static void InitializePsci(Hal::ACPI::CommonSDTHeader* xsdt) { + Hal::FADT::ParsedFADT fadt{}; + if (!Hal::FADT::Parse(xsdt, fadt) || !fadt.Valid) return; + if (!(fadt.ArmBootArchFlags & Hal::FADT::ArmBootPsciCompliant)) { + KernelLogStream(WARNING, "PSCI") << "Firmware is not PSCI compliant: no reset or power-off"; + return; + } + g_psci = (fadt.ArmBootArchFlags & Hal::FADT::ArmBootPsciUseHvc) ? PsciConduit::Hvc : PsciConduit::Smc; + KernelLogStream(OK, "PSCI") << "PSCI through " << (g_psci == PsciConduit::Hvc ? "HVC" : "SMC"); + } void EarlyInitialize() { // No per-CPU data yet: Smp::TryGetCurrentCpuData must see null. @@ -32,10 +70,11 @@ namespace Arch { asm volatile("msr vbar_el1, %0\n\tisb" :: "r"(ArchExceptionVectors) : "memory"); // Kernel mappings are RWX (Paging.cpp), so writable must not - // imply execute-never. + // imply execute-never; user code may maintain its own caches. uint64_t sctlr; asm volatile("mrs %0, sctlr_el1" : "=r"(sctlr)); sctlr &= ~SctlrWxn; + sctlr |= SctlrUct | SctlrUci; asm volatile("msr sctlr_el1, %0\n\tisb" :: "r"(sctlr)); // CPACR_EL1.FPEN = 0b11: FP/SIMD usable at EL0 and EL1 (the kernel @@ -57,10 +96,12 @@ namespace Arch { void InitializeMemoryAttributes() { } - // TODO(aarch64): GIC distributor/redistributor from the ACPI MADT. - void InitializeInterrupts(Hal::ACPI::CommonSDTHeader*) { + void InitializeInterrupts(Hal::ACPI::CommonSDTHeader* xsdt) { Smp::InitBsp(); - KernelLogStream(WARNING, "Arch") << "aarch64: no interrupt controller driver"; + if (!Gic::Initialize(xsdt)) { + KernelLogStream(ERROR, "Arch") << "aarch64: no interrupt controller, running without IRQs"; + } + InitializePsci(xsdt); } void InitializePlatformDevices() { @@ -73,12 +114,22 @@ namespace Arch { void LateInitialize() { } - void ListPlatformDevices(PlatformDeviceSink, void*) { + void ListPlatformDevices(PlatformDeviceSink sink, void* context) { + if (Gic::IsInitialized()) { + sink(context, 1, "GICv2", "ARM Generic Interrupt Controller"); + sink(context, 2, "Generic Timer", "ARM architected timer (EL1 virtual)"); + } } - // TODO(aarch64): PSCI SYSTEM_RESET through the conduit the FADT names. void Reboot() { + PsciCall(PsciSystemReset); HaltForever(); } + void PowerOff() { + if (g_psci != PsciConduit::None) { + PsciCall(PsciSystemOff); + } + } + } diff --git a/kernel/src/Arch/aarch64/Timer.cpp b/kernel/src/Arch/aarch64/Timer.cpp index 7f1d767..19367b5 100644 --- a/kernel/src/Arch/aarch64/Timer.cpp +++ b/kernel/src/Arch/aarch64/Timer.cpp @@ -1,24 +1,115 @@ /* * Timer.cpp - * aarch64 tick timer (implements Arch/Timer.hpp) + * aarch64 tick timer: the EL1 virtual generic timer (implements Arch/Timer.hpp) * Copyright (c) 2026 Daniel Hammer */ #include +#include +#include +#include +#include +#include +#include +#include -// TODO(aarch64): drive the EL1 virtual timer (CNTV_TVAL/CNTV_CTL) from -// CNTFRQ_EL0, re-arming on each tick, once the GIC delivers its PPI. +// The generic timer counts at CNTFRQ_EL0 on every CPU, so it needs no +// calibration. Each CPU's virtual timer raises a PPI (the GTDT names it, +// normally INTID 27); the tick is re-armed from the interrupt's ack hook, +// which also drops the level-triggered line before the EOI. + +using namespace Kt; namespace Arch::Timer { - bool InitializeBsp(uint32_t) { - return false; + // CNTV_CTL_EL0 + static constexpr uint64_t CtlEnable = 1ULL << 0; + static constexpr uint64_t CtlMask = 1ULL << 1; + + // GTDT timer flags + static constexpr uint32_t GtdtEdgeTriggered = 1u << 0; + + static constexpr uint32_t DefaultVirtualTimerIntid = 27; + + struct Gtdt { + Hal::ACPI::CommonSDTHeader Header; + uint64_t CntControlBase; + uint32_t Reserved; + uint32_t SecureEl1Gsiv; + uint32_t SecureEl1Flags; + uint32_t NonSecureEl1Gsiv; + uint32_t NonSecureEl1Flags; + uint32_t VirtualTimerGsiv; + uint32_t VirtualTimerFlags; + } __attribute__((packed)); + + static uint64_t g_ticksPerMs = 0; + static uint32_t g_intid = DefaultVirtualTimerIntid; + static bool g_edgeTriggered = false; + + static inline void WriteCtl(uint64_t value) { + asm volatile("msr cntv_ctl_el0, %0\n\tisb" :: "r"(value) : "memory"); } - void StartPeriodic(uint32_t) { + static inline uint64_t ReadCval() { + uint64_t value; + asm volatile("mrs %0, cntv_cval_el0" : "=r"(value)); + return value; + } + + static inline void WriteCval(uint64_t value) { + asm volatile("msr cntv_cval_el0, %0\n\tisb" :: "r"(value) : "memory"); + } + + // Advance the deadline by one period from the previous one (no drift), + // skipping ticks the CPU missed rather than replaying them. + static void Rearm() { + uint64_t period = Smp::GetCurrentCpuData()->arch.timerPeriod; + if (period == 0) { + WriteCtl(CtlMask); + return; + } + uint64_t now = ReadTimestamp(); + uint64_t next = ReadCval() + period; + if ((int64_t)(next - now) <= 0) next = now + period; + WriteCval(next); + } + + static void ReadGtdt() { + auto* gtdt = (Gtdt*)Gic::FindTable(Gic::CurrentXsdt(), "GTDT"); + if (gtdt == nullptr || gtdt->Header.Length < sizeof(Gtdt)) return; + if (gtdt->VirtualTimerGsiv >= 16 && gtdt->VirtualTimerGsiv < 32) { + g_intid = gtdt->VirtualTimerGsiv; + g_edgeTriggered = (gtdt->VirtualTimerFlags & GtdtEdgeTriggered) != 0; + } + } + + bool InitializeBsp(uint32_t periodMs) { + uint64_t frequency; + asm volatile("mrs %0, cntfrq_el0" : "=r"(frequency)); + if (frequency < 1000 || !Gic::IsInitialized()) return false; + g_ticksPerMs = frequency / 1000; + + ReadGtdt(); + Gic::SetAckHook(IRQ_TIMER, Rearm); + Gic::RoutePpi(g_intid, IRQ_TIMER, g_edgeTriggered); + StartPeriodic(periodMs); + + KernelLogStream(OK, "Timer") << "Generic timer: " << base::dec << frequency + << " Hz counter, virtual timer INTID " << (uint64_t)g_intid; + return true; + } + + void StartPeriodic(uint32_t periodMs) { + uint64_t period = g_ticksPerMs * periodMs; + Smp::GetCurrentCpuData()->arch.timerPeriod = period; + WriteCval(ReadTimestamp() + period); + WriteCtl(CtlEnable); } void Stop() { + Smp::GetCurrentCpuData()->arch.timerPeriod = 0; + WriteCtl(CtlMask); } } diff --git a/kernel/src/Arch/x86_64/Cpu.hpp b/kernel/src/Arch/x86_64/Cpu.hpp index e8cbbf4..5ac1480 100644 --- a/kernel/src/Arch/x86_64/Cpu.hpp +++ b/kernel/src/Arch/x86_64/Cpu.hpp @@ -79,6 +79,9 @@ namespace Arch { asm volatile("wbinvd" ::: "memory"); } + inline void SyncInstructionCache(const void*, uint64_t) { + } + inline void FlushTlbPage(uint64_t virtualAddress) { asm volatile("invlpg (%0)" :: "r"(virtualAddress) : "memory"); } diff --git a/kernel/src/Arch/x86_64/Platform.cpp b/kernel/src/Arch/x86_64/Platform.cpp index f0dbaf3..67bb360 100644 --- a/kernel/src/Arch/x86_64/Platform.cpp +++ b/kernel/src/Arch/x86_64/Platform.cpp @@ -77,4 +77,8 @@ namespace Arch { __builtin_unreachable(); } + // x86 powers off through ACPI S5 (AcpiShutdown). + void PowerOff() { + } + } diff --git a/kernel/src/Drivers/USB/Xhci.cpp b/kernel/src/Drivers/USB/Xhci.cpp index 1885520..3a0bcee 100644 --- a/kernel/src/Drivers/USB/Xhci.cpp +++ b/kernel/src/Drivers/USB/Xhci.cpp @@ -220,6 +220,13 @@ namespace Drivers::USB::Xhci { *(volatile uint32_t*)(g_opBase + reg) = value; } + // PollEvents() acknowledges the Port Status Change event, clearing PRC, + // so a controller that resets instantly (QEMU) can complete the reset + // between two reads of PRC. A port that left reset enabled is done too. + static bool PortResetComplete(uint32_t portsc) { + return (portsc & PORTSC_PRC) || ((portsc & PORTSC_PED) && !(portsc & PORTSC_PR)); + } + static uint32_t ReadOp(uint32_t reg) { return *(volatile uint32_t*)(g_opBase + reg); } @@ -474,6 +481,16 @@ namespace Drivers::USB::Xhci { BudgetExhausted, }; + // Without MSI nothing interrupts: the deferred-work check (timer and + // idle loop) looks at the event ring itself instead. This is the only + // mode on platforms whose PCIe has no MSI controller (Raspberry Pi 4). + static bool g_pollMode = false; + + static bool EventRingHasWork() { + const volatile TRB& evt = g_evtRing[g_evtRingDequeue]; + return ((evt.Control & TRB_CYCLE_BIT) != 0) == g_evtRingCCS; + } + static PollResult PollEventsBounded(uint32_t maxEvents) { // PollEvents runs from synchronous poll loops (ControlTransfer, // SendCommand, firmware download) and idle bottom halves on different @@ -1396,6 +1413,9 @@ namespace Drivers::USB::Xhci { } bool HasDeferredWork() { + if (g_initialized && g_pollMode && EventRingHasWork()) { + g_irqDrainPending.store(true, std::memory_order_release); + } return g_initialized && (g_irqDrainPending.load(std::memory_order_acquire) || g_deferredWorkPending.load(std::memory_order_acquire) || @@ -1537,7 +1557,7 @@ namespace Drivers::USB::Xhci { for (uint32_t i = 0; i < 100000; i++) { PollEvents(); uint32_t ps = ReadOp(OP_PORTSC_BASE + port * OP_PORTSC_STRIDE); - if (ps & PORTSC_PRC) { + if (PortResetComplete(ps)) { resetDone = true; break; } @@ -1732,6 +1752,7 @@ namespace Drivers::USB::Xhci { // MSI setup if (!SetupMsi(dev.Bus, dev.Device, dev.Function)) { KernelLogStream(WARNING, "xHCI") << "MSI not available, using poll mode"; + g_pollMode = true; } // Enable interrupter 0 @@ -1772,7 +1793,7 @@ namespace Drivers::USB::Xhci { for (uint32_t i = 0; i < 100000; i++) { PollEvents(); uint32_t ps = ReadOp(OP_PORTSC_BASE + port * OP_PORTSC_STRIDE); - if (ps & PORTSC_PRC) { resetDone = true; break; } + if (PortResetComplete(ps)) { resetDone = true; break; } for (int j = 0; j < 100; j++) Arch::CompilerBarrier(); } @@ -2045,6 +2066,7 @@ namespace Drivers::USB::Xhci { // ----------------------------------------------------------------- if (!SetupMsi(foundDev->Bus, foundDev->Device, foundDev->Function)) { KernelLogStream(WARNING, "xHCI") << "MSI not available, using poll mode"; + g_pollMode = true; } // ----------------------------------------------------------------- diff --git a/kernel/src/Efi/UEFI.hpp b/kernel/src/Efi/UEFI.hpp index f51d802..b15f6d6 100644 --- a/kernel/src/Efi/UEFI.hpp +++ b/kernel/src/Efi/UEFI.hpp @@ -276,6 +276,13 @@ namespace Efi { inline EFI_RESET_SYSTEM g_ResetSystem = nullptr; inline void Init(SystemTable* ST, const montauk::boot::EfiInfo& efi) { + /* The system table and the runtime regions are firmware-reserved + memory, which the HHDM does not cover on every architecture: + map them (identity and HHDM) before the first access. */ + if (Memory::VMM::g_paging) { + Memory::VMM::g_paging->MapEfiRuntime(efi); + } + Kt::KernelLogStream(Kt::OK, "UEFI") << "ST Minor Revision: " << ST->Header.Revision.MinorRevision; Kt::KernelLogStream(Kt::OK, "UEFI") << "ST Major Revision: " << ST->Header.Revision.MajorRevision; @@ -284,12 +291,6 @@ namespace Efi { if (ST->RuntimeServices != nullptr) { Kt::KernelLogStream(Kt::OK, "UEFI") << "EFI Runtime Service API is available."; - /* Identity-map EFI runtime service regions so firmware code - can reference its own data at physical addresses */ - if (Memory::VMM::g_paging) { - Memory::VMM::g_paging->MapEfiRuntime(efi); - } - EFI_TIME Time; EFI_TIME_CAPABILITIES TimeCapabilities; diff --git a/kernel/src/Sched/ElfLoader.cpp b/kernel/src/Sched/ElfLoader.cpp index 6faf8e5..ed441a3 100644 --- a/kernel/src/Sched/ElfLoader.cpp +++ b/kernel/src/Sched/ElfLoader.cpp @@ -528,6 +528,7 @@ namespace Sched { Fs::Vfs::CloseBackendFile(file); return 0; } + Arch::SyncInstructionCache(page, 0x1000); } } @@ -718,6 +719,7 @@ namespace Sched { uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + pageDataOffset; uint8_t* src = fileData + srcOffset; memcpy(dst, src, copySize); + Arch::SyncInstructionCache(dst, copySize); } } } diff --git a/kernel/src/Sched/Scheduler.cpp b/kernel/src/Sched/Scheduler.cpp index 300e899..a726b5a 100644 --- a/kernel/src/Sched/Scheduler.cpp +++ b/kernel/src/Sched/Scheduler.cpp @@ -442,6 +442,7 @@ namespace Sched { // User code that calls SYS_EXIT(0) Arch::WriteExitStub((uint8_t*)stubPage); + Arch::SyncInstructionCache(stubPage, 0x1000); } // Returning from the entry function lands in the exit stub. diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 9237c36..bdba443 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -2,20 +2,19 @@ MAKEFLAGS += -rR .SUFFIXES: -# Target architecture. -ARCH := x86_64 +# Target architecture (ARCH=x86_64 or aarch64) and the cross compiler +# from toolchain/local/. +include mk/arch.mk -# Auto-detect cross compiler from toolchain/local/. -TOOLCHAIN_PREFIX := $(shell cd .. && pwd)/toolchain/local/bin/x86_64-montauk- ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - CC = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) + CC = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ CC := $(TOOLCHAIN_PREFIX)gcc endif -# Compiler flags. The x86_64-montauk toolchain supplies the target ABI +# Compiler flags. The -montauk toolchain supplies the target ABI # (static ET_EXEC, 4 KiB pages, no red zone) and header paths; system # programs additionally avoid FP/SIMD and their own runtime (-nostdlib). override CXXFLAGS := \ @@ -30,10 +29,7 @@ override CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -I include # Linker flags: freestanding static ELF. @@ -43,7 +39,7 @@ override LDFLAGS := \ -T link.ld # Output directory. -BINDIR := bin +BINDIR := bin$(ARCH_SUFFIX) # Discover all programs (each subdirectory under src/ is a program). PROGRAMS := $(notdir $(wildcard src/*)) @@ -98,18 +94,34 @@ WPDST := $(patsubst $(WPDIR)/%,$(BINDIR)/os/wallpapers/%,$(WPSRC)) .PHONY: all clean 2048 files settings fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver sshd terminal syslog procmgr powermgr calculator charmap login desktop shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs icons fonts configs osdata bearssl libc tls libjpeg libjpegwrite install-apps libloader crashpad rtlsdr sdr check-syscalls gen-syscalls rust -all: bearssl libc libjpeg libjpegwrite tls libloader rtlsdr sdr devkit $(TARGETS) files settings fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities sshserver terminal syslog procmgr powermgr calculator charmap 2048 paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell sshd icons fonts install-apps crashpad rust $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(OSDATADST) $(FWDST) $(LICDST) $(WPDST) +# The on-OS SDK, tcc (an x86 code generator) and the Rust programs exist +# for x86_64 only. +ifneq ($(ARCH),x86_64) + ARCH_SKIP := devkit tcc rust +endif + +ALL_TARGETS := bearssl libc libjpeg libjpegwrite tls libloader rtlsdr sdr devkit $(TARGETS) files settings fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities sshserver terminal syslog procmgr powermgr calculator charmap 2048 paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs login desktop shell sshd icons fonts install-apps crashpad rust $(MANDST) $(WWWDST) $(CA_CERTS) $(CONFIGDST) $(OSDATADST) $(FWDST) $(LICDST) $(WPDST) + +all: $(filter-out $(ARCH_SKIP),$(ALL_TARGETS)) # Build BearSSL static library (cross-compiled for freestanding x86_64). -BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc) +BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/$(ARCH)/include -isystem $(abspath include/libc) +ifeq ($(ARCH),x86_64) + BEARSSL_ARCH_FLAGS := -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-red-zone -mcmodel=small +else + BEARSSL_ARCH_FLAGS := $(ARCH_CFLAGS) +endif +BEARSSL_LIB := lib/bearssl/build$(ARCH_SUFFIX)/libbearssl.a -lib/bearssl/build/libbearssl.a: +$(BEARSSL_LIB): $(MAKE) -C lib/bearssl CONF=MontaukOS \ BEARSSL_CC="$(CC)" \ BEARSSL_AR="$(TOOLCHAIN_PREFIX)ar" \ + BUILD=build$(ARCH_SUFFIX) \ + BEARSSL_ARCH_FLAGS="$(BEARSSL_ARCH_FLAGS)" \ BEARSSL_INCLUDES="$(BEARSSL_INCLUDES)" -bearssl: lib/bearssl/build/libbearssl.a +bearssl: $(BEARSSL_LIB) # Build shared libc static library. # @@ -120,11 +132,12 @@ bearssl: lib/bearssl/build/libbearssl.a # under -j and silently leaves programs linked against a stale libc. # Grouped target (&:, GNU make 4.3+): one sub-make produces all of them. LIBC_DIR := lib/libc -LIBC_LIB := $(LIBC_DIR)/liblibc.a +LIBC_LIB := $(LIBC_DIR)/$(ARCH_OUT)liblibc.a LIBC_SRCS := $(wildcard $(LIBC_DIR)/*.c $(LIBC_DIR)/*.h $(LIBC_DIR)/*.S \ $(LIBC_DIR)/crt/*.c) $(LIBC_DIR)/Makefile -LIBC_OUTPUTS := $(LIBC_LIB) $(LIBC_DIR)/liblibc-full.a \ - $(LIBC_DIR)/crt1.o $(LIBC_DIR)/crti.o $(LIBC_DIR)/crtn.o +LIBC_OUTPUTS := $(LIBC_LIB) $(LIBC_DIR)/$(ARCH_OUT)liblibc-full.a \ + $(LIBC_DIR)/$(ARCH_OUT)crt1.o $(LIBC_DIR)/$(ARCH_OUT)crti.o \ + $(LIBC_DIR)/$(ARCH_OUT)crtn.o $(LIBC_OUTPUTS) &: $(LIBC_SRCS) $(MAKE) -C $(LIBC_DIR) @@ -282,7 +295,7 @@ login: bearssl libc $(MAKE) -C src/login # Build shell via its own Makefile (multi-file build). -shell: +shell: libc $(MAKE) -C src/shell # Build desktop via its own Makefile (depends on libc, libjpeg, bearssl for user.h, dialogs, and registry config files). @@ -291,11 +304,11 @@ desktop: libc libjpeg bearssl libloader dialogs configs # Copy SVG icons for the desktop into bin/os/icons/. icons: - ../scripts/copy_icons.sh + PROGRAMS_BIN=$(BINDIR) ../scripts/copy_icons.sh # Copy TTF fonts for the desktop into bin/os/fonts/. fonts: - ../scripts/copy_fonts.sh + PROGRAMS_BIN=$(BINDIR) ../scripts/copy_fonts.sh # Copy default system config files into bin/config/. configs: $(CONFIGDST) @@ -400,7 +413,7 @@ crashpad: libc # Install app bundles (manifests, icons, data files) into bin/apps//. install-apps: 2048 files settings paint spreadsheet wordprocessor weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver terminal syslog procmgr powermgr calculator charmap screenshot texteditor mandelbrot printers timezone crashpad - ../scripts/install_apps.sh + PROGRAMS_BIN=$(BINDIR) ../scripts/install_apps.sh # Copy man pages into bin/os/man/ so mkramdisk.sh picks them up. $(BINDIR)/os/man/%: $(MANDIR)/% @@ -446,14 +459,16 @@ $(BINDIR)/os/wallpapers/%: $(WPDIR)/% # (montauk/capabilities.h, Api/Syscall.hpp, ...) rebuilds every program that # uses it. A missing depfile matches the empty rule below, which forces a # rebuild; that is how programs built before this tracking existed catch up. -$(BINDIR)/os/%.elf: src/%/main.cpp link.ld GNUmakefile $(LIBC_LIB) obj/%/main.elf.d - mkdir -p $(BINDIR)/os obj/$* - $(CXX) $(CXXFLAGS) -MMD -MP -MT $@ -MF obj/$*/main.elf.d -c src/$*/main.cpp -o obj/$*/main.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) obj/$*/main.o $(LIBC_LIB) -o $@ +OBJ := obj$(ARCH_SUFFIX) -obj/%/main.elf.d: ; -.PRECIOUS: obj/%/main.elf.d --include $(wildcard obj/*/main.elf.d) +$(BINDIR)/os/%.elf: src/%/main.cpp link.ld GNUmakefile $(LIBC_LIB) $(OBJ)/%/main.elf.d + mkdir -p $(BINDIR)/os $(OBJ)/$* + $(CXX) $(CXXFLAGS) -MMD -MP -MT $@ -MF $(OBJ)/$*/main.elf.d -c src/$*/main.cpp -o $(OBJ)/$*/main.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJ)/$*/main.o $(LIBC_LIB) -o $@ + +$(OBJ)/%/main.elf.d: ; +.PRECIOUS: $(OBJ)/%/main.elf.d +-include $(wildcard $(OBJ)/*/main.elf.d) # ============================================================================ # Native development kit (Montauk SDK): binutils built for MontaukOS @@ -524,7 +539,7 @@ else endif clean: - rm -rf $(BINDIR) obj $(RUST_DIR)/target + rm -rf $(BINDIR) $(OBJ) $(RUST_DIR)/target $(MAKE) -C lib/bearssl clean $(MAKE) -C lib/libc clean $(MAKE) -C lib/libjpeg clean diff --git a/programs/include/gui/framebuffer.hpp b/programs/include/gui/framebuffer.hpp index afb94ec..31f6b53 100644 --- a/programs/include/gui/framebuffer.hpp +++ b/programs/include/gui/framebuffer.hpp @@ -13,6 +13,18 @@ namespace gui { +// Drain write-combining stores to the scanout buffer before it is flipped +// or composited by someone else. +inline void wc_store_fence() { +#if defined(__x86_64__) + asm volatile("sfence" ::: "memory"); +#elif defined(__aarch64__) + asm volatile("dsb st" ::: "memory"); +#else +#error "unsupported architecture" +#endif +} + class Framebuffer { uint32_t* hw_fb; uint32_t* hw_fb2; // second scanout buffer (page flip), nullptr if unsupported @@ -322,12 +334,12 @@ public: montauk::memcpy(mirror, src, row_bytes); } } - if (hw_mirror) asm volatile("sfence" ::: "memory"); + if (hw_mirror) wc_store_fence(); if (hw_fb2) { // Wait for the latch (vsync): the buffer we just left becomes // safe to draw into only once the new one is actually scanning. - asm volatile("sfence" ::: "memory"); + wc_store_fence(); int64_t presented = montauk::fb_flip(hw_next, 1); if (presented == hw_next) { hw_next ^= 1; @@ -359,7 +371,7 @@ public: montauk::memcpy(mirror, src, row_bytes); } } - asm volatile("sfence" ::: "memory"); + wc_store_fence(); } } } diff --git a/programs/include/libc/montauk.h b/programs/include/libc/montauk.h index 44456a2..93a7a76 100644 --- a/programs/include/libc/montauk.h +++ b/programs/include/libc/montauk.h @@ -419,6 +419,8 @@ typedef struct { Raw syscall wrappers ==================================================================== */ +#if defined(__x86_64__) + static inline long _mtk_syscall0(long nr) { long ret; __asm__ volatile("syscall" : "=a"(ret) : "a"(nr) @@ -491,6 +493,66 @@ static inline long _mtk_syscall5(long nr, long a1, long a2, long a3, long a4, lo return ret; } +#elif defined(__aarch64__) + +// AArch64: number in x8, arguments in x0-x5, `svc #0`; the kernel +// preserves every register except x0, which carries the result. +static inline long _mtk_syscall0(long nr) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0"); + __asm__ volatile("svc #0" : "=r"(x0) : "r"(x8) : "memory"); + return x0; +} + +static inline long _mtk_syscall1(long nr, long a1) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8) : "memory"); + return x0; +} + +static inline long _mtk_syscall2(long nr, long a1, long a2) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1) : "memory"); + return x0; +} + +static inline long _mtk_syscall3(long nr, long a1, long a2, long a3) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + register long x2 __asm__("x2") = a3; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2) : "memory"); + return x0; +} + +static inline long _mtk_syscall4(long nr, long a1, long a2, long a3, long a4) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + register long x2 __asm__("x2") = a3; + register long x3 __asm__("x3") = a4; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3) : "memory"); + return x0; +} + +static inline long _mtk_syscall5(long nr, long a1, long a2, long a3, long a4, long a5) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + register long x2 __asm__("x2") = a3; + register long x3 __asm__("x3") = a4; + register long x4 __asm__("x4") = a5; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4) : "memory"); + return x0; +} + +#else +#error "unsupported architecture" +#endif + /* ==================================================================== Process management ==================================================================== */ diff --git a/programs/include/libc/setjmp.h b/programs/include/libc/setjmp.h index 9933b25..2da46f2 100644 --- a/programs/include/libc/setjmp.h +++ b/programs/include/libc/setjmp.h @@ -7,7 +7,11 @@ extern "C" { #endif -typedef unsigned long jmp_buf[8]; +#if defined(__aarch64__) +typedef unsigned long jmp_buf[21]; /* x19-x30, sp, d8-d15 */ +#else +typedef unsigned long jmp_buf[8]; /* rbx, rbp, r12-r15, rsp, rip */ +#endif int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val) __attribute__((noreturn)); diff --git a/programs/include/montauk/syscall.h b/programs/include/montauk/syscall.h index 0411a8a..917c350 100644 --- a/programs/include/montauk/syscall.h +++ b/programs/include/montauk/syscall.h @@ -1,6 +1,6 @@ /* * syscall.h - * MontaukOS program-side syscall wrappers using SYSCALL instruction + * MontaukOS program-side syscall wrappers (x86_64 SYSCALL, AArch64 SVC) * Copyright (c) 2025 Daniel Hammer */ @@ -13,6 +13,8 @@ namespace montauk { // ---- Raw SYSCALL wrappers ---- +#if defined(__x86_64__) + // The SYSCALL handler does not restore RDI, RSI, RDX, R10, R8, R9 // (they are skipped on the return path). We move arguments into the // correct registers inside the asm block and list ALL argument @@ -108,6 +110,79 @@ namespace montauk { return ret; } +#elif defined(__aarch64__) + + // AArch64: number in x8, arguments in x0-x5, `svc #0`; the kernel + // preserves every register except x0, which carries the result. + + inline int64_t syscall0(uint64_t nr) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0"); + asm volatile("svc #0" : "=r"(x0) : "r"(x8) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall1(uint64_t nr, uint64_t a1) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + asm volatile("svc #0" : "+r"(x0) : "r"(x8) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall2(uint64_t nr, uint64_t a1, uint64_t a2) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + register uint64_t x1 asm("x1") = a2; + asm volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall3(uint64_t nr, uint64_t a1, uint64_t a2, uint64_t a3) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + register uint64_t x1 asm("x1") = a2; + register uint64_t x2 asm("x2") = a3; + asm volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall4(uint64_t nr, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + register uint64_t x1 asm("x1") = a2; + register uint64_t x2 asm("x2") = a3; + register uint64_t x3 asm("x3") = a4; + asm volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall5(uint64_t nr, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + register uint64_t x1 asm("x1") = a2; + register uint64_t x2 asm("x2") = a3; + register uint64_t x3 asm("x3") = a4; + register uint64_t x4 asm("x4") = a5; + asm volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4) : "memory"); + return (int64_t)x0; + } + + inline int64_t syscall6(uint64_t nr, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6) { + register uint64_t x8 asm("x8") = nr; + register uint64_t x0 asm("x0") = a1; + register uint64_t x1 asm("x1") = a2; + register uint64_t x2 asm("x2") = a3; + register uint64_t x3 asm("x3") = a4; + register uint64_t x4 asm("x4") = a5; + register uint64_t x5 asm("x5") = a6; + asm volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) : "memory"); + return (int64_t)x0; + } + +#else +#error "unsupported architecture" +#endif + // ---- Typed wrappers ---- // Process diff --git a/programs/lib/libc/Makefile b/programs/lib/libc/Makefile index 2f3b0fd..17966b3 100644 --- a/programs/lib/libc/Makefile +++ b/programs/lib/libc/Makefile @@ -6,7 +6,7 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) CC := $(TOOLCHAIN_PREFIX)gcc AR := $(TOOLCHAIN_PREFIX)ar @@ -20,7 +20,7 @@ endif # ---- Paths ---- LIBC_INC := ../../include/libc -OBJDIR := obj +OBJDIR := obj$(ARCH_SUFFIX) CRTDIR := crt ASM_OBJS := $(OBJDIR)/setjmp.o @@ -38,12 +38,8 @@ CFLAGS := \ -fno-PIC \ -ffunction-sections \ -fdata-sections \ - -m64 \ - -march=x86-64 \ - -msse \ - -msse2 \ - -mno-red-zone \ - -mcmodel=small \ + $(ARCH_CFLAGS) \ + $(ARCH_FP_FLAGS) \ -isystem $(LIBC_INC) \ -isystem $(shell $(CC) -print-file-name=include) @@ -55,18 +51,16 @@ CRT_CFLAGS := \ -fno-stack-protector \ -fno-stack-check \ -fno-PIC \ - -m64 \ - -march=x86-64 \ - -mno-red-zone \ + $(ARCH_CFLAGS) \ -fno-tree-loop-distribute-patterns \ -isystem $(LIBC_INC) \ -isystem $(shell $(CC) -print-file-name=include) # ---- Target ---- -TARGET := liblibc.a -SDK_TARGET := liblibc-full.a -CRT_OBJS := crt1.o crti.o crtn.o +TARGET := $(ARCH_OUT)liblibc.a +SDK_TARGET := $(ARCH_OUT)liblibc-full.a +CRT_OBJS := $(ARCH_OUT)crt1.o $(ARCH_OUT)crti.o $(ARCH_OUT)crtn.o .PHONY: all clean @@ -77,6 +71,7 @@ all: $(TARGET) $(SDK_TARGET) $(CRT_OBJS) # a float leave the decimal-conversion and pow/exp/log code behind. Programs # that do need %e/%f/%g must link with -Wl,-u,_pf_putfloat to force it in. $(TARGET): $(OBJDIR)/libc.o $(OBJDIR)/printf_float.o $(ASM_OBJS) + @mkdir -p $(dir $@) $(AR) rcs $@ $^ $(OBJDIR)/libc.o: libc.c printf_internal.h Makefile @@ -87,7 +82,7 @@ $(OBJDIR)/printf_float.o: printf_float.c printf_internal.h Makefile @mkdir -p $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ -$(OBJDIR)/setjmp.o: setjmp.S Makefile +$(OBJDIR)/setjmp.o: arch/setjmp-$(ARCH).S Makefile @mkdir -p $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ @@ -97,18 +92,22 @@ $(OBJDIR)/setjmp.o: setjmp.S Makefile # compiled ON MontaukOS. Function-level --gc-sections still applies to the # rest; only the float path is pinned. Image size is not a concern here. $(SDK_TARGET): $(OBJDIR)/libc-merged.o $(ASM_OBJS) + @mkdir -p $(dir $@) $(AR) rcs $@ $^ $(OBJDIR)/libc-merged.o: $(OBJDIR)/libc.o $(OBJDIR)/printf_float.o $(LD) -r -o $@ $(OBJDIR)/libc.o $(OBJDIR)/printf_float.o -crt1.o: $(CRTDIR)/crt1.c Makefile +$(ARCH_OUT)crt1.o: $(CRTDIR)/crt1.c Makefile + @mkdir -p $(dir $@) $(CC) $(CRT_CFLAGS) -c $< -o $@ -crti.o: $(CRTDIR)/crti.c Makefile +$(ARCH_OUT)crti.o: $(CRTDIR)/crti.c Makefile + @mkdir -p $(dir $@) $(CC) $(CRT_CFLAGS) -c $< -o $@ -crtn.o: $(CRTDIR)/crtn.c Makefile +$(ARCH_OUT)crtn.o: $(CRTDIR)/crtn.c Makefile + @mkdir -p $(dir $@) $(CC) $(CRT_CFLAGS) -c $< -o $@ clean: diff --git a/programs/lib/libc/arch/setjmp-aarch64.S b/programs/lib/libc/arch/setjmp-aarch64.S new file mode 100644 index 0000000..a5c779b --- /dev/null +++ b/programs/lib/libc/arch/setjmp-aarch64.S @@ -0,0 +1,49 @@ +/* + * setjmp-aarch64.S + * setjmp/longjmp for AArch64 MontaukOS userspace + * Copyright (c) 2026 Daniel Hammer +*/ + +/* jmp_buf: x19-x28, x29 (fp), x30 (lr), sp, d8-d15 -- everything AAPCS64 + requires a callee to preserve. */ + +.text + +.global setjmp +.type setjmp, %function +setjmp: + stp x19, x20, [x0, #0] + stp x21, x22, [x0, #16] + stp x23, x24, [x0, #32] + stp x25, x26, [x0, #48] + stp x27, x28, [x0, #64] + stp x29, x30, [x0, #80] + mov x2, sp + str x2, [x0, #96] + stp d8, d9, [x0, #104] + stp d10, d11, [x0, #120] + stp d12, d13, [x0, #136] + stp d14, d15, [x0, #152] + mov w0, #0 + ret +.size setjmp, . - setjmp + +.global longjmp +.type longjmp, %function +longjmp: + ldp x19, x20, [x0, #0] + ldp x21, x22, [x0, #16] + ldp x23, x24, [x0, #32] + ldp x25, x26, [x0, #48] + ldp x27, x28, [x0, #64] + ldp x29, x30, [x0, #80] + ldr x2, [x0, #96] + mov sp, x2 + ldp d8, d9, [x0, #104] + ldp d10, d11, [x0, #120] + ldp d12, d13, [x0, #136] + ldp d14, d15, [x0, #152] + cmp w1, #0 + csinc w0, w1, wzr, ne + ret +.size longjmp, . - longjmp diff --git a/programs/lib/libc/setjmp.S b/programs/lib/libc/arch/setjmp-x86_64.S similarity index 100% rename from programs/lib/libc/setjmp.S rename to programs/lib/libc/arch/setjmp-x86_64.S diff --git a/programs/lib/libc/crt/crt1.c b/programs/lib/libc/crt/crt1.c index f23743b..88ea88d 100644 --- a/programs/lib/libc/crt/crt1.c +++ b/programs/lib/libc/crt/crt1.c @@ -8,6 +8,8 @@ * calls main(), then exits with main()'s return code. */ +#if defined(__x86_64__) + static inline long _sys1(long nr, long a1) { long ret; __asm__ volatile( @@ -31,6 +33,27 @@ static inline long _sys2(long nr, long a1, long a2) { return ret; } +#elif defined(__aarch64__) + +static inline long _sys1(long nr, long a1) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8) : "memory"); + return x0; +} + +static inline long _sys2(long nr, long a1, long a2) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1) : "memory"); + return x0; +} + +#else +#error "unsupported architecture" +#endif + #define SYS_EXIT 0 #define SYS_GETARGS 25 #define SYS_GETEXECPATH 151 diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index c7137b9..2166fa5 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -32,6 +32,8 @@ Raw syscall wrappers (C versions matching kernel ABI) ======================================================================== */ +#if defined(__x86_64__) + static inline long _mtk_syscall0(long nr) { long ret; __asm__ volatile("syscall" : "=a"(ret) : "a"(nr) @@ -89,6 +91,55 @@ static inline long _mtk_syscall4(long nr, long a1, long a2, long a3, long a4) { return ret; } +#elif defined(__aarch64__) + +// AArch64: number in x8, arguments in x0-x5, `svc #0`; the kernel +// preserves every register except x0, which carries the result. +static inline long _mtk_syscall0(long nr) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0"); + __asm__ volatile("svc #0" : "=r"(x0) : "r"(x8) : "memory"); + return x0; +} + +static inline long _mtk_syscall1(long nr, long a1) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8) : "memory"); + return x0; +} + +static inline long _mtk_syscall2(long nr, long a1, long a2) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1) : "memory"); + return x0; +} + +static inline long _mtk_syscall3(long nr, long a1, long a2, long a3) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + register long x2 __asm__("x2") = a3; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2) : "memory"); + return x0; +} + +static inline long _mtk_syscall4(long nr, long a1, long a2, long a3, long a4) { + register long x8 __asm__("x8") = nr; + register long x0 __asm__("x0") = a1; + register long x1 __asm__("x1") = a2; + register long x2 __asm__("x2") = a3; + register long x3 __asm__("x3") = a4; + __asm__ volatile("svc #0" : "+r"(x0) : "r"(x8), "r"(x1), "r"(x2), "r"(x3) : "memory"); + return x0; +} + +#else +#error "unsupported architecture" +#endif + /* Syscall numbers */ #define SYS_EXIT 0 #define SYS_YIELD 1 diff --git a/programs/lib/libjpeg/Makefile b/programs/lib/libjpeg/Makefile index 7c499f0..a92b869 100644 --- a/programs/lib/libjpeg/Makefile +++ b/programs/lib/libjpeg/Makefile @@ -6,7 +6,7 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) CC := $(TOOLCHAIN_PREFIX)gcc AR := $(TOOLCHAIN_PREFIX)ar @@ -19,8 +19,7 @@ endif LIBC_INC := ../../include/libc PROG_INC := ../../include -OBJDIR := obj - +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CFLAGS := \ @@ -36,25 +35,22 @@ CFLAGS := \ -fno-PIC \ -ffunction-sections \ -fdata-sections \ - -m64 \ - -march=x86-64 \ - -msse \ - -msse2 \ - -mno-red-zone \ - -mcmodel=small \ + $(ARCH_CFLAGS) \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) \ -isystem $(shell $(CC) -print-file-name=include) # ---- Target ---- -TARGET := libjpeg.a +TARGET := $(ARCH_OUT)libjpeg.a .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJDIR)/stb_image_impl.o + @mkdir -p $(dir $@) $(AR) rcs $@ $^ $(OBJDIR)/stb_image_impl.o: stb_image_impl.c Makefile diff --git a/programs/lib/libjpeg/libjpeg.a b/programs/lib/libjpeg/libjpeg.a index df67214a1fc9117f69634ec5cc2f1fa58c0ea23b..4ac9d428eaee1d3ef6d3891f57886dc19b45b88e 100644 GIT binary patch delta 214 zcmdltS!Ca2kqOf5MwW(##-?T)m5iBS?B*Dz_82C{?J-PDN;%Vg@|jYn*X1!8P2Zcx zB*UFsT%4+)3nGoCU(aJI-M%rOX{jCK$?f6mn9>=Uj___ju%5|`k*R@q`;QGw$K;u| z07Wh^-IHOO&AWZUTc&54Obd9ocZf6VF*B9$Zr>rrtfm7JdEmx;jtL~P!IQZxiYbM6 zyT%e`HYKKAyweSiF}pE!@NTa-#{7<%X&LYIj8n{UOjCKMpE$)_##F`I?r@rUyTfUg GIy(T`LrEt9 delta 237 zcmdltS!Ca2kqOf52A0OgCWeL^m5iCdY$J2S<`|~-7$(N;F-%NKIny8KF&U{B7pE%d z<^oA0AeEP|Ta=ojTa}*&5=_p`Pf5+OEzV8M$(e4G&r~|SE{`d7`^J2xrFM)d+r!r} zr86>3;@f^;J(C$DlONyq9~+pC$ul(pMJ_PilVQr_+rHo}(=$z`JihH6;>>!?Oip~; zcStd->3~EYxG|q&0*P$!WG;(hGUD5=v4ojTiK&Bcy1_AKH>NPY?G?wE-!U_l@J-J+ d#T>_!%s2hSDdsXJ559JX)6Cl)PP5e60RYkJPD20y diff --git a/programs/lib/libjpeg/obj/stb_image_impl.o b/programs/lib/libjpeg/obj/stb_image_impl.o index a57bd248b83677eb0b2e82f1e9f38768b96756b9..54aaebfb19f041308aea0c9f2d64cfd7522b5892 100644 GIT binary patch delta 184 zcmX@mCvu=qq@jgz2~*DWb2&_@({h-MrrYN*$#CZu7pE%df=Hw3kvUAI+l_OXmfA6% z+EPvc4O+`-Tvz^^E+my iWxUg09cPYXn#w!f>jZNdQx$Lfp%cv851nACvjYG&2SBU< delta 207 zcmX@mCvu=qq@jgz2~*DW)Ep)w_2S}G1>IaAX#}M5@^y<+Q*^8H^FV^hx%nxnIkv^Q zi8(pb_vJ8^PRn6R-EN%AwA79p4?^i7AE-I&7ow*NZJ{EnHagm3z*EgC&1hUx`dHDlqEVx@F*IpIAP|wD29QJ$5RZ|y$W>|=o_n=#$%m}ca4Le&yK^yF&i2i*G|c> z|NVS(96o)zadWUP90=5eYBK%mCpVrz{p!KrFVb!o-^oQ&>-c0VcFl?QSGnRqrGZb^b*c^g&{HvhujOH^=TuVMyU_?rVdTS&DeTF|Y;RvY#ro2S zx&#j9V;0p}{DEzYTs$n+J5#rmqFZpJy>0R60<5P0!0QXJ-@jas;EWOXfZ{|K4E!Q- zdLf$VUyHj6rOsU_D#9etc8jMKBNtJwD@GnofEp+k96R~SQgqnv;If$e__COrAIT%V z2hJ|REYxyc31(9RI8uT^Jm!j01ZX1h=~D5Y;CC7Vqyht$KqO1P=r;=)Q1yGz!{wyDW{Lo9Cd)Rm&+TUECbqd-I8 zP?fm5p-xvJ8MMGs!>dpm^P~sjo=^a%h*rxg1Z5S@5O)Qol85gH5vC`^!5WFnAwD4% zfAC0+412l7*=q!Tfq2In{7&aB6^;i~8NK}-j z@e%{iAeH_WX1OqiE9!+Z8{Abd1=GL}Y&#e1Z;+0_TN^}jG7pKN=fR^lBG)@jS3T%X zWc%6T_2Q@3Ej6&wZuk`!Qz)*xIb`crLm}J(wy7hVF*)`U4sQ`W%Bf94GJBxEYtpyGkeCo0QnsJ{f zC;^3&czBQ0o@DVOv8mVeyLFSNUWS`rZbO>LD{GTVONb+F*e`pH)A!0$24zp~mDI1n z--*S?jCQGfjD78*ty~>%$9&LPQg`;Db`)93s_;X5s&W(g2ud@pcyiwy-e56~3dbk@i zsKKQ!cI%Vu!RN8oe8=z^;T~T(0k_BLq;p<8+2M#XPKx?2_MAkX&xv|sMCCf?%X~At zQ?h9h_{2#xRXge3W|;m+3>bKg-Z_H?{-&n8XyCd0P7mDPHl6mT;r7dF^&q#^X(MMr zVz&-mzJWXHIt=`ac)E4Tz&kYln}JV{x6R>R%=CPtgG%*h*ctdQ>Z@M#fnI}J--r6D F{{d*2o0|Xt delta 2093 zcmZ8iZETZO6y9^*vaf)GsI}D$!31TxjdlnW@dFK8H*wvBA8t&`xVv<{&eGCOl;l|X^4fxwb9x_zq;(f?I$QFjV~3Ur7a^pE%BO@G-=sl>*W0z zC4qo}=OYOe8+e&32~-*Q1G-L)fp<+v0DQg}Q#}1TdA$*In-PQ?Q`r+lfwwoAlJ=z$ zH9{N-BA=?jAJ}%Gi^s%zy}D|qZrPF60M0JKYjmA>bqPBCi}eV;HR67?l0+vB{2PmN zOVL8tz`dnX=R7HT5jmhH@QfuWLN_-oK{2J18eSqeVtnQ$blL7mS;F04mT>b;`AM6J z7le?HN^S_DfL0L4Lm0tdTv?7VO|tlSxpx}E=Tv1T1U{pf7UB{#lVMn(Ndv&1{__APMlyY6RxxDv(1mHW*Kg| zC}MF{B}P0)H0f-cOclpt3+&z?8vrvCh$eE_=Tr07agOjVL38D!^F{Q zaWkpo)kp`;f*N}js}i2vaMBYE<7=XjY#}0BIAU>cL@G_>D-p!#hQ*OuiOaM2pjcey z@md-73*ZHH0^e)#mO5OgqfpV6CqPP`9u-4(5ofPQk$0-Dy2qW$ zb_Tp!{1k*5UT-%%$Hf#)>fRK!b*s@Reg~RV&jw6OJcMJf3*OCHEkZMiD_YQ%bzbj& z3lE)ydshsT>43%e#3XQ%s*K@TLOt)^h!`?>$|l)wfm*Z)r^#EU6EEka_VuQWzf}&K zRHLEC70zzev=t%H zhIAg=CbjPd-xQnmy?(ZS#o;OQk}KwX`&gAhe@{@QJMF2;m-vS`;gY&FyAk$vYT0Y^QU&~= z@plb;CXeryo9a4e#f7ew1GbTSATB+6z{7DFQ4!yc%M-fTQqes&r`!i)AKRN!S)X8A zrf;W~xvwylvq^If7{0`-(|9%a^vO{7_2DsE z;Zmpi^i6j4K%zC@7xE)o;I{|h_HNW^{}}E^WLpC$YIE9HI6t*p zhc0N~j=C-b@6mJq$-v*z_%#FfCfnxNVa)P4e@W%~Z`fJt1$FE&20?R4tsX>U_5bRL Bm?QuI diff --git a/programs/lib/libjpegwrite/obj/stb_image_write_impl.o b/programs/lib/libjpegwrite/obj/stb_image_write_impl.o index d52704d1419b2a044aebaa12fc176b31697feb2c..2f815bfe5a4e6ee41396c342115f9ca1a0a78bbb 100644 GIT binary patch delta 2022 zcmZ8iZA_C_6n>vuhJZ_E$yn3IF?BzjX22+$g26bMv=jscmncju1xE%Ez&WPrp$7H(vbM6+mUbW65ni~a$Zh#AQ~Fv}cnBRg+Scd%Fg1=rC-6mStfo42Qo=jNYoq!g2(t<{dVS9i-Th+VMfR~tpK(PT|ui|(N z_=isgfeHgY84&>JaVE^xC>7LeShR-LI*^1bRN#O`+yPZNkSHoOI2|joEO( zM|Ih7ia5xrY{t<^cXMz`r>k}b=<%Hanx62hI04GYMItJwE*DAS5NI$L(^w);9^7KJ zpc{G2-lWAmX46fyE}vhksUROtjMG3q*ZmC5E^DiEX3moQ75Qu52o$cl;|tE8b2XXs~YR; z2E0$B!o6I57tcty(UJ5MTimA&MO@g|vaSd#Ag+VF#Y_)D-Y7;SM5-qJZ=oW<*h_+p zw*-?y?B}tR@>s438Y$&SR$44Yi&z#^<>7Vdf+pDF4_fkY_X{=3C}a3VL49TTRov2~ zw;Xv8W03v>XotuVlwH9q7&udb8etz(ecBoqUg9c+=Ns?@A?=k&G+`xq4zlDH(8xg! zxC-=0x37V=RC7k4W7S-8B+al9&x2xX;IOSzQ7>4+)#fy+XI|{lHY#f5%{Z^oLL;AzNkO(IW^K~bglz&%^hpa^ z_|RKhdCKY1)rxO~tt6O(_Aov?nfJNpZNVsIZF&?MZexv3T5RL}m`?YPz``Myj=&jx zToQw z?bUGaTgp4zfH!E=cZqk?A(Q;}lDfkleHut7Z3rI;*F$xFyEcUf>`(zu8*pFny4Efm z@IhKT45u~ZwrrpsbZnTf+>rNko5R(%fhLC0{J;BC{>dZ_V=u)a<+U`*E z`oTc=Dz`rkxSdBf0!MNv>Gag_tU_{G2HZi(qp&1@9$c;6G0>+J{)+)$Plrd5WWBBE YUFx4Ubdx@i*GF*$A``NH3^n`y1FNHwN&o-= delta 2026 zcmZ8ie@xV680YhTPks$*h;(s(P}Zi?0^~6DN-Hhy2g#jKTS6IkfJ_LG0|Y(PX+t14 z@s!#FvRMMz_>m4)y+Vsk|FF1fm1|k{N7mL{EOFq<;jHz1x%b@e``zxI`+h#}^ZR+; zyWSmty*vKU$2gWke=mb|Wn<&cM>A{r+sdMDcV@%Rip;?7Ivp&p-CeP>W>aIWucn6F zY3Py1Qm{*tx6|-1k{X-Js#;1*%Nxpbt@4%`3r~uS7@Bzz&4?pk9?aQ@Y$}q7X}qMFkU&uzDokD$r5~-Vn2b8XV|C9>EE-I zi<_WfC#zi*GSP($2tR0bKI{mRKOYVeE97K8<7lCuU&3*nuHL#xk8NF~=`O#DgMzjc zAPdFhFF>~N3hFPw6#gQg8>J#yqf2gPCuq*iY^I4G^YE*e3O#UOka|6wx1ebcZoxwn z+u(4$sp8%c8=dA;Di5at|4#K{y8#~~S0TH678EGts$8aoBKCEKY`XYbRu$onNt9_+ z_9~{V=akbmdQtg_)HX>q^mzl`3M$&p**9~Kba`(H{mv3U(5hli?4tA+BMxF*P@sfq z67o_BVj)&RhF(MEB4gbVW&%6#sSqA+ioj%mbgI+ zKCb=?ped(Y>?YEugevJp04GH=IL-Pr+kN|S%?P&Ev*iAAOH}NoD1B-(zgfC3GAXXEok8lPv6U3&X%sd_*PilYIJU7L8cJQ%LLDyKKlM*`FS|8auITgDc z>%@A9Pc%96HY(%9?Ip74gkCxR(SH(`O>DP{Q0nSZS=MGoXZe-F+YI;$wJ`4(@L5Xf zVgCncvo82H=;5H#L6bdPB0Hg%$1+cofnGfbz7;~J^!CVn3Z64;o zhga0jOd05x$bIXQd&xr)RaYJ-e5qC}lZljzLm~+mkntx-U n4=Mbn0k_b;5oD)-uIO#*Z#8n0{vjB}Nn+ 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Ĉ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 MAustM8OPWEFAc<2i~s-t diff --git a/programs/lib/tls/obj/tls.o b/programs/lib/tls/obj/tls.o index 5eccf5dc847230c6ba926d9f08e0b2563d608912..c1198fae315fc0659152801b95c49f1bae794e7f 100644 GIT binary patch literal 121200 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 literal 114152 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/, bin-/ and lib//build-/. + +ARCH ?= x86_64 + +ifeq ($(filter $(ARCH),x86_64 aarch64),) + $(error Unsupported ARCH '$(ARCH)' for userspace) +endif + +MONTAUK_ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/../..) + +ifeq ($(ARCH),x86_64) + ARCH_SUFFIX := + ARCH_OUT := +else + ARCH_SUFFIX := -$(ARCH) + ARCH_OUT := build-$(ARCH)/ +endif + +TOOLCHAIN_PREFIX := $(MONTAUK_ROOT)/toolchain/local/bin/$(ARCH)-montauk- +TOOLCHAIN_MISSING := $(ARCH)-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh $(ARCH) first + +# ARCH_FP_FLAGS: programs that use floating point / SIMD (GUI apps) +# ARCH_NOFP_FLAGS: system programs that must not touch FP/SIMD registers +# ARCH_CFLAGS: code-model flags the libraries pass explicitly +ifeq ($(ARCH),x86_64) + ARCH_FP_FLAGS := -msse -msse2 + ARCH_NOFP_FLAGS := -mno-80387 -mno-mmx -mno-sse -mno-sse2 + ARCH_CFLAGS := -m64 -march=x86-64 -mno-red-zone -mcmodel=small + ARCH_LD_EMULATION := elf_x86_64 +else + ARCH_FP_FLAGS := + ARCH_NOFP_FLAGS := -mgeneral-regs-only + ARCH_CFLAGS := -mcmodel=small + ARCH_LD_EMULATION := aarch64elf +endif diff --git a/programs/src/2048/Makefile b/programs/src/2048/Makefile index b4d35dc..41be959 100644 --- a/programs/src/2048/Makefile +++ b/programs/src/2048/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -46,8 +45,8 @@ SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/2048/2048.elf -LOADER_LIB := $(LIBDIR)/libloader/liblibloader.a -LIBC_LIB := $(LIBDIR)/libc/liblibc.a +LOADER_LIB := $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a +LIBC_LIB := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/audio/Makefile b/programs/src/audio/Makefile index 429c286..3eb7ac5 100644 --- a/programs/src/audio/Makefile +++ b/programs/src/audio/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/audio/audio.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/audio - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/bluetooth/Makefile b/programs/src/bluetooth/Makefile index e1c1533..5dedb74 100644 --- a/programs/src/bluetooth/Makefile +++ b/programs/src/bluetooth/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/bluetooth/bluetooth.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/bluetooth - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/calculator/Makefile b/programs/src/calculator/Makefile index b6d94e2..5ee46a2 100644 --- a/programs/src/calculator/Makefile +++ b/programs/src/calculator/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/calculator/calculator.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/calculator - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/capabilities/Makefile b/programs/src/capabilities/Makefile index f2ab451..65d2d71 100644 --- a/programs/src/capabilities/Makefile +++ b/programs/src/capabilities/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -46,7 +45,7 @@ SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/capabilities/capabilities.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/charmap/Makefile b/programs/src/charmap/Makefile index 0d52d54..7c4d425 100644 --- a/programs/src/charmap/Makefile +++ b/programs/src/charmap/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/charmap/charmap.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/charmap - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/crashpad/Makefile b/programs/src/crashpad/Makefile index 4039ad8..43fe0c2 100644 --- a/programs/src/crashpad/Makefile +++ b/programs/src/crashpad/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ @@ -47,7 +46,7 @@ SRCS := main.cpp stb_truetype_impl.cpp font_data.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/crashpad/crashpad.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/desktop/Makefile b/programs/src/desktop/Makefile index e314a08..1d46073 100644 --- a/programs/src/desktop/Makefile +++ b/programs/src/desktop/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -19,11 +19,10 @@ PROG_INC := ../../include JPEG_LIB := ../../lib/libjpeg LIBC_LIB := ../../lib/libc BEARSSL := ../../lib/bearssl -LOADER_LIB := ../../lib/libloader/liblibloader.a +LOADER_LIB := ../../lib/libloader/$(ARCH_OUT)liblibloader.a LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- C++ compiler flags ---- CXXFLAGS := \ @@ -40,8 +39,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ @@ -71,7 +69,7 @@ all: $(TARGET) # ---- Libraries ---- -LIBS := $(LOADER_LIB) $(JPEG_LIB)/libjpeg.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(LOADER_LIB) $(JPEG_LIB)/$(ARCH_OUT)libjpeg.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a $(TARGET): $(OBJS) $(LIBS) $(LINK_LD) Makefile mkdir -p $(BINDIR)/os diff --git a/programs/src/devexplorer/Makefile b/programs/src/devexplorer/Makefile index 640e09d..6e5fdcc 100644 --- a/programs/src/devexplorer/Makefile +++ b/programs/src/devexplorer/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I ../../lib/bearssl/inc @@ -63,9 +62,9 @@ TARGET := $(BINDIR)/apps/devexplorer/devexplorer.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/devexplorer - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/dialogs/Makefile b/programs/src/dialogs/Makefile index e0769a4..3ba9254 100644 --- a/programs/src/dialogs/Makefile +++ b/programs/src/dialogs/Makefile @@ -4,12 +4,12 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CC = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - LD = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - STRIP = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CC = $(error $(TOOLCHAIN_MISSING)) + CXX = $(error $(TOOLCHAIN_MISSING)) + LD = $(error $(TOOLCHAIN_MISSING)) + STRIP = $(error $(TOOLCHAIN_MISSING)) else CC := $(TOOLCHAIN_PREFIX)gcc CXX := $(TOOLCHAIN_PREFIX)g++ @@ -18,9 +18,9 @@ else endif PROG_INC := ../../include -LIBOUTDIR := ../../bin/os -OBJDIR := obj -LEGACY_APPDIR := ../../bin/apps/dialogs +LIBOUTDIR := ../../bin$(ARCH_SUFFIX)/os +OBJDIR := obj$(ARCH_SUFFIX) +LEGACY_APPDIR := ../../bin$(ARCH_SUFFIX)/apps/dialogs LIBC_SRC := ../../lib/libc/libc.c GCC_INCLUDE := $(shell $(CC) -print-file-name=include) @@ -40,8 +40,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -DGUI_DIALOGS_LIBRARY_BUILD \ -I $(PROG_INC) \ @@ -55,7 +54,7 @@ LDFLAGS := \ --hash-style=sysv \ -u dialogs_run_request \ -u dialogs_message_box \ - -m elf_x86_64 + -m $(ARCH_LD_EMULATION) LIBC_CFLAGS := \ -std=gnu11 \ @@ -69,8 +68,7 @@ LIBC_CFLAGS := \ -fvisibility=hidden \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -isystem $(PROG_INC)/libc \ -isystem $(GCC_INCLUDE) diff --git a/programs/src/disks/Makefile b/programs/src/disks/Makefile index bd01ba0..56ed015 100644 --- a/programs/src/disks/Makefile +++ b/programs/src/disks/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/disks/disks.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/disks - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/display/Makefile b/programs/src/display/Makefile index f2ecd83..c326e71 100644 --- a/programs/src/display/Makefile +++ b/programs/src/display/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -46,7 +45,7 @@ SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/display/display.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/fetch/Makefile b/programs/src/fetch/Makefile index 7fc9a6c..06bc4b4 100644 --- a/programs/src/fetch/Makefile +++ b/programs/src/fetch/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -21,9 +21,8 @@ LIBC_LIB := ../../lib/libc LIBC_INC := ../../include/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -39,10 +38,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) \ -I $(BEARSSL)/inc @@ -56,7 +52,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Target ---- diff --git a/programs/src/files/Makefile b/programs/src/files/Makefile index f7799f3..8267468 100644 --- a/programs/src/files/Makefile +++ b/programs/src/files/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib BEARSSL := ../../lib/bearssl JPEG_LIB := ../../lib/libjpeg @@ -39,8 +39,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I $(BEARSSL)/inc @@ -65,7 +64,7 @@ TARGET := $(BINDIR)/apps/files/files.elf all: $(TARGET) -LIBS := $(JPEG_LIB)/libjpeg.a $(BEARSSL)/libbearssl.a $(LIBDIR)/libc/liblibc.a +LIBS := $(JPEG_LIB)/$(ARCH_OUT)libjpeg.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a $(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBS) mkdir -p $(BINDIR)/apps/files diff --git a/programs/src/fontpreview/Makefile b/programs/src/fontpreview/Makefile index 000ae53..90d816a 100644 --- a/programs/src/fontpreview/Makefile +++ b/programs/src/fontpreview/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -18,9 +18,8 @@ endif LIBC_LIB := ../../lib/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -37,8 +36,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) # ---- Linker flags ---- @@ -50,7 +48,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(LIBC_LIB)/liblibc.a +LIBS := $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Source files ---- diff --git a/programs/src/imageviewer/Makefile b/programs/src/imageviewer/Makefile index 7288716..4d6f17f 100644 --- a/programs/src/imageviewer/Makefile +++ b/programs/src/imageviewer/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -20,9 +20,8 @@ LIBC_LIB := ../../lib/libc LIBC_INC := ../../include/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -39,8 +38,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) @@ -53,7 +51,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(JPEG_LIB)/libjpeg.a $(LIBC_LIB)/liblibc.a +LIBS := $(JPEG_LIB)/$(ARCH_OUT)libjpeg.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Source files ---- diff --git a/programs/src/installer/Makefile b/programs/src/installer/Makefile index 82050a6..fffcb4a 100644 --- a/programs/src/installer/Makefile +++ b/programs/src/installer/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -63,9 +62,9 @@ TARGET := $(BINDIR)/apps/installer/installer.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/installer - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/keyboard/Makefile b/programs/src/keyboard/Makefile index 7239611..834376f 100644 --- a/programs/src/keyboard/Makefile +++ b/programs/src/keyboard/Makefile @@ -3,29 +3,29 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -Wno-unused-parameter \ -Wno-unused-function -ffreestanding -fno-stack-protector -fno-stack-check \ - -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections -msse -msse2 \ + -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections $(ARCH_FP_FLAGS) \ -MMD -MP -I $(PROG_INC) -isystem $(PROG_INC)/libc LDFLAGS := -nostdlib -Wl,--gc-sections -T $(LINK_LD) SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/keyboard/keyboard.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean all: $(TARGET) diff --git a/programs/src/libloader/Makefile b/programs/src/libloader/Makefile index fd88028..a7d72ad 100644 --- a/programs/src/libloader/Makefile +++ b/programs/src/libloader/Makefile @@ -1,8 +1,6 @@ # Makefile for libloader -ARCH := x86_64 - -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk CXX := $(TOOLCHAIN_PREFIX)g++ AR := $(TOOLCHAIN_PREFIX)ar @@ -18,29 +16,26 @@ override CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -I ../../include \ -isystem ../../include/libc \ -isystem ../../include/montauk LIBDIR := ../../lib/libloader -LEGACY_BINDIR := ../../bin +LEGACY_BINDIR := ../../bin$(ARCH_SUFFIX) .PHONY: all clean remove-legacy -all: remove-legacy $(LIBDIR)/liblibloader.a +all: remove-legacy $(LIBDIR)/$(ARCH_OUT)liblibloader.a remove-legacy: rm -f $(LEGACY_BINDIR)/liblibloader.a -$(LIBDIR)/liblibloader.a: libloader.cpp - @mkdir -p $(LIBDIR) +$(LIBDIR)/$(ARCH_OUT)liblibloader.a: libloader.cpp + @mkdir -p $(LIBDIR)/$(ARCH_OUT) $(CXX) $(CXXFLAGS) -c libloader.cpp -o libloader.o - $(AR) rcs $(LIBDIR)/liblibloader.a libloader.o + $(AR) rcs $(LIBDIR)/$(ARCH_OUT)liblibloader.a libloader.o rm -f libloader.o clean: - rm -f $(LIBDIR)/liblibloader.a $(LEGACY_BINDIR)/liblibloader.a + rm -f $(LIBDIR)/$(ARCH_OUT)liblibloader.a $(LEGACY_BINDIR)/$(ARCH_OUT)liblibloader.a diff --git a/programs/src/login/Makefile b/programs/src/login/Makefile index ce06ec4..bcb121e 100644 --- a/programs/src/login/Makefile +++ b/programs/src/login/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -20,9 +20,8 @@ LIBC_LIB := ../../lib/libc JPEG_LIB := ../../lib/libjpeg BEARSSL := ../../lib/bearssl LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -39,8 +38,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I $(BEARSSL)/inc @@ -73,7 +71,7 @@ TARGET := $(BINDIR)/os/login.elf all: $(TARGET) -LIBS := $(JPEG_LIB)/libjpeg.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(JPEG_LIB)/$(ARCH_OUT)libjpeg.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a $(TARGET): $(OBJS) $(LIBS) $(LINK_LD) Makefile mkdir -p $(BINDIR)/os diff --git a/programs/src/lua/Makefile b/programs/src/lua/Makefile index 1189f99..41c3693 100644 --- a/programs/src/lua/Makefile +++ b/programs/src/lua/Makefile @@ -1,20 +1,20 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CC = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - AR = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CC = $(error $(TOOLCHAIN_MISSING)) + AR = $(error $(TOOLCHAIN_MISSING)) else CC := $(TOOLCHAIN_PREFIX)gcc AR := $(TOOLCHAIN_PREFIX)ar endif SRCDIR := src -OBJDIR := obj +OBJDIR := obj$(ARCH_SUFFIX) LIBC_DIR := ../../lib/libc -BINDIR := ../../bin/os -LIBDIR := ../../bin/sdk/lua +BINDIR := ../../bin$(ARCH_SUFFIX)/os +LIBDIR := ../../bin$(ARCH_SUFFIX)/sdk/lua CFLAGS := \ -std=gnu11 \ @@ -31,8 +31,7 @@ CFLAGS := \ -fno-stack-check \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -D__MONTAUKOS__=1 \ -DLUA_COMPAT_5_3 \ -I$(SRCDIR) \ @@ -74,15 +73,15 @@ STAGE_HEADERS := \ all: $(TARGET_LIB) $(TARGET_BIN) $(STAGE_HEADERS) -$(TARGET_LIB): $(BASE_OBJS) $(LIBC_DIR)/liblibc.a +$(TARGET_LIB): $(BASE_OBJS) $(LIBC_DIR)/$(ARCH_OUT)liblibc.a @mkdir -p $(LIBDIR) $(AR) rcs $@ $(BASE_OBJS) -$(TARGET_BIN): $(LUA_MAIN) $(TARGET_LIB) $(LIBC_DIR)/liblibc.a $(LIBC_DIR)/crt1.o $(LIBC_DIR)/crti.o $(LIBC_DIR)/crtn.o +$(TARGET_BIN): $(LUA_MAIN) $(TARGET_LIB) $(LIBC_DIR)/$(ARCH_OUT)liblibc.a $(LIBC_DIR)/$(ARCH_OUT)crt1.o $(LIBC_DIR)/$(ARCH_OUT)crti.o $(LIBC_DIR)/$(ARCH_OUT)crtn.o @mkdir -p $(BINDIR) $(CC) $(CFLAGS) $(LDFLAGS) \ - $(LIBC_DIR)/crt1.o $(LIBC_DIR)/crti.o \ - $(LUA_MAIN) $(TARGET_LIB) $(LIBC_DIR)/liblibc.a $(LIBC_DIR)/crtn.o \ + $(LIBC_DIR)/$(ARCH_OUT)crt1.o $(LIBC_DIR)/$(ARCH_OUT)crti.o \ + $(LUA_MAIN) $(TARGET_LIB) $(LIBC_DIR)/$(ARCH_OUT)liblibc.a $(LIBC_DIR)/$(ARCH_OUT)crtn.o \ -lgcc -o $@ $(LIBDIR)/include/%: $(SRCDIR)/% diff --git a/programs/src/mandelbrot/Makefile b/programs/src/mandelbrot/Makefile index 4886b13..fd1d0f5 100644 --- a/programs/src/mandelbrot/Makefile +++ b/programs/src/mandelbrot/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/mandelbrot/mandelbrot.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/mandelbrot - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/music/Makefile b/programs/src/music/Makefile index 42cb45d..7a75cc4 100644 --- a/programs/src/music/Makefile +++ b/programs/src/music/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -I . \ -isystem $(PROG_INC)/libc @@ -63,9 +62,9 @@ TARGET := $(BINDIR)/apps/music/music.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/music - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/network/Makefile b/programs/src/network/Makefile index 6774b8c..a909ca3 100644 --- a/programs/src/network/Makefile +++ b/programs/src/network/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -46,7 +45,7 @@ SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/network/network.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/paint/Makefile b/programs/src/paint/Makefile index a8ef53a..34c679a 100644 --- a/programs/src/paint/Makefile +++ b/programs/src/paint/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -62,9 +61,9 @@ TARGET := $(BINDIR)/apps/paint/paint.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/paint - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/pdfviewer/Makefile b/programs/src/pdfviewer/Makefile index 9f9bea4..d73af79 100644 --- a/programs/src/pdfviewer/Makefile +++ b/programs/src/pdfviewer/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,10 +17,10 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib -JPEG_LIB := $(LIBDIR)/libjpeg/libjpeg.a +JPEG_LIB := $(LIBDIR)/libjpeg/$(ARCH_OUT)libjpeg.a # ---- Compiler flags ---- @@ -38,8 +38,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -58,15 +57,15 @@ OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) # ---- Target ---- TARGET := $(BINDIR)/apps/pdfviewer/pdfviewer.elf -LOADER_LIB := $(LIBDIR)/libloader/liblibloader.a +LOADER_LIB := $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a .PHONY: all clean all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(JPEG_LIB) $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(JPEG_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/pdfviewer - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(JPEG_LIB) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(JPEG_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ HEADERS := pdfviewer.h diff --git a/programs/src/powermgr/Makefile b/programs/src/powermgr/Makefile index 14c6e3d..29b2b28 100644 --- a/programs/src/powermgr/Makefile +++ b/programs/src/powermgr/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -51,9 +50,9 @@ TARGET := $(BINDIR)/apps/powermgr/powermgr.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/powermgr - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/printctl/Makefile b/programs/src/printctl/Makefile index 33a1395..241a6bc 100644 --- a/programs/src/printctl/Makefile +++ b/programs/src/printctl/Makefile @@ -3,9 +3,9 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -15,9 +15,8 @@ LIBC_LIB := ../../lib/libc BEARSSL := ../../lib/bearssl TLS_LIB := ../../lib/tls LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) CXXFLAGS := \ -std=gnu++20 \ -g -O2 -pipe \ @@ -31,10 +30,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I $(BEARSSL)/inc @@ -51,9 +47,9 @@ DEPS := $(OBJDIR)/main.d all: $(TARGET) -$(TARGET): $(OBJDIR)/main.o $(LINK_LD) Makefile $(LIBC_LIB)/liblibc.a +$(TARGET): $(OBJDIR)/main.o $(LINK_LD) Makefile $(LIBC_LIB)/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/os - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJDIR)/main.o $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJDIR)/main.o $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/main.o: main.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/printd/Makefile b/programs/src/printd/Makefile index 554e1d9..0c2db90 100644 --- a/programs/src/printd/Makefile +++ b/programs/src/printd/Makefile @@ -3,9 +3,9 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -16,9 +16,8 @@ TLS_LIB := ../../lib/tls BEARSSL := ../../lib/bearssl JPEGWRITE := ../../lib/libjpegwrite LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) CXXFLAGS := \ -std=gnu++20 \ -g -O2 -pipe \ @@ -32,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I $(BEARSSL)/inc @@ -45,7 +43,7 @@ LDFLAGS := \ SRCS := main.cpp test_page_jpeg.cpp font_data.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) -LIBS := $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(JPEGWRITE)/libjpegwrite.a $(LIBC_LIB)/liblibc.a +LIBS := $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(JPEGWRITE)/$(ARCH_OUT)libjpegwrite.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a TARGET := $(BINDIR)/os/printd.elf DEPS := $(OBJS:.o=.d) diff --git a/programs/src/printers/Makefile b/programs/src/printers/Makefile index 8bd17d0..4a331c3 100644 --- a/programs/src/printers/Makefile +++ b/programs/src/printers/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ @@ -47,7 +46,7 @@ SRCS := main.cpp stb_truetype_impl.cpp font_data.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/printers/printers.elf -LIBS := $(LIBDIR)/tls/libtls.a $(LIBDIR)/bearssl/libbearssl.a $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/tls/$(ARCH_OUT)libtls.a $(LIBDIR)/bearssl/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/procmgr/Makefile b/programs/src/procmgr/Makefile index 96cf3fd..bccd521 100644 --- a/programs/src/procmgr/Makefile +++ b/programs/src/procmgr/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -51,9 +50,9 @@ TARGET := $(BINDIR)/apps/procmgr/procmgr.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/procmgr - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/rtlsdr/Makefile b/programs/src/rtlsdr/Makefile index 636da5d..b50f027 100644 --- a/programs/src/rtlsdr/Makefile +++ b/programs/src/rtlsdr/Makefile @@ -1,18 +1,18 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk CXX := $(TOOLCHAIN_PREFIX)g++ CC := $(TOOLCHAIN_PREFIX)gcc LD := $(TOOLCHAIN_PREFIX)ld STRIP := $(TOOLCHAIN_PREFIX)strip PROG_INC := ../../include -OBJDIR := obj -LIBOUTDIR := ../../bin/os +OBJDIR := obj$(ARCH_SUFFIX) +LIBOUTDIR := ../../bin$(ARCH_SUFFIX)/os LIBC_SRC := ../../lib/libc/libc.c GCC_INCLUDE := $(shell $(CC) -print-file-name=include) -CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -ffreestanding -fno-stack-protector -fno-stack-check -fPIC -fvisibility=hidden -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections -mno-80387 -mno-mmx -mno-sse -mno-sse2 -MMD -MP -I $(PROG_INC) -isystem $(PROG_INC)/libc +CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -ffreestanding -fno-stack-protector -fno-stack-check -fPIC -fvisibility=hidden -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections $(ARCH_NOFP_FLAGS) -MMD -MP -I $(PROG_INC) -isystem $(PROG_INC)/libc LIBC_CFLAGS := -std=gnu11 -O2 -ffreestanding -fno-stack-protector -fno-stack-check -fPIC -fvisibility=hidden -ffunction-sections -fdata-sections -isystem $(PROG_INC)/libc -isystem $(GCC_INCLUDE) -LDFLAGS := -shared --build-id=none --gc-sections --hash-style=sysv -m elf_x86_64 +LDFLAGS := -shared --build-id=none --gc-sections --hash-style=sysv -m $(ARCH_LD_EMULATION) OBJS := $(OBJDIR)/rtlsdr.o $(OBJDIR)/r820t.o TARGET := $(LIBOUTDIR)/rtlsdr.lib .PHONY: all clean diff --git a/programs/src/screenshot/Makefile b/programs/src/screenshot/Makefile index e9e47ad..6d3c1c8 100644 --- a/programs/src/screenshot/Makefile +++ b/programs/src/screenshot/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -23,8 +23,7 @@ LIBC_LIB := $(PROGRAMS)/lib/libc PROG_INC := $(PROGRAMS)/include LINK_LD := $(PROGRAMS)/link.ld BINDIR := $(PROGRAMS)/bin -OBJDIR := obj - +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -41,8 +40,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -56,7 +54,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(JPEGWRITE_LIB)/libjpegwrite.a $(LOADER_LIB)/liblibloader.a $(LIBC_LIB)/liblibc.a +LIBS := $(JPEGWRITE_LIB)/$(ARCH_OUT)libjpegwrite.a $(LOADER_LIB)/$(ARCH_OUT)liblibloader.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Source files ---- diff --git a/programs/src/sdr/Makefile b/programs/src/sdr/Makefile index 9a4e652..038bdb1 100644 --- a/programs/src/sdr/Makefile +++ b/programs/src/sdr/Makefile @@ -1,18 +1,18 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk CXX := $(TOOLCHAIN_PREFIX)g++ PROG_INC := ../../include LINK_LD := ../../link.ld -OBJDIR := obj -TARGET := ../../bin/os/sdr.elf -LIBS := ../../lib/libloader/liblibloader.a ../../lib/libc/liblibc.a -CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -ffreestanding -fno-stack-protector -fno-stack-check -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections -mno-80387 -mno-mmx -mno-sse -mno-sse2 -I $(PROG_INC) -isystem $(PROG_INC)/libc +OBJDIR := obj$(ARCH_SUFFIX) +TARGET := ../../bin$(ARCH_SUFFIX)/os/sdr.elf +LIBS := ../../lib/libloader/$(ARCH_OUT)liblibloader.a ../../lib/libc/$(ARCH_OUT)liblibc.a +CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -ffreestanding -fno-stack-protector -fno-stack-check -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections $(ARCH_NOFP_FLAGS) -I $(PROG_INC) -isystem $(PROG_INC)/libc LDFLAGS := -nostdlib -Wl,--gc-sections -T $(LINK_LD) .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJDIR)/main.o $(LIBS) $(LINK_LD) Makefile - mkdir -p ../../bin/os + mkdir -p ../../bin$(ARCH_SUFFIX)/os $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJDIR)/main.o $(LIBS) -o $@ $(OBJDIR)/main.o: main.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/settings/Makefile b/programs/src/settings/Makefile index a48f99b..db82536 100644 --- a/programs/src/settings/Makefile +++ b/programs/src/settings/Makefile @@ -3,23 +3,23 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib BEARSSL := ../../lib/bearssl CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -Wno-unused-parameter \ -Wno-unused-function -ffreestanding -fno-stack-protector -fno-stack-check \ - -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections -msse -msse2 \ + -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections $(ARCH_FP_FLAGS) \ -MMD -MP -I $(PROG_INC) -isystem $(PROG_INC)/libc \ -I $(BEARSSL)/inc LDFLAGS := -nostdlib -Wl,--gc-sections -T $(LINK_LD) @@ -28,7 +28,7 @@ SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/settings/settings.elf # bearssl: montauk/user.h (account records) needs its headers and hashes. -LIBS := $(BEARSSL)/libbearssl.a $(LIBDIR)/libc/liblibc.a +LIBS := $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean all: $(TARGET) diff --git a/programs/src/shell/Makefile b/programs/src/shell/Makefile index f44fc74..6748e86 100644 --- a/programs/src/shell/Makefile +++ b/programs/src/shell/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,10 +17,9 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin +BINDIR := ../../bin$(ARCH_SUFFIX) LIBDIR := ../../lib -OBJDIR := obj - +OBJDIR := obj$(ARCH_SUFFIX) # ---- C++ compiler flags ---- CXXFLAGS := \ @@ -36,10 +35,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -MMD -MP \ -I . \ -I $(PROG_INC) @@ -64,9 +60,9 @@ TARGET := $(BINDIR)/os/shell.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/os - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp shell.h Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/spreadsheet/Makefile b/programs/src/spreadsheet/Makefile index 4445f13..1955380 100644 --- a/programs/src/spreadsheet/Makefile +++ b/programs/src/spreadsheet/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -57,15 +56,15 @@ OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) # ---- Target ---- TARGET := $(BINDIR)/apps/spreadsheet/spreadsheet.elf -LOADER_LIB := $(LIBDIR)/libloader/liblibloader.a +LOADER_LIB := $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a .PHONY: all clean all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/spreadsheet - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/sshd/Makefile b/programs/src/sshd/Makefile index 0d04f72..9c423c0 100644 --- a/programs/src/sshd/Makefile +++ b/programs/src/sshd/Makefile @@ -1,18 +1,18 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk CXX := $(TOOLCHAIN_PREFIX)g++ PROG_INC := ../../include LIBDIR := ../../lib LINK_LD := ../../link.ld -OBJDIR := obj -TARGET := ../../bin/os/sshd.elf +OBJDIR := obj$(ARCH_SUFFIX) +TARGET := ../../bin$(ARCH_SUFFIX)/os/sshd.elf CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -ffreestanding \ -fno-stack-protector -fno-stack-check -fno-rtti -fno-exceptions \ - -ffunction-sections -fdata-sections -mno-80387 -mno-mmx -mno-sse -mno-sse2 \ + -ffunction-sections -fdata-sections $(ARCH_NOFP_FLAGS) \ -MMD -MP -I $(PROG_INC) -I $(LIBDIR)/bearssl/inc -isystem $(PROG_INC)/libc LDFLAGS := -nostdlib -Wl,--gc-sections -T $(LINK_LD) -LIBS := $(LIBDIR)/bearssl/libbearssl.a $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/bearssl/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJDIR)/main.o $(LIBS) $(LINK_LD) Makefile diff --git a/programs/src/sshserver/Makefile b/programs/src/sshserver/Makefile index bfc7334..552f217 100644 --- a/programs/src/sshserver/Makefile +++ b/programs/src/sshserver/Makefile @@ -1,21 +1,21 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk CXX := $(TOOLCHAIN_PREFIX)g++ PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := -std=gnu++20 -g -O2 -pipe -Wall -Wextra -Wno-unused-parameter \ -ffreestanding -fno-stack-protector -fno-stack-check -fno-rtti -fno-exceptions \ - -ffunction-sections -fdata-sections -msse -msse2 -MMD -MP -I $(PROG_INC) \ + -ffunction-sections -fdata-sections $(ARCH_FP_FLAGS) -MMD -MP -I $(PROG_INC) \ -I $(LIBDIR)/bearssl/inc -isystem $(PROG_INC)/libc LDFLAGS := -nostdlib -Wl,--gc-sections -T $(LINK_LD) SRCS := main.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/sshserver/sshserver.elf -LIBS := $(LIBDIR)/bearssl/libbearssl.a $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/bearssl/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean all: $(TARGET) $(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBS) diff --git a/programs/src/syslog/Makefile b/programs/src/syslog/Makefile index ee919ad..84db24e 100644 --- a/programs/src/syslog/Makefile +++ b/programs/src/syslog/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -51,9 +50,9 @@ TARGET := $(BINDIR)/apps/syslog/syslog.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a $(LIBDIR)/libloader/liblibloader.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a mkdir -p $(BINDIR)/apps/syslog - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a $(LIBDIR)/libloader/liblibloader.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/tcc/Makefile b/programs/src/tcc/Makefile index 40298c7..46f77be 100644 --- a/programs/src/tcc/Makefile +++ b/programs/src/tcc/Makefile @@ -6,11 +6,11 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CC = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) - AR = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CC = $(error $(TOOLCHAIN_MISSING)) + CXX = $(error $(TOOLCHAIN_MISSING)) + AR = $(error $(TOOLCHAIN_MISSING)) else CC := $(TOOLCHAIN_PREFIX)gcc CXX := $(TOOLCHAIN_PREFIX)g++ @@ -21,8 +21,8 @@ endif PROG_INC := ../../include LIBDIR := ../../lib -OBJDIR := obj -BINDIR := ../../bin/os +OBJDIR := obj$(ARCH_SUFFIX) +BINDIR := ../../bin$(ARCH_SUFFIX)/os # ---- Compiler flags ---- @@ -42,8 +42,7 @@ CFLAGS := \ -fno-stack-check \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -fno-tree-loop-distribute-patterns \ -D__MONTAUKOS__=1 \ -DONE_SOURCE=0 \ @@ -93,7 +92,7 @@ TARGET := $(BINDIR)/tcc.elf # ---- CRT objects (staged from shared libc) ---- SHARED_CRT_DIR := $(LIBDIR)/libc -CRT_DIR := ../../bin/sdk/tcc/lib +CRT_DIR := ../../bin$(ARCH_SUFFIX)/sdk/tcc/lib CRT_OBJS := $(CRT_DIR)/crt1.o $(CRT_DIR)/crti.o $(CRT_DIR)/crtn.o # ---- Rules ---- @@ -102,9 +101,9 @@ CRT_OBJS := $(CRT_DIR)/crt1.o $(CRT_DIR)/crti.o $(CRT_DIR)/crtn.o all: $(TARGET) $(CRT_OBJS) $(CRT_DIR)/libc.a -$(TARGET): $(ALL_OBJS) $(LIBDIR)/libc/liblibc.a +$(TARGET): $(ALL_OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a @mkdir -p $(BINDIR) - $(CC) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) $(LIBDIR)/libc/liblibc.a -lgcc -o $@ + $(CC) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -lgcc -o $@ $(OBJDIR)/%.o: %.c Makefile config.h montauk_compat.h @mkdir -p $(OBJDIR) @@ -114,7 +113,7 @@ $(OBJDIR)/%.o: %.S Makefile @mkdir -p $(OBJDIR) $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ -$(SHARED_CRT_DIR)/liblibc.a $(SHARED_CRT_DIR)/liblibc-full.a $(SHARED_CRT_DIR)/crt1.o $(SHARED_CRT_DIR)/crti.o $(SHARED_CRT_DIR)/crtn.o: +$(SHARED_CRT_DIR)/$(ARCH_OUT)liblibc.a $(SHARED_CRT_DIR)/liblibc-full.a $(SHARED_CRT_DIR)/crt1.o $(SHARED_CRT_DIR)/crti.o $(SHARED_CRT_DIR)/crtn.o: $(MAKE) -C $(SHARED_CRT_DIR) $(CRT_DIR)/crt1.o: $(SHARED_CRT_DIR)/crt1.o @@ -132,7 +131,7 @@ $(CRT_DIR)/crtn.o: $(SHARED_CRT_DIR)/crtn.o # liblibc-full.a, not liblibc.a: programs compiled on-OS with tcc cannot pass # -u _pf_putfloat, so this sysroot ships the variant with the printf float path # already bound in. See lib/libc/Makefile. -$(CRT_DIR)/libc.a: $(LIBDIR)/libc/liblibc-full.a +$(CRT_DIR)/libc.a: $(LIBDIR)/libc/$(ARCH_OUT)liblibc-full.a @mkdir -p $(CRT_DIR) cp $< $@ diff --git a/programs/src/terminal/Makefile b/programs/src/terminal/Makefile index cedf13c..4b67f05 100644 --- a/programs/src/terminal/Makefile +++ b/programs/src/terminal/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -51,9 +50,9 @@ TARGET := $(BINDIR)/apps/terminal/terminal.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/terminal - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/texteditor/Makefile b/programs/src/texteditor/Makefile index 64ef351..43dc5b0 100644 --- a/programs/src/texteditor/Makefile +++ b/programs/src/texteditor/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -17,8 +17,8 @@ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib # ---- Compiler flags ---- @@ -37,8 +37,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -57,15 +56,15 @@ OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) # ---- Target ---- TARGET := $(BINDIR)/apps/texteditor/texteditor.elf -LOADER_LIB := $(LIBDIR)/libloader/liblibloader.a +LOADER_LIB := $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a .PHONY: all clean all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LOADER_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/texteditor - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LOADER_LIB) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ $(OBJDIR)/%.o: %.cpp Makefile mkdir -p $(OBJDIR) diff --git a/programs/src/timezone/Makefile b/programs/src/timezone/Makefile index 3d5c3f9..9eb56b2 100644 --- a/programs/src/timezone/Makefile +++ b/programs/src/timezone/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -MMD -MP \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc @@ -46,7 +45,7 @@ SRCS := main.cpp stb_truetype_impl.cpp font_data.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) TARGET := $(BINDIR)/apps/timezone/timezone.elf -LIBS := $(LIBDIR)/libc/liblibc.a +LIBS := $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a .PHONY: all clean diff --git a/programs/src/video/Makefile b/programs/src/video/Makefile index eefab16..8684b19 100644 --- a/programs/src/video/Makefile +++ b/programs/src/video/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -I . \ -isystem $(PROG_INC)/libc @@ -51,9 +50,9 @@ TARGET := $(BINDIR)/apps/video/video.elf all: $(TARGET) -$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/liblibc.a +$(TARGET): $(OBJS) $(LINK_LD) Makefile $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a mkdir -p $(BINDIR)/apps/video - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a -o $@ HEADERS := avi.hpp diff --git a/programs/src/weather/Makefile b/programs/src/weather/Makefile index 2fc4f39..da5ab6b 100644 --- a/programs/src/weather/Makefile +++ b/programs/src/weather/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -21,9 +21,8 @@ LIBC_LIB := ../../lib/libc LIBC_INC := ../../include/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -40,8 +39,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) \ -I $(BEARSSL)/inc @@ -55,7 +53,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Source files ---- diff --git a/programs/src/wiki/Makefile b/programs/src/wiki/Makefile index 8f10a39..0be6971 100644 --- a/programs/src/wiki/Makefile +++ b/programs/src/wiki/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -21,9 +21,8 @@ LIBC_LIB := ../../lib/libc LIBC_INC := ../../include/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -39,10 +38,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ + $(ARCH_NOFP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) \ -I $(BEARSSL)/inc @@ -56,7 +52,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Target ---- diff --git a/programs/src/wikipedia/Makefile b/programs/src/wikipedia/Makefile index 5e72f1f..cc390af 100644 --- a/programs/src/wikipedia/Makefile +++ b/programs/src/wikipedia/Makefile @@ -6,9 +6,9 @@ MAKEFLAGS += -rR # ---- Toolchain ---- -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif @@ -21,9 +21,8 @@ LIBC_LIB := ../../lib/libc LIBC_INC := ../../include/libc PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj - +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) # ---- Compiler flags ---- CXXFLAGS := \ @@ -40,8 +39,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(LIBC_INC) \ -I $(BEARSSL)/inc @@ -55,7 +53,7 @@ LDFLAGS := \ # ---- Libraries ---- -LIBS := $(TLS_LIB)/libtls.a $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a +LIBS := $(TLS_LIB)/$(ARCH_OUT)libtls.a $(BEARSSL)/build$(ARCH_SUFFIX)/libbearssl.a $(LIBC_LIB)/$(ARCH_OUT)liblibc.a # ---- Source files ---- diff --git a/programs/src/wordprocessor/Makefile b/programs/src/wordprocessor/Makefile index ef8b33a..4390608 100644 --- a/programs/src/wordprocessor/Makefile +++ b/programs/src/wordprocessor/Makefile @@ -4,17 +4,17 @@ MAKEFLAGS += -rR .SUFFIXES: -TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-montauk- +include ../../mk/arch.mk ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) - CXX = $(error x86_64-montauk toolchain not found. Run ./toolchain/build-montauk-toolchain.sh first) + CXX = $(error $(TOOLCHAIN_MISSING)) else CXX := $(TOOLCHAIN_PREFIX)g++ endif PROG_INC := ../../include LINK_LD := ../../link.ld -BINDIR := ../../bin -OBJDIR := obj +BINDIR := ../../bin$(ARCH_SUFFIX) +OBJDIR := obj$(ARCH_SUFFIX) LIBDIR := ../../lib CXXFLAGS := \ @@ -31,8 +31,7 @@ CXXFLAGS := \ -fno-exceptions \ -ffunction-sections \ -fdata-sections \ - -msse \ - -msse2 \ + $(ARCH_FP_FLAGS) \ -I $(PROG_INC) \ -isystem $(PROG_INC)/libc \ -I ../../lib/bearssl/inc @@ -44,8 +43,8 @@ LDFLAGS := \ SRCS := main.cpp document.cpp render.cpp input.cpp print_export.cpp stb_truetype_impl.cpp OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) -LOADER_LIB := $(LIBDIR)/libloader/liblibloader.a -LIBS := $(LOADER_LIB) $(LIBDIR)/tls/libtls.a $(LIBDIR)/bearssl/libbearssl.a $(LIBDIR)/libjpegwrite/libjpegwrite.a $(LIBDIR)/libc/liblibc.a +LOADER_LIB := $(LIBDIR)/libloader/$(ARCH_OUT)liblibloader.a +LIBS := $(LOADER_LIB) $(LIBDIR)/tls/$(ARCH_OUT)libtls.a $(LIBDIR)/bearssl/build$(ARCH_SUFFIX)/libbearssl.a $(LIBDIR)/libjpegwrite/$(ARCH_OUT)libjpegwrite.a $(LIBDIR)/libc/$(ARCH_OUT)liblibc.a TARGET := $(BINDIR)/apps/wordprocessor/wordprocessor.elf diff --git a/scripts/copy_fonts.sh b/scripts/copy_fonts.sh index d0a68e7..d4abddc 100755 --- a/scripts/copy_fonts.sh +++ b/scripts/copy_fonts.sh @@ -8,7 +8,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -FONT_DST="$PROJECT_ROOT/programs/bin/os/fonts" +FONT_DST="$PROJECT_ROOT/programs/${PROGRAMS_BIN:-bin}/os/fonts" mkdir -p "$FONT_DST" diff --git a/scripts/copy_icons.sh b/scripts/copy_icons.sh index ba89a0e..ac0e715 100755 --- a/scripts/copy_icons.sh +++ b/scripts/copy_icons.sh @@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" ICON_SRC="$PROJECT_ROOT/programs/gui/icons/Flat-Remix-Blue-Light-darkPanel" -ICON_DST="$PROJECT_ROOT/programs/bin/os/icons" +ICON_DST="$PROJECT_ROOT/programs/${PROGRAMS_BIN:-bin}/os/icons" mkdir -p "$ICON_DST" diff --git a/scripts/install_apps.sh b/scripts/install_apps.sh index 21fad15..cc1c896 100755 --- a/scripts/install_apps.sh +++ b/scripts/install_apps.sh @@ -9,7 +9,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" SRC="$PROJECT_ROOT/programs/src" -BIN="$PROJECT_ROOT/programs/bin" +# PROGRAMS_BIN: the output tree, bin (x86_64) or bin-. +BIN="$PROJECT_ROOT/programs/${PROGRAMS_BIN:-bin}" ICON_SRC="$PROJECT_ROOT/programs/gui/icons/Flat-Remix-Blue-Light-darkPanel" # App definitions: name|icon_source_path diff --git a/toolchain/README.md b/toolchain/README.md index af9546b..e7b4c61 100644 --- a/toolchain/README.md +++ b/toolchain/README.md @@ -6,11 +6,16 @@ Two cross toolchains live here, both installed to `toolchain/local/`: |--------|--------|---------| | `build-toolchain.sh` | `x86_64-elf` | Bare-metal compiler for the kernel | | `build-montauk-toolchain.sh` | `x86_64-montauk` | OS-aware compiler for userspace programs | +| `build-montauk-toolchain.sh aarch64` | `aarch64-montauk` | the same for the ARM port | Both use Binutils 2.43.1 + GCC 14.2.0 and share the source trees in `src/`. The Montauk target is added by the patches in `patches/` plus the target header `files/montauk.h` (installed as -`gcc/config/montauk.h` in the GCC tree). +`gcc/config/montauk.h` in the GCC tree). The AArch64 target is a second +pair of patches (`*-montauk-aarch64.patch`) applied on top, with its +target header `files/aarch64-montauk.h` (installed as +`gcc/config/aarch64/montauk.h`). The ARM kernel is built with clang, not +with a bare-metal GCC. ## The x86_64-montauk target @@ -42,6 +47,27 @@ The in-tree programs are built `-fno-exceptions -fno-rtti` (the project convention), but that is a project style choice, not a toolchain limit — see the STL section below. +## The aarch64-montauk target + +`./toolchain/build-montauk-toolchain.sh aarch64` builds +`aarch64-montauk-gcc/g++` next to the x86 compilers, with its sysroot in +`toolchain/sysroot-aarch64/` and its libc from +`programs/lib/libc/build-aarch64/`. On a first build the libc cannot be +compiled yet, so the script builds GCC against the headers alone and +completes the sysroot afterwards. The target matches x86_64-montauk +(static `ET_EXEC` at 0x400000, 4 KiB segment alignment, the same crt +files and `-lc`), plus two defaults chosen so the shared userspace +behaves the same on both architectures: + +- `-fsigned-char`: plain `char` is signed, as on x86 (AAPCS64 makes it + unsigned). The GUI's CP1252 text handling assumes signed bytes. +- `-mno-outline-atomics`: inline LL/SC atomics. Outline atomics choose + LSE at run time from HWCAP, which Montauk does not provide, and their + helpers are in libgcc, which `-nostdlib` programs never link. + +`make ARCH=aarch64` at the repository root builds the userspace with it +(into `programs/bin-aarch64/`); see `programs/mk/arch.mk`. + ## C++ standard library (hosted libstdc++) `build-montauk-toolchain.sh` builds and installs a **hosted** libstdc++ diff --git a/toolchain/build-montauk-toolchain.sh b/toolchain/build-montauk-toolchain.sh index 1f9b1e2..795f6f2 100755 --- a/toolchain/build-montauk-toolchain.sh +++ b/toolchain/build-montauk-toolchain.sh @@ -1,9 +1,10 @@ #!/usr/bin/env bash # -# build-montauk-toolchain.sh — Build an x86_64-montauk cross compiler +# build-montauk-toolchain.sh — Build an -montauk cross compiler # (Binutils + GCC) for MontaukOS userspace programs. # -# Usage: ./toolchain/build-montauk-toolchain.sh +# Usage: ./toolchain/build-montauk-toolchain.sh [x86_64|aarch64] +# (or ARCH=aarch64 ./toolchain/build-montauk-toolchain.sh) # # Unlike the bare-metal x86_64-elf toolchain (build-toolchain.sh), this # target knows the Montauk userspace ABI: it links static ET_EXEC @@ -13,9 +14,11 @@ # # The toolchain is installed to toolchain/local/ and provides: # x86_64-montauk-gcc, x86_64-montauk-g++, x86_64-montauk-ld, etc. +# (aarch64-montauk-* for ARCH=aarch64; both can live side by side). # # The target sysroot (libc headers + libs) is assembled into -# toolchain/sysroot/ from programs/include/libc and programs/lib/libc. +# toolchain/sysroot/ (x86_64) or toolchain/sysroot-/ from +# programs/include/libc and programs/lib/libc. # Re-run this script after changing libc headers or rebuilding libc to # refresh the sysroot (the sysroot step always runs; compiler builds # are skipped once installed). @@ -27,7 +30,12 @@ set -euo pipefail # ── Versions (kept in lockstep with build-toolchain.sh) ─────────────────────── BINUTILS_VERSION="2.43.1" GCC_VERSION="14.2.0" -TARGET="x86_64-montauk" +ARCH="${1:-${ARCH:-x86_64}}" +case "${ARCH}" in + x86_64|aarch64) ;; + *) echo "Unsupported architecture: ${ARCH}" >&2; exit 1 ;; +esac +TARGET="${ARCH}-montauk" # ── Directories ─────────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -35,7 +43,13 @@ REPO_DIR="$(dirname "${SCRIPT_DIR}")" PREFIX="${SCRIPT_DIR}/local" SRC_DIR="${SCRIPT_DIR}/src" BUILD_DIR="${SCRIPT_DIR}/build" -SYSROOT="${SCRIPT_DIR}/sysroot" +if [[ "${ARCH}" == x86_64 ]]; then + SYSROOT="${SCRIPT_DIR}/sysroot" + BUILD_SUFFIX="" +else + SYSROOT="${SCRIPT_DIR}/sysroot-${ARCH}" + BUILD_SUFFIX="-${ARCH}" +fi PATCH_DIR="${SCRIPT_DIR}/patches" FILES_DIR="${SCRIPT_DIR}/files" @@ -104,54 +118,87 @@ apply_patch() { fi } +# The AArch64 target is a second patch on top of the first. +apply_arch_patch() { + local dir="$1" patch="$2" marker="$3" + if grep -q "aarch64-\*-montauk" "${dir}/${marker}"; then + bold "Already patched for aarch64: $(basename "${dir}")" + else + bold "Patching $(basename "${dir}") for aarch64..." + patch -d "${dir}" -p1 < "${patch}" + fi +} + apply_patch "${SRC_DIR}/binutils-${BINUTILS_VERSION}" "${PATCH_DIR}/binutils-${BINUTILS_VERSION}-montauk.patch" apply_patch "${SRC_DIR}/gcc-${GCC_VERSION}" "${PATCH_DIR}/gcc-${GCC_VERSION}-montauk.patch" +apply_arch_patch "${SRC_DIR}/binutils-${BINUTILS_VERSION}" \ + "${PATCH_DIR}/binutils-${BINUTILS_VERSION}-montauk-aarch64.patch" bfd/config.bfd +apply_arch_patch "${SRC_DIR}/gcc-${GCC_VERSION}" \ + "${PATCH_DIR}/gcc-${GCC_VERSION}-montauk-aarch64.patch" gcc/config.gcc cp "${FILES_DIR}/montauk.h" "${SRC_DIR}/gcc-${GCC_VERSION}/gcc/config/montauk.h" +cp "${FILES_DIR}/aarch64-montauk.h" "${SRC_DIR}/gcc-${GCC_VERSION}/gcc/config/aarch64/montauk.h" # ── Assemble the target sysroot ─────────────────────────────────────────────── # usr/include — the Montauk libc headers (self-contained C; stddef/stdint/ # stdarg come from GCC itself) plus the montauk/ SDK headers. # usr/lib — crt startup objects and the libc static library. -bold "Assembling sysroot from programs/lib/libc..." -make -C "${REPO_DIR}/programs" libc >/dev/null - -rm -rf "${SYSROOT}" -mkdir -p "${SYSROOT}/usr/include" "${SYSROOT}/usr/lib" -cp -r "${REPO_DIR}/programs/include/libc/." "${SYSROOT}/usr/include/" -cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk" -cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api" -# Freestanding C++ headers (, , , ...) — -# the subset the kernel and the in-tree programs build against. This is -# NOT the whole C++ story: a hosted libstdc++ is built further down and -# installs its own headers under ${PREFIX}/x86_64-montauk/include/c++. -# That directory comes first on the include path and this one comes -# last, so a plain g++ invocation gets the hosted headers and these are -# shadowed. See "C++ standard library" in README.md. -cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/x86_64/include/." "${SYSROOT}/usr/include/" -cp "${REPO_DIR}/programs/lib/libc/crt1.o" \ - "${REPO_DIR}/programs/lib/libc/crti.o" \ - "${REPO_DIR}/programs/lib/libc/crtn.o" "${SYSROOT}/usr/lib/" -cp "${REPO_DIR}/programs/lib/libc/liblibc.a" "${SYSROOT}/usr/lib/libc.a" -# libm is an empty stand-in (math lives inside libc.a; the g++ driver -# links -lm unconditionally). libstdc++ is copied from the toolchain -# once built - the empty stand-in only bridges the first bootstrap. -ar rcs "${SYSROOT}/usr/lib/libm.a" -if [[ -f "${PREFIX}/x86_64-montauk/lib/libstdc++.a" ]]; then - cp "${PREFIX}/x86_64-montauk/lib/libstdc++.a" "${SYSROOT}/usr/lib/libstdc++.a" -else - ar rcs "${SYSROOT}/usr/lib/libstdc++.a" +LIBC_DIR="${REPO_DIR}/programs/lib/libc" +if [[ "${ARCH}" != x86_64 ]]; then + LIBC_DIR="${LIBC_DIR}/build-${ARCH}" fi -green "Sysroot ready." + +# On a first build for a new architecture the libc cannot be compiled yet +# (it needs this compiler): the sysroot then holds only headers, which is +# all building GCC needs, and is completed once GCC exists. +assemble_sysroot() { + bold "Assembling sysroot from programs/lib/libc..." + local have_libc=1 + make -C "${REPO_DIR}/programs" libc ARCH="${ARCH}" >/dev/null 2>&1 || have_libc=0 + [[ -f "${LIBC_DIR}/liblibc.a" && -f "${LIBC_DIR}/crt1.o" ]] || have_libc=0 + + rm -rf "${SYSROOT}" + mkdir -p "${SYSROOT}/usr/include" "${SYSROOT}/usr/lib" + cp -r "${REPO_DIR}/programs/include/libc/." "${SYSROOT}/usr/include/" + cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk" + cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api" + # Freestanding C++ headers (, , , ...) — + # the subset the kernel and the in-tree programs build against. This is + # NOT the whole C++ story: a hosted libstdc++ is built further down and + # installs its own headers under ${PREFIX}/${TARGET}/include/c++. + # That directory comes first on the include path and this one comes + # last, so a plain g++ invocation gets the hosted headers and these are + # shadowed. See "C++ standard library" in README.md. + cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/${ARCH}/include/." "${SYSROOT}/usr/include/" + if [[ ${have_libc} == 1 ]]; then + cp "${LIBC_DIR}/crt1.o" "${LIBC_DIR}/crti.o" "${LIBC_DIR}/crtn.o" "${SYSROOT}/usr/lib/" + cp "${LIBC_DIR}/liblibc.a" "${SYSROOT}/usr/lib/libc.a" + else + bold "libc not built yet - sysroot has headers only." + fi + # libm is an empty stand-in (math lives inside libc.a; the g++ driver + # links -lm unconditionally). libstdc++ is copied from the toolchain + # once built - the empty stand-in only bridges the first bootstrap. + ar rcs "${SYSROOT}/usr/lib/libm.a" + if [[ -f "${PREFIX}/${TARGET}/lib/libstdc++.a" ]]; then + cp "${PREFIX}/${TARGET}/lib/libstdc++.a" "${SYSROOT}/usr/lib/libstdc++.a" + else + ar rcs "${SYSROOT}/usr/lib/libstdc++.a" + fi + green "Sysroot ready." + return 0 +} + +assemble_sysroot # ── Build Binutils ──────────────────────────────────────────────────────────── if [[ -x "${PREFIX}/bin/${TARGET}-ld" ]]; then bold "Binutils already installed — skipping." else bold "Building Binutils ${BINUTILS_VERSION} for ${TARGET}..." - rm -rf "${BUILD_DIR}/binutils-montauk" - mkdir -p "${BUILD_DIR}/binutils-montauk" + rm -rf "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}" + mkdir -p "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}" ( - cd "${BUILD_DIR}/binutils-montauk" + cd "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}" "${SRC_DIR}/binutils-${BINUTILS_VERSION}/configure" \ --target="${TARGET}" \ --prefix="${PREFIX}" \ @@ -174,10 +221,10 @@ if [[ -x "${PREFIX}/bin/${TARGET}-gcc" ]]; then bold "GCC already installed — skipping." else bold "Building GCC ${GCC_VERSION} for ${TARGET}..." - rm -rf "${BUILD_DIR}/gcc-montauk" - mkdir -p "${BUILD_DIR}/gcc-montauk" + rm -rf "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}" + mkdir -p "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}" ( - cd "${BUILD_DIR}/gcc-montauk" + cd "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}" "${SRC_DIR}/gcc-${GCC_VERSION}/configure" \ --target="${TARGET}" \ --prefix="${PREFIX}" \ @@ -203,6 +250,11 @@ else green "GCC and libstdc++ installed." fi +# A first build for this architecture had no libc: complete the sysroot. +if [[ ! -f "${SYSROOT}/usr/lib/libc.a" ]] || [[ ! -s "${SYSROOT}/usr/lib/libstdc++.a" ]]; then + assemble_sysroot +fi + # ── Done ────────────────────────────────────────────────────────────────────── echo green "=== ${TARGET} cross compiler ready ===" diff --git a/toolchain/files/aarch64-montauk.h b/toolchain/files/aarch64-montauk.h new file mode 100644 index 0000000..55e290d --- /dev/null +++ b/toolchain/files/aarch64-montauk.h @@ -0,0 +1,43 @@ +/* + * aarch64-montauk.h + * GCC target definitions for aarch64-montauk userspace + * (installed as gcc/config/aarch64/montauk.h) + * Copyright (c) 2026 Daniel Hammer + * + * Programs are static, non-PIE ET_EXEC images loaded by the kernel + * ELF loader (kernel/src/Sched/ElfLoader.cpp) at their linked + * address. The loader maps 4 KiB pages, so segments must not use + * the 64 KiB AArch64 default alignment. +*/ + +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define("__montauk__"); \ + builtin_define("__MONTAUK__"); \ + builtin_assert("system=montauk"); \ + } while (0) + +/* Inline LL/SC atomics: outline atomics pick LSE at run time from HWCAP, + which Montauk does not provide, and their helpers live in libgcc, which + -nostdlib programs never link. + Signed plain char, as on x86_64-montauk: the userspace is shared between + the architectures and its CP1252 text handling assumes it. + -moutline-atomics / -funsigned-char still override. */ +#undef CC1_SPEC +#define CC1_SPEC "%{!moutline-atomics:-mno-outline-atomics} %{!funsigned-char:-fsigned-char}" + +#undef LINK_SPEC +#define LINK_SPEC \ + "-maarch64elf -X -z max-page-size=0x1000 %{shared:-shared} %{!shared:-static}" + +/* As on x86_64-montauk: crt1/crti/crtn from the Montauk libc, + crtbegin/crtend from libgcc. */ +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "crt1.o%s crti.o%s crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +#undef LIB_SPEC +#define LIB_SPEC "-lc" diff --git a/toolchain/patches/binutils-2.43.1-montauk-aarch64.patch b/toolchain/patches/binutils-2.43.1-montauk-aarch64.patch new file mode 100644 index 0000000..5dd5382 --- /dev/null +++ b/toolchain/patches/binutils-2.43.1-montauk-aarch64.patch @@ -0,0 +1,35 @@ +--- a/bfd/config.bfd ++++ b/bfd/config.bfd +@@ -248,6 +248,11 @@ + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec aarch64_pei_le_vec aarch64_pe_le_vec" + want64=true + ;; ++ aarch64-*-montauk*) ++ targ_defvec=aarch64_elf64_le_vec ++ targ_selvecs=aarch64_elf64_be_vec ++ want64=true ++ ;; + aarch64-*-pe* | aarch64-*-mingw*) + targ_defvec=aarch64_pe_le_vec + targ_selvecs="aarch64_pe_le_vec aarch64_pei_le_vec aarch64_elf64_le_vec aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec pdb_vec" +--- a/gas/configure.tgt ++++ b/gas/configure.tgt +@@ -128,6 +128,7 @@ + case ${generic_target} in + aarch64*-*-elf*) fmt=elf;; + aarch64*-*-fuchsia*) fmt=elf;; ++ aarch64*-*-montauk*) fmt=elf;; + aarch64*-*-haiku*) fmt=elf em=haiku ;; + aarch64*-*-genode*) fmt=elf;; + aarch64*-*-linux*) fmt=elf em=linux +--- a/ld/configure.tgt ++++ b/ld/configure.tgt +@@ -89,6 +89,8 @@ + targ_emul=aarch64elf + targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" + ;; ++aarch64-*-montauk*) targ_emul=aarch64elf ++ ;; + aarch64-*-cloudabi*) targ_emul=aarch64cloudabi + targ_extra_emuls=aarch64cloudabib + ;; diff --git a/toolchain/patches/gcc-14.2.0-montauk-aarch64.patch b/toolchain/patches/gcc-14.2.0-montauk-aarch64.patch new file mode 100644 index 0000000..bb008bb --- /dev/null +++ b/toolchain/patches/gcc-14.2.0-montauk-aarch64.patch @@ -0,0 +1,40 @@ +--- a/gcc/config.gcc ++++ b/gcc/config.gcc +@@ -1189,7 +1189,7 @@ + esac + + case ${target} in +-aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*) ++aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems* | aarch64*-*-montauk*) + tm_file="${tm_file} elfos.h newlib-stdint.h" + tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-elf-raw.h" + tmake_file="${tmake_file} aarch64/t-aarch64" +@@ -1204,6 +1204,11 @@ + tm_file="${tm_file} aarch64/rtems.h rtems.h" + tmake_file="${tmake_file} aarch64/t-aarch64-rtems" + ;; ++ aarch64-*-montauk*) ++ tm_file="${tm_file} aarch64/montauk.h" ++ # As for x86_64-montauk: the libc has no stdint.h of its own. ++ use_gcc_stdint=provide ++ ;; + esac + case $target in + aarch64_be-*) +--- a/libgcc/config.host ++++ b/libgcc/config.host +@@ -418,6 +418,14 @@ + tmake_file="${tmake_file} t-dfprules" + md_unwind_header=aarch64/aarch64-unwind.h + ;; ++aarch64*-*-montauk*) ++ extra_parts="$extra_parts crtbegin.o crtend.o crtfastmath.o" ++ tmake_file="${tmake_file} ${cpu_type}/t-aarch64" ++ tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" ++ tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" ++ tmake_file="${tmake_file} t-dfprules" ++ md_unwind_header=aarch64/aarch64-unwind.h ++ ;; + aarch64*-*-freebsd*) + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64"