Skip to content
an abstraction layer across user-space Linux, baremetal, and RTOS environments
C CMake C++ Objective-C
Branch: master
Clone or download
edmooring Merge pull request #104 from xiaoxiang781216/nuttx
nuttx: correctly handle the hardware which hasn't the interrupt controller

Signed-off-by: Ed Mooring <>
Latest commit 77b648f Nov 18, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
cmake cmake: Only look for doxygen package if docs enabled May 26, 2018
examples examples: fixed include to make libmetal compile with TCLIBC=musl Jun 30, 2019
test zynqmp_r5: Update required xilinx libraries Mar 7, 2019
.gitignore gitignore: Update to ignore vim temp files Mar 22, 2018
.travis.yml ci: install cmake 3.13.1 for Zephyr build Mar 7, 2019
CMakeLists.txt Correct the name of the Xilinx supported platform May 19, 2016 README: Correct Zephyr typo Mar 30, 2018



Libmetal provides common user APIs to access devices, handle device interrupts and request memory across the following operating environments:

  • Linux user space (based on UIO and VFIO support in the kernel)
  • RTOS (with and without virtual memory)
  • Bare-metal environments

Build Steps

Building for Linux Host

 $ git clone
 $ mkdir -p libmetal/<build directory>
 $ cd libmetal/<build directory>
 $ cmake ..
 $ make VERBOSE=1 DESTDIR=<libmetal install location> install

Cross Compiling for Linux Target

Use meta-openamp to build libmetal library. Use package libmetal in your yocto config file.

Building for Baremetal

To build on baremetal, you will need to provide a toolchain file. Here is an example toolchain file:

    set (CMAKE_SYSTEM_PROCESSOR "arm"              CACHE STRING "")
    set (MACHINE "zynqmp_r5" CACHE STRING "")

    set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
    set (CMAKE_C_FLAGS          "-mfloat-abi=soft -mcpu=cortex-r5 -Wall -Werror -Wextra \
       -flto -Os -I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" CACHE STRING "")

    SET(CMAKE_AR  "gcc-ar" CACHE STRING "")

    include (cross-generic-gcc)
  • Note: other toolchain files can be found in the cmake/platforms/ directory.
  • Compile with your toolchain file.
    $ mkdir -p build-libmetal
    $ cd build-libmetal
    $ cmake <libmetal_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
    $ make VERBOSE=1 DESTDIR=<libmetal_install> install

Building for Zephyr

As Zephyr uses CMake, we build libmetal library and test application as targets of Zephyr CMake project. Here is how to build libmetal for Zephyr:

    $ export ZEPHYR_GCC_VARIANT=zephyr
    $ export ZEPHYR_SDK_INSTALL_DIR=<where Zephyr SDK is installed>
    $ source <git_clone_zephyr_project_source_root>/

    $ cmake <libmetal_source_root> -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \
    $ make VERBOSE=1 all
    # If we have turned on tests with "-DWITH_TESTS=on" when we run cmake,
    # we launch libmetal test on Zephyr QEMU platform as follows:
    $ make VERBOSE=1 run


The following subsections give an overview of interfaces provided by libmetal.

Platform and OS Independent Utilities

These interfaces do not need to be ported across to new operating systems.


The libmetal I/O region abstraction provides access to memory mapped I/O and shared memory regions. This includes:

  • primitives to read and write memory with ordering constraints, and
  • ability to translate between physical and virtual addressing on systems that support virtual memory.


The libmetal logging interface is used to plug log messages generated by libmetal into application specific logging mechanisms (e.g. syslog). This also provides basic message prioritization and filtering mechanisms.


This is a simple doubly linked list implementation used internally within libmetal, and also available for application use.

Other Utilities

The following utilities are provided in lib/utilities.h:

  • Min/max, round up/down, etc.
  • Bitmap operations
  • Helper to compute container structure pointers
  • ... and more ...


The libmetal version interface allows user to get the version of the library.

Top Level Interfaces

The users will need to call two top level interfaces to use libmetal APIs:

  • metal_init - initialize the libmetal resource
  • metal_finish - release libmetal resource

Each system needs to have their own implementation inside libmetal for these two APIs to call:

  • metal_sys_init
  • metal_sys_finish

For the current release, libmetal provides Linux userspace and bare-metal implementation for metal_sys_init and metal_sys_finish.

For Linux userspace, metal_sys_init sets up a table for available shared pages, checks whether UIO/VFIO drivers are avail, and starts interrupt handling thread.

For bare-metal, metal_sys_init and metal_sys_finish just returns.


The libmetal atomic operations API is consistent with the C11/C++11 stdatomics interface. The stdatomics interface is commonly provided by recent toolchains including GCC and LLVM/Clang. When porting to a different toolchain, it may be necessary to provide an stdatomic compatible implementation if the toolchain does not already provide one.


libmetal provides memory allocation and release APIs.


libmetal provides the following locking APIs.


libmetal has a generic mutex implementation which is a busy wait. It is recommended to have OS specific implementation for mutex.

The Linux userspace mutex implementation uses futex to wait for the lock and wakeup a waiter.

Condition Variable

libmetal condition variable APIs provide "wait" for user applications to wait on some condition to be met, and "signal" to indicate a particular even occurs.


libmetal spinlock APIs provides busy waiting mechanism to acquire a lock.


libmetal has a generic static shared memory implementation. If your OS has a global shared memory allocation, you will need to port it for the OS.

The Linux userspace shmem implementation uses libhugetlbfs to support huge page sizes.

Bus and Device Abstraction

libmetal has a static generic implementation. If your OS has a driver model implementation, you will need to port it for the OS.

The Linux userspace abstraction binds the devices to UIO or VFIO driver. The user applications specify which device to use, e.g. bus "platform" bus, device "f8000000.slcr", and then the abstraction will check if platform UIO driver or platform VFIO driver is there. If platform VFIO driver exists, it will bind the device to the platform VFIO driver, otherwise, if UIO driver exists, it will bind the device to the platform UIO driver.

The VFIO support is not yet implemented.


libmetal provides APIs to register an interrupt, disable interrupts and restore interrupts.

The Linux userspace implementation will use a thread to call select() function to listen to the file descriptors of the devices to see if there is an interrupt triggered. If there is an interrupt triggered, it will call the interrupt handler registered by the user application.


libmetal provides APIs to flush and invalidate caches.

The cache APIs for Linux userspace are empty functions for now as cache operations system calls are not avaiable for all architectures.


libmetal DMA APIs provide DMA map and unmap implementation.

After calling DMA map, the DMA device will own the memory. After calling DMA unmap, the cpu will own the memory.

For Linux userspace, it only supports to use UIO device memory as DMA memory for this release.


libmetal time APIs provide getting timestamp implementation.


libmetal sleep APIs provide getting delay execution implementation.


This API is for compiler dependent functions. For this release, there is only a GCC implementation, and compiler specific code is limited to atomic operations.

You can’t perform that action at this time.