vm.c void inituvm(pde_t *pgdir, char *init, uint sz)

トップページ
jupiteroak.hatenablog.com


vm.c
https://github.com/mit-pdos/xv6-public/blob/master/vm.c#L182

void inituvm(pde_t *pgdir, char *init, uint sz)
{
  char *mem;

  if(sz >= PGSIZE)
    panic("inituvm: more than a page");
  mem = kalloc();
  memset(mem, 0, PGSIZE);
  mappages(pgdir, 0, PGSIZE, V2P(mem), PTE_W|PTE_U);
  memmove(mem, init, sz);
}

引数pgdirが指定するページディレクトリに仮想アドレス0x0000 0000~0x0000 0FFFと割り当てたページフレーム(4KBのメモリ領域)のマッピングを設定し、そのページフレームに先頭アドレス init・サイズがszのメモリ領域に格納されている内容をロードします。

引数 pde_t *pgdir
設定対象となるページディレクトリの先頭アドレスです。

引数 char *init
ページフレームにロードさせたい内容を含んだメモリ領域の先頭アドレスです。

引数 uint sz
ページフレームにロードさせたい内容を含んだメモリ領域のサイズ(バイト単位)です。


処理の内容

サイズszが4KB以上の場合はメッセージを出力する

if(sz >= PGSIZE)
    panic("inituvm: more than a page");

サイズszが4KB(#define PGSIZE 4096)以上になる場合は、panic関数を呼び出して、メッセージを出力します。

ページフレームとして使用する4KBのメモリ領域を割り当てる

mem = kalloc();

kalloc関数を呼び出して、ページフレームとして使用する4KBのメモリ領域を割り当てます。

ページフレームを0で初期化する

memset(mem, 0, PGSIZE);

memset関数を呼び出して、ページフレームとして使用する4KB(#define PGSIZE 4096)のメモリ領域を0で初期化します。

ページフレームのマッピングを行う

mappages(pgdir, 0, PGSIZE, V2P(mem), PTE_W|PTE_U);

mappages関数を呼び出して、pgdirで指定されたページディレクトリに、仮想アドレス0~0+PGSIZE-1と物理アドレスV2P(mem)~ V2P(mem)+PGSIZE-1 のマッピングを設定します(0x0000 0000~0x0000 0FFFと物理アドレスV2P(mem)~V2P(mem)+0x0FFFのマッピングを設定します)。
ページフレームとして使用する4KBのメモリ領域の先頭アドレスmemは仮想アドレスなので、V2Pマクロを使って物理アドレスにV2P(mem)に変換しています。
マッピングで使用するPTEのbit1(ページテーブルエントリのR/Wフラグ)を1、PTEのbit2(ページテーブルエントリのU/Sフラグ)を1にするために、mappages関数の第3引数にPTE_W(#define PTE_W 0x002)とPTE_U(#define PTE_U 0x004)の論理和を指定しています。
PTEのbit1(ページテーブルエントリのR/Wフラグ)が1の時は、ページフレームが読み書き可能であることを示しています。
PTEのbit2(ページテーブルエントリのU/Sフラグ)が1の時は、ユーザープロセスがページフレームにアクセスできることを示しています。

ページフレームに先頭アドレス init・サイズがszのメモリ領域に格納されている内容をロードする

memmove(mem, init, sz);

memmove関数を呼び出して、先頭アドレス init・サイズがszのメモリ領域に格納されている内容を、ページフレームへロードします。
この処理を実行しているプロセス(に関わるページディレクトリ)においては仮想アドレスmemは物理アドレスV2P(mem)に対応しており、pgdirで指定されたページディレクトリにおいては仮想アドレス0x0000 0000は物理アドレスV2P(mem)に対応しています。