{"id":70379,"date":"2026-11-06T09:01:45","date_gmt":"2026-11-06T08:01:45","guid":{"rendered":"https:\/\/www.inovex.de\/?p=70379"},"modified":"2026-11-06T09:05:51","modified_gmt":"2026-11-06T08:05:51","slug":"zephyr-linux-cointegration-meeting-early-bootup-requirements","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/","title":{"rendered":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_89 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#Available-Building-Blocks\" >Available Building Blocks<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#Shared-Memory-and-Inter-Processor-Interrupts\" >Shared Memory and Inter-Processor Interrupts<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#The-Resource-Table\" >The Resource Table<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#VirtIO-and-VRings\" >VirtIO and VRings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#RPMsg\" >RPMsg<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#Load-and-Attach-Model-Compared\" >Load and Attach Model Compared<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<p><span style=\"font-weight: 400;\">Modern application processors increasingly ship with more than one kind of CPU in the same package. This allows a much more direct integration of a feature-rich multi-purpose operating system together with an operating system for real-time or safety applications, compared to what would be possible with separate, dedicated microprocessors or controllers.<\/span><!--more--><\/p>\n<p><span style=\"font-weight: 400;\">A common combination consists of an ARM Cortex-A application processor together with a separate Cortex-M real-time processor. The first of the two typically runs Linux and takes care of networking, heavy computation or a user interface, while the latter runs an RTOS like <a href=\"https:\/\/www.zephyrproject.org\/\">Zephyr<\/a> and is responsible for applications with real-time or safety requirements or managing low-level peripherals.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Such a system requires careful, well-defined coordination between the involved processors, which is also referred to as <\/span><a href=\"https:\/\/openamp.readthedocs.io\/en\/latest\/protocol_details\/lifecyclemgmt_overview.html\"><i><span style=\"font-weight: 400;\">lifecycle management<\/span><\/i><\/a><span style=\"font-weight: 400;\">: The startup ordering of the processors must be clearly defined, as well as the communication channels and used protocols between them, and sometimes also the coordination of shutdown sequences.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In the context of Linux, this is achieved with the <\/span><a href=\"https:\/\/docs.kernel.org\/staging\/remoteproc.html\"><i><span style=\"font-weight: 400;\">remoteproc<\/span><\/i><\/a><span style=\"font-weight: 400;\"> framework. Once booted, a Linux userspace component can use this framework to control the real-time processor (also referred to as the <i>remote processor<\/i>), load an application to it, and help establish necessary communication channels. The entire process is well documented, and plenty of documentation (remoteproc, <a href=\"https:\/\/docs.kernel.org\/staging\/rpmsg.html\">rpmsg<\/a>, <a href=\"https:\/\/docs.oasis-open.org\/virtio\/virtio\/v1.3\/virtio-v1.3.html\">virtio 1.3<\/a>), articles, and conference talks are already available (<a href=\"https:\/\/wiki.st.com\/stm32mpu\/wiki\/Linux_RPMsg_framework_overview\">ST Microelectronics: Linux RPMsg framework overview<\/a>, <a href=\"https:\/\/www.rt-rk.com\/rpmsg-based-inter-core-communication-in-heterogeneous-embedded-systems\/\">rt-rk: RPMsg-Based Inter-Core Communication in Heterogeneous Embedded Systems<\/a>, <a href=\"https:\/\/developer.toradex.com\/software\/hmp\/hmp-nxp\/how-to-use-remoteproc\/\">Toradex: How To Use RemoteProc<\/a>, <a href=\"https:\/\/www.youtube.com\/watch?v=Ovg3rCZoAdQ\">Iuliana Prodan: Enhancing OpenAMP: Making Linux and Zephyr Work Better Together<\/a>). <\/span><span style=\"font-weight: 400;\">However, this solution is not suitable for systems which require a very fast bootup of the real-time processor. Even if the Linux system is optimized for fast bootup, the resulting bootup delay for the real-time processor will still be measured in seconds. This is too long if the real-time system is required to be up and running within milliseconds.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">One solution for this problem is booting the realtime core <\/span><i><span style=\"font-weight: 400;\">before<\/span><\/i><span style=\"font-weight: 400;\"> Linux, then let Linux attach to it. While this can easily be achieved by small changes in the bootloader configuration, the real challenge is adapting the lifecycle management. With the same Linux-side configuration as before, Linux will assume it has full control over the lifecycle and resets and reconfigures the already running realtime processor.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">So the question is, how can we establish a bootup process where Linux does not follow its default <\/span><i><span style=\"font-weight: 400;\">load<\/span><\/i><span style=\"font-weight: 400;\"> model but instead <\/span><i><span style=\"font-weight: 400;\">attaches<\/span><\/i><span style=\"font-weight: 400;\"> itself to the already running processor? And how are the communication channels established, if the lifecycle is no longer managed only by Linux? In contrast to the well documented <\/span><i><span style=\"font-weight: 400;\">load<\/span><\/i><span style=\"font-weight: 400;\"> model, there is little to no documentation available on how to implement the <\/span><i><span style=\"font-weight: 400;\">attach<\/span><\/i><span style=\"font-weight: 400;\"> model.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This article is split into two parts: this first installment establishes the foundational concepts and technical background, while the second part, following shortly, will walk through a complete hands-on implementation.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Available-Building-Blocks\"><\/span>Available Building Blocks<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The building blocks for establishing communication between two independent processors are already available. The following sections assign them to their respective layer in the ISO\/OSI layering model and briefly describe their role.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"Shared-Memory-and-Inter-Processor-Interrupts\"><\/span>Shared Memory and Inter-Processor Interrupts<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Communication between two independent processors requires a means of data transfer and a way of signalling each other. Correctly sequencing both allows implementing robust inter-processor communication.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Although other methods exist, shared memory is the most common mechanism for transferring data between independent cores on a single chip. With shared memory, the sending processor writes data into a memory region accessible by both processors and triggers an inter-processor interrupt to notify the receiving processor. The receiving processor then reads the data and acknowledges completion back to the sender.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Establishing and using shared memory for inter-processor communication comes with three general challenges: both involved sides must agree on the concrete memory location and size of the shared memory <\/span><i><span style=\"font-weight: 400;\">carveout<\/span><\/i><span style=\"font-weight: 400;\">, they may need to maintain cache coherence, and accessing the shared memory region might impact performance. In addition, inter-processor interrupts are mostly implemented with vendor-specific solutions. In most cases, a dedicated on-chip peripheral provides the necessary functionality but typically requires driver support from both involved operating systems. For this part of the article series, it is sufficient to know that these challenges exist. The second part will go into more detail about how they are solved in a concrete example.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Together, shared memory and inter-processor interrupts form the <\/span><i><span style=\"font-weight: 400;\">physical<\/span><\/i><span style=\"font-weight: 400;\"> layer of the ISO\/OSI layering model.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"The-Resource-Table\"><\/span>The Resource Table<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">A shared memory carveout alone is not sufficient. Both sides also need to agree on a shared data structure definition, and it must be clarified which side is responsible for its initialization. This is the task of the resource table: it is a supporting data structure for establishing communication channels on top of shared memory.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The format and purpose of the resource table are defined by Linux\u2019s <a href=\"https:\/\/docs.kernel.org\/staging\/remoteproc.html\">remoteproc framework<\/a>. <\/span><span style=\"font-weight: 400;\">It is used by the remote processor to tell Linux what it needs to properly function. This includes the number and type of communication channels for higher-level protocols as well as their configuration and status information.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The remoteproc framework establishes four default resource categories inside the resource table. These categories include <\/span><i><span style=\"font-weight: 400;\">carveout<\/span><\/i><span style=\"font-weight: 400;\">, <\/span><i><span style=\"font-weight: 400;\">devmem<\/span><\/i><span style=\"font-weight: 400;\">, <\/span><i><span style=\"font-weight: 400;\">trace<\/span><\/i><span style=\"font-weight: 400;\">, and <\/span><i><span style=\"font-weight: 400;\">vdev<\/span><\/i><span style=\"font-weight: 400;\">. Among them, <\/span><i><span style=\"font-weight: 400;\">only vdev <\/span><\/i><span style=\"font-weight: 400;\">plays a role throughout this article series. Furthermore, the label <\/span><i><span style=\"font-weight: 400;\">carveout<\/span><\/i><span style=\"font-weight: 400;\"> creates a semantic overlap: on one hand, it describes the statically defined shared memory sections, and on the other hand, a resource type built into remoteproc and its resource table. For proprietary requirements, developers may implement custom protocols through a designated range of vendor-specific resource types.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Crucially, the interaction between the remote and master processors is implemented as a strict system contract rather than an active conversation during runtime. The remote processor statically defines its demands within the resource table at compile time, and the master processor reads these demands to provision the environment. If the master side fails to provide the resources requested via the table, communication cannot succeed. This mechanism is independent of the underlying real-time operating system and functions identically whether using Zephyr, another RTOS, or a bare-metal implementation.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">As with the shared memory carveout, the memory location for the resource table must be agreed on by both processors. When using the <\/span><i><span style=\"font-weight: 400;\">load<\/span><\/i><span style=\"font-weight: 400;\"> model, the resource table is placed in a special section within the ELF image that contains the application for the remote processor. In that case, Linux\u2019s remoteproc framework will extract the resource table from this ELF section and place it at the correct memory location before the application on the remote processor is started. In contrast, the <\/span><i><span style=\"font-weight: 400;\">attach<\/span><\/i><span style=\"font-weight: 400;\"> model requires that the resource table is placed in memory <\/span><i><span style=\"font-weight: 400;\">before<\/span><\/i><span style=\"font-weight: 400;\"> Linux boots. It must, however, still be <\/span><i><span style=\"font-weight: 400;\">initialized by Linux<\/span><\/i><span style=\"font-weight: 400;\">. How this is achieved in detail will be explained in the second part of this article.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The resource table cannot be attributed to a singular ISO\/OSI layer: it contains configuration information relevant throughout the entire communication stack.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"VirtIO-and-VRings\"><\/span>VirtIO and VRings<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">As mentioned above, the resource table tells the controlling side how many communication channels of what type it shall create, such that both sides can use them.\u00a0<\/span><span style=\"font-weight: 400;\">Although custom transports could be used, the remote side typically requests communication using <\/span><i><span style=\"font-weight: 400;\">Virtual I\/O<\/span><\/i><span style=\"font-weight: 400;\"> (short: <\/span><i><span style=\"font-weight: 400;\">virtio<\/span><\/i><span style=\"font-weight: 400;\">), using two <\/span><i><span style=\"font-weight: 400;\">vrings<\/span><\/i><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The <a href=\"https:\/\/docs.oasis-open.org\/virtio\/virtio\/v1.3\/virtio-v1.3.html\">virtio specification<\/a> is mostly known in the context of virtual machines, but its concepts also apply to situations where two processors communicate with each other over shared memory. Virtio knows two types of communication participants: <\/span><i><span style=\"font-weight: 400;\">devices<\/span><\/i><span style=\"font-weight: 400;\"> and <\/span><i><span style=\"font-weight: 400;\">drivers<\/span><\/i><span style=\"font-weight: 400;\">. Here, Linux provides the <\/span><i><span style=\"font-weight: 400;\">driver<\/span><\/i><span style=\"font-weight: 400;\"> side, and the remote processor acts as a <\/span><i><span style=\"font-weight: 400;\">device<\/span><\/i><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Virtio offers a number of predefined device types. Each one has, among other properties, a well-known device id, a specific number of vrings for predefined purposes, and a specified runtime behavior.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">With virtio, device and driver exchange bulk data with the help of so-called <\/span><i><span style=\"font-weight: 400;\">vrings<\/span><\/i><span style=\"font-weight: 400;\"> (the virtio specification calls them <\/span><i><span style=\"font-weight: 400;\">virtqueues<\/span><\/i><span style=\"font-weight: 400;\">, Linux and Zephyr refer to them as <\/span><i><span style=\"font-weight: 400;\">vring<\/span><\/i><span style=\"font-weight: 400;\">). Instead of the actual payload, a vring transports <\/span><i><span style=\"font-weight: 400;\">buffer descriptors<\/span><\/i><span style=\"font-weight: 400;\">, and handles pieces of memory allocated from a shared <\/span><i><span style=\"font-weight: 400;\">buffer pool<\/span><\/i><span style=\"font-weight: 400;\">. A noteworthy detail is the unidirectionality of a vring: communication from driver to device happens through a different vring than communication in the other direction.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Virtio and vrings implement the transport layer of the ISO\/OSI layering model.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"RPMsg\"><\/span>RPMsg<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">On top of the communication facilities implemented by virtio lives rpmsg, also known as &#8220;Remote Processor Messaging&#8221;. Rpmsg is a <\/span><i><span style=\"font-weight: 400;\">messaging bus<\/span><\/i> <span style=\"font-weight: 400;\">used to open communication endpoints and announce services by name. Rpmsg is directly supported by virtio as a dedicated, well-known device type. Its specification is part of the <a href=\"https:\/\/docs.kernel.org\/staging\/rpmsg.html\">Linux kernel documentation<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">As soon as a remote virtio device creates an rpmsg endpoint, the Linux kernel tries to find an rpmsg driver that matches the announced channel name. Upon success, Linux loads that driver and begins interacting with the virtual device. If, for example, Zephyr on the remote side creates an endpoint with the name `rpmsg-tty`, and if Linux has a matching rpmsg device driver, then Linux will instantiate a <\/span><span style=\"font-weight: 400;\">\/dev\/ttyRPMSG0<\/span><span style=\"font-weight: 400;\"> device. This new tty device implements the other side of the connection. <\/span><span style=\"font-weight: 400;\">If Linux has no matching driver, udev will see the announcement, but no driver will be loaded.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Announcing a new service is also possible from the Linux side. Analog to the example above, a Linux driver could as well declare a new endpoint, and Zephyr could react to this event. In this article, the focus is on announcements made by Zephyr.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Load-and-Attach-Model-Compared\"><\/span>Load and Attach Model Compared<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The above building blocks are everything that is needed to implement both use cases: the <\/span><i><span style=\"font-weight: 400;\">load<\/span><\/i><span style=\"font-weight: 400;\"> model and also the <\/span><i><span style=\"font-weight: 400;\">attach<\/span><\/i><span style=\"font-weight: 400;\"> model. Since the ultimate goal is booting the remote core as early as possible, it is worth taking one step back and visualizing the bootup flow of both models.<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><a href=\"#image_load_model\">Figure 1<\/a> depicts the well documented load model. After the device is powered on, the bootloader starts executing on the Cortex-A53 processor. The bootloader loads the Linux kernel into memory and starts the kernel. After the Linux kernel brings up a functioning userspace, a process is able to locate, load, and deploy the ELF image for the remote Cortex-M7 core. Only now, the M7 core is released, boots up Zephyr, and a handshake between both processors can take place.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In contrast, <a href=\"#image_attach_model\">Figure 2<\/a> shows the attach model. The bootloader first takes care of loading and starting the application for the remote processor, and only afterwards the Linux kernel is started. The M7 core begins executing even before the Linux kernel is loaded into memory. It can run critical business logic while waiting for Linux to become ready in the background, which is exactly what is needed for an early boot-up scenario.<\/span><\/p>\n<figure id=\"attachment_71060\" aria-describedby=\"caption-attachment-71060\" style=\"width: 477px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2.png\"><img loading=\"lazy\" decoding=\"async\" id=\"image_load_model\" class=\"wp-image-71060 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2.png\" alt=\"\" width=\"477\" height=\"405\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2.png 477w, https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2-300x255.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2-400x340.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/load_model.drawio-2-360x306.png 360w\" sizes=\"auto, (max-width: 477px) 100vw, 477px\" \/><\/a><figcaption id=\"caption-attachment-71060\" class=\"wp-caption-text\">Figure 1: The load model. Linux boots first, then Zephyr is started on the M7.<\/figcaption><\/figure>\n<figure id=\"attachment_71058\" aria-describedby=\"caption-attachment-71058\" style=\"width: 497px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2.png\"><img loading=\"lazy\" decoding=\"async\" id=\"image_attach_model\" class=\"wp-image-71058 size-full\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2.png\" alt=\"\" width=\"497\" height=\"405\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2.png 497w, https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2-300x244.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2-400x326.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/attach_model.drawio-2-360x293.png 360w\" sizes=\"auto, (max-width: 497px) 100vw, 497px\" \/><\/a><figcaption id=\"caption-attachment-71058\" class=\"wp-caption-text\">Figure 2: The attach model. The bootloader first starts Zephyr on the M7, Linux attaches later.<\/figcaption><\/figure>\n<div class=\"mceTemp\">\n<p><span style=\"font-weight: 400;\">The two figures highlight the differences in ordering and timing between the load and attach models. In the load model, nearly the entire Linux boot process occurs between the power-on reset and the release of the M7 processor. The bootloader must load a kernel image of several megabytes from storage and potentially validate its integrity. The kernel then boots, initializes its memory management, probes drivers, brings up devices, and mounts the root file system. Only after these steps are complete can the init system start a service to load the image for the M7 processor. Consequently, even a highly optimized system spends seconds on this path.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In contrast, the attach model requires only the bootloader as a prerequisite. It copies an application image of a few hundred kilobytes into memory and immediately releases the M7 processor. Including a potential integrity check performed on the M7 image, this sequence completes within a few milliseconds after the power-on reset. Ultimately, the entire Linux boot process is moved off the critical path of the real-time application.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Both diagrams also depict an initial handshake between both involved processors. Without going into too much detail here \u2013 the followup article will cover the specifics &#8211; this handshake always includes the same basic steps:<\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Linux reads the resource table and identifies a vdev entry requesting an rpmsg device with two vrings.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Linux initializes the vrings and the buffer pool inside the shared memory carveout.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Linux signals readiness by setting a status flag in the vdev entry and subsequently notifies Zephyr on the M7 processor.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Zephyr detects the change in the status flag, initializes its end of the vrings, and announces its rpmsg endpoints through their service names.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Linux matches each announced service name against its rpmsg drivers and instantiates the corresponding devices.<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">When following the load model, Linux\u2019s remoteproc parses the resource table <\/span><i><span style=\"font-weight: 400;\">prior<\/span><\/i><span style=\"font-weight: 400;\"> to populating memory and releasing the M7 core, so Zephyr encounters minimal or no initial wait time in step 3. In contrast, the attach model lets Zephyr start ahead of Linux. While Zephyr has to wait on Linux in step 3 for an unknown time to complete initialization, it can immediately execute critical application tasks, while the communication channel to the Linux side is established in a background task. This, however, can only be accomplished if Zephyr can place the resource table into memory on its own: the resource table must no longer be part of the ELF image. Finally, all clocks, pins, and peripherals used by Zephyr must remain untouched by Linux, which otherwise might disable them during the boot process.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">This concludes the introductory part of this article series, covering the fundamentals of a remoteproc setup with rpmsg-based communication between the processors. An early start of the real-time processor requires a different initialization model than the conventional deployment that relies on the load model. Instead, time-critical applications utilize the attach model and boot\u00a0 the real-time core early. To establish robust inter-processor communication, both paradigms leverage the same building blocks: hardware interrupts, shared memory carveouts,\u00a0 a shared resource table, virtio on the transport layer, and rpmsg endpoints. The second part of this article series discusses the technical details of the involved building blocks, and it explains the necessary steps to implement the attach model on a Toradex Verdin SoM.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Stay tuned!<\/span><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Modern application processors increasingly ship with more than one kind of CPU in the same package. This allows a much more direct integration of a feature-rich multi-purpose operating system together with an operating system for real-time or safety applications, compared to what would be possible with separate, dedicated microprocessors or controllers.<\/p>\n","protected":false},"author":456,"featured_media":71422,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[],"service":[527],"level":[1280],"coauthors":[{"id":456,"display_name":"Stefan Kratochwil","user_nicename":"skratochwil"}],"class_list":["post-70379","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","service-embedded-systems-en"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH<\/title>\n<meta name=\"description\" content=\"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO &amp; RPMsg im Detail.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO &amp; RPMsg im Detail.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-06T08:01:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-11-06T08:05:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1500\" \/>\n\t<meta property=\"og:image:height\" content=\"880\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Stefan Kratochwil\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration-1024x601.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Stefan Kratochwil\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/\"},\"author\":{\"name\":\"Stefan Kratochwil\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#\\\/schema\\\/person\\\/7bc6a7ea18496ccb143c7cc4fd4bb73a\"},\"headline\":\"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements\",\"datePublished\":\"2026-11-06T08:01:45+00:00\",\"dateModified\":\"2026-11-06T08:05:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/\"},\"wordCount\":2367,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Zephyr_Linux_Co-Integration.png\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/\",\"name\":\"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Zephyr_Linux_Co-Integration.png\",\"datePublished\":\"2026-11-06T08:01:45+00:00\",\"dateModified\":\"2026-11-06T08:05:51+00:00\",\"description\":\"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO & RPMsg im Detail.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Zephyr_Linux_Co-Integration.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Zephyr_Linux_Co-Integration.png\",\"width\":1500,\"height\":880},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/zephyr-linux-cointegration-meeting-early-bootup-requirements\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/inovexde\",\"https:\\\/\\\/x.com\\\/inovexgmbh\",\"https:\\\/\\\/www.instagram.com\\\/inovexlife\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/inovex\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/#\\\/schema\\\/person\\\/7bc6a7ea18496ccb143c7cc4fd4bb73a\",\"name\":\"Stefan Kratochwil\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g10096b24c4b4fb574e910a5b3b28238e\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g\",\"caption\":\"Stefan Kratochwil\"},\"url\":\"https:\\\/\\\/www.inovex.de\\\/en\\\/blog\\\/author\\\/skratochwil\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH","description":"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO & RPMsg im Detail.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/","og_locale":"en_US","og_type":"article","og_title":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH","og_description":"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO & RPMsg im Detail.","og_url":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2026-11-06T08:01:45+00:00","article_modified_time":"2026-11-06T08:05:51+00:00","og_image":[{"width":1500,"height":880,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png","type":"image\/png"}],"author":"Stefan Kratochwil","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration-1024x601.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Written by":"Stefan Kratochwil","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/"},"author":{"name":"Stefan Kratochwil","@id":"https:\/\/www.inovex.de\/en\/#\/schema\/person\/7bc6a7ea18496ccb143c7cc4fd4bb73a"},"headline":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements","datePublished":"2026-11-06T08:01:45+00:00","dateModified":"2026-11-06T08:05:51+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/"},"wordCount":2367,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/en\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/","url":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/","name":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png","datePublished":"2026-11-06T08:01:45+00:00","dateModified":"2026-11-06T08:05:51+00:00","description":"Boot-Verz\u00f6gerungen auf Multicore-SoCs vermeiden: Wie das Remoteproc Attach-Model Echtzeitkerne in Millisekunden vor Linux startet. Architektur, VirtIO & RPMsg im Detail.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Zephyr_Linux_Co-Integration.png","width":1500,"height":880},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/en\/blog\/zephyr-linux-cointegration-meeting-early-bootup-requirements\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/en\/"},{"@type":"ListItem","position":2,"name":"Zephyr-Linux Co-Integration \u2013 Meeting Early Bootup Requirements"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/en\/#website","url":"https:\/\/www.inovex.de\/en\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/en\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.inovex.de\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/en\/#\/schema\/person\/7bc6a7ea18496ccb143c7cc4fd4bb73a","name":"Stefan Kratochwil","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g10096b24c4b4fb574e910a5b3b28238e","url":"https:\/\/secure.gravatar.com\/avatar\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1eb853325d0a39ffa27acf77eb3b14be262fb3f67c7482f8d33057d96cd875ef?s=96&d=retro&r=g","caption":"Stefan Kratochwil"},"url":"https:\/\/www.inovex.de\/en\/blog\/author\/skratochwil\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/posts\/70379","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/users\/456"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/comments?post=70379"}],"version-history":[{"count":5,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/posts\/70379\/revisions"}],"predecessor-version":[{"id":71435,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/posts\/70379\/revisions\/71435"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/media\/71422"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/media?parent=70379"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/tags?post=70379"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/service?post=70379"},{"taxonomy":"level","embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/level?post=70379"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/en\/wp-json\/wp\/v2\/coauthors?post=70379"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}