Skip to content

fels 0.14.0

Latest

Choose a tag to compare

@github-actions github-actions released this 07 Nov 13:20
· 8 commits to main since this release

Fels runs without an operating system: --target uefi makes a UEFI application and
--target freestanding an ELF for a kernel, on x86-64 and now on 64-bit ARM too, with
interrupt handlers as plain functions and a heap a kernel can hand memory to. Programs can carry
debug info (-g), so a debugger shows their source lines, parameters and locals. And a few
fixes: a println in a long loop no longer runs out of stack, and in the editor a module's
function completes as the whole call.

Added

  • Debug info: -g (and fels build -g for a project) gives a program the source lines,
    functions, parameters and locals with their types that a debugger shows: a PDB beside a
    Windows program, DWARF in a Linux one. On Windows the program is then linked by LLD, which
    needs the Windows SDK's import libraries.
  • UEFI applications: --target uefi (or a.target(.uefi) in build.fels) makes name.efi,
    which the firmware starts with no operating system. println goes to the firmware's console,
    zones take the firmware's pages, and std.uefi has the system table, stall, keys, clear,
    the framebuffer, shutdown and reboot. examples/uefi draws on the screen and turns off.
  • Freestanding programs: --target freestanding (or .freestanding) makes a static ELF
    with no operating system, for a kernel. A _start calls main and halts, or the program's
    own #entry is the start; no function uses the red zone; zones take a static heap, and
    std.freestanding.set_output names where println writes. examples/kernel boots in QEMU
    as a multiboot kernel and prints on the screen and the serial port.
  • std.x86: port I/O, cli/sti/hlt, lgdt/lidt, the control registers, MSRs,
    rdtsc and cpuid.
  • --link-arg <flag> passes a flag to the linker as it is, such as a linker script.
  • Interrupt handlers as functions: #interrupt makes an x86-64 function the CPU calls with
    the frame it pushed (*const x86::InterruptFrame) and, for some exceptions, an error code; it
    saves every register it uses and returns with iretq. x86::Idt holds them
    (set(vector, core::fn_ptr(f)), load()). Code can't call one.
  • 64-bit ARM without an operating system: --target aarch64-uefi and
    --target aarch64-freestanding (or a.arch(.aarch64) in build.fels). std.aarch64 has the
    barriers, the system registers and exception vectors that call an ordinary function with the
    saved registers. examples/kernel_aarch64 boots on QEMU's virt machine.
  • Memory for a kernel: std.freestanding.add_memory(base, len) gives zones more memory and
    free_memory() says how much is left. Zones give their memory back when they end.

Changed

  • A freestanding program without an #entry of its own starts where its linker script's
    ENTRY says, or at _start; the linker was told _start and ignored the script.
  • #extern("kernel32.dll", …) built, but the program then did not start: Windows looked
    for kernel32.dll.dll. A library name with .dll is now an error that shows the name
    without it.

Fixed

  • #section, #weak, #cold, #keep and #link_name were dropped from a function in every
    native build: the passes that run before code generation rebuilt it without them.
  • A function named where an extern fn goes (set_output(serial_write)) was passed as a
    closure, so the callee called the wrong address. It is now the function's own address.
  • A core::asm template written as a """ block reached the assembler with its escapes and
    quotes as written; it is now the block's lines.
  • A println("{x}") in a loop crashed with a stack overflow (exit code 0xC00000FD) after tens
    of thousands of passes: each pass took more stack for the values in the braces and never gave
    it back. A format's values now have one place on the stack, which every pass reuses.
  • In the editor, a module's function after io:: (or any alias::) completed as its name only.
    It now completes as the call, with a tab stop per argument, and shows its parameters and its
    documentation, as a function in scope does.