BUFFALO NAS スマホ/タブレット/PC対応 ネットワークHDD LinkStation 1TB LS210D0101G

NASを購入した。家のパソコン間のファイル共有とかデータ移動に利用するためだ。パソコンでデータを移動する場合、共有フォルダを設定していても、別の部屋にあるパソコンの電源を入れに行かなければならず、少しの手間ではあるが、面倒臭かった。USBメモリがすぐ手元にあるわけでもなく、USB経由はコネクタへ抜き差しするのとコピー処理が遅いのが難点だ。
本当に欲しかったのはSynology NASキットだった。手元にある500GBの2.5inch SATA HDDを取り付けて利用しようと思っていたのだが、このNASケースは3.5inch専用のだった。

Synology NASキット 2ベイ DS220j/JP【ガイドブック付】 クアッドコアCPU 512MBメモリ搭載 ライトユーザー向け 国内正規代理店品 電話サポート対応品 DiskStation

新しい3.5inch HDDをわざわざ買うと無駄金になるし、NASキット自体が三万円近くするので、半額近く安くなる時期を待っていた。しかし、三年経過して全然値段が下がらないので、仕方なく、Amazonで一番値段の安かった、長持ちを期待しない経過措置として、バッファローのHDD付きの1TBのNASを購入した。

BUFFALO NAS スマホ/タブレット/PC対応 ネットワークHDD 1TB LS210D0101G 【エントリーモデル】 LinkStation

取り付けは簡単。ルーターへ接続して、電源を入れ、ルーターのセキュリティ設定でLinkStationのアクセスを許可したら、すぐWindowsからメディアサーバーとして認識された。NAS Navigater2という環境設定ツールをバッファローのサイトからダウンロードし、インストールし、ツールを起動するとLinkStationのアイコンをダブルクリックすると、何の躓きもなくファイルシステムを参照できた。家庭内でしか利用しない(しかも私一人だけ)ので、設定画面でshareフォルダーを公開フォルダーに設定し、アクセス制限なしにログイン認証なしにした。パソコンを起動したときに自動で共有フォルダを参照するように「ネットワークドライブの割り当て」でWindows側で、Zドライブに設定した。ここで気を付けるべきなのは、NASであるLinkStationが、デフォルトではDHCPでIPアドレスが可変なことだ。(固定IPで設定することも可能)だからマシン名で参照するように設定しなければならない。LinkStationのマシン名はデフォルトでは”LS210D75G”なので、そのままでもよいが、趣味で自分の好みの名前にした。”\\マシン名\share”(WordPressのエディタでは円マークが”\”に自動変換されてしまう)でエクスプローラーから参照できるになった。他のWindowsパソコンも同様に設定した。全て簡単に終わってしまった。
唯一気になったのは、近くに置くと、騒音というほどではないが、HDDのモーター音が少し気になる。コピーもギガビットLANとはいえ、SSDの速度に慣れた現在では早いとは言えない。機器情報では、HDDはTOSHIBA製で、ファイルシステムはxfsだった。

深夜には使わないので、スリープタイマーを設定することにした。設定条件は3つまで設定できるようだ。設定項目は「毎日」と「毎週」で、3つ共「毎週」を選択し、平日は午後5時に起動し、深夜の1時で電源オフする設定をした。その設定をしたとき、エラーとなったのだが、単純な勘違いで、深夜の一時は翌日なので、01時を指定すると当日の1時を指定したことになる。翌日の深夜1時は25時を選択する必要があった。土曜日は午後1時に起動して深夜1時(25時)で電源オフの設定。日曜日は朝8時から深夜1時までとした。祭日などで平日に使う場合は、LinkStation背面の電源スイッチを手動でOFF/ONして、電源を入れなければならないようだ。

その他、いろいろ機能がある。BitTorrentはネットワークファイル共有ソフトだが、何のために付属しているのかよく分からない。AFPはMacOS用のファイル共有機能のためのプロトコルだから不要。WEBアクセス機能はインターネット経由での外からのファイルアクセスだから必要ないし、公式サイトからツールを取得する必要があって、おそらくネームサーバーとかセキュリティとか面倒臭いと思われる。バックアップ機能にTime MachineというMacOS用の機能があるが不要。SSL認証も必要がないので、使うことはないだろう。

問題が発生したのはManjaro Linuxだった。Thunarで”smb://LinkStationのマシン名/共有フォルダ名”でアクセスしようとしたが、匿名でログインしようとすると、エラーとなってしまう。LinkStation側ではアクセス制限を設定せず、誰でもパスワードなしでフルアクセスできるようになっているし、実際、Windows10ではログイン設定も必要なく、簡単に接続できている。LinkStation側ではアクセス用のログインユーザーを設定していないが、試しにguestでログインしようとしたが、やはりエラーとなる。非常に不思議。
以前からWindowsネットワークへのアクセスエラーがあったが、Manjaro LinuxはSamba関連の不具合を抱えたままのように思える。Manjaro LinuxのつぎはぎOSプログラムのバックアップが主目的であったが、突破口を思い付かないので、保留としておく。

(2023/5/13 追記) パソコンのメモリを16Gbyteへ増やしたので、Linux Mint 21.1 CinnamonをVMwareへインストールして遊んでいた。ふと思いついて、Linux Mintの標準ファイルマネージャ―のNemoから「ローケーションパス形式の切替」で”smb://LinkStationのマシン名/共有フォルダ名”を実行したら、匿名ログインでLinkStationの共有フォルダへアクセスでき、ファイル参照ができた。やはりManjaro Linuxのファイルマネージャ―のThunarにはバグがあるのだろう。いつか修正されればよいが、、、、と、ここでまた思いついて、Manjaro LinuxのKDE Plasmaエディションを試すことにした。メモリが増えたのでXfceでなくても使えるようになったからだ。KDEの標準ファイルマネージャーはdolphinで、最初は使い方がよく分からなかったが、あっさりLinkStationの共有フォルダにアクセスできた。Manjaro + Xfceの組み合わせか、Manjaro + Thunarの組み合わせに問題があるのだろう。ただメモリの少ないVH-AD3S proではKDEが使えないので、私の問題の解決にはならないのは残念だ。

(2023/5/26 追記の追記) VH-AD3S proの液晶ユニットが折り畳めなくなって、液晶ユニットを取り外し、無線LANアンテナとmicroHDMIケーブルでキーボード型パソコンに改装したついでに、SSDのManjaro Linux Xfceを最新版をダウンロードして、USBメモリからクリーンインストールしたら、ThunarからLinkStationへ接続することができた。最新版でバグが修正されたのか、アップデートの不良の問題だったのかは不明だが、解決できたので良しとする。
(、、、の追記)なぜか翌日、接続しなくなった。不思議???

カテゴリー: PC周辺機器, パソコン | コメントする

マルチタスクへの長い道程 その2 — つぎはぎOS

タイマー機能について誤解していたようだ。T-Kernelではシステムタイマーと物理タイマーとで、別になっていて、今まで作成したPITを利用したタイマー割込みはT-Kernel2.0/SMの物理タイマー機能に当たるようだ。
何が違うかと言うと、システムタイマーでは1985年1月1日(GMT)からのミリ秒とマイクロ秒を保持しなければならず、PC-ATではCMOSのRTC(Real-Time Clock)でシステム時刻を持ってカレンダー情報を提供している機能に当たるようだ。PITをそのままシステムタイマーとして使うことも考えたが、どちらにしても、時分年月日の情報を取得するためにRTCへアクセスするのだし、RTCはIRQ8の周期的な割込みを発生させることもでき、CMOSのRTCを使う方が便利だと思った。

という訳で、今までのPITでの割込み機能は物理タイマー機能のAPIへと修正することにした。その前に、改めてCMOSへのアクセスと、RTCからのIRQ8の割り込みハンドラを作成しなければならなかったが、もう慣れたもので、T_Kernel2.0仕様ではミリ秒とマイクロ秒単位のカウンターを持つようになっているが、手抜きでマイクロ秒単位のシステムコールは実装せず、RTCは10msec周期でIRQ8割り込みを発生させるように作成した。
RTCはなぜかCMOS(というRAM領域)へ年、月、日、曜日、時、分、秒までしか書き込んでくれない。しかも、通常のバイナリ数値ではなく、BCD表現でCMOSの内部RAMへ値を書き込んでいる。最初はそれに気づかず、バイナリだと思ってプログラミングして、どハマリした。英語のサイトでは、レジスタBを最初に読んで、モードを確認するよう記述があった。レジスタBの値を見て、BCD表現なのか、12時間表現なのか、米国サマータイムが有効なのかを判定するよう推奨していた。

Linuxでは、起動時にRTCの値を読むだけで、後はソフトウェアカウンターで加算しているらしい。私もRTCを読んでミリ秒へ変換し、IRQ8割り込みごとにカウントアップする方法を取ることにしていた。しかし、最初の一回だけIRQ8が発生するだけで、周期的に割込みが起こらなかった。サンプルプログラムも見ながら設定を確認したが、何をやっても駄目だった。
英語サイトによると、RTCからの割り込みはPIC回路との関連で相性が悪いらしく、割込みが”undefined state”となり、EOIができなくなるなどのトラブルがあるらしい。”IRQ danger”などという物騒な?短いチャプターで忠告までしていた。RTCは優先度が高いはずだが、IRQ8などというスレーブPICに接続されていることも関係しているのかもしれない。なぜ低い優先度の割り込みなのか理由は分からないが、PC-ATのつぎはぎの発展の歴史的経緯があるのかもしれない。
それで方針を変更し、RTCからは起動時に時刻を取得して初期値として保存し、PITのタイマーを使って10msec毎にカウントアップすることにした。PC-ATのPITで割込み使えるのはTimer0だけなので、結局、T-Kernel2.0/SMの物理タイマー機能は実装を止めることにした。

Linuxは1970年1月1日 00:00:00(UTC)からのミリ秒(設定によりマイクロ秒の高精度タイマーが使える)、Windowsは19701970年1月1日 00:00:00(ローカルタイム)からのミリ秒のカウント値持つらしいが、T-Kernel2.0では1985年1月1日(GMT)からのカウント値となっていた。理由は不明。拡張でマイクロ秒のカウンターも持つことになっている。困ったのは、「うるう年」と「うるう秒」の計算で、いろいろ調べて、うるう秒は諦め、うるう年の処理を適当に作成した。どうせ正確な時刻にはならないし、私個人では正確な検証はできない。将来インターネットに接続できるようになったら(いつのことやら)、NTPで時刻を補正する機能を実現する時に、また考えようと思う。グレゴリオ暦では、うるう年は以下のような条件を満たす年らしい。1985年以降で何回あるかをカウントして、日数を足すことにした。(2023年現在は9回。来年がうるう年)

・西暦が4で割り切れる年をうるう年とする (ユリウス暦と同じ)
・しかし、上記のうち、西暦が100で割り切れる年はうるう年としない
・だがしかし、上記のうち、西暦が400で割り切れる年はうるう年とする

うるう秒は、三年に一度、加算か減算するのだが、これは国際機関が原子時計との誤差を見ながら、いつ変更するかを決めているので、プログラムで計算することはできない。NTPで通知された時に変更するしか方法がない。

ミリ秒単位の時刻までは正確に検証できないので、2023/2/23という日付までの算出値が正しいかどうかを確認し、午後の15時までの時間だけのミリ秒を電卓の値と同じであることを確認した。うるう年も含めて、そこまでは何とか正しい値となっていた。
また、Timer-0によるカウントアップも行われ、T-Kernel2.0のtk_ref_tim()のシステムコールで、日時のミリ秒と合算した戻り値を返しているらしいことを確認した。(戻り値が正確なミリ秒の時刻かどうかは確認のしようがない)RTC回路への時刻補正は現時点では実装しなかったため、tk_set_tim()はTimer-0のソフトウェアカウンター値を訂正して、偽装した。GMTのままだと日本時間と9時間ずれるので、日本時間へのローカルタイムの変換は、NTPを実装する時に改めて実装し直そうと思う。

RTC/CMOSのIRQ8でのソフトウェアタイマーカウンターの実装は諦めたが、あるサイトの記事によると、RTCにも歴史的な発展の過程でいくつも種類があるらしく、CPU ID命令でTCSの種類を判定して、CPUの種類でRTCの種類を判定して処理を変えるらしい。サイト検索では、CPUの種類を調べるのはウィルスが使う基本テクニックらしく、それに関連したコンピューターウィルスの記事が多かった。面倒臭いので、深入りしないことにする。

カテゴリー: Linux, VirtualBox, つぎはぎOS | コメントする

マルチタスクへの長い道程 その1 — つぎはぎOS

T-Kernel2.0そのものの移植は断念して、includeファイルの定数やシステムコールのextern宣言などのヘッダファイルだけをコピーして、仕様書を読みながら自分なりに「つぎはぎ」に少しずつ構築していくことにした。

割り込み管理機能関係を、まず実装した。割り込みができなければ、マルチタスクは実現できないからだ。割込み関連のシステムコール(割り込みハンドラはタスク独立部、とか仕様書に書いてあった)tk_def_int()、tk_ret_int()、EI()、DI()などの簡単なシステムコールを実装した。T-Kernel/SMにも割り込みコントローラー用のAPI機能があり、自作したプログラムを流用できそうだったので、それも実装した。これでTimer割り込みだけでも動作すれば、ラウンドロビンのマルチタスクのタスクスイッチングを実現できるのではないかと思った。プリエンプティブでないのでリアルタイム性はない。それで、NTR、、、、ではなく、NRT(Non-Real-Time)-OS(仮称)とでも呼ぶことにしようか、、、、

T-Kernel2.0の割り込みマスク関係のシステムコールの仕様では、変更前の割込みフラグの状態を変数へ保持するようになっている。多重割込みへの対応のためか?必要なのだろうか?理由は不明?それで、80386の割り込みフラグはどこにあるかというと、EFLAGSレジスタにあった。pushfdという、EFLAGSをスタックへ書き込むアセンブラ命令があるのを初めて知った。これを使って、フラグレジスタの値を取得することができる。しかし、アセンブルでエラーになった。16bit命令のはずのpushfはOKだった。調べてみると、pushfとpushfdは、どちらも0x9cという命令コードが同じで、実際に実行する時のCPUモードで動きが違うようになるらしい。だから、gasは区別せず、同じものとしてコードを作成するようだ。いいのか?ちょっと不安。
試行錯誤でブートモニターのサブルーチンをT-Kernel用へ修正をしていて、PIC操作の自作ルーチンにバグを見つけた。T-Kernel2.0の割込みコントローラー操作のAPI仕様では、タイマー割込みやキーボード割込みなどを一つずつ割込み許可、禁止の制御をするようになっているが、私はなぜだかPICコマンドのOCW3コマンドで、割込みマスクの現在の状態を保持するIMRレジスタを読み出しするのだと思っていて、steploaderやboot_monitorは、PIC初期化の時に数日試してもOCW3コマンドでIMRが読み出しできなかったので、初期化で一度に全ての割り込みマスク設定をして、個別での変更はできないのだと諦めていた。実際はICW1–>ICW4で初期化した後に、OCW1の読み出しで、いつでもIMRを読み出しできるらしい。マスク設定値を書き込みすることしかできないと思い込んでいた(マスクする時は同じレジスタへ値を書き込む)。
できるのが当たり前と言えば当たり前で、参考文献の解説記事の簡便なサンプルプログラムでは、一度にPICのマスクを設定する仕方は掲載されていたが、現在のマスク値を読みだして、当該ビットだけを変更して再設定するようにはなってなかったため、読み出しできないものと思い込んだようだ。自作OSを始めた初期の頃で、まだ回路関係の知識がない時期に作成した部分なので、こんな初歩的な思い違いをしていた。修正して、当該IRQだけ割り込み許可、禁止できることを確認できた。
少し話が違うが、PICにはIRRとISRというレジスタがあり、IRRは割り込みを「要求」している割り込み番号の情報を保持し、ISRは割り込み「処理」を受け付けた割り込み番号のビットを保持する。割り込みが複数発生して、待ち(CPUへの要求)状態になっている割り込み番号のIRRの各ビットがオンになり、割り込み要求が受け付けられて、割り込みハンドラが起動されると、割り込み処理中ということでIRRのビットがオフになり、ISRの割り込み番号のビットがオンになる。つまり、割り込みハンドラは自分の割り込み番号のIRRは参照できず、他の割り込みの要求状態だけ参照することができるということで、何に使うのかよくわからない。これも多重割り込みのためか?割り込みを禁止して、ポーリングする時に使うのか?とりあえず、T-Kernel2.0/SMにCheckInt()というAPIがあり、今後利用する場面があるかもしれないので、ついでに実装しておいた。

キーボード割り込みも自作のものを流用したが、どうしても割り込みハンドラが起動しない。それで思い出したのが、キーボードは入力回路上、マウスと一体になっていて、スレーブPICのマウス割り込みにも接続していることだ。マスターPICのスレーブPICとカスケード接続しているIRQ2の割り込みを許可したら、あっさりキーボード割り込みが起動できた。もう数か月前のことで、うっかり忘れていた。

T-Kernelには割り込みハンドラの高級言語対応ルーチンの機能を持っていて、一体どうやって実現しようか何日も悩んだ。
割り込みが発生して、ハンドラが動き出したらすぐ現在の、タスク実行していた時のレジスタ情報を退避し、終了前に同じ状態へ復帰しなければならない。そこはアセンブラが必要だ。しかし、T-Kernel仕様では割り込みハンドラはiret命令で終了してはならないことになっている。これは割り込みハンドラ内でタスク起動のシステムコールを実行した場合、タスク切り替えをしなければならず、割り込み発生時のタスクには戻らない可能性があるからだ。つまり、メモリの何処かへ退避したレジスタ情報をタスクディスパッチャーへ渡して、そこでタスクの実行中情報として保存してから、新たに実行するタスクのレジスタ情報をCPUへ設定しなければならない。
結論として、80386では高級言語対応ルーチンは実現が難しい、不可能ではないが、効率が悪すぎる、ということが分かって、断念した。理由は、タスク独立部である割り込みハンドラはIDTを利用するプロテクトモードでは、起動されても自分の割り込みベクタ番号を知ることができないからだ。つまり、高級言語対応ルーチンのアセンブラからどのC言語処理関数を実行するべきか判断できない。割り込みベクタごとに関数名を決め打ちにしてしまい、システムコールがなくてもリンクで自動的に結合できるが、最大255個の個別の割り込みハンドラを用意しなければならない。ARM-CPU用のサンプルプログラムでは、ハンドラ起動時のプログラムカウンタから割り込みベクタテーブルの先頭アドレスを引いて、4で割ることでベクタ番号を算出していた。おそらく8086モードのような単純な構造のベクタテーブルなのだろう。IDTはディスクリプタの内部に割り込みハンドラのアドレスを自由に書き込めるので、その方法は使えない。やるとしたら、アセンブラ部分を含めてC言語で丸ごと割り込みサブルーチンを作成するしかない。調べた限りでは、”_attribute__(interrupt)”のような指定をして、インラインアセンブラでレジスタ退避や復帰、tk_ret_int()の実行などを記述しなければならず、そうなると、もはや通常の関数ではないので、TA_ASM指定で登録することになり、せっかくの高級言語対応ルーチンが無意味になる。
割り込みはできるだけ処理を短くしなければならないのだから、アセンブラで記述するメリットはあるし、上記のようにC言語で記述することが生産性に寄与することがないのならば、少なくとも80386の仕様では、できないことはないが効率的ではない、と考えられる。そういうわけで、NTR-OS・・・・じゃなかった、、、NRT-OSでは高級言語対応ルーチンは実装しないことにした。(それとも何か解決策があるのだろうか?全く思いつかない)

T-Kernel2.0/SMのシステムメモリ管理機能のシステムコールを手抜きで実装した。VirtualBoxのRAMは1Gbyteに設定しているので、空き領域が数百Mbyteあるので、払い出しの機能だけで、解放や再配置、再利用はしない(Freeの時、何もしない)ことにした。払い出し用のメモリポインタだけインクリメントで管理し、領域を使い切ったらメモリ不足としてエラーを返す。当面、使い切る可能性はないので、手を抜けるところは抜いて、NRT-OSの機能を増やすことに専念しようと思う。

未だにタスクスケジューリングやタスクディスパッチへ辿り着けないが、長い道程を少しずつ歩いていこうと思う。

カテゴリー: Linux, VirtualBox, つぎはぎOS | コメントする

小説 サラゴサ手稿 岩波文庫

ポーランドの大貴族が書いた長編小説。今までポーランドの作品は読んだことがなかったので、Amazonのお勧めに出てきたものを購入した。次から次へと、話が横滑りしていき、しかも奇想天外なエピソード(時代的に宗教関連とスペインやイスラムの風俗に関するものが多い)が連続して、宗教関連はちょっと辟易するが、慣れれば、ラノベ的な異世界魔法世界のような感覚で面白くなった。

— 小説 サラゴサ首肯 上・中・下 岩波文庫

三百ページ以上の三分冊で、一向に話が終息する様子がなく、登場人物も増えて行って、途中で誰が何をしているのか混乱するのは、ガルシア・マルケスの「百年の孤独」みたいで、ある意味、時代を先取りしたような先駆的な要素もある。
ずっと無名で一部の知識人にしか知られてなかったそうで、その面白さは、当時の有名作家の何人かがエピソードを丸ごとパクって自分の作品として発表したというほどだ。こんな結末になるとは、読んでいるうちには予想もできなかったが、ラスト近くで話が次第に収束していくと、読み終わるのが寂しいような気持ちになった。長編小説へ気長に付き合うことのできる人へお薦めしたい。

カテゴリー: 書籍 | コメントする

システムメモリマップ取得、ページング、マルチタスク — つぎはぎOSの方針

とりあえず、「つぎはぎOS」はページングで仮想記憶を実現した上で、マルチタスクOSを移植することにした。

以前挫折したページングに再度挑戦しようとして調べていたら、リアルモードのステップローダーで、ACPI仕様の拡張BIOSでシステムメモリマップを取得する必要があることが分かった。その理由は、i686のRAMは最大4G-byteなのだが、その全てが使えるわけではないからだ。ハードウェアから作成するような組み込みシステムだと、固定情報として内部に持てばよいが、パソコンは実際のRAMのサイズは各マシンで個別だし、BIOS領域やDMA領域、VRAM領域があって、そこは使えない。そういった個別のマシン情報をBIOSから取得してテーブルマップのようなものを内部で作成する必要がある。動的メモリ割り当てのmalloc()とかも、そういった情報を基にRAMの領域を割り当てているらしい。拡張BIOS機能の0xE820のINT 0x15というシステムメモリマップ取得で、ループで情報を読み出し、BOOT_INFOにそのまま格納して、ステップローダーからブートモニターへ渡すようにした。実際のシステムメモリマップ生成と参照は、ブートモニターの初期化処理で行った。新しくコマンドを作成し、BOOT_INFOの内容を画面へ表示させるようにした。システムメモリマップのエントリー情報は20バイトのサイズだったので、VirtualBoxのACPIは3.0より前の仕様のようだ。これで実メモリのどこを使ってよいか、利用可能なRAMサイズがどれくらいかが明確になった。
余談だが、Windows用のVirtualBoxは利用しない方が良い。というのは、テストのためにWindows10へVirtualBoxをインストールしたら、VMwareのネットワーク機能と競合して、VMwareの動作がおかしくなった。アンインストールも簡単ではない、ネットで検索すれば分かるが、レジストリや隠しファイルのようなものがそこかしこに残っていて、削除が面倒だ。Oracleがわざとやっているのか、フリーソフトのため手が回らないかのどちらかだろう。

このシステムメモリマップは、malloc()などの動的メモリ管理にも必要な情報であり、ページングのPDE/PTEの作成でも、この情報を基に物理アドレスの上位10bitと続きの中位10bitを設定することになる。下位12bitは実行プログラムでのオフセットを使ってアクセスするらしい。32bitモードでの仮想メモリは4Gbyteのリニアアドレスなのだが、実メモリは1Gbyteしかなかったりすることは普通にあるわけで、実メモリと仮想メモリの対応付けをするテーブル情報をPDE/PTEで持つわけだ。仮想メモリのどこに実メモリを割り付けるか、スワップするのかという設定もこのテーブル情報で行う。
はっきり言って、ディスクへのスワップ機能がないなら、実メモリをセグメント分割してアプリケーションへ割り当てた方が簡単だが、将来的な拡張を考えて、ページングを実装することにした。実メモリを割り付けない領域にアクセスしたら、ページフォールトが発生することになる。常識的に考えれば、OSのプログラムをディスクへスワップさせてはならないのだから、スワップする領域はアプリケーションに割り当てることになる。現状、ディスクへのスワップ機能を実装しないので、実メモリ=仮想メモリという対応付けとなる。だから、仮想メモリ4GBのどの領域をOSが使って、アプリケーションにどの領域を割り当てるかという計画的な配分を考えなければならない。
ちょっと頭を悩ませたのが、PDEとPTEのデータ形式だ。資料では4-byteのフラグビットとアドレスの簡便な形式なのだが、メモリ上に作成しなければなない。知っての通り、x86はリトルエンディアンで、メモリ上にもリトルエンディアンで作成しなければならないのか、ビッグエンディアンで作成しなければならないのか、資料では0-bitから31-bitまでの意味付けしか書いてなくて迷った。結論から言うと、リトルエンディアン形式でメモリ上に作成するのが正解だった。そういうものだと受け入れるしかないのだろうが、自分は生理的にビッグエンディアンの方が精神衛生上、好ましい。

ページング機能を実装して思ったのは、ディスクへのスワップ機能がなければ、不要な機能だということだ。仮想メモリは、OSやタスク、プロセスを仮想的なメモリ配置へ再編するために、OSのアドレッシングが物理アドレスと違うため、リンクファイルでアドレス設定を工夫しなければならなくなる。全体的にシステムが複雑化して、デバッグが難しくなるというデメリットが大きい。(あるサイトでは、にわたま問題—-鶏が先か、卵が先か—-と書いてあった。それくらい悩ましい問題らしい)
それに、PDEの設定にはU/S-bit(user-privilegeとsupervisor-privilege)があって、つまり、supervisor-privilegeのPDEで指定した4M-byte分のPTEの仮想メモリは、ユーザーアプリケーションでアクセスできない領域になるわけで、結局、PTEテーブル一つ分の4M-byte単位でOS領域とユーザーアプリケーション領域を考えて配置することになり、柔軟性が全くない。それなら実メモリをGDT/LDTでセグメントで配分する方が簡単に思える。PTE毎にもU/S-bitはあるのだが、PDEレベルで設定された時は無視されるのだろうか?それなら、PDEにU/S-bitは必要ない。整合性を考えると不思議な仕様だ。それとも私の理解不足か。
ディスクへのスワップでメモリ不足を気にしなくても良いなら、その見返りはあるかもしれないが、HDDなどのディスク装置へのスワップは遅すぎて、RAMを増設した方が、ずっと効率的で費用対効果が高い。SSDの速度ならスワップも気にならないのだが、SSDでないなら、実記憶のまま、注意深く自分でメモリ配置をした方が、解りやすくて処理速度も早くて、絶対的に良い(と思う)。今回、BIOSで取得したシステムメモリマップを見ても、BIOSの利用領域などがあって、自由に使えるメモリ領域は途中で分断されていて、リニアに使えない。だから、仮想メモリに物理マップをマッピングする時も、OSやタスクでアクセスできない領域を避けるように考慮してマッピングする必要があり、それなら実メモリのまま、使えない領域を避ければ良いだけで、何のために仮想メモリという機能があるのか、どんな利便性があるのか分からなくなる。今回は勉強と将来の拡張(スワップ機能の実装)のために、ページングだけ実装して、見かけ上、今までと違和感なく動作させることができた。

マルチタスクには、T-Kernel2.0を採用することにした。理由はフリーで、日本語ドキュメントがきちんと整備されていること、ミドルウェアでTCP/IPのモジュールやFatFsと同程度のファイルシステムのモジュールが、フリーで提供されていることが理由だ。
詳しいことは分からないが、μT-Kernel仕様というのが、IEEEで採用され、国際標準になっていることも考慮した。Linuxは普通に動いて、皆が使っているし、自分で何かしようにも英語情報ばかりでは、自分でできることはほとんどない。T-KernelはARM CPUをターゲットにしているので、ハードウェア関連の初期化関数などを用意すれば、使えるのではないかと思っていた、、、、

しかし、その考えは甘かった。おそらく東京大学の頭のいい人が作成したのだろうが、スパゲッティプログラムではないが、システム合理的に最高性能を出すために最適化されているために、普通の人間が理解するには、既に組込みシステムやマルチタスクの経験豊富な人であれば別だが、余りにも複雑怪奇すぎて、勉強用の教材には向かない。FatFsを移植する時は、自作すべき関数の名称や機能が明確になっていて、何をしていいのか分からないということはなかった。改めてFatFsの出来の良さが分かった。
T-Kernel2.0は、特にMakefileの構造が複雑で、Perlスクリプトまで使った超絶技巧を用いてmakeしている。私はOSを勉強して移植したいだけであって、makeやPerlの超難度テクニックの習得を前提とされると、肝心のOSの内容にまで辿り着くことができない。頭のいい人の罪のない欠点だが、自分が理解できることは、普通の頭しか持たない人間でも同じように理解できるのだという単純な思い込みがあると思う。こんな複雑だと、全体構造をある程度は理解できないと、移植して再利用などできはしない。しばらくは解析をしようとおもうが、別のマルチタスクOSを探すことになるかもしれない。

(2023/2/4 追記)T-Kernel2.0のソースを解析していくと、T-Kernel2.0はARMコアの機能と仕様に強く依存していて、また、市場に出回っていない特殊なボード仕様にも依存していて、移植性がなかった。一応、ソースプログラム内でハードウェア依存部とかを切り分けてはいるが、プログラムのロジック全体が、ARM独自のアセンブラ命令や機能でないと実現できないプログラミング(至るところにARMのインラインアセンブラが埋め込まれていた)になっており、他のCPUに移植する場合、ARMのアセンブラや機能を把握できてないと移植作業もできない、、、、、というか、教材にもならないし、実用性もないOSだと分かった。
MakefileやPerlスクリプトも複雑で、自分の開発環境用に修正するのも容易ではない。FatFsは移植部分をdiskio.cというファイルで基本ロジックと機能の外形を提供していて、そこだけ理解してしまうと、実質的に数時間で移植できた。
μT-Kernelのソースも見てみたが、T-Kernel2.0と作りが同じで、ARM依存が強く、移植できそうにない。実際、STM32とかルネサスとかARM系(?)の4種類の開発環境と移植例しかなく、FreeRTOSのようにx86を含めた数十種類もの移植例はない。宣伝用のデモにでもVMwareなどの仮想マシン環境上で動作するサンプルを提供しても良さそうなものだが、開発元であっても、それが容易ではないくらい移植が難しいのだろう。
FreeRTOSは英語が基本だし、Amazonに買収されていて、情報を検索すると強制的にAWS関係の広告へ誘導されてしまう。つぎはぎOSの拡張のためにはマルチタスク化は避けて通れないが、他に適当なOSSが見つからない。ラウンドロビン方式でのリアルタイム性のない簡単なマルチタスクだけ自作してみるか、、、、、困った、、、、、

カテゴリー: Linux, VirtualBox, つぎはぎOS, 自作OS | コメントする

自作OS — ソースファイルの整理、ライブラリ作成、Timer機能の追加、、、そして、つぎはぎOSの道へ

ステップローダーの不要になった機能を削除してスリム化し、ステップローダーとブートモニターで共通に使う関数をcommonディレクトリへ集約した。今回、i686-elf-arというライブラリ作成用のツールがあることを初めて知り、自作のmemcpy()などの汎用関数をライブラリ化して、common/lib/へlibstring.aとして作成した。静的ライブラリをつくるため、rcsというオプションを意味も分からずサイトの情報通りに付けて作成したが、コンパイルとリンクもできて、VirtualBoxで動作したからうまくいっているのだと思う。FatFsなどの<string.h>参照のために、pseude_string.hへlnコマンドでファイルリンクを設定した。
これから肥大化していくであろう開発に備えて、Makefileを含めて全体の整理を行った。commonディレクトリへ移動したインクルードファイルをMakefileのi686-elf-gccのオプションで-I指定、ライブラリはオプションの「最後の位置」で-Lと-lの指定で参照するように変更した。FatFsを共通化することも考えたが、ffconf.hのリードオンリー構成とリード/ライト構成のオブジェクトサイズの違いがあるし、今後FatFsがバージョンアップしても、安定して動いているなら旧バージョンのままでよいし、新しくビルドするモジュールにだけそれぞれリンクする方が賢明だと思った。ステップローダーの自作ソースは3ファイルだけになり、ロードモジュールはFatFs(リードオンリー構成)を含めて16.2K-byteに収まった。ブートモニターの自作分は6ファイルで現在40.6K-byte(リード/ライト構成のFatFsを含む)となった。普通の開発だとstdxxxなどのシステム共通ライブラリの更新はしないものだが、自作のものなので、しょっちゅう思い付いて修正や追加を行っていて、そんな時のcommonを含めたmakeの依存関係の設定が私にはよく理解できておらず、一部の再コンパイル漏れがでたりして、結局make cleanでオブジェクトを削除してから全部をmakeしなおすことが多い。どこかに頭のいいMakefileのサンプルがないだろうか、、、、、

関係ないかもしれないが、ステップローダーでリードオンリー構成のFatFsをできるだけ小さくしようとffconf.hを設定したら、以下のような警告が出るようになった。
ff.c:809:13: warning: ‘put_utf’ defined but not used [-Wunused-function]809 | static UINT put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */
警告なので、リンクと実行に何の影響もないのだが、put_utfという変数名からすると、UNICODE関連のような気もする。宣言しても使われてない(defined but not used)ということなので、コメントアウトしてしまおうかと思ったが、ff.cのソースを見ると、LNF関連定義の#ifdefでコードの生成が複雑に絡み合っているみたいだったので、そのままにしておいた。

ずっと後回しにしていたが、ブートモニターにTimer割り込みを追加した。PITの初期化は簡単なので、割込み間隔は取り敢えず10msecとして、すぐに動くようになった。シングルタスクなので、単純にウェイトするためにしか使えないが、OSにタイマー機能は必要だ。

思いがけず、ブートローダーの起動に成功して、その感動でここまで突っ走ってきたが、プログラミングと関係ない仕事をしながらでは、可処分自由時間の確保が難しい。今はもう満足感もあるが、疲れたというのが正直なところ。FatFsの作者の方に感謝するとともに、すごい人の作った、すごいプログラムを使わせてもらう方針へ転換することにした。
今はOSSが盛んな時代でもあるし、既にオープンソースがあるものについて、自己満足で作成することに疑問を持つようになった。やるのなら、それらを使った新しいことをやりたい。これからもOSは作り続けるが、オープンソースを利用し、謂わば「つぎはぎOS」として、自分なりのアイディアを盛り込んだOSを少しずつ構築しようと思う。

カテゴリー: Linux, VirtualBox, 自作OS | コメントする

ゲーミングキーボード Logicool G512r-TC 有線 RGB タクタイル

自作OSの作成に疲れたのもあって、しばらくSteamのゲームをして遊んでいた。それなりに継続して遊んでいるのは、DEAD OR ALIVE6だが、ゲームパッドを持ってないので、キーボード入力で操作しているが、Dランクから全然上達しない。というのは、反射的な操作をした時に、思った通りの動作をしてくれないからだ。昔は自分の入力ミス、指が追い付いてないと思っていたが、二年近くも操作して、指が慣れた今は、キー入力の順番が入れ替わったような動作やキー入力の無視、遅延などが発生していると確信している。最近、ゲーミングキーボードというゲーム用のキーボードがあることを知り、複数キー同時押しやゴーストインプットを防ぐ機能があるとのことで、自分の所為なのか、キーボードの所為なのか、疑問を解消するために、ゲーミングキーボードを衝動買いしてしまった。普通のキーボードなら二千円もあれば買えるのに、自分でも馬鹿みたいに思うが、自分の感じる怪しい現象が本当のことなのか、違うのかどうしても知りたいと思った。

ゲーミングキーボード Logicool G512r-TC 有線 RGB タクタイル

選択したポイントは、26キーロールオーバーという複数のキーをどの順序で同時押ししても、狙い通りのコマンドを発動できることと、アンチゴースティングとかいう機能によって、複数のゲーミングコマンドを同時に押した時に確実にコントロールすることができる、などと説明に書いてあったことだ。
流石に数万円の高機能品は買えなくて、ぎりぎりキーボードに出せる金額のこのキーボードに決めた。一万円以上したので、これで問題解決しなかったら、自分の技術不足、思い違いだと認められるかと思った。

最初の感想は、ずっしり重い。キーボードが打鍵で動かないようにしているのだろうが、重すぎる気がした。それと、USBコネクタが二股になっているのに驚いた。片方はUSBパススルーで給電のためらしい。全く有用でない光る機能のためらしいが、それらを省いて、もっと安くしてもらいたいと思う。専用の常駐ソフトは使わずにいたが、むやみにキーボードが点滅し続けるのでうざい。不本意だが、Lghubとかいう専用ソフトを入れると、点滅が止まった。

タッチタイピングが変わって違和感があったが、これは慣れの問題なので仕方ない。使ってみると、キャラ操作がスムーズになり、キー入力の入れ替わりが無くなったように感じた。同時押し技のホールドが決まり易くなったが、キー入力の無視はそのままだった。ネットで調べてみると、DEAD OR ALIVE6は連続キー入力の無反応時間が他の同類ソフトと比べて長めで、コンボ技の途中キャンセル機能やコンボ技の最後のタイミングをずらす遅延機能があって、それに当てはまらない連続的なキー入力は切り捨てるような仕様になっている、というような書き込みがあった。もしそうなら、高性能なゲーミングキーボードを買っても改善は見込めない。ホールドはキャンセルや遅延入力の受け付けがないので、このキーボードで改善されたのだろう。正直これでは、一万円のコスパには合わない。五千円くらいで充分だった。しかし、ゲーミングキーボード自体は悪いことはないので、できるだけ長く使って、コストに合うようになることを願いたい。

(2023/4/10追記)Dead Or Alive6をずっとプレイしていたが、もう「S」と「D」のキーの表面の塗装が少し剥げてしまった。ゲームで連打しているので、文字が薄れたりするのは仕方がないが、早すぎないだろうか。コストのために塗装剤の質の悪いものを使っているのかもしれない。選択を失敗したとまでは言わないが、正直、がっかりした。

カテゴリー: PC周辺機器, ゲーム | コメントする

FatFSの移植(FDへのファイル作成) — 自作OS

ステップローダーの作成と本番用ブートローダーの分離と制御移行に成功したので、FatFsのファイル書き込み機能の実装を行った。これまでの経緯については、以前の記事を参照して欲しい。

disk_write()コマンドは、disk_read()コマンドの時と同様に、既に作成済みのDMA処理でディスクへ書き込む関数を流用して簡単に作成できた。
テスト用の簡易コマンドを作成して、コマンド実行で短いテキストファイルをフロッピーディスクイメージ内へ新規作成を行い、そのフロッピーイメージをManjaro Linuxでマウントすると、正常に認識され、Mousepadでも開いて中身を表示できた。一部を修正して保存。アンマウントして、再度、VirtualBoxで起動すると、簡易lsコマンドで一覧表示され、簡易catコマンドで修正した通りの内容が表示された。

直接関係ないことだが、FatFsをコンパイルする時に、i686-elf-gccでは8-bbyteのQWORDが選択され、エラーとなってしまって、付け焼刃で、QWORDを使用しないように勝手に修正している。/usr/lib/gcc/——-/stdint.hというインクルードファイルが必要だった。stdint.hから必要なものをリライトして、pseudo_stdint.hというファイルを作成して対応しようと思ったが、中身は#ifdefなどのマクロ判定の塊で、ロジックを追うのが面倒だったので、ff.hを手作業で32bit用に修正した。
確証はないのだが、コンパイルエラーの原因は、i686-elf-gccの問題だと思う。英語のサイトを調べ回って理解できた限りでは、Manjaro Linuxのi686-elf-gccのオリジナルはgcc-11.2.0なので、標準C言語の2011年仕様に準拠していて、FatFsは変数の型を選択する際、#defineマクロの__STD_VERSION__などで、1999L以上かどうかでstdint.hと8-byte=QWORDを採用するかどうか判定していて、i686-elf-gcc自体は32bit限定のgccなのだが、#defineマクロの判定のために、stdint.hとQWORD型を採用してしまっているように見えた。stdint.hを参照するようにすれば、エラーはなくなるのかもしれないが、i686-elf-gccがQWORD型へ対応できているのか分からない。

一応、目標とするところは終えた。Timer割り込みとカレンダー機能とか、共通ルーチンのライブラリ化と分離もやっておかないとソースが重複したり複雑になったりするので、今やっておいた方がいいし、必要なら簡易なシステムコールを作成するか、いろいろな事情があって迷っている。

カテゴリー: Linux, VirtualBox, 自作OS | コメントする

FatFsの移植(FD書き込みの挫折) — 自作OS

今度はFDDへの書き込みのためのdisk_write()、disk_ioctl()を作成する。
テストのために、フロッピーディスクイメージの空きセクタへ1セクター書き込むアセンブラのサブルーチンを作成し、writefdという簡易コマンドを作成して、バイナリエディターでフロッピーディスクイメージの指定したセクタへデータを書き込んでいるかテスト確認してから、FatFsへ移植することにした。

FDDへのDMA転送設定は、DMA回路のモードレジスターへの設定値を変えるだけなので、read用の関数をコピーし、5分で修正できた。
FDDへのWRITE-DATA(0x05)の制御コマンドのシーケンスもREAD-DATAと同じような流れで、IRQ6割り込み待ちとSENSE INTERRUPT STATUSコマンドの送信など、ほとんどコピーし、違いとしては、コマンド処理ステータスのST1のNW-bit(bit1)がフロッピーディスクが書き込み禁止であることを通知するためにONになるので、それをエラーチェックすることぐらいしかなかった。そんな風に、disk_write()は三時間ほどで簡単に作成できた。テスト用書き込みコマンドを作成し、指定したセクターへ設定したデータを書き込むことを確認した。
disk_ioctl()は、ドライブ情報得る時やフォーマット操作をする時など、ディスク操作関数の内部で使われるらしい。ブートモニターにはフォーマット機能をもたせる必要がない(起動ドライブの自分自身を消去することになる)ので、最低限の処理だけならドライブ情報を通知するだけで、簡単に作成できた。

作成中に思わぬコンパイルエラーが発生した。今まではFatFsをリードオンリーの最小構成でビルドしていたのが、リード/ライトに設定変更したら、stdarg.h、math.h、string.hのstrlen()が存在しないというエラーメッセージだった。math.hはf_printf()で浮動小数点処理を組み込むようになっていたからで、それを取り外した。strlen()は64bitサイズの変数を扱うためで、また新たに作成しても良かったがlonglong型を使うことはないので、これもffconf.hの設定を変更して、64bitサイズを組み込まないようにした。
問題はstdarg.hで、初めて見るヘッダファイルだが、va_listやらva_startやらva_argとかの関数を提供しているらしかった。調べてみるとprintf()やscanf()など引数の個数が可変の関数のためのマクロ定義だと分かった。gccの内部で対処できる事前定義された処理なので、ヘッダファイルをそのまま利用しても問題ないらしかった。念の為、/usr/lib/gcc/——-/stdarg.hを探し出して、中身の正味6行分をリライトして、pseudo_stdarg.hを作成した。それでコンパイルエラーは出なくなった。しかし、今度はリンクエラーが出るようになった。前にも経験した「relocation truncated to fit: R_386_16 against `.data’」で、オブジェクトのサイズが以前より10K-byte以上増えて、0xffffまでの16bitリアルモードのラベルシンボルの範囲に収まらなくなっていた。回避方法を模索してみたが、調べても何もわからず、f_printf()などの関数の動作確認は断念し、DMA書き込みルーチンの検証はできたので、FatFsをリードオンリー構成へ戻した。

メモリマップを見直してみたが、10K-byteを空けるのは難しく、何とか収めたとしても、プログラムの追加や修正をしたら、また同じエラーが出るのは目に見えている。スタック領域として使っている領域も、30K-byte程度しかなく、スタックへローカル変数を大量に確保する高級言語でのプログラミングでは少なめで、削るわけにもいかない。
さんざん考えた挙句、二段階ローディング(?)ともいうべき方法をとることにした。今のブートモニターはリードオンリーだけで機能拡張はせず、16bitモデルのシンボルを含まない32bitプロテクトモードの別個のモジュールバイナリをフロッピーイメージからRAMへロードして、制御をそちらへ全て移す。FatFsのモジュールなどは重複するが、現在の方法ではこれ以上、機能を拡張できないので、もう行き詰まっている。現在のブートモニターはステップローダー(仮称)という名前にして画面表示やコマンド実行などの不要な機能を削除し、32bitプロテクトモードへの変更とプログラムロード機能だけに特化し、0x00010000以降へFatFs(リードオンリー構成)で本番用ブートモニターをロードし、そこへジャンプする。本番用ブートモニターには制限がなくなるので、ステップローダーのメモリ領域も含めて、作業用に利用することができるはずだ。かなり大きな改修だが、自作OSという試行錯誤に必要な試練だと思うことにする。
しかし、8bitから続くx86系CPUは至るところでアーキテクチャーにツギハギ感がある。ARMやMIPSなどは、同じような問題は起こらないのだろうか? とちょっと興味を持った。

ステップローダー(仮称)を作成中に、gnuアセンブラの変なjmp命令の書き方を知った。本番用ブートモニターへジャンプ(ステップローダーへは戻らない)する時、0x00010000という絶対アドレスへジャンプするのだが、movl $0x00010000,%eaxでジャンプ先アドレスを設定して、jmp %eaxだとエラーになる。こういう場合、jmp *%eaxと書かなくてはいけない。ちゃんとgnuアセンブラが、’*’を付けるよう警告してくれる。癖のあるgnuアセンブラのよく意味の分からない古い記述、みたいな書き込みが英語のサイトにあった。まあ、滅多に使うことのない記述だが、覚え書きとして残しておく。

本番用ブートローダーは、16bitのプロテクトモード変更処理の部分だけ削除し、メモリ配置だけ修正して機能はそのままにした。ステップローダー(仮称)から自動でロードされ、最初に再度ハードウェア関連の初期化処理をして、コマンド入力の画面まで表示された、と思ったら、キーボード回路の初期化に失敗した。ステップモニター(仮称)の方でも必要ないのにキーボード回路の初期化をしていたので、そちらを削除したら、ブートモニターがキー入力を受け付けるようになった。何度初期化をしても問題ないと思っていたので、腑に落ちないが、時間がある時に原因を究明しようと思う。ブートモニターでもlsやcatなどのコマンドが正常に実行できた。やれやれだ。次はFatFsをリード/ライト構成にして、フロッピーディスクへファイルを作成しようと思う。

カテゴリー: Linux, VirtualBox, 自作OS | コメントする

FatFsの移植(読み込みだけできた) — 自作OS