movw - みる会図書館


検索対象: UNIX MAGAZINE 2002年8月号
12件見つかりました。

1. UNIX MAGAZINE 2002年8月号

0073 : 0074 : 4 $INITSEG , $go し inux のプートプロセス movsw ljmp MOV 命令は、以下の書式で叩プから叩 2 ヘデータ をコピーします。、、 m 。 v " に続く 1 文字はコピーするデー タの大きさを表すイ市子で、 b は 1 バイト、 w は 2 バイ ト、 I ( 工ノのは 4 バイトを意味します。 mov [bwl] 0 1 , 0 ア 2 SUB 命令は、以下の書式で叩 2 から叩ノ : した 結果を叩 2 ロ褓内します。 sub CbwI] 叩プ , 0 〃 2 36 行目の DEF-INITSEG は、 asm/boot. h に次のよ うな定数旦言があり、コンパイル時に、 0X9000 " に展開さ れます。 #define DEF_INITSEG 0X9000 ここまでの説明で、 64 ~ 70 行目は、以下のようにレ ジスタを設定するコードであることが理解できたと思い レジスタの内容は、 MOVS 命令を 1 回実行するたびにデ クリメントされるので、系区しか終った啼点で、その内容 は 0 になります。 72 行目を実行する点で CX レジスタには 256 か設 定されています。そして、 73 行目の MOVSW 命令は 1 回で 2 バイトを転送します。この 2 つの命令を繰り返す ことによって、結果的に 512 バイトのデータを 07C00H から 90000H , 云送することかできます。 74 行目の LJMP 命令は、以下の書式で指定される セグメントとオフセットのアドレスへジャンプする命令 ljmp セグメント値 , オフセット値 74 行目にある、、 g 。 " は、 60 行目のようにアドレスに付 けられたラベルを表します。これは、すぐ次の過程に登場 します。 スタックの設定 bootsect を移動したあと、セグメント間ジャンフ。命令 によりラベル、 g 。 " から処理カ台まります。 ます。 DS: 07COH ES: 9000H AX: 9000H CX : 256 SI: 0 DI: 0 0082 : go : movw 0086 : 0087 : 0088 : movw movw movw $ 0X4000 ー 12 , %di %ax , %ds %ax, %ss %di, %sp 71 行目の CLD 命令は、 EFLAGS レジスタの DF フラグをクリアします。この処理の意味は、 73 行目の MOVS 命令にあります。 とりあえす 72 行目は飛よして、 73 行目の MOVS 命 令をみましよう。ここでは、 DS:(E)SI カ甘旨すアドレスの データを ES:(E)DI に転送しています。転送するバイト 数は、 MOV 命令とに b 、 w 、 1 のいすれかで指定し ますにこでは w = 2 バイト ) 。そして、 DF フラグがクリ アされている場合、 (E)SI と (E)DI は転送したバイト数 だけ加算されます。これとは逆に、セットされている場合 は減算されます。つまり、 73 行目の MOVSW 命令は、 07C0 : 0000H から 9000 : 0000H へ 2 バイト転送し、さら に SI と DI の内容を 0 から 2 に更新します。しかし、 こでしたいのは 2 バイトではなくて 512 バイトです。 そこで、 72 行目の REP 命令か登場します。 この REP 命令は、次に続く MOVS 命令を (E)CX レジスタ値の回数だけ繰り返す操作をおこないます。 CX UNIX MAGAZINE 2002.8 82 ~ 88 行目は bootsect が使用するスタックを設定す るためのコードで、レジスタの内容が以下のように更新さ れます。 DI: 3FF4H DS: 9000H SS: 9000H SP: 3FF4H 82 行目の 4000H は、 bootsect とセットアップ・ルー チンのサイズ、そしてスタック領域に十分と想定されるサ イズを足し合わせた値です。つまり、適当な直です。 こから引いている 12 という直は、フロッピードライプ のパラメータをオ内するための領域の大きさです。以 E の 関係は、図 6 のように表すことができます。 フロッピードライフのパラメータ設定 bootsect は、フロッピーからの言ムみを BIOS のサー ピスを利用しておこないます。しかし、一部の BIOS の 49

2. UNIX MAGAZINE 2002年8月号

4 し inux のプートプロセス 表 3 INT 10H , Function 03H -- ーカーソノ立置の言蒄ムみ 表 4 INT 10H , Function 13H ー一文字列の書込み AH BH 出力 CH CL DH DL 03H ページ番号 行番号の始まり 行番号の終り 行番号 ( 0 から始まる ) 列番号 ( 0 から始まる ) AH AL BH BL CX DH DL ES:BP 出力 13H 書込みモード なし 文字列かオ褓内されているアドレス 列番号 ( 0 から始まる ) 行番号 ( 0 から始まる ) 文字列の長さ 表示生 ページ番号 ビット 2 ー 7 : 予斉み ( 0 ) ビット 1 : 文字列中に属生文字を含む ビット 0 : 書込み後にカーソル移動 INT 13 を実行した結果、 CF フラグがセットされて いれば、 CL レジスタに設定したセクタ番号が大きすぎる ことを愈未しています。この場合、 CL レジスタの値を小 さくして同じ処理を繰り返します。一方、言ムみに成功し た場合は CF フラグがクリアされるので、ループを抜け ます。 以 E をまとめると、 126 ~ 139 行目のコードを実行した 結果、トラックあたりのセクタ数がラベル sect 。 rs のアド フロッピーからデータの言囚みを開始する前に、ディス メッセージ Loading の表示 レスに書き込まれることになります。 プレイに、、 Loading" の文字列を表示します。 0142 : 0143 : 0144 : 0145 : 0146 : 0149 : 0150 : 0151 : movb xorb int movw movb movw movw int $ 0X03 , % $ 0X10 $ 9 , %cx $ 0X07 , %bl $msgl , %bp $ 0X1301 , %ax $ 0X10 . byte 13 , 10 . ascii "Loading" 在位置に文字列、、 Loading" を書き出す処理をおこなうこ とになります。 ラベル msgl ( 411 行目 ) の最初にある、、 13 , 10 " は、 テと佖帚文字 (CR/LF) です。 セットアップ・ルーチンの読込み こまでの処理は、いってみれは軽く準備 ( 材巣をしてい たようなものでした。 こから、いよいよフロッピーから のデータの言囚みが始まります。 この時点で、 bootsect プログラムは、物理アドレスの 90000H から 901FFH に位置しています。 157 ~ 179 行 目のコードは、セットアップ・ルーチンをプートセクタの 直後である 90200H 以降にロードします。このとき、フ ロッピーからの言もムみをトラックごとにおこない、効率よ く ( 高速に ) 読み込むように工夫されています。 0411 : msgl : 0412 : 順番は前後しますが、ます 150 ~ 151 行目を見てくださ こでは、ディスプレイ上に文字列を表示する BIOS 機能を呼び出しています。 BIOS への入力は表 4 のように なります。しかし、 145 ~ 150 行目のあいだに DH と DL を設定せすに、その前の 142 ~ 144 行目の出力値を利用し ています。 142 ~ 144 行目のコードは、現在のカーソノ立置を得る BIOS 機能を呼び出しています。 BIOS への入力と出力を 表 3 に示します。 まとめると、 142 ~ 151 行目のコードは、カーソルの現 UNIX MAGAZINE 2002.8 0157 : 0158 : 0159 : 0161 : 0162 : 0163 : 0164 : 0165 : 0166 : 0167 : 0168 : 0169 : 0170 : 0171 : 0172 : 0173 : 0174 : 。ー movw movw movw xorb int movw next—step ・ $ 0X0001 , %ax $sread, %si %ax , %ax %dl , %dl $ 0X13 $ 0X0200 , %bx %cl , %al sectors, %CX setup—sects, # second sector %al # sector/track sread # initialize FDC movb movw subw cmpb jbe movw subw no—cyl— ca11 no—cyl_crosslng sectors , crossmg : read_track 53

3. UNIX MAGAZINE 2002年8月号

4 Linux のプートプロセス スタック領域 ドライブ・パラメータ 93FF4 94000 図 6 スタックの言聢 12 バイト デフォルト設定では、複数のセクタを一度に読み込めない ものがあるようです。たとえは、同し 10 セクタを読み込 むとしても、 1 セクタすっ 10 回読み込むのと、 10 セクタ を 1 回て読み込むのでは、そのレスポンスタイムに大きな 違いがあります。 そこで、以下の部分ではドライプのパラメータ・テープ ルを BIOS から取り出し、複数のセクタを 1 回で読み込 セットアップ・ルーチン bootsect 90200 90000 めるように、その設定を変更します。 0105 : 0106 : 0107 : 0108 : 0109 : 0110 : 0111 : 0112 : 0113 : 0114 : movw mOVW pushw ldsw movb pushw rep movsw POPW POPW %cx , %fs $ 0X78 , %bx %ds %ds %di %di $ 6 , %cl # %cx = 0 # 転送ワード数 図 7 ldsw %fs:(%bx), %si の動作 とになります。 00000 が指すアドレス FFFFF こで、 REP MOVSW 命令を実行する直前のレジス レスはシステム BIOS の領域です ) として説明します。 こでは便喃勺に FOOO:EFC7H ( このアド す。しかし、 実際は BIOS の不転頁やバージョンによって異なるようで アドレスは、、 F000 : EFC7H " であると書かれていますが、 れていることカ吩かります。このドキュメントには、その フロッピードライプのパラメータ表へのアドレスかオ褓内さ IEH に対応する位置にはハンドラのアドレスではなく、 の BIOS サービスリスト 4 を参照すると、割込みべクタ IEH に対応します。そこで、前回紹介した Browns さん 物理アドレス 0000 : 0078H のエントリは、割込みべクタ 4 バイトのエントリが並んでいるわけです。したがって、 が順番に格納されています。つまり、 1 ハンドラあたり には、割込みハンドラのセグメントとオフセット値の組 を調べる必要があります。リアルモードの割込みテープル この処理の意味を早するには、割込みテープルの内容 タの内容を石忍しましよう。 DS: F000H ES: 9000H SI: EFC7H DI: 3FF4H CX: 0006H LDSW 命令は、第 1 オペランドカ甘旨すアドレスから 2 バイトを第 2 オペランドにコピーし、さらに続く 2 バイ トを DS レジスタにコピーします ( 図 7 ) 。 前回の REP 命令を実行した結果、 CX レジスタには 0 が入っているため、 105 行目で FS レジスタにも 0 か設 定されます。よって、 108 行目の LDSW 命令は、アド レス 0000 : 0078H の 2 ノヾイトを SI レジスタにコピーし、 0000 : 007AH の 2 バイトを DS レジスタにコピーするこ 50 こまでをまとめると、 105 ~ 114 行目のコードは、 FEFC7H から始まる 12 バイトの内容を 93FF4H / 対云 送する処理をおこないます。 PUSH 命令はレジスタの内容をスタックに待避し、 POP は反対にスタックから取り出したデータをレジス タにオ褓内する命令です。 4 http://www.delorie.com/djgpp/doc/rbinter/ix/ http://www.clipx.net/ng/rbrown/index.htm UNIX MAGAZINE 2002.8

4. UNIX MAGAZINE 2002年8月号

4 図 9 セットアップ・ルーチンがセクタに配置される例 (a) CL = 17 、 AL = 10 の場合 bootsect Linux のプートプロセス 表面 セットアップ 丿レーチン という 1 つの命令て置き換えられると思うのですが、なぜ このようになっているのかは分かりません。 174 行目の read-track では、フロッヒーから読み込 む処理をおこないます。詳しくは次の項で説明しますが、 223 ~ 225 行目のデータて表される位置から、 AL レジス タに設定したセクタ数を ES:BX レジスタカ甘旨すアドレス ヘロードします。 176 行目の set-next は、 read-track で読み込んだセ クタ数を 223 ~ 225 行目のデータに加えて更新するサプ ルーチンです。これも頁で解説します。 178 行目の SUB ・命令では、 setup-sects の内容から読 み込んだセクタ数を減算して setup-sects を更新します。 このとき、 setup-sects の値が 0 であれは読込み終了で す。反対に 0 でなけれは、もう 1 回 nextstep にジャン プし、次のトラックから残りの部分を読み込みます。 トラック読込み こでメインの流れからいったん外れ、サプルーチン read-track と set-next の重川乍を解説します。 ますは read-track です。このサプルーチンはフロッピ ーからデータを読み込む処理をおこないます。サプルーチ ンの入力では、 AL レジスタに言も囚みセクタ数、 ES:BX レジスタに転送先アドレスを指定します。 シリンダ番号、セクタ番号、ヘッダ番号は 223 ~ 225 行目の領域を参照し、ドライプ番号はつねに 0 を設定し ます。 UNIX MAGAZINE 2002.8 表面 0270 : 0271 : 0272 : 0273 : 0274 : 0275 : 0276 : 0279 : 0280 : 0281 : 0282 : 0283 : 0284 : 0285 : 0286 : 0287 : 0288 : 0289 : 0290 : 0291 : 0292 : 0293 : 0294 : 0295 : 0296 : 0297 : (b) CL = 17 、 AL = 19 の場合 read—track: 丿レーチン セットアップ bootsect 裏面 pu sha pusha movw movw int popa movw movw lncw movb mOVW andw movb pushw pushw pushw pushw int addw popa ret $Oxe2e, %ax $ 7 , %bx $ 0X10 %cx %dl , %ch 2(%si) , %dx %dl , %dh $ 0X0100 , %dx %dx %cx %bx %ax $ 0X13 bad_rt $ 8 , %sp (%si) track sread # 2(%si) = head PUSHA と POPA は、すべての汎用レジスタを スタックに待避 / 復元する命令です。ちまちまと何回も PUSH や POP 命令を実行しなくても、一気に処理して くれるイ甦リな命令です。 273 ~ 275 行目のコードは、現在のカーソル位置に ( ドット文字 :ASCII の (E) を表示します俵 6 ) 。 55

5. UNIX MAGAZINE 2002年8月号

4 し inux のプートプロセス 図 5 bootsect の動 ( 要 bootsect が 07C00H に読み込まれる ① 送することを繰り返します。この処理の様子を図 5 に示し %ax , %es %si, %si %di , %di ⑤ 100000H 以降に転送する 07C00 bootsect 100000 メモリホール 10000 90000 転送 100000 ② 90000H に転送する 90000 移動 bootsect ⑥さらに 64KB のデータを読み込む 100000 10000 90000 カーネル 100000 セットアップ・ルーチンを 90200H にロードする 3 ⑦さらに転送する。以降、⑥と⑦を繰り返す 90000 setu p 100000 10000 90000 転送 100000 0 続く 64KB のテータを読み込む 10000 90000 カーネル 100000 以下では、 bootsect がフロッピーからカーネルを読み bootsect BIOS は POST (Power On Self Test : 電源投入時 順を説明します。 込み、セットアップ・ルーチンを起動するところまでの手 タ ( 512 バイト ) を物理アドレスの 07C00H にロードし 自己奓断テスト ) カ絲冬ると、フロッピーから最初の 1 セク bootsect の動イ乍の概要 ます。ここから bootsect の実行か始まります。 64KB ずつ読み込み、順次 100000H 以降のアドレスに転 して、その後に続く展開ルーチンと圧縮されたカーネルを ルーチンを直後のアドレス ( 90200H ) にロードします。そ 自分自身を 90000H にします。次に、セットアップ・ 物理アドレス 07C00H にロードされた bootsect は、 48 ます。 自分自身を 90000H へ移動する bootsect は最初に、自分自身を 07C00H から 90000H へ移動する処理をおこないます。 bootsect のプログラム は、 BIOS によって 07C00H から 07DFFH の範囲に 読み込まれています。この 512 バイトのデータを REP と MOVSW 命令を使って転送し、転送先のプログラム にジャンプします。 0035 : BOOTSEG INITSEG start: movw movw movw mOVW movw subw subw cld rep 0060 : 0036 : 0072 : 0071 : 0070 : 0069 : 0068 : 0067 : 0066 : 0065 : 0064 : 0X07C0 = DEF_INITSEG $BOOTSEG , %ax , %ds $INITSEG, %ax % ax $ 256 , %cx UNIX MAGAZINE 2002.8

6. UNIX MAGAZINE 2002年8月号

4 inux のプートプロセス うか。 bootsect. S に書いておけば、こんなにややこしい 譴囚みバイト数を計算します。データの転送先ポインタで LCALL 命令など使わすにすむはずです。しかし、 boot- ある BX にその値を加え、 258 ~ 260 行目てオ徹が発生 sect. S には書けない理由があるのです。 するかを確かめます。もし、益れが生した場合は、 262 ~ 264 行目でオ徹益れカ起きない最大セクタ数を求めます。 その答は単純で、プートセクタの 512 バイトに収まら 結 : 軆に、 253 ~ 264 行目を実行すると、言もムみセクタ ないからです。そこで、 bootsect-helper だけを setup. S 数が AL レジスタにオ褓内されます。そして、サプルーチン に追い出したのだと思われます。以下は、 setup. S から抜 read-track と set-next か呼び出されて、フロッピーか き出したコードです。 らの言囚みと言も囚みイ立置データの更辛励ゞおこなわれます。 その後 JMP 命令でふたたび 239 行目に戻り、サプ 0091 : type-of-loader : ルーチン bootsect-kludge か呼び出されます。このサプ 0821 : bootsect—helper : ルーチンは彳おしますが、とりあえす、 231 ~ 268 行目の $ 0 , %cs :bootsect—es 0822 : cmpw コードは、カーネルの本を読み終るまで、フロッピーか bootsect—second 0823 : 0824 : ら 1 トラックすっ繰り返し転送する処理をおこなうのだと $ 0X20 , %cs :type—of—loader 0825 : movb 理解してください。 %es, %ax 0826 : movw 0827 : Shrw フロック転送 %ah, %cs :bootsect—src—base + 2 0828 : %es , %ax 0829 : movw サプルーチンの read-it から呼び出された bootsect- %ax, %cs :bootsect—es 0830 : movw $SYSSEG , %ax kludge は、 64KB のプロックを IMB 以上のエリアに転 0831 : subw 1ret 0832 : 送する処理をおこないます ( 図 5 ー 5 ) 。 0833 : 238 行目で設疋している 0X220 ' は、アドレスのオフ bootsect_second: 0834 : %cx 0835 : pushw セット値を指しています。この部分のコードを実行する時 %si pushw 0836 : 点では、すでに 9000 : 200H 以降にセットアップ・ルーチ %bx 0837 : pushw %bx , %bx 0838 : testw ンがロードされています。したがって、 220H とは、セッ bootsect—ex 0839 : j ne トアップ・ルーチンの地頁から 20H バイト目を表し、そ 0840 : $ 0X8000 , %cx のアドレスには setup. S の 133 行目で次のようなデータ 0841 : movw %cs 0842 : pushw が定義されています。 %es 0843 : POPW $bootsect—gdt , %si 0844 : mOVW 0132 : bootsect—kludge : $ 0X8700 , %ax 0845 : movw . word bootsect—helper , SETUPSEG 0133 : $ 0X15 0846 : int bootsect—panic 0847 : この SETUPSEG は、コンノヾイル時に、、 0X9020 " に J c 0848 : 展開されます。 :bootsect—es , %es %cs 0849 : movw %cs :bootsect—dst—base 十 2 0850 ; incb 239 行目の LCALL 命令はオフセット・アドレス 220H 0851 : bootsect_ を呼び出すのではなく、 220H に書かれているアドレスを %cs : bootsect—dst—base 十 2 , 0852 : 呼び出します。つまり、セグメント 9020H のオフセット $ 4 , % 曲 0853 : shlb 0854 : bootsecthlper を呼び出すことになります。 %al , %al 0855 : bootsect-helper のゴードも setup. S に書かれてい %bx 0856 : %si 0857 : ます。なお、 bootsect-helper はセットアップ・ルーチ %cx 0858 : ン内から呼び出されることはありません。このサプルー 0859 : チンは、 bootsect から利用されるためのサプルーチンで す。それでは、なぜ bootsect のためのサプルーチンが bootsect. S ではなく、 setup. S に含まれているのでしょ . byte 0 xorb POPW POPW POPW 1ret 0 0 0 0 0 0 0 0 tn 0 0 0 0 1 2 っ ) 6 6 6 8 8 8 0 0 0 58 UNIX MAGAZINE 2002.8

7. UNIX MAGAZINE 2002年8月号

カーネルの読込み いよいよ大詰め、カーネルを読み込む処理が始まりま す。 0038 : 0181 : 0182 : 0183 : 0184 : 0185 : 0367 : 0368 : 0369 : 0370 : 0371 : 0372 : 0397 : 0399 : 0400 : 0401 : 0407 : 4 ロ nux のプートプロセス %ax , %cx $ 9 , %cx $ 9 , %ax # CR # LF SYSSEG pushw POPW call ca11 call pr int —nl : movw int movb int ret = DEF_SYSSEG $SYSSEG %es read_it kill_motor print—nl $Oxe0d, %ax $ 0X10 $Oxa, %al $ 0X10 0255 : 0256 : 0257 : 0258 : 0260 : 0262 : 0263 : 0264 : 0265 : 0266 : 0267 : 0268 : movw shlw addw Jnc subw shrw ok2_read : call call JIIIP 0419 : syssize: %bx, %cx read _re ad %ax , %ax %bx , %ax 0k2 0k2 ー . word SYSSIZE rp—read set_next read_track kill_motor : XO て xorb int ret %dl , %dl $ 0X13 reset FDC 38 行目の DEF-SYSSEG は、コンパイル時に 0X1000 に展開されます。よって、 182 行目で ES レジスタに 0X1000 が設定されます。このセグメントは、図 5 の 4 に 示したアドレスです。 183 行目で呼び出しているサプルーチン read-it は、 図 5 の 4 ~ 7 の処理をおこないます。 kill-motor はフロッ ピードライプのモーターを停止し俵 5 ) 、 print-nl は改 行文字を表示するサプルーチンです俵 6 ) 。 まず、 read-it から説明します。 0231 : 0232 : 0233 : 0234 : 0235 : 0236 : 0238 : 0239 : 0247 : 0248 : 0250 : 0252 : 0253 : 0254 : read_it : movw testw die: Jne XO て rp—read: $Ox0fff, die %bx , %bx %ax bootsect—kludge = 0X220 1Ca11 bootsect—kludge cmpw jbe ret okl_read: mOVW subw syssize, 0/oax okl_read sectors, %ax 232 ~ 234 行目は、 ES レジスタの内容が 4KB にアラ インメントされているかをチェックするコードです。 233 行目の TEST 命令は、 AND 命令と同し処理を おこなって EFLAGS レジスタのフラグを変化させます 行目でトラック内の未言ムみセクタ数を求め、 256 行目で 可能な最大セクタ数を算出しています。ます、 253 ~ 254 253 ~ 264 行目では、セグメント境界を越えない言もムみ イト目に書き込まれるようになっています。 ーネルファイルをまとめあげる時点で、 : 頁から 500 バ sects と同様、すべてのコンパイル処理か終ったあと、カ 上け ) か書かれています。この値は、 417 行目の setup- ネルを合わせたサイズを 16 で割った数 ( 小れ点以下、切 419 行目の syssize には、図 4 の展開ルーチンとカー で説明します。 に 0 カ弓区ってきます。 bootsect-kludge についてはあと 期化処理がおこなわれることになっていて、 AX レジスタ みの終了を判断します ( 247 行目 ) 。 1 回目の呼出しでは初 す。そして、 AX レジスタの値と syssize を上交して言も囚 ピーをおこない、その累言が AX レジスタに返ってきま 239 行目の bootsect-kludge ではデータブロックのコ のネ川月値てす。 れは 266 行目の read-track に与える ES:BX レジスタ 235 行目で BX レジスタを 0 に設定していますが、 のコードではないかと思います。 測ですが、プログラムのケアレスミスをチェックするため ため、 234 行目の無限ループに入ることはありません。推 ES レジスタの内容は 182 行目で 1000H が設定される ん。文字どおり、テストするだけなのです。 が、オペランドに指定したレジスタの内容は変化させませ UNIX MAGAZINE 2002.8 57

8. UNIX MAGAZINE 2002年8月号

4 し inux のプートプロセス 図 10 read-it の言蒲ムみ列 10000 1 回 目 2 回 目 3 回 目 4 回 目 5 回 目 18 回 目 7 回 目 8 回 目 1 FFFF ルート・ / ヾーティションを得る いよいよ bootsect もクロージングです。 すこし話を戻しましよう。 183 行目で read-it を呼び 出してカーネルをロードしたあと、フロッピードライプの モーターを停止してからの続きです。 195 ~ 214 行目のコードは、カーネルか起動したあとの ルト・パーティションのテンヾイス番号を決定する処理を おこないます。ただし、その値はカーネルをコンパイルし たときに、プートプロックの 508 バイト目 ( 423 行目 ) に 書き込まれています。よって、通常は 197 行目から 214 行目にジャンプするだけです。 行されるときの転送先のアドレスは 110000H 、 3 回目は 120000H ・・・・・・となります。 852 ~ 855 行目の処理では、転送済みのバイト数を 16 kludge の戻り値が syssize を超えるときがきます。その さらに同様の処理か繰り返さそのうちに bootsect- 1000H カ亟ってくるようになります。 ロックコピーがおこなわオ t 、それ以降は AX レジスタに になります。このとき、 bootsect-kludge で 1 回目のプ ど 64KB の読込みか完了して、 BX レジスタの内容が 0 このように、何回かループを繰り返していると、ちょう タ読み込むと、ちょうど 64KB になります ( 図 10 ) 。 6 ) 。そして、 18 セクタすっ 6 回読み込み、最後に 9 セク 目の read-track か読み込むセクタ数は 11 です ( 18 ー 1 ー ルーチンの大きさが 6 セクタだとします。このとき、 1 回 たとえは、 1 トラックが 18 セクタで、セットアッフ・ プか数回繰り返されます。 0 カ区ってきます。その後同様に 238 ~ 268 行目のルー め 839 行目から 852 行目にジャンプし、 AX レジスタに sect-kludge の呼出しでは、 BX レジスタが 0 ではないた はせいぜい数セクタだからです。そして、 2 回目の boot- ンが存在するので、 1 回目の read-track で読み込めるの ん。 1 トラック目には bootsect とセットアッフ・ルーチ では IFFFFH いつばいまで読み込まれることはありませ セクタまで読み込みます。ただし、 1 回目の read-track は期イゞおこなわれます。そして、 1 トラック目の最終 ます、 1 回目に bootsect-kludge か呼び出されたとき チンに戻りましよう。 こで、もう一度 231 ~ 268 行目の read-it サプルー す。 419 行目の syssize を説明したところで出てきたもので で割った値を計算しています。この、、 16 " という数字は、 点で、 read-it の処理カ鮗了します。 60 0195 : 0196 : 0197 : 0198 : 0199 : 0200 : 0201 : 0202 : 0203 : 0204 : 0205 : 0206 : 0207 : 0208 : 0209 : 0210 : 0211 : 0212 : 0213 : 0214 : movw Ort•J movw movw cmpw movb cmpw cmpw root—dev, %ax %ax , %ax root_defined sectors , %bx $ 0X0208 , %ax $ 15 , %bx root_defined $Ox1c, %al $ 18 , %bx root_defined $ 0X20 , %al $ 36 , %bx root_defined $ 0 , %al root_defined : movw , root_dev 0423 : root_dev : . word ROOT-DEV たとえば、私が使っているカーネルファイルの 508 ~ 509 バイト目には、以下のような値か書かれています。 # dd if=/boot/vm1inuz—2.4.17 bs=l skip=508=> count=2 ー 0d —t xl 0000000 07 03 しています。 # ls ー 1 /dev/hda7 ・略・・・て 00t disk 3 , 7 Dec 16 2001 /dev/hda7 下線を引いたところの数字が同じなのが root-dev の 意味です。皆さんのカーネルファイルも調べてみてくだ そして、ルート・パーティションは hda7 をマウント UNIX MAGAZINE 2002.8

9. UNIX MAGAZINE 2002年8月号

4 •inux のプートプロセス 表 1 フロッピードライフ・のパラメータ・テーカレ 型 説明 first specify byte BYTE bits 7 ー 4 : step rate ()h = 2ms, Eh = 4ms, Dh ー 6ms, etc. ) bits 3 ー 0 : head unload time (0Fh = 240mS ) second specify byte BYTE bits 7 ー 1 : head load time ( 01h = 4ms) 0 : non-DMA mode (always 0 ) bit Note: The DOS boot sector sets the head load time to 15ms, however , one should retry t he op eration 0 Ⅱ fail ure delay until motor turned 0 仕 ( ⅲ clock ticks) 02h BYTE bytes per sector ( 00h = 128 , 01h = 256 , 02h = 512 , 03h = 1024 ) 03h BYTE sectors per track (maximum if different for different tracks) 04h BYTE length of gap between sectors (2Ah for 5.25 ” 1Bh for 3.5 ” ) 05h BYTE data length (ignored if bytes-per-sector field nonzero) BYTE 06h gap length when formatting ( 50h for 5.25 ” 6Ch for 3.5 " ) 07h BYTE format filler byte (default F6h) 08h BYTE head settle time in milliseconds 09h BYTE motor start time in 1 / 8 seconds 0Ah BYTE (http://www.delorie ・ com/djgpp/doc/rbinter/よりキ卆 ) 図 8 新しいドライプ・パラメータ表を言聢する オフセット 00h 01h す ( 図 8 ) 。 0115 : 0116 : 0117 : $ 36 , Ox4(%di) movb mOVW %es, %fs:2(%bx) movw 115 行目で書き込んでいる 36 という数値は、 2.88MB のフロッピーのセクタ数です。なお、現在ひろく普及して いる 3.5 インチ 1.44 B のフロッピーは、 1 トラックあ たり 18 セクタです。 1.44MB のフロッピードライプカ材妾続されている計算 機に、 2.88MB 用の値を設定すると壊れるんしゃないか と心配してしまいますが、大きい数値を設定するぶんには とくに問題はないようです。反対に、実際よりも小さい数 値を設定するとパフォーマンスの問題が発生します。 トラックあたりのセクタ数を調べる 次に、 トラックあたりのセクタ数を詩ヾます。 movw $disksizes, 0/oSi 0126 : 0127 : probe—loop : 0128 : lodsb 0129 : cbtw 0130 : movw 0131 : cmpw 0132 : コ ae 0133 : 0134 : 旧パラメータ・テーブル FE FC7 新パラメータ・テーブル 93FF4 00078 9000 : 3FF4 を書き込む レジスタ DS と DI は、スタックへのイ ( 107 行目と 110 行目 ) と復元 ( 113 ~ 114 行目 ) をおこなうため、結 果的に内容の変化はありません。 以 . E の処理でコピーしたパラメータ・テープルの構造を 表 1 に示します。難しそうな設定項目が並んでいますが、 分からなくても気にする必要はありません ( しつは、私に もよく分かりません ) 。 次の処理では、パラメータ・テープルの 5 番目のエント リを 36 に変更し、修正したテープルをインストールしま # %ds : (%si) → %al # always $ 0 → %ah %ax, sectors $disksizes + 4, %si got—sectors %cx , %ax x chgw 51 UNIX MAGAZINE 2002.8

10. UNIX MAGAZINE 2002年8月号

続く 280 ~ 292 行目は、フロッピーからデータを読み 込む処理をおこないます。ここで設定しているパラメータ の意味については、さきほどの表 2 を参照してください。 286 行目の AND 命令は、 DH レジスタの値を 0 か 1 のいすれかに ( フロッピーのヘッダは 2 つなので ) 、そし て DL レジスタの値を 0 に設定するために実行されます。 288 ~ 291 行目の 4 つの PUSH 命令は、囚み工ラーが 発生したときに、サプルーチン bad-rt でエラー表示をお こなう用途のためにスタックに保存されます。工ラーが発 生しなかった場合は、 295 行目でスタックポインタを移動 させることにより、 PUSH したデータを破棄します。 以上、必要なパラメータの言を終えたあと、 292 行目 で INT 命令を実行してフロッピーからデータを読み込み ます。 271 行目ですべての汎用レジスタを待避し、最後の 296 行目でそれらをスタックから復元するので、 read-track サプルーチンを実行しても汎用レジスタの内容は刻ヒしま せん。 次の set-next は、 223 ~ 225 行目の領域に read-track で読み込んだセクタ数を加算し、さらに言ムみバイト数を BX レジスタに加える処理をおこないます。 4 し inux のプートプロセス 表 6 INT 10H , Function 0 冊 H $ 9 , %cx 一文字の書込み 0315 : 0316 : 0317 : 0318 : 0319 : 0320 : movw addb movw AH AL BH 出力 0 EH 書き込む文字のコード ページ番号 なし %es , %ax $ 0X10 , % 曲 %ax , %es %bx , %bx set_next_fin : ret 0299 : 0300 : 0301 : 0302 : 0303 : 0304 : 0305 : 0306 : 0307 : 0308 : 0309 : 0310 : 0311 : 0312 : 0313 : 0314 : 56 set_next : movw addw cmp movw incw ok4_set : ok3_set : movw shlw addw Jnc %ax , %cx sectors, ok3_set $ 0X0001 , %ax %ax, 2(%si) ok4_set 4(%si) set—next fin %cx , %bx (%si) %ax , %ax %ax, sre ad next track # change head set sread 301 行目の ADD 命令は、下記の書式で叩 2 と叩ノ を加算した結果を叩 2 に内します。 add [bwl] 0 ノ , 叩 2 よって、 301 行目では sread と読み込んだセクタ数 の合言が AX レジスタにオ褓内されます。ただし、加算し た結果が sectors を超えることはありません。なぜなら、 read-track の呼出し条件が、トラックの境界を越える読 込みをおこなわないからです。 302 行目の CMP 命令は、 sectors と AX レジスタの 内容を上交し、同値であれば EFLAGS レジスタの ZF フラグをセットします。続く 303 行目の JNE 命令は、 ZF フラグがクリアされている場合に指定されたアドレス にジャンプします。 まとめると、 301 ~ 303 行目の意味は、 read-track がト ラックの最終セクタまで読み込んだ場合は 304 行目に進 み、反対に、職冬セクタまで読み込んでいない場合は 311 行目にジャンプするという処理になります。 304 ~ 305 行目ではヘッダ番号を、 307 行目ではトラッ ク番号を更新する処理をおこないます。 305 行目で最下位 ピットを反転しているのは、フロッピーのヘッダ番号は 0 と 1 の 2 つしかないためです。 フロッピーの 1 セクタは 512 バイトです。 312 行目で 9 ビット左シフトしているのは、セクタ数に 512 を掛け て、読み込んだバイト数を算出するためです。そして、そ の結果を BX レジスタに加算します。 314 行目の JNC は、 CF フラグがクリアされていた ら、指定されたアドレスにジャンフする命令です。 315 ~ 318 行目は、 313 行目の ADD 命令によりオ徹益 れが発生し、セグメントを越えてしまった場合の処理のた めと思われますが、この部分が実行されることはないよう です。セットアップ・ルーチンが 64KB 以上の大きさに なることはありませんし、彳あする read-it サプルーチン から呼び出されるときも、セグメントを越えないようにプ ログラムされているからです。 UNIX MAGAZINE 2002.8