OSを1000行で書いてみた(をやってみる): 01
留学によってとれなかった授業であるOS(Operating System)の講義の内容の埋め合わせをしたいと思っています.
ネット上にあるいくつかの大学の講義資料と共に、少し前に話題になった"OSを1000行で作る" に手を出してみます.よかったら一緒に読んでつくってみませんか.
第一回は05. "Hello World!を表示する" まで行きます.
WSL2インストールしてUbuntu上で動かしてます.
個人的に情報付け足しておきたい部分を書いています.
01 開発環境.
とりあえずなんだこれ?となると思いますが,まずはインストールを済ませてしまいましょう.OpenSBIとQEMUについての説明は後ほど.
02 RISK-Vについて.
オープンソースライセンスの命令セットアーキテクチャ.日本でもやったし、イタリアでもこれで勉強した.私はちゃんと自分で実装したことないので実装してみたい.
一応説明しておくと、RISK-Vはただの言語(ex. add x1, x2, x3)
私たちが作るのはOSであって、RISC-Vで実装されたCPU上でOS(たとえば xv6-riscv や Linux-riscvなど)が動いてその上でemacsなどのアプリケーションが走る、その根幹部分である.
CSR: Control and Status Register
03 03 OSの全体像.
本プロジェクトを通してシンプルなOSを作成できる.(いくつかの内容は欠けているが重要な部分は満たしている)
04 ブート処理
RISK-Vの3つのモード
まずはRISK-Vのモードについて説明.
モード | 概要 |
---|---|
M-mode | 最も特権が高い.ファーム/ハードウェア制御 |
S-mode | カーネルが動作するモード |
U-mode | アプリケーションが動作するモード |
この3つのモードのうち,Mモードで実行されるファームウェアである.つまり,SBIとは一番偉い管理者権限を持ってるソフト.
OpenSBI: Supervisor Binary Interfaceのオープンソースの実装.
OS(S-Mode:カーネルが動作する)とSEE(M-Mode:最も権限が強い)のインターフェースの役割を果たす部分である.
QEMU:(generic and open source)machine emulator/virtualizer
リンカスクリプト(拡張子.ld): プログラムの各データ領域をメモリ上にどう配置するかを指定する.OSや組込みシステムでのメモリの正確な制御のために必要.
ここから少し初見だと難しくなると思うので、注意深く.
リンカスクリプトは、メモリ(演算命令を持ってきて実行するところ)の領域を規定します.
↓以下のサイトが分かりやすかったのでお借りしました.
Cの授業とか計算機構成の演習とか,コンピュータアーキテクチャなどの授業でさらっと勉強した記憶.これらの領域を規定していきます.
ENTRY(boot)
SECTIONS {
. = 0x80200000;
.text :{
KEEP(*(.text.boot));
*(.text .text.*);
}
.rodata : ALIGN(4) {
*(.rodata .rodata.*);
}
.data : ALIGN(4) {
*(.data .data.*);
}
.bss : ALIGN(4) {
__bss = .;
*(.bss .bss.* .sbss .sbss.*);
__bss_end = .;
}
. = ALIGN(4);
. += 128 * 1024; /* 128KB */
__stack_top = .;
}
ここでは,
.text : コード領域
.rodata: 定数データ領域.読み取り専用.(初期値あり)
.data: 読み書き可能データ領域.(ヒープ、スタックのことと解釈)
.bss: 読み書き可能データ領域.(初期値なし)
という風に宣言しています.
これにプラスアルファでいくつか設定すると…
x0/zero 00000000 x1/ra 8000a084 x2/sp 80032f30 x3/gp 00000000
x4/tp 80033000 x5/t0 00000001 x6/t1 00000000 x7/t2 00000000
x8/s0 80032f50 x9/s1 00000001 x10/a0 00000000 x11/a1 87000000
x12/a2 00000007 x13/a3 00000019 x14/a4 4014112d x15/a5 00000001
x16/a6 00000008 x17/a7 00000002 x18/s2 00000000 x19/s3 00000000
x20/s4 87000000 x21/s5 00000000 x22/s6 80006800 x23/s7 8001c020
x24/s8 00002000 x25/s9 8002b4e4 x26/s10 00000000 x27/s11 00000000
x28/t3 616d6569 x29/t4 8001a5a1 x30/t5 000000fc x31/t6 00000000
f0/ft0 ffffffff00000000 f1/ft1 ffffffff00000000 f2/ft2 ffffffff00000000 f3/ft3 ffffffff00000000
f4/ft4 ffffffff00000000 f5/ft5 ffffffff00000000 f6/ft6 ffffffff00000000 f7/ft7 ffffffff00000000
f8/fs0 ffffffff00000000 f9/fs1 ffffffff00000000 f10/fa0 ffffffff00000000 f11/fa1 ffffffff00000000
f12/fa2 ffffffff00000000 f13/fa3 ffffffff00000000 f14/fa4 ffffffff00000000 f15/fa5 ffffffff00000000
f16/fa6 ffffffff00000000 f17/fa7 ffffffff00000000 f18/fs2 ffffffff00000000 f19/fs3 ffffffff00000000
f20/fs4 ffffffff00000000 f21/fs5 ffffffff00000000 f22/fs6 ffffffff00000000 f23/fs7 ffffffff00000000
f24/fs8 ffffffff00000000 f25/fs9 ffffffff00000000 f26/fs10 ffffffff00000000 f27/fs11 ffffffff00000000
f28/ft8 ffffffff00000000 f29/ft9 ffffffff00000000 f30/ft10 ffffffff00000000 f31/ft11 ffffffff00000000
ただしくレジスタなどが設定されました(詳しくは元サイトをご覧ください.)見覚えのあるx0-x31/f0-f31のレジスタがでてきたので満足です.
05 hello world!
kernel.h上でOpenSBIを呼び出すことで実現していると理解しました.Console Putcharを用いて,一文字ずつ画面に出力していく.
OpenSBI v1.2
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
--中略--
Hello World!
なんだかんだあってなんとかHello Worldできました.やり方は参考リンク先に書いてある通りです.よくあることだけど、なぜか動かなくて色々試したらいつの間にか動いた.結局なぜうまくいったのか理由が分からず悔しい.これを一から書いた人は本当にすごいと思います.
次はprintf 関数を実装します.
間違っている内容あったら教えてほしいです.使用させていただいた資料,技術等に感謝申し上げます.
Discussion