Targeting a bare-metal environment


Could someone tell me what aspects of the Crystal toolchain and libraries need to be extended or changed to target a bare metal environment for an existing LLVM supported processor architecture ?

I’m interested in targeting a bare metal Arm AArch64 environment. The aim is to incrementally explore the possible use of Crystal for firmware development as a first step.

The underlying assumptions are that so long as Crystal’s run-time requirements can be met for the bare-metal environment (things like memory allocators, GC aspects, signal/exception handling etc perhaps) and the application or use-case isn’t susceptible to the potential time determinism issues around the use of a GC etc, then the expressiveness of Crystal and it’s type-safety et al can be attractive for systems development.

Any thoughts appreciated.

At present I’m studying Lilith which I think would have had to address similar things.


1 Like

Hi again.

Here are some things that I’ve learnt that I’d like to share in case they help someone, along with some additional questions that I have. Would appreciate any insights.

  1. Some of the bare-metal crystal experiments I’ve seen so far are:

  2. The Lilith strategy (which Stakach re-uses) is to use a modified compiler + custom allocator + custom conservative mark and sweep garbage collector + custom prelude. The allocator and the GC are a part of the OS kernel which IIUC links against the compiler library.

    • Some compiler modifications are to do with introducing a Markable class which dynamic types (such as Array and Hash) are made to inherit from. This class introduces scaffolding that helps the custom GC do its marking action.

    • Other compiler modifications are to do with making certain symbols accessible by the OS kernel (such as where the globals reside) which are then used by the custom GC.

    • And then there’s the custom prelude which re-implements most of the language primitives.

    • Question: What I don’t get is why should there be a custom prelude ? Why can’t the compiler’s ‘built-in’ prelude (crystal/src/ be used as-is especially since the allocator and GC are being used from outside the compiler ? Also: Why the need to have explicit Markability ? Doesn’t the built-in Boehm GC have all of that when working with the crystal compiler already ?

  3. At present, my thinking is that a good solution to make Crystal usable for bare-metal targets would be:

    • Look for target “rich” run-time environment specific code or assumptions in the compiler and its supplied libs (Linux/Windows et al). Where applicable, find clean ways of making such code conditionally re-targetable to a bare-metal environment. The GNU target triple would be $ARCH-unknown-none. The code I am alluding to is anything that relies on OS kernel specific facilities (threads, processes, synchronisation primitives, signals, filesystem nuances et al). For such code, a reasonable set of assumptions can be made with regard to the bare-metal environment. Initially one can stub out complex bits in favour of a single threaded non-preemptive environment. Then more complexity can be added incrementally culminating in bridging to an RTOS etc.

    • Look for similar bits in the compiler supplied prelude. Try to define clean interfaces that make it possible to use as much of the prelude as possible by a bare-metal environment.

    • Do the same for any allocator and GC specific code and make it possible to conditionally link to a bare-metal environment specified GC and allocator combination. Basically analyse what Lilith has done and see if interfaces can be implemented that make linkage with a more general bare-metal environment as clean as possible.

    • Use an emulated environment (qemu for Cortex-M class microcontrollers) as the basis for all of this with the ultimate aim of migrating to real silicon (probably Raspberry Pi Pico which is well supported by micropython today).

    • Question: Does the above sound like a reasonable route to enabling crystal use in bare-metal environments ?

I’ll continue studying and experimenting and I hope to share what I learn in the hope that I don’t veer to far off. Any thoughts welcome! Thanks.


Bare metal means no OS?

In this context, yes that’s what it means. Think micropython or mruby.

1 Like