Open64

ゼロからのOS入門の作業ログ

k_koheyk_kohey

day08cのMemoryManagerの実装を開始した.
MemoryManagerはページフレームという単位でメモリを使用中か否かという状態を用いて管理する.
OS起動時にメモリのどの範囲が使用中か,あるいはそうでないのかをMemoryManagerに設定するために,UEFIから受け取ったメモリーマップを基にhogehoegする処理を書いた.
しかし肝心のMemoryManagerの実装はまだ歯抜けとなっているので,次回そこをやる予定.

k_koheyk_kohey

過去の作業ログを転記.

2024/01/14
このエラーを治す.

ld.lld: error: undefined symbol: pci::ScanAllBus()
>>> referenced by main.cpp:136
>>>               main.o:(KernelMain)

ld.lld: error: undefined symbol: pci::ReadVendorId(unsigned char, unsigned char, unsigned char)
>>> referenced by main.cpp:142
>>>               main.o:(KernelMain)

ld.lld: error: undefined symbol: pci::ReadClassCode(unsigned char, unsigned char, unsigned char)
>>> referenced by main.cpp:143
>>>               main.o:(KernelMain)
make: *** [Makefile:19: kernel.elf] Error 1

2024/01/21
PCIデバイス一覧見れた
がんばってこれを書いている
https://github.com/uchan-nos/mikanos/compare/osbook_day06b...osbook_day06c
2024/01/28
main.cppのこのへん書いてる

2024/02/04
割り込み方式でマウスが動くようになった.
176pのまとめ助かる
イベントループを使って割り込み命令を処理するように変更した
iOSもタッチスクリーンへの入力やタイマーなどによって割り込み命令が発生し,各スレッドにあるイベントループがそれを処理しているはずなので,iOSもこんな実装なのかな~と想像しながら書いてた.

2024/02/12
08aまで終わった
IsAvailableはまだ実装していない
stack領域は移動した

k_koheyk_kohey

MemoryManagerの実装を終わらせてday09aに入った.
day08cのMemoryManagerの実装は以下の2つを抑えていると,内容を理解できた.

  • FrameIDはFrameのメモリ先頭位置を表している(単なる識別子ではなく,識別できる事以上の意味を持つ)
    • 実際のメモリ先頭位置を得るにはkBytesPerFrameをかける必要がある
  • 配列alloc_map_の各要素には,各フレームの利用状況がビット列を使って表現されている
    • 1フレームの利用状況は1ビットで表現される

day09aはsbrkの実装まで行った.sbrkはNewLib(Cのライブラリ)にあるmallocの実装が呼び出す関数であり,mallocによって割り当てられるメモリの先頭アドレスを返却する必要がある(多分).sbrkを実装する事によって,独自の割当て処理を実装できる設計はOpne Closedな設計で良いなと感じた.実装が終わってビルドも通っているが,このあたりはランタイムでホゲホゲする処理なので,day08cの実装も含めてちゃんと動くかは謎である.

次回はレイヤー周りの実装をする予定.インスタンスの生成に失敗してたら今日の実装がミスっているということだろう.

k_koheyk_kohey

day09aの実装を引き続き進めている.LayerやWindowの実装をざっくりと終わらせて,今は淡々とLayerManagerの各関数を写景している.
写景していて謎に感じるのは各Objectの依存関係だ.直感的にはWindowがLayerを所有しているように思っていたのだが,LayerがWindowを参照するコードが多々ある.ある程度実装を進めていくと,このあたりの関係性もわかってくるのだろうか.これ以外にも描画のメカニズムがいまいち理解できていない気がするので,実装後は改めてコードを見直したい.
次はLayerManager::UpDownの実装からやる予定.

k_koheyk_kohey

9aを終わらせた.長かった.今日具体的に行ったことは,主にLayerManagerの実装およびLayerを使った描画に置き換える事だ.Layerを使った実装に置き変える際に,graphicsやconsoleにも差分が生じていてダルかった.正直,このあたりの描画処理は実装するだけなので,あまり関心が沸かず身が入らなかった.9bからはパフォーマンスの改善に入る予定.

k_koheyk_kohey

9bを終わらせた.次はPixelの書き込みのパフォーマンスを上げていく.軽く方針について読んだが,全ピクセルをマウスが動くたびに書き込み処理をする(変数へ代入していく)のは無駄なので,memcpyを使ってメモリ領域を効率よくコピーしてくように変える,という方針と理解している.すると,全ピクセル文のループ処理が一つ消えるので早くなる,という理屈.......違うかもしれない.実装している内に完全理解に到れることを願う.

k_koheyk_kohey

LocalAPICタイマはレジスタに値を書き込むことで,カウンタの減少スペードを設定できる.

k_koheyk_kohey
  • ウィンドウ画像をフレームバッファに書き込む処理の高速化
  • 書き込むべきピクセル数の削減

を行っていく

k_koheyk_kohey

fatal error: 'cstdint' file not found
とエラーが出たときは、ライブラリが見つかってない状態。

対処法がよくわからなかったが、用意されてるshellスクリプトを実行すればとりあえず解決するらしい。

source $HOME/osbook/devenv/buildenv.sh
https://timtoronto634.hatenablog.com/entry/2022/02/03/095331

知らなかった

k_koheyk_kohey

9cを進めた.シャドウバッファの実装やシャドウバッファを利用する部分を書籍のとおりに行った.しかし,書籍に記載されていない部分の実装はまだ行えていないので,ビルドを通すためにはまだ実装が必要となる.

memcpyのシンボルが見つかってないような挙動が見えたので,少し不安になっている.

k_koheyk_kohey

bitsからbyteに変換する際は,bitsに7を足してから8で割る.
そうすると,bitsに端数があっても(8で割り切れなくても)bitsを表現するのに必要なbyte数がわかって便利

(bits_per_pixel + 7) / 8

k_koheyk_kohey

この本,いつ終わるんだ?と心配になって試算してみたら,このペースだと後8ヶ月必要な事がわかり笑ってしまった.

k_koheyk_kohey

day09を終わらせた.次はday10aの続きからやる.day10aはコードは書ききっているが,qmenueがクラッシュする不具合があるのでその不具合を修正する必要がある.

k_koheyk_kohey
  • 10a
    • マウスが画面端から出ないように制御する
  • 10b
    • アプリケーションのウインドウを出す
  • 10c
    • ウインドにメインループのループ回数を記載する
k_koheyk_kohey

day10bまで終わらせた.day10cは最初の方だけ実装している.day10cでやる事は,メインループの回数を表示するWindowのチラツキを改善する事だ.UIが描画される順は,まずWindowの背景をまず表示しその後にWindowが表示される順番となる.はじめにWindowの背景が描画された際にはWindowが表示されていないため,Windowが表示されていない時間が一定存在する.そのため,Windowの表示有無が高速に切り替わるのでチラツキが起こる.再描画するエリアを限定することによって,これを解決しようとしている

k_koheyk_kohey

day10終わった.day11aのinitializeGraphicsとinitalizeConsoleを実装したところで終わった.次は,引き続き肥大化したmain関数を別の関数に切り分けていく作業を行う.

k_koheyk_kohey

ウインドウにマウスカーソルを重ねるとカーソルにチラツキが起こるのを直していく.
チラつく原因は,ウインドを表示したあとにカーソルを表示するため,カーソルが表示していない期間が存在するから.
ちらつきを回避するためにウインドウ->マウスという複数の描画を行うのではなく,最初に表示する画像のバイナリをバックバッファという場所にためてから,それを画面に一気に表示するという方法を取る.

k_koheyk_kohey

カーソルを重ねてもチラツキが起きない事を確認した

k_koheyk_kohey

マウスのクリック時における割り込み処理をハンドルできるようにする

k_koheyk_kohey

本家リポジトリのosbook_day10fのタグ打ちミスってますな

k_koheyk_kohey

11dまで進んだ.複数個のタイマーを作成する話だった.ただ,ここまでではタイマーのカウントアップの周期が秒単位ではなくLocal APICタイマの周波数に依存するため,タイマーの経過秒数を測る事ができない.11eではこの問題を解決し経過秒数を計測できるタイマに改善する.Local APICタイマの周波数がわかれば,カウントアップする毎に何秒経過したかが計算できるので,ACPI PMタイマを使ってLocal APICタイマの周波数を計測する.ACPI PMタイマを制御するためにはレジスタやメモリ空間をhogehogeする必要があり大変そう.

k_koheyk_kohey

タイマーと聞くと時計アプリ的なものを想像するけど,クロック信号?のような0 1の波の1の時に割り込み信号を送る素子を操るAPI的な解釈のほうが正しいのかもしれない.

k_koheyk_kohey

day12eまで

k_koheyk_kohey

12章入った.キー入力の章でタイマーの続きの理由をやる理由がよくわからない

k_koheyk_kohey

Local APICの周波数をAPIC PMを使って測定してLocal APICのタイマーを作るんじゃなくて,すでに周波数がわかってるAPIC PMだけを使ってタイマーを作るのじゃアカンのか?

k_koheyk_kohey

うーん.定義しているのにシンボルが見つからない.ヘッダーもインポートしている.なぜ?
次調べる.

ld.lld: error: undefined symbol: DrawTextbox(PixelWriter&, Vector2D<int>, Vector2D<int>)
>>> referenced by main.cpp:89
>>>               main.o:(InitializeTextWindow())
make: *** [Makefile:26: kernel.elf] Error 1
k_koheyk_kohey

day12fから

k_koheyk_kohey

RIP
次に実行する命令のアドレスを示す

RSP
スタックの先頭のアドレスを示す.
スタックはスタックフレームという単位で,ローカル変数,RBP,リターンアドレスのの順で情報を保存している.
RBPはスタックの底のアドレスを示す.リターンアドレスは関数の終了後にどこにジャンプするかを示す.

k_koheyk_kohey

ノイマンコンピュータはレジスタから命令を1つずつ取り出して実行していくだけなので,並行処理(コンテキストスイッチ)を実現するためには,レジスタの値を書き換えて次に実効するタスクを変えてCPUを騙す.

k_koheyk_kohey

タスクを切り替えるだけなら,切り替えたい先のタスクの先頭アドレスをRIPに書き換えることにより実行先を変更し,タスクの引数をRDIとRSIにいれるだけで良いが,切り替え元に戻るためには元のタスクの状態も保持しておき適切に状態を復元する必要がある.

k_koheyk_kohey

C++の非同期処理機能を使えないの?とふと思ったが,言語機能がOSのラインタムAPIに依存しているからありえないかww

k_koheyk_kohey

day13bから

k_koheyk_kohey

協調的マルチタスクをやめて,プリエンプティブ・マルチタスクにした

k_koheyk_kohey

day14bから

k_koheyk_kohey

TaskをWakeupする仕組みを用意すれば,マウスのカーソルの移動割り込み処理が走った時に,Main Taskを起こせばマウスのカクつきがなくなるみたいな話だと思う

k_koheyk_kohey

逆にWakeupするまではSleepするから,今まで不要にMain Taskに割り当てられていた時間を別のTaskに割り当てられる.