ゼロからのOS自作入門をやる
とりあえず写経しつつ5章まですすめた。
6章からも継続して写経していくつもり。
なんかこまったことがあったらメモしてく。
Vector2Dクラスの定義でミスしてた。
operator +=
で受け取るVector2Dクラスが同じ型とは限らないので、別の型で定義しているところ、クラス自体と同じようにtemplate<typename T>
って書いてしまっていた。
template<typename T>
struct Vector2D {
T x, y;
template<typename U>
Vector2D<T>& operator += (const Vector2D<U>& rhs){
x += rhs.x;
y += rhs.y;
return *this;
}
};
変数にinlineがついているの初めてみた。
inline int hoge;
inline変数といってC++17から使える機能らしい。
inlineをつけた変数宣言をヘッダに書いた場合、変数の実体は単一になる。変数宣言だけ.cppソースに抜きだして…とかしなくていい。
7章に入った。
IDTはstd::array
で割り込みベクタ定義して、ここに割り込み記述子登録しておく。
IDTのoffsetには割り込みハンドラのアドレスを設定する。
ゼロからのOS自作入門ではMSI割り込みの仕組みを使って割り込みを発生させる。
MSI割り込みでは特定のメモリアドレスへの書き込みで、割り込みを発生させる。割り込みが発生したら、割り込みベクタを見に行って対応する割り込みハンドラを探し、実行する。
割り込みの設定をしたあとは、Kernelのmain関数で無限ループで割り込み待ちをする。
インラインアセンブラでcli命令を実施し、割り込み許可フラグを落として割り込みを止める。
メッセージを受け取れたらsti命令で割り込み許可フラグを立て割り込みを許可する。
こうしている理由は、割り込みのメッセージを受け取ってる最中に新たなメッセージが積まれると厄介だから。割り込みに限らず、プロセス間通信とかでもよくやる。セマフォとかつかったり。
メッセージキューが空だったらhlt命令を使ってCPUを省電力モードにする。割り込みが起こるとhltから自動で復帰するらしい。
9章
プログラマからは隠蔽されたシャドウバッファを作って、描画時にはシャドウバッファからフレームバッファにmemcpyで書き込むようにした。
memcpyで書き込むことで高速化をしている?
サブのバッファを作って裏で書いておいて、描画時に一括でコピーする方式はダブルバッファリング方式とか言って、描画系の処理を書くとよく出てくる。
このスクラップすごい放ったらかしにしてましたが、裏でやってました。
今は19章 ページングをやっています。
↓はELFファイルを読み込んで、最初のロードセグメントを探しているところ。
Elf64_Phdr->e_phoff
がElfの先頭からプログラムヘッダへのオフセットが入っているので、ehdr
に足し合わせれば実際に置いてあるメモリがわかる。
プログラムヘッダは配列になっているので、Elf64_Ehdr->phnum
だけ回してElf64_Phdr->p_type
を見ていけばLOADセグメントを探せる。
最初のLOADセグメントを返している。
Elf64_Phdr* GetProgramHeader(Elf64_Ehdr* ehdr){
return reinterpret_cast<Elf64_Phdr*>(
reinterpret_cast<uintptr_t>(ehdr) + ehdr->e_phoff);
}
uintptr_t GetFirstLoadAddress(Elf64_Ehdr* ehdr){
auto phdr = GetProgramHeader(ehdr);
for(int i = 0; i < ehdr->e_phnum; ++i){
if(phdr[i].p_type != PT_LOAD) continue;
return phdr[i].p_vaddr;
}
return 0;
}