EFI stubなArch Linuxのインストール

QEMU上の仮想マシンEFI stubなArch Linuxをインストールする。 ここでのホストはUbuntu 16.04.4 TLSとする。 なお[1][2][3][4]を参考にした。

OVMFのダウンロードとArch Linuxのインストールディスクのダウンロード

最初にOVMFをダウンロードして解凍する。 OVMFはTianoCoreをベースにした仮想マシン向けのUEFI実装である。

$ wget https://www.kraxel.org/repos/jenkins/edk2/edk2.git-ovmf-x64-0-20180508.84.g7cd8a57599.noarch.rpm
$ rpm2cpio edk2.git-ovmf-x64-0-20180508.84.g7cd8a57599.noarch.rpm | cpio -idmv
$ cp usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd .
$ cp usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd .

Arch Linuxのインストールディスクをダウンロードする。

$ wget http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/iso/2018.05.01/archlinux-2018.05.01-x86_64.iso

インストール先のディスクイメージを作成する。

$ qemu-img create -f raw arch-amd64.img 32G

仮想マシンの起動と設定

インストールディスクから起動する。 これ以降は仮想マシンでの操作となる。

$ qemu-system-x86_64 -enable-kvm -k ja -m 2048 -localtime -drive if=pflash,format=raw,readonly,file=OVMF_CODE-pure-efi.fd -drive if=pflash,format=raw,file=OVMF_VARS-pure-efi.fd -hda arch-amd64.img -net nic,model=e1000 -net user -cdrom archlinux-2018.05.01-x86_64.iso -boot d

キーボードレイアウトを設定。

# loadkeys jp106

gdiskパーティションを作成。 ここでは/dev/sda1を512MBのEFIパーティション、 /dev/sda2を残りのすべての容量としたLinuxパーティションとした。

# gdisk /dev/sda
Command (? for help):o
Command (? for help):n
Permission number: 1
First sector     : 
Last sector      : +512M
Hex code or GUID : ef00
Command (? for help):n
Permission number: 2
First sector     : 
Last sector      :  
Hex code or GUID : 8300

最後に書き込みを行う。

Command (? for help):w

パーティションをフォーマット

# mkfs.vfat -F32 /dev/sda1
# mkfs.ext4 /dev/sda2

それぞれをマウント。

# mount /dev/sda2
# mkdir -p /mnt/boot
# mount /dev/sda1 /mnt/boot

ダウンロードのミラーサイトを設定。

# nano /etc/pacman.d/mirrorlist

システムのインストール。

# pacstrap -i /mnt base base-devel

fstabの生成。

# genfstab -U -p /mnt >> /mnt/etc/fstab

localeの設定。

# locale-gen
# echo LANG=en_US.UTF-8 > /etc/locale.conf
# export LANG=en_US.UTF-8

キーボードマップの設定。

# echo KEYMAP=jp106 > /etc/vconsole.conf

localtimeの設定。

# rm /etc/localtime
# ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# hwclock -u -w

ホスト名の設定。

# echo "arch-vm" > /etc/hostname

DHCPクライアントの設定。

# systemctl enable dhcpcd.service

パスワードの設定。

# passwd

GRUB2の代わりにefibootmgrEFI Variableを設定。

# efibootmgr -d /dev/sda -p 1 -c -L "Arch Linux" -l /vmlinuz-linux -u "root=dev/sda2 rw initrd=initramfs-linux.img"
# efibootmgr -v

exitしてhalt。

# exit
# halt

以下で正しく起動することを確認。

$ qemu-system-x86_64 -enable-kvm -k ja -m 2048 -localtime -drive if=pflash,format=raw,readonly,file=OVMF_CODE-pure-efi.fd -drive if=pflash,format=raw,file=OVMF_VARS-pure-efi.fd -hda arch-amd64.img -net nic,model=e1000 -net user

EFI stubなLinux kernelのビルド

先の説明でインストールしたArch LinuxEFI stubとなっている。 ここでは、ホストでLinux kernelをビルドしそれを仮想マシンにインストールしてみる。

Linuxカーネルのビルド

カーネルをダウンロードする。

$ git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux.git --branch v4.17 --depth 1

ホストのconfigをコピーして多少の修正を行い、ホスト上でビルドする。 make menuconfigCONFIG_EFI_STUB=yとなっていることを確認する。 makeするときのjob数はホストのCPUのコア数に応じて変更する。

$ cp /boot/config-4.15.0-33-generic .config
$ make menuconfig
$ make -j9

Linux kernelの仮想マシンへのインストール

仮想マシンのディスクイメージをマウントする。

# /sbin/kpartx -av arch-amd64.img
# mount /dev/mapper/loop0p2 /mnt

ホストでビルドしたカーネル仮想マシンにインストールする。

# make INSTALL_MOD_PATH=/mnt modules_install
# mkdir -p /mnt/var/tmp
# cp System.map /mnt/var/tmp
# cp arch/x86_64/boot/bzImage /mnt/var/tmp
# umount /mnt

最後に仮想マシン上でホストでビルドしたbzImageとSystem.mapをコピーし、 initramfsを生成する。

# cp -f /var/tmp/bzImage /boot/vmlinuz-linux
# cp -f /var/tmp/System.map /boot/System.map
# mkinitcpio -c /etc/mkinitcpio.conf -g /boot/initramfs-linux.img

最後に再起動し、ビルドしたバージョンのカーネルであることを確認する。

参考文献

技術書典5で「UEFI読本 基礎編 Linux編」を頒布

2018年10月8日に池袋サンシャインシティで開催される 技術書典5において「海洋軟件」として 「UEFI読本 基礎編 Linux編」を頒布する. 配置先は「お09」である.

UEFI読本 基礎編 Linux

以下,本書「はじめに」より抜粋.

UEFIが2005年に登場してから10年以上が経過した。 現在のx86系CPUを搭載したコンピュータのほとんどが UEFIに対応しており、かつOSも当然のように対応している。 しかし、UEFIやそこからの起動を解説をした文書は非常に少なく、 規格書かソースコードを読み解くしかなかった。 本書はそのような現状に応えるべく企画された。

本書は「UEFI読本 基礎編 Linux編」というUEFIについての解説書である。 「基礎編」と「Linux編」の2部構成となっており、 「基礎編」ではUEFIでのOSの起動を知るためのUEFIの基礎について解説を行い、 「Linux編」ではLinux kernelのソースコードを実際に追跡してみていく。

LKL.js: Linux kernelを直接JavaScript上で動かす

Linux kernelを直接JavaScript上で動かした. つまり,JSLinuxのようにEmulatorをJavaScriptで作成し, その上でLinuxを動かすのではなく, JavaScriptで書かれたLinuxを生成し,それを動かす,ということである.

f:id:retrage01:20180721131907p:plain
LKL.js Architecture

リポジトリは以下の通り.

なお lkl.js Demo にデモを用意した. SharedArrayBufferを有効にして試してみてほしい.

続きを読む

HiFive1でZephyr

HiFive1とは,SiFiveによって開発されたRISC-V搭載のArduino互換ボードである. 一方,Zephyrは,Linux Foundationにより開発が進められている組み込み向けOSである. upstreamのZephyrはHiFive1に対応している. ここでは,ZephyrをHiFive1向けにビルドしてみる.

続きを読む

RustでBrainfuck処理系を高速化して遊んでみる

Brainfuckとは><+-.,[]の8つの命令からなるプログラミング言語である. 実装が簡単であるために,すでに多くの言語によって実装がなされている. ここでは, Adventures in JIT compilation: Part 1 - an interpreter を参考にC++の実装をRustに移植し,そのパフォーマンスを計測し,比較をして遊んでみる.

Brainfuckの実装

実装したBrainfuck

  • simpleinterp
  • optinterp
  • optinterp2
  • optinterp3

の4通りがある.

simpleinterpは素朴な実装であり,高速化はなされていない. optinterpは[]の対応表を実行時に作成することにより最適化を図っている. optinterp2は8つの命令に加えて高水準な命令を定義し, 局所的に実行される命令をそれらの命令に置き換えることで最適化を行う. optinterp3はさらに実行されるループに使われるパターンを高水準な命令に置き換え,最適化を行う.

実装の概要については BrainF*ckの高速化 において解説している.

ベンチマークと計測方法

先に挙げたブログ内では mandelbrotfactorの2つのスクリプトベンチマークに用いている. ここでもこれらのスクリプトを用いることとする.

実行速度の計測にはtimeを用いる. 計測時には--releaseオプションを指定し,最適化がなされるようにした.

実行環境は

MacBook Air (11-inch, Early 2014)
CPU: 1.7 GHz Intel Core i7
RAM: 8GB 1600 MHz DDR3
OS: macOS High Sierra 10.13.5
cargo: 1.26.0
rustc: 1.26.2

である.

mandelbrot

mandelbrotの場合の比較.

simpleinterp: cargo run --release mandelbrot.bf  47.78s user 0.14s system 99% cpu 48.037 total
optinterp:    cargo run --release mandelbrot.bf  25.90s user 0.10s system 99% cpu 26.080 total
optinterp2:   cargo run --release mandelbrot.bf  8.30s user 0.08s system 99% cpu 8.443 total
optinterp3:   cargo run --release mandelbrot.bf  6.46s user 0.09s system 99% cpu 6.617 total

f:id:retrage01:20180618225424p:plain
Mandelbrot Performance

factor

factorの場合の比較

simpleinterp: cargo run --release factor.bf < prime  17.16s user 0.10s system 99% cpu 17.321 total
optinterp:    cargo run --release factor.bf < prime  9.64s user 0.09s system 99% cpu 9.790 total
optinterp2:   cargo run --release factor.bf < prime  3.45s user 0.09s system 98% cpu 3.611 total
optinterp3:   cargo run --release factor.bf < prime  2.93s user 0.07s system 98% cpu 3.039 total

f:id:retrage01:20180618225420p:plain
Factor Performance

まとめ

いずれのスクリプトの場合でも simpleinterp > optinterp > optinterp2 > optinterp3 の順の実行時間であった.これは元記事とも一致する. さらに元記事のようにJITなどを用いて最適化することも考えられる.

参考文献

8cc in Lazy K

本日は4月1日で,エイプリルフールの日である. ただ,書いている現在は午後9時で,ちょっと嘘をつくには遅すぎる時間である.そこで,今回は何にも役に立たないものを作ってみようと思った. そこで,表題の通り,Lazy Kで書かれた8ccを生成して遊んでみた.

生成

  1. ELVMで生成された8cc.bf をダウンロード
  2. bf2lazy.c をダウンロード

  3. 2.で1.をLazy Kに変換

gcc bf2lazy.c -o bf2lazy
./bf2lazy < 8cc.bf > 8cc.bf.lazy
  1. 生成されたLazy Kのコード
$ du -h 8cc.bf.lazy
 12G    8cc.bf.lazy

バカみたいにでかくなる.

検証

おそらくは正しく動くはずであるが,8cc.bfだけで検証するのが相当かかるようなので,8cc.bf.lazyではさらに検証に時間がかかるはずなので,やらないこととする.

まとめ

適当にやったらLazy Kのコードがバカでかくなった. 生成されたコードは無用の長物なので,どこにもあげないが,簡単に生成できるので,暇な人はやってみよう.