Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@ of Zephyr CMake project. Here is how to build libmetal for Zephyr:
$ make VERBOSE=1 run
```

### Building for QNX

To build libmetal for QNX, QNX SDP as well as configuration files from [ports/libmetal](https://github.com/qnx-ports/build-files/tree/main/ports/libmetal) are required. Here is how to build:

```
# Create QNX workspace and install source code
mkdir -p ~/qnx_workspace && cd ~/qnx_workspace
git clone https://github.com/qnx-ports/build-files
git clone https://github.com/OpenAMP/libmetal

# Source the environment
source ~/qnx800/qnxsdp-env.sh

#Build libmetal
make -C build-files/ports/libmetal install -j4
```

`x86_64` and `aarch64` specific `libmetal.so*` files will be created under `build-files/ports/libmetal/<arch>/build` as well as be installed in SDP under `<qnx-sdp>/target/qnx/<arch>/usr/local/lib`

**Note**: Custom build options or installation paths can be added to QNX build. For example

```
WITH_STATIC_LIB=ON WITH_TESTS=ON make -C build-files/ports/libmetal install -j4 USE_INSTALL_ROOT=true INSTALL_ROOT_nto=<staging-install-folder>
```

## Interfaces

The following subsections give an overview of interfaces provided by libmetal.
Expand Down
7 changes: 6 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ 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}
if (QNX)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/${f}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} RENAME ${PROJECT_NAME}/${f})
else (QNX)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/include/${PROJECT_NAME}/${f}
DESTINATION include RENAME ${PROJECT_NAME}/${f})
endif (QNX)
if (${f} MATCHES "^[^/]*\\.h")
collect (PROJECT_HDR_TESTS "metal/${f}")
endif (${f} MATCHES "^[^/]*\\.h")
Expand Down
21 changes: 21 additions & 0 deletions lib/system/qnx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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)
collect (PROJECT_LIB_SOURCES utilities.c)

collect (PROJECT_LIB_DEPS cache)
39 changes: 39 additions & 0 deletions lib/system/qnx/alloc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To update in all source file in this PR ( I will create a PR for the reste of the libmetal files)

Suggested change
/*
/**

* @file qnx/alloc.h
* @brief QNX libmetal memory allocation definitions.
*/

#ifndef __METAL_ALLOC__H__
#error "Include metal/alloc.h instead of metal/qnx/alloc.h"
#endif

#ifndef __METAL_QNX_ALLOC__H__
#define __METAL_QNX_ALLOC__H__

#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

static inline void *__metal_allocate_memory(unsigned int size)
{
return malloc(size);
}

static inline void __metal_free_memory(void *ptr)
{
free(ptr);
}

#ifdef __cplusplus
}
#endif

#endif /* __METAL_QNX_ALLOC__H__ */
27 changes: 27 additions & 0 deletions lib/system/qnx/assert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/assert.h
* @brief QNX libmetal assertion support.
*/

#ifndef __METAL_ASSERT__H__
#error "Include metal/assert.h instead of metal/qnx/assert.h"
#endif

#ifndef __METAL_QNX_ASSERT__H__
#define __METAL_QNX_ASSERT__H__

#include <assert.h>

/**
* @brief Assertion macro for QNX-based applications.
* @param cond Condition to evaluate.
*/
#define metal_sys_assert(cond) assert(cond)

#endif /* __METAL_QNX_ASSERT__H__ */
45 changes: 45 additions & 0 deletions lib/system/qnx/cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/cache.h
* @brief QNX cache operation primitives for libmetal.
*/

#ifndef __METAL_CACHE__H__
#error "Include metal/cache.h instead of metal/qnx/cache.h"
#endif

#ifndef __METAL_QNX_CACHE__H__
#define __METAL_QNX_CACHE__H__

#include <stdlib.h>
#include <sys/mman.h>
#include <sys/cache.h>
#include <metal/assert.h>
#include <metal/sys.h>

#ifdef __cplusplus
extern "C" {
#endif

extern struct cache_ctrl __qnx_cache_control;

static inline void __metal_cache_flush(void *addr, unsigned int len)
{
CACHE_FLUSH(&__qnx_cache_control, addr, (uint64_t)__qnx_get_physical_address(addr, len), len);

Check warning on line 33 in lib/system/qnx/cache.h

View workflow job for this annotation

GitHub Actions / compliance review

LONG_LINE

lib/system/qnx/cache.h:33 line over 100 characters
}

static inline void __metal_cache_invalidate(void *addr, unsigned int len)
{
CACHE_INVAL(&__qnx_cache_control, addr, (uint64_t)__qnx_get_physical_address(addr, len), len);

Check warning on line 38 in lib/system/qnx/cache.h

View workflow job for this annotation

GitHub Actions / compliance review

LONG_LINE

lib/system/qnx/cache.h:38 line over 100 characters
}

#ifdef __cplusplus
}
#endif

#endif /* __METAL_QNX_CACHE__H__ */
19 changes: 19 additions & 0 deletions lib/system/qnx/condition.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/condition.c
* @brief QNX libmetal condition variable handling.
*/

#include <metal/condition.h>

int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m)
{
int ret = pthread_cond_wait(&cv->cond, m);

return (ret == EOK) ? 0 : -ret;
}
59 changes: 59 additions & 0 deletions lib/system/qnx/condition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/condition.h
* @brief QNX condition variable primitives for libmetal.
*/

#ifndef __METAL_CONDITION__H__
#error "Include metal/condition.h instead of metal/qnx/condition.h"
#endif

#ifndef __METAL_QNX_CONDITION__H__
#define __METAL_QNX_CONDITION__H__

#include <pthread.h>
#include <metal/errno.h>
#include <metal/assert.h>

#ifdef __cplusplus
extern "C" {
#endif

struct metal_condition {
pthread_cond_t cond;
};

/*
* METAL_CONDITION_INIT - static metal condition variable initialization
*/
#define METAL_CONDITION_INIT { PTHREAD_COND_INITIALIZER }

static inline void metal_condition_init(struct metal_condition *cv)
{
metal_assert(pthread_cond_init(&cv->cond, NULL) == EOK);
}

static inline int metal_condition_signal(struct metal_condition *cv)
{
int ret = pthread_cond_signal(&cv->cond);

return (ret == EOK) ? 0 : -ret;
}

static inline int metal_condition_broadcast(struct metal_condition *cv)
{
int ret = pthread_cond_broadcast(&cv->cond);

return (ret == EOK) ? 0 : -ret;
}

#ifdef __cplusplus
}
#endif

#endif /* __METAL_QNX_CONDITION__H__ */
29 changes: 29 additions & 0 deletions lib/system/qnx/device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/device.c
* @brief QNX libmetal device operations.
*/

#include <metal/device.h>

int metal_generic_dev_sys_open(struct metal_device *dev)
{
struct metal_io_region *io;
unsigned int i, ret;

/* map I/O memory regions */
for (i = 0; i < dev->num_regions; i++) {
io = &dev->regions[i];
ret = metal_sys_io_mem_map(io);
if (ret != 0)
return ret;
}

return 0;
}

79 changes: 79 additions & 0 deletions lib/system/qnx/init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2025, BlackBerry Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

/*
* @file qnx/init.c
* @brief QNX libmetal initialization.
*/

#include <sys/types.h>
#include <metal/sys.h>
#include <metal/device.h>
#include <metal/irq.h>
#include <metal/cache.h>
#include <metal/utilities.h>

#include "irq.h"

struct metal_state _metal;
struct cache_ctrl __qnx_cache_control;
static int GENERIC_BUS_REGISTER;

static void metal_init_page_sizes(void)
{
_metal.page_size = sysconf(_SC_PAGESIZE);
_metal.page_shift = metal_log2(_metal.page_size);
}

int metal_sys_init(const struct metal_init_params *params)
{
int ret;

/* Initialize page size */
metal_init_page_sizes();

/* Initialize IRQ */
ret = metal_qnx_irq_init();
if (ret != 0) {
metal_log(METAL_LOG_ERROR, "irq init failed - %s\n",
strerror(-ret));
return ret;
}

/* Initialize cache */
memset(&__qnx_cache_control, 0, sizeof(__qnx_cache_control));
__qnx_cache_control.fd = NOFD;

ret = cache_init(0, &__qnx_cache_control, NULL);
if (ret == -1) {
metal_log(METAL_LOG_ERROR, "cache init failed - %s\n",
strerror(errno));
return -errno;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to initialize the cache and the IRQs here?
I the libmetal is only used for the openamp library porting layer. theses initialization are probably already done during your QNX system initialization.


/* Initialize generic bus */
ret = metal_bus_register(&metal_generic_bus);
if (ret != 0) {
metal_log(METAL_LOG_DEBUG, "generic bus init failed - %s\n",
strerror(-ret));
} else {
GENERIC_BUS_REGISTER = 1;
}

metal_unused(params);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to move at the beginning of the function


return 0;
}

void metal_sys_finish(void)
{
cache_fini(&__qnx_cache_control);
metal_qnx_irq_shutdown();
if (GENERIC_BUS_REGISTER) {
metal_bus_unregister(&metal_generic_bus);
}
}

Loading
Loading