<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Akira Moroo</title>
    <description>The latest articles on DEV Community by Akira Moroo (@retrage).</description>
    <link>https://dev.to/retrage</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F288230%2Ff548beda-4454-46d2-909a-e8e5f2d8c6c4.png</url>
      <title>DEV Community: Akira Moroo</title>
      <link>https://dev.to/retrage</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/retrage"/>
    <language>en</language>
    <item>
      <title>9pfsPkg: Network Boot from Bell Labs</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Sat, 01 Aug 2020 07:11:08 +0000</pubDate>
      <link>https://dev.to/retrage/9pfspkg-network-boot-from-bell-labs-14ic</link>
      <guid>https://dev.to/retrage/9pfspkg-network-boot-from-bell-labs-14ic</guid>
      <description>&lt;p&gt;I developed a Plan 9 file system (9P) client for UEFI to enable network booting from a commodity 9P server. By leveraging the simplicity and flexibility of 9P, the UEFI can do network boot from cloud storage without any effort. This blog post gives you a brief overview of 9pfsPkg.&lt;/p&gt;

&lt;p&gt;The source code and introduction slides are available at:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/yabits"&gt;
        yabits
      &lt;/a&gt; / &lt;a href="https://github.com/yabits/9pfsPkg"&gt;
        9pfsPkg
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      9P Client File System for UEFI
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
9pfsPkg&lt;/h1&gt;
&lt;p&gt;9pfsPkg is a Plan 9 file system protocol (9P) client for UEFI.
It provides EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface for network transparent file system operation.&lt;/p&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;p&gt;9pfsPkg is released under the &lt;a href="https://raw.githubusercontent.com/yabits/9pfsPkg/master/LICENSE"&gt;BSD-2-Clause Plus Patent License&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/yabits/9pfsPkg"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;div class="ltag_speakerdeck"&gt;
  &lt;iframe height="463" id="talk_frame_39188800796a4bc89cc48e83a3d0393a" src="//speakerdeck.com/player/39188800796a4bc89cc48e83a3d0393a" width="710"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  What is Network Boot?
&lt;/h2&gt;

&lt;p&gt;Network boot is a boot method which loading boot images over the network. To make this possible, the BIOS has its network stack.&lt;br&gt;
There are two methods for network booting: PXE Boot and HTTP Boot.&lt;/p&gt;

&lt;p&gt;PXE (Pre-eXecution Environment) Boot is the most widely used method as it exists from the Legacy BIOS era. It is standardized and implemented as not only proprietary but also open source. PXE boot uses TFTP to transfer files. This protocol is not popular, so it requires a dedicated TFTP server.&lt;/p&gt;

&lt;p&gt;HTTP Boot uses HTTP for transferring images. It has been standardized from UEFI 2.5 in 2015[0]. It supports modern features like DNS and TLS. Since it uses HTTP, we can use commodity HTTP servers (e.g. Apache HTTP Server, Nginx).&lt;/p&gt;

&lt;p&gt;Below is the interface of the HTTP protocol.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cZzzd7dk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-http-protocol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cZzzd7dk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-http-protocol.png" alt="EFI HTTP Protocol"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Configure()&lt;/code&gt; sets the configuration, &lt;code&gt;Request()&lt;/code&gt; sends a request, and &lt;code&gt;Response()&lt;/code&gt; receives a response. By using these functions, we can implement HTTP Boot bootloader like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;EFI_STATUS&lt;/span&gt; &lt;span class="nf"&gt;HttpBootLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Send request&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TxToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Recieve response&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RxToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Start loaded image&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gBS&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;StartImage&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ImageHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This example shows how it is easy to boot with HTTP on UEFI.&lt;/p&gt;
&lt;h2&gt;
  
  
  UEFI is Extensible
&lt;/h2&gt;

&lt;p&gt;UEFI is an abbreviation of the Unified Extensible Firmware Interface. As it includes the word "Extensible," it has a modular design. The modules are called "Protocol" and UEFI has features that load external protocols in its core. By calling &lt;code&gt;EFI_BOOT_SERVICES.InstallProtocolInterface()&lt;/code&gt; with passing a loaded protocol to &lt;code&gt;Interface&lt;/code&gt; argument, it installs an external protocol.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JGCgjZP2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-install-protocol-interface.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JGCgjZP2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-install-protocol-interface.png" alt="EFI_BOOT_SERVICES.InstallProtocolInterface()"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As an example of a UEFI protocol, I introduce the Simple File System Protocol. This protocol provides a file system independent file operation interfaces. Here is a figure of the interfaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ATDz-kcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-simple-file-system-protocol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ATDz-kcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-efi-simple-file-system-protocol.png" alt="EFI Simple File System Protocol"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OpenVolume()&lt;/code&gt; in Simple File System Protocol opens a volume and returns File Protocol &lt;code&gt;Root&lt;/code&gt; that represents the root directory. File Protocol provides file operation functions like &lt;code&gt;Open()&lt;/code&gt;, &lt;code&gt;Read()&lt;/code&gt;, &lt;code&gt;Write()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, even it has abstract interfaces, UEFI supports the FAT file system only by default. There are some third-party non-FAT file system drivers. Here is an example of the use of such a file system driver: UEFI Rootkits. A rootkit is malware that targets kernels or firmware. Once infected, it installs other rootkits and/or agents. Hacking Team's rkloader[2] and LoJax[3] are such UEFI rootkits. They have NTFS UEFI drivers to embed kernel rootkits to the target Windows system. This driver is a port of NTFS-3G, an open-source NTFS implementation, and has Simple File System Protocol as an interface. The following snippet from the rkloader shows how Simple File System Protocol makes embedding an agent easy.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;EFI_STATUS&lt;/span&gt;
&lt;span class="n"&gt;EFIAPI&lt;/span&gt;
&lt;span class="nf"&gt;InstallAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;EFI_FILE_HANDLE&lt;/span&gt; &lt;span class="n"&gt;CurDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;CHAR16&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;  &lt;span class="n"&gt;FileNameUser&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Open FileNameScout as FileHandle&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CurDir&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CurDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileNameScout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EFI_FILE_MODE_READ&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;EFI_FILE_MODE_WRITE&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;EFI_FILE_MODE_CREATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Write pSectiondata to FileHandle&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;VirtualSize&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;UINT8&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;pSectiondata&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// Close FileHandle&lt;/span&gt;
  &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EFI_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;First of all, open a file by &lt;code&gt;Open()&lt;/code&gt;, deploy the agent by &lt;code&gt;Write()&lt;/code&gt;, and close the file with &lt;code&gt;Close()&lt;/code&gt;. As you can see, it is simple and does not have any trick.&lt;/p&gt;
&lt;h2&gt;
  
  
  Plan 9 File Protocol
&lt;/h2&gt;

&lt;p&gt;Now, let's think about network boot. I pointed out that the current network boots are network-aware and less flexibility. Thus, we want a network transparent file system and protocol for network boot while maintaining the feasibility of the file system.&lt;/p&gt;

&lt;p&gt;Here is the answer: Plan 9 File Protocol (9P)[8]&lt;/p&gt;

&lt;p&gt;Plan 9 from Bell Labs (Plan 9)[7] is a Unix successor OS developed by the original Unix developer in Bell Labs. "Everything is a file.", which is a well known Unix philosophy, is a core design decision on Plan 9. P9 is a protocol developed by Plan 9 developers to deal with remote files in the same manner as local files. Below is a flow of loading a file with 9P.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b7RmBKvb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-9p-flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b7RmBKvb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-9p-flow.png" alt="9P Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The client negotiates by &lt;code&gt;version&lt;/code&gt; and connects with &lt;code&gt;attach&lt;/code&gt; to get a file descriptor of the root directory. &lt;code&gt;walk&lt;/code&gt; searches to the target file, &lt;code&gt;open&lt;/code&gt; it, and &lt;code&gt;read&lt;/code&gt; it. As you can see, 9P is a protocol that file operations and messages correspond to one-by-one.&lt;/p&gt;

&lt;p&gt;9P is popular in the fields of not related to Plan 9 due to clarity and simplicity. For instance, the Linux kernel has a 9P client file system called v9fs[4]. VirtIO has a virtio-9p 9P server to share the host file system with the guests[5]. &lt;/p&gt;

&lt;p&gt;Recently, Microsoft has released Windows 10 update, and Windows Subsystem for Linux 2 (WSL2) is now officially supported. It runs a guest Linux on the Hyper-V VM in contrast to WSL1. Because VM disk image is a monolithic file, it is hard to access inside files with the same manner of host file access. To solve this issue, WSL2 uses 9P to access guest files from the host. The host Windows has 9P client to access the guest Linux files. The guest has a 9P server to process requests from the host to share the files[6].&lt;/p&gt;
&lt;h2&gt;
  
  
  9pfsPkg
&lt;/h2&gt;

&lt;p&gt;As I described in the previous section, 9P is still widely used nowadays. I implemented a 9P client file system for UEFI: 9pfsPkg.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/yabits"&gt;
        yabits
      &lt;/a&gt; / &lt;a href="https://github.com/yabits/9pfsPkg"&gt;
        9pfsPkg
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      9P Client File System for UEFI
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
9pfsPkg&lt;/h1&gt;
&lt;p&gt;9pfsPkg is a Plan 9 file system protocol (9P) client for UEFI.
It provides EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface for network transparent file system operation.&lt;/p&gt;
&lt;h2&gt;
License&lt;/h2&gt;
&lt;p&gt;9pfsPkg is released under the &lt;a href="https://raw.githubusercontent.com/yabits/9pfsPkg/master/LICENSE"&gt;BSD-2-Clause Plus Patent License&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/yabits/9pfsPkg"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;9pfsPkg is a 9P client file system UEFI driver with a Simple File System Protocol interface. Because 9P is a network transparent file system, we can use existing non-network-aware tools (e.g. UEFI Shell) for file operations via networks without any modification by using 9pfsPkg. Another advantage of the file system is that it does not require dedicated servers (like TFTP in PXE Boot).&lt;/p&gt;

&lt;h2&gt;
  
  
  9P Boot
&lt;/h2&gt;

&lt;p&gt;Let's take a look at a boot by 9P (9P Boot). The below shows the overview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cE627nEA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-9p-boot-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cE627nEA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-9p-boot-overview.png" alt="9P Boot Overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First of all, the 9P service runs on the server with an exported directory (e.g. &lt;code&gt;/tmp/9&lt;/code&gt;). Next, the client loads the 9pfsPkg UEFI driver to create a new volume. The driver processes operations to the file system volume and communicates with the server via the UEFI network stack to handle the file operations.&lt;/p&gt;

&lt;p&gt;The below video clip shows what it looks:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__video-wrapper"&gt;
        &lt;div class="ltag__twitter-tweet__media--video-preview"&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eRoX9FNt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/ext_tw_video_thumb/1262395370589630466/pu/img/2S5fGdRluAVd2oQO.jpg" alt="unknown tweet media content"&gt;
          &lt;img src="/assets/play-butt.svg" class="ltag__twitter-tweet__play-butt" alt="Play butt"&gt;
        &lt;/div&gt;
        &lt;div class="ltag__twitter-tweet__video"&gt;
          
            
          
        &lt;/div&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zii5I7kL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/591270213573718016/8rN9YkZ2_normal.png" alt="retrage profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        retrage
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/retrage"&gt;@retrage&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I'm making 9pfsPkg, 9P client for UEFI in Simple File System Protocol manner. It can boot GRUB from the remote server. The code will be available later. 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      14:55 PM - 18 May 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1262396289901309955" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1262396289901309955" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      6
      &lt;a href="https://twitter.com/intent/like?tweet_id=1262396289901309955" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      12
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;When the UEFI startups, we can see the local file system &lt;code&gt;FS0:&lt;/code&gt; only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mapping table
      FS0: Alias(s):HD0a65535a1:;BLK1:
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Load 9pfsPkg UEFI driver by &lt;code&gt;load 9pfs.efi&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FS0:\&amp;gt; load 9pfs.efi
Image 'FS0:\9pfs.efi' loaded at 7E2E7000 - Success
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The new file system &lt;code&gt;FS1:&lt;/code&gt; has appeared.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Mapping table
      FS0: Alias(s):HD0a65535a1:;BLK1:                                          
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
      FS1: Alias(s):F1:
          PciRoot(0x0)/Pci(0x2,0x0)/MAC(525400123456,0x1)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0,0xFFFF,0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In contrast to local &lt;code&gt;FS0:&lt;/code&gt;, the device path of remote &lt;code&gt;FS1:&lt;/code&gt; is &lt;code&gt;PciRoot(0x0)/Pci(0x2,0x0)/MAC(525400123456,0x1)&lt;/code&gt;. It represents that the volume is on the remote server.&lt;/p&gt;

&lt;p&gt;By executing &lt;code&gt;fs1:&lt;/code&gt; and &lt;code&gt;grubx64.efi&lt;/code&gt;, it boots the bootloader GRUB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FS0:\&amp;gt; fs1:
FS1:\&amp;gt; grubx64.efi
                             GNU GRUB  version 2.02

   Minimal BASH-like line editing is supported. For the first word, TAB
   lists possible command completions. Anywhere else TAB lists possible
   device or file completions.


grub&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At this point, UEFI Shell and GRUB deal with the remote files in the same manner as local files. There is no network boot specific process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy Boot
&lt;/h2&gt;

&lt;p&gt;9P Boot enables non-network-aware network boot. To take more advantages of the 9P, I propose Proxy Boot as an application of 9P Boot. It can boot from other servers via the direct server as a proxy. By using Proxy Boot, UEFI can boot from cloud storage without any effort. Following is the overview of Proxy Boot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TSFI2aku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-proxy-boot-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TSFI2aku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-proxy-boot-overview.png" alt="Proxy Boot Overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used Google Cloud Storage (GCS) for the network boot. The storage bucket has boot images. The server mounts the bucket as a file system using gcsfuse[9]. The 9P server uses the gcsfuse's mount point (e.g. /mnt/gcs) as an exported directory. The client mounts the volume in the same manner as 9P Boot. The client UEFI can treat the cloud storage files as if local files.&lt;/p&gt;

&lt;p&gt;The below is the demo:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__video-wrapper"&gt;
        &lt;div class="ltag__twitter-tweet__media--video-preview"&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U1vDdS-F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/ext_tw_video_thumb/1267761925170933760/pu/img/YcNT_Rl_IsThl1hO.jpg" alt="unknown tweet media content"&gt;
          &lt;img src="/assets/play-butt.svg" class="ltag__twitter-tweet__play-butt" alt="Play butt"&gt;
        &lt;/div&gt;
        &lt;div class="ltag__twitter-tweet__video"&gt;
          
            
          
        &lt;/div&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zii5I7kL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/591270213573718016/8rN9YkZ2_normal.png" alt="retrage profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        retrage
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/retrage"&gt;@retrage&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I confirmed network boot BitVisor (thin-hypervisor) from Google Cloud Platform Storage via the 9P server with less effort. The 9P client for UEFI, 9pfsPkg is available at &lt;a href="https://t.co/biJrg1G71o"&gt;github.com/yabits/9pfsPkg&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      10:18 AM - 02 Jun 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1267762465703485445" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1267762465703485445" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      14
      &lt;a href="https://twitter.com/intent/like?tweet_id=1267762465703485445" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      25
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Create a GCS bucket and upload boot images. I used BitVisor (thin-hypervisor) as a practical boot image. &lt;code&gt;loadvmm.efi&lt;/code&gt; is the loader, and &lt;code&gt;bitvisor.elf&lt;/code&gt; is the actual BitVisor image. They are default build and no modification for the network boot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0XGUV55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-gcs-bucket.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0XGUV55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/9pfspkg-gcs-bucket.png" alt="GCS Bucket"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, mount the bucket on the server using gcsfuse at &lt;code&gt;/mnt/gcs&lt;/code&gt; mount point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo -E gcsfuse proxy-boot /mnt/gcs
 Using mount point: /mnt/gcs
Opening GCS connection...
Opening bucket...
Mounting file system...
File system has been successfully mounted.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On the client, load the driver with &lt;code&gt;load 9pfs.efi&lt;/code&gt;, move to &lt;code&gt;fs1:&lt;/code&gt;, and call &lt;code&gt;loadvmm.efi&lt;/code&gt; to boot BitVisor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shell&amp;gt; fs0:
FS0:\&amp;gt; load 9pfs.efi
FS0:\&amp;gt; map -u
FS0:\&amp;gt; fs1:
FS1:\&amp;gt; loadvmm.efi
Starting BitVisor...
Copyright (c) 2007, 2008 University of Tsukuba
All rights reserved.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once again, the UEFI Shell and &lt;code&gt;loadvmm.efi&lt;/code&gt; operates the cloud storage files as if local files, and there is no cloud-specific process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, I pointed out that the existing network boots are network-aware and less flexible. The 9P client file system for UEFI (9pfsPkg) enables network transparent network boot (9P Boot). As an application of the 9pfsPkg, I proposed a network boot from cloud storage via the server (Proxy Boot) without any effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[0] &lt;a href="https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_A_Feb14.pdf"&gt;https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_A_Feb14.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[1] &lt;a href="https://tnishinaga.hatenablog.com/entry/2017/12/22/221956"&gt;https://tnishinaga.hatenablog.com/entry/2017/12/22/221956&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[2] &lt;a href="https://github.com/hackedteam/vector-edk"&gt;https://github.com/hackedteam/vector-edk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[3] &lt;a href="https://www.welivesecurity.com/wp-content/uploads/2018/09/ESET-LoJax.pdf"&gt;https://www.welivesecurity.com/wp-content/uploads/2018/09/ESET-LoJax.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[4] &lt;a href="https://www.kernel.org/doc/Documentation/filesystems/9p.txt"&gt;https://www.kernel.org/doc/Documentation/filesystems/9p.txt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[5] &lt;a href="https://www.linux-kvm.org/page/9p_virtio"&gt;https://www.linux-kvm.org/page/9p_virtio&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[6] &lt;a href="https://youtu.be/63wVlI9B3Ac?t=481"&gt;https://youtu.be/63wVlI9B3Ac?t=481&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[7] &lt;a href="https://9p.io/plan9/"&gt;https://9p.io/plan9/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[8] &lt;a href="http://man.cat-v.org/plan_9/5/"&gt;http://man.cat-v.org/plan_9/5/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[9] &lt;a href="https://github.com/GoogleCloudPlatform/gcsfuse"&gt;https://github.com/GoogleCloudPlatform/gcsfuse&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>network</category>
      <category>boot</category>
      <category>9p</category>
      <category>uefi</category>
    </item>
    <item>
      <title>Linux Kernel Library Nabla Containers Internals</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Mon, 11 May 2020 09:49:46 +0000</pubDate>
      <link>https://dev.to/retrage/linux-kernel-library-nabla-containers-internals-55eh</link>
      <guid>https://dev.to/retrage/linux-kernel-library-nabla-containers-internals-55eh</guid>
      <description>&lt;p&gt;This post describes the design and implementation of Linux Kernel Library Nabla Containers (LKL Nabla), Linux based unikernels as processes. The previous post introduces LKL Nabla and provides how to build and run. Since most of the unikernel work is done by frankenlibc LKL/musl, mainly focus on frankenlibc Solo5 port in this post.&lt;/p&gt;

&lt;p&gt;You can find LKL Nabla code at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/runnc/tree/lkl-musl"&gt;https://github.com/retrage/runnc/tree/lkl-musl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/frankenlibc/tree/solo5"&gt;https://github.com/retrage/frankenlibc/tree/solo5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Modifications to runnc
&lt;/h2&gt;

&lt;p&gt;Before diving into frankenlibc code, let’s take a look at the modifications to runnc.&lt;/p&gt;

&lt;p&gt;When runnc is executed, it initializes devices that will be used by the container. Then, the runtime builds arguments and launches a container as a process.&lt;/p&gt;

&lt;p&gt;What kind of devices will be provided? On current runnc implementation, it can provide only one network device and block device correspondingly. This situation is the same in LKL Nabla.&lt;/p&gt;

&lt;p&gt;A container manager like Docker pulls container an image and extracts to a rootfs as a directory. runnc creates a disk image from the rootfs directory. The disk image format is ISO in Rumprun, but the default file system is ext4 in LKL. Thus, it is switched to ext4 in LKL Nabla.&lt;br&gt;
For the implementation, see &lt;a href="https://github.com/retrage/runnc/blob/lkl-musl/nabla-lib/storage/storage_linux.go"&gt;&lt;code&gt;CreateExt4()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rumprun accepts JSON config from arguments on runtime. The original runnc builds config on container initialization. On the other hand, LKL also allows JSON config on runtime. However, the config format is quite different from Rumprun’s one. LKL Nabla’s runnc creates a config for LKL.&lt;br&gt;
&lt;a href="https://github.com/retrage/runnc/blob/lkl-musl/llruntimes/nabla/runnc-cont/lkl.go"&gt;llruntimes/nabla/runnc-cont/lkl.go&lt;/a&gt; is the config builder for LKL.&lt;/p&gt;

&lt;p&gt;After the initialization, runnc launches a unikernel process using Solo5 tender like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--mem="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"--net:tap="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--block:rootfs="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UniKernelBin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"__RUMP_FDINFO_NET_tap=4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unikernelArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunArgs&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c"&gt;// snip&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newenv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  frankenlibc
&lt;/h2&gt;

&lt;p&gt;Now, it’s time to dive into Solo5 port frankenlibc. It was a bunch of tools to run Rumprun unikernel on userspace. It was forked and added LKL/musl support. LKL Nabla uses this fork to run LKL on Solo5.&lt;/p&gt;

&lt;p&gt;Below shows the architecture of frankenlibc.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;frankenlibc Layers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;musl libc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LKL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;librumpuser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;franken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An application is the top of the 7 layers. The host is the bottom. The host-dependent layer is a platform. The code is located in &lt;a href="https://github.com/retrage/frankenlibc/tree/solo5/platform"&gt;platform&lt;/a&gt; directory. To port a new host, you will have to add the code to the platform.&lt;/p&gt;

&lt;p&gt;The interfaces that platform code should provide are the same as Linux system calls. Here is the list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;__libc_start_main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;clock_getres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockid_t&lt;/span&gt; &lt;span class="n"&gt;clk_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;timespec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockid_t&lt;/span&gt; &lt;span class="n"&gt;clk_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;timespec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;clock_nanosleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clockid_t&lt;/span&gt; &lt;span class="n"&gt;clk_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;timespec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;timespec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;remain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;fcntl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;fstat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;fsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getpagesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getrandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="nf"&gt;lseek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;whence&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;mmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;prot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nflags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;munmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;mprotect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;prot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;pollfd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nfds_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;pread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;preadv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;iovec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iovcnt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;pwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;pwritev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;iovec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iovcnt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;off_t&lt;/span&gt; &lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;readv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;iovec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iovcnt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;writev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;iovec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;iov&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iovcnt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It looks much larger than that of Solo5 as it provides only 13 hypercalls to the guest OS, but some of them are optional. We need to implement the platform code using the hypercalls for porting LKL/musl to Solo5.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entry Point
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;solo5_start_main()&lt;/code&gt; is an entry point in Solo5 guest. A Solo5 tender starts the OS from this function. The argument is a pointer to &lt;code&gt;struct solo5_start_info&lt;/code&gt;. It contains &lt;code&gt;cmdline&lt;/code&gt;, &lt;code&gt;heap_start&lt;/code&gt; and &lt;code&gt;heap_size&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;solo5_start_info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cmdline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uintptr_t&lt;/span&gt; &lt;span class="n"&gt;heap_start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;heap_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cmdline&lt;/code&gt; is an argument string passed when the unikernel process is launched. As frankenlibc expects &lt;code&gt;envp&lt;/code&gt; and &lt;code&gt;argv&lt;/code&gt; will be passed from the host, cmdline is parsed into envp and argv in the initialization.&lt;br&gt;
rexec, a launch tool for frankenlibc, can pass a JSON config through a file descriptor. The FD value is shared using the environment variable (e.g. &lt;code&gt;__RUMP_FDINFO_CONFIGJSON&lt;/code&gt;). However, this method cannot be applied to Solo5 port because any environment variable cannot be shared with Solo5 guests. Therefore, the JSON config is passed from cmdline as a string in the Solo5 port.&lt;/p&gt;

&lt;p&gt;The other arguments &lt;code&gt;heap_start&lt;/code&gt; and &lt;code&gt;heap_size&lt;/code&gt; are information about heap provided by the tender. They are used for memory manager initialization. In this Solo5 port, the memory manager is a simple buddy allocator from &lt;a href="http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary"&gt;mini-os&lt;/a&gt;. It is used in the &lt;code&gt;mmap()&lt;/code&gt;/&lt;code&gt;munmap()&lt;/code&gt; &lt;a href="https://github.com/retrage/frankenlibc/blob/solo5/platform/solo5/mmap.c"&gt;platform code&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Devices
&lt;/h3&gt;

&lt;p&gt;In *nix system, most of the devices are represented as files and the operations are read/write to the file descriptor. frankenlibc also use this manner in platform code.&lt;br&gt;
rexec opens devices and passes the FD numbers through environment variables (e.g. &lt;code&gt;__RUMP_FDINFO_NET_tap&lt;/code&gt;). This behavior is the same as the JSON config. The franken layer registers devices using the FD info in &lt;a href="https://github.com/retrage/frankenlibc/blob/solo5/franken/init/fdinit.c"&gt;&lt;code&gt;fdinit()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Solo5, devices attached at runtime must be specified at build time. When building a guest, a JSON format config called Application Manifest &lt;code&gt;manifest.json&lt;/code&gt; must be supplied. It declares user-specified devices. In contrast to Solo5, frankenlibc rexec can specify devices at run time. As described before, current runnc can deal with one block device and one network device. Therefore, the Solo5 port uses fixed &lt;code&gt;manifest.json&lt;/code&gt; that specifies one block device &lt;code&gt;rootfs&lt;/code&gt; and one network device &lt;code&gt;tap&lt;/code&gt;. Below is the config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solo5.manifest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rootfs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BLOCK_BASIC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NET_BASIC"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A device in Solo5 is represented by &lt;code&gt;solo5_handle_t&lt;/code&gt;, not by the file descriptor. In the frankenlibc Solo5 port, as the devices are fixed, it assigns a virtual FD number to the Solo5 device handle.&lt;/p&gt;

&lt;p&gt;Solo5 provides interfaces for reading/writing devices and console. In &lt;code&gt;read()&lt;/code&gt;/&lt;code&gt;write()&lt;/code&gt; platform code, it identifies the FD number and call appropriate hypercalls.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;poll()&lt;/code&gt;/&lt;code&gt;clock_nanosleep()&lt;/code&gt; are used for waiting network packets. Each network device has file descriptor &lt;code&gt;pollfd&lt;/code&gt; to store polling state in frankenlibc. For Solo5 port, &lt;code&gt;solo5_yield()&lt;/code&gt; is used to implement &lt;code&gt;poll()&lt;/code&gt;/&lt;code&gt;clock_nanosleep()&lt;/code&gt; The behavior is almost the same as the Linux port.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;clock_nanosleep()&lt;/code&gt;, it calls &lt;code&gt;solo5_yield()&lt;/code&gt; and if the network handle is set on &lt;code&gt;ready_set&lt;/code&gt;, it updates the &lt;code&gt;pollfd.revents&lt;/code&gt; and wake the associated thread. In &lt;code&gt;poll()&lt;/code&gt;, it sleeps until &lt;code&gt;timeout&lt;/code&gt; and sets FD's &lt;code&gt;revents&lt;/code&gt; if &lt;code&gt;pollfd.revents&lt;/code&gt; is updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This post summarized LKL Nabla internals. The most of implementations are straight forward thanks to frankenlibc platform-independent interfaces and simple Solo5 hypercalls. However, since LKL has different interfaces with Rumprun, patches to runnc for LKL port is quite large. It will be better to have a switching option to change between Rumprun and LKL on runnc.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>unikernel</category>
      <category>anykernel</category>
    </item>
    <item>
      <title>Porting Linux to Nabla Containers</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Sat, 18 Apr 2020 08:20:05 +0000</pubDate>
      <link>https://dev.to/retrage/porting-linux-to-nabla-containers-j3</link>
      <guid>https://dev.to/retrage/porting-linux-to-nabla-containers-j3</guid>
      <description>&lt;p&gt;This is an introduction of Linux Kernel Library ported to Nabla Containers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nabla-containers/runnc.git"&gt;runnc&lt;/a&gt; is an OCI runtime that runs process-level isolated unikernels. It is built on the top of &lt;a href="https://github.com/Solo5/solo5"&gt;Solo5&lt;/a&gt;, a sandbox for unikernels, and several unikernels (MirageOS, IncludeOS, Rumprun) run on it. The original runnc uses Rumprun, a NetBSD based unikernel. However, as Docker is started from Linux, it is needed to have system call level compatibility with Linux. Therefore, I ported Linux Kernel Library (LKL) and musl libc to Solo5 and put together with runnc.&lt;/p&gt;

&lt;h2&gt;
  
  
  frankenlibc on Solo5
&lt;/h2&gt;

&lt;p&gt;frankenlibc is a set of tools to run Rump unikernels in various environments. It has a fork that ported LKL and some libraries. I used this frankenlibc fork and added Solo5 platform support.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/frankenlibc/tree/solo5"&gt;https://github.com/retrage/frankenlibc/tree/solo5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Building frankenlibc
&lt;/h3&gt;

&lt;p&gt;Clone the repository and checkout &lt;code&gt;solo5&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone https://github.com/retrage/frankenlibc.git
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;frankenlibc
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git checkout solo5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Clone full Solo5 repository to avoid build failure and update submodules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone https://github.com/Solo5/solo5.git
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git submodule update &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Apply some patches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;find patches/solo5/ &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; f&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;patch &lt;span class="nt"&gt;-p1&lt;/span&gt; &amp;lt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, run the build script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./build.sh &lt;span class="nt"&gt;-k&lt;/span&gt; linux notests solo5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find libraries and toolchain wrappers in &lt;code&gt;rump&lt;/code&gt; directory after building successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Even if &lt;code&gt;notests&lt;/code&gt; specified, &lt;code&gt;build.sh&lt;/code&gt; builds simple tests to &lt;code&gt;rumpobj/tests&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;tap100&lt;/code&gt; tap device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip tuntap add tap100 mode tap
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip addr add 10.0.0.1/24 dev tap100
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;dev tap100 up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;disk.img&lt;/code&gt; disk image. As LKL/frankenlibc creates directories on initialization, some operations fail if read-only ISO image is used. To avoid this issue, we use the Ext4 file system image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dd &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/zero &lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;disk.img &lt;span class="nv"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1024 &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;20480
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mkfs.ext4 &lt;span class="nt"&gt;-F&lt;/span&gt; disk.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that Solo5 requires an application manifest on build time, which is embedded in a unikernel binary. In current frankenlibc Solo5 support, the manifest is common across binaries and specifies &lt;code&gt;rootfs&lt;/code&gt; block device and &lt;code&gt;tap&lt;/code&gt; network device. We have to provide these devices even not used in the applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/frankenlibc/blob/solo5/platform/solo5/manifest.json"&gt;https://github.com/retrage/frankenlibc/blob/solo5/platform/solo5/manifest.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run &lt;code&gt;hello&lt;/code&gt; test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;RUMP_VERBOSE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ./rump/bin/rexec rumpobj/tests/hello rootfs:disk.img tap:tap100
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the Linux platform, &lt;code&gt;rexec&lt;/code&gt; provides a sandbox environment for unikernels using seccomp like Solo5's tenders. In the Solo5 platform, it is just a shell script wrapper for &lt;code&gt;spt&lt;/code&gt; tender.&lt;/p&gt;

&lt;h2&gt;
  
  
  LKL Nabla Containers
&lt;/h2&gt;

&lt;p&gt;Now, it's time to integrate with Nabla Containers. Since the original runnc imports older version of Solo5, I updated it and adapted the runnc code base.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/runnc/tree/lkl-musl"&gt;https://github.com/retrage/runnc/tree/lkl-musl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Updating Supplied Arguments
&lt;/h3&gt;

&lt;p&gt;Below is the original code that creates arguments for Solo5 tender.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--x-exec-heap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--mem="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s"&gt;"--net-mac="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--net="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--disk="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UniKernelBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;unikernelArgs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--x-exec-heap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--mem="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s"&gt;"--net="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--disk="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UniKernelBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;unikernelArgs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the latest Solo5 (frankenlibc Solo5 platform uses), &lt;code&gt;--net-mac&lt;/code&gt; option is removed and we can specify multiple block devices and network devices with &lt;code&gt;--block:&lt;/code&gt; and &lt;code&gt;--net:&lt;/code&gt; options. Ideally, it should support multiple devices. However, as described before, it can specify &lt;code&gt;rootfs&lt;/code&gt; and &lt;code&gt;tap&lt;/code&gt; only. So, the port ends up with the support of these devices like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NablaRunBin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--mem="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"--net:tap="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--block:rootfs="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;disk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UniKernelBin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating Disk Image
&lt;/h3&gt;

&lt;p&gt;I added &lt;code&gt;CreateExt4()&lt;/code&gt; function and &lt;code&gt;llmodules/fs/ext4_storage.go&lt;/code&gt; to create Ext4 rootfs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// CreateExt4 creates ext4 raw disk image from the dir argument&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateExt4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TempFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/tmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"nabla"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;fname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
        &lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unable to resolve abs target path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;absDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unable to resolve abs dir path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"virt-make-fs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"raw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ext4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;absDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unable to run virt-make-fs command"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;virt-make-fs&lt;/code&gt;, a part of &lt;a href="http://libguestfs.org/"&gt;libguestfs&lt;/a&gt; has similar interface with &lt;code&gt;genisoimage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It would be better to switch &lt;code&gt;NewISOFsHandler()&lt;/code&gt; and &lt;code&gt;NewExt4FsHandler()&lt;/code&gt; on run time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building and Installing runnc
&lt;/h3&gt;

&lt;p&gt;Same as original.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone https://github.com/retrage/runnc.git
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/github.com/retrage
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;/runnc &lt;span class="nv"&gt;$GOPATH&lt;/span&gt;/github.com/retrage/runnc
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;runnc
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git apply patches/0001-solo5-elf-segment-align-workaround.patch
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make build
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing with Docker Images
&lt;/h3&gt;

&lt;p&gt;I provided a set of Makefiles build LKL Nabla Container base Docker images. It builds Solo5 and frankenlibc, and Docker images.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/lkl-nabla-base-build"&gt;https://github.com/retrage/lkl-nabla-base-build&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also pushed pre-built Docker images to Docker Hub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/repository/docker/retrage/lkl-nabla-hello-base"&gt;retrage/lkl-nabla-hello-base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/repository/docker/retrage/lkl-nabla-python3-base"&gt;retrage/lkl-nabla-python3-base&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use images like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;runnc retrage/lkl-nabla-python3-base:
&lt;span class="go"&gt;latest -c "print(\'hello\')"
[sudo] password for akira:
nabla-run arg [/opt/runnc/bin/nabla-run --mem=512 --net:tap=tap28157ba5950e --bl
ock:rootfs=/var/run/docker/runtime-runnc/moby/28157ba5950e3e84824bd843fd1dafb06eccc7de2020a0619d6a5b463e5f2c2b/rootfs.img /var/lib/docker/overlay2/3d36c19950e53eefded8e1933f3d7e51990fc4c7b065be6c00776eeab8fb3136/merged/python3.nabla __RUMP_FDINFO_NET_tap=4 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=28157ba5950e PYTHONHASHSEED=1 PYTHONHOME=/usr/local HOME=/ -- -c print(\'hello\')]
            |      ___|
  __|  _ \  |  _ \ __ \
\__ \ (   | | (   |  ) |
____/\___/ _|\___/____/
Solo5: Bindings version v0.6.4-6-g756accf-dirty
Solo5: Memory map: 512 MB addressable:
Solo5:   reserved @ (0x0 - 0xfffff)
Solo5:       text @ (0x100000 - 0x889fff)
Solo5:     rodata @ (0x88a000 - 0xb4cfff)
Solo5:       data @ (0xb4d000 - 0xe7dfff)
&lt;/span&gt;&lt;span class="gp"&gt;Solo5:       heap &amp;gt;&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; 0xe7e000 &amp;lt; stack &amp;lt; 0x20000000
&lt;span class="go"&gt;sleeping 50000 usec
hello
Solo5: solo5_exit(0) called
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post, I introduced a brief of LKL Nabla Containers. It is still in an early stage and has room for improvement, but already runs practical applications like Python. I would like to measure the performance and evaluate the pros/cons.&lt;/p&gt;

&lt;p&gt;Below is the TODO list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace workaround for Solo5&lt;/li&gt;
&lt;li&gt;Flexible &lt;code&gt;manifest.json&lt;/code&gt; handling on build time&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Pass &lt;code&gt;lkl.json&lt;/code&gt; through run time arguments&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;Do not pass &lt;code&gt;__RUMP_FDINFO_NET_tap=4&lt;/code&gt; environment variable on run time&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Update: May 1st, 2020
&lt;/h2&gt;

&lt;p&gt;After wrote this post, I found that LKL must use network information created by the container runtime. Otherwise, the network does not work properly. I added the 3rd feature described in the above TODO list to frankenlibc and runnc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/frankenlibc/commit/fb4fde66c73c8bec58d754249db77edb66537955"&gt;add external lkl json config support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/runnc/commit/e73c1203e8a1b19d4813917d893aec6181432e01"&gt;Create lkl config json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The OCI runtime builds and passes JSON config for LKL at startup. LKL parses it along with environment variables and arguments.&lt;/p&gt;

&lt;p&gt;Now, popular network applications Nginx and redis work on LKL Nabla Containers. They are available as base Docker Images.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/repository/docker/retrage/lkl-nabla-nginx-base"&gt;retrage/lkl-nabla-nginx-base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/repository/docker/retrage/lkl-nabla-redis-base"&gt;retrage/lkl-nabla-redis-base&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>unikernel</category>
      <category>anykernel</category>
    </item>
    <item>
      <title>Debugging OVMF with GDB</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Mon, 09 Dec 2019 02:36:39 +0000</pubDate>
      <link>https://dev.to/retrage/debugging-ovmf-with-gdb-1nf7</link>
      <guid>https://dev.to/retrage/debugging-ovmf-with-gdb-1nf7</guid>
      <description>&lt;p&gt;In this blog post, I will describe how to debug OVMF using GDB without any special tool unlike another post[1].&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Mapping in UEFI
&lt;/h2&gt;

&lt;p&gt;On x64 UEFI, it provides flat single address memory space and places the firmware itself and UEFI images on the space without any memory protection. In this way, we can do source code level debugging any UEFI code with a debugger. On OVMF, each feature is modularized&lt;br&gt;
and the module is loaded as UEFI image. BootServices is included in &lt;code&gt;DxeCore.efi&lt;/code&gt;, loaded at boot time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Notify: PPI Guid: EE16160A-E8BE-47A6-820A-C6900DB0250A, Peim notify entry point: 836CA9
PlatformPei: ClearCacheOnMpServicesAvailable
DiscoverPeimsAndOrderWithApriori(): Found 0x0 PEI FFS files in the 1th FV
DXE IPL Entry
Loading PEIM D6A2CB7F-6A18-4E2F-B43B-9920A733700A
Loading PEIM at 0x00007EA8000 EntryPoint=0x00007EAB0BC DxeCore.efi
Loading DXE CORE at 0x00007EA8000 EntryPoint=0x00007EAB0BC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Debug Symbols in EDK2
&lt;/h2&gt;

&lt;p&gt;EDK2 build system generates debug symbol information &lt;code&gt;*.debug&lt;/code&gt; along with executables &lt;code&gt;*.efi&lt;/code&gt; on debug build (&lt;code&gt;-b DEBUG&lt;/code&gt;). If you use gcc (example: &lt;code&gt;GCC5&lt;/code&gt;), it compiles source code to ELF object files, link with custom linker script, and convert to PE format. Thus, the debug info is for ELF&lt;br&gt;
and can be recognized by GDB. On the other hand, Visual Studio and clang/lld (&lt;code&gt;CLANG9&lt;/code&gt;)[2] generates PE/COFF directly and the debug info may be PDB.&lt;/p&gt;

&lt;p&gt;To summarize, the points are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OVMF code is placed on the flat single memory space.&lt;/li&gt;
&lt;li&gt;GDB can debug EDK2 UEFI image built with gcc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look at how to debug OVMF.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building EDK2
&lt;/h2&gt;

&lt;p&gt;Build EDK2 using gcc as usual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github.com:tianocore/edk2.git
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;edk2
&lt;span class="nv"&gt;$ &lt;/span&gt;git submodule update &lt;span class="nt"&gt;--init&lt;/span&gt; &lt;span class="nt"&gt;--recursive&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nt"&gt;-C&lt;/span&gt; BaseTools
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ./edksetup.sh
&lt;span class="nv"&gt;$ &lt;/span&gt;build &lt;span class="nt"&gt;-p&lt;/span&gt; OvmfPkg/OvmfPkgX64.dsc &lt;span class="nt"&gt;-b&lt;/span&gt; DEBUG &lt;span class="nt"&gt;-a&lt;/span&gt; X64 &lt;span class="nt"&gt;-t&lt;/span&gt; GCC5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To make debugging easy, create a Makefile as follow. Note that we have to connect debugcon at 0x402 to dump debug information (&lt;code&gt;debug.log&lt;/code&gt;) from OVMF[4].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env make
&lt;/span&gt;
&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/bash

&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;debug.log
&lt;span class="nv"&gt;OVMFBASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;edk2/Build/OvmfX64/DEBUG_GCC5/
&lt;span class="nv"&gt;OVMFCODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(OVMFBASE)&lt;/span&gt;/FV/OVMF_CODE.fd
&lt;span class="nv"&gt;OVMFVARS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(OVMFBASE)&lt;/span&gt;/FV/OVMF_VARS.fd
&lt;span class="nv"&gt;QEMU&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;qemu-system-x86_64
&lt;span class="nv"&gt;QEMUFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;raw,file&lt;span class="o"&gt;=&lt;/span&gt;fat:rw:image &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pflash,format&lt;span class="o"&gt;=&lt;/span&gt;raw,readonly,file&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(OVMFCODE)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pflash,format&lt;span class="o"&gt;=&lt;/span&gt;raw,file&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$(OVMFVARS)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-debugcon&lt;/span&gt; file:&lt;span class="nv"&gt;$(LOG)&lt;/span&gt; &lt;span class="nt"&gt;-global&lt;/span&gt; isa-debugcon.iobase&lt;span class="o"&gt;=&lt;/span&gt;0x402 &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-serial&lt;/span&gt; stdio &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-nographic&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-nodefaults&lt;/span&gt;

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nv"&gt;$(QEMU)&lt;/span&gt; &lt;span class="nv"&gt;$(QEMUFLAGS)&lt;/span&gt;

&lt;span class="nl"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nv"&gt;$(QEMU)&lt;/span&gt; &lt;span class="nv"&gt;$(QEMUFLAGS)&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;run debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before debugging, run the firmware to get &lt;code&gt;debug.log&lt;/code&gt;. It may be better to provide &lt;code&gt;startup.nsh&lt;/code&gt; script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we have &lt;code&gt;debug.log&lt;/code&gt;. It includes the addresses of loaded UEFI images like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Loading PEIM at 0x00007EA8000 EntryPoint=0x00007EAB0BC DxeCore.efi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, extract text section (&lt;code&gt;.text&lt;/code&gt;) RVA from &lt;code&gt;*.efi&lt;/code&gt; PE binaries. This can be done by &lt;code&gt;readelf&lt;/code&gt; if it is ELF, but the images are PE format. Here we use &lt;a href="https://github.com/retrage/peinfo"&gt;retrage/peinfo&lt;/a&gt;[3].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone git@github.com:retrage/peinfo.git
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;peinfo
&lt;span class="nv"&gt;$ &lt;/span&gt;make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;peinfo extracts section information from a binary. This time we want to know VirtualAddress in RVA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name: .text
VirtualSize: 0x000204c0
VirtualAddress: 0x00000240
SizeOfRawData: 0x000204c0
PointerToRawData: 0x00000240
PointerToRelocations: 0x00000000
PointerToLinenumbers: 0x00000000
NumberOfRelocations: 0x0000
NumberOfLinenumbers: 0x0000
Characteristics: 0x60000020
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run following bash script with &lt;code&gt;debug.log&lt;/code&gt; and peinfo. This outputs a snippet of GDB script that adds symbol information (&lt;code&gt;add-symbol-file&lt;/code&gt;). It calculates the address of UEFI image text section from base address and VirtualAddress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"debug.log"&lt;/span&gt;
&lt;span class="nv"&gt;BUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"edk2/Build/OvmfX64/DEBUG_GCC5/X64"&lt;/span&gt;
&lt;span class="nv"&gt;PEINFO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"peinfo/peinfo"&lt;/span&gt;

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;Loading | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; efi | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;LINE&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f6&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"[:cntrl:]"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PEINFO&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 5 text | &lt;span class="nb"&gt;grep &lt;/span&gt;VirtualAddress | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;TEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"print(hex(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; + &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ADDR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;))"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;SYMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;efi/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;debug/g"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"add-symbol-file &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUILD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SYMS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEXT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bash gen_symbol_offsets.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; gdbscript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The generated GDB script is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PcdPeim.debug 0x82c380
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/ReportStatusCodeRouterPei.debug 0x831080
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/StatusCodeHandlerPei.debug 0x833100
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PlatformPei.debug 0x835100
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/PeiCore.debug 0x7ee8240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DxeIpl.debug 0x7ee3240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/S3Resume2Pei.debug 0x7edf240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/CpuMpPei.debug 0x7ed6240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DxeCore.debug 0x7ea8240
add-symbol-file edk2/Build/OvmfX64/DEBUG_GCC5/X64/DevicePathDxe.debug 0x7b8f240
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we are ready.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make debug
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's place a breakpoint at &lt;code&gt;BootServices-&amp;gt;HandleProtocol()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(gdb) source gdbscript
(gdb) b CoreHandleProtocol
(gdb) target remote localhost:1234
(gdb) c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The debugger stops, and we can do source code level debug.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   ┌──/home/akira/src/ovmf-debug/edk2/MdeModulePkg/Core/Dxe/Hand/Handle.c──────┐
   │933     CoreHandleProtocol (                                               │
   │934       IN EFI_HANDLE       UserHandle,                                  │
   │935       IN EFI_GUID         *Protocol,                                   │
   │936       OUT VOID            **Interface                                  │
   │937       )                                                                │
B+&amp;gt;│938     {                                                                  │
   │939       return CoreOpenProtocol (                                        │
   │940               UserHandle,                                              │
   │941               Protocol,                                                │
   │942               Interface,                                               │
   │943               gDxeCoreImageHandle,                                     │
   │944               NULL,                                                    │
   │945               EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL                     │
   └───────────────────────────────────────────────────────────────────────────┘
remote Thread 1 In: CoreHandleProtocol                      L938  PC: 0x7eb6ad4 



(gdb) 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2019/12/05 Postscript
&lt;/h3&gt;

&lt;p&gt;tnishinaga gave me the improved version of the script&lt;br&gt;
to support multiple search paths. Thank you!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"debug.log"&lt;/span&gt;
&lt;span class="nv"&gt;BUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./Build"&lt;/span&gt;
&lt;span class="nv"&gt;SEARCHPATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./Build/OvmfX64/DEBUG_GCC5/X64/ ./Build/Edk2SamplePkgX64/DEBUG_GCC5/X64/"&lt;/span&gt;
&lt;span class="nv"&gt;PEINFO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"peinfo/peinfo"&lt;/span&gt;

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LOG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;Loading | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; efi | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;LINE&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f6&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"[:cntrl:]"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;EFIFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SEARCHPATHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; f&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PEINFO&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EFIFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; 5 text | &lt;span class="nb"&gt;grep &lt;/span&gt;VirtualAddress | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;TEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"print(hex(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; + &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ADDR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;))"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;SYMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;efi/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;debug/g"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;SYMFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SEARCHPATHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SYMS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; f&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"add-symbol-file &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SYMFILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TEXT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[1] &lt;a href="https://jp3bgy.github.io/blog/uefi/2018/12/24/How-to-Source-Debug-OVMF.html"&gt;https://jp3bgy.github.io/blog/uefi/2018/12/24/How-to-Source-Debug-OVMF.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[2] &lt;a href="https://github.com/tianocore/edk2/commit/15330934dc860c20b2143c802f3b4285e89021e3"&gt;https://github.com/tianocore/edk2/commit/15330934dc860c20b2143c802f3b4285e89021e3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[3] &lt;a href="https://github.com/retrage/peinfo"&gt;https://github.com/retrage/peinfo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[4] &lt;a href="https://github.com/tianocore/tianocore.github.io/wiki/How-to-debug-OVMF-with-QEMU-using-GDB"&gt;https://github.com/tianocore/tianocore.github.io/wiki/How-to-debug-OVMF-with-QEMU-using-GDB&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firmware</category>
      <category>uefi</category>
      <category>ovmf</category>
      <category>gdb</category>
    </item>
    <item>
      <title>Librarizing Linux kernel for Unikernels</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Mon, 09 Dec 2019 02:30:45 +0000</pubDate>
      <link>https://dev.to/retrage/librarizing-linux-kernel-for-unikernels-1hek</link>
      <guid>https://dev.to/retrage/librarizing-linux-kernel-for-unikernels-1hek</guid>
      <description>&lt;p&gt;NOTE: This is a repost of my previous blog post on Medium.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@retrage/librarizing-linux-kernel-for-unikernels-2b021b281bee" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DqbLSi3p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/fit/c/96/96/0%2AqW_6PjwpPmsuLce9.png" alt="retrage"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@retrage/librarizing-linux-kernel-for-unikernels-2b021b281bee" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Librarizing Linux kernel for Unikernels | by retrage | Medium&lt;/h2&gt;
      &lt;h3&gt;retrage ・ &lt;time&gt;Jun 2, 2019&lt;/time&gt; ・ 9 min read
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KBvj_QRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/medium_icon-90d5232a5da2369849f285fa499c8005e750a788fdbf34f5844d5f2201aae736.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I ported the Linux kernel to Unikraft as an external library. This makes it possible to reuse the rich functions of the Linux kernel for Unikernel with less functionality. In this blog post, I describe the overview of the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linux Kernel Library
&lt;/h3&gt;

&lt;p&gt;The Linux kernel is a well-maintained mature open source OS kernel. Recently, there have been researches that propose reuse its components.&lt;a href="https://github.com/lkl/linux"&gt;The Linux Kernel Library (LKL)&lt;/a&gt; is one of them, which uses the Linux kernel as a form of Library OS with minimum modifications. LKL is not currently an official Linux project, but it is actively being developed (v4.19 is the latest). Below is the architecture of LKL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P7TvtRXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-architecture.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P7TvtRXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-architecture.png" alt="The architecture of LKL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LKL has a host-independent architecture named &lt;code&gt;lkl&lt;/code&gt;, and the actual host-dependent code is separated from the arch. The independent and dependent code is placed under &lt;code&gt;arch/lkl&lt;/code&gt; and &lt;code&gt;tools/lkl&lt;/code&gt; correspondingly. For POSIX host environment, &lt;code&gt;tools/lkl/lib/posix-host.c&lt;/code&gt; plays the role.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unikraft
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://xenproject.org/developers/teams/unikraft/"&gt;Unikraft&lt;/a&gt; is an experimental project by Xen Project which aims to build small and lightweight Unikernel images by providing divided Unikernel functions. The following is the architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7SBwfNrO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/unikraft-architecture.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7SBwfNrO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/unikraft-architecture.png" alt="The architecture of Unikraft"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unikraft itself consists of three parts: main libs, platform libs, and architecture libs. main libs contain architecture and platform independent libraries. platform libs provide platform dependent code as libraries. It currently supports Xen, KVM, and Linux userspace as platforms. architecture libs are libraries for architecture; x86, arm, and arm64. A user has to specify the target architecture and platform by Kconfig when building Unikraft application. The Unikraft build system generates a Unikernel image corresponding to each target.&lt;/p&gt;

&lt;p&gt;Unikraft supports external libraries along with internal libraries. There are several official external libraries in public such as newlib, lwip, compiler-rt, eigen, libcxx, libcxxabi, libunwind, and libuuid.&lt;/p&gt;

&lt;p&gt;For more details about porting external libraries to Unikraft, see &lt;a href="http://www.unikraft.org/developers-app.html"&gt;External Library Development&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  LKL on Unikraft
&lt;/h2&gt;

&lt;p&gt;Since Unikraft is still at an early stage, it does not have a mature network stack or file system. To tackle this issue, we ported LKL as an external library for Unikraft. Here we introduce two types of the port.&lt;/p&gt;

&lt;h3&gt;
  
  
  LKL on Unikraft v1
&lt;/h3&gt;

&lt;p&gt;First of all, we integrated LKL to Unikraft build system. The architecture is shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MXl9WOYl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-on-unikraft-v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MXl9WOYl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-on-unikraft-v1.png" alt="The architecture of LKL on Unikraft v1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this version of the port, we added new architecture and platform libraries for LKL. They are just stub and only used when specified in Kconfig. The disadvantage of this design is that it is impossible to build LKL for other architectures or platforms. In addition, it can not cooperate with other Unikraft libraries.&lt;/p&gt;

&lt;p&gt;The code is available at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/uk-lkl/unikraft/tree/retrage/lkl"&gt;uk-lkl/unikraft:retrage/lkl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  LKL on Unikraft v2
&lt;/h3&gt;

&lt;p&gt;Next, we introduce v2 which can be used as an actual library. Below is the overview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M-L-Jj5V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-on-unikraft-v2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M-L-Jj5V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://retrage.github.io/img/lkl-on-unikraft-v2.png" alt="The architecture of LKL on Unikraft v2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By this design, we can choose any architecture and platform in concept since LKL is separated from architecture and platform. In addition, other Unikraft libraries can use LKL functions.&lt;/p&gt;

&lt;p&gt;For implementation, we added a new host-dependent code called &lt;code&gt;uk-host.c&lt;/code&gt; to support Unikraft as a new LKL host environment. The LKL host-dependent code requires some primitives such as mutex, semaphore, thread, timer, etc. on the host side, however, Unikraft main libs cannot satisfy the requirements because of the lack of functionality. Therefore, we ported these primitives from &lt;a href="https://github.com/littlekernel/lk"&gt;littlekernel&lt;/a&gt;, an embedded kernel to LKL. The only LKL host has to do is that calling callback functions periodic time to run the preemptive scheduler. The port of littlekernel is independent of Unikraft. Here is the implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/linux/tree/retrage/fiber"&gt;retrage/linux:retrage/fiber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;p&gt;The port of LKL supports only x86_64 architecture and KVM platform for some reason.&lt;/p&gt;

&lt;p&gt;Unikraft has two types of libc implementation, newlib, and nolibc. newlib is an official external library that supports full libc functions. On the other hand, nolibc provides minimal libc functions so that general libc functions can be used even if newlib does not exist. This version of LKL port is designed to work with nolibc to reduce dependencies. However, since nolibc have enough functions and constants required by LKL, we added the following functions and constants to nolibc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stdbool&lt;/li&gt;
&lt;li&gt;fputc, putchar&lt;/li&gt;
&lt;li&gt;STD{IN,OUT,ERR}_FILENO&lt;/li&gt;
&lt;li&gt;strncat&lt;/li&gt;
&lt;li&gt;strtok_r&lt;/li&gt;
&lt;li&gt;setjmp/longjmp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The modified LKL expects the callback function is called periodically as mentioned above, but Unikraft does not provide an interface to register a callback function. Fortunately, it starts a periodic timer at startup, so we just added the interface.&lt;/p&gt;

&lt;p&gt;In the KVM platform, a final image is generated using the custom linker script. Since the LKL binary &lt;code&gt;liblkl.o&lt;/code&gt; has symbols that are not referred explicitly, they are deleted or hidden by linking using the linker script. For this reason, the linker script is modified so that the symbols from LKL are kept correctly.&lt;/p&gt;

&lt;p&gt;The modified Unikraft and the port of LKL is here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/uk-lkl/unikraft/tree/retrage/lkl-v2"&gt;uk-lkl/unikraft:retrage/lkl-v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/uk-lkl/lkl"&gt;uk-lkl/lkl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Demonstration
&lt;/h4&gt;

&lt;p&gt;To demonstrate LKL on Unikraft, we ported &lt;code&gt;tools/lkl/tests/boot&lt;/code&gt; from LKL as &lt;a href="https://github.com/uk-lkl/boot"&gt;uk-lkl/boot&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir unikraft &amp;amp;&amp;amp; cd unikraft
$ git clone git@github.com:uk-lkl/unikraft.git --branch=retrage/lkl-v2
$ mkdir libs &amp;amp;&amp;amp; cd libs
$ git clone --recursive git@github.com:uk-lkl/lkl.git
$ cd ..
$ mkdir apps &amp;amp;&amp;amp; cd apps
$ git clone git@github.com:uk-lkl/boot.git
$ cd boot
$ make menuconfi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Select x86 architecture and KVM guest platform. Save and exit Kconfig. Then, run make.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To run the final image, run &lt;code&gt;run.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./run.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It will output as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[    0.721134] ERR:  [libukboot] boot.c @ 88   : Failed to initialize bus driver 0x56b060: -1
Welcome to  _ __             _____
 __ _____  (_) /__ _______ _/ _/ /_
/ // / _ \/ /  '_// __/ _ `/ _/ __/
\_,_/_//_/_/_/\_\/_/  \_,_/_/ \__/
                  Titan 0.2~ebcb42a
1..33 # boot
* 1 mutex
ok 1 mutex
 ---
 time_us: 0
 log: |
 ...
* 2 semaphore
ok 2 semaphore
 ---
 time_us: 0
 log: |
 ...
* 3 join
ok 3 join
 ---
 time_us: 1
 log: |
  joined 7909384
 ...
* 4 start_kernel
ok 4 start_kernel
 ---
 time_us: 9281
 log: |
  [    0.000000] Linux version 4.19.0+ (akira@akira-Z270) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)) #1 Thu May 30 23:10:09 JST 2019
  [    0.000000] bootmem address range: 0x1c001000 - 0x1d000000
  [    0.000000] On node 0 totalpages: 4095
  [    0.000000]   Normal zone: 56 pages used for memmap
  [    0.000000]   Normal zone: 0 pages reserved
  [    0.000000]   Normal zone: 4095 pages, LIFO batch:0
  [    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
  [    0.000000] pcpu-alloc: [0] 0 
  [    0.000000] Built 1 zonelists, mobility grouping off.  Total pages: 4039
  [    0.000000] Kernel command line: mem=16M loglevel=8
  [    0.000000] Dentry cache hash table entries: 2048 (order: 2, 16384 bytes)
  [    0.000000] Inode-cache hash table entries: 1024 (order: 1, 8192 bytes)
  [    0.000000] Memory available: 16088k/16380k RAM
  [    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
  [    0.000000] NR_IRQS: 4096
  [    0.000000] lkl: irqs initialized
  [    0.000000] clocksource: lkl: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
  [    0.198000] lkl: time and timers initialized (irq1)
  [    2.093000] pid_max: default: 4096 minimum: 301
  [   15.926000] Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
  [   18.024000] Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
  [ 2722.817000] console [lkl_console0] enabled
  [ 2732.709000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
  [ 2760.874000] random: get_random_u32 called from bucket_table_alloc.isra.6+0x9b/0x250 with crng_init=0
  [ 2774.823000] NET: Registered protocol family 16
  [ 3121.319000] clocksource: Switched to clocksource lkl
  [ 3181.520000] NET: Registered protocol family 2
  [ 3261.648000] tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes)
  [ 3263.125000] TCP established hash table entries: 512 (order: 0, 4096 bytes)
  [ 3264.198000] TCP bind hash table entries: 512 (order: 0, 4096 bytes)
  [ 3265.141000] TCP: Hash tables configured (established 512 bind 512)
  [ 3286.743000] UDP hash table entries: 128 (order: 0, 4096 bytes)
  [ 3287.830000] UDP-Lite hash table entries: 128 (order: 0, 4096 bytes)
  [ 3456.331000] workingset: timestamp_bits=62 max_order=12 bucket_order=0
  [ 4041.077000] SGI XFS with ACLs, security attributes, no debug enabled
  [ 6032.987000] jitterentropy: Initialization failed with host not compliant with requirements: 2
  [ 6038.248000] io scheduler noop registered
  [ 6038.908000] io scheduler deadline registered
  [ 6067.383000] io scheduler cfq registered (default)
  [ 6068.093000] io scheduler mq-deadline registered
  [ 6068.764000] io scheduler kyber registered
  [ 7894.266000] NET: Registered protocol family 10
  [ 7979.259000] Segment Routing with IPv6
  [ 7988.492000] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
  [ 8097.859000] Warning: unable to open an initial console.
  [ 8106.456000] This architecture does not have kernel memory protection.
  [ 8107.119000] Run /init as init process
  lkl_start_kernel(&amp;amp;lkl_host_ops, "mem=16M loglevel=8") = 0 
 ...
* 5 getpid
ok 5 getpid
 ---
 time_us: 5
 log: |
  lkl_sys_getpid() = 1 
 ...
* 6 syscall_latency
ok 6 syscall_latency
 ---
 time_us: 126
 log: |
  avg/min/max: lkl:107822000/104000000/450000000 native:6788000/6000000/77000000
 ...
* 7 umask
ok 7 umask
 ---
 time_us: 0
 log: |
  lkl_sys_umask(0777) = 18 
 ...
* 8 umask2
ok 8 umask2
 ---
 time_us: 0
 log: |
  lkl_sys_umask(0) = 511 
 ...
* 9 creat
ok 9 creat
 ---
 time_us: 9
 log: |
  lkl_sys_creat("/file", access_rights) = 0 
 ...
* 10 close
ok 10 close
 ---
 time_us: 0
 log: |
  lkl_sys_close(0) = 0 
 ...
* 11 failopen
ok 11 failopen
 ---
 time_us: 9
 log: |
  lkl_sys_open("/file2", 0, 0) = -2 No such file or directory
 ...
* 12 open
ok 12 open
 ---
 time_us: 7
 log: |
  lkl_sys_open("/file", LKL_O_RDWR, 0) = 0 
 ...
* 13 write
ok 13 write
 ---
 time_us: 4
 log: |
  lkl_sys_write(0, wrbuf, sizeof(wrbuf)) = 5 
 ...
* 14 lseek_cur
ok 14 lseek_cur
 ---
 time_us: 0
 log: |
  lkl_sys_lseek(0, 0, LKL_SEEK_CUR) = 5 
 ...
* 15 lseek_end
ok 15 lseek_end
 ---
 time_us: 0
 log: |
  lkl_sys_lseek(0, 0, LKL_SEEK_END) = 5 
 ...
* 16 lseek_set
ok 16 lseek_set
 ---
 time_us: 0
 log: |
  lkl_sys_lseek(0, 0, LKL_SEEK_SET) = 0 
 ...
* 17 read
ok 17 read
 ---
 time_us: 1
 log: |
  lkl_sys_read=5 buf=test
 ...
* 18 fstat
ok 18 fstat
 ---
 time_us: 1
 log: |
  lkl_sys_fstat=0 mode=100721 size=5
 ...
* 19 mkdir
ok 19 mkdir
 ---
 time_us: 8
 log: |
  lkl_sys_mkdir("/mnt", access_rights) = 0 
 ...
* 20 stat
ok 20 stat
 ---
 time_us: 7
 log: |
  lkl_sys_stat("/mnt")=0 mode=40721
 ...
* 21 pipe2
ok 21 pipe2
 ---
 time_us: 9
 log: |
 ...
* 22 epoll
ok 22 epoll
 ---
 time_us: 5
 log: |
 ...
* 23 mount_fs_proc
ok 23 mount_fs_proc
 ---
 time_us: 18
 log: |
  lkl_mount_fs("proc") = 0 
 ...
* 24 chdir_proc
ok 24 chdir_proc
 ---
 time_us: 7
 log: |
  lkl_sys_chdir("proc") = 0 
 ...
* 25 open_cwd
ok 25 open_cwd
 ---
 time_us: 7
 log: |
 ...
* 26 getdents64
ok 26 getdents64
 ---
 time_us: 6
 log: |
  4 . .. fs bus irq net sys tty kmsg maps misc stat iomem crypto driver 
  mounts uptime vmstat cmdline cpuinfo devices ioports loadavg meminfo version 
  consoles kallsyms slabinfo softirqs zoneinfo buddyinfo diskstats interrupts 
  partitions timer_list 
 ...
* 27 close_dir_fd
ok 27 close_dir_fd
 ---
 time_us: 0
 log: |
  lkl_sys_close(dir_fd) = 0 
 ...
* 28 chdir_root
ok 28 chdir_root
 ---
 time_us: 7
 log: |
  lkl_sys_chdir("/") = 0 
 ...
* 29 umount_fs_proc
ok 29 umount_fs_proc
 ---
 time_us: 11
 log: |
  lkl_umount_timeout("proc", 0, 1000) = 0 
 ...
* 30 lo_ifup
ok 30 lo_ifup
 ---
 time_us: 44
 log: |
  lkl_if_up(1) = 0 
 ...
* 31 gettid
ok 31 gettid
 ---
 time_us: 0
 log: |
  7893000
 ...
* 32 many_syscall_threads
ok 32 many_syscall_threads
 ---
 time_us: 26
 log: |
 ...
* 33 stop_kernel
ok 33 stop_kernel
 ---
 time_us: 531
 log: |
  [145272.871000] reboot: Restarting system
  lkl_sys_halt() = 0 
 ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;p&gt;The current LKL on Unikraft has the following issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It needs modifications to Unikraft.&lt;/li&gt;
&lt;li&gt;It does not support disk operations and networks.&lt;/li&gt;
&lt;li&gt;It hangs under some certain situations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first issue is described above in details. The second issue is because of the lack of file system and network support by Unikraft. The third issue is not only on Unikraft, but also with &lt;a href="https://github.com/retrage/linux/tree/retrage/fiber"&gt;retrage/linux:retrage/fiber&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a design issue, the use of Linux kernel does not match with Unikraft policy. Unikraft aims to build 'slim' Unikernel images by building the necessary libraries, but LKL reuses existing Linux kernel which is 'fat'. The size of the final image tends to be large if LKL is integrated.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ieeexplore.ieee.org/document/5541547"&gt;LKL: The Linux kernel library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://xenproject.org/developers/teams/unikraft/"&gt;Unikraft - Xen Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.usenix.org/sites/default/files/conference/protected-files/lisa18_slides_kuenzer.pdf"&gt;Unikraft: Unikernels Made Easy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.unikraft.org/"&gt;Unikraft's Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>unikernel</category>
      <category>unikraft</category>
      <category>anykernel</category>
    </item>
    <item>
      <title>LKL.js: Running Linux Kernel on JavaScript *Directly*</title>
      <dc:creator>Akira Moroo</dc:creator>
      <pubDate>Mon, 09 Dec 2019 02:23:33 +0000</pubDate>
      <link>https://dev.to/retrage/lkl-js-running-linux-kernel-on-javascript-directly-63n</link>
      <guid>https://dev.to/retrage/lkl-js-running-linux-kernel-on-javascript-directly-63n</guid>
      <description>&lt;p&gt;NOTE: This is a repost of my previous post on Medium.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@retrage/lkl-js-running-linux-kernel-on-javascript-directly-9bc8c7abfc5d" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DqbLSi3p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/fit/c/96/96/0%2AqW_6PjwpPmsuLce9.png" alt="retrage"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@retrage/lkl-js-running-linux-kernel-on-javascript-directly-9bc8c7abfc5d" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;LKL.js: Running Linux Kernel on JavaScript *Directly* | by retrage | Medium&lt;/h2&gt;
      &lt;h3&gt;retrage ・ &lt;time&gt;Jul 25, 2018&lt;/time&gt; ・ 10 min read
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KBvj_QRD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/medium_icon-90d5232a5da2369849f285fa499c8005e750a788fdbf34f5844d5f2201aae736.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I ported Linux kernel directly on JavaScript. In other words, I translated the Linux kernel to JavaScript using Emscripten, and Unlike JSLinux, it runs without emulators.&lt;/p&gt;

&lt;p&gt;The following is the working repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/linux/tree/retrage/em-v2"&gt;https://github.com/retrage/linux/tree/retrage/em-v2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I published a demonstration site for LKL.js. Please enable SharedArrayBuffer and try it out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://retrage.github.io/lkl-js"&gt;LKL.js Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also published slides about LKL.js.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://speakerdeck.com/retrage/lkl-dot-js-running-linux-kernel-on-javascript-star-directly-star"&gt;https://speakerdeck.com/retrage/lkl-dot-js-running-linux-kernel-on-javascript-star-directly-star&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Linux Kernel Library (LKL)
&lt;/h2&gt;

&lt;p&gt;We use Linux Kernel Library (LKL) which makes the Linux kernel an anykernel. LKL is a fork of torvalds/linux. It is designed to put LKL specific code only in &lt;code&gt;arch/lkl&lt;/code&gt; and runs without modifications of other code. By this design, it makes easy to follow the mainline. (Currently v5.3) Since LKL is anykernel, it runs on user space of various OS such as Linux, FreeBSD, and Windows, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emscripten
&lt;/h2&gt;

&lt;p&gt;Emscripten is LLVM based C/C++ to &lt;br&gt;
JavaScript/WebAssembly transpiler.&lt;br&gt;
It also provides a Unix-like environment to run translated software&lt;br&gt;
on web browsers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Can we port LKL to JavaScript with Emscripten?
&lt;/h2&gt;

&lt;p&gt;LKL runs on various OSes, Emscripten provides Unix-like&lt;br&gt;
environment. So can LKL be ported to JavaScript with Emscripten?&lt;/p&gt;
&lt;h3&gt;
  
  
  Current Status of Linux Kernel Build with Clang
&lt;/h3&gt;

&lt;p&gt;First of all, the Linux kernel is deeply dependent on gcc-extension, and there is a doubt that Clang can not compile it. Once upon the time, there was LLVMLinux project that aims to compile Linux kernel with Clang. However, through the efforts of the Google Android team, two LTS (4.4 and 4.9) can be built with Clang. Now, LKL can be built with Clang.&lt;/p&gt;
&lt;h3&gt;
  
  
  LKL Build Flow 101
&lt;/h3&gt;

&lt;p&gt;Let's look at the build flow of LKL.&lt;br&gt;
First, when&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;make &lt;span class="nt"&gt;-C&lt;/span&gt; tools/lkl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;is performed, the build system determines which source code (*.c/*.S)&lt;br&gt;
to be built from the Kconfig settings and compiles them. Object files (*.o) generated by compiling are once archived by &lt;code&gt;ar&lt;/code&gt; to &lt;code&gt;built-in.o&lt;/code&gt;. Next, it links all &lt;code&gt;built-in.o&lt;/code&gt; files into &lt;code&gt;vmlinux&lt;/code&gt; at once. For host side code, files under &lt;code&gt;tools/lkl/lib&lt;/code&gt; compiled and linked to &lt;code&gt;liblkl.o&lt;/code&gt;. Finally, link all files (&lt;code&gt;vmlinux&lt;/code&gt; and &lt;code&gt;liblkl.o&lt;/code&gt;) to &lt;code&gt;liblkl.so&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a simple build flow of LKL.&lt;/p&gt;
&lt;h2&gt;
  
  
  Porting LKL with Emscripten
&lt;/h2&gt;

&lt;p&gt;Next, we will take a look at how to port LKL with Emscripten.&lt;/p&gt;

&lt;p&gt;Not limited to Emscripten, when using LLVM infrastructures, the compiler compiles source to target with the following flow.&lt;/p&gt;

&lt;p&gt;Soruce -&amp;gt; LLVM IR -&amp;gt; Target&lt;/p&gt;

&lt;p&gt;In this way, the source is once converted to LLVM IR (*.bc/*.ll) and then converted to the target. In Emscripten, the "linking" is the conversion from LLVM IR to JavaScript. Therefore, it is necessary to first convert all (including libc etc. provided by Emscripten) to LLVM IR.&lt;/p&gt;
&lt;h3&gt;
  
  
  Generating vmlinux.bc
&lt;/h3&gt;

&lt;p&gt;The build using &lt;code&gt;emcc&lt;/code&gt; (An Emscripten Clang wrapper) is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nt"&gt;-C&lt;/span&gt; tools/lkl &lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CC&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;AR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PY&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;/ar.py"&lt;/span&gt; &lt;span class="nv"&gt;V&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The two important things here are &lt;code&gt;$FCFLAS&lt;/code&gt; and &lt;code&gt;ar.py&lt;/code&gt;. I will explain each one. (Note that &lt;code&gt;C="$CC $CFLAGS"&lt;/code&gt; is forced to pass &lt;code&gt;$CFLAGS&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$CFLAGS&lt;/code&gt; is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s WASM=0"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s ASYNCIFY=1"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s EMULATE_FUNCTION_POINTER_CASTS=1"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s USE_PTHREADS=1"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s PTHREAD_POOL_SIZE=4"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -s TOTAL_MEMORY=1342177280"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The options are to pass to Emscripten. Please refer to the Emscripten manual for details.&lt;/p&gt;

&lt;p&gt;Furthermore, the following definitions are specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DMAX_NR_ZONES=2"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DNR_PAGEFLAGS=20"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DSPINLOCK_SIZE=0"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DF_GETLK64=12"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DF_SETLK64=13"&lt;/span&gt;
&lt;span class="nv"&gt;CFLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CFLAGS&lt;/span&gt;&lt;span class="s2"&gt; -DF_SETLKW64=14"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These values are originally obtained by compiling an empty file at the time of Linux kernel build. However, this time they can not be obtained directly. Therefore, we have to specify these values which come from when building with the x86_64 environment.&lt;/p&gt;

&lt;p&gt;Next, I will explain &lt;code&gt;ar.py&lt;/code&gt;. The following is a snippet of &lt;code&gt;ar.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"objs"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="n"&gt;objs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;".o"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="s"&gt;"built-in"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;objs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"aw"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As explained above, the build system of Linux kernel gathers object files by &lt;code&gt;ar&lt;/code&gt; and links them to get &lt;code&gt;vmlinux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To work with Emscripten we need to get &lt;code&gt;vmlinux&lt;/code&gt; as a LLVM bitcode. LLVM has a linker called &lt;code&gt;llvm-link&lt;/code&gt; that links multiple LLVM bitcode files to get one LLVM bitcode. To generate &lt;code&gt;vmlinux.bc&lt;/code&gt;, we need to use &lt;code&gt;llvm-link&lt;/code&gt;, but there is a problem. &lt;code&gt;llvm-link&lt;/code&gt; can not take archive files as arguments like &lt;code&gt;ld&lt;/code&gt;s. Therefore, we have to record object files that are originally archived. In this case, &lt;code&gt;ar.py&lt;/code&gt; will record them as file paths in &lt;code&gt;objs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, Let's look at the part of &lt;code&gt;vmlinux.bc&lt;/code&gt; generation. I added following scripts to &lt;code&gt;scripts/link-vmlinux.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;info CLEAN obj 
python &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;srctree&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/clean-obj.py"&lt;/span&gt;

info GEN link-vmlinux.sh
python &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;srctree&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/link-vmlinux-gen.py"&lt;/span&gt;

info LINK vmlinux
bash &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;srctree&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/link-vmlinux.sh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;clean-obj.py&lt;/code&gt; removes duplicated file paths from &lt;code&gt;objs&lt;/code&gt; which is generated by &lt;code&gt;ar.py&lt;/code&gt;. &lt;code&gt;link-vmlinux-gen.py&lt;/code&gt; generates &lt;code&gt;vmlinux-link.sh&lt;/code&gt; (not &lt;code&gt;scripts/link-vmlinux.sh&lt;/code&gt;) which performs &lt;code&gt;llvm-link&lt;/code&gt;. By performing &lt;code&gt;vmlinux-link.sh&lt;/code&gt;, we can get &lt;code&gt;vmlinux.bc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the flow of generating &lt;code&gt;vmlinux.bc&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating boot.js
&lt;/h3&gt;

&lt;p&gt;Next, I will look at until JavaScript code is generated. As explained above, since LKL is one of Library OS, &lt;code&gt;vmlinux&lt;/code&gt; does not work on its own, it works only when it has a part of an application. In this case, our target is &lt;code&gt;tools/lkl/tests/boot&lt;/code&gt; which is LKL's &lt;code&gt;Hello, world&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$LINK&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot.bc &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot-in.o &lt;span class="nv"&gt;$LKL&lt;/span&gt;/lib/liblkl-in.o &lt;span class="nv"&gt;$LKL&lt;/span&gt;/lib/lkl.o
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, we have to link &lt;code&gt;vmlinux.bc&lt;/code&gt; (&lt;code&gt;$LKL/lib/lkl.o&lt;/code&gt;), host dependent part &lt;code&gt;$LKL/lib/liblkl-in.o&lt;/code&gt; and applicatin part &lt;code&gt;$LKL/tests/boot-in.o&lt;/code&gt; and get &lt;code&gt;$LKL/tests/boot.bc&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$DIS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot.ll &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot.bc
&lt;span class="nv"&gt;$CP&lt;/span&gt; ~/.emscripten_cache/asmjs/dlmalloc.bc js/dlmalloc.bc
&lt;span class="nv"&gt;$CP&lt;/span&gt; ~/.emscripten_cache/asmjs/libc.bc js/libc.bc
&lt;span class="nv"&gt;$CP&lt;/span&gt; ~/.emscripten_cache/asmjs/pthreads.bc js/pthreads.bc
&lt;span class="nv"&gt;$DIS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; js/dlmalloc.ll js/dlmalloc.bc
&lt;span class="nv"&gt;$DIS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; js/libc.ll js/libc.bc
&lt;span class="nv"&gt;$DIS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; js/pthreads.ll js/pthreads.bc
&lt;span class="nv"&gt;$PY&lt;/span&gt; rename_symbols.py &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot.ll &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot-mod.ll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, it disassembles all LLVM bitcode files (&lt;code&gt;$LKL/tests/boot.bc&lt;/code&gt; and &lt;code&gt;libc.bc&lt;/code&gt; etc.) using &lt;code&gt;llvm-dis&lt;/code&gt;. Next, it applies &lt;code&gt;rename_symbols.py&lt;/code&gt; to &lt;code&gt;boot.ll&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is a reason for performing such operations. This is because function names used in the Linux kernel conflict with function names used in libcs. In normal LKL, this conflict is avoided by using ELF linker tricks. Meanwhile, since JavaScript generated by Emscripten does not have a namespace, such collisions occur. Therefore, by rewriting the functions names that would collide with &lt;code&gt;rename_symbols.py&lt;/code&gt;, it can avoid collisions.&lt;/p&gt;

&lt;p&gt;In addition, &lt;code&gt;rename_symbols.py&lt;/code&gt; also performs operations such as converting inline assemblies in Linux kernel to Emscripten &lt;code&gt;emscripten_asm_const_int&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;boot-mod.ll&lt;/code&gt;,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;EMCC_DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;$CC&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; js/boot.html &lt;span class="nv"&gt;$LKL&lt;/span&gt;/tests/boot-mod.ll &lt;span class="nv"&gt;$CFLAGS&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;generate HTML and JavaScript files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Workarounds
&lt;/h2&gt;

&lt;p&gt;Although we generated the Linux kernel translated in "completely" JavaScript and the application &lt;code&gt;boot.js&lt;/code&gt;, it will not work as it is. This is due to the fact that the architecture of computers and JavaScript is very different. So we have to make some modifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replacing inline assemblies
&lt;/h3&gt;

&lt;p&gt;In the Linux kernel, the architecture-dependent code is basically placed&lt;br&gt;
under &lt;code&gt;arch/$ARCH&lt;/code&gt;, and another code is architecture independent. However, an empty inline assembly may be inserted so that optimization by the compiler prevents meaningful code from being lost at compile time. Here is an example, &lt;code&gt;set_normalized_timespec64&lt;/code&gt; in &lt;code&gt;kernel/time/time.c&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;set_normalized_timespec64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timespec64&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time64_t&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s64&lt;/span&gt; &lt;span class="n"&gt;nsec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nsec&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;NSEC_PER_SEC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*
         * The following asm() prevents the compiler from
         * optimising this loop into a modulo operation. See
         * also __iter_div_u64_rem() in include/linux/time.h
         */&lt;/span&gt;
        &lt;span class="n"&gt;asm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"+rm"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nsec&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;nsec&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;NSEC_PER_SEC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nsec&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;asm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"+rm"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nsec&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;nsec&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;NSEC_PER_SEC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tv_sec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tv_nsec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nsec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Such Inline assemblies cause a failure to convert from LLVM bitcode to&lt;br&gt;
JavaScript. Therefore, we have to replace inline assemblies such as &lt;code&gt;asm("" : "+rm"(nsec))&lt;/code&gt; with &lt;code&gt;emcsripten_asm_const_int&lt;/code&gt; which calls JavaScript code from C defined in Emscripten.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fix early_param
&lt;/h3&gt;

&lt;p&gt;In the Linux kernel, there is &lt;code&gt;early_param&lt;/code&gt;. This is defined in &lt;code&gt;include/linux/init.h&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;obs_kernel_param&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;setup_func&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;early&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cm"&gt;/* snip */&lt;/span&gt;
&lt;span class="cp"&gt;#define __setup_param(str, unique_id, fn, early)            \
    static const char __setup_str_##unique_id[] __initconst     \
        __aligned(1) = str;                     \
    static struct obs_kernel_param __setup_##unique_id      \
        __used __section(.init.setup)               \
        __attribute__((aligned((sizeof(long)))))        \
        = { __setup_str_##unique_id, fn, early }
&lt;/span&gt;&lt;span class="cm"&gt;/* snip */&lt;/span&gt;
&lt;span class="cp"&gt;#define early_param(str, fn)                        \
    __setup_param(str, fn, fn, 1)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;early_param&lt;/code&gt; is a macro, taking &lt;code&gt;str&lt;/code&gt; and &lt;code&gt;fn&lt;/code&gt; as arguments, and &lt;code&gt;obs_kernel_param&lt;/code&gt; structure placed in &lt;code&gt;.init.setup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By referring to &lt;code&gt;arch/lkl/kernel/vmlinux.ldS&lt;/code&gt; which is generated in the build of LKL, we can see that &lt;code&gt;.init.setup&lt;/code&gt; is arranged between &lt;code&gt;__setup_start&lt;/code&gt; and &lt;code&gt;__setup_end&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;__setup_start = .; KEEP(*(.init.setup)) __setup_end = .;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These symbols will be used in &lt;code&gt;init/main.c&lt;/code&gt; as follows. Here it compares one of boot parameter (&lt;code&gt;param&lt;/code&gt;) of Linux kernel with &lt;code&gt;str&lt;/code&gt; of &lt;code&gt;obs_kernel_param&lt;/code&gt; in &lt;code&gt;.init.setup&lt;/code&gt;. If it matches, it will execute &lt;code&gt;(*setup_func)(char*)&lt;/code&gt; with argument &lt;code&gt;val&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* Check for early params. */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;do_early_param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;obs_kernel_param&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;__setup_start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;__setup_end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;early&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;parameq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
             &lt;span class="n"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"earlycon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setup_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;pr_warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Malformed early option '%s'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="cm"&gt;/* We accept everything at this stage. */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In summary, &lt;code&gt;do_early_param&lt;/code&gt; executes &lt;code&gt;setup_func&lt;/code&gt; registered by &lt;code&gt;early_param&lt;/code&gt; by referring boot parameters.&lt;/p&gt;

&lt;p&gt;However, since it uses ELF symbols, it does not work correctly in JavaScript. For this reason, the function which will be called here is hard coded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;do_early_param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/* XXX: There is a lot of early_param, but hardcode in init/main.c */&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;early_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX_INIT_ARGS&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"quiet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"loglevel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;early_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;early_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                     &lt;span class="n"&gt;strcmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;early_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"earlycon"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* debug */&lt;/span&gt;
                                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_kernel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="n"&gt;pr_warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Malformed early option '%s'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* quiet */&lt;/span&gt;
                                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quiet_kernel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="n"&gt;pr_warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Malformed early option '%s'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* loglevel */&lt;/span&gt;
                                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                        &lt;span class="n"&gt;pr_warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Malformed early option '%s'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                &lt;span class="nl"&gt;default:&lt;/span&gt;
                                &lt;span class="n"&gt;pr_warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unknown early option '%s'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/* We accept everything at this stage. */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Fix initcall
&lt;/h3&gt;

&lt;p&gt;Like &lt;code&gt;early_param&lt;/code&gt;, &lt;code&gt;initcall&lt;/code&gt; which are called in the initialization manages functions using ELF symbols. With JavaScript alone, we can not know which function should be called. Therefore, we have to generate inticall tables from &lt;code&gt;System.map&lt;/code&gt; generated by a normal build of LKL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;SIG&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="n"&gt;initcall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SIG&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="n"&gt;initcalls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initcall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initcalls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/* initcall{} */"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EM_ASM({"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;initcall&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;initcall&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;blacklist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"    /* _"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;initcall&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;"(); */"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"    _"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;initcall&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;"();"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"});"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above is the initcall table generation script. We hard-code the code to &lt;code&gt;do_initcalls&lt;/code&gt;. &lt;code&gt;EM_ASM&lt;/code&gt; is an inline assembly that directly calls the JavaScript code in C.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;__init&lt;/span&gt; &lt;span class="nf"&gt;do_initcalls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/* XXX: initcalls are broken, so hardcode here */&lt;/span&gt;
        &lt;span class="cm"&gt;/* initcall0 */&lt;/span&gt;
        &lt;span class="n"&gt;EM_ASM&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="n"&gt;_net_ns_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="cm"&gt;/* initcall1 */&lt;/span&gt;
        &lt;span class="n"&gt;EM_ASM&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="n"&gt;_lkl_console_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;_wq_sysfs_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;_ksysfs_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="cm"&gt;/* snip */&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Demonstration and the Results
&lt;/h2&gt;

&lt;p&gt;As described at the top, LKL.js uses pthread, we have to enable SharedArrayBuffer. Although every modern web browsers are shipped with SharedarrayBuffer, it is disabled by default because of Spectre mitigation in Mozilla Firefox. Therefore, please enable it before executing the demo.&lt;/p&gt;

&lt;p&gt;The following is the result of &lt;code&gt;start_kernel&lt;/code&gt;. We can see that it shows dmesg on browsers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  [    0.000000] Linux version 4.16.0+ (akira@akira-Z270) () #13 Tue Jul 17 23:01:19 JST 2018
  [    0.000000] bootmem address range: 0x675000 - 0x1674000
  [    0.000000] On node 0 totalpages: 4095
  [    0.000000]   Normal zone: 36 pages used for memmap
  [    0.000000]   Normal zone: 0 pages reserved
  [    0.000000]   Normal zone: 4095 pages, LIFO batch:0
  [    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
  [    0.000000] pcpu-alloc: [0] 0 
  [    0.000000] Built 1 zonelists, mobility grouping off.  Total pages: 4059
  [    0.000000] Kernel command line: mem=16M loglevel=8
  [    0.000000] Parameter  is obsolete, ignored
  [    0.000000] Parameter  is obsolete, ignored
  [    0.000000] Dentry cache hash table entries: 2048 (order: 1, 8192 bytes)
  [    0.000000] Inode-cache hash table entries: 1024 (order: 0, 4096 bytes)
  [    0.000000] Memory available: 16144k/16380k RAM
  [    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
  [    0.000000] NR_IRQS: 1024
  [    0.000000] lkl: irqs initialized
  [    0.000000] clocksource: lkl: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
  [    0.000100] lkl: time and timers initialized (irq1)
  [    0.001100] pid_max: default: 4096 minimum: 301
  [    0.009400] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
  [    0.009900] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
  [    0.327100] console [lkl_console0] enabled
  [    0.329600] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
  [    0.329700] xor: automatically using best checksumming function   8regs     
  [    0.341199] NET: Registered protocol family 16
  [    0.388999] clocksource: Switched to clocksource lkl
  [    0.414100] NET: Registered protocol family 2
  [    0.437700] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes)
  [    0.438199] TCP established hash table entries: 1024 (order: 0, 4096 bytes)
  [    0.439000] TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
  [    0.439600] TCP: Hash tables configured (established 1024 bind 1024)
  [    0.443200] UDP hash table entries: 256 (order: 0, 4096 bytes)
  [    0.444000] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
  [    0.472100] workingset: timestamp_bits=30 max_order=12 bucket_order=0
  [    0.863100] SGI XFS with ACLs, security attributes, no debug enabled
  [    0.923700] jitterentropy: Initialization failed with host not compliant with requirements: 2
  [    0.924599] io scheduler noop registered
  [    0.924900] io scheduler deadline registered
  [    0.933099] io scheduler cfq registered (default)
  [    0.933500] io scheduler kyber registered
  [    1.633500] NET: Registered protocol family 10
  [    1.658400] Segment Routing with IPv6
  [    1.660800] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
  [    1.674200] ------------[ cut here ]------------
  [    1.675500] WARNING: CPU: 0 PID: 0 at arch/lkl/kernel/setup.c:188   (null)
  [    1.675899] Call Trace:
  [    1.676200] 
  [    1.676999] ---[ end trace 941dc55fe0966cff ]---
  [    1.684299] Warning: unable to open an initial console.
  [    1.685200] This architecture does not have kernel memory protection.
  pthread_join((pthread_t)tid, NULL): No such process
  lkl_start_kernel(&amp;amp;lkl_host_ops, "mem=16M loglevel=8") = 0 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;From the above results, we confirmed that Linux kernel was booted directly in JavaScript. However, it just outputted dmesg and it is not suitable for practical use at all. This is because of the following problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It fails to create kernel threads.&lt;/li&gt;
&lt;li&gt;It fails to mount rootfs.&lt;/li&gt;
&lt;li&gt;It fails to execute init (PID 1).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, support for pthreads in Emscripten is not good. We extracted semaphore, mutex, and thread from Little Kernel (LK) and add them to LKL as green threads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/retrage/linux/tree/retrage/fiber"&gt;https://github.com/retrage/linux/tree/retrage/fiber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We plan to create LKL.js using this green threads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We created a Linux kernel fully translated in JavaScript using LKL and Emscripten. It boots the Linux kernel and we confirmed that it shows dmesg. Although the architecture is greatly different between computers and JavaScript, we found that it works somewhat by adding some fixes and workarounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lkl/linux"&gt;https://github.com/lkl/linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kripken/emscripten"&gt;https://github.com/kripken/emscripten&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://llvm.org/"&gt;https://llvm.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://clang.llvm.org/"&gt;https://clang.llvm.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.linuxfoundation.org/llvmlinux"&gt;https://wiki.linuxfoundation.org/llvmlinux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/734071/"&gt;https://lwn.net/Articles/734071/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://llvm.org/docs/CommandGuide/llvm-link.html"&gt;http://llvm.org/docs/CommandGuide/llvm-link.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://0xax.gitbooks.io/linux-insides/Concepts/linux-cpu-3.html"&gt;https://0xax.gitbooks.io/linux-insides/Concepts/linux-cpu-3.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/littlekernel/lk"&gt;https://github.com/littlekernel/lk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>javascript</category>
      <category>unikernel</category>
      <category>emscripten</category>
    </item>
  </channel>
</rss>
