メモリ - みる会図書館


検索対象: UNIX MAGAZINE 2004年5月号
20件見つかりました。

1. UNIX MAGAZINE 2004年5月号

連載 /FreeBSD のブートプロセスをみる E801H からメモリサイズを得ようと試みます。 サービス E801H の入出力データの形式を表 3 に示しま す。上記のコードを実行した結果、 IKB 単位の拡張メモ リ ( 物理アドレス 100000H 以上のメモリ ) のサイズカ畯 数 extmem に格納されます。 AX レジスタの最大値が 3C00H ( = 15MB ) であること から、このサービスで取得可能なメモリサイズは、 FFFFH x 64 十 3C00H = 4 , 209 , 600KB となり、最大で約 4GB までのメモリサイズを取得するこ とができます。 サービス E801H の呼出しに失敗した場合には、 RTC の CMOS-RAM 領域から拡張メモリのサイズを取得しま す。この RTC から得られる拡張メモリのサイズも IKB 単位です。 最後に、 1 , 711 ~ 1 , 715 行目では、以上の処理で得られ た情報をもとにメモリマップを作成します。 最大メモリサイズの調整 0200 : 1 ong Maxmem = 0 ; 1717 : physmap—done : atop (physmap [physmap—idx + 1] ) ; 1736 : Maxmem 1737 : 1738 : #ifdef MAXMEM Maxmem = MAXMEM / 4 ; 1739 : 1740 : #endif なんらかの理由で OS カ吏用するメモリサイズを制限し たい場合や、 BIOS が正しいメモリサイズを返してくれな いときは、カーネルのコンパイル・オプションか環境変数 の言当定により、メモリサイズを指定することができます 1 , 736 行目では、 BIOS から得られた最終メ、リアにレ スから Maxmem を設疋しています。変数 Maxmem の 値はメモリサイズのバイト数ではなく、最終ページフレー ム番号を表します。 コンパイル・オプション MAXMEM5 を設定した場合 は、 1 , 739 行目で Maxmem 値が - ヒ書きされます。 if ((cp=getenv("hw. physmem") ) ! =NULL) { u—int64—t A110wMem , sanity ; char *ep ; 表 3 INT 15H , Function E801H ーーメモリサイス得 入力 AX E801H 出力 CF 工ラーの場合セットされる ( 成功の場合はクリア ) IM ~ 16M の領域のサイズ ( 単位 IKB) AX 16M 以 - ヒの領域のサイズ ( 単位 64KB) BX CX AX と同等 DX BX と同等 (pt—entry—t * ) vm86paddr ; 1671 : pte = for (i = basemem / 4 ; i く 160 ; 十十 ) 1672 : pte [i] ( 土くく PAGE_SHIFT) ー 1673 : PG_V ー PG_RW ー PG_U; 1674 : 1675 : 1676 : 1677 : if (physmap [ 1 ] ! = 0 ) goto physmap—done ; 前述の INT 12H の実行を省略した場合、 1 , 534 行目か ら 1 , 580 行目へジャンプするため、変数 basemem は設 定されません。 1 , 649 ~ 1 , 674 行目では、サービス E820H で得られた メモリマップから basemern を推測する処理をおこないま す。そして、その値が 640 よりも小さかった場合は、 1 , 568 ~ 1 , 578 行目と同様に、 BIOS カ吏用する管理領域をマッ プする PTE を、、読み書き可能 " に変更します。 サービス E820H からメモリマップが得られたときは、 次の E801H と RTC からメモリサイズを得る処理はおこ なわずに、 1 , 717 行目にジャンプします。 E801H と RTC からメモリサイズを得る 1682 : vmf . vmf—ax = 0XE801 ; if (vm86—intca11(0x15, &vmf) 1683 : 1684 : = vmf . vmf—cx + vmf . vmf_dx*64; e xtmem } else { 1685 : = rtcin(Ox17) + 1694 : e xtmem (rtcin(Ox18) くく 8 ) ; 1695 : 1696 : 1711 : 1712 : 1713 : 1714 : 1715 : physmap [ 0 ] physmap [ 1 ] = basemem * 1024 ; physmap—idx = 2 ; 1746 : physmap [physmap—idx] = 0X100000 ; 1747 : physmap Cphysmap—idx + 1 ] 1748 : physmap [physmap—idx] + extmem*1024 ; 1749 : サービス E820H の呼出しに失敗した場合は、サービス 5 MAXMEM は IKB 単位でメモリサイズを孑彳定します。 167 UNIX MAGAZINE 2004.5

2. UNIX MAGAZINE 2004年5月号

0 FreeBSD の フートプロセスをみる 白崎博生 getmemsize 前回は、 btext から呼び出されるⅲ it386 ( ) について 説明しました。今回は、そのⅲ it386 ( ) から呼び出される getmemsize() をとりあげます。 getmemsize getmemsize() は、 OS カ吏用できるメモリの物理アド レスを調べたり、 4MB ページフレームを用いてページテー プルを再設定する pmap-bootstrap() を呼び出します。 拡張に次ぐ拡張を繰り返してきた歴史をもつ pc 互換機 では、新旧とりまぜて何通りかの方法で本体に載っている 物理メモリを調べることができます。 getmemsize() は、 そのなかから以下の 4 つの方法を用いてメモリサイズを調 べます 1 。ただし、これら 4 つをすべて使うわけではなく、 これに失敗したら、次はこれ " という方針に沿って順番に 試していきます。 ・ BIOS INT 12H う頁から 640KB までの使用可能なメモリのサイズを調 べることができます。 BIOS が予約している領域は除外 されます。 ・ BIOS INT 15H , Function E820H 引機のメモリマップが得られます。 4GB (32bit) を 超えるメモリサイズも調べることができます。 ・ BIOS INT 15H , Function E801H 4GB までの拡張メモリ ( 物理アドレス 100000H 以上 のメモリ ) のサイズを調べることができます。 ・ RTC CMOS 63MB までの拡張メモリのサイズしか調べられない旧い 1 Linux カーネル 2.4 では、 INT 15H の Function E820H 、 Func- tion E801H 、 Function 88H を実行します。 UN 工 X MAGAZ 工 NE 2004.5 サービスです 2 ところが、 「 E820H でも先頭から 640KB までのメモリサイズは分 かるやん。最初に INT 12H を呼び出す必要はないんと ちゃうの ? 」 と不思議に思います。たとえば、 BIOS が E820H をサ ポートしていない場合は、カーネルは E801H を呼び出し ますが、 E801H では 640KB までのメモリサイズが得ら れません。そこで、 INT 12H と組み合わせて全体のメモ リを調べます。しかし、最初に INT 12H を呼び出してか ら、その次に E820H を呼び出すのは無駄なように思われ ますが、その理由は分かりませんでした。 getmemsize() は、ファイル i386/i386/machdep. c で 定義されています。 INT 12H からメモリサイスを得る 1509 : static void 1510 : 1511 1514 : 1515 : 1517 : 1520 : 1521 : 1522 : 1523 : 1524 : 1525 : 1526 : getmemsize (int first) u—illt basemem , extmem•, struct vm86frame vmf ; vm-paddr-t pa , physmap [ 16 ] ; struct bios_smap *smap ; hasbr0kenint12 = 0 ; TUNABLE_INT_FETCH ( "hw. hasbrokenint 12 " &hasbrokenint 12 ) ; bzero(&vmf , sizeof (struct vm86frame) ) ; bzero (physmap , sizeof (physmap) ) ; basemem = 0 ; 2 さらに旧い BIOS では、 15MB までのサイズしか調べられません。 163

3. UNIX MAGAZINE 2004年5月号

連載 /FreeBSD のブートプロセスをみる 表 4 physmap と phys-avail 0 メ列 (VMware Workstation 4.0.5 / メモリ 128 、価 B ) インデックス physmap phys-avail 0 1 2 3 4 07F00000 07DF0000 00000000 0009F800 00100000 003E4000 07DF0000 07F00000 00001000 0009F000 「ついでに、メモリが壊れていることも検知できるんとち 図 3 カーネル・メッセ 5 08000000 08000000 ーシ / ヾッファ ゃう ? 」 と考えてしまいそうですが、 6 00000000 00000000 物理アドレス空間 こで検査の対象になるのは ページフレームの先頭アドレスだけなので、分かるのはメ モリの有無だけです。ただし、ページフレーム内のすべて のアドレスを検査するようにコードを変更するのはそれほ と灘しくなさそうです 6 。 表 4 に、図 1 の環境での配列 physmap と phys-avail の例を示します。これらの配列では、偶数インデックスが メモリ範囲の開始アドレス、奇数インデックスが終了アド レスを表すため、分かりやすいようにそれぞれの組を二重 線で区切ってあります。 インデックス 1 の 0009F800H が 0009F000H に変更 されているのは、 4KB ページフレームの境界にアライメ ントされたためです。インデックス 2 の 003E4000H は カーネル・メッセージバッフアの割当て 1 , 816 行目の変数 first が反映された結果です。 仮想アドレス空間 msgbuf バイト 32 , 768 PTE ↑ msgbufmap ↑ 8 ページ avail_e nd 1903 : 1905 : 1906 : 1907 : 1908 : 1909 : 1910 : 1913 : 1914 : 1915 : 1916 : } while (phys—avail [pa—indx—l] + PAGE_SIZE + round_page (MSGBUF_SIZE) > = phys—avail [pa—indx] ) { physmem ー = atop (phys—avail [pa—indx] ー phys—avail [pa—indx—l] ) ; phys-avail [pa—indx——] phys-avail [pa—indx——] avail—end = phys—avail [pa—indx] ; round-page (MSGBUF—SIZE) ; phys-avail [pa-indx] Maxmem = atop (phys-avail [pa—indx] ) ; 6 ある日突然、カーネルのプートプロセスカ隧中でパニックするようになった り、ユーザープロセスが頻繁に謎の異常終了を繰り返すようになった場合、 原因としてメモリバスのどこカ功ゞ切れたことを疑ってみるとよいでしよう。 memtest86 というツールを使えば、メモリカ哥れているか調べることカで きます。そして、壊れたページフレームをカーネルカ駛わないように 1 , 831 ~ 1 , 855 行目のコードを書き換えれば、カーネルがふたたひ元気に動き始め るかもしれません。場合によっては、酉改リ phys-avail のサイズも調整が 必要です。 なお、 Linux カーネルには BadMEM というパッチがあり、壊れたペー ジフレームを空きメモリのリストから除くことカきます。 170 FreeBSD カーネルは、メモリマップの最後から連続す るべージフレームをメッセージバッファ用に割り当てます ( 図 3 ) 。 最後のメモリプロックから必要なページフレーム数カ 保できなかったときは、そのプロックを、、なかったこと " に して ( 1903 ~ 1 , 908 行目 ) 、その 1 つ前のプロックからメ ッセージバッファ用の領域を割り当てます。しかし、その 1 つ前のプロックに十分な大きさがあるかどうかまではチェ ックしません。おそらく、図 1 にあるように、メモリマップ の最後のタイプ 1 ( 表 2 参照 ) の使用可能領域が、、飛び地 " になっていることを考慮しているのでしよう (7EF0000H から 7F00000H のあたり ) 。 BIOS の種類や PC の構成 によっては、最後の使用可能領域がかなり小さくなること があるのかもしれません。 ところで、せつかくのメモリを捨ててしまうのはもった いない気がしますが、 MSGBUF-SIZE はコンパイル時に 32 , 768 に置き換えられるので、 1 , 903 行目でチェックして いるサイズは 36KB ( 9 ページ ) です。いまどきの PC で は、 36KB くらいなくなっても、、誤差 " 程度でしよう。と はいっても、なんとなくもったいない気もします。 このように、連続するべージフレームが割り当てられな かった場合にメモリを捨ててしまうのは、コードカ礬隹に なってしまうからだそうです ( ソースコード中のコメント より ) 。 1 , 913 ~ 1 , 915 行目では、実際にメッセージバッファ用 UNIX MAGAZINE 2004.5

4. UNIX MAGAZINE 2004年5月号

SMAP SMAP SMAP 1639 : 1640 : 1641 : 1642 : 1643 : 1644 : 1608 : 1609 : 1610 : 1611 : 1614 : 1615 : 1616 : 1617 : 1618 : 1621 : 1622 : 1623 : 1624 : 1626 : 1627 : 1628 : 1629 : 1630 : 1631 : 1632 : 1633 : 1634 : 1635 : 1636 : 1637 : 連載 /FreeBSD のブートプロセスをみる SMAP type SMAP type SMAP type SMAP type SMAP type SMAP type SMAP type SMAP type 図 1 カーネルか表示する刊 820H から得たメモリマッフでメ列 (VMware Workstation 4.0.5 / メモリ 128 、 IB ) type type type = 01 = 02 = 02 = 02 = 01 = 03 = 04 = 01 = 02 = 02 = 02 base base base base base base base base base base base = 0000000000000000 le Ⅱ = 000000000009f800 = 000000000009f800 len = 0000000000000800 = 00000000000dC000 len = 0000000000004000 = 00000000000e4000 len = 000000000001C000 = 0000000000100000 len = 0000000007df0000 = 0000000007ef0000 len = 000000000000C000 = 0000000007efC000 le Ⅱ = 0000000000004000 = 0000000007f00000 le Ⅱ = 0000000000100000 = 00000000feC00000 le Ⅱ = 0000000000010000 = 00000000fee00000 len = 0000000000001000 = 00000000fffe0000 le Ⅱ = 0000000000020000 goto next—run ; if (smap—>base > = goto next—run ; if (smap—>length 0xffffffff) printf ( "%uK of memory above ignored\n" 4GB (u—int) (smap—>length / 1024 ) ) ; goto next—run; for (i=O; i く = physmap—idx; i + = 2 ) { if (smap—>base く physmap Ci + 1 ] ) { region, ignoring second region\n") ; or non—montonic memory printf ( if (boothowto & RB-VERBOSE) goto next—run ; smap—>length ; physmap [physmap—idx + 1 ] + = physmap [physmap—idx + 1 ] ) { if (smap—>base goto next—run ; physmap—idx + = 2 ; break; address map , giving up\n" ) ; " T00 many segments in the physical printf ( if (physmap—idx = = PHYSMAP—SIZE) } while (vmf . vmf—ebx ! = 0 ) ; ne Xt _run : smap—>base + smap—>length ; physmap [physmap—idx + 1 ] physmap [physmap—idx] = smap—>base ; BIOS サービス INT 15H Function E820H ( 以下、 、、サービス E820H " と表記します ) は、メモリのサイズだ けでなく、 の領域は BIOS カ駛うんやから使うたらあ UNIX MAGAZINE 2004.5 かん " というアドレスも教えてくれる便利なサービスです。 この情報が得られれば、 OS は正確にその領域を除いてメ モリを利用することができます。ただし、これは比較的新 しいサービスなので、ひと昔前の PC の BIOS には実装 されていません。 サービス E820H からメモリマップが得られる場合、 FreeBSD カーネルのプートオプションとして—v を指定 すると、プート時に図 1 のようなメッセージが表示されま す。この図の例は、 VMware Workstation 4.0.5 ( メモ リ 128MB ) にインストールした FreeBSD で表示された ものです。 128MB を 16 進数で表すと 8000000H なの で、メモリサイズが正しく得られていることが分かります。 ただし、最後の 4GB 付近の予約領域工ントリカ舸を表し ているのかは分かりません。 最近のサーバー用 PC ( とくにデータベース・サーバー など ) では、 4GB 以上のメモリカっていることも珍しく ありません。そして、サービス E820H も 4GB を超える メモリを調べることができます。 ところが、 32bit のアドレスパスで表現できる最大のア ドレスは 4GB なので、そのままでは 4GB 以上のメモリ にアクセスするのは不可能です。そこで、 Pentium では PAE (PhysicaI Address Extension) という機構を用意 し、これを使って 4GB 以上のメモリにアクセスするよう になっています。 FreeBSD 5.1 は PAE に対応している ので、カーネルのコンパイル時に PAE オプションを有 (i) 」 にすれば 4GB 以 - ヒのメモリも扱えます 4 。 一方、サービス E820H が実装されていない (BIOS が 旧い ) PC では呼出しに失敗します。この場合は、次に進 んで INT 15H , Function E801H の実行を試みます。 4 私自身はこの物老を使ったことがないので、動くかどうかは知りません。 165

5. UNIX MAGAZINE 2004年5月号

1750 : 1751 : 1752 : 1753 : 1754 : 1755 : 1756 : 1757 : 1758 : 1759 : 1760 : 1761 : 1762 : 1763 : 1764 : 1765 : 1766 : 1767 : 1768 : 1769 : 1770 : 1771 : 1772 : 1773 : 1774 : 1775 : 1776 : 1777 : 1778 : 1784 : 1785 : 連載 /FreeBSD のブートプロセスをみる sanity=A110wMem=strtouq(cp, &ep , switch(*ep) { default : break ; A110wMem くく = A110wMem くく = 10 ; case ) M : case A110wMem case ) G : の ; くく = 10 ; 10 ; タ領域を仮想アドレス空間に割り当てたり、ページテープ ルの内容を変更する処理をおこないます。以降のコードは pmap-bootstrap() の結果を利用するため、順番は前後し ますが、あとで説明する pmap-bootstrap() をさきに読 むことをお勧めします。 ページフレームのアクセステスト 0202 : 1793 : 1794 : 1795 : 1796 : 1797 : vm—paddr—t phys-avail [ 10 ] ; physmap [ 0 ] = PAGE-SIZE; / / 1 ページ目は A110wMem = sanity = 0 ; = 0 ) if (A110wMem A110wMem = 0 ; if (A110wMem く sanity) freeenv(cp) ; Maxmem = atop (A110wMem) ; else size of '%s'\n", (p) ; printf ( " lgnoring invalid memory ptoa( (vm-paddr-t) Maxmem) ; physmap [physmap—idx + 1 ] Maxmem ) if (atop (physmap [physmap—idx + 1 ] ) く %1dK\n" , Maxmem * 4 ) ; printf ("PhysicaI memory use set t0 Maxmem & & ( bootho t0 & RB—VERBOSE) ) if (atop (physmap [physmap-idx + 1 ] ) ! = pa—indx = 0 ; / / 対象から外す 環境変数 hw. physmem カ第乂疋されていると、その文字 列を数値に変換して Mexmem に上書きします。 そして、 1 , 784 ~ 1 , 785 行目では、 Maxmem が BIOS から得たメモリサイズよりも大きい場合は、 physmap の最 後のエントリを書き換えます。反対に、 Maxmem のほう が小さい場合は、あとで出てくる 1 , 809 行目の条件文 (pa く end) で処理されます。 ところで、「本当は 256MB しかあらへんのに、、、 512MB あるで " ってウソの言定を書いたらどうなるんやろ」と考え た人もいるでしよう。しかし、あとでメモリのアクセステ ストがおこなわれるため、残念ながら ( ? ) カーネルはウソ phys—avail [pa—indx + + ] = physmap [ 0 ] ; phys—avail [pa—indx] = physmap [ 0 ] ; pte = CMAPI ; こまでの処理で、 BIOS のサービスやコンパイル・オ ままでは空き領域として使えません。 が、 physmap のメモリマップは以下の理由により、その モリマップカ己列 physmap に絲されています。ところ プション、環境変数から得られた情報を用いて作成したメ そこで、以降では physmap のメモリマップから、、使え る。 ・カーネルのテキストやデータセグメントが含まれてい ない。 実際のメモリよりも大きな値が設定されているかもしれ ・ページフレーム境界にアライメントされていない。 いきましよう。 次の for ループはすこし長くなりますが、一気に読んで ドの割込みハンドラテープルがあるためです。 ジ目を対象から除外しています。この領域にはリアルモー 1 , 793 ~ 1 , 796 行目では、 00000H ~ OOFFFH の 1 ペー ます ( 図 2 ) 。 対して読み書きテストをおこなってメモリの存在を確認し 理ページフレームを順番にマッピングし、そのアドレスに ここ以降の処理では、 CMAPI が指す仮想アドレスに物 プ " を配列 phys-avail に作成します。 ない部分 " を除外し、カーネルが使える、、空きメモリマッ の設定に騙されたりはしません。 ページテーブルの再言又疋 pmap—bootstrap(first , 0 ) ; 1788 : 1 788 行目の pmap-bootstrap() は、 168 1803 : 1804 : 1805 : 1806 : 1807 : 1808 : いくつかのデー f0 て (i=O; i く =physmap-idx; 土 + = 2 ) { vm—paddr—t end ; end = ptoa( (vm—paddr—t) Maxmem) ; if (physmap[i + 1 ] く end) end = trunc—page (physmap Ci + 1 ] ) ; UNIX MAGAZINE 2004.5

6. UNIX MAGAZINE 2004年5月号

連載 /FreeBSD のブートプロセスをみる 表 2 INT 15H , Function E820H ーーメモリマッフ陬得 入力 EAX EDX EBX ECX ES:DI 出力 CF EAX ES:DI ECX EBX 0000E820H 534D4150H ('SMAP') 前回の EBX ( 初回の場合は 0 ) 20 工ントリバッフアのアドレス 工ラーの場合にセットされる ( 成功の場合はクリア ) 534D4150H ( 、 SMAP') マッフ。工ントリ バッフアへ書き込んだバイト数 続くエントリがある場合は 0 以外のイ直 工ントリのに 4 バイト 4 バイト 4 バイト 4 バイト 4 バイト べースアドレスの下位 32bit べースアドレスの上位 32bit 領域の長さの下位 32bit 領域の長さの上位 32bit 領域のタイプ 1 : 使用可能なメモリ 2 : 予約領域 3 : ACPI 用メモリ 4 : ACPI NVS * 用メモリ ページフレームにアクセスすることになります。 1 , 592 行 目の vmf-es と vmf-di は、それぞれ 0100H と 0000H が十内されます。 1 , 585 行目の pmap-kenter() は、 sm 叩カ甘旨すイ反想アド レス領域を読み書きできるように PTE を定しますが、以 降のコードで smap に何かを書き込むことはありません。 こで pmap-kenter() を実行する未はないと よって、 思われます。 1 , 600 行目の vm86-datacall() は、表 2 のサービスを 呼び出します。 1 , 607 ~ 1 , 628 行目では、エントリ内容の整合「生をチェッ クしています。 1 , 630 ~ 1 , 633 行目は、連続するメモリ領域が 2 つの工 ントリに分割されて返された場合に、それらのエントリを 1 つにまとめる処理です。ただし、 1 回目の smap の base にはかならず 0 が格納されているので ( 物理メモリのアド レスは 0 から始まるからです ) 、 1 , 630 行目の条件式が成立 して 1 , 631 行目が実行されます。 1 , 641 ~ 1 , 642 行目では、メモリマップの先頭アドレス と終了アドレスを配列 physmap に設疋しています。 以上のコードの内容はとくに難しくはありませんが、 図 1 と見くらべながら読むと、さらに具体的なイメージが っかみやすくなるでしよう。このときの physmap の結果 は、後述の表 4 に示します。 * NVS : Non Volatile Sleeping memory 1 , 580 ~ 1 , 644 行目では、 CPU を一時的に仮想 8086 モードに移行してサービス E820H ( 表 2 ) を実行し、メモ リマップを配列 physmap ( 1 , 517 行目で亘言しています ) に定します。 イ反想 8086 モードでは、リアルモードと同様にセグメン ト機構カ働きますが、ページング機構はプロテクトモード のまま動いています。そして、サービス E820H は、レジ スタ ES:DI で指定された領域に戻り値 ( マップエントリ ) を書き込みます。このため、サービス E820H を実行する には、どこかに、、読み書き可能 " なページフレームが必要に なります。 1 , 590 ~ 1 , 592 行目は、 1 , 600 行目の vm86-datacall() が CPU を仮想 8086 モードに移行したときに、 01000H から OIFFFH までのページフレーム ( ページ番号 1 ) を読 み書きできるように (f 反想 8086 モード用の ) PTE を定 する準備を整えます。 1 , 591 行目のポインタ変数 smap は、仮想アドレス C0001000H を指しますが、ページング機構により物理ア ドレス 00001000H に変換され、上記のページ番号 1 の 166 1649 : 1650 : 1651 : 1652 : 1653 : 1654 : 1655 : 1656 : 1657 : 1658 : 1659 : 1660 : 1661 : 1662 : 1663 : 1664 : 1665 : 1666 : 1667 : 1668 : 1669 : 1670 : if (basemem for (i=O; i く = physmap-idx; i + = 2 ) { if (physmap [i] 0X00000000 ) { basemem = physmap[i + 1 ] / 1024 ; break ; if (basemem basemem = 640 ; if (basemem > 640 ) { printf ( "Preposterous BIOS basemem of %uK , truncating tO 640K \ Ⅱ " basemem) ; basemem = 640 ; for ()a = trunc—page (basemem*1024) ; pa く 0Xa0000 ; pa + = PAGE—SIZE) pmap—kenter (KERNBASE + pa' (a) ; UNIX MAGAZINE 2004.5

7. UNIX MAGAZINE 2004年5月号

連載 /FreeBSD のブートプロセスをみる 表 1 INT 12H ーーメモリサイス取得 入力 AH 出力 AX 1533 : 1534 : 1535 : 12H goto int15e820 ; if (hasbr0kenint12) { BIOS が予約している領域は除外される 640KB 以下の領域のサイズ ( 単位 KB) getmemsize() は、最初に BIOS のサービス INT 12H を呼び出し、先頭から 640KB までの使用可能なメモリの サイズを調べます。ところが、 BIOS の種類やバージョン によっては INT 12H をサポートしていないものがあるら しく、これを呼び出すとカーネルがパニックしてしまうよ うです。 FreeBSD では、この問題への対策として環境変 数 hw. hasbrokenint12 が用意されています。この変数に 0 以外の値カ殳定されていると、 INT 12H の呼出しを省 略して次の BIOS INT 15H , Function E820H の処理 へジャンプします。 PC 互換機のなかには、 AOOOOH のちょっと下位の領 E820H からメモリサイズを得る のページフレーム番号を表しています。 1 , 577 行目の、、 160 " は、メモリホールが始まる A0000H フする PTE を作成 ( または上書き ) します。 レスを第 2 引数の物理アドレスに、、読み書き可能 " でマッ 1 , 570 行目の pmap-kenter() は、第 1 引数のイ反想アド です。 レスを含むべージフレームの先頭アドレスを求めるマクロ 1 , 568 行目の trunc-page() は、引数で与えられたアド レスは、、言囚み専用 " に設疋されています。 ate-pagetables 」の項で述べたように、もともとこのアド フラグを、、読み書き可能 " に変更します。 3 月号の「 cre- の領域に対する PTE (Page TabIe Entry) の制御 管理領域が存在する場合は、 1 , 568 ~ 1 , 578 行目でそ になりました 3 。 理領域として予約されているため、 basemem の値は 638 ThinkPad T40 では、 9F800H から 9FFFFH までが管 し小さい値になります。たとえば、私が使っている IBM そのような PC では basemem の値は 640 よりもすこ 域をハードウェア管理領域として予約しているものがあり、 1540 : 1541 : 1542 : 1543 : 1544 : 1545 : 1546 : 1568 : 1569 : 1570 : 1576 : 1577 : 1578 : vm86—intca11(Ox12, &vmf) ; bas emem = vmf . vmf ー・ if (basemem > 640 ) { printf ( "Preposterous BIOS basemem of %uK , truncating to 640K \ Ⅱ” basemem) ; basemem = 640 ; for ()a = trunc—page (basemem * 1024 ) ; pa く 0Xa0000 ; pa + = PAGE-SIZE) pmap—kenter (KERNBASE + pa, (a) ; (pt—entry—t *)vm86paddr ; pte for (i = basemem / 4 ; i く 160 ; i + + ) pte Ci] = (i くく PAGE—SHIFT) ー PG_V ー PG_RW ー PG_U; 1 , 540 行目の vm86-intcaII() は CPU を一時的に反想 8086 モードに移行し、表 1 のサービスを呼び出します。そ の結果は、 vmf. vmf-ax から得られます ( 1 , 541 行目 ) 。 そもそも、メモリが 640KB 未満の PC では FreeBSD のカーネルのロードすらできないので、 「 basemem はかならず 640 になるんとちゃうの ? 」 と思うかもしれません。たしかに一見すると不思議です が、 OS は 00000H から 9FFFFH の物理アドレス空間を すべて使えるわけではないのです。 164 1580 : 1585 : 1590 : 1591 : 1592 : 1593 : 1594 : 1595 : 1596 : 1597 : 1598 : 1599 : 1600 : 1601 : 1602 : 1603 : 1604 : 1605 : 1606 : 1607 : int 15e820 : pmap-kenter (KERNBASE + 4096 , 4096 ) ; vmc ・ npages = 0 ; smap = (void * ) vm86-addpage(&vmc, 1 , KERNBASE + 4096 ) ) ; vm86—getptr(&vmc , (vm—offset-t) smap , &vmf . vmf—es, &vmf . vmf—di) ; printf ( "SMAP type=%02x if (boothowto & RB—VERBOSE) break ; if (i Ⅱ vmf . vmf—eax ! = SMAP—SIG) i = vm86-dataca11(Ox15, &vmf , vmf . vmf_ecx = 20 ; vmf . vmf—edx = 0X534D4150 ; / / vmf . vmf_eax = 0XE820 ; do { vmf . vmf—ebx = 0 ; physmap—idx = 0 ; &vmc) ; "SMAP" if (smap—>type ! = 0X01 ) smap—>length) ; smap—>type , smap¯>base , base=%01611x le Ⅱ = % 01611X \ Ⅱ " 3 638 x 1 , 024 = 653 , 312 = 9F800H UN 工 X MAGAZINE 2004.5

8. UNIX MAGAZINE 2004年5月号

5 EMC にみるストレージ市場の動向 getmemsize—メモリサイズの取得 FreeBSD のプートプロセスをみる OSPF のエリア内経路計算 ー P ルーティング , SFU の導入と NFS の設定 Services fo ′ UNIX usbd と ine 記にみる rc スクリプトの特徴 プログラミング・テクニック 学内ネットワークの更新と整備 ー新・自敷芸術科学大学のネットワーク構築 Wiki を情報共有に活用する UNIX Communication Notes 、ティレクトリ内容のミラー FiIe::SyncNM0d 、 pe 市用のント

9. UNIX MAGAZINE 2004年5月号

図 2 里メモリのアクセステスト 仮想アドレス空間 CMAPI C0000000 連載 /FreeBSD のブートプロセスをみる PG_RW PG_N ; 物理アドレス空間 00800000 007F0000 00101000 00100000 0009 F000 00002000 00001000 00000000 1847 : 1848 : 1852 : 1853 : 1854 : 1855 : 1856 : 1858 : 1859 : 1864 : 1865 : 1866 : 1878 : 1879 : 1880 : 1881 : 1882 : 1883 : 1884 : 1885 : 1886 : 1887 : 1895 : 1894 : 1893 : 1892 : 1891 : 1890 : 1889 : 1888 : page-bad = TRUE ; *(volatile int *)ptr = 0X0 ; if (*(volatile int *)ptr ! = 0X0 ) { page—bad = TRUE ; / / 元のデータを戻す *(int *)ptr = tmp; if (page—bad = TRUE) { continue ; " T00 many 五 oles in the physical printf ( if (pa—indx pa—indx 十十 ; } else { phys—avail [pa—indx] + =PAGE—SIZE; if (phys—avail Cpa-indx] phy smem + + ; pa + PAGE-SIZE ; phys—avail [pa—indx] phys—avail [pa—indx + + ] break ; pa—indx— address space, giving up\n") ; 00000000 1809 : 1810 : 1811 : 1815 : 1816 : 1817 : 1818 : 1819 : 1823 : 1824 : 1825 : 1826 : 1827 : 1831 : 1832 : 1833 : 1834 : 1838 : 1839 : 1840 : 1841 : 1845 : 1846 : for ()a = round—page (physmap [i] ) ; pa く end ; pa + = PAGE—S 工 (E) { int *ptr (int * ) CADDRI ; int tmp , page—bad ; / / カーネル領域は飛ばす *pte invltlb ( ) ; / / マッピングを外す if ()a > = 0X100000 continue ; page—bad = FALSE ; / / ページをマッピング *pte = pa ー PG—V ー invltlb ( ) ; / / 元のデータを保存 tmp = *(int *)ptr; pa く first) *(volatile int *)ptr = 0xaaaaaaaa; if (*(volatile int *)ptr ! = Oxaaaaaaaa ) { page—bad = TRUE; * (volatile int *)ptr = 0X55555555 ; if (*(volatile int *)ptr ! = 0X55555555 ) { page-bad = TRUE ・ *(volatile int *)ptr = 0xffffffff ; if (*(volatile int *)ptr ! = Oxffffffff) { UNIX MAGAZINE 2004.5 1 , 803 行目の for 文は、 physmap のメモリマップを 1 プロックごとに処理し、そして、 1 , 809 行目の for 文は、 1 つのプロックのなかを 1 ページフレームずっループ処理し ます。 1 , 816 行目は、変数 pa カ甘旨す物理ページフレームがカー ネルの領域に含まれるかをチェックします。 3 月号で説明 したように、カーネルは物理アドレス 00100000H 以降に ロードされ、データ領域の最終アドレスは、 btext から渡 された引数 first に十内されています。 1 , 824 行目は、 ptr が指す仮想アドレスに変数 pa の物 理ページフレームをマッピングし、 1 , 825 行目の inv 旧 b ( ) で TLB (Translation Lookaside Buffer) をフラッシュ します。 続く 1 , 831 ~ 1 , 855 行目では、ページフレームのう頁ア ドレスにデータを読み書きし、そのアドレスにメモリカ 在するかどうかを検査しています。それならば、 169

10. UNIX MAGAZINE 2004年5月号

アプリケーションを一気に再インストールできる、忘れや すいのは Web プラウザの、、お気に入り " などを外部に保 存しておくことである、 PC をイ夏するだけでなく、ユー ザーである子どもへの教育をしつかりおこない、スキルア ップにつなげられるようにする必要がある、といったフォ ローがきました。 Newsgroups: 斤0S. ms-windows. xp,fj. sys. ibmpc Subject: ご受ください Subject: Video Encode 題未でホームビデオの編集をしているのですが、現在使 っている Pentium III (600MHz) のマシンではエンコ ードにかなり時間がかかったりコマ落ちしたりします。新 しいマシンを買おうと思うのですが、 xeon (3.6GHz) と Pentium 4 ( 3.6GHz ) 、ノート PC 用の Pentium M (1.7GHz) ではどれが処理能力カ皜くて安定しているので しようか、という質問記事です。 これに対して、ノート PC とデスクトップ PC ではかな り差がある、 Xeon と Pentium 4 の差は xeon をマルチ プロセッサ構成にしないかぎりあまり大きくないのではな いか、 Xeon はサーバー用 CPU 、 Pentium 4 は一殳向け CPU である、マルチプロセッサ対応の関係もあって Xeon のべースクロック数は 533MHz 止まりだが、 Pentium 4 は 800MHz まである、 Pent ⅲ mM はクロック数あたりの 性能では Xeon や Pentium 4 を上回る、 Pentium M と Xeon/Pentium 4 では CPU の構造がまるで違う、処理 速度はべースクロック数のほかにもキャッシュサイズで変 わる、さらに Northwood や Prescott といった CPU の 製造プロセスでも異なる、 Xeon のマルチプロセッサ構成に すれば工ンコード速度は倍になる、実際にはメモリや HD の読み書き速度がネックとなり単純に倍にはならない、ビ デオ編集にはキャッシュサイズはあまり影響しないという 話もある、ビデオのエンコード速度はソフトウェアによっ ても異なる、ビデオ編集の場合は CPU の性能より HD の 読み書き速度のほうが大きく景彡響するのではないか、ビデ オ編集には大容量の HD が必要になると思うが、ノート PC は 2.5 ⅲ ch HD に大容量の製品がないので現実的な選 択肢ではないだろう、現状の 600MHz CPU でぎりぎり 処理できるのなら 1.2GHz クラスの CPU で十分に処理 できる、処理性能はメモリの容量にも依存するのではない か、現在は 4GB クラスのメモリ容量は贅沢だが、来年に 154 は当り前になっているかもしれない、 きました。 Newsgroups: . SYS. mac. OS-X といったフォローが Subject: copy & paste between X11 and MacOSX Mac OS X 10.3 を使い始めたのですが、付属の X11 を使うとコピー & ペーストができないことに気づきました。 これまで使っていた Mac OS X 10.2 と XDarwin では 問題ありませんでした。なお、ウインドウ・マネージャー は twm を使っています。皆さんも同じ状況なのでしよう か、という質問記事です。 これに対して、 twm を使ったのカ源因だろう、オリジ ナルのウインドウ・マネージャーである quartz-wm の オンライン・マニュアルを参照してみるとよい、ほかの ウインドウ・マネージャーを使うときは、 quartz-wm に -only-proxy" オプションを付けて起動する必要があ る、 10.2 でもそれほどうまくいっているわけではない、こ れは OS というよりは Apple の X サーバーの問題で、付 属の X サーバーではなく XDarwin を使えばよい、日本 語文字列もペーストできるのか、 Mac OS x 側から X11 側へはできるが逆は試したことがない、といったフォロー がきました。 Newsgroups: . comp. dev. keyboard Subject: 八幡勇ーの「キーポード論」 日経 BP の「日経バイト」 3 月号に、「八幡勇ーの『キー ポード論』 ( 前編 ) 」という記事がありました。タイプライ ター以来のキーボードの歴史を俯瞰するおもしろい記事だ と思っていたら、 PFU の Happy Hacking Keyboard の開発者だったのですね。来月も読もうと思わせる記事で した、という感想記事です。 これに対して、図書館で読んでみたが、当時のタイプラ イターではタイピング速度が速くなると印字ヘッドが交差 してしまう問題があり、タイピング速度が一ヒがりすぎない ようにするため QWERTY 配列が登場したといわれてい ると書かれていて、やはり多くの人はこれを信じているの かと残念に思った、それを信じているわけではないのでは ないか、本当は印字ヘッドが隣り合う文字を続けて打っと 印字ヘッドが絡まるので、連続して打たれやすい文字は印 字ヘッドが並ばないように配列したのではなかったか、 の説も怪しいのではないか、 1870 年代の初期のタイプラ UNIX MAGAZ 工 NE 2004.5