6.828: Operating System Engineering (29)

今日は休日 mtg の日なのですが、現実トウヒ。check_boot_pgdir 手続きの確認。
とりあえず以下から確認。

	// check pages array
	n = ROUNDUP(npage*sizeof(struct Page), PGSIZE);
	for (i = 0; i < n; i += PGSIZE)
		assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);

UPAGES は inc/memlayout.h で定義されてる模様。コメントによれば以下。

 *                     |          RO PAGES            | R-/R-  PTSIZE
 *    UPAGES    ---->  +------------------------------+ 0xef000000

む、pages って何だろ。定義はされてます。

struct Page* pages;		// Virtual address of physical page array

これ、初期設定されてないな。でも pages って extern 宣言されてるな。ちなみに struct Page 型は inc/memlayout.h で定義されている模様。

/*
 * Page descriptor structures, mapped at UPAGES.
 * Read/write to the kernel, read-only to user programs.
 *
 * Each Page describes one physical page.
 * You can map a Page * to the corresponding physical address
 * with page2pa() in kern/pmap.h.
 */
LIST_HEAD(Page_list, Page);
typedef LIST_ENTRY(Page) Page_LIST_entry_t;

struct Page {
	Page_LIST_entry_t pp_link;	/* free list link */

	// pp_ref is the count of pointers (usually in page table entries)
	// to this page, for pages allocated using page_alloc.
	// Pages allocated at boot time using pmap.c's
	// boot_alloc do not have valid reference count fields.

	uint16_t pp_ref;
};

ええと LIST_HEAD マクロを展開されたら

struct Page_list {
   struct Page *lh_first; /* first element */
};

になるのかな。あるいは LIST_ENTRY もマクロな模様。以下?

typedef 
struct {
	struct Page *le_next;	/* next element */
	struct Page **le_prev;	/* ptr to ptr to this element */
}
Page_LIST_entry_t;

双方向リンクになってるのか。pages はやはり i386_vm_init 手続きで初期設定する模様。

	//////////////////////////////////////////////////////////////////////
	// Allocate an array of npage 'struct Page's and store it in 'pages'.
	// The kernel uses this array to keep track of physical pages: for
	// each physical page, there is a corresponding struct Page in this
	// array.  'npage' is the number of physical pages in memory.
	// User-level programs will get read-only access to the array as well.

ええと、UPAGES な領域ですが 0x400000 って 4096*1024 になるのか。PTSIZE は mmu.h にて以下な定義か。

// Page directory and page table constants.
#define NPDENTRIES	1024		// page directory entries per page directory
#define NPTENTRIES	1024		// page table entries per page table

#define PGSIZE		4096		// bytes mapped by a page
#define PGSHIFT		12		// log2(PGSIZE)

#define PTSIZE		(PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry

ちょっとまだイメージが微妙です。もう少し周辺の確認を。
ええと、check_va2pa という手続きが多用されてるので見てみます。コメントのあたりが以下。

// This function returns the physical address of the page containing 'va',
// defined by the page directory 'pgdir'.  The hardware normally performs
// this functionality for us!  We define our own version to help check
// the check_boot_pgdir() function; it shouldn't be used elsewhere.

static physaddr_t
check_va2pa(pde_t *pgdir, uintptr_t va)
{

pde_t は unsigned int なのか。てゆーか、ページング回路って何でしたっけ。ええと、詳解 Linux カーネルな記述が以下。

メモリ管理回路(MMU)は、セグメンテーション回路というハードウェアを用いて、論理アドレスをリニアアドレスに変換します。そのあと、ページング回路を用いて、リニアアドレスを物理アドレスに変換します。

詳解 Linux カーネル第3版より引用
中身を見てみます。

static physaddr_t
check_va2pa(pde_t *pgdir, uintptr_t va)
{
	pte_t *p;

	pgdir = &pgdir[PDX(va)];
	if (!(*pgdir & PTE_P))
		return ~0;
	p = (pte_t*) KADDR(PTE_ADDR(*pgdir));
	if (!(p[PTX(va)] & PTE_P))
		return ~0;
	return PTE_ADDR(p[PTX(va)]);
}

PDX とか PTX あたりのマクロは mmu.h で定義されてて以下な考え方。

// A linear address 'la' has a three-part structure as follows:
//
// +--------10------+-------10-------+---------12----------+
// | Page Directory |   Page Table   | Offset within Page  |
// |      Index     |      Index     |                     |
// +----------------+----------------+---------------------+
//  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
//  \----------- PPN(la) -----------/

linear address、という表現になってますね。PTE_P なマクロも mmu.h で以下。

// Page table/directory entry flags.
#define PTE_P		0x001	// Present

フラグは 9 bits 分の領域なのかな、ちなみに PTE_ADDR も同様で定義が以下。

// Address in page table or page directory entry
#define PTE_ADDR(pte)	((physaddr_t) (pte) & ~0xFFF)

あー、なんとなくそのまんまなカンジですね。ざっくり理解ですが

  • Page Directory Index を取り出して Page table/directory entry であることを確認
    • そうでなければ ~0 を戻す
  • Offset を取り出して VA に変換
    • 変換した VA は Page table/directory entry かどうか
      • そうでなければ ~0 を戻す
  • Page Table Index な Offset を戻す
    • これは PA って理解で良いのかな

うう

なんつーか、明快にイメージできてない。pages って何だ。もう少し pmap.c をがっつり読んだ方が良いみたいな会議中。