Skip to content

Commit

Permalink
Merge branch 'zephyrproject-rtos:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
mjchen0 authored Jun 28, 2023
2 parents d92f357 + 2f5068f commit 04931a5
Show file tree
Hide file tree
Showing 395 changed files with 8,088 additions and 2,384 deletions.
7 changes: 3 additions & 4 deletions MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,7 @@ Input:
- include/zephyr/input/
- samples/subsys/input/
- subsys/input/
- tests/drivers/build_all/input/
- tests/subsys/input/
description: >-
Input subsystem and drivers
Expand Down Expand Up @@ -1803,6 +1804,7 @@ Networking:
- rlubos
collaborators:
- tbursztyka
- ssharks
files:
- drivers/net/
- include/zephyr/net/
Expand Down Expand Up @@ -2441,15 +2443,12 @@ ITE Platforms:
- GTLin08
- RuibinChang
collaborators:
- Dino-Li
- GTLin08
- RuibinChang
- jackrosenthal
- keith-zephyr
- brockus-zephyr
- sjg20
files:
- boards/riscv/it8xxx2_evb/
- boards/riscv/it8*_evb/
- drivers/*/*/*it8xxx2*.c
- drivers/*/*it8xxx2*.c
- dts/bindings/*/*ite*
Expand Down
6 changes: 6 additions & 0 deletions arch/posix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,11 @@ if(NOT ${LLVM_SANITIZERS_ARG} STREQUAL "")
zephyr_link_libraries("${LLVM_SANITIZERS_ARG}")
endif()

# Override the C standard used for compilation to C 2011
# This is due to some tests using _Static_assert which is a 2011 feature, but
# otherwise relying on compilers supporting it also when set to C99.
# This was in general ok, but with some host compilers and C library versions
# it led to problems. So we override it to 2011 for native_posix.
set_property(GLOBAL PROPERTY CSTD c11)

add_subdirectory(core)
6 changes: 6 additions & 0 deletions arch/posix/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ zephyr_library_sources(
cpuhalt.c
fatal.c
irq.c
nsi_compat/nsi_compat.c
nsi_compat/nce.c
posix_core.c
swap.c
thread.c
)

zephyr_include_directories(
nsi_compat/
)
292 changes: 292 additions & 0 deletions arch/posix/core/nsi_compat/nce.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
/*
* Copyright (c) 2017 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* Native simulator CPU emulator,
* an *optional* module provided by the native simulator
* the hosted embedded OS / SW can use to emulate the CPU
* being started and stopped.
*
* Its mode of operation is that it step-locks the HW
* and SW operation, so that only one of them executes at
* a time. Check the docs for more info.
*/

#include <pthread.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include "nce_if.h"
#include "nsi_safe_call.h"

struct nce_status_t {
/* Conditional variable to know if the CPU is running or halted/idling */
pthread_cond_t cond_cpu;
/* Mutex for the conditional variable cond_cpu */
pthread_mutex_t mtx_cpu;
/* Variable which tells if the CPU is halted (1) or not (0) */
bool cpu_halted;
bool terminate; /* Are we terminating the program == cleaning up */
void (*start_routine)(void);
};

#define NCE_DEBUG_PRINTS 0

#define PREFIX "NCE: "
#define ERPREFIX PREFIX"error on "
#define NO_MEM_ERR PREFIX"Can't allocate memory\n"

#if NCE_DEBUG_PRINTS
#define NCE_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__)
#else
#define NCE_DEBUG(...)
#endif

extern void nsi_exit(int exit_code);

/*
* Initialize an instance of the native simulator CPU emulator
* and return a pointer to it.
* That pointer should be passed to all subsequent calls to this module.
*/
void *nce_init(void)
{
struct nce_status_t *this;

this = calloc(1, sizeof(struct nce_status_t));

if (this == NULL) { /* LCOV_EXCL_BR_LINE */
nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */
}
this->cpu_halted = true;
this->terminate = false;

NSI_SAFE_CALL(pthread_cond_init(&this->cond_cpu, NULL));
NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_cpu, NULL));

return (void *)this;
}

/*
* This function will:
*
* If called from a SW thread, release the HW thread which is blocked in
* a nce_wake_cpu() and never return.
*
* If called from a HW thread, do the necessary clean up of this nce instance
* and return right away.
*/
void nce_terminate(void *this_arg)
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

/* LCOV_EXCL_START */ /* See Note1 */
/*
* If we are being called from a HW thread we can cleanup
*
* Otherwise (!cpu_halted) we give back control to the HW thread and
* tell it to terminate ASAP
*/
if (this == NULL || this->cpu_halted) {
/*
* Note: The nce_status structure cannot be safely free'd up
* as the user is allowed to call nce_clean_up()
* repeatedly on the same structure.
* Instead we rely of on the host OS process cleanup.
* If you got here due to valgrind's leak report, please use the
* provided valgrind suppression file valgrind.supp
*/
return;
} else if (this->terminate == false) {

this->terminate = true;

NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));

this->cpu_halted = true;

NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu));
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));

while (1) {
sleep(1);
/* This SW thread will wait until being cancelled from
* the HW thread. sleep() is a cancellation point, so it
* won't really wait 1 second
*/
}
}
/* LCOV_EXCL_STOP */
}

/**
* Helper function which changes the status of the CPU (halted or running)
* and waits until somebody else changes it to the opposite
*
* Both HW and SW threads will use this function to transfer control to the
* other side.
*
* This is how the idle thread halts the CPU and gets halted until the HW models
* raise a new interrupt; and how the HW models awake the CPU, and wait for it
* to complete and go to idle.
*/
static void change_cpu_state_and_wait(struct nce_status_t *this, bool halted)
{
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));

NCE_DEBUG("Going to halted = %d\n", halted);

this->cpu_halted = halted;

/* We let the other side know the CPU has changed state */
NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu));

/* We wait until the CPU state has been changed. Either:
* we just awoke it, and therefore wait until the CPU has run until
* completion before continuing (before letting the HW models do
* anything else)
* or
* we are just hanging it, and therefore wait until the HW models awake
* it again
*/
while (this->cpu_halted == halted) {
/* Here we unlock the mutex while waiting */
pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu);
}

NCE_DEBUG("Awaken after halted = %d\n", halted);

NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));
}

/*
* Helper function that wraps the SW start_routine
*/
static void *sw_wrapper(void *this_arg)
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

/* Ensure nce_boot_cpu has reached the cond loop */
NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));

#if (NCE_DEBUG_PRINTS)
pthread_t sw_thread = pthread_self();

NCE_DEBUG("SW init started (%lu)\n",
sw_thread);
#endif

this->start_routine();
return NULL;
}

/*
* Boot the emulated CPU, that is:
* * Spawn a new pthread which will run the first embedded SW thread <start_routine>
* * Hold the caller until that embedded SW thread (or a child it spawns)
* calls nce_halt_cpu()
*
* Note that during this, an embedded SW thread may call nsi_exit(), which would result
* in this function never returning.
*/
void nce_boot_cpu(void *this_arg, void (*start_routine)(void))
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu));

this->cpu_halted = false;
this->start_routine = start_routine;

/* Create a thread for the embedded SW init: */
pthread_t sw_thread;

NSI_SAFE_CALL(pthread_create(&sw_thread, NULL, sw_wrapper, this_arg));

/* And we wait until the embedded OS has send the CPU to sleep for the first time */
while (this->cpu_halted == false) {
pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu);
}
NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu));

if (this->terminate) {
nsi_exit(0);
}
}

/*
* Halt the CPU, that is:
* * Hold this embedded SW thread until the CPU is awaken again,
* and release the HW thread which had been held on
* nce_boot_cpu() or nce_wake_cpu().
*
* Note: Can only be called from embedded SW threads
* Calling it from a HW thread is a programming error.
*/
void nce_halt_cpu(void *this_arg)
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

if (this->cpu_halted == true) {
nsi_print_error_and_exit("Programming error on: %s ",
"This CPU was already halted\n");
}
change_cpu_state_and_wait(this, true);
}

/*
* Awake the CPU, that is:
* * Hold this HW thread until the CPU is set to idle again
* * Release the SW thread which had been held on nce_halt_cpu()
*
* Note: Can only be called from HW threads
* Calling it from a SW thread is a programming error.
*/
void nce_wake_cpu(void *this_arg)
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

if (this->cpu_halted == false) {
nsi_print_error_and_exit("Programming error on: %s ",
"This CPU was already awake\n");
}
change_cpu_state_and_wait(this, false);

/*
* If while the SW was running it was decided to terminate the execution
* we stop immediately.
*/
if (this->terminate) {
nsi_exit(0);
}
}

/*
* Return 0 if the CPU is sleeping (or terminated)
* and !=0 if the CPU is running
*/
int nce_is_cpu_running(void *this_arg)
{
struct nce_status_t *this = (struct nce_status_t *)this_arg;

if (this != NULL) {
return !this->cpu_halted;
} else {
return false;
}
}

/*
* Notes about coverage:
*
* Note1: When the application is closed due to a SIGTERM, the path in this
* function will depend on when that signal was received. Typically during a
* regression run, both paths will be covered. But in some cases they won't.
* Therefore and to avoid confusing developers with spurious coverage changes
* we exclude this function from the coverage check
*/
26 changes: 26 additions & 0 deletions arch/posix/core/nsi_compat/nce_if.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NSI_COMMON_SRC_INCL_NCE_IF_H
#define NSI_COMMON_SRC_INCL_NCE_IF_H

#ifdef __cplusplus
extern "C" {
#endif

/* Native simulator CPU start/stop emulation module interface */

void *nce_init(void);
void nce_terminate(void *this);
void nce_boot_cpu(void *this, void (*start_routine)(void));
void nce_halt_cpu(void *this);
void nce_wake_cpu(void *this);
int nce_is_cpu_running(void *this);

#ifdef __cplusplus
}
#endif

#endif /* NSI_COMMON_SRC_INCL_NCE_IF_H */
Loading

0 comments on commit 04931a5

Please sign in to comment.