Personal tools
You are here: Home ブログ 学習経過 Categories 学習経過
« December 2010 »
Su Mo Tu We Th Fr Sa
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
Recent entries
sysfs tips 02 ohyama 2010-09-09
sysfs tips ohyama 2010-09-02
Haskell で周波数スペクトルを得る ohyama 2010-07-29
Haskell で線形識別関数の学習を行う ohyama 2010-07-19
Haskell で逆行列を求める ohyama 2010-07-16
Recent comments
Re:vim に lisp 機能をつける t.mimori 2010-12-16
Re:Haskell で周波数スペクトルを得る H.OHYAMA 2010-08-01
Re:lkml でお勉強 (その1-1) Hiroyasu OHYAMA 2009-08-21
Re:lkml でお勉強 (その1-1) kosaki 2009-08-20
Re:vim に lisp 機能をつける ohyama 2008-05-08
Categories
学習経過
GNU/Linux
 
Document Actions

学習経過

Up one level

Document Actions

学習経過その2

1週間かけて学習してきたOSのメモリ管理の学習が実を結んだ。

誠に愚かしい事に、かつての自分は最新の技術のみを理解して満足する人間であった。
言い替えれば、かつての技術を学ぶ必要性を理解出来ていなかった。

皮肉にも、否定していた行動をとることで、その必要性を理解できた。

そういう点でもタネンバウムさんの本は、実によく出来ていると思う。プロセスでもそうだったが、コンピュータが出来たての頃の技術についても詳しく説明されている。その技術の利点と欠点を踏まえた上で、次世代の技術を解説されているので、歴史的な次世代技術の登場の必要性や必然性を理解することが出来た。
具体例をメモリ構造で言うと、MFTの固定区分におけるメモリ構造の不便性を甲斐小するために、スワッピングを用いたり、使用メモリとホールをリンクリストで管理したりと色々な手法を用いて効率的なメモリ管理を達成しようとしていた。けれども、外部断片の問題が常について回る。もちろん詰直しを行えば良いわけだが、ページングがそれを解決してくれた。この流れには、先に述べた必然性を感じる。

このごく当然な事を理解し、かつての技術を学ぶ必要性を理解(他人に対し明確に説明する事が出来る)した事は、メモリ管理について一定の理解が出来た事よりも嬉しい。


ところで、今日でメモリ管理の学習をはじめて2週間だが、自分の学習は1週間区切りで完結している。
つまり、1週間知識を溜め込み、月曜に理解をする。これは、図ったことではなく質問をするチャンスが月曜に限られている事からこうなっている。
今日まで、ページ化セグメンテーションについての概要が理解できず、苦しんでいた。セグメント管理をページングしたら、セグメント管理の利点である論理制御の点が損なわれるのではないかという疑問を持っていた(細かな疑問点をこれ以上文章で説明する事が難しいので、割愛させていただく)。

これを質問により解決できた時、無類の喜びを感じる。

大抵の疑問は、"そもそも…"という基本に立ち帰ると分かったりする。
今回の疑問も例に漏れず、セグメントとは何か? という所からスタートして理解できた(又、清水謙多郎:著の「オペレーティングシステム」にも御世話になった)。
一度理解できると、それまでに学習してきた知識とその知識がリンクして、いろいろとわかってくる。なるほど、こうやって、実メモリに収まらないセグメントも管理できるわけだ。なるほど、OSの授業で「巨大なプログラムでは、実際に全てがメモリに乗るわけではなく、分割されて乗るわけなんだけど…」の話はこれを言っていたのか。

プロセス・メモリ管理が理解できると、ファイルシステムの構造が知りたくなる。これが『楽しい』って事なのかもしれない。
その後、入出力の理論を学習したら、いよいよ実装に入ってゆこうと思う。

ただ、一つ気がかりなのが。。。「COM」を理解できていない事。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/5b667fd27d4c904e305d306e2/tbping

学習経過その3

今日、須崎さんが退職された。
須崎さんが居ることによって、自分は安心感を得られた。なので、とても親近感を感じた。
それは、須崎さんに限ったことではないのだが、最近は須崎さんから仕事を頂く事が多く、毎日のようにお世話になっていた。同時に、迷惑も書けていたと思う。
そんな須崎さんから「今日が最後の出社日」なるメールを突然受け取った時には、驚きも合いなり鼻の先が少し痛くなった。

須崎さん。あなたと接せられた時間はとても少なかったですが、充実していました。
そして、最後のmantisの仕事を振ってくれてありがとうございます。とても楽しかったです。

あぁ。須崎さんに対して発言するには、自分には関係が薄すぎる。
にも関わらず、須崎さんへのコメントを井上さんから賜わるはずだったのに、井上さんの冗談であろう振りに思わず乗ってしまい、つまらんバイトの薄っぺらい話しにしてしまった。
あれは誠に軽率な行為だったと今になって、激しい自己嫌悪に襲われる。結局井上さんからのお言葉が、バイトなんぞの話しにすげ代わり、怒髪衝冠な社員さんもいたと思う。ほんとうにごめんなさい。



感情に身を任せて筆を走らせると止むことを知らず、このまま行くと極めて耳障りで目障りな自暴記事になると思うので、「学習経過」と銘打っているので、感傷的な論議はほどほどに本題に入る。

入出力構造以外のOSの仕組みはだいぶ理解できた。
これで人並みにはOSについては知っていると言える。

しかしまだまだ構造について知らない部分はたくさんあると思う。
けれどもこれ以上は活字ではなく、現物から理解しようと思う。
いよいよカーネルコードに飛 び込む(タネンバウムさんの引率で)。氏の本はminixカーネルについて丁寧に解説してくれているが、アセンブラコードはおろかCのコードも、これまで のように少し(実際には深く)考えた程度では理解させてくれない。
なので今週末は、マイクロカーネルの要、プロセスのメッセージ処理に的を絞ってコードを 追ってく。

順調にコードから仕組みについて深い理解ができたら月曜は晴れ晴れした表情で出社できることだろう。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/5b667fd27d4c904e305d306e3/tbping

学習経過 その4

今日はシグナルについて書くことにする。
この部分を学習するに当たり、割り込みと関連づけて考えずにはいられない。
これを踏まえてシグナルの受信について考えてみる。

『シグナルの重要な特徴として相手のプロセスの状態に関係なく、いつでもシグナルを送る事ができる』と教本にある。しかし、シグナルの送信後すぐに相手側プロセスが受信するのではない。ソフト割り込みのように、シグナル送信を"生成"と"配信"の二段階に別けている。
シグナルの生成は、送信先プロセスのプロセスディスクリプタにシグナルが送信された事を通知する。シグナルの配信ではカーネルが、送信先プロセスにシグナルに対する処理を行わせる。

さて、シグナルの生成は送信側プロセスの任意のタイミングで行われるわけだが、シグナルの配信はいつ行われるのか。2段階に別けているという事は、配送は遅延処理されそうである。
実際にはカーネル実行パスによって、プロセスの保留中シグナルが確認され、配送される。

ところで、シグナルの配信はカレントプロセスに対してのみ行われる。
この前提を考えたときに、疑問が生じる。
カーネル実行パスが処理されなければ、いつまでたっても配送されず、仮に実行されても目的にのプロセスが実行中に保留中シグナルが確認されないかもしれない。つまり、いつまでたっても目的のプロセスにシグナルが配送されないかもしれない。というもの。

しかし、その疑問はインターバルタイマ割り込みの理解によって瞬時に解決できる。
インターバルタイマは1tick毎に発生する割り込みで、処理が終了するとカーネル実行パスが処理される。プロセス時間(クォンタム時間)の更新 (update_process_times()関数)はtick毎に行われる。つまり、スケジューリングの基準となるCPU時間の分解能は 1tickなので、tick毎に実行されるインターバルタイマの終了によって呼び出されるカーネル実行パス中で処理される保留中シグナルは、全てのプロセスの実行時間が無くなるまでに配送される。

これを書き終えて素朴な疑問が浮って沸いた。
シグナルを、現在の処理に割り込む点や、遅延処理される点から以前に学習したソフト割り込みと同一視してしまいそうになる。プロセスに対して処理を行う事で、プロセスを殺したりできる事は理解できたが、割り込みとシグナルの明確な違いを知りたい。シグナルのシグナルたらしめる物とは何か。

「シグナル処理はプロセス間通信と考える事が出来る。割り込みはカーネルに対する処理であるのに対して、シグナルはプロセスに対する処理である。」との事。では、プロセスに対する処理をシグナル以外にできないのだろうか。もし、シグナルという機能を使わなければプロセスに対して命令する事ができないなら、シグナルの必然性が存在する。
しかし、そうでもないらしい。事実、プロセス間通信を行うならば、ソケットを使う手法が存在するとの事。なるほど、プロセスが親子関係ならばパイプも使えるだろう。

それでは謎は解決されない。しかし、概ね納得する事はできた。
先にも述べたように、シグナルは30年以上前から存在する機能であり、新しい機能(ソケット等)は次々存在する。なので、シグナルは歴史的にも技術的にもプリミティブな機能であると言えるとの事。加えて、メモリ管理無しのOSはありえないが、シグナル無しのOSはありえると事。
なるほど、古きからある技術のようだが、シグナルによってプロセスを殺させるという話しはとてもわかりやすい内容であった。割り込みとシグナルを分離して考える事のできる今、教本の内容をより素直に自分のものに出来るだろう。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/5b667fd27d4c904e-305d306e4/tbping

Re:学習経過 その4

Posted by ohyama at 2007-01-25 23:35
おかしな日本語表現を較正した結果、トップへ上がってしまいました。
でしゃばった行為をしてしまい、ごめんなさい。

語らなければ伝わらない『知』について

先日、works mozilla 拡張機能の勉強会に参加した。
手軽で面白い技術だと思ったのだが、あまり流行っていないらしい。そして、browser.xul が呼び出すJavaScript 関数についての解説をしているサイトが極端に少ないらしい。つまり、『知りたくばソースを見ろ』といった状態という事だ。
別にソースを気合いで読み解くのも悪くないのだが、ソースを媒介としたコミュニケーションの限界を指摘する人も居り、自分自身もLinuxカーネルの機能や動作を学習する上で、ドキュメントのお世話になり、解説サイトや解説書籍に至ってはバイブルとなり、その言葉の通り携帯している。
このように、語らなければ伝わらない『知』が存在するらしい。その上で、両者の関係をイコールで考えたくなる。
技術は自ら語ることをしない。だからこそ、作者が有形・無形の痕跡を残すのだろう。つまり本やドキュメントに限らず、その技術のすばらしさを解いて回っても同じ事だという事。それは先日参加した LinuxWorld Expo/Tokyo 2007 の Ruby のまつもとさんを見てそう思った(これについての感想は、諸事情により自重する)。

人も同じ事が言えるのではなかと思うことがある。
嘘だという声が聞こえてきそうだ。その気持ちはわかる。つまり、技術がただそこに佇むだけで、そこに存在するだけの対して、人は自ら自分の位置と情報発信する存在だからである。
しかし、ハードボイルドな人間が居る。自分はこれを、何も語らずに何かを生産しつづける人間と定義する。今ここで、自らの存在を示し、ブログ等で自分の活動を頻繁に報告し、さして生産能力を持たない自分は、その対象とはなりえない。
上記の存在を石で例える。広大な場所に黒ずむただの石もあれば、キラリと光る宝石もある。まさに玉石混淆な世界。だが、これらは自ら光源を持ち発光しているわけではないので、光が無い場所ではダイヤも単なるの石になってしまう。

ここで、Master Hamagishi について考えてみる。
自分がアリエルに来てから、もうすぐ1年が経つ。やっとアリエルという組織がどんなものか把握してきたと思っている。
かつて、Mr.Hamagishi に会ったときと、今の Master Hamagishi の印象は大部変わった。これは氏が変化されたという事ではなく、自分の認識が変化したからである。当時抱いた氏に対する自分の印象は、弱い人だった。これは肉体的に弱いという事ではなく、自分を始点、井上さんを終点と考えたベクトルで若干自分寄りの存在だと思っていたという事。
アリエルにおいて、このベクトルはその人物の重要性を表すものであると認識していた。
さてその根拠だが、当時の自分の目からは、多くの人間に仕事を押しつけられ、何かと文句を言われている氏の背中が小さく見えた。
だが。その当時抱いた氏に対する印象も、自分が氏の実力に対してあまりに無知であったが為である。

今自分が思っている事をここへ書く事は即ち、自分の無能さを自らによって証言する事に他ならないのだが、既に周知の事実だと予測し、話を続ける。
昨今の自分の境遇の変化によって、Master Hamagishi の仕事の一部を引き継ぐ事となった。
これにより、これまで当人の口からは決して語られる事が無かった事実を、氏の仕事を代行する事によって知る事となる。

近い話では、メールサーバーとネームサーバーの移行作業における話がある。
組織におけるメールシステムは極めて重要であり、これにおける設定の不備やトラブルで幾度と無くお叱りを受け、これまで見たこともない井上さんの鋭い眼光を見る事もあった。
トラブルが起き、解決できず、時間が迫り、パニックになりかける。そして、Master Hamagishi に泣き付いた。
氏は涼しい顔で、問題点を指摘し、何がまずいのかを言い当てる。自分はそれに従い、問題を解決する。
一瞬の出来事であった。それは、氏の卓越したネットワークの知識と経験が成す技なのだろう。
このネットワークの知識と経験について、井上さんや大谷さんは言わずもがなだが、ネットワークについて調べる度に Master Hamagishi の名前が自分の中でそこに並記され、その凄さに関心する。何故なら Master Hamagishi は、このような広大な分散システムを支配する複雑な技術の根底を理解し、それにより社内ネットワークはもより、AirOne の基幹システムを支える人間の一人なのだから。
氏が、Arielの重要人物である事は言うまでもない、自分が月曜から姿を眩まそうとも、業務においてはさしたる支障は発生しないだろうが、Master Hamagishi がいなくなったら大混乱が生じる事は想像するに易い。


かつて思った、氏は仕事を押しつけられているという大いなる誤解をここで訂正したい。氏が優秀であるが故に氏に仕事が集まるのだ、それも氏でなければ解決できない仕事が...である。そして、氏がかつて叱責されていたのは、クリティカルな部分を扱うがゆえの宿命なのだろう。
先のメールサーバーの話のついでに、この仕事は運と Master Hamagishi の力に恵まれ、大失敗をする事はしなかった。これにおいて、自分は幾度と無くroot 権限で直線的な動作をするスクリプトを作成、実行してきた。今思えば、この行為は銃弾が飛び交う中、地雷源を目隠しで歩くようなものだ。
人がノーミスで仕事を成功させつづける事は考えにくい。幾度か被弾する事もあっただろう。些細なミスなら笑って済まされるかも知れないが、重要な仕事でミスを犯した場合、叱責される事もあるだろう。つまり、氏がこれまでに叱責されていた事は、氏に重要な仕事が回って来る事の証明なのだろう。

そんな師の大きな背中を見ながら、自分は知識を付けた上で、師に感化され、師の技を盗み、大きくなりたい。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/8a9e3089306a3051308c4f1d308f3089306a3044300e77e5300f306b306430443066/tbping

Re:語らなければ伝わらない『知』について

Posted by inoue at 2007-06-05 00:55
> 手軽で面白い技術だと思ったのだが、あまり流行っていないらしい。

少し誤解があるので訂正します。firefox拡張機能自体は、それなりに(firefox作成者の目論見程度には)流行っていると思います。流行っていないと感じるのは、XULアプリケーションの方です。

> browser.xul が呼び出すJavaScript 関数...

この言い方も微妙ですが、まあ、この辺の説明はあまりしなかったので。mozilla開発者の名誉のために補足しておくと、文書化がよくされている領域もあります。XULは良く文書化されています。XPCOMで提供されるインターフェースの文書化はあまり無いようです。

Master Hamagishiは、技術的な強さもさることながら、精神的な強さ(タフさ)が際立っています。先月のSoftware Design(http://gihyo.jp/magazine/SD/archive/2007/200705)の特集記事に「KKD[勘・経験・度胸]に頼らない機器管理/運用方法」がありました。Kの点でMaster Hamagishiに追いつくことは可能かもしれませんが、Dの点では無理です。ダークサイドに落ちない限りは。

ブートローダー(その1)

初回である今回は、自分が作ろうとしているブートローダはどんなものか。という事から、ブートシーケンスの流れをおさらいする。
次回以降で、実際に手を動かした結果を見せながら、今回話す道をなぞってゆく事にする。又、前回同様にフロッピーディスクからブートを行う前提で話しを進める。

尚、ここで言うブートローダーは、フロッピーの先頭セクタを読み込むところから、圧縮カーネルイメージを展開し、処理をカーネルに渡すところまでの処理を行うプログラムを指す。
ブートローダの主な仕事は次の通りである。
1) 圧縮カーネルイメージの読み込み
2) カーネルへ渡すパラメータの設定
3) プロテクトモードへの移行
4) カーネルイメージの展開・読み込み

では。ブートシーケンスの流れを細かく追ってゆく。
PCの電源を投入すると、BIOSがハードウェアのチェックを行い、結果を 0x00000 - 0x00600 の予約領域に書き込む。そしてブートデバイスを選定すると、そのデバイスの先頭セクタの内容を先頭セグメントの 0x07C0 に内容が読み込まれる(ブートシーケンスにおける Linux のメモリレイアウトについては、Documentation/i386/boot.txt に詳しい記述が存在する)。
1セクタ分しか存在しないこの領域で出来る事は少ないので、ここには次のブート処理が書かれたデータを読み込み、そこに移動するという内容を記載する。BIOS には、02 interrupt 0x13 において、フロッピーディスクから ES: BX で指定されたアドレスにデータを初期化するインターフェイスが存在する。これを用いて、ディスクに存在するブートプログラムをメモリに読み込み、処理を実行する。

ただ、リアルモードにおけるアドレスバスは、20bit しか存在しないので、1MBを優に越える圧縮カーネルイメージを置くことはできない。
なので、圧縮カーネルイメージは1MBを越える領域に対して転送を行う必要がある。これを行う為に、087 interrupt 0x15 のBIOSコールを呼び出し、拡張メモリ領域に対してデータ転送を行う。これにより、24bit 幅のメモリ領域に対してデータ転送が可能となる。しかし、メモリ転送なので、リアルモードにおけるメインメモリに圧縮カーネルイメージをいったん読み込む必要がある。これを実現させる為に、小さなバッファ領域をメインメモリ中に作成し、そこにディスクに存在する圧縮カーネルイメージを読み込み、データ転送を行い、再びバッファにデータよ読み込むという動作を繰り返すテクニックを使う。

ここまではそんなに面倒な事ではない。しかし、次に難敵が立ちはだかる。カーネルパラメータの初期化である。
ブートローダーは、Linux(カーネル)に対して値を渡すために、4KBのカーネルパラメータ領域を作成し、初期化を行う必要がある。
各パラメータのオフセットと内容は、Documentation/i386/zero-page.txt に書かれている。

この敵を倒すと、次に謎な敵が一匹姿を表す。A20 アドレスバスについてである。
x86 において、A20 を無効化されている場合がある。何故このような事がされているかというと、8086 において 0xFFFF0 + 0x00010 のアドレスは、0x00000 とされる事を利用して、0x9A000 以降に存在するBIOS予約領域と 0x00000 のBIOS領域を連続領域として扱う事を考案し、プログラムの命令数を減らすという事を行っていたらしい。昔の人が考える事は、現代に生きる自分が素直に理解できるものでは必ずしもないらしい。
いづれにしろ、昔の遺産を引き継ぐために、x86 で、A20 の21bit目のアドレスバスを無効化しているらしい。A20 のライン制御はキーボードコントローラを用いて行われる。
以下のコードは、arch/i386/boot/setup.S を抜粋したものである。ここで、A20ラインを有効にしている。

<pre class="literal-block">
    movb    $0xD1, %al            # command write
    outb    %al, $0x64
    movb    $0xDF, %al            # A20 on
    outb    %al, $0x60
</pre>

ここでいよいよ、CR0レジスタの最下位ビットをオンにし、プロテクトモードに切替える。
そして、先ほど拡張メモリ領域に転送したカーネルイメージを展開し、展開したアドレスにジャンプして、startup_32() を呼び出す。

ここまでが、簡単なブートの流れである。次回以降、ここで解説した内容のプログラムを動かしながらソースを読んでゆく。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e1/tbping

ブートローダー(その2)

今回は、ブートセクタに書かれたプログラムを実行し、ブートセクタの次のセクタに保存されているデータ(プログラム)を読み込み、処理を読み込んだ先に移すところまでを見てゆく(一週間時間を開けたわりには、異常に進みが遅い)。

<a href="http://dev.ariel-networks.com/Members/ohyama/stuff/first2second.tgz/download">ソースはこちら</a>

主なプログラムは以下の2つ。
boot.S    : ブートセクタの処理
second.S    : ブートセクタの次のセクタ領域の処理

では、中身について簡単に解説する。
ブートに成功すると、boot.S の .text セッションは、0x07C00 に読み込まれる。
boot.S は、0x07C0 をベースセグメントとする start に処理を移す。そして、フロッピーの初期化を行う為、init_fd において、BIOSコール(00 interurupt 0x13)を呼び出す。
そして、次のセクタに保存されている。データを呼び出す為、load_second で 02 interrupt 0x13 を呼び出し、1セクタ分だけ 0x90000 に読み込み、0x9000 をセグメントへ処理を移す。

さて、以前のプログラムでは、-fomit-frame-point オプションを指定し、gdb のコードスタック領域を削ったり、EBX レジスタのリザーブを省略したり、-fno-ident オプション、-finhibit-size-directivce オプションを指定し、ident ディレクティブ や .size ディレクティブを省略するなど、乾いた雑巾を搾る事を行っていたが、ここでは、最適化オプション -O2 を指定している以外、何もしていない。
それでも、boot バイナリを覗いてみると、ブートセクタの半分もまだ使っていない。512バイトあれば、(bios の助けを借りて)結構いろいろな事が出来るようだ。
しかし、ここでの仕事はこれで十分である。

0x9000 に読み込まれた second.S は、15 interrupt 0x10 のBIOSコールを呼び出し、ディスプレイに文字を出力し、読み込みが成功した事を表示する。表示が終わると、無限ループに入る。
ここで、ブートセクタの箱庭から 64K の広い(?)世界が広がる。次回以降、この領域を使って話しを進める。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e2/tbping

ブートローダー(その3)

bootsect.S の次の処理は、メモリの 0x90000 にロードされた bootsect.S が読み込んだ (はずの) セットアップルーチン start_to_setup ルーチン (arch/i386/setup.S) へ処理を移す。
ここでは、各種ハードウェアのチェックを行って、プロテクトモードに切替える処理をおなう。
早速ソースを見てゆく。

まずは、デバイスの初期化設定を行っている。int 0x13 (function 00) を呼び、%dl レジスタで指定したドライブを(恐らく再度*)初期化している。
(*) "恐らく"と言ったのは、GRUB や LILO がセットアップルーチンを読み込む為に、ドライブを読む為である。

次に、旧式のカーネルイメージかを気にしています。旧式のブートローダ(ここで言っているブートローダーとは、grub や lilo などのカーネルイメージをロードするプログラム)は大きいカーネルイメージをロードする事があるらしい。
__BIG_KERNEL__ が定義された時の $LOADED_HIGH 変数と loadflag のポインタ値が比較される事で判定される。
この判定に失敗した場合、 type_of_loader 変数によってブートローダのチェックが行われる(type_of_loader 変数は、linux がブートローダを認識する為の識別子であり、ブートローダの識別子とブートローダのバージョンから成り立つ)。
利用しているブートローダが旧式のLILOであった場合、loader_panic_mess にある文字列を出力して、hlt 命令を実行する(ちなみに、エラーメッセージは'LI'ではない)。

これに通ると、いよいよブートパラメータの設定を行う。
まずは、拡張メモリ領域(*2)のサイズを表すパラメータ($0x1e0)をクリアした後、($0x1e8)をクリアしている。この領域には、e820map 構造体(include/asm-i386/e820.h) が格納される。このデータ構造は、メインメモリのマップを格納するもので、"セグメント"を最小単位として、そのベースアドレス、長さ そして タイプを規定した20バイトのデータを最大128個持つ。
そして、INT 0x15 (function 0xe820) を呼び出し、0x1e8 をバッファアドレスとして、e820map 構造体を作成する。

(*2):リアルモードで扱えるメモリ範囲を越えたメモリ領域。ここでは、1M-16M と16M以降の領域を併せて言っている。前者は、INT 0x15 (function 87) によってメモリ転送が可能である。

次に、拡張メモリ領域サイズのチェックを行う。INT 0x15 (function e801)によって 1-16M における拡張メモリサイズと 16M 以降の拡張メモリサイズを把握できる。16M 以降のメモリは、64Kを1ブロックとして換算されるので、最大で4GBまでのメモリサイズを認識できる。
サービスルーチンからの戻り値 %bx (16MB 以降の拡張アドレス領域のサイズ)をコピーした %ebx を6ビット左シフトしているのは、0x1e8 のカーネルパラメータに、1MB-16MB までの拡張メモリ領域のサイズと、16MB 以降のそれの和を格納する為である。

ここまでで、linux(まだカーネルは呼ばれていないので、正確にはlinuxのセットアップルーチン)はどのセグメントのメモリ領域が予約領域で、どれが利用可能なメモリ領域かを判別できるよになった。又、拡張メモリ領域のサイズを知ることができた。

もしかすると、自分が想像していた bootsect.S の処理は自分が思っていたものよりもシンプルかもしれない。何故ならば、圧縮カーネルイメージを読み込ませるには拡張メモリ領域を利用しなければならないはずだが、bootsect.S が呼び出す、start_of_setup において、そのサイズを調べているわけだから。
とすると、前回自分が書いたプログラムが bootsect.S の仕事そのものだったのだろう。

次回は、この続きになるだろう。先は長い。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e3/tbping

ブートローダー(その4)

前回、start_of_setup 関数の中身を読みはじめ、リアルモードにおける拡張メモリ領域のチェックと、e820map 構造体の初期化及びブートパラメータの設定まで見てきた。
今回はその続きを見てゆく。

まず、キーボードのリピート/ディレイの設定を行っている。
そもそも、何故キーボードからの割り込みが発生した時にディレイ(遅延)を設けるのかというと、ディレイ時間が極端に小さい場合、キーを押下した時一瞬で画面がキーで埋め尽くされ、CPU処理時間の大半をI/Oに持っていかれてしまう為だ(と思う)。
これが設定されると、最初にキーが押下されてからディレイ時間が経過するまで、(BIOSがどのレイヤでこれを制御しているのか不明だが)キー入力の受け付けを行わない。又、キーが押され続けた時、リピートで設定した間隔で繰り返してI/Oが発行される。
ここでは、ディレイ時間が 250ms、リピート間隔が 30字/sec に設定されている。

そして、ビデオアダプタのチェックと、0x00 ブートパラメータの設定を video 関数(video.S) で行っている。
このパラメータ情報は、screen_info 構造体に格納され、SCREEN_INFO マクロがこのブートパラメータのアドレスを持つ。

次に、BIOS 予約領域 0x0000:0x0104 から 0x9000:0x0060 に対して16バイト分のデータを転送している。ここでは、プライマリHDD のパラメータを設定している。次に、同様にしてセカンダリHDDのブートパラメータを設定している。そして、セカンダリHDDのディスクナンバーを %dl レジスタに格納し、INT 13 (function 0x15) を呼び出し、ディスクタイプを取得する。
これに失敗もしくは、ディスクタイプがHDDではない場合、0x90 ブートパラメータをクリアする。

この後に、ROMテーブルのブートパラメータの設定を行っている。ROMテーブルには、その名の通り、BIOSの情報が格納される。
まず、ROMテーブルを格納するブートパラメータ 0xc0 を 0 で初期化し、INT 15 (function 0xc0) を呼び出し、ES:BX が指すアドレスに最大19バイトのROMテーブルを取得する。
これによって取得したROMテーブルのサイズはBIOSの種類によってサイズと情報が若干異なる。ここでは、最低 16 バイトのデータを転送し、0xC0 ブートパラメータを設定している。
このテーブルは、arch/i386/kernel/setup.c で定義されている sys_desc_table_struct 構造体のポインタから参照できる。

ここまで来ると、GAS コードにも大夫慣れて来る。
次は、PS/2 ポインタデバイスにおける処理である。0x1ff のブートパラメータを 0 で初期化した後、INT 11 を呼び出し 32bit のBIOS実装テーブルを取得し、EAX に保存する。
このテーブルを見ることによって、主要なデバイスの有無が確認できる。
ここでは、%al 下位 3 bit目を見る事によって、Pointing Device(PS) が実装されている事を確認できる。これが確認できた場合、0x1ff ブートパラメータに 0xAA を格納する。
尚、このブートパラメータの情報は AUX_DEVICE_INFO マクロによって確認できる。

さて。眼下には APM におけるブートパラメータの設定処理が横たわっている。カーネルオプションによってこれがサポートされていなくとも、動く気もしなくもないが一応中身を追ってみる。
例によってブートパラメータ 0x40 の初期化から処理がはじまる。そして、INT 15 (function 0x53) を呼び出し APM のバージョン及びフラグ情報を取得し、それぞれ AX レジスタ及び CXレジスタに保存する。
エラーチェックを行った後、32 bit プロテクトモードに対応しているかをチェックし、INT 15 (function 0x5304) を呼び出し、APMインターフェイスへの接続を切った後、INT 15 (function 0x5304) を呼び出し、APM インターフェイスへ接続を行っている。その際、出力された結果をブートパラメータ 0x40 に設定している。
尚、このデータも APM_BIOS_INFO マクロが示すアドレスから参照できる。
そして、再度 INT 15 (function 0x5300) を呼び出し、APM のバージョンとフラグ情報をブートパラメータに追加している(何故、再接続を行う前にブートパラメータを設定しないのだろうか)。

ところで、ブートプログラムを書くと言っておきながら、いつも通りソースコードをひたすら読んでばかりいる。しかし、細かい動作がわからず、優秀なドキュメントが存在しない状態では、こうするのがベターなのだろう。
などと言っている間に、ブートパラメータの初期化処理を読み終える。意外に呆気無かった。
結局、linux が設定するブートパラメータは、前回説明した拡張メモリサイズのパラメータと、今回説明した 7 個の計 8 個だけだ。

次はいよいよプロテクトモードへの移行である。

Category(s)
学習経過
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e4/tbping

Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.