Skip to content

Instantly share code, notes, and snippets.

@willnode
Last active May 26, 2025 06:02
Show Gist options
  • Save willnode/a31a1265d955dbb914001aba8a576ad2 to your computer and use it in GitHub Desktop.
Save willnode/a31a1265d955dbb914001aba8a576ad2 to your computer and use it in GitHub Desktop.
Build Redox for Aarch64 OS Guide

[WIP] Building Aarch64 Redox OS from Mac M1

Here's how you build Redox from Mac in May 2025. It's so much easier to do it now than in ancient days.

The only problem you may encounter is packaging the build, since it requires FUSE and it's requires patching Mac kernel, which I don't want. I (trying) develop a way to avoid it by using Podman only for that.

I run with UTM on QEMU virtualization. It works for me.

This notes is WIP, see https://gist.github.com/willnode/a31a1265d955dbb914001aba8a576ad2 for Redox OS native bootstrapping

TODO List:

  • Patch prefixes
  • Patch libredox
  • Patch relibc
  • Patch essential recipes

Clone & Install deps

Before you start, please install xcode and brew, then:

cd ~/Document
git clone https://gitlab.redox-os.org/redox-os/redox
cd redox
git submodule update --init --recursive
# Install necessary tooling except things that don't work
sed -i '' '/macfuse/d' ./native_bootstrap.sh
sed -i '' '/[email protected]/d' ./native_bootstrap.sh
sed -i '' '/x86_64-elf-gcc/d' ./native_bootstrap.sh
./native_bootstrap.sh -d
# Install additional things not listed
brew install help2man m4 # required by new libtool
brew install libiconv # required by binutils

Write this on .config:

PODMAN_BUILD=0
ARCH=aarch64
CONFIG_NAME=desktop

Then build the image with ./build.sh. At your first try it definitely gonna break so here's some patches you need to do...

Patches

Omit all build stripping

This is because it's can't be done after build, so just omit it.

sed -i '' 's/ && $(PREFIX_STRIP)//g' ./mk/prefix.mk

Skip fstools

In mk/fstools.mk, skip fstools installation, because it's linking to libc specifically written for linux, not mac.

$(HOST_FSTOOLS): installer redoxfs
+	echo "fstools Installation is skipped"
-	rm -rf $@ [email protected]
-	mkdir -p [email protected]
-	$(HOST_CARGO) install --root [email protected] --path installer --bin redox_installer
-	$(HOST_CARGO) install --root [email protected] --path redoxfs --bin redoxfs --bin redoxfs-mkfs
-	mv [email protected] $@
	touch $@

Force Use Prebuilt Prefix

TODO: (do not use this yet, need to provide prebuilt for m1)

In mk/config.mk, delete these conditionals because building them takes a looonggg time

-ifneq ($(HOST_TARGET),x86_64-unknown-linux-gnu)
-	# The binary prefix is only built for x86_64 Linux hosts
-	PREFIX_BINARY=0
-endif
...

-ifneq ($(UNAME),Linux)
-	PREFIX_BINARY=0
-endif
-ifneq ($(HOST_ARCH),x86_64)
-	PREFIX_BINARY=0
-endif

If you do this, you can skip patch binutils and cloning rust since it's no longer necessary.

Add libraries to $PATH

These library paths need to be added manually either in your terminal now or in ~/.zshrc:

export LIBRARY_PATH="/opt/homebrew/opt/isl/lib:/opt/homebrew/opt/gmp/lib:/opt/homebrew/opt/mpfr/lib:/opt/homebrew/opt/libiconv/lib:$LIBRARY_PATH"
export C_INCLUDE_PATH="/opt/homebrew/opt/isl/include:/opt/homebrew/opt/gmp/include:/opt/homebrew/opt/mpfr/include:/opt/homebrew/opt/libiconv/include:$C_INCLUDE_PATH"
export CPLUS_INCLUDE_PATH="/opt/homebrew/opt/isl/include:/opt/homebrew/opt/gmp/include:/opt/homebrew/opt/mpfr/include:/opt/homebrew/opt/libiconv/include:$CPLUS_INCLUDE_PATH"

# TODO: explanations
export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:/opt/homebrew/opt/findutils/libexec/gnubin:/opt/homebrew/opt/gnu-sed/libexec/gnubin:/opt/homebrew/opt/m4/bin/:$PATH"
ln -s /opt/homebrew/opt/m4/bin/m4 /opt/homebrew/opt/m4/bin/gm4

Patch Binutils & GCC to work with Clang 17

Note: Check with clang -v, if your Clang <17, you don't need this.

Issue: iains/gcc-14-branch#21 Fix: https://github.com/madler/zlib/commit/4bd9a71f3539b5ce47f0c67ab5e01f3196dc8ef9 File: prefix/aarch64-unknown-redox/binutils/zlib/zutil.h and prefix/aarch64-unknown-redox/gcc/zlib/zutil.h

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  7
-#  ifndef Z_SOLO
-#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
-#      include <unix.h> /* for fdopen */
-#    else
-#      ifndef fdopen
-#        define fdopen(fd,mode) NULL /* No fdopen() */
-#      endif
-#    endif
-#  endif
#endif

Patch: https://patchwork.sourceware.org/project/gdb/patch/[email protected]/ File: prefix/aarch64-unknown-redox/binutils/gdb/remote-sim.c

-[[noreturn]] static void gdb_os_error (host_callback *, const char *, ...);
+static void gdb_os_error(host_callback *, const char *, ...)
+  ATTRIBUTE_NORETURN;

Issue: https://github.com/orgs/Homebrew/discussions/5273 Patch: https://gcc.gnu.org/git/?p=gcc.git;a=blobdiff;f=gcc/system.h;h=03ab33ac960fd1681a6cc26d05e2ec498c12c733;hp=33e9d421115005dfefed2123bb0136ee6e4b971c;hb=68057560ff1fc0fb2df38c2f9627a20c9a8da5c5;hpb=47ebdbe5bf71d9eb260359b6aceb5cb071d97acd File: prefix/aarch64-unknown-redox/gcc/gcc/system.h

 
-/* Include <string> before "safe-ctype.h" to avoid GCC poisoning
-   the ctype macros through safe-ctype.h */
-
-#ifdef __cplusplus
-#ifdef INCLUDE_STRING
-# include <string>
-#endif
-#endif
-
-/* There are an extraordinary number of issues with <ctype.h>.
-   The last straw is that it varies with the locale.  Use libiberty's
-   replacement instead.  */
-#include "safe-ctype.h"
-
-#include <sys/types.h>
-
-#include <errno.h>
-
-#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO
-extern int errno;
-#endif
+/* Include C++ standard headers before "safe-ctype.h" to avoid GCC
+   poisoning the ctype macros through safe-ctype.h */
 
 #ifdef __cplusplus
 #if defined (INCLUDE_ALGORITHM) || !defined (HAVE_SWAP_IN_UTILITY)
@@ -229,6 +210,9 @@ extern int errno;
 #ifdef INCLUDE_SET
 # include <set>
 #endif
+#ifdef INCLUDE_STRING
+# include <string>
+#endif
 #ifdef INCLUDE_VECTOR
 # include <vector>
 #endif
@@ -245,6 +229,19 @@ extern int errno;
 # include <type_traits>
 #endif
 
+/* There are an extraordinary number of issues with <ctype.h>.
+   The last straw is that it varies with the locale.  Use libiberty's
+   replacement instead.  */
+#include "safe-ctype.h"
+
+#include <sys/types.h>
+
+#include <errno.h>
+
+#if !defined (errno) && defined (HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO
+extern int errno;
+#endif
+
 /* Some of glibc's string inlines cause warnings.  Plus we'd rather
    rely on (and therefore test) GCC's string builtins.  */
 #define __NO_STRING_INLINES

--- section below is not updated yet ---

Installing

I assume you're running from fresh Ubuntu aarch64.

sudo apt-get install cbindgen just make build-essential nasm pkg-config fuse3 libfuse3-dev libmpc-dev \
    texinfo bison flex cmake ninja-build autoconf autopoint libtool po4a doxygen gperf

Or if you dare directly running it on Mac.

brew install coreutils binutils findutils gnu-sed osxfuse cbindgen just make nasm pkg-config libmpc \
    mpfr gmp texinfo bison flex cmake ninja autoconf automake libtool libicinv po4a doxygen gperf

Then:

export LIBRARY_PATH=/opt/homebrew/Cellar/gmp/6.3.0/lib:/opt/homebrew/Cellar/mpfr/4.2.1/lib:/opt/homebrew/opt/libiconv/lib
export C_INCLUDE_PATH=/opt/homebrew/Cellar/gmp/6.3.0/include:/opt/homebrew/Cellar/mpfr/4.2.1/include:/opt/homebrew/opt/libiconv/include
export CPLUS_INCLUDE_PATH=/opt/homebrew/Cellar/gmp/6.3.0/include:/opt/homebrew/Cellar/mpfr/4.2.1/include:/opt/homebrew/opt/libiconv/include
export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:/opt/homebrew/opt/findutils/libexec/gnubin:/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"

Patches

I recommend patch the rust (see bootloader section) before compiling anything.

When recompiling GCC or Rust, don't forget to delete relevant builds in /prefix.

GCC compile configure

mk/prefix.mk:

	"$(ROOT)/$</configure" \
		--target="$(TARGET)" \
		--program-prefix="$(TARGET)-" \
		--prefix="" \
		--with-sysroot \
		--with-build-sysroot="$(ROOT)/$(PREFIX)/relibc-freestanding-install/$(TARGET)" \
		--with-native-system-header-dir="/include" \
+		--without-long-double-128 \
		--disable-multilib \
		--disable-nls \
		--disable-werror \
		--enable-languages=c,c++ \
		--enable-shared \
		--enable-threads=posix \

gettext with include libunistring && patch atomic

Need to patch all the long double to double. I have this change implemented for gettext and nano. Reference: https://stackoverflow.com/a/49123064/3908409

cd cookbook/recipes/tools/gettext/source
grep -Rl 'long double' * | xargs -tn1 sed -i -e 's/long double/double/g'
grep -Rl 'SIZEOF_LDBL <= sizeof (double)' * | xargs -tn1 sed -i -e 's/SIZEOF_LDBL <= sizeof (double)/SIZEOF_LDBL <= sizeof (long double)/g'

cookbook/recipes/tools/gettext/recipe.toml

script = """
COOKBOOK_CONFIGURE_FLAGS+=(
+   --disable-glib
    --disable-shared
+   --disable-java
+   --disable-csharp
    --enable-static
+   --with-included-libunistring
    ac_cv_have_decl_program_invocation_name=no
    gt_cv_locale_fr=false
    gt_cv_locale_fr_utf8=false
    gt_cv_locale_ja=false
    gt_cv_locale_tr_utf8=false
    gt_cv_locale_zh_CN=false
)
cookbook_configure
"""

PS: Not sure if anything else except --with-included-libunistring is necessary.

cookbook/recipes/tools/gettext/source/gettext-tools/gnulib-lib/asyncsafe-spin.c

#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) \
       || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) \
-     && !defined __ibmxl__
+     && !defined __ibmxl__ && !defined __redox__
/* Use GCC built-ins (available in GCC >= 4.7 and clang >= 3.1) that operate on
   the first byte of the lock.
   Documentation:
   <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html>
 */
#  elif (((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) \
          && !defined __sparc__) \
         || __clang_major__ >= 3) \
-       && !defined __ibmxl__
+       && !defined __ibmxl__ && !defined __redox__
/* Use GCC built-ins (available in GCC >= 4.1, except on SPARC, and
   clang >= 3.0).
   Documentation:
   <https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html>  */
  • cookbook/recipes/tools/gettext/source/gettext-tools/gnulib-lib/math.in.h
  • cookbook/recipes/tools/gettext/source/libtextstyle/lib/math.in.h
#if @GNULIB_FREXP@
# if @REPLACE_FREXP@
-#  if !(defined __cplusplus&& defined GNULIB_NAMESPACE)
+#  if !(defined __cplusplus && defined __redox__ && defined GNULIB_NAMESPACE)
#   undef frexp
#   define frexp rpl_frexp
#  endif

bash have long double set no

cookbook/recipes/shells/bash/source/configure

  if test "$GCC" = yes; then
-      ac_cv_type_long_double=yes
+      ac_cv_type_long_double=no
     else

openssl add platform and disable asm and patch sigjmp

cookbook/recipes/libs/openssl1/recipe.toml

COOKBOOK_CONFIGURE_FLAGS=(
    no-shared
    no-dgram
+   no-asm
    "redox-${ARCH}"
    --prefix="/"
)

cookbook/recipes/libs/openssl1/source/Configurations/10-main.conf

    "redox-x86_64" => {
        inherit_from     => [ "BASE_common", asm("x86_64_asm") ],
        cc               => "gcc",
        cflags           => "-DL_ENDIAN -DOSSL_SSIZE_MAX=LONG_MAX -DNO_SYSLOG -O3 -static -Wall",
        bn_ops           => "SIXTY_FOUR_BIT_LONG",
        thread_scheme    => "(unknown)",
    },
+   "redox-aarch64" => {
+       inherit_from     => [ "linux-generic64", asm("aarch64_asm") ],
+       cc               => "gcc",
+       cflags           => "-DL_ENDIAN -DOSSL_SSIZE_MAX=LONG_MAX -DNO_SYSLOG -O3 -static -Wall",
+       bn_ops           => "SIXTY_FOUR_BIT_LONG",
+       thread_scheme    => "(unknown)",
+       perlasm_scheme   => "void",
+   },

cookbook/recipes/libs/openssl1/source/crypto/armcap.c

#else

+/* Some platforms don't have the sigjmp_buf type in <setjmp.h>.  */
+#if defined _MSC_VER || defined __MINGW32__ || defined(__redox__)
+/* Native Woe32 API.  */
+# define sigjmp_buf jmp_buf
+# define sigsetjmp(env,savesigs) setjmp (env)
+# define siglongjmp longjmp
+#endif

static sigset_t all_masked;

patch ring (installer + pkgutils + installer-gui)

Apply https://gitlab.redox-os.org/willnode/ring/-/commit/5d895ab1e

  • cookbook/recipes/core/installer/source/Cargo.toml
  • cookbook/recipes/core/pkgutils/source/Cargo.toml
  • cookbook/recipes/gui/installer-gui/source/Cargo.toml
[patch.crates-io]
-ring = { git = "https://gitlab.redox-os.org/redox-os/ring.git", branch = "redox-unix-0.13.5" }
+ring = { git = "https://gitlab.redox-os.org/willnode/ring.git", branch = "redox-unix-0.13.5" }

fix git build unknown endianness

cookbook/recipes/tools/git/source/compat/bswap.h

# if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
#  define GIT_BYTE_ORDER GIT_BIG_ENDIAN
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
#  define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
# elif defined(__THW_BIG_ENDIAN__) && !defined(__THW_LITTLE_ENDIAN__)
#  define GIT_BYTE_ORDER GIT_BIG_ENDIAN
# elif defined(__THW_LITTLE_ENDIAN__) && !defined(__THW_BIG_ENDIAN__)
#  define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
# else
-#  error "Cannot determine endianness"
+#  define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
# endif

fix std1 build hint

cookbook/recipes/backends/sdl1/recipe.toml

script = """
COOKBOOK_CONFIGURE_FLAGS+=(
+   --build=aarch64-unknown-linux-gnu
+   --host=aarch64-unknown-redox
    --disable-loadso
    --disable-pthread-sem
    --disable-pulseaudio
    --disable-video-x11
    --enable-clock_gettime
    --enable-redoxaudio
    --enable-video-orbital
)

unlock vesad in initfs (for unlocking display)

cookbook/recipes/core/drivers-initfs/recipe.toml

aarch64_redefine_bin()
{
-   BINS=(inputd lived)
    case "${BOARD}" in
        raspi3bp)
            BINS+=(bcm2835-sdhcid)
        ;;
        raspi3b)
            BINS+=(bcm2835-sdhcid)
        ;;
        *)
        #qemu-virt
        ;;
    esac
}

Add PCID driver (trying for virtio display)

cookbook/recipes/core/drivers/recipe.toml

# Add additional drivers to the list to build, that are not in drivers-initfs
# depending on the target architecture
case "${TARGET}" in
    i686-unknown-redox | x86_64-unknown-redox)
        BINS+=(ac97d bgad pcid pcspkrd sb16d vboxd)
        ;;
+   aarch64-unknown-redox)
+       BINS+=(pcid)
+       ;;
    *)
        ;;
esac

Add desktop profile to aarch64

config/aarch64/desktop.toml (new file)

# Default desktop configuration

include = ["../desktop.toml"]

# Override the default settings here

# General settings
[general]
# Filesystem size in MiB
# filesystem_size = 1024

# Package settings
[packages]
# example = {}

Switch QEMU EFI back to default

This make ramfb device available. But then you have apply my patch to get it working

mk/qemu.mk (please adjust qemu version)

else ifeq ($(ARCH),x86_64)
+	efi=yes
+	live=yes
	QEMU_ARCH=x86_64
	QEMU_MACHINE?=q35
-	QEMU_CPU?=core2duo
-	QEMU_EFI=/usr/share/OVMF/OVMF_CODE.fd
+	QEMU_CPU=qemu64
+	QEMU_EFI=/opt/homebrew/Cellar/qemu/8.2.1/share/qemu/edk2-x86_64-code.fd
	QEMUFLAGS+=-smp 4 -m 2048
else ifeq ($(ARCH),aarch64)
	efi=yes
	live=yes
	QEMU_ARCH=aarch64
	QEMU_MACHINE=virt
-	QEMU_CPU=max
-	ifeq ($(BOARD),raspi3bp)
-		QEMU_EFI=https://gitlab.redox-os.org/Ivan/redox_firmware/-/raw/main/platform/raspberry_pi/rpi3/u-boot-rpi-3-b-plus.bin
-	else
-		QEMU_EFI=https://gitlab.redox-os.org/Ivan/redox_firmware/-/raw/main/platform/qemu/qemu_arm64/u-boot-qemu-arm64.bin
-	endif
+	QEMU_CPU=cortex-a72
+	QEMU_EFI=/opt/homebrew/Cellar/qemu/8.2.1/share/qemu/edk2-aarch64-code.fd
	QEMUFLAGS+=-smp 1 -m 2048
	ifneq ($(vga),no)
...
ifeq ($(efi),yes)
	FIRMWARE=$(BUILD)/firmware.rom
-	QEMUFLAGS+=-bios $(BUILD)/firmware.rom
+	QEMUFLAGS+= -drive if=pflash,format=raw,unit=0,file=$(FIRMWARE),readonly=on   
else
...

$(BUILD)/firmware.rom:
- ifeq ($(ARCH),aarch64)
-	wget -O $@ $(QEMU_EFI)
- else
	cp $(QEMU_EFI) $@
- endif

Current state of the work

Should have the disk image now and it's bootable and able to display though can't interact because ACPI drivers is yet supported.

Currently likely stuck here forever because at this time Redox has no BIOS in aarch64 for easy framebuffer access, or an ACPI support for aarch64 to get access for virtio display.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment