Explorar el Código

feat(freertos): Added FreeRTOS POSIX/Linux Simulator

* Added port layer from the FreeRTOS POSIX port, added
  additional port code for ESP-IDF.
* Created another hello world example using that POSIX
  port in tools/test_apps.
* Removed old linux app
Jakob Hasse hace 3 años
padre
commit
bfbbd9d790
Se han modificado 28 ficheros con 1380 adiciones y 168 borrados
  1. 9 8
      .gitlab/ci/host-test.yml
  2. 37 0
      components/freertos/CMakeLists.txt
  3. 125 26
      components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro.h
  4. 98 0
      components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h
  5. 59 0
      components/freertos/FreeRTOS-Kernel/portable/linux/include/spinlock.h
  6. 564 0
      components/freertos/FreeRTOS-Kernel/portable/linux/port.c
  7. 164 0
      components/freertos/FreeRTOS-Kernel/portable/linux/port_idf.c
  8. 109 0
      components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.c
  9. 51 0
      components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.h
  10. 2 1
      components/freertos/Kconfig
  11. 27 3
      components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h
  12. 4 3
      docs/en/api-guides/linux-host-testing.rst
  13. 0 5
      examples/build_system/.build-test-rules.yml
  14. 0 10
      examples/build_system/cmake/linux_host_app/CMakeLists.txt
  15. 0 38
      examples/build_system/cmake/linux_host_app/README.md
  16. 0 1
      examples/build_system/cmake/linux_host_app/main/CMakeLists.txt
  17. 0 30
      examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp
  18. 0 3
      examples/build_system/cmake/linux_host_app/sdkconfig.defaults
  19. 0 1
      tools/ci/check_copyright_ignore.txt
  20. 9 4
      tools/mocks/freertos/CMakeLists.txt
  21. 19 10
      tools/mocks/freertos/Kconfig
  22. 0 25
      tools/mocks/freertos/include/FreeRTOSConfig.h
  23. 8 0
      tools/test_apps/.build-test-rules.yml
  24. 7 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/CMakeLists.txt
  25. 45 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/README.md
  26. 4 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt
  27. 24 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c
  28. 15 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/pytest_hello_world_linux_compatible.py

+ 9 - 8
.gitlab/ci/host-test.yml

@@ -380,6 +380,15 @@ test_esp_event:
     - idf.py build
     - build/test_esp_event_host.elf
 
+test_hello_world_linux_compatible_example:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/tools/test_apps/linux_compatible/hello_world_linux_compatible
+    - idf.py --preview set-target linux
+    - idf.py build
+    - timeout 15 build/hello_world.elf > test.log
+    - grep "Hello world!" test.log
+
 test_esp_timer_cxx:
   extends: .host_test_template
   script:
@@ -429,14 +438,6 @@ test_system_cxx:
     - idf.py build
     - build/test_system_cxx_host.elf
 
-test_linux_example:
-  extends: .host_test_template
-  script:
-    - cd ${IDF_PATH}/examples/build_system/cmake/linux_host_app
-    - idf.py build
-    - timeout 5 ./build/linux_host_app.elf >test.log || true
-    - grep "Restarting" test.log
-
 test_partition_api_host:
   extends: .host_test_template
   script:

+ 37 - 0
components/freertos/CMakeLists.txt

@@ -6,6 +6,43 @@ endif()
 
 idf_build_get_property(target IDF_TARGET)
 
+if(${target} STREQUAL "linux")
+    set(kernel_dir "FreeRTOS-Kernel")
+    set(srcs
+        "${kernel_dir}/portable/linux/port.c"
+        "${kernel_dir}/portable/linux/port_idf.c"
+        "${kernel_dir}/portable/linux/utils/wait_for_event.c"
+        "${kernel_dir}/list.c"
+        "${kernel_dir}/queue.c"
+        "${kernel_dir}/tasks.c"
+        "${kernel_dir}/timers.c"
+        )
+
+    set(include_dirs
+        ${kernel_dir}/include
+        ${kernel_dir}/portable/linux/include  # For arch-specific FreeRTOSConfig_arch.h in portable/<arch>/include
+        ${kernel_dir}/portable/linux/include/freertos
+        "esp_additions/include/freertos" # For config via #include "FreeRTOSConfig.h"
+        "esp_additions/include" # For #include "freertos/task_snapshot.h" and #include "freertos/FreeRTOSConfig.h"
+        )
+
+    set(private_include_dirs
+        ${kernel_dir}/portable/linux
+        ${kernel_dir}/portable/priv_include
+        ${kernel_dir}/include/freertos
+        .
+        )
+
+    idf_component_register(SRCS "${srcs}"
+                        INCLUDE_DIRS ${include_dirs}
+                        PRIV_INCLUDE_DIRS  ${private_include_dirs})
+
+    target_compile_definitions(${COMPONENT_LIB} PUBLIC "projCOVERAGE_TEST=0")
+    target_link_libraries(${COMPONENT_LIB} PUBLIC pthread)
+
+    return()
+endif()
+
 if(CONFIG_FREERTOS_SMP)
     set(ldfragments linker_smp.lf)
     if(CONFIG_IDF_TARGET_ARCH_XTENSA)

+ 125 - 26
components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro.h

@@ -1,42 +1,141 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * FreeRTOS Kernel V10.4.6
+ * Copyright 2020 Cambridge Consultants Ltd.
  *
- * SPDX-License-Identifier: Apache-2.0
+ * SPDX-FileCopyrightText: 2020 Cambridge Consultants Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
  */
 
-#pragma once
 
-#include "esp_attr.h"
-#include <stdint.h>
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+#include <limits.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define portBYTE_ALIGNMENT			16
-#define portTICK_TYPE_IS_ATOMIC		1
+/*-----------------------------------------------------------
+ * Port specific definitions.
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
 
 /* Type definitions. */
-#define portCHAR		uint8_t
-#define portFLOAT		float
-#define portDOUBLE		double
-#define portLONG		int32_t
-#define portSHORT		int16_t
-#define portSTACK_TYPE	uint8_t
-#define portBASE_TYPE	int
-// interrupt module will mask interrupt with priority less than threshold
-#define RVHAL_EXCM_LEVEL    4
-
-typedef portSTACK_TYPE			StackType_t;
-typedef portBASE_TYPE			BaseType_t;
-typedef unsigned portBASE_TYPE	UBaseType_t;
-typedef uint32_t TickType_t;
-#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
-
-typedef int portMUX_TYPE;
-
-#define portTICK_PERIOD_MS			( ( TickType_t ) 1 )
+#define portCHAR        char
+#define portFLOAT       float
+#define portDOUBLE      double
+#define portLONG        long
+#define portSHORT       short
+#define portSTACK_TYPE  unsigned long
+#define portBASE_TYPE   long
+#define portPOINTER_SIZE_TYPE intptr_t
+
+typedef portSTACK_TYPE StackType_t;
+typedef long BaseType_t;
+typedef unsigned long UBaseType_t;
+
+typedef unsigned long TickType_t;
+#define portMAX_DELAY ( TickType_t ) ULONG_MAX
+
+#define portTICK_TYPE_IS_ATOMIC 1
+
+/*-----------------------------------------------------------*/
+
+/* Architecture specifics. */
+#define portSTACK_GROWTH            ( -1 )
+#define portHAS_STACK_OVERFLOW_CHECKING ( 1 )
+#define portTICK_PERIOD_MS          ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
+#define portTICK_RATE_MICROSECONDS  ( ( TickType_t ) 1000000 / configTICK_RATE_HZ )
+#define portBYTE_ALIGNMENT          8
+/*-----------------------------------------------------------*/
+
+/* Scheduler utilities. */
+extern void vPortYield( void );
+
+#define portYIELD() vPortYield()
+
+#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) vPortYield()
+#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
+/*-----------------------------------------------------------*/
+
+/* Critical section management. */
+extern void vPortDisableInterrupts( void );
+extern void vPortEnableInterrupts( void );
+#define portSET_INTERRUPT_MASK()        ( vPortDisableInterrupts() )
+#define portCLEAR_INTERRUPT_MASK()      ( vPortEnableInterrupts() )
+
+extern portBASE_TYPE xPortSetInterruptMask( void );
+extern void vPortClearInterruptMask( portBASE_TYPE xMask );
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+#define portSET_INTERRUPT_MASK_FROM_ISR()       xPortSetInterruptMask()
+#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)    vPortClearInterruptMask(x)
+#define portDISABLE_INTERRUPTS()                portSET_INTERRUPT_MASK()
+#define portENABLE_INTERRUPTS()                 portCLEAR_INTERRUPT_MASK()
+#define portENTER_CRITICAL(mux)                 {(void)mux;  vPortEnterCritical();}
+#define portEXIT_CRITICAL(mux)                  {(void)mux;  vPortExitCritical();}
+#define portENTER_CRITICAL_ISR(mux)             portENTER_CRITICAL(mux)
+#define portEXIT_CRITICAL_ISR(mux)              portEXIT_CRITICAL(mux)
+
+/*-----------------------------------------------------------*/
+
+extern void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield );
+extern void vPortCancelThread( void *pxTaskToDelete );
+#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) vPortThreadDying( ( pvTaskToDelete ), ( pxPendYield ) )
+#define portCLEAN_UP_TCB( pxTCB )   vPortCancelThread( pxTCB )
+/*-----------------------------------------------------------*/
+
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+/*-----------------------------------------------------------*/
+
+/*
+ * Tasks run in their own pthreads and context switches between them
+ * are always a full memory barrier. ISRs are emulated as signals
+ * which also imply a full memory barrier.
+ *
+ * Thus, only a compilier barrier is needed to prevent the compiler
+ * reordering.
+ */
+#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
+
+extern unsigned long ulPortGetRunTime( void );
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() /* no-op */
+#define portGET_RUN_TIME_COUNTER_VALUE()         ulPortGetRunTime()
 
 #ifdef __cplusplus
 }
 #endif
+
+// We need additional definitions for ESP-IDF code
+#include "portmacro_idf.h"
+
+#endif /* PORTMACRO_H */

+ 98 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h

@@ -0,0 +1,98 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This is the "IDF-part" of the POSIX portmacro.
+ * We need additional definitions for code in ESP-IDF which is kept here to separate the original
+ * FreeRTOS POSIX port code from the additional IDF POSIX port code.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include "sdkconfig.h"
+#include "esp_attr.h"
+#include "spinlock.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// TODO: IDF-5983 From esp_task.h, should later be used from there
+// or be refactored in IDF (e.g. move esp_task.h to freertos)
+// See also configMINIMAL_STACK_SIZE for more information.
+#define CONFIG_ESP_MAIN_TASK_STACK_SIZE ( ( unsigned short ) (0x4000 + 40) / sizeof(portSTACK_TYPE) ) // should be in Kconfig again
+#define CONFIG_ESP_MAIN_TASK_AFFINITY   0
+
+#define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES)
+#define ESP_TASK_PRIO_MIN (0)
+#define ESP_TASK_MAIN_PRIO            (ESP_TASK_PRIO_MIN + 1)
+#define ESP_TASK_MAIN_STACK           (CONFIG_ESP_MAIN_TASK_STACK_SIZE)
+#define ESP_TASK_MAIN_CORE            CONFIG_ESP_MAIN_TASK_AFFINITY
+
+// interrupt module will mask interrupt with priority less than threshold
+#define RVHAL_EXCM_LEVEL    4
+
+typedef spinlock_t portMUX_TYPE;
+
+/**< Spinlock initializer */
+#define portMUX_INITIALIZER_UNLOCKED {                      \
+            .owner = portMUX_FREE_VAL,                      \
+            .count = 0,                                     \
+        }
+#define portMUX_FREE_VAL                    SPINLOCK_FREE           /**< Spinlock is free. [refactor-todo] check if this is still required */
+
+void vPortYieldFromISR(void);
+void vPortYieldOtherCore(BaseType_t coreid);
+
+#define portMUX_INITIALIZE(mux)             spinlock_initialize(mux)    /*< Initialize a spinlock to its unlocked state */
+
+/**
+ * @brief Get the current core's ID
+ *
+ * @note dummy function for freertos simulator, always returns 0.
+ @ return BaseType_t 0
+ */
+static inline BaseType_t IRAM_ATTR xPortGetCoreID(void)
+{
+    return (BaseType_t) 0;
+}
+
+static inline bool portVALID_TCB_MEM(const void *ptr)
+{
+    return true;
+}
+
+static inline bool portVALID_STACK_MEM(const void *ptr)
+{
+    return true;
+}
+
+#define pvPortMallocTcbMem(size)        pvPortMalloc(size)
+#define pvPortMallocStackMem(size)      pvPortMalloc(size)
+
+BaseType_t xPortCheckIfInISR(void);
+
+/**
+ * @brief Checks if the current core is in an ISR context
+ *
+ * - ISR context consist of Low/Mid priority ISR, or time tick ISR
+ * - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
+ *
+ * @note [refactor-todo] Check if this should be inlined
+ * @return
+ *  - pdTRUE if in ISR
+ *  - pdFALSE otherwise
+ */
+static inline BaseType_t xPortInIsrContext(void)
+{
+    //Just call the FreeRTOS port interface version
+    return xPortCheckIfInISR();
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 59 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/include/spinlock.h

@@ -0,0 +1,59 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This file provides only very simple stubs to build IDF-based FreeRTOSes which use spinlocks on Linux.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPINLOCK_FREE          0xB33FFFFF
+#define SPINLOCK_WAIT_FOREVER  (-1)
+#define SPINLOCK_NO_WAIT        0
+#define SPINLOCK_INITIALIZER   {.owner = SPINLOCK_FREE,.count = 0}
+#define CORE_ID_REGVAL_XOR_SWAP (0xCDCD ^ 0xABAB)
+
+/**
+ * @brief Spinlock object
+ * Owner:
+ *  - Set to 0 if uninitialized
+ *  - Set to portMUX_FREE_VAL when free
+ *  - Set to CORE_ID_REGVAL_PRO or CORE_ID_REGVAL_AP when locked
+ *  - Any other value indicates corruption
+ * Count:
+ *  - 0 if unlocked
+ *  - Recursive count if locked
+ *
+ * @note Not a true spinlock as single core RISC-V does not have atomic compare and set instruction
+ * @note Keep portMUX_INITIALIZER_UNLOCKED in sync with this struct
+ */
+typedef struct {
+    uint32_t owner;
+    uint32_t count;
+}spinlock_t;
+
+static inline void __attribute__((always_inline)) spinlock_initialize(spinlock_t *lock)
+{
+}
+
+static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *lock, int32_t timeout)
+{
+    return true;
+}
+
+static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *lock)
+{
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 564 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/port.c

@@ -0,0 +1,564 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.3
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the Posix port.
+ *
+ * Each task has a pthread which eases use of standard debuggers
+ * (allowing backtraces of tasks etc). Threads for tasks that are not
+ * running are blocked in sigwait().
+ *
+ * Task switch is done by resuming the thread for the next task by
+ * signaling the condition variable and then waiting on a condition variable
+ * with the current thread.
+ *
+ * The timer interrupt uses SIGALRM and care is taken to ensure that
+ * the signal handler runs only on the thread for the current task.
+ *
+ * Use of part of the standard C library requires care as some
+ * functions can take pthread mutexes internally which can result in
+ * deadlocks as the FreeRTOS kernel can switch tasks while they're
+ * holding a pthread mutex.
+ *
+ * stdio (printf() and friends) should be called from a single task
+ * only or serialized with a FreeRTOS primitive such as a binary
+ * semaphore or mutex.
+ *----------------------------------------------------------*/
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <time.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "utils/wait_for_event.h"
+/*-----------------------------------------------------------*/
+
+#define SIG_RESUME SIGUSR1
+
+typedef struct THREAD
+{
+    pthread_t pthread;
+    TaskFunction_t pxCode;
+    void *pvParams;
+    BaseType_t xDying;
+    struct event *ev;
+} Thread_t;
+
+/*
+ * The additional per-thread data is stored at the beginning of the
+ * task's stack.
+ */
+static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
+{
+StackType_t *pxTopOfStack = *(StackType_t **)xTask;
+
+    return (Thread_t *)(pxTopOfStack + 1);
+}
+
+/*-----------------------------------------------------------*/
+
+static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
+static sigset_t xAllSignals;
+static sigset_t xSchedulerOriginalSignalMask;
+static pthread_t hMainThread = ( pthread_t )NULL;
+static volatile portBASE_TYPE uxCriticalNesting;
+/*-----------------------------------------------------------*/
+
+static portBASE_TYPE xSchedulerEnd = pdFALSE;
+/*-----------------------------------------------------------*/
+
+static void prvSetupSignalsAndSchedulerPolicy( void );
+static void prvSetupTimerInterrupt( void );
+static void *prvWaitForStart( void * pvParams );
+static void prvSwitchThread( Thread_t * xThreadToResume,
+                             Thread_t *xThreadToSuspend );
+static void prvSuspendSelf( Thread_t * thread);
+static void prvResumeThread( Thread_t * xThreadId );
+static void vPortSystemTickHandler( int sig );
+static void vPortStartFirstTask( void );
+/*-----------------------------------------------------------*/
+
+static void prvFatalError( const char *pcCall, int iErrno )
+{
+    fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
+    abort();
+}
+
+/*
+ * See header file for description.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack,
+                                       portSTACK_TYPE *pxEndOfStack,
+                                       TaskFunction_t pxCode, void *pvParameters )
+{
+Thread_t *thread;
+pthread_attr_t xThreadAttributes;
+size_t ulStackSize;
+int iRet;
+
+    (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
+
+    /*
+     * Store the additional thread data at the start of the stack.
+     */
+    thread = (Thread_t *)(pxTopOfStack + 1) - 1;
+    pxTopOfStack = (portSTACK_TYPE *)thread - 1;
+    ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
+
+    thread->pxCode = pxCode;
+    thread->pvParams = pvParameters;
+    thread->xDying = pdFALSE;
+
+    pthread_attr_init( &xThreadAttributes );
+    pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
+
+    thread->ev = event_create();
+
+    vPortEnterCritical();
+
+    iRet = pthread_create( &thread->pthread, &xThreadAttributes,
+                           prvWaitForStart, thread );
+    if ( iRet )
+    {
+        prvFatalError( "pthread_create", iRet );
+    }
+
+    vPortExitCritical();
+
+    return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+void vPortStartFirstTask( void )
+{
+Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    /* Start the first task. */
+    prvResumeThread( pxFirstThread );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * See header file for description.
+ */
+portBASE_TYPE xPortStartScheduler( void )
+{
+int iSignal;
+sigset_t xSignals;
+
+    hMainThread = pthread_self();
+
+    /* Start the timer that generates the tick ISR(SIGALRM).
+       Interrupts are disabled here already. */
+    prvSetupTimerInterrupt();
+
+    /* Start the first task. */
+    vPortStartFirstTask();
+
+    /* Wait until signaled by vPortEndScheduler(). */
+    sigemptyset( &xSignals );
+    sigaddset( &xSignals, SIG_RESUME );
+
+    while ( !xSchedulerEnd )
+    {
+        sigwait( &xSignals, &iSignal );
+    }
+
+    /* Cancel the Idle task and free its resources */
+#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
+    vPortCancelThread( xTaskGetIdleTaskHandle() );
+#endif
+
+#if ( configUSE_TIMERS == 1 )
+    /* Cancel the Timer task and free its resources */
+    vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
+#endif /* configUSE_TIMERS */
+
+    /* Restore original signal mask. */
+    (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask,  NULL );
+
+    return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+struct itimerval itimer;
+struct sigaction sigtick;
+Thread_t *xCurrentThread;
+
+    /* Stop the timer and ignore any pending SIGALRMs that would end
+     * up running on the main thread when it is resumed. */
+    itimer.it_value.tv_sec = 0;
+    itimer.it_value.tv_usec = 0;
+
+    itimer.it_interval.tv_sec = 0;
+    itimer.it_interval.tv_usec = 0;
+    (void)setitimer( ITIMER_REAL, &itimer, NULL );
+
+    sigtick.sa_flags = 0;
+    sigtick.sa_handler = SIG_IGN;
+    sigemptyset( &sigtick.sa_mask );
+    sigaction( SIGALRM, &sigtick, NULL );
+
+    /* Signal the scheduler to exit its loop. */
+    xSchedulerEnd = pdTRUE;
+    (void)pthread_kill( hMainThread, SIG_RESUME );
+
+    xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+    prvSuspendSelf(xCurrentThread);
+}
+/*-----------------------------------------------------------*/
+
+void vPortEnterCritical( void )
+{
+    if ( uxCriticalNesting == 0 )
+    {
+        vPortDisableInterrupts();
+    }
+    uxCriticalNesting++;
+}
+/*-----------------------------------------------------------*/
+
+void vPortExitCritical( void )
+{
+    uxCriticalNesting--;
+
+    /* If we have reached 0 then re-enable the interrupts. */
+    if( uxCriticalNesting == 0 )
+    {
+        vPortEnableInterrupts();
+    }
+}
+/*-----------------------------------------------------------*/
+
+void vPortYieldFromISR( void )
+{
+Thread_t *xThreadToSuspend;
+Thread_t *xThreadToResume;
+
+    xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    vTaskSwitchContext();
+
+    xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    prvSwitchThread( xThreadToResume, xThreadToSuspend );
+}
+/*-----------------------------------------------------------*/
+
+void vPortYield( void )
+{
+    vPortEnterCritical();
+
+    vPortYieldFromISR();
+
+    vPortExitCritical();
+}
+/*-----------------------------------------------------------*/
+
+void vPortDisableInterrupts( void )
+{
+    pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
+}
+/*-----------------------------------------------------------*/
+
+void vPortEnableInterrupts( void )
+{
+    pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xPortSetInterruptMask( void )
+{
+    /* Interrupts are always disabled inside ISRs (signals
+       handlers). */
+    return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+void vPortClearInterruptMask( portBASE_TYPE xMask )
+{
+}
+/*-----------------------------------------------------------*/
+
+static uint64_t prvGetTimeNs(void)
+{
+struct timespec t;
+
+    clock_gettime(CLOCK_MONOTONIC, &t);
+
+    return t.tv_sec * 1000000000ull + t.tv_nsec;
+}
+
+static uint64_t prvStartTimeNs;
+/* commented as part of the code below in vPortSystemTickHandler,
+ * to adjust timing according to full demo requirements */
+/* static uint64_t prvTickCount; */
+
+/*
+ * Setup the systick timer to generate the tick interrupts at the required
+ * frequency.
+ */
+void prvSetupTimerInterrupt( void )
+{
+struct itimerval itimer;
+int iRet;
+
+    /* Initialise the structure with the current timer information. */
+    iRet = getitimer( ITIMER_REAL, &itimer );
+    if ( iRet )
+    {
+        prvFatalError( "getitimer", errno );
+    }
+
+    /* Set the interval between timer events. */
+    itimer.it_interval.tv_sec = 0;
+    itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
+
+    /* Set the current count-down. */
+    itimer.it_value.tv_sec = 0;
+    itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
+
+    /* Set-up the timer interrupt. */
+    iRet = setitimer( ITIMER_REAL, &itimer, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "setitimer", errno );
+    }
+
+    prvStartTimeNs = prvGetTimeNs();
+}
+/*-----------------------------------------------------------*/
+
+static void vPortSystemTickHandler( int sig )
+{
+Thread_t *pxThreadToSuspend;
+Thread_t *pxThreadToResume;
+/* uint64_t xExpectedTicks; */
+
+    uxCriticalNesting++; /* Signals are blocked in this signal handler. */
+
+#if ( configUSE_PREEMPTION == 1 )
+    pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+#endif
+
+    /* Tick Increment, accounting for any lost signals or drift in
+     * the timer. */
+/*
+ *      Comment code to adjust timing according to full demo requirements
+ *      xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
+ *        / (portTICK_RATE_MICROSECONDS * 1000);
+ * do { */
+        xTaskIncrementTick();
+/*        prvTickCount++;
+ *    } while (prvTickCount < xExpectedTicks);
+*/
+
+#if ( configUSE_PREEMPTION == 1 )
+    /* Select Next Task. */
+    vTaskSwitchContext();
+
+    pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
+#endif
+
+    uxCriticalNesting--;
+}
+/*-----------------------------------------------------------*/
+
+void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
+{
+Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
+
+    pxThread->xDying = pdTRUE;
+}
+
+void vPortCancelThread( void *pxTaskToDelete )
+{
+Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
+
+    /*
+     * The thread has already been suspended so it can be safely cancelled.
+     */
+    pthread_cancel( pxThreadToCancel->pthread );
+    pthread_join( pxThreadToCancel->pthread, NULL );
+    event_delete( pxThreadToCancel->ev );
+}
+/*-----------------------------------------------------------*/
+
+static void *prvWaitForStart( void * pvParams )
+{
+Thread_t *pxThread = pvParams;
+
+    prvSuspendSelf(pxThread);
+
+    /* Resumed for the first time, unblocks all signals. */
+    uxCriticalNesting = 0;
+    vPortEnableInterrupts();
+
+    /* Call the task's entry point. */
+    pxThread->pxCode( pxThread->pvParams );
+
+    /* A function that implements a task must not exit or attempt to return to
+    * its caller as there is nothing to return to. If a task wants to exit it
+    * should instead call vTaskDelete( NULL ). Artificially force an assert()
+    * to be triggered if configASSERT() is defined, so application writers can
+        * catch the error. */
+    configASSERT( pdFALSE );
+
+    return NULL;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSwitchThread( Thread_t *pxThreadToResume,
+                             Thread_t *pxThreadToSuspend )
+{
+BaseType_t uxSavedCriticalNesting;
+
+    if ( pxThreadToSuspend != pxThreadToResume )
+    {
+        /*
+         * Switch tasks.
+         *
+         * The critical section nesting is per-task, so save it on the
+         * stack of the current (suspending thread), restoring it when
+         * we switch back to this task.
+         */
+        uxSavedCriticalNesting = uxCriticalNesting;
+
+        prvResumeThread( pxThreadToResume );
+        if ( pxThreadToSuspend->xDying )
+        {
+            pthread_exit( NULL );
+        }
+        prvSuspendSelf( pxThreadToSuspend );
+
+        uxCriticalNesting = uxSavedCriticalNesting;
+    }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSuspendSelf( Thread_t *thread )
+{
+    /*
+     * Suspend this thread by waiting for a pthread_cond_signal event.
+     *
+     * A suspended thread must not handle signals (interrupts) so
+     * all signals must be blocked by calling this from:
+     *
+     * - Inside a critical section (vPortEnterCritical() /
+     *   vPortExitCritical()).
+     *
+     * - From a signal handler that has all signals masked.
+     *
+     * - A thread with all signals blocked with pthread_sigmask().
+        */
+    event_wait(thread->ev);
+}
+
+/*-----------------------------------------------------------*/
+
+static void prvResumeThread( Thread_t *xThreadId )
+{
+    if ( pthread_self() != xThreadId->pthread )
+    {
+        event_signal(xThreadId->ev);
+    }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupSignalsAndSchedulerPolicy( void )
+{
+struct sigaction sigresume, sigtick;
+int iRet;
+
+    hMainThread = pthread_self();
+
+    /* Initialise common signal masks. */
+    sigfillset( &xAllSignals );
+    /* Don't block SIGINT so this can be used to break into GDB while
+     * in a critical section. */
+    sigdelset( &xAllSignals, SIGINT );
+
+    /*
+     * Block all signals in this thread so all new threads
+     * inherits this mask.
+     *
+     * When a thread is resumed for the first time, all signals
+     * will be unblocked.
+     */
+    (void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
+                           &xSchedulerOriginalSignalMask );
+
+    /* SIG_RESUME is only used with sigwait() so doesn't need a
+       handler. */
+    sigresume.sa_flags = 0;
+    sigresume.sa_handler = SIG_IGN;
+    sigfillset( &sigresume.sa_mask );
+
+    sigtick.sa_flags = 0;
+    sigtick.sa_handler = vPortSystemTickHandler;
+    sigfillset( &sigtick.sa_mask );
+
+    iRet = sigaction( SIG_RESUME, &sigresume, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "sigaction", errno );
+    }
+
+    iRet = sigaction( SIGALRM, &sigtick, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "sigaction", errno );
+    }
+}
+/*-----------------------------------------------------------*/
+
+unsigned long ulPortGetRunTime( void )
+{
+struct tms xTimes;
+
+    times( &xTimes );
+
+    return ( unsigned long ) xTimes.tms_utime;
+}
+/*-----------------------------------------------------------*/

+ 164 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/port_idf.c

@@ -0,0 +1,164 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This file contains most of the code located in the demo application in the
+ * upstream FreeRTOS repository. It is put here so that IDF applications can
+ * seamlessly switch between Linux and chip targets without the need to provide
+ * or implement additional functionality if the target is the Linux target.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "utils/wait_for_event.h"
+#include "esp_log.h"
+
+static const char *TAG = "port";
+
+static volatile UBaseType_t uxInterruptNesting = 0;
+
+/* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
+ * use a callback function to optionally provide the memory required by the idle
+ * and timer tasks.  This is the stack that will be used by the timer task.  It is
+ * declared here, as a global, so it can be checked by a test that is implemented
+ * in a different file. */
+StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
+
+BaseType_t xPortCheckIfInISR(void)
+{
+    return uxInterruptNesting;
+}
+
+void app_main(void);
+
+static void main_task(void* args)
+{
+    app_main();
+    vTaskDelete(NULL);
+}
+
+int main(int argc, const char **argv)
+{
+    // This makes sure that stdio is flushed after each '\n' so that idf.py monitor
+    // reads the program output on time.
+    setvbuf(stdout, NULL, _IOLBF, 0);
+
+    usleep(1000);
+    portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
+                                                ESP_TASK_MAIN_STACK, NULL,
+                                                ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
+    assert(res == pdTRUE);
+    (void)res;
+
+    ESP_LOGI(TAG, "Starting scheduler.");
+    vTaskStartScheduler();
+
+    // This line should never be reached
+    assert(false);
+}
+
+void esp_vApplicationIdleHook(void)
+{
+    /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
+     * to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
+     * task.  It is essential that code added to this hook function never attempts
+     * to block in any way (for example, call xQueueReceive() with a block time
+     * specified, or call vTaskDelay()).  If application tasks make use of the
+     * vTaskDelete() API function to delete themselves then it is also important
+     * that vApplicationIdleHook() is permitted to return to its calling function,
+     * because it is the responsibility of the idle task to clean up memory
+     * allocated by the kernel to any task that has since deleted itself. */
+
+
+    usleep( 15000 );
+}
+
+void esp_vApplicationTickHook( void ) { }
+
+#if  (  configUSE_TICK_HOOK > 0 )
+void vApplicationTickHook( void )
+{
+    esp_vApplicationTickHook();
+}
+#endif
+
+void vPortYieldOtherCore( BaseType_t coreid ) { } // trying to skip for now
+
+/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
+ * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
+ * used by the Idle task. */
+void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
+                                    StackType_t ** ppxIdleTaskStackBuffer,
+                                    uint32_t * pulIdleTaskStackSize )
+{
+/* If the buffers to be provided to the Idle task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+    static StaticTask_t xIdleTaskTCB;
+    static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
+
+    /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
+     * state will be stored. */
+    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+    /* Pass out the array that will be used as the Idle task's stack. */
+    *ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+    /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+     * Note that, as the array is necessarily of type StackType_t,
+     * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+/*-----------------------------------------------------------*/
+
+/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
+ * application must provide an implementation of vApplicationGetTimerTaskMemory()
+ * to provide the memory that is used by the Timer service task. */
+void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
+                                     StackType_t ** ppxTimerTaskStackBuffer,
+                                     uint32_t * pulTimerTaskStackSize )
+{
+/* If the buffers to be provided to the Timer task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+    static StaticTask_t xTimerTaskTCB;
+
+    /* Pass out a pointer to the StaticTask_t structure in which the Timer
+     * task's state will be stored. */
+    *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
+
+    /* Pass out the array that will be used as the Timer task's stack. */
+    *ppxTimerTaskStackBuffer = uxTimerTaskStack;
+
+    /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
+     * Note that, as the array is necessarily of type StackType_t,
+     * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+
+void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
+{
+#define ERR_STR1 "***ERROR*** A stack overflow in task "
+#define ERR_STR2 " has been detected."
+    const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
+
+    char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = {0};
+
+    char *dest = buf;
+    for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
+        dest = strcat(dest, str[i]);
+    }
+	printf("%s\n", buf);
+    abort();
+}

+ 109 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.c

@@ -0,0 +1,109 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "wait_for_event.h"
+
+struct event
+{
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    bool event_triggered;
+};
+
+struct event * event_create()
+{
+    struct event * ev = malloc( sizeof( struct event ) );
+
+    ev->event_triggered = false;
+    pthread_mutex_init( &ev->mutex, NULL );
+    pthread_cond_init( &ev->cond, NULL );
+    return ev;
+}
+
+void event_delete( struct event * ev )
+{
+    pthread_mutex_destroy( &ev->mutex );
+    pthread_cond_destroy( &ev->cond );
+    free( ev );
+}
+
+bool event_wait( struct event * ev )
+{
+    pthread_mutex_lock( &ev->mutex );
+
+    while( ev->event_triggered == false )
+    {
+        pthread_cond_wait( &ev->cond, &ev->mutex );
+    }
+
+    ev->event_triggered = false;
+    pthread_mutex_unlock( &ev->mutex );
+    return true;
+}
+bool event_wait_timed( struct event * ev,
+                       time_t ms )
+{
+    struct timespec ts;
+    int ret = 0;
+
+    clock_gettime( CLOCK_REALTIME, &ts );
+    ts.tv_sec += ms / 1000;
+    ts.tv_nsec += ((ms % 1000) * 1000000);
+    pthread_mutex_lock( &ev->mutex );
+
+    while( (ev->event_triggered == false) && (ret == 0) )
+    {
+        ret = pthread_cond_timedwait( &ev->cond, &ev->mutex, &ts );
+
+        if( ( ret == -1 ) && ( errno == ETIMEDOUT ) )
+        {
+            return false;
+        }
+    }
+
+    ev->event_triggered = false;
+    pthread_mutex_unlock( &ev->mutex );
+    return true;
+}
+
+void event_signal( struct event * ev )
+{
+    pthread_mutex_lock( &ev->mutex );
+    ev->event_triggered = true;
+    pthread_cond_signal( &ev->cond );
+    pthread_mutex_unlock( &ev->mutex );
+}

+ 51 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.h

@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+#ifndef _WAIT_FOR_EVENT_H_
+#define _WAIT_FOR_EVENT_H_
+
+#include <stdbool.h>
+#include <time.h>
+
+struct event;
+
+struct event * event_create();
+void event_delete( struct event * );
+bool event_wait( struct event * ev );
+bool event_wait_timed( struct event * ev,
+                       time_t ms );
+void event_signal( struct event * ev );
+
+
+
+#endif /* ifndef _WAIT_FOR_EVENT_H_ */

+ 2 - 1
components/freertos/Kconfig

@@ -21,7 +21,7 @@ menu "FreeRTOS"
         config FREERTOS_UNICORE
             # Todo: Replace with CONFIG_NUM_CORES (IDF-4986)
             bool "Run FreeRTOS only on first core"
-            default "y" if IDF_TARGET_ESP32S2
+            default "y" if IDF_TARGET_ESP32S2 || IDF_TARGET_LINUX
             select ESP_SYSTEM_SINGLE_CORE_MODE
             help
                 This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want
@@ -169,6 +169,7 @@ menu "FreeRTOS"
         config FREERTOS_TIMER_TASK_STACK_DEPTH
             int "configTIMER_TASK_STACK_DEPTH"
             range 1536 32768
+            default 2053 if IDF_TARGET_LINUX
             default 2048
             help
                 Set the timer task's stack size (see configTIMER_TASK_STACK_DEPTH documentation for more details).

+ 27 - 3
components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h

@@ -102,8 +102,17 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #endif //configUSE_TICKLESS_IDLE
 #define configCPU_CLOCK_HZ                              (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * 1000000)
 #define configTICK_RATE_HZ                              CONFIG_FREERTOS_HZ
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configMAX_PRIORITIES                            ( 7 ) // Default in upstream simulator
+/* The stack allocated by FreeRTOS will be passed passed to a pthread.
+   pthread has a minimal stack size which currently is 16KB.
+   The rest is for additional structures of the POSIX/Linux port.
+   This is a magic number since PTHREAD_STACK_MIN seems to not be a constant. */
+#define configMINIMAL_STACK_SIZE                        ( ( unsigned short ) (0x4000 + 40) / sizeof(portSTACK_TYPE) )
+#else
 #define configMAX_PRIORITIES                            ( 25 )  //This has impact on speed of search for highest priority
 #define configMINIMAL_STACK_SIZE                        ( 768 + configSTACK_OVERHEAD_TOTAL )
+#endif
 #define configUSE_TIME_SLICING                          1
 #define configUSE_16_BIT_TICKS                          0
 #define configIDLE_SHOULD_YIELD                         0
@@ -123,9 +132,12 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 
 #define configMAX_TASK_NAME_LEN                         CONFIG_FREERTOS_MAX_TASK_NAME_LEN
 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS         CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
-#ifndef CONFIG_IDF_TARGET_LINUX
 #define configSTACK_DEPTH_TYPE                          uint32_t
+#ifndef CONFIG_IDF_TARGET_LINUX
 #define configUSE_NEWLIB_REENTRANT                      1
+#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       1
+#else
+#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       0 // Default in upstream simulator
 #endif
 #if CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY
 #define configENABLE_BACKWARD_COMPATIBILITY             1
@@ -133,15 +145,18 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define configENABLE_BACKWARD_COMPATIBILITY             0
 #endif
 #define configASSERT(a)                                 assert(a)
-#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       1
 
 // ----------------------- Memory  -------------------------
 
 #define configSUPPORT_STATIC_ALLOCATION                 1
 #define configSUPPORT_DYNAMIC_ALLOCATION                1
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configTOTAL_HEAP_SIZE                           ( ( size_t ) ( 65 * 1024 ) ) // Default in upstream simulator
+#else
 //We define the heap to span all of the non-statically-allocated shared RAM. ToDo: Make sure there
 //is some space left for the app and main cpu when running outside of a thread.
 #define configTOTAL_HEAP_SIZE                           (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) )
+#endif
 #define configAPPLICATION_ALLOCATED_HEAP                1
 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP       0
 
@@ -163,9 +178,13 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
 #define configGENERATE_RUN_TIME_STATS                   1   /* Used by vTaskGetRunTimeStats() */
 #endif
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configUSE_TRACE_FACILITY                        1
+#else
 #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
 #define configUSE_TRACE_FACILITY                        1   /* Used by uxTaskGetSystemState(), and other trace facility functions */
 #endif
+#endif
 #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
 #define configUSE_STATS_FORMATTING_FUNCTIONS            1   /* Used by vTaskList() */
 #endif
@@ -194,7 +213,6 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define INCLUDE_uxTaskPriorityGet                       1
 #define INCLUDE_vTaskDelete                             1
 #define INCLUDE_vTaskSuspend                            1
-#define INCLUDE_xTaskDelayUntil                         1
 #define INCLUDE_vTaskDelay                              1
 #define INCLUDE_xTaskGetIdleTaskHandle                  1
 #define INCLUDE_xTaskAbortDelay                         1
@@ -206,7 +224,13 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define INCLUDE_xTaskResumeFromISR                      1
 #define INCLUDE_xTimerPendFunctionCall                  1
 #define INCLUDE_xTaskGetSchedulerState                  1
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define INCLUDE_xTaskGetCurrentTaskHandle               0 // not defined in POSIX simulator
+#define INCLUDE_vTaskDelayUntil                         1
+#else
+#define INCLUDE_xTaskDelayUntil                         1
 #define INCLUDE_xTaskGetCurrentTaskHandle               1
+#endif
 //Unlisted
 #define INCLUDE_pxTaskGetStackStart                     1
 

+ 4 - 3
docs/en/api-guides/linux-host-testing.rst

@@ -36,10 +36,11 @@ The current focus of the Linux host tests is on creating isolated unit tests of
 
 A complete implementation of IDF to run on Linux does not exist currently.
 
-There are currently two examples for running IDF-built code on Linux host: 
+Examples for running IDF-built code on Linux host include (non-exhaustive list): 
 
-- An example :example_file:`hello-world application <build_system/cmake/linux_host_app/README.md>` 
-- A :component_file:`unit test for NVS <nvs_flash/host_test/nvs_page_test/README.md>`.
+- :component_file:`unit test for the NVS Page class <nvs_flash/host_test/nvs_page_test/README.md>`.
+- :component_file:`unit test for esp_event <esp_event/host_test/esp_event_unit_test/main/esp_event_test.cpp>`.
+- :component_file:`unit test for mqtt <mqtt/host_test/README.md>`.
 
 Inside the component which should be tested, there is a separate directory ``host_test``, besides the "traditional" ``test`` directory or the ``test_apps`` directory. It has one or more subdirectories::
 

+ 0 - 5
examples/build_system/.build-test-rules.yml

@@ -6,11 +6,6 @@ examples/build_system/cmake/import_lib:
       temporary: true
       reason: lack of runners
 
-examples/build_system/cmake/linux_host_app:
-  enable:
-    - if: IDF_TARGET == "linux"
-      reason: only test on linux
-
 examples/build_system/cmake/plugins:
   disable_test:
     - if: IDF_TARGET not in ["esp32", "esp32c3"]

+ 0 - 10
examples/build_system/cmake/linux_host_app/CMakeLists.txt

@@ -1,10 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-
-include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-set(COMPONENTS main)
-
-# Freertos is included via common components, however, currently only the mock component is compatible with linux
-# target.
-list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
-
-project(linux_host_app)

+ 0 - 38
examples/build_system/cmake/linux_host_app/README.md

@@ -1,38 +0,0 @@
-| Supported Targets | Linux |
-| ----------------- | ----- |
-
-This hello-world example builds a simple hello-world application for Linux.
-The compiler used is the Linux-gcc.
-
-There are two major differences to an IDF application built for an ESP chip compared to an application build for Linux:
-
-1. The entry-point on Linux is `int main(int argc, char **argv)`, instead of `void app_main(void)` on an ESP chip.
-   In this example for Linux, the `void app_main(void)` function is still included to make the connection to the IDF entry point clearer.
-   However, it is simply called by `int main(int argc, char **argv)`.
-   Refer to the source file [linux_host_app.cpp](main/linux_host_app.cpp) to see how it is used.
-
-2. The project-level [CMakeLists.txt](CMakeLists.txt) for Linux is different from that of a normal IDF application for an ESP chip.
-   On Linux, there is an additional line `set(COMPONENTS main)`, which clears the common requirements (default dependencies usually included in all IDF applications).
-   This is currently necessary as the Linux-host feature is still under development.
-   Otherwise, a lot of hardware-dependent code would be pulled in.
-
-# Requirements
-Currently, Ruby is required for the mock override of FreeRTOS.
-
-# Build
-Source the IDF environment as usual, then set the Linux target:
-```bash
-idf.py --preview set-target linux
-```
-sdkconfig.defaults sets the Linux target by default, so this not strictly necessary.
-
-Once this is done, build the application:
-```bash
-idf.py build
-```
-Since this application runs on host, the flashing step is unnecessary.
-
-# Run
-```bash
-`build/linux_host_app.elf`
-```

+ 0 - 1
examples/build_system/cmake/linux_host_app/main/CMakeLists.txt

@@ -1 +0,0 @@
-idf_component_register(SRCS "linux_host_app.cpp")

+ 0 - 30
examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp

@@ -1,30 +0,0 @@
-/* Hello World Example
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-
-#include "stdio.h"
-#include <unistd.h>
-
-void app_main() {
-    while(1) {
-        printf("Hello, Host!\n");
-
-        for (int i = 10; i >= 0; i--) {
-            printf("Restarting in %d seconds...\n", i);
-            sleep(1);
-        }
-    }
-}
-
-int main(int argc, char **argv)
-{
-    setbuf(stdout, NULL);
-    app_main();
-
-    return 0;
-}

+ 0 - 3
examples/build_system/cmake/linux_host_app/sdkconfig.defaults

@@ -1,3 +0,0 @@
-CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
-CONFIG_IDF_TARGET="linux"
-CONFIG_COMPILER_CXX_EXCEPTIONS=y

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -1582,7 +1582,6 @@ examples/build_system/cmake/import_prebuilt/main/main.c
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.c
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.h
 examples/build_system/cmake/import_prebuilt/prebuilt/main/main.c
-examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp
 examples/build_system/cmake/multi_config/main/func.h
 examples/build_system/cmake/multi_config/main/func_dev.c
 examples/build_system/cmake/multi_config/main/func_prod.c

+ 9 - 4
tools/mocks/freertos/CMakeLists.txt

@@ -4,13 +4,15 @@ message(STATUS "building FREERTOS MOCKS (only task, event-groups and queue)")
 
 idf_component_get_property(original_freertos_dir freertos COMPONENT_OVERRIDEN_DIR)
 
+set(kernel_dir "${original_freertos_dir}/FreeRTOS-Kernel")
+
 set(include_dirs
-    "include"
-    "${original_freertos_dir}/FreeRTOS-Kernel/include"
+    "${kernel_dir}/include"
     "${original_freertos_dir}/esp_additions/include"
     "${original_freertos_dir}/esp_additions/include/freertos"
-    "${original_freertos_dir}/FreeRTOS-Kernel/include/freertos" # this is due to the way includes are generated in CMock
-    "${original_freertos_dir}/FreeRTOS-Kernel/portable/linux/include")
+    "${kernel_dir}/portable/linux/include" # For FreeRTOSConfig_arch.h
+    "${kernel_dir}/include/freertos" # this is due to the way includes are generated in CMock (without freertos prefix)
+)
 
 idf_component_mock(INCLUDE_DIRS ${include_dirs}
     REQUIRES esp_common
@@ -18,3 +20,6 @@ idf_component_mock(INCLUDE_DIRS ${include_dirs}
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/task.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/event_groups.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/queue.h)
+
+idf_component_get_property(freertos_lib freertos COMPONENT_LIB)
+target_compile_definitions(${freertos_lib} PUBLIC "projCOVERAGE_TEST=0")

+ 19 - 10
tools/mocks/freertos/Kconfig

@@ -1,13 +1,22 @@
 menu "FreeRTOS"
-    config FREERTOS_MAX_TASK_NAME_LEN
-        int "Maximum task name length"
-        range 1 256
-        default 16
-        help
-            Changes the maximum task name length. Each task allocated will
-            include this many bytes for a task name. Using a shorter value
-            saves a small amount of RAM, a longer value allows more complex
-            names.
 
-            For most uses, the default of 16 is OK.
+    menu "Kernel"
+        config FREERTOS_HZ
+            int "configTICK_RATE_HZ"
+            range 1 1000
+            default 1000
+            help
+                Sets the FreeRTOS tick interrupt frequency in Hz (see configTICK_RATE_HZ documentation for more
+                details).
+
+        config FREERTOS_MAX_TASK_NAME_LEN
+            int "configMAX_TASK_NAME_LEN"
+            range 1 256
+            default 16
+            help
+                Sets the maximum number of characters for task names (see configMAX_TASK_NAME_LEN documentation for
+                more details).
+
+                Note: For most uses, the default of 16 characters is sufficient.
+    endmenu
 endmenu

+ 0 - 25
tools/mocks/freertos/include/FreeRTOSConfig.h

@@ -1,25 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#define STACK_OVERHEAD_CHECKER                          256
-#define STACK_OVERHEAD_OPTIMIZATION                     320
-#define STACK_OVERHEAD_APPTRACE                         1280
-#define STACK_OVERHEAD_WATCHPOINT                       60
-#define configSTACK_OVERHEAD_TOTAL (                              \
-                                    STACK_OVERHEAD_CHECKER +      \
-                                    STACK_OVERHEAD_OPTIMIZATION + \
-                                    STACK_OVERHEAD_APPTRACE +     \
-                                    STACK_OVERHEAD_WATCHPOINT     \
-                                                            )
-#define configMINIMAL_STACK_SIZE                        ( 768 + configSTACK_OVERHEAD_TOTAL )
-#define configMAX_PRIORITIES                            ( 25 )  //This has impact on speed of search for highest priority
-#define configUSE_PREEMPTION                            1
-#define configUSE_IDLE_HOOK                             CONFIG_FREERTOS_USE_IDLE_HOOK
-#define configUSE_TICK_HOOK                             CONFIG_FREERTOS_USE_TICK_HOOK
-#define configUSE_16_BIT_TICKS                          0
-#define configUSE_TRACE_FACILITY 1
-#define configSUPPORT_DYNAMIC_ALLOCATION                1
-#define configUSE_MUTEXES                               1
-#define configUSE_RECURSIVE_MUTEXES                     1

+ 8 - 0
tools/test_apps/.build-test-rules.yml

@@ -11,6 +11,14 @@ tools/test_apps/build_system/ldgen_test:
       temporary: true
       reason: target esp32c2 is not supported yet
 
+tools/test_apps/linux_compatible/hello_world_linux_compatible:
+  enable:
+    - if: INCLUDE_DEFAULT == 1 or IDF_TARGET == "linux"
+  disable_test:
+    - if: IDF_TARGET not in ["esp32", "esp32c3"]
+      temporary: true
+      reason: pytest doesn't support linux target yet, hence, it's tested independenly in the host_tests stage
+
 tools/test_apps/peripherals/usb:
   enable:
     - if: IDF_TARGET in ["esp32s2", "esp32s3"]

+ 7 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/CMakeLists.txt

@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(COMPONENTS main)
+project(hello_world)

+ 45 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/README.md

@@ -0,0 +1,45 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | Linux |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | ----- |
+
+# Hello World Example Compatible with POSIX-port
+
+This is a version of the "Hello World" example compatible with the linux target. Just by using `idf.py (--preview) set-target <target>`, it can be compiled for chip targets as well as for the [FreeRTOS POSIX/Linux simulator](https://www.freertos.org/FreeRTOS-simulator-for-Linux.html), i.e., for running it on Linux. The applications can then be run on the chosen target.
+
+## Requirements
+
+If you want to use this example on Linux, you need a Linux machine as host. The remaining requirements are the same requirements as for [Unit Testing on Linux (using cmock)](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/linux-host-testing.html#requirements), except you do not need Ruby.
+
+## How to use example
+
+### Configure the project
+
+No special configuration is required, we also do not recommend changing configuration when compiled for the POSIX/Linux simulator as this is still in preview. If you have to configure something, use the usual IDF menuconfig:
+```
+idf.py menuconfig
+```
+
+### Build and Flash
+
+You can compile this example for chip targets, e.g. ESP32 and then run it by using:
+```
+idf.py set-target esp32
+idf.py build
+idf.py -p <port> flash monitor
+```
+
+If you want to build this example for the linux target and run it, use the same commands except setting the linux target and omitting the flash command:
+```
+idf.py --preview set-target linux
+idf.by build
+idf.py monitor
+```
+The linux target is still in preview, hence the necessary `--preview` argument. Flashing can be omitted on Linux.
+
+
+## Example folder contents
+
+The files in this project have the same structure as the files in the [original Hello World application](../../../../examples/get-started/hello_world/).
+
+## Example Output
+
+The output is similar to the output of the [original Hello World application](../../../../examples/get-started/hello_world/), except that no chip information is printed and there won't be any bootloader output on the linux target.

+ 4 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt

@@ -0,0 +1,4 @@
+idf_component_register(SRCS "hello_world_main.c"
+                    INCLUDE_DIRS "")
+
+target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

+ 24 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c

@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+void app_main(void)
+{
+    printf("Hello world!\n");
+
+    for (int i = 10; i >= 0; i--) {
+        printf("Restarting in %d seconds...\n", i);
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+    printf("Restarting now.\n");
+    fflush(stdout);
+    exit(0);
+}

+ 15 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/pytest_hello_world_linux_compatible.py

@@ -0,0 +1,15 @@
+# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded_idf.dut import IdfDut
+
+# Note that support for Linux target console applications hasn't been implemented for pytest-embedded yet
+# (https://github.com/espressif/pytest-embedded/issues/106)
+
+
+@pytest.mark.esp32
+@pytest.mark.esp32c3
+@pytest.mark.generic
+def test_hello_world_linux_compatible(dut: IdfDut) -> None:
+    dut.expect('Hello world!')