FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

xv6がブートしてから最初のプロセスが立ち上がるまでの仕組み

f:id:msyksphinz:20160601001536p:plain

xv6は最初にブートがかかってから、暫くメモリや外部周辺機器の初期化を行うが、そのあとどのようにして最初のプログラムが立ち上がるのだろうか?

まずは、ブートローダが起動を完了すると、mpmain()に入る。

// Bootstrap processor starts running C code here.
// Allocate a real stack and switch to it, first
// doing some setup required for memory allocator to work.
int
main(void)
{
  kinit1(end, P2V(4*1024*1024)); // phys page allocator
  kvmalloc();      // kernel page table
...
  userinit();      // first user process
  // Finish setting up this processor in mpmain.
  mpmain();
}

mpmain()ではスケジューラを呼び出し、登録されているプロセスの中から最初に実行可能なプログラムを実行する。

static void
mpmain(void)
{
  int cpu_id = cpu->id;
  cprintf("cpu%d %: starting...\n", cpu_id);
  cprintf("mpmain = 0x%p\n", mpmain);
  idtinit();       // load idt register
  xchg(&cpu->started, 1); // tell startothers() we're up
  scheduler();     // start running processes
}
...
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
      if(p->state != RUNNABLE)
        continue;

      proc = p;
      switchuvm(p);
      p->state = RUNNING;

      swtch(&cpu->scheduler, proc->context);
      switchkvm();

このとき、コンテキストの切り替えを行うのだが、このコンテキストはどのようになっているのだろう?

x86のコンテキストの定義では、以下のように定義されていた。

  • proc.h
// Per-CPU state
struct cpu {
  uchar id;                    // Local APIC ID; index into cpus[] below
  struct context *scheduler;   // swtch() here to enter scheduler
...
};

struct context {
  uint edi;
  uint esi;
  uint ebx;
  uint ebp;
  uint eip;
};

RISC-Vでは、以下のようになるかな?

struct context {
  uint s0;
  uint s1;
  uint s2;
  uint s3;
  uint s4;
  uint s5;
  uint s6;
  uint s7;
  uint s8;
  uint ra;
};

これを使って、swtch.Sを定義し、プロセスを切り替えるプログラムを書いていく。ただしまだ動作していない。調査が必要だなあ。。

swtch:
  addi  sp, sp, -40

  # Save old callee-save registers and the link register
  sw    ra, 36(sp)
  sw    s8, 32(sp)
  sw    s7, 28(sp)
  sw    s6, 24(sp)
  sw    s5, 20(sp)
  sw    s4, 16(sp)
  sw    s3, 12(sp)
  sw    s2,  8(sp)
  sw    s1,  4(sp)
  sw    s0,  0(sp)

  # Switch stacks
  sw    sp, 0(a0)
  move  sp, a1

  # Load new callee-save registers
  lw    ra, 36(sp)
  lw    s8, 32(sp)
  lw    s7, 28(sp)
  lw    s6, 24(sp)
  lw    s5, 20(sp)
  lw    s4, 16(sp)
  lw    s3, 12(sp)
  lw    s2,  8(sp)
  lw    s1,  4(sp)
  lw    s0,  0(sp)
  addi  sp, sp, 40
  jr    ra
  nop

参考にしている書籍

はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)

はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)