エンタープライズ:特集 2003/01/28 09:44:00 更新

Linuxでハイパー・スレッディング――Pentium4/3.06GHzで遊ぼう
第2回 泥沼のRedHatカーネルデバッギング (5/5)

デバッギングその2:mpparse.c

 さてsmp_scan_config()自体は短いからちょっと見ていただこう。

static int __init smp_scan_config (unsigned long base, unsigned long length)
{
  unsigned long *bp = phys_to_virt(base);
  struct intel_mp_floating *mpf;

  Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
  if (sizeof(*mpf) != 16)
    printk("Error: MPF size\n");

  while (length > 0) {
    mpf = (struct intel_mp_floating *)bp;
    if ((*bp == SMP_MAGIC_IDENT) &&
      (mpf->mpf_length == 1) &&
      !mpf_checksum((unsigned char *)bp, 16) &&
      ((mpf->mpf_specification == 1)
        || (mpf->mpf_specification == 4)) ) {

      smp_found_config = 1;
      printk("found SMP MP-table at %08lx\n",
            virt_to_phys(mpf));
      reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
      if (mpf->mpf_physptr)
        reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE);
      mpf_found = mpf;
      return 1;
    }
    bp += 4;
    length -= 16;
  }
  return 0;
}

 ここで、SMP_MAGIC_IDENTというシンボルは「/usr/src/linux-2.4.20/include/asm_i386/mpspec.h」で定義されていて、

#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')

となっている。つまり「_MP_」という文字列で、smp_scan_config()は与えられたアドレスからこの文字列を探してゆき、どこかで見つかったらsmp_found_configに「1」を設定して返す、という作業を行っている。いっぽうこの関数を呼び出すのは「find_intel_smp()」という関数で、

void __init find_intel_smp (void)
{
  unsigned int address;

  /*
   * FIXME: Linux assumes you have 640K of base ram..
   * this continues the error...
   *
   * 1) Scan the bottom 1K for a signature
   * 2) Scan the top 1K of base RAM
   * 3) Scan the 64K of bios
   */
  if (smp_scan_config(0x0,0x400) ||
    smp_scan_config(639*0x400,0x400) ||
      smp_scan_config(0xF0000,0x10000))
    return;
  /*
   * If it is an SMP machine we should know now, unless the
   * configuration is in an EISA/MCA bus machine with an
   * extended bios data area.
   *
   * there is a real-mode segmented pointer pointing to the
   * 4K EBDA area at 0x40E, calculate and scan it here.
   *
   * NOTE! There are Linux loaders that will corrupt the EBDA
   * area, and as such this kind of SMP config may be less
   * trustworthy, simply because the SMP table may have been
   * stomped on during early boot. These loaders are buggy and
   * should be fixed.
   */

  address = *(unsigned short *)phys_to_virt(0x40E);
  address <<= 4;
  smp_scan_config(address, 0x1000);
  if (smp_found_config)
    printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
}

といった感じだ。ちょっと長いが、コメントを見れば判るとおり

・アドレス先頭の1Kバイト
・ベースメモリ先頭の1Kバイト
・BIOS中の64Kバイト

の3つの個所を検索し、そこに「_MP_」という文字列の入った領域が含まれているかを確認しているようだ。もっとも単に含まれているかどうかだけではなく、その文字列に続く構造体でMP Specification 1.1か1.4であることも確認しており、それらが格納されていればSMP対応とみなして、必要なデータをそこから引っ張り出すという作業をしている。

 そこで、BIOSなりメモリエリアにこうしたデータが入っていないために、smp_found_configが0のままなのではないか、というのが筆者の想像である。これを確認するために、find_intel_smp()を

  /*
* FIXME: Linux assumes you have 640K of base ram..
* this continues the error...
*
* 1) Scan the bottom 1K for a signature
* 2) Scan the top 1K of base RAM
* 3) Scan the 64K of bios
*/
if (smp_scan_config(0x0,0x400) ||
smp_scan_config(639*0x400,0x400) ||
smp_scan_config(0xF0000,0x10000))
return;
/* Add by Ohara */
printk( "Ohara_scan_config_1 : %d\n", smp_scan_config(0x0,0x400));
printk( "Ohara_scan_config_2 : %d\n", smp_scan_config(639*0x400,0x400));
printk( "Ohara_scan_config_3 : %d\n", smp_scan_config(0xF0000,0x10000));
/* End of Ohara */

てな具合に書き換えてみた上で、カーネルを再構築してみた。さて、リブート後に/var/log/messagesを見てみると

Jan 22 22:39:47 localhost kernel: BIOS-provided physical RAM map:
Jan 22 22:39:47 localhost kernel: BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 0000000000100000 - 000000003ffec000 (usable)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 000000003ffec000 - 000000003ffef000 (ACPI data)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 000000003ffef000 - 000000003ffff000 (reserved)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 000000003ffff000 - 0000000040000000 (ACPI NVS)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 00000000fec00000 - 00000000fec01000 (reserved)
Jan 22 22:39:47 localhost kernel: BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
Jan 22 22:39:47 localhost syslog: klogd startup succeeded
Jan 22 22:39:47 localhost kernel: BIOS-e820: 00000000ffff0000 - 0000000100000000 (reserved)
Jan 22 22:39:47 localhost kernel: Warning only 896MB will be used.
Jan 22 22:39:47 localhost kernel: Use a HIGHMEM enabled kernel.
Jan 22 22:39:47 localhost kernel: 896MB LOWMEM available.
Jan 22 22:39:47 localhost kernel: Ohara_scan_config_1 : 0
Jan 22 22:39:47 localhost kernel: Ohara_scan_config_2 : 0
Jan 22 22:39:47 localhost kernel: Ohara_scan_config_3 : 0
Jan 22 22:39:47 localhost kernel: On node 0 totalpages: 229376

といった具合。先に示した/var/log/messagesと比較していただけるとわかるが、筆者の追加した「printk()」がちゃんと働いていることが分かる。それはさておき、smp_scan_config()の結果を見ると、どれも0が返ってきている。

ということで今回の結論

 さて、要するに845マザーではどこにもSMP用のテーブルが用意されていない、というのがLinux 2.4.20カーネルでHTが有効にならない直接的な理由であることはこれで確認できた。ただ不思議なのは、Windows XPとかWindows 2000では、このマザーボードを使ってもちゃんとHTが有効になることだ。となると考えられるのは

・Intel 845PEでは、今回find_intel_smp()で検索した「以外の」領域にSMP用のテーブルが置かれている
・Intel 845PEにはSMP用のテーブルはそもそも置かれていない。したがって、別の方法でSMP用の情報を認識する方法がある

のどちらかということになる。次回はこのあたりを調査してお知らせしたい。が、いつになるやら…。

前のページ | 1 2 3 4 5 |      

[大原雄介,ITmedia]