ext: move libmetal to hal

libmetal itself isn't an ipc library, its a generic HAL abstraction
library so move it into ext/hal where it belongs.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This commit is contained in:
Kumar Gala 2018-05-23 09:36:43 -05:00 committed by Kumar Gala
commit d8fa951a6e
184 changed files with 12668 additions and 0 deletions

41
README Normal file
View File

@ -0,0 +1,41 @@
libmetal
#####################
Origin:
https://github.com/OpenAMP/libmetal
Status:
606c31438025b9fb1515dace1c642d5835d8d33c [v2018.04]
When we import libmetal we removed the tests/ and examples/ dir to reduce
the amount of code imported.
Purpose:
HAL abstraction layer used by open-amp
Description:
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
Dependencies:
Depends on Zephyr itself as it utilizes Zephyr's APIs to provide an
abstraction to open-amp.
URL:
https://github.com/OpenAMP/libmetal
commit:
606c31438025b9fb1515dace1c642d5835d8d33c
Maintained-by:
External
License:
BSD-3-Clause
License Link:
https://github.com/OpenAMP/libmetal/blob/master/LICENSE.md

12
libmetal.cmake Normal file
View File

@ -0,0 +1,12 @@
include(ExternalProject)
ExternalProject_Add(
libmetal # Name for custom target
SOURCE_DIR $ENV{ZEPHYR_BASE}/ext/hal/libmetal/libmetal/
INSTALL_COMMAND "" # This particular build system has no install command
CMAKE_ARGS -DWITH_ZEPHYR=ON -DBOARD=${BOARD} -DWITH_DEFAULT_LOGGER=OFF -DWITH_DOC=OFF
)
ExternalProject_Get_property(libmetal BINARY_DIR)
set(LIBMETAL_INCLUDE_DIR ${BINARY_DIR}/lib/include)
set(LIBMETAL_LIBRARY ${BINARY_DIR}/lib/libmetal.a)

18
libmetal/.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
*.o
*~
!libs/system/zc702evk/linux/lib/*/*.a
*.bin
*.map
*.out
*.log
*.swp
*.swo
*.d
build*/
/tags
/TAGS
# cscope files
cscope.*
ncscope.*

100
libmetal/.travis.yml Normal file
View File

@ -0,0 +1,100 @@
language: minimal # setting language to C will override cross-compiler and fail
compiler:
- gcc
sudo: required
dist: trusty
env:
global:
- ZEPHYR_GCC_VARIANT=zephyr
- ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk
- ZEPHYR_BASE=$TRAVIS_BUILD_DIR/deps/zephyr
- ZEPHYR_SDK_VERSION=0.9.2
- ZEPHYR_SDK_DOWNLOAD_FOLDER=https://github.com/zephyrproject-rtos/meta-zephyr-sdk/releases/download/$ZEPHYR_SDK_VERSION
- ZEPHYR_SDK_SETUP_BINARY=zephyr-sdk-$ZEPHYR_SDK_VERSION-setup.run
- ZEPHYR_SDK_DOWNLOAD_URL=$ZEPHYR_SDK_DOWNLOAD_FOLDER/$ZEPHYR_SDK_SETUP_BINARY
- FREERTOS_ZIP_URL=https://downloads.sourceforge.net/project/freertos/FreeRTOS/V10.0.1/FreeRTOSv10.0.1.zip
matrix:
fast_finish: true
include:
- os: linux
env: TARGET="zephyr"
- os: linux
env: TARGET="linux"
- os: linux
env: TARGET="generic"
- os: linux
env: TARGET="freertos"
cache:
directories:
- $ZEPHYR_SDK_INSTALL_DIR
- /usr/local/bin
before_install:
- if [[ "$TARGET" == "zephyr" ]]; then
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test &&
sudo apt-get update -qq &&
sudo apt-get install libc6-dev-i386 make gperf gcc g++ python3-ply python3-yaml python3-pip device-tree-compiler ncurses-dev uglifyjs -qq &&
sudo pip3 install pyelftools;
fi
- if [[ "$TARGET" == "linux" ]]; then
sudo apt-get update -qq &&
sudo apt-get install libsysfs-dev libhugetlbfs-dev make gcc;
fi
# This is to kick start CI on generic platform. Will need to have a proper way to get the required packages
- if [[ "$TARGET" == "generic" || "$TARGET" == "freertos" ]]; then
wget http://ppa.launchpad.net/team-gcc-arm-embedded/ppa/ubuntu/pool/main/g/gcc-arm-none-eabi/gcc-arm-embedded_7-2017q4-1~trusty3_amd64.deb &&
sudo dpkg -i gcc-arm-embedded_7-2017q4-1~trusty3_amd64.deb;
fi
- if [[ "$TARGET" == "freertos" ]]; then
wget $FREERTOS_ZIP_URL &&
pwd && ls &&
unzip FreeRTOSv10.0.1.zip > /dev/null;
fi
install: >
if [[ "$TARGET" == "zephyr" && "$(cat $ZEPHYR_SDK_INSTALL_DIR/sdk_version)" != "$ZEPHYR_SDK_VERSION" ]]; then
wget $ZEPHYR_SDK_DOWNLOAD_URL &&
chmod +x $ZEPHYR_SDK_SETUP_BINARY &&
rm -rf $ZEPHYR_SDK_INSTALL_DIR &&
./$ZEPHYR_SDK_SETUP_BINARY --quiet -- -y -d $ZEPHYR_SDK_INSTALL_DIR > /dev/null;
fi
before_script: >
if [[ "$TARGET" == "zephyr" ]]; then
cd .. &&
git clone --depth=1 https://github.com/zephyrproject-rtos/zephyr.git &&
cd zephyr &&
source zephyr-env.sh;
fi
script:
- if [[ "$TARGET" == "zephyr" ]]; then
mkdir -p ../libmetal/build-zephyr &&
cd ../libmetal/build-zephyr &&
cmake .. -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 -DWITH_TESTS=on &&
make VERBOSE=1;
fi
- if [[ "$TARGET" == "linux" ]]; then
mkdir -p build-linux &&
cd build-linux &&
cmake .. -DWITH_TESTS_EXEC=on &&
make VERBOSE=1 all test;
fi
- if [[ "$TARGET" == "generic" ]]; then
mkdir -p build-generic &&
cd build-generic &&
cmake .. -DCMAKE_TOOLCHAIN_FILE=template-generic &&
make VERBOSE=1;
fi
- if [[ "$TARGET" == "freertos" ]]; then
mkdir -p build-freertos &&
cd build-freertos &&
export &&
cmake .. -DCMAKE_TOOLCHAIN_FILE=template-freertos -DCMAKE_C_FLAGS="-I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Source/include/ -I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Demo/CORTEX_STM32F107_GCC_Rowley -I$PWD/../FreeRTOSv10.0.1/FreeRTOS/Source/portable/GCC/ARM_CM3" &&
make VERBOSE=1;
fi

37
libmetal/CMakeLists.txt Normal file
View File

@ -0,0 +1,37 @@
cmake_minimum_required (VERSION 2.6)
list (APPEND CMAKE_MODULE_PATH
"${CMAKE_SOURCE_DIR}/cmake"
"${CMAKE_SOURCE_DIR}/cmake/modules"
"${CMAKE_SOURCE_DIR}/cmake/platforms")
include (syscheck)
project (metal C)
include (CheckIncludeFiles)
include (CheckCSourceCompiles)
include (collect)
include (options)
include (depends)
foreach(_inc_path ${CMAKE_INCLUDE_PATH})
collect (PROJECT_INC_DIRS "${_inc_path}")
endforeach()
enable_testing ()
add_subdirectory (lib)
if (WITH_TESTS)
add_subdirectory (test)
endif (WITH_TESTS)
if (WITH_DOC)
add_subdirectory (doc)
endif (WITH_DOC)
if (WITH_EXAMPLES)
add_subdirectory (examples)
endif (WITH_EXAMPLES)
# vim: expandtab:ts=2:sw=2:smartindent

41
libmetal/LICENSE.md Normal file
View File

@ -0,0 +1,41 @@
Software License Agreement (BSD License)
========================================
Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of Xilinx nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Notes
=========================================
Use the following tag instead of the full license text in the individual files:
SPDX-License-Identifier: BSD-3-Clause
This enables machine processing of license information based on the SPDX
License Identifiers that are here available: http://spdx.org/licenses/

21
libmetal/MAINTAINERS.md Normal file
View File

@ -0,0 +1,21 @@
# libmetal Maintainers
libmetal project is maintained by the OpenAMP open source community.
Everyone is encouraged to submit issues and changes to improve libmetal.
The intention of this file is to provide a set of names that developers can
consult when they have a question about OpenAMP and to provide a a set of
names to be CC'd when submitting a patch.
## Project Administration
Wendy Liang <wendy.liang@xilinx.com>
### All patches CC here
open-amp@googlegroups.com
## Machines
### Xilinx Platform - Zynq-7000
Wendy Liang <wendy.liang@xilinx.com>
### Xilinx Platform - Zynq UltraScale+ MPSoC
Wendy Liang <wendy.liang@xilinx.com>

220
libmetal/README.md Normal file
View File

@ -0,0 +1,220 @@
# libmetal
## Overview
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 https://github.com/OpenAMP/libmetal.git
$ 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](https://github.com/openamp/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_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
SET(CMAKE_AR "gcc-ar" CACHE STRING "")
SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
SET(CMAKE_C_ARCHIVE_FINISH true)
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>/zephyr-env.sh
$ cmake <libmetal_source_root> -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \
[-DWITH_TESTS=on]
$ 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
```
## Interfaces
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.
#### I/O
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.
#### Log
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.
#### List
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 ...
#### Version
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.
### Atomics
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.
### Alloc
libmetal provides memory allocation and release APIs.
### Locking
libmetal provides the following locking APIs.
#### Mutex
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.
#### Spinlock
libmetal spinlock APIs provides busy waiting mechanism to acquire a lock.
### Shmem
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.
### Interrupt
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.
### Cache
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.
### DMA
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.
### Time
libmetal time APIs provide getting timestamp implementation.
### Sleep
libmetal sleep APIs provide getting delay execution implementation.
### Compiler
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.

View File

@ -0,0 +1,36 @@
function (collector_create name base)
set_property (GLOBAL PROPERTY "COLLECT_${name}_LIST")
set_property (GLOBAL PROPERTY "COLLECT_${name}_BASE" "${base}")
endfunction (collector_create)
function (collector_list var name)
get_property (_list GLOBAL PROPERTY "COLLECT_${name}_LIST")
set (${var} "${_list}" PARENT_SCOPE)
endfunction (collector_list)
function (collector_base var name)
get_property (_base GLOBAL PROPERTY "COLLECT_${name}_BASE")
set (${var} "${_base}" PARENT_SCOPE)
endfunction (collector_base)
function (collect name)
collector_base (_base ${name})
string(COMPARE NOTEQUAL "${_base}" "" _is_rel)
set (_list)
foreach (s IN LISTS ARGN)
if (_is_rel)
get_filename_component (s "${s}" ABSOLUTE)
file (RELATIVE_PATH s "${_base}" "${s}")
endif (_is_rel)
list (APPEND _list "${s}")
endforeach ()
set_property (GLOBAL APPEND PROPERTY "COLLECT_${name}_LIST" "${_list}")
endfunction (collect)
# Create global collectors
collector_create (PROJECT_INC_DIRS "")
collector_create (PROJECT_LIB_DIRS "")
collector_create (PROJECT_LIB_DEPS "")
collector_create (PROJECT_HDR_TESTS "")
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,36 @@
find_package (Doxygen)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
check_include_files (stdatomic.h HAVE_STDATOMIC_H)
check_include_files (linux/futex.h HAVE_FUTEX_H)
find_package (HugeTLBFS)
if (HUGETLBFS_FOUND)
collect (PROJECT_INC_DIRS "${HUGETLBFS_INCLUDE_DIR}")
collect (PROJECT_LIB_DEPS "${HUGETLBFS_LIBRARIES}")
add_definitions(-DHAVE_HUGETLBFS_H)
endif(HUGETLBFS_FOUND)
find_package (LibSysFS REQUIRED)
collect (PROJECT_INC_DIRS "${LIBSYSFS_INCLUDE_DIR}")
collect (PROJECT_LIB_DEPS "${LIBSYSFS_LIBRARIES}")
find_package(Threads REQUIRED)
collect (PROJECT_LIB_DEPS "${CMAKE_THREAD_LIBS_INIT}")
find_package(LibRt REQUIRED)
collect (PROJECT_LIB_DEPS "${LIBRT_LIBRARIES}")
else ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
# TODO: fix for find_path() to detect stdatomic.h
# find_path (HAVE_STDATOMIC_H stdatomic.h)
set (_saved_cmake_required_flags ${CMAKE_REQUIRED_FLAGS})
set (CMAKE_REQUIRED_FLAGS "-c" CACHE STRING "")
check_include_files (stdatomic.h HAVE_STDATOMIC_H)
set (CMAKE_REQUIRED_FLAGS ${_saved_cmake_required_flags})
endif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,34 @@
# FindHugeTLBFS
# --------
#
# Find HugeTLBFS
#
# Find the native HugeTLBFS includes and library This module defines
#
# ::
#
# HUGETLBFS_INCLUDE_DIR, where to find hugetlbfs.h, etc.
# HUGETLBFS_LIBRARIES, the libraries needed to use HugeTLBFS.
# HUGETLBFS_FOUND, If false, do not try to use HugeTLBFS.
#
# also defined, but not for general use are
#
# ::
#
# HUGETLBFS_LIBRARY, where to find the HugeTLBFS library.
find_path (HUGETLBFS_INCLUDE_DIR hugetlbfs.h)
set (HUGETLBFS_NAMES ${HUGETLBFS_NAMES} hugetlbfs)
find_library (HUGETLBFS_LIBRARY NAMES ${HUGETLBFS_NAMES})
# handle the QUIETLY and REQUIRED arguments and set HUGETLBFS_FOUND to TRUE if
# all listed variables are TRUE
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (HUGETLBFS DEFAULT_MSG HUGETLBFS_LIBRARY HUGETLBFS_INCLUDE_DIR)
if (HUGETLBFS_FOUND)
set (HUGETLBFS_LIBRARIES ${HUGETLBFS_LIBRARY})
endif (HUGETLBFS_FOUND)
mark_as_advanced (HUGETLBFS_LIBRARY HUGETLBFS_INCLUDE_DIR)

View File

@ -0,0 +1,46 @@
#.rst:
# FindLibRt
# --------
#
# Find the native realtime includes and library.
#
# IMPORTED Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines :prop_tgt:`IMPORTED` target ``LIBRT::LIBRT``, if
# LIBRT has been found.
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables:
#
# ::
#
# LIBRT_INCLUDE_DIRS - where to find time.h, etc.
# LIBRT_LIBRARIES - List of libraries when using librt.
# LIBRT_FOUND - True if realtime library found.
#
# Hints
# ^^^^^
#
# A user may set ``LIBRT_ROOT`` to a realtime installation root to tell this
# module where to look.
find_path(LIBRT_INCLUDE_DIRS
NAMES time.h
PATHS ${LIBRT_ROOT}/include/
)
find_library(LIBRT_LIBRARIES rt)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibRt DEFAULT_MSG LIBRT_LIBRARIES LIBRT_INCLUDE_DIRS)
mark_as_advanced(LIBRT_INCLUDE_DIRS LIBRT_LIBRARIES)
if(LIBRT_FOUND)
if(NOT TARGET LIBRT::LIBRT)
add_library(LIBRT::LIBRT UNKNOWN IMPORTED)
set_target_properties(LIBRT::LIBRT PROPERTIES
IMPORTED_LOCATION "${LIBRT_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${LIBRT_INCLUDE_DIRS}")
endif()
endif()

View File

@ -0,0 +1,34 @@
# FindLibSysFS
# --------
#
# Find LibSysFS
#
# Find the native LibSysFS includes and library This module defines
#
# ::
#
# LIBSYSFS_INCLUDE_DIR, where to find libsysfs.h, etc.
# LIBSYSFS_LIBRARIES, the libraries needed to use LibSysFS.
# LIBSYSFS_FOUND, If false, do not try to use LibSysFS.
#
# also defined, but not for general use are
#
# ::
#
# LIBSYSFS_LIBRARY, where to find the LibSysFS library.
find_path (LIBSYSFS_INCLUDE_DIR sysfs/libsysfs.h)
set (LIBSYSFS_NAMES ${LIBSYSFS_NAMES} sysfs)
find_library (LIBSYSFS_LIBRARY NAMES ${LIBSYSFS_NAMES})
# handle the QUIETLY and REQUIRED arguments and set LIBSYSFS_FOUND to TRUE if
# all listed variables are TRUE
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS (LIBSYSFS DEFAULT_MSG LIBSYSFS_LIBRARY LIBSYSFS_INCLUDE_DIR)
if (LIBSYSFS_FOUND)
set (LIBSYSFS_LIBRARIES ${LIBSYSFS_LIBRARY})
endif (LIBSYSFS_FOUND)
mark_as_advanced (LIBSYSFS_LIBRARY LIBSYSFS_INCLUDE_DIR)

View File

@ -0,0 +1,59 @@
set (PROJECT_VER_MAJOR 0)
set (PROJECT_VER_MINOR 1)
set (PROJECT_VER_PATCH 0)
set (PROJECT_VER 0.1.0)
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Debug)
endif (NOT CMAKE_BUILD_TYPE)
message ("-- Build type: ${CMAKE_BUILD_TYPE}")
if (NOT CMAKE_INSTALL_LIBDIR)
set (CMAKE_INSTALL_LIBDIR "lib")
endif (NOT CMAKE_INSTALL_LIBDIR)
if (NOT CMAKE_INSTALL_BINDIR)
set (CMAKE_INSTALL_BINDIR "bin")
endif (NOT CMAKE_INSTALL_BINDIR)
set (_host "${CMAKE_HOST_SYSTEM_NAME}/${CMAKE_HOST_SYSTEM_PROCESSOR}")
message ("-- Host: ${_host}")
set (_target "${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}")
message ("-- Target: ${_target}")
if (NOT DEFINED MACHINE)
set (MACHINE "Generic")
endif (NOT DEFINED MACHINE)
message ("-- Machine: ${MACHINE}")
# handle if '-' in machine name
string (REPLACE "-" "_" MACHINE ${MACHINE})
if (NOT DEFINED PROJECT_SYSTEM)
string (TOLOWER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM)
string (TOUPPER ${CMAKE_SYSTEM_NAME} PROJECT_SYSTEM_UPPER)
endif (NOT DEFINED PROJECT_SYSTEM)
string (TOLOWER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR)
string (TOUPPER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR_UPPER)
string (TOLOWER ${MACHINE} PROJECT_MACHINE)
string (TOUPPER ${MACHINE} PROJECT_MACHINE_UPPER)
option (WITH_STATIC_LIB "Build with a static library" ON)
if ("${PROJECT_SYSTEM}" STREQUAL "linux")
option (WITH_SHARED_LIB "Build with a shared library" ON)
option (WITH_TESTS "Install test applications" ON)
endif ("${PROJECT_SYSTEM}" STREQUAL "linux")
if (WITH_TESTS AND (${_host} STREQUAL ${_target}))
option (WITH_TESTS_EXEC "Run test applications during build" ON)
endif (WITH_TESTS AND (${_host} STREQUAL ${_target}))
option (WITH_DEFAULT_LOGGER "Build with default logger" ON)
option (WITH_DOC "Build with documentation" ON)
set (PROJECT_EC_FLAGS "-Wall -Werror -Wextra" CACHE STRING "")
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,6 @@
# cmake 3.3.2 does not know CMAKE_SYSTEM_NAME=FreeRTOS, we set it to Generic
include (cross-generic-gcc)
string (TOLOWER "FreeRTOS" PROJECT_SYSTEM)
string (TOUPPER "FreeRTOS" PROJECT_SYSTEM_UPPER)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,10 @@
set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER CACHE STRING "")
include (CMakeForceCompiler)
CMAKE_FORCE_C_COMPILER ("${CROSS_PREFIX}gcc" GNU)
CMAKE_FORCE_CXX_COMPILER ("${CROSS_PREFIX}g++" GNU)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,10 @@
set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER CACHE STRING "")
include (CMakeForceCompiler)
CMAKE_FORCE_C_COMPILER ("icc${CROSS_SUFFIX}" IAR)
CMAKE_FORCE_CXX_COMPILER ("icc${CROSS_SUFFIX} --eec++" IAR)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,8 @@
set (CMAKE_SYSTEM_NAME "Linux" CACHE STRING "")
set (CMAKE_C_COMPILER "${CROSS_PREFIX}gcc" CACHE STRING "")
set (CMAKE_CXX_COMPILER "${CROSS_PREFIX}g++" CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER CACHE STRING "")
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER CACHE STRING "")
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,7 @@
set (CMAKE_SYSTEM_PROCESSOR "microblaze" CACHE STRING "")
set (MACHINE "microblaze_generic" CACHE STRING "")
set (CROSS_PREFIX "mb-" CACHE STRING "")
# These flags are for a demo. If microblaze is changed, the flags need to be changed too.
set (CMAKE_C_FLAGS "-mlittle-endian -mxl-barrel-shift -mxl-pattern-compare \
-mcpu=v10.0 -mno-xl-soft-mul" CACHE STRING "")
include (cross-generic-gcc)

View File

@ -0,0 +1,12 @@
# Modify to match your needs. These setttings can also be overridden at the
# command line. (eg. cmake -DCMAKE_C_FLAGS="-O3")
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "template" CACHE STRING "")
set (CROSS_PREFIX "arm-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "" CACHE STRING "")
include (cross-freertos-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,12 @@
# Modify to match your needs. These setttings can also be overridden at the
# command line. (eg. cmake -DCMAKE_C_FLAGS="-O3")
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "template" CACHE STRING "")
set (CROSS_PREFIX "arm-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "" CACHE STRING "")
include (cross-generic-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,9 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynq7" CACHE STRING "")
set (CROSS_PREFIX "arm-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard" CACHE STRING "")
include (cross-freertos-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,5 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (CROSS_SUFFIX "arm" CACHE STRING "")
include (cross-generic-iar)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,9 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynq7" CACHE STRING "")
set (CROSS_PREFIX "arm-none-eabi-" CACHE STRING "")
set (CMAKE_C_FLAGS "-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard" CACHE STRING "")
include (cross-generic-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,5 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (CROSS_PREFIX "arm-xilinx-linux-gnueabi-" CACHE STRING "")
include (cross-linux-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,8 @@
set (CMAKE_SYSTEM_PROCESSOR "aarch64" CACHE STRING "")
set (MACHINE "zynqmp_a53" CACHE STRING "")
set (CROSS_PREFIX "aarch64-none-elf-" CACHE STRING "")
set (CMAKE_C_FLAGS "" CACHE STRING "")
include (cross-freertos-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,8 @@
set (CMAKE_SYSTEM_PROCESSOR "aarch64" CACHE STRING "")
set (MACHINE "zynqmp_a53" CACHE STRING "")
set (CROSS_PREFIX "aarch64-none-elf-" CACHE STRING "")
set (CMAKE_C_FLAGS "" CACHE STRING "")
include (cross-generic-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,5 @@
set (CMAKE_SYSTEM_PROCESSOR "aarch64" CACHE STRING "")
set (CROSS_PREFIX "aarch64-linux-gnu-" CACHE STRING "")
include (cross-linux-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,8 @@
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" CACHE STRING "")
include (cross-freertos-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,10 @@
set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
set (MACHINE "zynqmp_r5" CACHE STRING "")
set (CROSS_PREFIX "armr5-none-eabi-" CACHE STRING "")
# Xilinx SDK version earlier than 2017.2 use mfloat-abi=soft by default to generat libxil
set (CMAKE_C_FLAGS "-mfloat-abi=hard -mfpu=vfpv3-d16 -mcpu=cortex-r5" CACHE STRING "")
include (cross-generic-gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,12 @@
# use "Generic" as CMAKE_SYSTEM_NAME
if (WITH_ZEPHYR)
set (CMAKE_SYSTEM_NAME "Generic" CACHE STRING "")
string (TOLOWER "Zephyr" PROJECT_SYSTEM)
string (TOUPPER "Zephyr" PROJECT_SYSTEM_UPPER)
set(IS_TEST 1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
if (CONFIG_CPU_CORTEX_M)
set (MACHINE "cortexm" CACHE STRING "")
endif (CONFIG_CPU_CORTEX_M)
endif (WITH_ZEPHYR)

View File

@ -0,0 +1,19 @@
if (DOXYGEN_FOUND)
configure_file (Doxyfile.in Doxyfile @ONLY)
add_custom_target (doc ALL
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
DESTINATION share/doc/${PROJECT_NAME})
install (FILES ${PROJECT_SOURCE_DIR}/README.md
DESTINATION share/doc/${PROJECT_NAME})
install (FILES ${PROJECT_SOURCE_DIR}/LICENSE.md
DESTINATION share/doc/${PROJECT_NAME})
endif (DOXYGEN_FOUND)
# vim: expandtab:ts=2:sw=2:smartindent

2385
libmetal/doc/Doxyfile.in Normal file

File diff suppressed because it is too large Load Diff

100
libmetal/lib/CMakeLists.txt Normal file
View File

@ -0,0 +1,100 @@
collector_create (PROJECT_LIB_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}")
collector_create (PROJECT_LIB_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}")
collect (PROJECT_LIB_DIRS "${CMAKE_CURRENT_BINARY_DIR}")
collect (PROJECT_INC_DIRS "${CMAKE_CURRENT_BINARY_DIR}/include")
collect (PROJECT_LIB_HEADERS alloc.h)
collect (PROJECT_LIB_HEADERS assert.h)
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS cache.h)
collect (PROJECT_LIB_HEADERS compiler.h)
collect (PROJECT_LIB_HEADERS condition.h)
collect (PROJECT_LIB_HEADERS config.h)
collect (PROJECT_LIB_HEADERS cpu.h)
collect (PROJECT_LIB_HEADERS device.h)
collect (PROJECT_LIB_HEADERS dma.h)
collect (PROJECT_LIB_HEADERS io.h)
collect (PROJECT_LIB_HEADERS irq.h)
collect (PROJECT_LIB_HEADERS list.h)
collect (PROJECT_LIB_HEADERS log.h)
collect (PROJECT_LIB_HEADERS mutex.h)
collect (PROJECT_LIB_HEADERS shmem.h)
collect (PROJECT_LIB_HEADERS sleep.h)
collect (PROJECT_LIB_HEADERS spinlock.h)
collect (PROJECT_LIB_HEADERS sys.h)
collect (PROJECT_LIB_HEADERS time.h)
collect (PROJECT_LIB_HEADERS utilities.h)
collect (PROJECT_LIB_HEADERS version.h)
collect (PROJECT_LIB_SOURCES dma.c)
collect (PROJECT_LIB_SOURCES device.c)
collect (PROJECT_LIB_SOURCES init.c)
collect (PROJECT_LIB_SOURCES io.c)
collect (PROJECT_LIB_SOURCES log.c)
collect (PROJECT_LIB_SOURCES shmem.c)
collect (PROJECT_LIB_SOURCES version.c)
add_subdirectory (compiler)
add_subdirectory (processor)
add_subdirectory (system)
collector_list (_inc_dirs PROJECT_INC_DIRS)
collector_list (_sources PROJECT_LIB_SOURCES)
collector_list (_headers PROJECT_LIB_HEADERS)
collector_list (_deps PROJECT_LIB_DEPS)
foreach (f ${_headers})
configure_file (${f} include/${PROJECT_NAME}/${f} @ONLY)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/${f}
DESTINATION include RENAME ${PROJECT_NAME}/${f})
if (${f} MATCHES "^[^/]*\\.h")
collect (PROJECT_HDR_TESTS "metal/${f}")
endif (${f} MATCHES "^[^/]*\\.h")
endforeach (f)
include_directories (${_inc_dirs})
add_definitions (-DMETAL_INTERNAL)
if (WITH_DEFAULT_LOGGER)
add_definitions (-DDEFAULT_LOGGER_ON)
endif (WITH_DEFAULT_LOGGER)
if (WITH_ZEPHYR)
zephyr_library_named(metal)
add_dependencies(metal offsets_h)
target_sources (metal PRIVATE ${_sources})
else (WITH_ZEPHYR)
# Build a shared library if so configured.
if (WITH_SHARED_LIB)
set (_lib ${PROJECT_NAME}-shared)
add_library (${_lib} SHARED ${_sources})
target_link_libraries (${_lib} ${_deps})
install (TARGETS ${_lib} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
if (PROJECT_EC_FLAGS)
string(REPLACE " " ";" _ec_flgs ${PROJECT_EC_FLAGS})
target_compile_options (${_lib} PUBLIC ${_ec_flgs})
endif (PROJECT_EC_FLAGS)
set_target_properties (${_lib} PROPERTIES
OUTPUT_NAME "${PROJECT_NAME}"
VERSION "${PROJECT_VER}"
SOVERSION "${PROJECT_VER_MAJOR}"
)
endif (WITH_SHARED_LIB)
# Build a static library if so configured.
if (WITH_STATIC_LIB)
set (_lib ${PROJECT_NAME}-static)
add_library (${_lib} STATIC ${_sources})
install (TARGETS ${_lib} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
if (PROJECT_EC_FLAGS)
string(REPLACE " " ";" _ec_flgs ${PROJECT_EC_FLAGS})
target_compile_options (${_lib} PUBLIC ${_ec_flgs})
endif (PROJECT_EC_FLAGS)
set_target_properties (${_lib} PROPERTIES
OUTPUT_NAME "${PROJECT_NAME}"
)
endif (WITH_STATIC_LIB)
endif (WITH_ZEPHYR)
# vim: expandtab:ts=2:sw=2:smartindent

46
libmetal/lib/alloc.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file alloc.h
* @brief Memory allocation handling primitives for libmetal.
*/
#ifndef __METAL_ALLOC__H__
#define __METAL_ALLOC__H__
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup Memory Allocation Interfaces
* @{ */
/**
* @brief allocate requested memory size
* return a pointer to the allocated memory
*
* @param[in] size size in byte of requested memory
* @return memory pointer, or 0 if it failed to allocate
*/
static inline void *metal_allocate_memory(unsigned int size);
/**
* @brief free the memory previously allocated
*
* @param[in] ptr pointer to memory
*/
static inline void metal_free_memory(void *ptr);
#include <metal/system/@PROJECT_SYSTEM@/alloc.h>
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_ALLOC__H__ */

24
libmetal/lib/assert.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file assert.h
* @brief Assertion support.
*/
#ifndef __METAL_ASSERT__H__
#define __METAL_ASSERT__H__
#include <metal/system/@PROJECT_SYSTEM@/assert.h>
/**
* @brief Assertion macro.
* @param cond Condition to test.
*/
#define metal_assert(cond) metal_sys_assert(cond)
#endif /* __METAL_ASSERT_H__ */

26
libmetal/lib/atomic.h Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file atomic.h
* @brief Atomic primitives for libmetal.
*/
#ifndef __METAL_ATOMIC__H__
#define __METAL_ATOMIC__H__
#include <metal/config.h>
#if defined(HAVE_STDATOMIC_H) && !defined(__STDC_NO_ATOMICS__) && \
!defined(__cplusplus)
# include <stdatomic.h>
#elif defined(__GNUC__)
# include <metal/compiler/gcc/atomic.h>
#else
# include <metal/processor/@PROJECT_PROCESSOR@/atomic.h>
#endif
#endif /* __METAL_ATOMIC__H__ */

57
libmetal/lib/cache.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cache.h
* @brief CACHE operation primitives for libmetal.
*/
#ifndef __METAL_CACHE__H__
#define __METAL_CACHE__H__
#include <metal/system/@PROJECT_SYSTEM@/cache.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup cache CACHE Interfaces
* @{ */
/**
* @brief flush specified data cache
*
* @param[in] addr start memory logical address
* @param[in] len length of memory
* If addr is NULL, and len is 0,
* It will flush the whole data cache.
*/
static inline void metal_cache_flush(void *addr, unsigned int len)
{
return __metal_cache_flush(addr, len);
}
/**
* @brief invalidate specified data cache
*
* @param[in] addr start memory logical address
* @param[in] len length of memory
* If addr is NULL, and len is 0,
* It will invalidate the whole data cache.
*/
static inline void metal_cache_invalidate(void *addr, unsigned int len)
{
return __metal_cache_invalidate(addr, len);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_CACHE__H__ */

21
libmetal/lib/compiler.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file compiler.h
* @brief Compiler specific primitives for libmetal.
*/
#ifndef __METAL_COMPILER__H__
#define __METAL_COMPILER__H__
#if defined(__GNUC__)
# include <metal/compiler/gcc/compiler.h>
#else
# error "Missing compiler support"
#endif
#endif /* __METAL_COMPILER__H__ */

View File

@ -0,0 +1,3 @@
add_subdirectory (gcc)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,4 @@
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS compiler.h)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file gcc/atomic.h
* @brief GCC specific atomic primitives for libmetal.
*/
#ifndef __METAL_GCC_ATOMIC__H__
#define __METAL_GCC_ATOMIC__H__
#ifdef __cplusplus
extern "C" {
#endif
typedef int atomic_flag;
typedef char atomic_char;
typedef unsigned char atomic_uchar;
typedef short atomic_short;
typedef unsigned short atomic_ushort;
typedef int atomic_int;
typedef unsigned int atomic_uint;
typedef long atomic_long;
typedef unsigned long atomic_ulong;
typedef long long atomic_llong;
typedef unsigned long long atomic_ullong;
#define ATOMIC_FLAG_INIT 0
#define ATOMIC_VAR_INIT(VAL) (VAL)
typedef enum {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#define atomic_flag_test_and_set(FLAG) \
__sync_lock_test_and_set((FLAG), 1)
#define atomic_flag_test_and_set_explicit(FLAG, MO) \
atomic_flag_test_and_set(FLAG)
#define atomic_flag_clear(FLAG) \
__sync_lock_release((FLAG))
#define atomic_flag_clear_explicit(FLAG, MO) \
atomic_flag_clear(FLAG)
#define atomic_init(OBJ, VAL) \
do { *(OBJ) = (VAL); } while (0)
#define atomic_is_lock_free(OBJ) \
(sizeof(*(OBJ)) <= sizeof(long))
#define atomic_store(OBJ, VAL) \
do { *(OBJ) = (VAL); __sync_synchronize(); } while (0)
#define atomic_store_explicit(OBJ, VAL, MO) \
atomic_store((OBJ), (VAL))
#define atomic_load(OBJ) \
({ __sync_synchronize(); *(OBJ); })
#define atomic_load_explicit(OBJ, MO) \
atomic_load(OBJ)
#define atomic_exchange(OBJ, DES) \
({ \
typeof(OBJ) obj = (OBJ); \
typeof(*obj) des = (DES); \
typeof(*obj) expval; \
typeof(*obj) oldval = atomic_load(obj); \
do { \
expval = oldval; \
oldval = __sync_val_compare_and_swap( \
obj, expval, des); \
} while (oldval != expval); \
oldval; \
})
#define atomic_exchange_explicit(OBJ, DES, MO) \
atomic_exchange((OBJ), (DES))
#define atomic_compare_exchange_strong(OBJ, EXP, DES) \
({ \
typeof(OBJ) obj = (OBJ); \
typeof(EXP) exp = (EXP); \
typeof(*obj) expval = *exp; \
typeof(*obj) oldval = __sync_val_compare_and_swap( \
obj, expval, (DES)); \
*exp = oldval; \
oldval == expval; \
})
#define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO) \
atomic_compare_exchange_strong((OBJ), (EXP), (DES))
#define atomic_compare_exchange_weak(OBJ, EXP, DES) \
atomic_compare_exchange_strong((OBJ), (EXP), (DES))
#define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO) \
atomic_compare_exchange_weak((OBJ), (EXP), (DES))
#define atomic_fetch_add(OBJ, VAL) \
__sync_fetch_and_add((OBJ), (VAL))
#define atomic_fetch_add_explicit(OBJ, VAL, MO) \
atomic_fetch_add((OBJ), (VAL))
#define atomic_fetch_sub(OBJ, VAL) \
__sync_fetch_and_sub((OBJ), (VAL))
#define atomic_fetch_sub_explicit(OBJ, VAL, MO) \
atomic_fetch_sub((OBJ), (VAL))
#define atomic_fetch_or(OBJ, VAL) \
__sync_fetch_and_or((OBJ), (VAL))
#define atomic_fetch_or_explicit(OBJ, VAL, MO) \
atomic_fetch_or((OBJ), (VAL))
#define atomic_fetch_xor(OBJ, VAL) \
__sync_fetch_and_xor((OBJ), (VAL))
#define atomic_fetch_xor_explicit(OBJ, VAL, MO) \
atomic_fetch_xor((OBJ), (VAL))
#define atomic_fetch_and(OBJ, VAL) \
__sync_fetch_and_and((OBJ), (VAL))
#define atomic_fetch_and_explicit(OBJ, VAL, MO) \
atomic_fetch_and((OBJ), (VAL))
#define atomic_thread_fence(MO) \
__sync_synchronize()
#define atomic_signal_fence(MO) \
__sync_synchronize()
#ifdef __cplusplus
}
#endif
#endif /* __METAL_GCC_ATOMIC__H__ */

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file gcc/compiler.h
* @brief GCC specific primitives for libmetal.
*/
#ifndef __METAL_GCC_COMPILER__H__
#define __METAL_GCC_COMPILER__H__
#ifdef __cplusplus
extern "C" {
#endif
#define restrict __restrict__
#define metal_align(n) __attribute__((aligned(n)))
#define metal_weak __attribute__((weak))
#ifdef __cplusplus
}
#endif
#endif /* __METAL_GCC_COMPILER__H__ */

73
libmetal/lib/condition.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file condition.h
* @brief Condition variable for libmetal.
*/
#ifndef __METAL_CONDITION__H__
#define __METAL_CONDITION__H__
#include <metal/mutex.h>
#include <metal/utilities.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup condition Condition Variable Interfaces
* @{ */
/** Opaque libmetal condition variable data structure. */
struct metal_condition;
/**
* @brief Initialize a libmetal condition variable.
* @param[in] cv condition variable to initialize.
*/
static inline void metal_condition_init(struct metal_condition *cv);
/**
* @brief Notify one waiter.
* Before calling this function, the caller
* should have acquired the mutex.
* @param[in] cv condition variable
* @return zero on no errors, non-zero on errors
* @see metal_condition_wait, metal_condition_broadcast
*/
static inline int metal_condition_signal(struct metal_condition *cv);
/**
* @brief Notify all waiters.
* Before calling this function, the caller
* should have acquired the mutex.
* @param[in] cv condition variable
* @return zero on no errors, non-zero on errors
* @see metal_condition_wait, metal_condition_signal
*/
static inline int metal_condition_broadcast(struct metal_condition *cv);
/**
* @brief Block until the condition variable is notified.
* Before calling this function, the caller should
* have acquired the mutex.
* @param[in] cv condition variable
* @param[in] m mutex
* @return 0 on success, non-zero on failure.
* @see metal_condition_signal
*/
int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m);
#include <metal/system/@PROJECT_SYSTEM@/condition.h>
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_CONDITION__H__ */

50
libmetal/lib/config.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file config.h
* @brief Generated configuration settings for libmetal.
*/
#ifndef __METAL_CONFIG__H__
#define __METAL_CONFIG__H__
#ifdef __cplusplus
extern "C" {
#endif
/** Library major version number. */
#define METAL_VER_MAJOR @PROJECT_VER_MAJOR@
/** Library minor version number. */
#define METAL_VER_MINOR @PROJECT_VER_MINOR@
/** Library patch level. */
#define METAL_VER_PATCH @PROJECT_VER_PATCH@
/** Library version string. */
#define METAL_VER "@PROJECT_VER@"
/** System type (linux, generic, ...). */
#define METAL_SYSTEM "@PROJECT_SYSTEM@"
#define METAL_SYSTEM_@PROJECT_SYSTEM_UPPER@
/** Processor type (arm, x86_64, ...). */
#define METAL_PROCESSOR "@PROJECT_PROCESSOR@"
#define METAL_PROCESSOR_@PROJECT_PROCESSOR_UPPER@
/** Machine type (zynq, zynqmp, ...). */
#define METAL_MACHINE "@PROJECT_MACHINE@"
#define METAL_MACHINE_@PROJECT_MACHINE_UPPER@
#cmakedefine HAVE_STDATOMIC_H
#cmakedefine HAVE_FUTEX_H
#ifdef __cplusplus
}
#endif
#endif /* __METAL_CONFIG__H__ */

17
libmetal/lib/cpu.h Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cpu.h
* @brief CPU primitives for libmetal.
*/
#ifndef __METAL_CPU__H__
#define __METAL_CPU__H__
# include <metal/processor/@PROJECT_PROCESSOR@/cpu.h>
#endif /* __METAL_CPU__H__ */

167
libmetal/lib/device.c Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <errno.h>
#include <metal/assert.h>
#include <metal/device.h>
#include <metal/list.h>
#include <metal/log.h>
#include <metal/sys.h>
#include <metal/utilities.h>
#include <metal/dma.h>
#include <metal/cache.h>
int metal_bus_register(struct metal_bus *bus)
{
if (!bus || !bus->name || !strlen(bus->name))
return -EINVAL;
if (metal_bus_find(bus->name, NULL) == 0)
return -EEXIST;
metal_list_init(&bus->devices);
metal_list_add_tail(&_metal.common.bus_list, &bus->node);
metal_log(METAL_LOG_DEBUG, "registered %s bus\n", bus->name);
return 0;
}
int metal_bus_unregister(struct metal_bus *bus)
{
metal_list_del(&bus->node);
if (bus->ops.bus_close)
bus->ops.bus_close(bus);
metal_log(METAL_LOG_DEBUG, "unregistered %s bus\n", bus->name);
return 0;
}
int metal_bus_find(const char *name, struct metal_bus **result)
{
struct metal_list *node;
struct metal_bus *bus;
metal_list_for_each(&_metal.common.bus_list, node) {
bus = metal_container_of(node, struct metal_bus, node);
if (strcmp(bus->name, name) != 0)
continue;
if (result)
*result = bus;
return 0;
}
return -ENOENT;
}
int metal_device_open(const char *bus_name, const char *dev_name,
struct metal_device **device)
{
struct metal_bus *bus;
int error;
if (!bus_name || !strlen(bus_name) ||
!dev_name || !strlen(dev_name) ||
!device)
return -EINVAL;
error = metal_bus_find(bus_name, &bus);
if (error)
return error;
if (!bus->ops.dev_open)
return -ENODEV;
error = (*bus->ops.dev_open)(bus, dev_name, device);
if (error)
return error;
return 0;
}
void metal_device_close(struct metal_device *device)
{
metal_assert(device && device->bus);
if (device->bus->ops.dev_close)
device->bus->ops.dev_close(device->bus, device);
}
int metal_register_generic_device(struct metal_device *device)
{
if (!device->name || !strlen(device->name) ||
device->num_regions > METAL_MAX_DEVICE_REGIONS)
return -EINVAL;
device->bus = &metal_generic_bus;
metal_list_add_tail(&_metal.common.generic_device_list,
&device->node);
return 0;
}
int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
struct metal_device **device)
{
struct metal_list *node;
struct metal_device *dev;
(void)bus;
metal_list_for_each(&_metal.common.generic_device_list, node) {
dev = metal_container_of(node, struct metal_device, node);
if (strcmp(dev->name, dev_name) != 0)
continue;
*device = dev;
return metal_generic_dev_sys_open(dev);
}
return -ENODEV;
}
int metal_generic_dev_dma_map(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg_in,
int nents_in,
struct metal_sg *sg_out)
{
(void)bus;
(void)device;
int i;
if (sg_out != sg_in)
memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg)));
for (i = 0; i < nents_in; i++) {
if (dir == METAL_DMA_DEV_W) {
metal_cache_flush(sg_out[i].virt, sg_out[i].len);
}
metal_cache_invalidate(sg_out[i].virt, sg_out[i].len);
}
return nents_in;
}
void metal_generic_dev_dma_unmap(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg,
int nents)
{
(void)bus;
(void)device;
(void)dir;
int i;
for (i = 0; i < nents; i++) {
metal_cache_invalidate(sg[i].virt, sg[i].len);
}
}
struct metal_bus metal_weak metal_generic_bus = {
.name = "generic",
.ops = {
.bus_close = NULL,
.dev_open = metal_generic_dev_open,
.dev_close = NULL,
.dev_irq_ack = NULL,
.dev_dma_map = metal_generic_dev_dma_map,
.dev_dma_unmap = metal_generic_dev_dma_unmap,
},
};

176
libmetal/lib/device.h Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file device.h
* @brief Bus abstraction for libmetal.
*/
#ifndef __METAL_BUS__H__
#define __METAL_BUS__H__
#include <stdint.h>
#include <metal/io.h>
#include <metal/list.h>
#include <metal/dma.h>
#include <metal/sys.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup device Bus Abstraction
* @{ */
#ifndef METAL_MAX_DEVICE_REGIONS
#define METAL_MAX_DEVICE_REGIONS 32
#endif
struct metal_bus;
struct metal_device;
/** Bus operations. */
struct metal_bus_ops {
void (*bus_close)(struct metal_bus *bus);
int (*dev_open)(struct metal_bus *bus,
const char *dev_name,
struct metal_device **device);
void (*dev_close)(struct metal_bus *bus,
struct metal_device *device);
void (*dev_irq_ack)(struct metal_bus *bus,
struct metal_device *device,
int irq);
int (*dev_dma_map)(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg_in,
int nents_in,
struct metal_sg *sg_out);
void (*dev_dma_unmap)(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg,
int nents);
};
/** Libmetal bus structure. */
struct metal_bus {
const char *name;
struct metal_bus_ops ops;
struct metal_list devices;
struct metal_list node;
};
/** Libmetal generic bus. */
extern struct metal_bus metal_generic_bus;
/** Libmetal device structure. */
struct metal_device {
const char *name; /**< Device name */
struct metal_bus *bus; /**< Bus that contains device */
unsigned num_regions; /**< Number of I/O regions in
device */
struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of
I/O regions in device*/
struct metal_list node; /**< Node on bus' list of devices */
int irq_num; /**< Number of IRQs per device */
void *irq_info; /**< IRQ ID */
};
/**
* @brief Register a libmetal bus.
* @param[in] bus Pre-initialized bus structure.
* @return 0 on success, or -errno on failure.
*/
extern int metal_bus_register(struct metal_bus *bus);
/**
* @brief Unregister a libmetal bus.
* @param[in] bus Pre-registered bus structure.
* @return 0 on success, or -errno on failure.
*/
extern int metal_bus_unregister(struct metal_bus *bus);
/**
* @brief Find a libmetal bus by name.
* @param[in] name Bus name.
* @param[out] bus Returned bus handle.
* @return 0 on success, or -errno on failure.
*/
extern int metal_bus_find(const char *name, struct metal_bus **bus);
/**
* @brief Statically register a generic libmetal device.
*
* In non-Linux systems, devices are always required to be statically
* registered at application initialization.
* In Linux system, devices can be dynamically opened via sysfs or libfdt based
* enumeration at runtime.
* This interface is used for static registration of devices. Subsequent calls
* to metal_device_open() look up in this list of pre-registered devices on the
* "generic" bus.
* "generic" bus is used on non-Linux system to group the memory mapped devices.
*
* @param[in] device Generic device.
* @return 0 on success, or -errno on failure.
*/
extern int metal_register_generic_device(struct metal_device *device);
/**
* @brief Open a libmetal device by name.
* @param[in] bus_name Bus name.
* @param[in] dev_name Device name.
* @param[out] device Returned device handle.
* @return 0 on success, or -errno on failure.
*/
extern int metal_device_open(const char *bus_name, const char *dev_name,
struct metal_device **device);
/**
* @brief Close a libmetal device.
* @param[in] device Device handle.
*/
extern void metal_device_close(struct metal_device *device);
/**
* @brief Get an I/O region accessor for a device region.
*
* @param[in] device Device handle.
* @param[in] index Region index.
* @return I/O accessor handle, or NULL on failure.
*/
static inline struct metal_io_region *
metal_device_io_region(struct metal_device *device, unsigned index)
{
return (index < device->num_regions
? &device->regions[index]
: NULL);
}
/** @} */
#ifdef METAL_INTERNAL
extern int metal_generic_dev_sys_open(struct metal_device *dev);
extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
struct metal_device **device);
extern int metal_generic_dev_dma_map(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg_in,
int nents_in,
struct metal_sg *sg_out);
extern void metal_generic_dev_dma_unmap(struct metal_bus *bus,
struct metal_device *device,
uint32_t dir,
struct metal_sg *sg,
int nents);
#endif /* METAL_INTERNAL */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_BUS__H__ */

58
libmetal/lib/dma.c Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <string.h>
#include <metal/device.h>
#include <metal/log.h>
#include <metal/dma.h>
#include <metal/atomic.h>
int metal_dma_map(struct metal_device *dev,
uint32_t dir,
struct metal_sg *sg_in,
int nents_in,
struct metal_sg *sg_out)
{
int nents_out;
if (!dev || !sg_in || !sg_out)
return -EINVAL;
if (!dev->bus->ops.dev_dma_map)
return -ENODEV;
/* memory barrier */
if (dir == METAL_DMA_DEV_R)
/* If it is device read, apply memory write fence. */
atomic_thread_fence(memory_order_release);
else
/* If it is device write or device r/w,
apply memory r/w fence. */
atomic_thread_fence(memory_order_acq_rel);
nents_out = dev->bus->ops.dev_dma_map(dev->bus,
dev, dir, sg_in, nents_in, sg_out);
return nents_out;
}
void metal_dma_unmap(struct metal_device *dev,
uint32_t dir,
struct metal_sg *sg,
int nents)
{
/* memory barrier */
if (dir == METAL_DMA_DEV_R)
/* If it is device read, apply memory write fence. */
atomic_thread_fence(memory_order_release);
else
/* If it is device write or device r/w,
apply memory r/w fence. */
atomic_thread_fence(memory_order_acq_rel);
if (!dev || !dev->bus->ops.dev_dma_unmap || !sg)
return;
dev->bus->ops.dev_dma_unmap(dev->bus,
dev, dir, sg, nents);
}

79
libmetal/lib/dma.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file dma.h
* @brief DMA primitives for libmetal.
*/
#ifndef __METAL_DMA__H__
#define __METAL_DMA__H__
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup dma DMA Interfaces
* @{ */
#include <stdint.h>
#include <metal/sys.h>
#define METAL_DMA_DEV_R 1 /**< DMA direction, device read */
#define METAL_DMA_DEV_W 2 /**< DMA direction, device write */
#define METAL_DMA_DEV_WR 3 /**< DMA direction, device read/write */
/**
* @brief scatter/gather list element structure
*/
struct metal_sg {
void *virt; /**< CPU virtual address */
struct metal_io_region *io; /**< IO region */
int len; /**< length */
};
struct metal_device;
/**
* @brief Map memory for DMA transaction.
* After the memory is DMA mapped, the memory should be
* accessed by the DMA device but not the CPU.
*
* @param[in] dev DMA device
* @param[in] dir DMA direction
* @param[in] sg_in sg list of memory to map
* @param[in] nents_in number of sg list entries of memory to map
* @param[out] sg_out sg list of mapped memory
* @return number of mapped sg entries, -error on failure.
*/
int metal_dma_map(struct metal_device *dev,
uint32_t dir,
struct metal_sg *sg_in,
int nents_in,
struct metal_sg *sg_out);
/**
* @brief Unmap DMA memory
* After the memory is DMA unmapped, the memory should
* be accessed by the CPU but not the DMA device.
*
* @param[in] dev DMA device
* @param[in] dir DMA direction
* @param[in] sg sg list of mapped DMA memory
* @param[in] nents number of sg list entries of DMA memory
*/
void metal_dma_unmap(struct metal_device *dev,
uint32_t dir,
struct metal_sg *sg,
int nents);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_DMA__H__ */

34
libmetal/lib/init.c Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <metal/sys.h>
int metal_init(const struct metal_init_params *params)
{
int error = 0;
memset(&_metal, 0, sizeof(_metal));
_metal.common.log_handler = params->log_handler;
_metal.common.log_level = params->log_level;
metal_list_init(&_metal.common.bus_list);
metal_list_init(&_metal.common.generic_shmem_list);
metal_list_init(&_metal.common.generic_device_list);
error = metal_sys_init(params);
if (error)
return error;
return error;
}
void metal_finish(void)
{
metal_sys_finish();
memset(&_metal, 0, sizeof(_metal));
}

137
libmetal/lib/io.c Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <limits.h>
#include <metal/io.h>
#include <metal/sys.h>
void metal_io_init(struct metal_io_region *io, void *virt,
const metal_phys_addr_t *physmap, size_t size,
unsigned page_shift, unsigned int mem_flags,
const struct metal_io_ops *ops)
{
const struct metal_io_ops nops = {NULL, NULL, NULL, NULL, NULL, NULL};
io->virt = virt;
io->physmap = physmap;
io->size = size;
io->page_shift = page_shift;
if (page_shift >= sizeof(io->page_mask) * CHAR_BIT)
/* avoid overflow */
io->page_mask = -1UL;
else
io->page_mask = (1UL << page_shift) - 1UL;
io->mem_flags = mem_flags;
io->ops = ops ? *ops : nops;
metal_sys_io_mem_map(io);
}
int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
void *restrict dst, int len)
{
void *ptr = metal_io_virt(io, offset);
int retlen;
if (offset > io->size)
return -ERANGE;
if ((offset + len) > io->size)
len = io->size - offset;
retlen = len;
if (io->ops.block_read) {
retlen = (*io->ops.block_read)(
io, offset, dst, memory_order_seq_cst, len);
} else {
atomic_thread_fence(memory_order_seq_cst);
while ( len && (
((uintptr_t)dst % sizeof(int)) ||
((uintptr_t)ptr % sizeof(int)))) {
*(unsigned char *)dst =
*(const unsigned char *)ptr;
dst++;
ptr++;
len--;
}
for (; len >= (int)sizeof(int); dst += sizeof(int),
ptr += sizeof(int),
len -= sizeof(int))
*(unsigned int *)dst = *(const unsigned int *)ptr;
for (; len != 0; dst++, ptr++, len--)
*(unsigned char *)dst =
*(const unsigned char *)ptr;
}
return retlen;
}
int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
const void *restrict src, int len)
{
void *ptr = metal_io_virt(io, offset);
int retlen;
if (offset > io->size)
return -ERANGE;
if ((offset + len) > io->size)
len = io->size - offset;
retlen = len;
if (io->ops.block_write) {
retlen = (*io->ops.block_write)(
io, offset, src, memory_order_seq_cst, len);
} else {
while ( len && (
((uintptr_t)ptr % sizeof(int)) ||
((uintptr_t)src % sizeof(int)))) {
*(unsigned char *)ptr =
*(const unsigned char *)src;
ptr++;
src++;
len--;
}
for (; len >= (int)sizeof(int); ptr += sizeof(int),
src += sizeof(int),
len -= sizeof(int))
*(unsigned int *)ptr = *(const unsigned int *)src;
for (; len != 0; ptr++, src++, len--)
*(unsigned char *)ptr =
*(const unsigned char *)src;
atomic_thread_fence(memory_order_seq_cst);
}
return retlen;
}
int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
unsigned char value, int len)
{
void *ptr = metal_io_virt(io, offset);
int retlen = len;
if (offset > io->size)
return -ERANGE;
if ((offset + len) > io->size)
len = io->size - offset;
retlen = len;
if (io->ops.block_set) {
(*io->ops.block_set)(
io, offset, value, memory_order_seq_cst, len);
} else {
unsigned int cint = value;
unsigned int i;
for (i = 1; i < sizeof(int); i++)
cint |= ((unsigned int)value << (8 * i));
for (; len && ((uintptr_t)ptr % sizeof(int)); ptr++, len--)
*(unsigned char *)ptr = (unsigned char) value;
for (; len >= (int)sizeof(int); ptr += sizeof(int),
len -= sizeof(int))
*(unsigned int *)ptr = cint;
for (; len != 0; ptr++, len--)
*(unsigned char *)ptr = (unsigned char) value;
atomic_thread_fence(memory_order_seq_cst);
}
return retlen;
}

359
libmetal/lib/io.h Normal file
View File

@ -0,0 +1,359 @@
/*
* Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file io.h
* @brief I/O access primitives for libmetal.
*/
#ifndef __METAL_IO__H__
#define __METAL_IO__H__
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <metal/assert.h>
#include <metal/compiler.h>
#include <metal/atomic.h>
#include <metal/sys.h>
#include <metal/cpu.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup io IO Interfaces
* @{ */
#ifdef __MICROBLAZE__
#define NO_ATOMIC_64_SUPPORT
#endif
struct metal_io_region;
/** Generic I/O operations. */
struct metal_io_ops {
uint64_t (*read)(struct metal_io_region *io,
unsigned long offset,
memory_order order,
int width);
void (*write)(struct metal_io_region *io,
unsigned long offset,
uint64_t value,
memory_order order,
int width);
int (*block_read)(struct metal_io_region *io,
unsigned long offset,
void *restrict dst,
memory_order order,
int len);
int (*block_write)(struct metal_io_region *io,
unsigned long offset,
const void *restrict src,
memory_order order,
int len);
void (*block_set)(struct metal_io_region *io,
unsigned long offset,
unsigned char value,
memory_order order,
int len);
void (*close)(struct metal_io_region *io);
};
/** Libmetal I/O region structure. */
struct metal_io_region {
void *virt; /**< base virtual address */
const metal_phys_addr_t *physmap; /**< table of base physical address
of each of the pages in the I/O
region */
size_t size; /**< size of the I/O region */
unsigned long page_shift; /**< page shift of I/O region */
metal_phys_addr_t page_mask; /**< page mask of I/O region */
unsigned int mem_flags; /**< memory attribute of the
I/O region */
struct metal_io_ops ops; /**< I/O region operations */
};
/**
* @brief Open a libmetal I/O region.
*
* @param[in, out] io I/O region handle.
* @param[in] virt Virtual address of region.
* @param[in] physmap Array of physical addresses per page.
* @param[in] size Size of region.
* @param[in] page_shift Log2 of page size (-1 for single page).
* @param[in] mem_flags Memory flags
* @param[in] ops ops
*/
void
metal_io_init(struct metal_io_region *io, void *virt,
const metal_phys_addr_t *physmap, size_t size,
unsigned page_shift, unsigned int mem_flags,
const struct metal_io_ops *ops);
/**
* @brief Close a libmetal shared memory segment.
* @param[in] io I/O region handle.
*/
static inline void metal_io_finish(struct metal_io_region *io)
{
if (io->ops.close)
(*io->ops.close)(io);
memset(io, 0, sizeof(*io));
}
/**
* @brief Get size of I/O region.
*
* @param[in] io I/O region handle.
* @return Size of I/O region.
*/
static inline size_t metal_io_region_size(struct metal_io_region *io)
{
return io->size;
}
/**
* @brief Get virtual address for a given offset into the I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into shared memory segment.
* @return NULL if offset is out of range, or pointer to offset.
*/
static inline void *
metal_io_virt(struct metal_io_region *io, unsigned long offset)
{
return (io->virt != METAL_BAD_VA && offset <= io->size
? (uint8_t *)io->virt + offset
: NULL);
}
/**
* @brief Convert a virtual address to offset within I/O region.
* @param[in] io I/O region handle.
* @param[in] virt Virtual address within segment.
* @return METAL_BAD_OFFSET if out of range, or offset.
*/
static inline unsigned long
metal_io_virt_to_offset(struct metal_io_region *io, void *virt)
{
size_t offset = (uint8_t *)virt - (uint8_t *)io->virt;
return (offset < io->size ? offset : METAL_BAD_OFFSET);
}
/**
* @brief Get physical address for a given offset into the I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into shared memory segment.
* @return METAL_BAD_PHYS if offset is out of range, or physical address
* of offset.
*/
static inline metal_phys_addr_t
metal_io_phys(struct metal_io_region *io, unsigned long offset)
{
unsigned long page = (io->page_shift >=
sizeof(offset) * CHAR_BIT ?
0 : offset >> io->page_shift);
return (io->physmap != NULL && offset <= io->size
? io->physmap[page] + (offset & io->page_mask)
: METAL_BAD_PHYS);
}
/**
* @brief Convert a physical address to offset within I/O region.
* @param[in] io I/O region handle.
* @param[in] phys Physical address within segment.
* @return METAL_BAD_OFFSET if out of range, or offset.
*/
static inline unsigned long
metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
{
unsigned long offset =
(io->page_mask == (metal_phys_addr_t)(-1) ?
phys - io->physmap[0] : phys & io->page_mask);
do {
if (metal_io_phys(io, offset) == phys)
return offset;
offset += io->page_mask + 1;
} while (offset < io->size);
return METAL_BAD_OFFSET;
}
/**
* @brief Convert a physical address to virtual address.
* @param[in] io Shared memory segment handle.
* @param[in] phys Physical address within segment.
* @return NULL if out of range, or corresponding virtual address.
*/
static inline void *
metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys)
{
return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
}
/**
* @brief Convert a virtual address to physical address.
* @param[in] io Shared memory segment handle.
* @param[in] virt Virtual address within segment.
* @return METAL_BAD_PHYS if out of range, or corresponding
* physical address.
*/
static inline metal_phys_addr_t
metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
{
return metal_io_phys(io, metal_io_virt_to_offset(io, virt));
}
/**
* @brief Read a value from an I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into I/O region.
* @param[in] order Memory ordering.
* @param[in] width Width in bytes of datatype to read. This must be 1, 2,
* 4, or 8, and a compile time constant for this function
* to inline cleanly.
* @return Value.
*/
static inline uint64_t
metal_io_read(struct metal_io_region *io, unsigned long offset,
memory_order order, int width)
{
void *ptr = metal_io_virt(io, offset);
if (io->ops.read)
return (*io->ops.read)(io, offset, order, width);
else if (ptr && sizeof(atomic_uchar) == width)
return atomic_load_explicit((atomic_uchar *)ptr, order);
else if (ptr && sizeof(atomic_ushort) == width)
return atomic_load_explicit((atomic_ushort *)ptr, order);
else if (ptr && sizeof(atomic_uint) == width)
return atomic_load_explicit((atomic_uint *)ptr, order);
else if (ptr && sizeof(atomic_ulong) == width)
return atomic_load_explicit((atomic_ulong *)ptr, order);
else if (ptr && sizeof(atomic_ullong) == width)
#ifndef NO_ATOMIC_64_SUPPORT
return atomic_load_explicit((atomic_ullong *)ptr, order);
#else
return metal_processor_io_read64((atomic_ullong *)ptr, order);
#endif
metal_assert(0);
return 0; /* quiet compiler */
}
/**
* @brief Write a value into an I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into I/O region.
* @param[in] value Value to write.
* @param[in] order Memory ordering.
* @param[in] width Width in bytes of datatype to read. This must be 1, 2,
* 4, or 8, and a compile time constant for this function
* to inline cleanly.
*/
static inline void
metal_io_write(struct metal_io_region *io, unsigned long offset,
uint64_t value, memory_order order, int width)
{
void *ptr = metal_io_virt(io, offset);
if (io->ops.write)
(*io->ops.write)(io, offset, value, order, width);
else if (ptr && sizeof(atomic_uchar) == width)
atomic_store_explicit((atomic_uchar *)ptr, value, order);
else if (ptr && sizeof(atomic_ushort) == width)
atomic_store_explicit((atomic_ushort *)ptr, value, order);
else if (ptr && sizeof(atomic_uint) == width)
atomic_store_explicit((atomic_uint *)ptr, value, order);
else if (ptr && sizeof(atomic_ulong) == width)
atomic_store_explicit((atomic_ulong *)ptr, value, order);
else if (ptr && sizeof(atomic_ullong) == width)
#ifndef NO_ATOMIC_64_SUPPORT
atomic_store_explicit((atomic_ullong *)ptr, value, order);
#else
metal_processor_io_write64((atomic_ullong *)ptr, value, order);
#endif
else
metal_assert (0);
}
#define metal_io_read8_explicit(_io, _ofs, _order) \
metal_io_read((_io), (_ofs), (_order), 1)
#define metal_io_read8(_io, _ofs) \
metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
#define metal_io_write8_explicit(_io, _ofs, _val, _order) \
metal_io_write((_io), (_ofs), (_val), (_order), 1)
#define metal_io_write8(_io, _ofs, _val) \
metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
#define metal_io_read16_explicit(_io, _ofs, _order) \
metal_io_read((_io), (_ofs), (_order), 2)
#define metal_io_read16(_io, _ofs) \
metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
#define metal_io_write16_explicit(_io, _ofs, _val, _order) \
metal_io_write((_io), (_ofs), (_val), (_order), 2)
#define metal_io_write16(_io, _ofs, _val) \
metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
#define metal_io_read32_explicit(_io, _ofs, _order) \
metal_io_read((_io), (_ofs), (_order), 4)
#define metal_io_read32(_io, _ofs) \
metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
#define metal_io_write32_explicit(_io, _ofs, _val, _order) \
metal_io_write((_io), (_ofs), (_val), (_order), 4)
#define metal_io_write32(_io, _ofs, _val) \
metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
#define metal_io_read64_explicit(_io, _ofs, _order) \
metal_io_read((_io), (_ofs), (_order), 8)
#define metal_io_read64(_io, _ofs) \
metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
#define metal_io_write64_explicit(_io, _ofs, _val, _order) \
metal_io_write((_io), (_ofs), (_val), (_order), 8)
#define metal_io_write64(_io, _ofs, _val) \
metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
/**
* @brief Read a block from an I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into I/O region.
* @param[in] dst destination to store the read data.
* @param[in] len length in bytes to read.
* @return On success, number of bytes read. On failure, negative value
*/
int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
void *restrict dst, int len);
/**
* @brief Write a block into an I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into I/O region.
* @param[in] src source to write.
* @param[in] len length in bytes to write.
* @return On success, number of bytes written. On failure, negative value
*/
int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
const void *restrict src, int len);
/**
* @brief fill a block of an I/O region.
* @param[in] io I/O region handle.
* @param[in] offset Offset into I/O region.
* @param[in] value value to fill into the block
* @param[in] len length in bytes to fill.
* @return On success, number of bytes filled. On failure, negative value
*/
int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
unsigned char value, int len);
#include <metal/system/@PROJECT_SYSTEM@/io.h>
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_IO__H__ */

116
libmetal/lib/irq.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file irq.h
* @brief Interrupt handling primitives for libmetal.
*/
#ifndef __METAL_IRQ__H__
#define __METAL_IRQ__H__
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup irq Interrupt Handling Interfaces
* @{ */
#include <stdlib.h>
/** IRQ handled status */
#define METAL_IRQ_NOT_HANDLED 0
#define METAL_IRQ_HANDLED 1
/**
* @brief type of interrupt handler
* @param[in] irq interrupt id
* @param[in] priv private data
* @return irq handled status
*/
typedef int (*metal_irq_handler) (int irq, void *priv);
struct metal_device;
/**
* @brief Register interrupt handler for driver ID/device.
*
* @param[in] irq interrupt id
* @param[in] irq_handler interrupt handler
* @param[in] dev metal device this irq belongs to (can be NULL).
* @param[in] drv_id driver id is a unique interrupt handler identifier.
* It can also be used for driver data.
* @return 0 for success, non-zero on failure
*/
int metal_irq_register(int irq,
metal_irq_handler irq_handler,
struct metal_device *dev,
void *drv_id);
/**
* @brief Unregister interrupt handler for driver ID and/or device.
*
* If interrupt handler (hd), driver ID (drv_id) and device (dev)
* are NULL, unregister all handlers for this interrupt.
*
* If interrupt handler (hd), device (dev) or driver ID (drv_id),
* are not NULL, unregister handlers matching non NULL criterias.
* e.g: when call is made with drv_id and dev non NULL,
* all handlers matching both are unregistered.
*
* If interrupt is not found, or other criterias not matching,
* return -ENOENT
*
* @param[in] irq interrupt id
* @param[in] irq_handler interrupt handler
* @param[in] dev metal device this irq belongs to
* @param[in] drv_id driver id. It can be used for driver data.
* @return 0 for success, non-zero on failure
*/
int metal_irq_unregister(int irq,
metal_irq_handler irq_handler,
struct metal_device *dev,
void *drv_id);
/**
* @brief disable interrupts
* @return interrupts state
*/
unsigned int metal_irq_save_disable(void);
/**
* @brief restore interrupts to their previous state
* @param[in] flags previous interrupts state
*/
void metal_irq_restore_enable(unsigned int flags);
/**
* @brief metal_irq_enable
*
* Enables the given interrupt
*
* @param vector - interrupt vector number
*/
void metal_irq_enable(unsigned int vector);
/**
* @brief metal_irq_disable
*
* Disables the given interrupt
*
* @param vector - interrupt vector number
*/
void metal_irq_disable(unsigned int vector);
#include <metal/system/@PROJECT_SYSTEM@/irq.h>
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_IRQ__H__ */

102
libmetal/lib/list.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file list.h
* @brief List primitives for libmetal.
*/
#ifndef __METAL_LIST__H__
#define __METAL_LIST__H__
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup list List Primitives
* @{ */
struct metal_list {
struct metal_list *next, *prev;
};
/*
* METAL_INIT_LIST - used for initializing an list elmenet in a static struct
* or global
*/
#define METAL_INIT_LIST(name) { .next = &name, .prev = &name }
/*
* METAL_DECLARE_LIST - used for defining and initializing a global or
* static singleton list
*/
#define METAL_DECLARE_LIST(name) \
struct metal_list name = METAL_INIT_LIST(name)
static inline void metal_list_init(struct metal_list *list)
{
list->next = list->prev = list;
}
static inline void metal_list_add_before(struct metal_list *node,
struct metal_list *new_node)
{
new_node->prev = node->prev;
new_node->next = node;
new_node->next->prev = new_node;
new_node->prev->next = new_node;
}
static inline void metal_list_add_after(struct metal_list *node,
struct metal_list *new_node)
{
new_node->prev = node;
new_node->next = node->next;
new_node->next->prev = new_node;
new_node->prev->next = new_node;
}
static inline void metal_list_add_head(struct metal_list *list,
struct metal_list *node)
{
metal_list_add_after(list, node);
}
static inline void metal_list_add_tail(struct metal_list *list,
struct metal_list *node)
{
metal_list_add_before(list, node);
}
static inline int metal_list_is_empty(struct metal_list *list)
{
return list->next == list;
}
static inline void metal_list_del(struct metal_list *node)
{
node->next->prev = node->prev;
node->prev->next = node->next;
node->next = node->prev = node;
}
static inline struct metal_list *metal_list_first(struct metal_list *list)
{
return metal_list_is_empty(list) ? NULL : list->next;
}
#define metal_list_for_each(list, node) \
for ((node) = (list)->next; \
(node) != (list); \
(node) = (node)->next)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_LIST__H__ */

62
libmetal/lib/log.c Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdarg.h>
#include <stdio.h>
#include <metal/log.h>
#include <metal/sys.h>
void metal_default_log_handler(enum metal_log_level level,
const char *format, ...)
{
#ifdef DEFAULT_LOGGER_ON
char msg[1024];
va_list args;
static const char *level_strs[] = {
"metal: emergency: ",
"metal: alert: ",
"metal: critical: ",
"metal: error: ",
"metal: warning: ",
"metal: notice: ",
"metal: info: ",
"metal: debug: ",
};
va_start(args, format);
vsnprintf(msg, sizeof(msg), format, args);
va_end(args);
if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
level = METAL_LOG_EMERGENCY;
fprintf(stderr, "%s%s", level_strs[level], msg);
#else
(void)level;
(void)format;
#endif
}
void metal_set_log_handler(metal_log_handler handler)
{
_metal.common.log_handler = handler;
}
metal_log_handler metal_get_log_handler(void)
{
return _metal.common.log_handler;
}
void metal_set_log_level(enum metal_log_level level)
{
_metal.common.log_level = level;
}
enum metal_log_level metal_get_log_level(void)
{
return _metal.common.log_level;
}

93
libmetal/lib/log.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file log.h
* @brief Logging support for libmetal.
*/
#ifndef __METAL_METAL_LOG__H__
#define __METAL_METAL_LOG__H__
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup logging Library Logging Interfaces
* @{ */
/** Log message priority levels for libmetal. */
enum metal_log_level {
METAL_LOG_EMERGENCY, /**< system is unusable. */
METAL_LOG_ALERT, /**< action must be taken immediately. */
METAL_LOG_CRITICAL, /**< critical conditions. */
METAL_LOG_ERROR, /**< error conditions. */
METAL_LOG_WARNING, /**< warning conditions. */
METAL_LOG_NOTICE, /**< normal but significant condition. */
METAL_LOG_INFO, /**< informational messages. */
METAL_LOG_DEBUG, /**< debug-level messages. */
};
/** Log message handler type. */
typedef void (*metal_log_handler)(enum metal_log_level level,
const char *format, ...);
/**
* @brief Set libmetal log handler.
* @param[in] handler log message handler.
* @return 0 on success, or -errno on failure.
*/
extern void metal_set_log_handler(metal_log_handler handler);
/**
* @brief Get the current libmetal log handler.
* @return Current log handler.
*/
extern metal_log_handler metal_get_log_handler(void);
/**
* @brief Set the level for libmetal logging.
* @param[in] level log message level.
*/
extern void metal_set_log_level(enum metal_log_level level);
/**
* @brief Get the current level for libmetal logging.
* @return Current log level.
*/
extern enum metal_log_level metal_get_log_level(void);
/**
* @brief Default libmetal log handler. This handler prints libmetal log
* mesages to stderr.
* @param[in] level log message level.
* @param[in] format log message format string.
* @return 0 on success, or -errno on failure.
*/
extern void metal_default_log_handler(enum metal_log_level level,
const char *format, ...);
/**
* Emit a log message if the log level permits.
*
* @param level Log level.
* @param ... Format string and arguments.
*/
#define metal_log(level, ...) \
((level <= _metal.common.log_level && _metal.common.log_handler) \
? (void)_metal.common.log_handler(level, __VA_ARGS__) \
: (void)0)
/** @} */
#ifdef __cplusplus
}
#endif
#include <metal/system/@PROJECT_SYSTEM@/log.h>
#endif /* __METAL_METAL_LOG__H__ */

87
libmetal/lib/mutex.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file mutex.h
* @brief Mutex primitives for libmetal.
*/
#ifndef __METAL_MUTEX__H__
#define __METAL_MUTEX__H__
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup mutex Mutex Interfaces
* @{ */
#include <metal/system/@PROJECT_SYSTEM@/mutex.h>
/**
* @brief Initialize a libmetal mutex.
* @param[in] mutex Mutex to initialize.
*/
static inline void metal_mutex_init(metal_mutex_t *mutex)
{
__metal_mutex_init(mutex);
}
/**
* @brief Deinitialize a libmetal mutex.
* @param[in] mutex Mutex to deinitialize.
*/
static inline void metal_mutex_deinit(metal_mutex_t *mutex)
{
__metal_mutex_deinit(mutex);
}
/**
* @brief Try to acquire a mutex
* @param[in] mutex Mutex to mutex.
* @return 0 on failure to acquire, non-zero on success.
*/
static inline int metal_mutex_try_acquire(metal_mutex_t *mutex)
{
return __metal_mutex_try_acquire(mutex);
}
/**
* @brief Acquire a mutex
* @param[in] mutex Mutex to mutex.
*/
static inline void metal_mutex_acquire(metal_mutex_t *mutex)
{
__metal_mutex_acquire(mutex);
}
/**
* @brief Release a previously acquired mutex.
* @param[in] mutex Mutex to mutex.
* @see metal_mutex_try_acquire, metal_mutex_acquire
*/
static inline void metal_mutex_release(metal_mutex_t *mutex)
{
__metal_mutex_release(mutex);
}
/**
* @brief Checked if a mutex has been acquired.
* @param[in] mutex mutex to check.
* @see metal_mutex_try_acquire, metal_mutex_acquire
*/
static inline int metal_mutex_is_acquired(metal_mutex_t *mutex)
{
return __metal_mutex_is_acquired(mutex);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_MUTEX__H__ */

View File

@ -0,0 +1,3 @@
add_subdirectory (${PROJECT_PROCESSOR})
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,4 @@
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS cpu.h)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file gcc/atomic.h
* @brief GCC specific atomic primitives for libmetal.
*/
#ifndef __METAL_AARCH64_ATOMIC__H__
#define __METAL_AARCH64_ATOMIC__H__
#endif /* __METAL_ARM_ATOMIC__H__ */

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cpu.h
* @brief CPU specific primatives
*/
#ifndef __METAL_AARCH64_CPU__H__
#define __METAL_AARCH64_CPU__H__
#define metal_cpu_yield() asm volatile("yield")
#endif /* __METAL_AARCH64_CPU__H__ */

View File

@ -0,0 +1,4 @@
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS cpu.h)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file gcc/atomic.h
* @brief GCC specific atomic primitives for libmetal.
*/
#ifndef __METAL_ARM_ATOMIC__H__
#define __METAL_ARM_ATOMIC__H__
#endif /* __METAL_ARM_ATOMIC__H__ */

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cpu.h
* @brief CPU specific primatives
*/
#ifndef __METAL_ARM_CPU__H__
#define __METAL_ARM_CPU__H__
#define metal_cpu_yield()
#endif /* __METAL_ARM_CPU__H__ */

View File

@ -0,0 +1,4 @@
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS cpu.h)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file microblaze/atomic.h
* @brief Microblaze specific atomic primitives for libmetal
*/
#ifndef __METAL_MICROBLAZE_ATOMIC__H__
#define __METAL_MICROBLAZE_ATOMIC__H__
#endif /* __METAL_MICROBLAZE_ATOMIC__H__ */

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cpu.h
* @brief CPU specific primatives on microblaze platform.
*/
#ifndef __METAL_MICROBLAZE__H__
#define __METAL_MICROBLAZE__H__
#include <stdint.h>
#include <metal/atomic.h>
#define metal_cpu_yield()
static inline void metal_processor_io_write64(void *ptr, uint64_t value,
memory_order order)
{
void *tmp = &value;
atomic_store_explicit((atomic_ulong *)ptr, *((atomic_ulong *)tmp), order);
tmp += sizeof(atomic_ulong);
ptr += sizeof(atomic_ulong);
atomic_store_explicit((atomic_ulong *)ptr, *((atomic_ulong *)tmp), order);
}
static inline uint64_t metal_processor_io_read64(void *ptr, memory_order order)
{
uint64_t long_ret;
void *tmp = &long_ret;
*((atomic_ulong *)tmp) = atomic_load_explicit((atomic_ulong *)ptr, order);
tmp += sizeof(atomic_ulong);
ptr += sizeof(atomic_ulong);
*((atomic_ulong *)tmp) = atomic_load_explicit((atomic_ulong *)ptr, order);
return long_ret;
}
#endif /* __METAL_MICROBLAZE__H__ */

View File

@ -0,0 +1,4 @@
collect (PROJECT_LIB_HEADERS atomic.h)
collect (PROJECT_LIB_HEADERS cpu.h)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file gcc/atomic.h
* @brief GCC specific atomic primitives for libmetal.
*/
#ifndef __METAL_X86_64_ATOMIC__H__
#define __METAL_X86_64_ATOMIC__H__
#endif /* __METAL_X86_64_ATOMIC__H__ */

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file cpu.h
* @brief CPU specific primatives
*/
#ifndef __METAL_X86_64_CPU__H__
#define __METAL_X86_64_CPU__H__
#define metal_cpu_yield() asm volatile("rep; nop")
#endif /* __METAL_X86_64_CPU__H__ */

48
libmetal/lib/shmem.c Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file generic/shmem.c
* @brief Generic libmetal shared memory handling.
*/
#include <errno.h>
#include <metal/assert.h>
#include <metal/shmem.h>
#include <metal/sys.h>
#include <metal/utilities.h>
int metal_shmem_register_generic(struct metal_generic_shmem *shmem)
{
/* Make sure that we can be found. */
metal_assert(shmem->name && strlen(shmem->name) != 0);
/* Statically registered shmem regions cannot have a destructor. */
metal_assert(!shmem->io.ops.close);
metal_list_add_tail(&_metal.common.generic_shmem_list,
&shmem->node);
return 0;
}
int metal_shmem_open_generic(const char *name, size_t size,
struct metal_io_region **result)
{
struct metal_generic_shmem *shmem;
struct metal_list *node;
metal_list_for_each(&_metal.common.generic_shmem_list, node) {
shmem = metal_container_of(node, struct metal_generic_shmem, node);
if (strcmp(shmem->name, name) != 0)
continue;
if (size > metal_io_region_size(&shmem->io))
continue;
*result = &shmem->io;
return 0;
}
return -ENOENT;
}

83
libmetal/lib/shmem.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file shmem.h
* @brief Shared memory primitives for libmetal.
*/
#ifndef __METAL_SHMEM__H__
#define __METAL_SHMEM__H__
#include <metal/io.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup shmem Shared Memory Interfaces
* @{ */
/** Generic shared memory data structure. */
struct metal_generic_shmem {
const char *name;
struct metal_io_region io;
struct metal_list node;
};
/**
* @brief Open a libmetal shared memory segment.
*
* Open a shared memory segment.
*
* @param[in] name Name of segment to open.
* @param[in] size Size of segment.
* @param[out] io I/O region handle, if successful.
* @return 0 on success, or -errno on failure.
*
* @see metal_shmem_create
*/
extern int metal_shmem_open(const char *name, size_t size,
struct metal_io_region **io);
/**
* @brief Statically register a generic shared memory region.
*
* Shared memory regions may be statically registered at application
* initialization, or may be dynamically opened. This interface is used for
* static registration of regions. Subsequent calls to metal_shmem_open() look
* up in this list of pre-registered regions.
*
* @param[in] shmem Generic shmem structure.
* @return 0 on success, or -errno on failure.
*/
extern int metal_shmem_register_generic(struct metal_generic_shmem *shmem);
#ifdef METAL_INTERNAL
/**
* @brief Open a statically registered shmem segment.
*
* This interface is meant for internal libmetal use within system specific
* shmem implementations.
*
* @param[in] name Name of segment to open.
* @param[in] size Size of segment.
* @param[out] io I/O region handle, if successful.
* @return 0 on success, or -errno on failure.
*/
int metal_shmem_open_generic(const char *name, size_t size,
struct metal_io_region **result);
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_SHMEM__H__ */

44
libmetal/lib/sleep.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file sleep.h
* @brief Sleep primitives for libmetal.
*/
#ifndef __METAL_SLEEP__H__
#define __METAL_SLEEP__H__
#include <metal/system/@PROJECT_SYSTEM@/sleep.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup sleep Sleep Interfaces
* @{ */
/**
* @brief delay in microseconds
* delay the next execution in the calling thread
* fo usec microseconds.
*
* @param[in] usec microsecond intervals
* @return 0 on success, non-zero for failures
*/
static inline int metal_sleep_usec(unsigned int usec)
{
return __metal_sleep_usec(usec);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_SLEEP__H__ */

68
libmetal/lib/spinlock.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file spinlock.h
* @brief Spinlock primitives for libmetal.
*/
#ifndef __METAL_SPINLOCK__H__
#define __METAL_SPINLOCK__H__
#include <metal/atomic.h>
#include <metal/cpu.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup spinlock Spinlock Interfaces
* @{ */
struct metal_spinlock {
atomic_int v;
};
/** Static metal spinlock initialization. */
#define METAL_SPINLOCK_INIT {ATOMIC_VAR_INIT(0)}
/**
* @brief Initialize a libmetal spinlock.
* @param[in] slock Spinlock to initialize.
*/
static inline void metal_spinlock_init(struct metal_spinlock *slock)
{
atomic_store(&slock->v, 0);
}
/**
* @brief Acquire a spinlock.
* @param[in] slock Spinlock to acquire.
* @see metal_spinlock_release
*/
static inline void metal_spinlock_acquire(struct metal_spinlock *slock)
{
while (atomic_flag_test_and_set(&slock->v)) {
metal_cpu_yield();
}
}
/**
* @brief Release a previously acquired spinlock.
* @param[in] slock Spinlock to release.
* @see metal_spinlock_acquire
*/
static inline void metal_spinlock_release(struct metal_spinlock *slock)
{
atomic_flag_clear(&slock->v);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_SPINLOCK__H__ */

148
libmetal/lib/sys.h Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file sys.h
* @brief System primitives for libmetal.
* @brief Top level include internal to libmetal library code.
*/
#ifndef __METAL_SYS__H__
#define __METAL_SYS__H__
#include <stdlib.h>
#include <metal/log.h>
#include <metal/list.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup system Top Level Interfaces
* @{ */
/** Physical address type. */
typedef unsigned long metal_phys_addr_t;
/** Interrupt request number. */
typedef int metal_irq_t;
/** Bad offset into shared memory or I/O region. */
#define METAL_BAD_OFFSET ((unsigned long)-1)
/** Bad physical address value. */
#define METAL_BAD_PHYS ((metal_phys_addr_t)-1)
/** Bad virtual address value. */
#define METAL_BAD_VA ((void *)-1)
/** Bad IRQ. */
#define METAL_BAD_IRQ ((metal_irq_t)-1)
/**
* Initialization configuration for libmetal.
*/
struct metal_init_params {
/** log message handler (defaults to stderr). */
metal_log_handler log_handler;
/** default log message level (defaults to emergency). */
enum metal_log_level log_level;
};
/**
* System independent runtime state for libmetal. This is part of a system
* specific singleton data structure (@see _metal).
*/
struct metal_common_state {
/** Current log level. */
enum metal_log_level log_level;
/** Current log handler (null for none). */
metal_log_handler log_handler;
/** List of registered buses. */
struct metal_list bus_list;
/** Generic statically defined shared memory segments. */
struct metal_list generic_shmem_list;
/** Generic statically defined devices. */
struct metal_list generic_device_list;
};
struct metal_state;
#include <metal/system/@PROJECT_SYSTEM@/sys.h>
#ifndef METAL_INIT_DEFAULTS
#define METAL_INIT_DEFAULTS \
{ \
.log_handler = metal_default_log_handler, \
.log_level = METAL_LOG_INFO, \
}
#endif
/** System specific runtime data. */
extern struct metal_state _metal;
/**
* @brief Initialize libmetal.
*
* Initialize the libmetal library.
*
* @param[in] params Initialization params (@see metal_init_params).
*
* @return 0 on success, or -errno on failure.
*
* @see metal_finish
*/
extern int metal_init(const struct metal_init_params *params);
/**
* @brief Shutdown libmetal.
*
* Shutdown the libmetal library, and release all reserved resources.
*
* @see metal_init
*/
extern void metal_finish(void);
#ifdef METAL_INTERNAL
/**
* @brief libmetal system initialization.
*
* This function initializes libmetal on Linux or Generic platforms. This
* involves obtaining necessary pieces of system information (sysfs mount path,
* page size, etc.).
*
* @param[in] params Initialization parameters (@see metal_init_params).
* @return 0 on success, or -errno on failure.
*/
extern int metal_sys_init(const struct metal_init_params *params);
/**
* @brief libmetal system shutdown.
*
* This function shuts down and releases resources held by libmetal Linux or
* Generic platform layers.
*
* @see metal_sys_init
*/
extern void metal_sys_finish(void);
#endif
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_SYS__H__ */

View File

@ -0,0 +1,3 @@
add_subdirectory (${PROJECT_SYSTEM})
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,24 @@
collect (PROJECT_LIB_HEADERS alloc.h)
collect (PROJECT_LIB_HEADERS assert.h)
collect (PROJECT_LIB_HEADERS cache.h)
collect (PROJECT_LIB_HEADERS condition.h)
collect (PROJECT_LIB_HEADERS io.h)
collect (PROJECT_LIB_HEADERS irq.h)
collect (PROJECT_LIB_HEADERS log.h)
collect (PROJECT_LIB_HEADERS mutex.h)
collect (PROJECT_LIB_HEADERS sleep.h)
collect (PROJECT_LIB_HEADERS sys.h)
collect (PROJECT_LIB_SOURCES condition.c)
collect (PROJECT_LIB_SOURCES device.c)
collect (PROJECT_LIB_SOURCES init.c)
collect (PROJECT_LIB_SOURCES io.c)
collect (PROJECT_LIB_SOURCES irq.c)
collect (PROJECT_LIB_SOURCES shmem.c)
collect (PROJECT_LIB_SOURCES time.c)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE})
add_subdirectory(${PROJECT_MACHINE})
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE})
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/alloc.c
* @brief FreeRTOS libmetal memory allocattion definitions.
*/
#ifndef __METAL_ALLOC__H__
#error "Include metal/alloc.h instead of metal/freertos/alloc.h"
#endif
#ifndef __METAL_FREERTOS_ALLOC__H__
#define __METAL_FREERTOS_ALLOC__H__
#include "FreeRTOS.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void *metal_allocate_memory(unsigned int size)
{
return (pvPortMalloc(size));
}
static inline void metal_free_memory(void *ptr)
{
vPortFree(ptr);
}
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_ALLOC__H__ */

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file assert.h
* @brief FreeRTOS assertion support.
*/
#ifndef __METAL_ASSERT__H__
#error "Include metal/assert.h instead of metal/freertos/assert.h"
#endif
#ifndef __METAL_FREERTOS_ASSERT__H__
#define __METAL_FREERTOS_ASSERT__H__
#include <assert.h>
/**
* @brief Assertion macro for FreeRTOS applications.
* @param cond Condition to evaluate.
*/
#define metal_sys_assert(cond) assert(cond)
#endif /* __METAL_FREERTOS_ASSERT__H__ */

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/cache.h
* @brief FreeRTOS cache operation primitives for libmetal.
*/
#ifndef __METAL_CACHE__H__
#error "Include metal/cache.h instead of metal/freertos/cache.h"
#endif
#ifndef __METAL_FREERTOS_CACHE__H__
#define __METAL_FREERTOS_CACHE__H__
#ifdef __cplusplus
extern "C" {
#endif
extern void metal_machine_cache_flush(void *addr, unsigned int len);
extern void metal_machine_cache_invalidate(void *addr, unsigned int len);
static inline void __metal_cache_flush(void *addr, unsigned int len)
{
metal_machine_cache_flush(addr, len);
}
static inline void __metal_cache_invalidate(void *addr, unsigned int len)
{
metal_machine_cache_invalidate(addr, len);
}
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_CACHE__H__ */

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file generic/condition.c
* @brief Generic libmetal condition variable handling.
*/
#include <metal/condition.h>
int metal_condition_wait(struct metal_condition *cv,
metal_mutex_t *m)
{
/* TODO: Implement condition variable for FreeRTOS */
(void)cv;
(void)m;
return 0;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file generic/condition.h
* @brief Generic condition variable primitives for libmetal.
*/
#ifndef __METAL_CONDITION__H__
#error "Include metal/condition.h instead of metal/freertos/condition.h"
#endif
#ifndef __METAL_FREERTOS_CONDITION__H__
#define __METAL_FREERTOS_CONDITION__H__
#include <metal/atomic.h>
#ifdef __cplusplus
extern "C" {
#endif
struct metal_condition {
metal_mutex_t *m; /**< mutex.
The condition variable is attached to
this mutex when it is waiting.
It is also used to check correctness
in case there are multiple waiters. */
atomic_int v; /**< condition variable value. */
};
/** Static metal condition variable initialization. */
#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0) }
static inline void metal_condition_init(struct metal_condition *cv)
{
/* TODO: Implement condition variable for FreeRTOS */
(void)cv;
return;
}
static inline int metal_condition_signal(struct metal_condition *cv)
{
/* TODO: Implement condition variable for FreeRTOS */
(void)cv;
return 0;
}
static inline int metal_condition_broadcast(struct metal_condition *cv)
{
/* TODO: Implement condition variable for FreeRTOS */
(void)cv;
return 0;
}
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_CONDITION__H__ */

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/device.c
* @brief FreeRTOS device operations.
*/
#include <metal/device.h>
#include <metal/sys.h>
#include <metal/utilities.h>
int metal_generic_dev_sys_open(struct metal_device *dev)
{
struct metal_io_region *io;
unsigned i;
/* map I/O memory regions */
for (i = 0; i < dev->num_regions; i++) {
io = &dev->regions[i];
if (!io->size)
break;
metal_sys_io_mem_map(io);
}
return 0;
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/init.c
* @brief FreeRTOS libmetal initialization.
*/
#include <metal/sys.h>
#include <metal/utilities.h>
#include <metal/device.h>
struct metal_state _metal;
int metal_sys_init(const struct metal_init_params *params)
{
metal_unused(params);
metal_bus_register(&metal_generic_bus);
return 0;
}
void metal_sys_finish(void)
{
metal_bus_unregister(&metal_generic_bus);
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/io.c
* @brief FreeRTOS libmetal io operations
*/
#include <metal/io.h>
void metal_sys_io_mem_map(struct metal_io_region *io)
{
unsigned long p;
size_t psize;
void *va;
va = io->virt;
psize = io->size;
if (psize) {
if (psize >> io->page_shift)
psize = (size_t)1 << io->page_shift;
for (p = 0; p <= (io->size >> io->page_shift); p++) {
metal_machine_io_mem_map(va, io->physmap[p],
psize, io->mem_flags);
va += psize;
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/io.h
* @brief FreeRTOS specific io definitions.
*/
#ifndef __METAL_IO__H__
#error "Include metal/io.h instead of metal/freertos/io.h"
#endif
#ifndef __METAL_FREEROTS_IO__H__
#define __METAL_FREEROTS_IO__H__
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef METAL_INTERNAL
/**
* @brief memory mapping for an I/O region
*/
void metal_sys_io_mem_map(struct metal_io_region *io);
/**
* @brief memory mapping
*/
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
size_t size, unsigned int flags);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREEROTS_IO__H__ */

View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/irq.c
* @brief FreeRTOS libmetal irq definitions.
*/
#include <errno.h>
#include <metal/irq.h>
#include <metal/sys.h>
#include <metal/log.h>
#include <metal/mutex.h>
#include <metal/list.h>
#include <metal/utilities.h>
#include <metal/alloc.h>
/** IRQ handlers descriptor structure */
struct metal_irq_hddesc {
metal_irq_handler hd; /**< irq handler */
void *drv_id; /**< id to identify the driver
of the irq handler */
struct metal_device *dev; /**< device identifier */
struct metal_list node; /**< node on irq handlers list */
};
/** IRQ descriptor structure */
struct metal_irq_desc {
int irq; /**< interrupt number */
struct metal_list hdls; /**< interrupt handlers */
struct metal_list node; /**< node on irqs list */
};
/** IRQ state structure */
struct metal_irqs_state {
struct metal_list irqs; /**< interrupt descriptors */
metal_mutex_t irq_lock; /**< access lock */
};
static struct metal_irqs_state _irqs = {
.irqs = METAL_INIT_LIST(_irqs.irqs),
.irq_lock = METAL_MUTEX_INIT(_irqs.irq_lock),
};
int metal_irq_register(int irq,
metal_irq_handler hd,
struct metal_device *dev,
void *drv_id)
{
struct metal_irq_desc *irq_p = NULL;
struct metal_irq_hddesc *hdl_p;
struct metal_list *node;
unsigned int irq_flags_save;
if (irq < 0) {
metal_log(METAL_LOG_ERROR,
"%s: irq %d need to be a positive number\n",
__func__, irq);
return -EINVAL;
}
if ((drv_id == NULL) || (hd == NULL)) {
metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n",
__func__, irq);
return -EINVAL;
}
/* Search for irq in list */
metal_mutex_acquire(&_irqs.irq_lock);
metal_list_for_each(&_irqs.irqs, node) {
irq_p = metal_container_of(node, struct metal_irq_desc, node);
if (irq_p->irq == irq) {
struct metal_list *h_node;
/* Check if drv_id already exist */
metal_list_for_each(&irq_p->hdls, h_node) {
hdl_p = metal_container_of(h_node,
struct metal_irq_hddesc,
node);
/* if drv_id already exist reject */
if ((hdl_p->drv_id == drv_id) &&
((dev == NULL) || (hdl_p->dev == dev))) {
metal_log(METAL_LOG_ERROR,
"%s: irq %d already registered."
"Will not register again.\n",
__func__, irq);
metal_mutex_release(&_irqs.irq_lock);
return -EINVAL;
}
}
/* irq found and drv_id not used, get out of metal_list_for_each */
break;
}
}
/* Either need to add handler to an existing list or to a new one */
hdl_p = metal_allocate_memory(sizeof(struct metal_irq_hddesc));
if (hdl_p == NULL) {
metal_log(METAL_LOG_ERROR,
"%s: irq %d cannot allocate mem for drv_id %d.\n",
__func__, irq, drv_id);
metal_mutex_release(&_irqs.irq_lock);
return -ENOMEM;
}
hdl_p->hd = hd;
hdl_p->drv_id = drv_id;
hdl_p->dev = dev;
/* interrupt already registered, add handler to existing list*/
if ((irq_p != NULL) && (irq_p->irq == irq)) {
irq_flags_save = metal_irq_save_disable();
metal_list_add_tail(&irq_p->hdls, &hdl_p->node);
metal_irq_restore_enable(irq_flags_save);
metal_log(METAL_LOG_DEBUG, "%s: success, irq %d add drv_id %p \n",
__func__, irq, drv_id);
metal_mutex_release(&_irqs.irq_lock);
return 0;
}
/* interrupt was not already registered, add */
irq_p = metal_allocate_memory(sizeof(struct metal_irq_desc));
if (irq_p == NULL) {
metal_log(METAL_LOG_ERROR, "%s: irq %d cannot allocate mem.\n",
__func__, irq);
metal_mutex_release(&_irqs.irq_lock);
return -ENOMEM;
}
irq_p->irq = irq;
metal_list_init(&irq_p->hdls);
metal_list_add_tail(&irq_p->hdls, &hdl_p->node);
irq_flags_save = metal_irq_save_disable();
metal_list_add_tail(&_irqs.irqs, &irq_p->node);
metal_irq_restore_enable(irq_flags_save);
metal_log(METAL_LOG_DEBUG, "%s: success, added irq %d\n", __func__, irq);
metal_mutex_release(&_irqs.irq_lock);
return 0;
}
/* helper function for metal_irq_unregister() */
static void metal_irq_delete_node(struct metal_list *node, void *p_to_free)
{
unsigned int irq_flags_save;
irq_flags_save=metal_irq_save_disable();
metal_list_del(node);
metal_irq_restore_enable(irq_flags_save);
metal_free_memory(p_to_free);
}
int metal_irq_unregister(int irq,
metal_irq_handler hd,
struct metal_device *dev,
void *drv_id)
{
struct metal_irq_desc *irq_p;
struct metal_list *node;
if (irq < 0) {
metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n",
__func__, irq);
return -EINVAL;
}
/* Search for irq in list */
metal_mutex_acquire(&_irqs.irq_lock);
metal_list_for_each(&_irqs.irqs, node) {
irq_p = metal_container_of(node, struct metal_irq_desc, node);
if (irq_p->irq == irq) {
struct metal_list *h_node, *h_prenode;
struct metal_irq_hddesc *hdl_p;
unsigned int delete_count = 0;
metal_log(METAL_LOG_DEBUG, "%s: found irq %d\n",
__func__, irq);
/* Search through handlers */
metal_list_for_each(&irq_p->hdls, h_node) {
hdl_p = metal_container_of(h_node,
struct metal_irq_hddesc,
node);
if (((hd == NULL) || (hdl_p->hd == hd)) &&
((drv_id == NULL) || (hdl_p->drv_id == drv_id)) &&
((dev == NULL) || (hdl_p->dev == dev))) {
metal_log(METAL_LOG_DEBUG,
"%s: unregister hd=%p drv_id=%p dev=%p\n",
__func__, hdl_p->hd, hdl_p->drv_id, hdl_p->dev);
h_prenode = h_node->prev;
metal_irq_delete_node(h_node, hdl_p);
delete_count++;
h_node = h_prenode;
}
}
/* we did not find any handler to delete */
if (!delete_count) {
metal_log(METAL_LOG_DEBUG, "%s: No matching entry\n",
__func__);
metal_mutex_release(&_irqs.irq_lock);
return -ENOENT;
}
/* if interrupt handlers list is empty, unregister interrupt */
if (metal_list_is_empty(&irq_p->hdls)) {
metal_log(METAL_LOG_DEBUG,
"%s: handlers list empty, unregister interrupt\n",
__func__);
metal_irq_delete_node(node, irq_p);
}
metal_log(METAL_LOG_DEBUG, "%s: success\n", __func__);
metal_mutex_release(&_irqs.irq_lock);
return 0;
}
}
metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__);
metal_mutex_release(&_irqs.irq_lock);
return -ENOENT;
}
unsigned int metal_irq_save_disable(void)
{
sys_irq_save_disable();
return 0;
}
void metal_irq_restore_enable(unsigned int flags)
{
(void)flags;
sys_irq_restore_enable();
}
void metal_irq_enable(unsigned int vector)
{
sys_irq_enable(vector);
}
void metal_irq_disable(unsigned int vector)
{
sys_irq_disable(vector);
}
/**
* @brief default handler
*/
void metal_irq_isr(unsigned int vector)
{
struct metal_list *node;
struct metal_irq_desc *irq_p;
metal_list_for_each(&_irqs.irqs, node) {
irq_p = metal_container_of(node, struct metal_irq_desc, node);
if ((unsigned int)irq_p->irq == vector) {
struct metal_list *h_node;
struct metal_irq_hddesc *hdl_p;
metal_list_for_each(&irq_p->hdls, h_node) {
hdl_p = metal_container_of(h_node,
struct metal_irq_hddesc,
node);
(hdl_p->hd)(vector, hdl_p->drv_id);
}
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/irq.c
* @brief FreeRTOS libmetal irq definitions.
*/
#ifndef __METAL_IRQ__H__
#error "Include metal/irq.h instead of metal/freertos/irq.h"
#endif
#ifndef __METAL_FREERTOS_IRQ__H__
#define __METAL_FREERTOS_IRQ__H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief default interrupt handler
* @param[in] vector interrupt vector
*/
void metal_irq_isr(unsigned int vector);
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_IRQ__H__ */

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Linaro nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* @file freertos/log.h
* @brief FreeRTOS libmetal log handler definition.
*/
#ifndef __METAL_METAL_LOG__H__
#error "Include metal/log.h instead of metal/freertos/log.h"
#endif
#ifndef __METAL_FREERTOS_LOG__H__
#define __METAL_FREERTOS_LOG__H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_LOG__H__ */

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/mutex.h
* @brief FreeRTOS mutex primitives for libmetal.
*/
#ifndef __METAL_MUTEX__H__
#error "Include metal/mutex.h instead of metal/freertos/mutex.h"
#endif
#ifndef __METAL_FREERTOS_MUTEX__H__
#define __METAL_FREERTOS_MUTEX__H__
#include <metal/assert.h>
#include "FreeRTOS.h"
#include "semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
SemaphoreHandle_t m;
} metal_mutex_t;
/*
* METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct
* or global
*/
#define METAL_MUTEX_INIT(m) { NULL }
/*
* METAL_MUTEX_DEFINE - used for defining and initializing a global or
* static singleton mutex
*/
#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = METAL_MUTEX_INIT(m)
static inline void __metal_mutex_init(metal_mutex_t *mutex)
{
metal_assert(mutex);
mutex->m = xSemaphoreCreateMutex();
metal_assert(mutex->m != NULL);
}
static inline void __metal_mutex_deinit(metal_mutex_t *mutex)
{
metal_assert(mutex && mutex->m != NULL);
vSemaphoreDelete(mutex->m);
mutex->m=NULL;
}
static inline int __metal_mutex_try_acquire(metal_mutex_t *mutex)
{
metal_assert(mutex && mutex->m != NULL);
return xSemaphoreTake(mutex->m, ( TickType_t ) 0 );
}
static inline void __metal_mutex_acquire(metal_mutex_t *mutex)
{
metal_assert(mutex && mutex->m != NULL);
xSemaphoreTake(mutex->m, portMAX_DELAY);
}
static inline void __metal_mutex_release(metal_mutex_t *mutex)
{
metal_assert(mutex && mutex->m != NULL);
xSemaphoreGive(mutex->m);
}
static inline int __metal_mutex_is_acquired(metal_mutex_t *mutex)
{
metal_assert(mutex && mutex->m != NULL);
return (NULL == xSemaphoreGetMutexHolder(mutex->m)) ? 0 : 1;
}
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_MUTEX__H__ */

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/shmem.c
* @brief FreeRTOS libmetal shared memory handling.
*/
#include <metal/shmem.h>
int metal_shmem_open(const char *name, size_t size,
struct metal_io_region **io)
{
return metal_shmem_open_generic(name, size, io);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/sleep.h
* @brief FreeRTOS sleep primitives for libmetal.
*/
#ifndef __METAL_SLEEP__H__
#error "Include metal/sleep.h instead of metal/freertos/sleep.h"
#endif
#ifndef __METAL_FREERTOS_SLEEP__H__
#define __METAL_FREERTOS_SLEEP__H__
#include <FreeRTOS.h>
#include <task.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline int __metal_sleep_usec(unsigned int usec)
{
const TickType_t xDelay = usec / portTICK_PERIOD_MS;
vTaskDelay(xDelay);
return 0;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_SLEEP__H__ */

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/sys.h
* @brief FreeRTOS system primitives for libmetal.
*/
#ifndef __METAL_SYS__H__
#error "Include metal/sys.h instead of metal/freertos/sys.h"
#endif
#ifndef __METAL_FREERTOS_SYS__H__
#define __METAL_FREERTOS_SYS__H__
#include "./@PROJECT_MACHINE@/sys.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef METAL_MAX_DEVICE_REGIONS
#define METAL_MAX_DEVICE_REGIONS 1
#endif
/** Structure for FreeRTOS libmetal runtime state. */
struct metal_state {
/** Common (system independent) data. */
struct metal_common_state common;
};
#ifdef METAL_INTERNAL
/**
* @brief restore interrupts to state before disable_global_interrupt()
*/
void sys_irq_restore_enable(void);
/**
* @brief disable all interrupts
*/
void sys_irq_save_disable(void);
#endif /* METAL_INTERNAL */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_SYS__H__ */

View File

@ -0,0 +1,5 @@
collect (PROJECT_LIB_HEADERS sys.h)
collect (PROJECT_LIB_SOURCES sys.c)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2018, Linaro Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file generic/template/sys.c
* @brief machine specific system primitives implementation.
*/
#include <metal/io.h>
#include <metal/sys.h>
#include <metal/utilities.h>
#include <stdint.h>
void sys_irq_restore_enable(void)
{
/* Add implementation here */
}
void sys_irq_save_disable(void)
{
/* Add implementation here */
}
void sys_irq_enable(unsigned int vector)
{
metal_unused(vector);
/* Add implementation here */
}
void sys_irq_disable(unsigned int vector)
{
metal_unused(vector);
/* Add implementation here */
}
void metal_machine_cache_flush(void *addr, unsigned int len)
{
metal_unused(addr);
metal_unused(len);
/* Add implementation here */
}
void metal_machine_cache_invalidate(void *addr, unsigned int len)
{
metal_unused(addr);
metal_unused(len);
/* Add implementation here */
}
void metal_generic_default_poll(void)
{
/* Add implementation here */
}
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
size_t size, unsigned int flags)
{
metal_unused(pa);
metal_unused(size);
metal_unused(flags);
/* Add implementation here */
return va;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, Linaro Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/template/sys.h
* @brief freertos template system primitives for libmetal.
*/
#ifndef __METAL_FREERTOS_SYS__H__
#error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h"
#endif
#ifndef __METAL_FREERTOS_TEMPLATE_SYS__H__
#define __METAL_FREERTOS_TEMPLATE_SYS__H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef METAL_INTERNAL
void sys_irq_enable(unsigned int vector);
void sys_irq_disable(unsigned int vector);
#endif /* METAL_INTERNAL */
#ifdef __cplusplus
}
#endif
#endif /* __METAL_FREERTOS_SYS__H__ */

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/time.c
* @brief freertos libmetal time handling.
*/
#include <FreeRTOS.h>
#include <task.h>
#include <metal/time.h>
unsigned long long metal_get_timestamp(void)
{
return (unsigned long long)xTaskGetTickCount();
}

View File

@ -0,0 +1,5 @@
collect (PROJECT_LIB_HEADERS sys.h)
collect (PROJECT_LIB_SOURCES sys.c)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2014, Mentor Graphics Corporation
* Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* @file freertos/zynq7/sys.c
* @brief machine specific system primitives implementation.
*/
#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/sys.h>
#include <stdint.h>
#include "xil_cache.h"
#include "xil_exception.h"
#include "xil_mmu.h"
#include "xscugic.h"
/* Translation table is 16K in size */
#define ARM_AR_MEM_TTB_SIZE 16*1024
/* Each TTB descriptor covers a 1MB region */
#define ARM_AR_MEM_TTB_SECT_SIZE 1024*1024
/* Mask off lower bits of addr */
#define ARM_AR_MEM_TTB_SECT_SIZE_MASK (~(ARM_AR_MEM_TTB_SECT_SIZE-1UL))
/* default value setting for disabling interrupts */
static unsigned int int_old_val = XIL_EXCEPTION_ALL;
void sys_irq_restore_enable(void)
{
Xil_ExceptionEnableMask(~int_old_val);
}
void sys_irq_save_disable(void)
{
int_old_val = mfcpsr() & XIL_EXCEPTION_ALL;
if (XIL_EXCEPTION_ALL != int_old_val) {
Xil_ExceptionDisableMask(XIL_EXCEPTION_ALL);
}
}
void metal_machine_cache_flush(void *addr, unsigned int len)
{
if (!addr && !len)
Xil_DCacheFlush();
else
Xil_DCacheFlushRange((intptr_t)addr, len);
}
void metal_machine_cache_invalidate(void *addr, unsigned int len)
{
if (!addr && !len)
Xil_DCacheInvalidate();
else
Xil_DCacheInvalidateRange((intptr_t)addr, len);
}
/**
* @brief poll function until some event happens
*/
void metal_weak metal_generic_default_poll(void)
{
asm volatile("wfi");
}
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
size_t size, unsigned int flags)
{
unsigned int section_offset;
unsigned int ttb_addr;
if (!flags)
return va;
/* Ensure the virtual and physical addresses are aligned on a
section boundary */
pa &= ARM_AR_MEM_TTB_SECT_SIZE_MASK;
/* Loop through entire region of memory (one MMU section at a time).
Each section requires a TTB entry. */
for (section_offset = 0; section_offset < size;
section_offset += ARM_AR_MEM_TTB_SECT_SIZE) {
/* Calculate translation table entry for this memory section */
ttb_addr = (pa + section_offset);
/* Write translation table entry value to entry address */
Xil_SetTlbAttributes(ttb_addr, flags);
}
return va;
}

Some files were not shown because too many files have changed in this diff Show More