feat: aarch64 port - Raspberry Pi 4/400 SD boot (SDHCI, ext2 root + first-boot grow), USB hubs, PCI INTx routing, SMP, DMA fences

This commit is contained in:
daniel committed 2026-10-25 13:48:26 +01:00
1 parent 8c09ccef66
commit 808e1d66fd
66 files changed
+3690 -196

No files matched your search

+13 -3
View File
@@ -45,7 +45,7 @@ BINDIR := bin$(ARCH_SUFFIX)
PROGRAMS := $(notdir $(wildcard src/*))
# Programs with custom Makefiles (built separately).
CUSTOM_BUILDS := 2048 files settings fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver terminal syslog procmgr powermgr calculator charmap desktop login shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad sshd rtlsdr sdr
CUSTOM_BUILDS := 2048 files settings fetch wiki wikipedia weather imageviewer fontpreview spreadsheet wordprocessor pdfviewer disks devexplorer installer audio music video bluetooth network display capabilities keyboard sshserver terminal syslog procmgr powermgr calculator charmap desktop login shell paint tcc lua screenshot texteditor mandelbrot printers timezone printd printctl dialogs libloader crashpad sshd rtlsdr sdr firstboot
SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS))
# Build targets: system programs go to bin/os/, apps go to bin/apps/<name>/.
@@ -92,7 +92,7 @@ WPDIR := data/wallpapers
WPSRC := $(wildcard $(WPDIR)/*.jpg)
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
.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 firstboot
# The on-OS SDK, tcc (an x86 code generator) and the Rust programs exist
# for x86_64 only.
@@ -102,6 +102,12 @@ 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)
# The Raspberry Pi SD image's first-boot program (built outside bin/, see
# src/firstboot/Makefile); the SD image is aarch64 only.
ifeq ($(ARCH),aarch64)
ALL_TARGETS += firstboot
endif
all: $(filter-out $(ARCH_SKIP),$(ALL_TARGETS))
# Build BearSSL static library (cross-compiled for freestanding x86_64).
@@ -263,7 +269,7 @@ terminal: libc
$(MAKE) -C src/terminal
# Build kernel log standalone GUI tool (depends on libc).
syslog: libc
syslog: libc libloader
$(MAKE) -C src/syslog
# Build process manager standalone GUI tool (depends on libc).
@@ -294,6 +300,9 @@ timezone: libc
login: bearssl libc
$(MAKE) -C src/login
firstboot: libc
$(MAKE) -C src/firstboot
# Build shell via its own Makefile (multi-file build).
shell: libc
$(MAKE) -C src/shell
@@ -547,6 +556,7 @@ clean:
$(MAKE) -C lib/tls clean
$(MAKE) -C src/fetch clean
$(MAKE) -C src/login clean
$(MAKE) -C src/firstboot clean
$(MAKE) -C src/shell clean
$(MAKE) -C src/desktop clean
$(MAKE) -C src/wikipedia clean
+14 -1
View File
@@ -312,6 +312,11 @@ namespace montauk::abi {
static constexpr uint64_t SYS_WIN_DRAG_FORMATS = 206; // (serial, TransferFormatInfo*, max) -> count
static constexpr uint64_t SYS_WIN_DRAG_GET_DATA = 207; // (serial, mime, buf, max, uint32_t* len) -> status
/* Storage.hpp -- grow a mounted volume (and its MBR partition) to fill the
free space after it. apply=0 only reports; apply=1 does one bounded slice
and returns 1 while more remains, 0 once done. CAP_STORAGE_ADMIN. */
static constexpr uint64_t SYS_FS_GROW = 208; // (drive, FsGrowStatus*, apply) -> 1 / 0 / status
/* Kernel-owned process capabilities. User identities may namespace
per-user resources, but never participate in authorization decisions. */
static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0;
@@ -838,7 +843,7 @@ namespace montauk::abi {
struct DiskInfo {
uint8_t port; // block device index
uint8_t type; // 0=none, 1=SATA, 2=SATAPI, 3=NVMe, 4=USB mass storage
uint8_t type; // 0=none, 1=SATA, 2=SATAPI, 3=NVMe, 4=USB mass storage, 5=SD card
uint8_t sataGen; // SATA gen (1/2/3)
uint8_t _pad0;
uint64_t sectorCount; // Total user-addressable sectors
@@ -920,6 +925,14 @@ namespace montauk::abi {
char label[32]; // volume label
};
struct FsGrowStatus {
uint64_t fsBytes; // filesystem size now
uint64_t partBytes; // partition size now
uint64_t targetBytes; // filesystem size once grown; == fsBytes if it cannot grow
uint32_t stepsDone; // progress of the grow, out of stepsTotal
uint32_t stepsTotal;
};
// Bluetooth scan result (returned by SYS_BTSCAN)
struct BtScanResult {
uint8_t bdAddr[6];
+1
View File
@@ -231,6 +231,7 @@ extern "C" {
#define MTK_SYS_WIN_DRAG_BEGIN 205
#define MTK_SYS_WIN_DRAG_FORMATS 206
#define MTK_SYS_WIN_DRAG_GET_DATA 207
#define MTK_SYS_FS_GROW 208
/* @SYSCALLS-END */
/* Syscall status codes (montauk/statuscodes.h for C++). */
+8
View File
@@ -654,6 +654,14 @@ namespace montauk {
inline int fs_sync() {
return (int)syscall0(montauk::abi::SYS_FS_SYNC);
}
// Grow mounted volume `drive` (and its MBR partition) to fill the free
// space after it. apply=false only fills `status`; apply=true does one
// slice of the work and returns 1 while more remains, 0 when finished,
// or a negative status.
inline int fs_grow(int drive, montauk::abi::FsGrowStatus* status, bool apply) {
return (int)syscall3(montauk::abi::SYS_FS_GROW, (uint64_t)drive,
(uint64_t)status, apply ? 1 : 0);
}
inline int fs_format(const montauk::abi::FsFormatParams* params) {
return (int)syscall1(montauk::abi::SYS_FSFORMAT, (uint64_t)params);
}
+1
View File
@@ -90,6 +90,7 @@ static void dd_draw_general(uint32_t* px, int bw, int bh, DiskDetailState* dd) {
else if (dd->info.type == 2) typeStr = "SATAPI";
else if (dd->info.type == 3) typeStr = "NVMe";
else if (dd->info.type == 4) typeStr = "USB Mass Storage";
else if (dd->info.type == 5) typeStr = "SD Card";
table_row("Type", typeStr);
snprintf(line, sizeof(line), "%d", (int)dd->info.port);
+87
View File
@@ -0,0 +1,87 @@
# Makefile for firstboot (Raspberry Pi first-boot volume grow) on MontaukOS
# Copyright (c) 2026 Daniel Hammer
#
# Only the Raspberry Pi SD image ships this program, so it is built into
# bin<arch>-rpi/ rather than bin<arch>/: everything under bin<arch>/ goes into
# the ramdisk. scripts/mk-rpi4-sd.sh lays bin<arch>-rpi/ over the system tree.
MAKEFLAGS += -rR
.SUFFIXES:
# ---- Toolchain ----
include ../../mk/arch.mk
ifeq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
CXX = $(error $(TOOLCHAIN_MISSING))
else
CXX := $(TOOLCHAIN_PREFIX)g++
endif
# ---- Paths ----
PROG_INC := ../../include
LIBC_LIB := ../../lib/libc
LINK_LD := ../../link.ld
BINDIR := ../../bin$(ARCH_SUFFIX)-rpi
OBJDIR := obj$(ARCH_SUFFIX)
# The login screen's font support, shared rather than copied.
LOGIN := ../login
# ---- Compiler flags ----
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 \
$(ARCH_FP_FLAGS) \
-I $(PROG_INC) \
-isystem $(PROG_INC)/libc
# ---- Linker flags ----
LDFLAGS := \
-nostdlib \
-Wl,--gc-sections \
-T $(LINK_LD)
# ---- Source files ----
OBJS := $(OBJDIR)/main.o $(OBJDIR)/font_data.o $(OBJDIR)/stb_truetype_impl.o
DEPS := $(OBJS:.o=.d)
# ---- Target ----
TARGET := $(BINDIR)/os/firstboot.elf
.PHONY: all clean
all: $(TARGET)
LIBS := $(LIBC_LIB)/$(ARCH_OUT)liblibc.a
$(TARGET): $(OBJS) $(LIBS) $(LINK_LD) Makefile
mkdir -p $(BINDIR)/os
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
$(OBJDIR)/%.o: %.cpp Makefile
mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
$(OBJDIR)/%.o: $(LOGIN)/%.cpp Makefile
mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
-include $(DEPS)
clean:
rm -rf $(OBJDIR) $(TARGET)
+216
View File
@@ -0,0 +1,216 @@
/*
* main.cpp
* Raspberry Pi first boot: grow the system volume to fill the SD card
* Copyright (c) 2026 Daniel Hammer
*/
// The SD card image is sized to its contents (scripts/mk-rpi4-sd.sh), so the
// ext2 system volume ends long before the card does. Started by init ahead of
// the login screen, this grows the partition and the volume into the rest of
// the card (SYS_FS_GROW, done in the kernel while the volume stays mounted)
// and shows its progress in the login screen's card style.
//
// Only the SD image ships this program, together with its init.toml service
// and capabilities.toml grant. Once the volume has grown it deletes itself, so
// later boots skip the (optional) service. If the grow fails it stays, and the
// next boot tries again, picking up where an interrupted grow left off.
#include <cstdint>
#include <montauk/syscall.h>
#include <montauk/string.h>
#include <montauk/heap.h>
#include <montauk/statuscodes.h>
#include <gui/gui.hpp>
#include <gui/framebuffer.hpp>
#include <gui/draw.hpp>
#include <gui/font.hpp>
#include <gui/canvas.hpp>
#include <gui/mtk/theme.hpp>
#include <libc/stdio.h>
using namespace gui;
inline void* operator new(unsigned long, void* p) { return p; }
static constexpr const char* SELF_PATH = "0:/os/firstboot.elf";
static constexpr int SYSTEM_DRIVE = 0;
// Card geometry, matching the login screen (src/login/login.hpp).
static constexpr int CARD_W = 432;
static constexpr int TITLEBAR_H = 30;
static constexpr int CONTENT_PAD_X = 24;
static constexpr int CONTENT_TOP_PAD = 18;
static constexpr int BAR_H = 8;
// How long the closing message stays up, and an error before boot continues.
static constexpr uint64_t DONE_VISIBLE_MS = 1500;
static constexpr uint64_t ERROR_VISIBLE_MS = 6000;
struct Screen {
Framebuffer fb;
int w, h;
mtk::Theme theme;
uint32_t* compose; // packed scratch buffer when the pitch is not w*4
};
// ==== Drawing ====
// total <= 0 hides the progress bar.
static void draw(Screen* s, const char* heading, const char* status,
const char* detail, int done, int total) {
bool packed = s->fb.pitch() == s->w * (int)sizeof(uint32_t);
uint32_t* target = packed ? s->fb.buffer() : s->compose;
if (!target) return;
Canvas c(target, s->w, s->h);
const mtk::Theme& th = s->theme;
int fh = system_font_height();
bool bar = total > 0;
int y = TITLEBAR_H + CONTENT_TOP_PAD;
int heading_y = y;
y += fh + 6;
int status_y = y;
y += fh;
int bar_y = 0, detail_y = 0;
if (bar) {
y += 14;
bar_y = y;
y += BAR_H + 8;
}
if (detail && detail[0]) {
detail_y = y;
y += fh;
}
int card_h = y + CONTENT_TOP_PAD + 10;
int card_x = (s->w - CARD_W) / 2;
int card_y = (s->h - card_h) / 2;
int content_w = CARD_W - 2 * CONTENT_PAD_X;
c.fill(Color::from_rgb(0x00, 0x00, 0x00));
int so = 4; // drop-shadow offset
c.fill_rect_alpha(card_x + so, card_y + card_h, CARD_W, so, colors::SHADOW);
c.fill_rect_alpha(card_x + CARD_W, card_y + so, so, card_h, colors::SHADOW);
c.fill_rect_alpha(card_x + CARD_W, card_y + card_h, so, so, colors::SHADOW);
c.fill_rect(card_x, card_y, CARD_W, card_h, colors::WINDOW_BG);
c.fill_rect(card_x, card_y, CARD_W, TITLEBAR_H, colors::TITLEBAR_BG);
c.rect(card_x, card_y, CARD_W, card_h, colors::BORDER);
c.hline(card_x, card_y + TITLEBAR_H - 1, CARD_W, colors::BORDER);
const char* title = "MontaukOS";
c.text(card_x + (CARD_W - text_width(title)) / 2,
card_y + (TITLEBAR_H - fh) / 2, title, th.text);
c.text(card_x + CONTENT_PAD_X, card_y + heading_y, heading, th.text);
c.text(card_x + CONTENT_PAD_X, card_y + status_y, status, th.text_subtle);
if (bar) {
int bx = card_x + CONTENT_PAD_X;
int by = card_y + bar_y;
c.fill_rounded_rect(bx, by, content_w, BAR_H, BAR_H / 2, Color::from_rgb(0xE4, 0xE4, 0xE4));
int fill = (int)((int64_t)content_w * done / total);
if (fill > 0) {
if (fill < BAR_H) fill = BAR_H;
c.fill_rounded_rect(bx, by, fill, BAR_H, BAR_H / 2, th.accent);
}
}
if (detail_y) c.text(card_x + CONTENT_PAD_X, card_y + detail_y, detail, th.text_subtle);
if (!packed) s->fb.copy_from(s->compose, s->w * (int)sizeof(uint32_t));
s->fb.flip();
}
// ==== Helpers ====
// "157 MB", "29.7 GB": decimal units, as card capacities are sold.
static void format_size(char* out, int n, uint64_t bytes) {
static constexpr uint64_t MB = 1000ull * 1000;
static constexpr uint64_t GB = 1000ull * MB;
if (bytes >= GB) {
uint64_t tenths = (bytes * 10 + GB / 2) / GB;
snprintf(out, n, "%llu.%llu GB", (unsigned long long)(tenths / 10),
(unsigned long long)(tenths % 10));
} else {
snprintf(out, n, "%llu MB", (unsigned long long)((bytes + MB / 2) / MB));
}
}
static void log_line(const char* msg) {
char line[192];
snprintf(line, sizeof(line), "firstboot: %s", msg);
montauk::write_log(line);
}
// The work is done (or there is none): remove this program so later boots
// skip its init service.
static void retire() {
if (montauk::fdelete(SELF_PATH) < 0) log_line("could not delete itself");
}
// ==== Main ====
extern "C" void _start() {
montauk::abi::FsGrowStatus st{};
int rc = montauk::fs_grow(SYSTEM_DRIVE, &st, false);
if (rc < 0 || st.targetBytes <= st.fsBytes) {
// A ramdisk root, a volume that cannot grow, or a card no larger than
// the image: nothing to do, now or on any later boot.
log_line(rc < 0 ? "system volume cannot grow" : "system volume already fills the card");
retire();
montauk::exit(0);
}
Screen* s = (Screen*)montauk::malloc(sizeof(Screen));
montauk::memset(s, 0, sizeof(Screen));
new (&s->fb) Framebuffer();
s->w = s->fb.width();
s->h = s->fb.height();
fonts::init();
s->theme = mtk::make_theme();
if (s->fb.pitch() != s->w * (int)sizeof(uint32_t)) {
s->compose = (uint32_t*)montauk::alloc((uint64_t)s->w * s->h * sizeof(uint32_t));
}
const char* heading = "Setting up your SD card";
char from[24], to[24], detail[96], msg[160];
format_size(from, sizeof(from), st.fsBytes);
format_size(to, sizeof(to), st.targetBytes);
snprintf(detail, sizeof(detail), "Growing from %s to %s", from, to);
snprintf(msg, sizeof(msg), "growing system volume from %s to %s", from, to);
log_line(msg);
draw(s, heading, "Expanding the system volume to fill the card...", detail, 0, 1);
// Each call writes a few MB of new filesystem metadata, then returns so
// the screen can update; the final call commits the new size.
do {
rc = montauk::fs_grow(SYSTEM_DRIVE, &st, true);
if (rc < 0) break;
bool committing = st.stepsDone + 1 >= st.stepsTotal;
draw(s, heading,
rc == 0 ? "Done." : committing ? "Finishing up..."
: "Expanding the system volume to fill the card...",
detail, (int)st.stepsDone, (int)st.stepsTotal);
} while (rc == 1);
if (rc < 0) {
snprintf(msg, sizeof(msg), "grow failed (status %d), will retry next boot", rc);
log_line(msg);
draw(s, heading, "The system volume could not be expanded.",
"MontaukOS will try again on the next boot.", 0, 0);
montauk::sleep_ms(ERROR_VISIBLE_MS);
montauk::exit(1);
}
format_size(to, sizeof(to), st.fsBytes);
snprintf(detail, sizeof(detail), "The system volume now holds %s.", to);
snprintf(msg, sizeof(msg), "system volume grown to %s", to);
log_line(msg);
draw(s, heading, "Done.", detail, 1, 1);
montauk::sleep_ms(DONE_VISIBLE_MS);
retire();
montauk::exit(0);
}
+8 -2
View File
@@ -57,7 +57,13 @@ struct Elf64Sym {
static constexpr uint16_t ET_EXEC = 2;
static constexpr uint16_t ET_DYN = 3;
static constexpr uint16_t EM_X86_64 = 62;
#if defined(__x86_64__)
static constexpr uint16_t kElfMachine = 62; // EM_X86_64
#elif defined(__aarch64__)
static constexpr uint16_t kElfMachine = 183; // EM_AARCH64
#else
#error "libloader: unsupported architecture"
#endif
static constexpr uint32_t SHT_SYMTAB = 2;
static constexpr uint32_t SHT_STRTAB = 3;
static constexpr uint32_t SHT_DYNSYM = 11;
@@ -102,7 +108,7 @@ static bool isValidElf(const Elf64Header* hdr, uint64_t size) {
return false;
}
if (hdr->e_ident[4] != 2 || hdr->e_ident[5] != 1) return false;
if (hdr->e_machine != EM_X86_64) return false;
if (hdr->e_machine != kElfMachine) return false;
if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) return false;
if (hdr->e_shentsize != sizeof(Elf64SectionHeader)) return false;
if (hdr->e_shoff == 0 || hdr->e_shnum == 0) return false;
+1 -1
View File
@@ -124,7 +124,7 @@ void draw_login_screen(LoginState* ls) {
Canvas c(target, sw, sh);
// ==== Background ====
if (ls->has_wallpaper && ls->bg_wallpaper) {
if (__atomic_load_n(&ls->has_wallpaper, __ATOMIC_ACQUIRE) && ls->bg_wallpaper) {
montauk::memcpy(target, ls->bg_wallpaper,
(uint64_t)sw * sh * sizeof(uint32_t));
} else {
+1 -1
View File
@@ -67,7 +67,7 @@ void draw_shutdown_screen(LoginState* ls, const char* heading, const char* statu
Rect titlebar = {card_x, card_y, CARD_W, TITLEBAR_H};
// ==== Background ====
if (ls->has_wallpaper && ls->bg_wallpaper) {
if (__atomic_load_n(&ls->has_wallpaper, __ATOMIC_ACQUIRE) && ls->bg_wallpaper) {
montauk::memcpy(target, ls->bg_wallpaper,
(uint64_t)sw * sh * sizeof(uint32_t));
} else {
+3 -1
View File
@@ -261,6 +261,8 @@ bool load_login_wallpaper(LoginState* ls) {
ls->bg_wallpaper = (uint32_t*)(blob + sizeof(CacheHeader));
ls->bg_wallpaper_w = ls->screen_w;
ls->bg_wallpaper_h = ls->screen_h;
ls->has_wallpaper = true;
// Runs on the wallpaper worker (main.cpp) while the screen is drawn from
// the main thread: publish the pixels only once they are complete.
__atomic_store_n(&ls->has_wallpaper, true, __ATOMIC_RELEASE);
return true;
}
+27 -7
View File
@@ -5,9 +5,23 @@
*/
#include "login.hpp"
#include <montauk/thread.h>
inline void* operator new(unsigned long, void* p) { return p; }
// The wallpaper loads on a worker thread: reading and decoding it (and, the
// first time, writing its cache) takes seconds from an SD card, and the login
// card must take input meanwhile. Set once the worker has finished.
static volatile bool g_wallpaper_done = false;
static constexpr uint64_t WALLPAPER_STACK_BYTES = 256 * 1024; // JPEG decode
static constexpr uint64_t WALLPAPER_POLL_MS = 50;
static int wallpaper_worker(void* arg) {
load_login_wallpaper((LoginState*)arg);
__atomic_store_n(&g_wallpaper_done, true, __ATOMIC_RELEASE);
return 0;
}
static void maybe_run_setup_session() {
auto doc = montauk::config::load("setup");
const char* mode = doc.get_string("environment.mode", "");
@@ -82,15 +96,15 @@ extern "C" void _start() {
maybe_run_setup_session();
initialize_login_mode(ls);
// Put the login card on screen before touching the wallpaper. Decoding a
// multi-megapixel JPEG takes long enough to read as a hang if nothing has
// been painted yet; drawn first, it lands as a background appearing behind
// a screen the user can already type into. The loop below redraws with the
// wallpaper because first_frame is still set.
// Put the login card on screen, then load the wallpaper behind it; the
// loop redraws once the worker is done.
draw_login_screen(ls);
load_login_wallpaper(ls);
if (montauk::thread_spawn(wallpaper_worker, ls, WALLPAPER_STACK_BYTES) < 0) {
wallpaper_worker(ls);
}
bool first_frame = true;
bool wallpaper_drawn = false;
uint64_t input_serial = montauk::input_wait(0, 0);
for (;;) {
bool mouse_changed = false;
@@ -117,13 +131,19 @@ extern "C" void _start() {
if (mouse_changed) handle_mouse(ls);
if (first_frame || mouse_changed || key_changed) {
bool wallpaper_ready = !wallpaper_drawn &&
__atomic_load_n(&g_wallpaper_done, __ATOMIC_ACQUIRE);
if (first_frame || mouse_changed || key_changed || wallpaper_ready) {
draw_login_screen(ls);
first_frame = false;
if (wallpaper_ready) wallpaper_drawn = true;
}
uint64_t wait_ms = fast_mouse_path ? 1
: ((mouse_changed || key_changed) ? 4 : UINT64_MAX);
// input_wait only wakes for input; look for the wallpaper meanwhile.
if (!wallpaper_drawn && wait_ms > WALLPAPER_POLL_MS) wait_ms = WALLPAPER_POLL_MS;
input_serial = montauk::input_wait(input_serial, wait_ms);
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ LOADER_LIB := $(PROGRAMS)/lib/libloader
LIBC_LIB := $(PROGRAMS)/lib/libc
PROG_INC := $(PROGRAMS)/include
LINK_LD := $(PROGRAMS)/link.ld
BINDIR := $(PROGRAMS)/bin
BINDIR := $(PROGRAMS)/bin$(ARCH_SUFFIX)
OBJDIR := obj$(ARCH_SUFFIX)
# ---- Compiler flags ----