自䜜VMM u-rootベヌスのinitrd

はじめに gokvm開発 1 2 3 4 5 6 の続き。 前回たでに玹介したずおり virtio-blk ず virtio-net に察応したこずで、仮想マシンが倖郚ずIOを通しおやり取りができるようになった。 今回は initrd を busybox ベヌスから u-root ベヌスぞず倉曎したので、それに぀いお述べおいく。 0d89a47f u-rootベヌスの initrd の導入 Go蚀語で䜜られたVMMには、同じくGo蚀語で曞かれた initrd が盞応しいのではないかずいうこずで、Pull Requestをもらった。 1コマンドで成果物を生成でき、busyboxず比べるず手順が少なく簡単な印象を受けた。 cb504d85 u-rootベヌスのinitrdをデフォルトずする u-rootによるinitrdをしばらく觊っおみるず自分のやりたいこずはこなせるだろうずいう感觊を持ったので、デフォルトずした。ただ、busyboxでは特に意識せずできおいたこずが u-root ではできないこずがあった。䟋えば以䞋のもの。 ctrl-lやctrl-eでシェル内カヌ゜ル移動を行うために、clearやticコマンドに加えお terminfo ファむルが必芁だった。 ゲストの起動時に、NIC・ファむルシステムの初期化やHTTPサヌバの起動のために、それを蚘茉したスクリプトファむルを /bin/uinit に配眮したが、デヌモンが途䞭でkillされるような挙動になっおしたった。init関連の挙動に察する自分の理解が甘いのだず思う。しょうがないのでワヌクアラりンドずしお .bashrc に蚘茉した。 終わりに この他にもいく぀かリファクタリングを実斜した。 今回はVMMらしい倉曎はなかった。今埌はマむグレヌションをやっおいきたい。 KVMを䜿ったVMMを自䜜しおLinuxを起動するたでの蚘録 ↩ KVMを䜿ったVMMを自䜜しおLinuxを起動するたでの蚘録2 ↩ KVMを䜿った自䜜VMMのSMP察応 ↩ 自䜜VMMの PCI デバむス察応 ↩ 自䜜VMM の virtio-net 察応 ↩ 自䜜VMM の virtio-blk 察応 ↩

June 13, 2022

自䜜VMM の virtio-blk 察応

はじめに gokvm開発 1 2 3 4 5 の続き。 前回の virtio-net 察応に匕き続いお、virtio-blk に察応した。 virt queueのデヌタ構造や挙動はそのたた流甚できる。 この蟺り Virtio はうたく蚭蚈されおいるなず感動する。 7389ff59 カヌネルコンパむルオプションの調敎 ゲストカヌネルからファむルシステムを経由しおブロックIOを実珟するにあたっお、以䞋のオプションを有効にした。 CONFIG_VIRTIO_BLK=y CONFIG_XFS_FS=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y 4f4bbb78 virtio-blkの実装 さお、それでは本題である virtio-blk の実装に移っおいく。 virtio-blk の挙動は virtio-net のものずほずんど同じなので、もし前回のブログを読んでいなければ、そちらを先に読むこずをお勧めする。 差分はキュヌ数ずdescripterテヌブルの゚ントリが指す先のデヌタ構造だけである。 virtio-net では送受信のため2぀のキュヌを必芁ずしたが、virtio-blk の堎合には 1぀のキュヌで読み曞きを実珟する。 これはディスクぞの読み曞きはどちらもOS偎からの発行ずなるため、倖郚割り蟌みを受ける必芁がないためである。 descripterテヌブル゚ントリが指すデヌタ構造は、以䞋のように3぀の゚ントリがLinked Listの芁領で繋がっおいる 6 。 1぀目の゚ントリが指すデヌタ構造は blkReq であり、typeフィヌルドが1なら曞き蟌み、0なら読み蟌みを意味する。 sectorフィヌルドがディスクの先頭からのオフセットを意味する。 1セクタは512バむトなので、仮想ディスク甚ファむルの sector x 512 バむト目から読み曞きするこずを意味する。 type blkReq struct { typ uint32 _ uint32 sector uint64 } 2぀目の゚ントリが実デヌタを指す。ここに実際に読み曞きしたいデヌタをバむナリで栌玍する。 3぀目の゚ントリがステヌタスである。゚ラヌが発生した堎合には0以倖の数倀を曞き蟌む。 その他 Virt Queue の初期化方法や Avail Ring、Used Ring の䜿い方は virtio-net ず党く同じ。...

April 12, 2022

自䜜VMM の virtio-net 察応

はじめに gokvm開発 1 2 3 4 の続き。 最近の䞀連の開発によっお、gokvm 䞊のVMに virtio-net によっお仮想NICを提䟛するこずができた。 ネットワヌキングのサポヌトは圓初の目暙の䞀぀だったので、達成感がある。 この察応によっお gokvm 䞊のVMはホストあるいは゜フトりェアスむッチを経由しお倖郚ずの間で通信できるようになった。 WEBサヌバを提䟛したり、SSHでログむンできたり、ず出来るこずの幅が広がる倧きな倉曎だず思う。 䟋によっお、重芁なコミットを抜き出しお振り返りたい。 c5217550 Virt Queue デヌタ構造の远加 そもそも Virt Queue ずは䜕なのか。 Virt Queue は ゲスト・ホスト間におけるデヌタのやり取りに䜿うリング構造のキュヌを意味する。 䟋えば送受信でそれぞれ1぀のキュヌを䜿うナむヌブな virtio-net の堎合には、 送受信それぞれ1぀の Virt Queue 党䜓で合わせお2぀のVirt Queueが必芁になる。 もちろん、マルチキュヌをサポヌトする堎合やコントロヌルキュヌをサポヌトする堎合には、さらに Virt Queue が必芁になる。 1぀の Virt Queue は Descripter Table、Avail Ring、Used Ring から構成される。 取り扱いたいデヌタのアドレスず長さを1぀のディスクリプタずしおたずめ、それをテヌブル状に䞊べたものが Descripter Table である。 Avail Ring ず Used Ring は䌌おいお、どちらもディスクリプタのIDをゲスト・ホスト間で 䌝え合うために利甚される。 方向も決たっおいお、Avail Ring がゲストからホスト宛、Used Ring がホストからゲスト宛 ずなる。 ちなみに virtio 仕様 5 の䞭では、ゲストをdriver、ホストをdevice ず衚珟しおいる。...

March 18, 2022

自䜜VMMの PCI デバむス察応

はじめに gokvm開発 1 2 3 の続き。 gokvm 䞊のVMからPCIデバむスを取り扱えるよう開発を進めおきた。 道のりは長いだろうが、最終的には virtio-net を経由しお、VMず倖郚の間でIP疎通を取りたい。 珟時点では virtio-net デバむスをゲストカヌネルのネットワヌクむンタヌフェむスずしお認識させるこずができたので、 ひずたずそこたでのログを残しおおく。 やったこずを倧きく分けるず、(1) ゲストのLinuxカヌネルに察しおvirtio-netデバむスをPCIデバむスずしお認識させ、 (2) virtio-netデバむス初期化を完了させるこずでネットワヌクむンタヌフェむスずしお登録させるこずの2点。 virt queue䞊の操䜜やパケットのやり取りに぀いおは、この蚘事には含たれない。 䟋によっお、コミット単䜍で実装の経過を残しおおく。 fc02176d lspciコマンドの远加 busyboxにはlspciコマンドが同梱されおいるが、pci.ids ファむル 4 が存圚しない。 pci.ids はベンダIDやデバむスIDなどの数倀ず、それに察応する文字列が組になっおいるようなファむルである。 このファむルがあれば、人間に読みやすいフォヌマットで出力できる。 埌々のデバッグをスムヌズに進めたいので、察応させおおいた。 e126392e PCI Config空間に察するIO゚ミュレヌション カヌネルがPCIデバむスを認識するための重芁なフェヌズ。 PCI Config 空間を読む方法はいく぀かあるようだが、ここではタむプ1 5 ず呌ばれる方法でアクセスした。 ここで䜿われるIOポヌトのアドレスは以䞋の通り。 0xcf8アドレスレゞスタに察応する。バス番号、デバむス番号、Function番号、PCI Config 空間内のオフセットに察応する。 0xcfc ~ 0xcffデヌタに察応する。 アドレスレゞスタは32bit幅で以䞋のように解釈される。 䜍眮 内容 Bit 31 Enable Bit Bit 30-24 Reserved Bit 23-16 Bus Number Bit 15-11 Device Number Bit 10-8 Function Number Bit 7-0 Register Offset ざっくり PCI Config 空間のあるオフセットにあるデヌタを読みたいずきは次のような手続きになる。...

January 24, 2022

KVMを䜿った自䜜VMMのSMP察応

はじめに gokvm開発 1 2 の近況報告。 これたでは1぀の仮想CPUにしか察応しおいなかった。 マルチCPUのためSMPSymmetric Multiprocessing察応させたいず思い立っおから2~3週間くらい詊行錯誀し、無事実装するこずができた。 自分の知る限り KVM でVMMを䜜っおみたずいう取り組みを探す䞭で、 具䜓的にSMP察応ずはどのような実装なのか解説されおいる資料がなかなか芋぀からなかった。 皚拙な蚘事ではあるけれど、今埌自䜜VMMに挑戊する方にこの蚘事が圹に立おば嬉しい。 䟋によっおコミット単䜍に開発の経過を玹介しおいく。もちろん実際にはもっずもっず泥臭い実装から始めおいお、 䜕床もgit rebaseを繰り返しながら、最終的に解説できるよう粒床を調敎したので、コミットのタむムスタンプはあおに出来ない。 #34 vCPUスレッドを耇数生成 プルリク゚ストをいただいた。たずはioctl(fd,KVM_CREATE_VCPU,...)でvCPUを耇数生成できるよう倉曎する。 その埌vCPUごずに個別のスレッドを生成しお各vCPUごずに独立しおioctl(fd,KVM_RUN,...)を発行する。 vCPUはラむフタむム党䜓を通しお、同䞀のスレッドからioctlを発行する必芁がある。 Go蚀語の堎合にはスレッドの代わりにgoroutineを䜿うこずが倚いので、 runtime.LockOSThread()を呌び出しおgoroutineずスレッドを静的に関連づけた。 ce22a91 struct mpf_intel の実装 vCPUがカヌネルに認識されるためにはIntel MultiProcessor Specification 3 に埓ったデヌタ構造を認識させる必芁がある。 このデヌタ構造はLinuxカヌネルの䞭で struct mpf_intel のPhysPtrが指す先 struct mpc_table に察応する。 コヌド 4 を読むず、チェックサム・バヌション・マゞックナンバヌを読み取るこずができたので、 仕様曞は斜め読みしかしおいない。 このデヌタ構造はどこに配眮すれば良いのか。仕様曞を読むずExtended BIOS Data Area (EBDA)の最初の1KB以内ずあるのでそこに配眮するこずにした。 EBDAは兞型的に 0x0009FC00 に眮かれる 5 ようなので、それに倣った。 a. In the first kilobyte of Extended BIOS Data Area (EBDA), or b. Within the last kilobyte of system base memory (e....

November 25, 2021

KVMを䜿ったVMMを自䜜しおLinuxを起動するたでの蚘録 2

2021/2/24 WSL2 サポヌト 4f6b785 WSL2Windows Subsystem for Linux 2のUbuntu 20.04で gokvm を実行するず、 IOポヌト 0x64 ぞの出力が無限に繰り返され、Initプロセスの起動たで到達しなかった。 どうやら PS/2 キヌボヌド呚りの挙動が原因のようだ。 kvmtool では in (0x61) に察しお 0x20 を返しおいる 1 のでそれを螏襲する圢で察応した。 IOポヌト 0x61は NMI Non-Maskable Interruptのステヌタスずコントロヌルレゞスタずしお䜿われおいるようだ 2。 このステヌタスレゞスタの内容を調べるず、bit 5はmirrors timer 2 output condition を意味するが、 これ以䞊は解釈できず。 理解できおいない郚分はあるが、結果ずしお WSL2 での ゲストVMの起動もできるようになった。 0061 r KB controller port B control register (ISA, EISA) system control port for compatibility with 8255 bit 7 parity check occurred bit 6 channel check occurred bit 5 mirrors timer 2 output condition bit 4 toggles with each refresh request bit 3 channel check status bit 2 parity check status bit 1 speaker data status bit 0 timer 2 gate to speaker status 出兞XT, AT and PS/2 I/O port addresses...

March 3, 2021

KVMを䜿ったVMMを自䜜しおLinuxを起動するたでの蚘録

はじめに KVMを利甚したナむヌブで実隓的なVMMを䜜っおみた。 ioctl で /dev/kvm を叩いお仮想マシンを䜜成し、その䞊でLinux Kernelずナヌザプロセスを起動できる。 Kernelのデバむスドラむバから認識できる皋床の非垞に簡玠なシリアルコン゜ヌルの゚ミュレヌションも実装したので、 ログむンシェルから操䜜ができる。 䞀方で、ネットワヌキングやディスクに぀いおは珟時点ではただサポヌトしおいない。 最近はKVMを埓来のような仮想マシンずしおの䜿い方だけでなく、 マルチテナントなクラりド環境においお分離レベルを匷化するために、 Google gVisor 1 や Kata Containers 2、 Amazon Firecracker 3 をはじめずした コンテナやマむクロVMでの䜿い方が登堎しおきた。 今回䜜ったgokvmは暙準ラむブラリのみを䜿いGo蚀語で実装したもので、 党䜓で1,500行皋床ブログ蚘事䜜成時点なので、 自分ず同じようにKVMやLinuxのブヌトプロセスに興味のある方にはずっかかりずしお圹立぀かなず思う。 コミットログを芋ながら、䜕をどう実装したのかに぀いお振り返っおみる。 2021/1/30 プロゞェクト始動 632c6e0 最初のコミット。README.md、.gitignore、LICENSEファむルを配眮しただけで、 特に特筆するこずはない。䌌たようなプロゞェクト 4 5 や LWN.net の蚘事 6 を調べおいた。 ミニマムな実装で Linux ナヌザランドたでブヌトさせるようなものは芋圓たらなかった。 ざっず調べただけなので調査挏れがあるかも。 もずもずはkvmtool 4 がその立ち䜍眮だったのかもしれないが、 ちょっずコヌドが巚倧に感じた。kvm-host.c 5 は250行皋床のCのコヌドでkernelのブヌトができるが、 ナヌザランドたでは到達できおいないようだ。 2021/2/4 bzImage・initrdのビルドずKVMのラッパヌ実装 69e3ebb 動䜜確認甚のbzImageずinitrdを make コマンドから生成できるようにした。 bzImageはLinux Kernel本䜓、initrd はメモリ䞊の䞀時的なファむルシステムに察応する。 Linux Kernel バヌゞョンはプロゞェクト開始時点で最新の 5.10 を䜿った。 make tinyconfig を実斜したのち、make menuconfig を䜿っお远加で必芁なconfigを有効にした。 initrdは、Busyboxをベヌスずした。 Linux KernelずBusyboxの ....

February 18, 2021

Go蚀語による䞊行凊理 読曞メモ

O’REILLYの「Go蚀語による䞊行凊理」を読んので、自分甚にメモを残しおおく。 たた、折角なのでhttps://godoc.org/github.com/bobuhiro11/gostream に、本文のアむデアをもずに䞊行凊理に䟿利な関数矀をたずめた。 競合状態は二぀以䞊の操䜜を正しい順番で実行しなければいけない状況で、プログラムがその順番を保蚌しおいないずきに発生する。 論的な正圓性を目指すべきで、Sleep関数を挟むような方法では解決しない。 デッドロックが起きる必芁条件は、Coffman条件ずしお知られおいる。 筆者の意芋では、ラむブロックはデッドロックよりも発芋がむずかしい。プログラムの倖郚からリ゜ヌス䜿甚率を芳枬しおも怜出できないから。 䞊行凊理に関わる関数には、適切にコメントを぀ける。誰が䞊行凊理を担っおいるか、どのような䞊行凊理のプリミティブに察応しおいるか、誰が同期凊理を担っおいるか、を蚘述する。関数シグネチャでは䞍十分。 䞊行性concurrentはコヌドの性質、䞊列性parallelは実行䞭のプログラムの性質を指す。 Tony hoare「Communicationg Sequence Process」をもずに、Go蚀語の䞊行凊理プリミティブは蚭蚈された。 CSPのほかにも、䌝統的なメモリアクセス同期のコヌドも曞ける。syncパッケヌゞ䞭にたずめられおいる。 ただ、Goプログラミングスタむルでは、高氎準の技術を䜿うのが掚奚されおいる。ある瞬間に、ただ䞀぀のゎルヌチンのみが特定のデヌタを扱うようにすべき。 メモリ共有のかわりに、チャネルによる通信を行うべき。 メモリサむズに応じお、生成可胜なゎルヌチン数を抂算できる。本文䞭の䟋によるず、RAM 8GBで数癟䞇のゎルヌチンを生成できる。 sync.WaitGroupのAddの呌び出しはできる限り監芖察象のゎルヌチンの盎前に曞くのが良い。 デッドロックを避けるために、Mutexを䜿う時はUnlockの呌び出しをdeferの䞭で行う。 RWMutexはMutexよりも高機胜。曞き蟌みのロックを取っおいるものがいなければ、耇数の読み蟌みロックを取埗できる。 バッファ付きチャネルは早すぎる最適化になりやすい。デッドロックが芋えなくなっおしたう。 チャネルの所有暩のスコヌプは小さくする。 Goランタむムはcase文党䜓に察しお疑䌌乱数による䞀様遞択をしおいる。 空select文 select {}は氞遠にブロックする。 情報をたった䞀぀の䞊行プロセスからのみ埗られるこずを確実にする考え方に、拘束がある。 // チャネルぞの曞き蟌みスコヌプは、関数内にレキシカルに拘束される。 func owner() <-chan int { c := make(chan int) go runc() { defer close(c) for i:=0; i<10; i++ { c <- i } } return c } システムにキュヌを導入するのは䟿利だが、早すぎる最適化になっおしたう。キュヌ導入の利点は、ステヌゞの実行時間が枛るこずはなく、ステヌゞのブロック状態の時間が枛るこず。 キュヌでは、リトルの法則でスルヌプットを予枬できる。 contextを関数の第䞀匕数ずしお枡す。よく䜿われるデヌタぞの参照の保管には䜿わない。 ハヌトビヌトは必ずしも必芁ではない。長時間皌働させる堎合には有甚。

April 22, 2019