1.. _Posix arch:
2
3The POSIX architecture
4######################
5
6.. contents::
7   :depth: 1
8   :backlinks: entry
9   :local:
10
11Overview
12********
13
14The POSIX architecture, in combination with the inf_clock SOC layer,
15provides 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: The native boards, :ref:`native_posix<native_posix>`
37and :ref:`native_sim<native_sim>`, and the :ref:`bsim boards<bsim boards>`.
38While they share the main objectives and principles, the first are 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 Windows Subsystem
67   for Linux (WSL) because WSL 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.. figure:: layering.svg
308    :align: center
309    :alt: Zephyr layering in native build
310    :figclass: align-center
311
312    Zephyr layering when built against an embedded target (left), and
313    targeting a POSIX arch based board (right)
314
315.. _posix_arch_design_archl:
316
317Arch layer
318==========
319
320In this architecture each Zephyr thread is mapped to one POSIX pthread.
321The POSIX architecture emulates a single threaded CPU/MCU by only allowing
322one SW thread to execute at a time, as commanded by the Zephyr kernel.
323Whenever the Zephyr kernel desires to context switch two threads,
324the POSIX arch blocks and unblocks the corresponding pthreads.
325
326This architecture provides the same interface to the Kernel as other
327architectures and is therefore transparent for the application.
328
329When using this architecture, the code is compiled natively for the host system,
330and typically as a 32-bit binary assuming pointer and integer types are 32-bits
331wide.
332
333Note that all threads use a normal Linux pthread stack, and do not use
334the Zephyr thread stack allocation for their call stacks or automatic
335variables. The Zephyr stacks (which are allocated in "static memory") are
336only used by the POSIX architecture for thread bookkeeping.
337
338SOC and board layers
339====================
340
341.. note::
342
343   This description applies to all current POSIX arch based boards on tree,
344   but it is not a requirement for another board to follow what is described here.
345
346When the executable process is started (that is the board
347:c:func:`main`, which is the linux executable C :c:func:`main`),
348first, early initialization steps are taken care of
349(command line argument parsing, initialization of the HW models, etc).
350
351After, the "CPU simulation" is started, by creating a new pthread
352and provisionally blocking the original thread. The original thread will only
353be used for HW models after this;
354while this newly created thread will be the first "SW" thread and start
355executing the boot of the embedded code (including the POSIX arch code).
356
357During this MCU boot process, the Zephyr kernel will be initialized and
358eventually this will call into the embedded application `main()`,
359just like in the embedded target.
360As the embedded SW execution progresses, more Zephyr threads may be spawned,
361and for each the POSIX architecture will create a dedicated pthread.
362
363Eventually the simulated CPU will be put to sleep by the embedded SW
364(normally when the boot is completed). This whole simulated CPU boot,
365until the first time it goes to sleep happens in 0 simulated time.
366
367At this point the last executing SW pthread will be blocked,
368and the first thread (reserved for the HW models now) will be allowed
369to execute again. This thread will, from now on, be the one handling both the
370HW models and the device simulated time.
371
372The HW models are designed around timed events,
373and this thread will check what is the next
374scheduled HW event, advance simulated time until that point, and call the
375corresponding HW model event function.
376
377Eventually one of these HW models will raise an interrupt to the
378simulated CPU. When the IRQ controller wants to wake the simulated
379CPU, the HW thread is blocked, and the simulated CPU is awakened by
380letting the last SW thread continue executing.
381
382This process of getting the CPU to sleep, letting the HW models run,
383and raising an interrupt which wake the CPU again is repeated until the end
384of the simulation, where the CPU execution always takes 0 simulated time.
385
386When a SW thread is awakened by an interrupt, it will be made to enter the
387interrupt handler by the soc_inf code.
388
389If the SW unmasks a pending interrupt while running, or triggers a SW
390interrupt, the interrupt controller may raise the interrupt immediately
391depending on interrupt priorities, masking, and locking state.
392
393Interrupts are executed in the context (and using the stack) of the SW
394thread in which they are received. Meaning, there is no dedicated thread or
395stack for interrupt handling.
396
397To ensure determinism when the Zephyr code is running,
398and to ease application debugging,
399the board uses a different time than real time: simulated time.
400How and if simulated time relates to the host time, is up to the simulated
401board.
402
403The Zephyr application sees the code executing as if the CPU were running at
404an infinitely fast clock, and fully decoupled from the underlying host CPU
405speed.
406No simulated time passes while the application or kernel code execute.
407
408.. _posix_busy_wait:
409
410Busy waits
411==========
412
413Busy waits work thanks to provided board functionality.
414This does not need to be the same for all boards, but both native_sim and the
415nrf52_bsim board work similarly thru the combination of a board specific
416`arch_busy_wait()` and a special fake HW timer (provided by the board).
417
418When a SW thread wants to busy wait, this fake timer will be programmed in
419the future time corresponding to the end of the busy wait and the CPU will
420be put immediately to sleep in the busy_wait caller context.
421When this fake HW timer expires the CPU will be waken with a special
422non-maskable phony interrupt which does not have a corresponding interrupt
423handler but will resume the busy_wait SW execution.
424Note that other interrupts may arrive while the busy wait is in progress,
425which may delay the `k_busy_wait()` return just like in real life.
426
427Interrupts may be locked out or masked during this time, but the special
428fake-timer non-maskable interrupt will wake the CPU nonetheless.
429
430
431NATIVE_TASKS
432============
433
434The soc_inf layer provides a special type of hook called the NATIVE_TASKS.
435
436These allow registering (at build/link time) functions which will be called
437at different stages during the process execution: Before command line parsing
438(so dynamic command line arguments can be registered using this hook),
439before initialization of the HW models, before the simulated CPU is started,
440after the simulated CPU goes to sleep for the first time,
441and when the application exists.
442