1.. _Posix arch: 2 3The POSIX architecture 4###################### 5 6.. contents:: 7 :depth: 1 8 :backlinks: entry 9 :local: 10 11Overview 12******** 13 14The native simulator in combination with the POSIX architecture and the inf_clock SOC layer, 15provide the foundation, architecture and SOC layers for a set of virtual test 16boards. 17 18Using these, a Zephyr application can be compiled together with 19the Zephyr kernel, creating a normal executable that runs as 20a native application on the host OS, without emulation. Instead, 21you use native host tools for compiling, debugging, and analyzing your 22Zephyr application, eliminating the need for architecture-specific 23target hardware in the early phases of development. 24 25.. note:: 26 27 The POSIX architecture is not related and should not be confused with the 28 :ref:`POSIX OS abstraction<posix_support>`. 29 The latter provides an adaptation shim that enables running applications 30 which require POSIX APIs on Zephyr. 31 32 33Types of POSIX arch based boards 34================================ 35 36Today there are two types of POSIX boards: 37:ref:`native_sim<native_sim>`, and the :ref:`bsim boards<bsim boards>`. 38While they share the main objectives and principles, the first is intended as 39a HW agnostic test platform which in some cases utilizes the host OS 40peripherals, while the second intend to simulate a particular HW platform, 41with focus on their radio (e.g. BT LE) and utilize the `BabbleSim`_ physical layer 42simulation and framework, while being fully decoupled of the host. 43 44.. _BabbleSim: 45 https://BabbleSim.github.io 46 47.. _posix_arch_deps: 48 49Host system dependencies 50======================== 51 52This port is designed and tested to run in Linux. 53 54.. note:: 55 56 You must have the 32-bit C library installed in your system 57 (in Ubuntu 16.04 install the gcc-multilib package) 58 59.. note:: 60 61 The POSIX architecture is known to **not** work on macOS due to 62 fundamental differences between macOS and other typical Unixes. 63 64.. note:: 65 66 The 32 bit version of this port does not directly work in the old Windows Subsystem 67 for Linux (WSL1) because WSL1 does not support native 32-bit binaries. 68 You may want to consider WSL2, or, if using :ref:`native_sim <native_sim>`, 69 you can also just use the ``native_sim/native/64`` 70 target: Check :ref:`32 and 64bit versions<native_sim32_64>`. 71 Otherwise `with some tinkering 72 <https://github.com/microsoft/WSL/issues/2468#issuecomment-374904520>`_ it 73 should be possible to make it work. 74 75 76.. _posix_arch_limitations: 77 78Important limitations 79********************* 80 81The underlying assumptions behind this port set some limitations on what 82can and cannot be done. 83These limitations are due to the code executing natively in 84the host CPU without any instrumentation or means to interrupt it unless the 85simulated CPU is sleeping. 86 87You can imagine the code executes in a simulated CPU 88which runs at an infinitely fast clock: No time passes while the CPU is 89running. 90Therefore interrupts, including timer interrupts, will not arrive 91while code executes, except immediately after the SW enables or unmasks 92them if they were pending. 93 94This behavior is intentional, as it provides a deterministic environment to 95develop and debug. 96For more information please see the 97`Rationale for this port`_ and :ref:`Architecture<posix_arch_architecture>` 98sections 99 100Therefore these limitations apply: 101 102- There can **not** be busy wait loops in the application code that wait for 103 something to happen without letting the CPU sleep. 104 If busy wait loops do exist, they will behave as infinite loops and 105 will stall the execution. For example, the following busy wait loop code, 106 which could be interrupted on actual hardware, will stall the execution of 107 all threads, kernel, and HW models: 108 109 .. code-block:: c 110 111 while (1){} 112 113 Similarly the following code where we expect ``condition`` to be 114 updated by an interrupt handler or another thread, will also stall 115 the application when compiled for this port. 116 117 .. code-block:: c 118 119 volatile condition = true; 120 while (condition){} 121 122 123- Code that depends on its own execution speed will normally not 124 work as expected. For example, code such as shown below, will likely not 125 work as expected: 126 127 .. code-block:: c 128 129 peripheral_x->run = true; 130 131 /* Wait for a number of CPU cycles */ 132 for (int i = 0; i < 100; i++) NOP; 133 134 /* We expect the peripheral done and ready to do something else */ 135 136 137- This port is not meant to, and could not possibly help debug races between 138 HW and SW, or similar timing related issues. 139 140- You may not use hard coded memory addresses because there is no I/O or 141 MMU emulation. 142 143 144Working around these limitations 145================================ 146 147If a busy wait loop exists, it will become evident as the application will be 148stalled in it. To find the loop, you can run the binary in a debugger and 149pause it after the execution is stuck; it will be paused in 150some part of that loop. 151 152The best solution is to remove that busy wait loop, and instead use 153an appropriate kernel primitive to synchronize your threads. 154Note that busy wait loops are in general a bad coding practice as they 155keep the CPU executing and consuming power. 156 157If removing the busy loop is really not an option, you may add a conditionally 158compiled call to :c:func:`k_cpu_idle` if you are waiting for an 159interrupt, or a call to :c:func:`k_busy_wait` with some small delay in 160microseconds. 161In the previous example, modifying the code as follows would work: 162 163.. code-block:: c 164 165 volatile condition = true; 166 while (condition) { 167 #if defined(CONFIG_ARCH_POSIX) 168 k_cpu_idle(); 169 #endif 170 } 171 172.. _posix_arch_unsupported: 173 174Significant unsupported features 175******************************** 176 177Currently, these are the most significant features which are not supported in this architecture: 178 179* :ref:`User mode/userspace <usermode_api>`: When building for these targets, 180 :kconfig:option:`CONFIG_USERSPACE` will always be disabled, 181 and all calls into the kernel will be done as normal calls. 182 183* Stack checks: :kconfig:option:`CONFIG_HW_STACK_PROTECTION`, 184 :kconfig:option:`CONFIG_STACK_CANARIES`, and 185 :kconfig:option:`CONFIG_THREAD_ANALYZER`. 186 This is due to how Zephyr allocated threads' stacks are not *actually* being used like they are 187 in other architectures. Check 188 :ref:`the architecture section's architecture layer paragraph <posix_arch_design_archl>` 189 for more information. 190 191.. _posix_arch_rationale: 192 193Rationale for this port 194*********************** 195 196The main intents of this port are: 197 198- Allow functional debugging, instrumentation and analysis of the code with 199 native tooling. 200- Allow functional regression testing, and simulations in which we have the 201 full functionality of the code. 202- Run tests fast: several minutes of simulated time per wall time second. 203- Possibility to connect to external tools which may be able to run much 204 faster or much slower than real time. 205- Deterministic, repeatable runs: 206 There must not be any randomness or indeterminism (unless host peripherals 207 are used). 208 The result must **not** be affected by: 209 210 - Debugging or instrumenting the code. 211 - Pausing in a breakpoint and continuing later. 212 - The host computer performance or its load. 213 214The aim of this port is not to debug HW/SW races, missed HW programming 215deadlines, or issues in which an interrupt comes when it was not expected. 216Normally those would be debugged with a cycle accurate Instruction Set Simulator 217(ISS) or with a development board. 218 219 220.. _posix_arch_compare: 221 222Comparison with other options 223***************************** 224 225This port does not try to replace cycle accurate instruction set simulators 226(ISS), development boards, or QEMU, but to complement them. This port's main aim 227is to meet the targets described in the previous `Rationale for this port`_ 228section. 229 230.. figure:: Port_vs_QEMU_vs.svg 231 :align: center 232 :alt: Comparison of different debugging targets 233 :figclass: align-center 234 235 Comparison of different debugging options. Note that realism has many 236 dimensions: Having the real memory map or emulating the exact time an 237 instruction executes is just some of it; Emulating peripherals accurately 238 is another side. 239 240This native port compiles your code directly for the host architecture 241(typically x86), with no instrumentation or 242monitoring code. Your code executes directly in the host CPU. That is, your code 243executes just as fast as it possibly can. 244 245Simulated time is normally decoupled from real host time. 246The problem of how to emulate the instruction execution speed is solved 247by assuming that code executes in zero simulated time. 248 249There is no I/O or MMU emulation. If you try to access memory through hardcoded 250addresses your binary will simply segfault. 251The drivers and HW models for this architecture will hide this from the 252application developers when it relates to those peripherals. 253In general this port is not meant to help developing low level drivers for 254target HW. But for developing application code. 255 256Your code can be debugged, instrumented, or analyzed with all normal native 257development tools just like any other Linux application. 258 259Execution is fully reproducible, you can pause it without side-effects. 260 261How does this port compare to QEMU: 262=================================== 263 264With QEMU you compile your image targeting the board which is closer to 265your desired board. For example an ARM based one. QEMU emulates the real memory 266layout of the board, loads the compiled binary and through instructions 267translation executes that ARM targeted binary on the host CPU. 268Depending on configuration, QEMU also provides models of some peripherals 269and, in some cases, can expose host HW as emulated target peripherals. 270 271QEMU cannot provide any emulation of execution speed. It simply 272executes code as fast as it can, and lets the host CPU speed determine the 273emulated CPU speed. This produces highly indeterministic behavior, 274as the execution speed depends on the host system performance and its load. 275 276As instructions are translated to the host architecture, and the target CPU and 277MMU are emulated, there is a performance penalty. 278 279You can connect gdb to QEMU, but have few other instrumentation abilities. 280 281Execution is not reproducible. Some bugs may be triggered only in some runs 282depending on the computer and its load. 283 284How does this port compare to an ISS: 285====================================== 286 287With a cycle accurate instruction set simulator you compile targeting either 288your real CPU/platform or a close enough relative. The memory layout is modeled 289and some or all peripherals too. 290 291The simulator loads your binary, slowly interprets each instruction, and 292accounts for the time each instruction takes. 293Time is simulated and is fully decoupled from real time. 294Simulations are on the order of 10 to 100 times slower than real time. 295 296Some instruction set simulators work with gdb, and may 297provide some extra tools for analyzing your code. 298 299Execution is fully reproducible. You can normally pause your execution without 300side-effects. 301 302.. _posix_arch_architecture: 303 304Architecture and design 305*********************** 306 307.. note:: 308 309 This section does not describe anymore the old :ref:`native_posix<native_posix>` or 310 :kconfig:option:`CONFIG_NATIVE_APPLICATION` based architecture. 311 It only describes the new native simulator based architecture used by targets built with the 312 :kconfig:option:`CONFIG_NATIVE_LIBRARY` option. 313 314.. note:: 315 316 This description applies to the boards on the tree, 317 but it is not a requirement for other POSIX arch based boards to follow what is described here. 318 319.. figure:: layering_natsim.svg 320 :align: center 321 :alt: Zephyr layering in a native simulator build 322 :figclass: align-center 323 324 Zephyr layering when built against an embedded target (left), and targeting a native_simulator 325 based board (right) 326 327.. figure:: components_natsim.svg 328 :align: center 329 :alt: native_sim boards and the native simulator 330 :figclass: align-center 331 332 Relationship between Zephyr, the native_sim target and the native simulator 333 334When building targeting Zephyr's :ref:`native_sim<native_sim>` board, we build our embedded SW, 335that is, our application, the Zephyr kernel, and any subsystems and drivers we have selected, 336with the :ref:`POSIX architecture<posix_arch_design_archl>` and the 337:ref:`inf_clock<posix_arch_design_socl>` SOC layers. 338The result of this build is a pre-linked elf library, which contains what we can call the 339embedded SW. 340Then the `native simulator <https://github.com/BabbleSim/native_simulator/>`_ runner will be built. 341And after both the "embedded SW" and the runner will be linked together to form the final Linux 342executable. 343This final executable is typically called ``zephyr.exe`` and can be run or debugged just like any 344other normal Linux executable. 345 346The native simulator runner provides the Linux program entry point, command line argument parsing, 347the HW models scheduler, as well as a component to emulate the CPU start/stop and CPU thread 348switching. 349It also provides a mechanism to register functions which need to be run at different points of the 350executable lifetime. 351When targeting native_sim, the native simulator is also built with some basic HW models like a 352system timer and an interrupt controller. 353You can find more information on these in the 354`native simulator design documentation <https://github.com/BabbleSim/native_simulator/blob/main/docs/Design.md>`_. 355 356The native_sim target is a single microcontroller (MCU) target with simple HW models. Other targets 357like the :ref:`simulated nRF5340 (nrf5340bsim)<nrf5340bsim>` are multi MCU targets. Where one 358embedded Zephyr image can be build for each MCU, and all MCU images and the runner are assembled 359together into one executable with more elaborate HW models of those SOCs. 360 361Native simulator runner context and the embedded context 362======================================================== 363 364It is worth noting that the embedded SW library is first pre-linked. That is that all symbols which 365can be resolved inside that library will be resolved. And that, after, all these library symbols, 366except a selected few marked with an special annotation, will be hidden from further linking. 367In this way, the runner link stage will not link to or conflict with any of these hidden symbols, 368neither from the runner itself or from other CPUs embedded SW libraries. 369It is also worth noting that all expected Zephyr sections are built and ordered with the Zephyr 370linker script in that first embedded SW library link. 371 372When the embedded SW is built, one has the option of linking an embedded C standard library with it, 373or leave at that point all C library calls unresolved, and let them be linked in the final stage 374with the host C library. 375 376Due to all this, we can conceptually see our build divided in two separate contexts: 377One is the embedded/Zephyr context, in which we build the Zephyr OS, an application for a given MCU, 378and which may be built with an embedded C library. 379Another is the runner context, which is always built with the host C library and which has very 380limited visibility into the embedded context. 381 382From the embedded context we can easily call into the runner context: All runner context symbols 383will be linkable in the final link stage unless another embedded symbol with the same name was 384already linked to it in the first pass. 385But from the runner context only the symbols from the embedded context annotated with the 386``NATIVE_SIMULATOR_IF`` macro will be linkable. 387 388From Zephyr's build system it is possible to request a file to be built in the runner context by 389adding it to the cmake ``native_simulator`` library target. You can check 390:zephyr_file:`arch/posix/CMakeLists.txt` for more information. 391 392You can find more information in the native simulator 393`build documentation <https://github.com/BabbleSim/native_simulator/blob/main/docs/Design.md#build-and-symbol-visibility>`_ 394 395.. _posix_arch_design_archl: 396 397Arch layer 398========== 399 400The POSIX architecture is mainly responsible for two things: 401 402* Set up the Zephyr build to produce an static library for the host architecture to be later 403 used with the native simulator build and linked with the native simulator runner. 404* Provide a thin adaptation between the API the Zephyr kernel expects from an architecture 405 layer and the native simulator CPU threading emulation (NCT). 406 407This layer together with the NCT maps each Zephyr thread into one POSIX pthread, and emulates a 408single threaded CPU/MCU by only allowing one SW thread to execute at a time, as commanded by the 409Zephyr kernel. Whenever the Zephyr kernel desires to context switch two threads, the POSIX arch, 410using NCT, blocks and unblocks the corresponding pthreads. 411 412This architecture provides the same interface to the Kernel as other 413architectures and is therefore transparent for the application. 414 415Note that all threads use a normal Linux pthread stack, and do not use 416the Zephyr thread stack allocation for their call stacks or automatic 417variables. The Zephyr stacks (which are allocated in "static memory") are 418only used by the POSIX architecture to keep thread bookkeeping data. 419 420When using this architecture, the code is compiled natively for the host system, 421and typically as a 32-bit binary assuming pointer and integer types are 32-bits 422wide. 423 424.. _posix_arch_design_socl: 425 426SOC layer 427========= 428 429This SOC layer is mainly a very thin layer on top of the native simulator CPU emulation layer, 430which is responsible for handling the simulation of the CPU start/stop, as well as the 431initialization of the arch layer, and calling into the Zephyr boot (:c:func:`z_cstart()`) during 432the CPU boot itself. 433 434It also provides the :ref:`native_tasks<posix_arch_design_native_tasks>`, and specifies 435a few other hooks it expects the board layer to provide. 436 437Board layer 438=========== 439 440The board layer is responsible to provide all the hooks the SOC layer and native simulator runner 441expect. This includes the hooks to boot the CPU (which call into the SOC layer), to handle 442interrupts, and the hooks for low level tracing and busy wait handling. 443 444The overall execution and scheduling is handled by the native simulator runner itself, which calls 445when necessary into the board layer hooks. 446You can find information about how the native simulator runs the embedded SW in its 447`design documentation <https://github.com/BabbleSim/native_simulator/blob/main/docs/Design.md#overall-execution>`_ 448 449For more complex simulated boards, like :ref:`bsim ones<bsim boards>`, the board layer also provides 450the necessary logic and configuration to mimic a real target and SOC. 451 452Note that the SOC/board split in this architecture is different than for other Zephyr targets. 453This was done to enable very different real SOC simulations to share a common architecture and SOC 454layer, while placing the real SOC specific replacement logic in the board layer. 455 456 457.. _posix_busy_wait: 458 459Busy waits 460========== 461 462Busy waits work thanks to logic provided by the board and native simulator. 463This does not need to be the same for all boards, but both :ref:`native_sim<native_sim>` and the 464:ref:`nrf*bsim boards<bsim boards>` work similarly through the combination of a board specific 465:c:func:`arch_busy_wait()` and an special fake HW timer provided by the native simulator. 466 467Please check the 468`native simulator busy wait design documentation <https://github.com/BabbleSim/native_simulator/blob/main/docs/Design.md#busy-waits>`_ 469for more info. 470 471.. _posix_arch_design_native_tasks: 472 473 474NATIVE_TASKS 475============ 476 477The soc_inf layer provides a special type of hook called the NATIVE_TASKS. 478 479These allow registering (at build/link time) embedded context functions which will be called 480at different stages during the process execution: Before command line parsing 481(so dynamic command line arguments can be registered using this hook), 482before initialization of the HW models, before the simulated CPU is started, 483after the simulated CPU goes to sleep for the first time, 484and when the application exists. 485 486These hooks are ultimately based on the 487`native simulator tasks <https://github.com/BabbleSim/native_simulator/blob/main/docs/Design.md#native-simulator-tasks>`_ 488which the users may also register from code built in the runner context. 489