proc.c struct cpu* mycpu(void)

トップページ
jupiteroak.hatenablog.com


proc.c
https://github.com/mit-pdos/xv6-public/blob/master/proc.c#L37

struct cpu*
mycpu(void)
{
  int apicid, i;
  
  if(readeflags()&FL_IF)
    panic("mycpu called with interrupts enabled\n");
  
  apicid = lapicid();
  // APIC IDs are not guaranteed to be contiguous. Maybe we should have
  // a reverse map, or reserve a register to store &cpus[i].
  for (i = 0; i < ncpu; ++i) {
    if (cpus[i].apicid == apicid)
      return &cpus[i];
  }
  panic("unknown apicid\n");
}

mycpu関数は、この関数を現在実行しているプロセッサに対応したcpu構造体を取得します。

戻り値 struct cpu* &cpus[i]
この関数を現在実行しているプロセッサに対応したcpu構造体のアドレスです。


cpu構造体について
cpu構造体は、そのcpu構造体に対応しているプロセッサについての情報を記録したデータ構造です。
1つのプロセッサにつき1つのcpu構造体が用意されています。
proc.h

// Per-CPU state
struct cpu {
  uchar apicid;                // Local APIC ID
  struct context *scheduler;   // swtch() here to enter scheduler
  struct taskstate ts;         // Used by x86 to find stack for interrupt
  struct segdesc gdt[NSEGS];   // x86 global descriptor table
  volatile uint started;       // Has the CPU started?
  int ncli;                    // Depth of pushcli nesting.
  int intena;                  // Were interrupts enabled before pushcli?
  struct proc *proc;           // The process running on this cpu or null
};


処理の内容

ハードウェア割り込みが無効化されていることを確認する

 if(readeflags()&FL_IF)
    panic("mycpu called with interrupts enabled\n");

readeflags関数を呼び出して取得したEFLFGSレジスタの値をFL_IF(#define FL_IF 0x0000 0200)を使ってマスク処理することにより、EFLFGSレジスタのIF(bit9 インターラプトエネーブルフラグ)の値を取り出しています。
readeflags()&FL_IFが真の場合→IFの値が1の場合→ハードウェア割り込みを有効化している場合は、panic関数を呼び出してメッセージを出力します。
readeflags()&FL_IFが偽の場合→IFの値が0の場合→ハードウェア割り込みを無効化している場合は、次の処理へ進みます。

この関数を実行しているプロセッサが持つLocal APIC IDを取得する

apicid = lapicid();

lapicid関数を呼び出して、この関数を実行しているプロセッサが持つLocal APIC IDレジスタからLocalAPIC IDを取得します。
このLocal APIC IDを用いてプロセッサの識別を行います。

配列cpusを走査してプロセッサに対応したcpu構造体を取得する

for (i = 0; i < ncpu; ++i) { 
if (cpus[i].apicid == apicid)
 return &cpus[i]; 
}

cpu構造体の配列cpusの中から、lapicid関数で取得したLocal APIC IDの値を持つcpu構造体を探し、そのcpu構造体のアドレスを戻り値として返します。

proc.h

// Per-CPU state
struct cpu {
  uchar apicid;                // Local APIC ID
  struct context *scheduler;   // swtch() here to enter scheduler
  struct taskstate ts;         // Used by x86 to find stack for interrupt
  struct segdesc gdt[NSEGS];   // x86 global descriptor table
  volatile uint started;       // Has the CPU started?
  int ncli;                    // Depth of pushcli nesting.
  int intena;                  // Were interrupts enabled before pushcli?
  struct proc *proc;           // The process running on this cpu or null
};

param.h

#define NCPU          8

mp.c

struct cpu cpus[NCPU]

proc.h

extern struct cpu cpus[NCPU];

cpu構造体が見つからなかった場合はメッセージを出力する

panic("unknown apicid\n");

lapicid関数で取得したLocal APIC IDの値を持つcpu構造体が見つからなかった場合は、panic関数を呼び出してメッセージを出力します。