[start_kernel() --> page_address_init()]
page_address_init() do nothing when all RAM can be mapped directly, otherwise, do following operations:
// mm\highmem.c:
static struct page_address_map page_address_maps[LAST_PKMAP]; void __init page_address_init(void) { int i; INIT_LIST_HEAD(&page_address_pool); for (i = 0; i < ARRAY_SIZE(page_address_maps); i++) list_add(&page_address_maps[i].list, &page_address_pool); for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) { INIT_LIST_HEAD(&page_address_htable[i].lh); spin_lock_init(&page_address_htable[i].lock); } spin_lock_init(&pool_lock); } |
page_address_pool is a global variable.
// mm\highmem.c:
/* * page_address_map freelist, allocated from page_address_maps. */ static struct list_head page_address_pool; /* freelist */ static spinlock_t pool_lock; /* protects page_address_pool */ |
page_address_htable[] is also a global variable.
// mm\highmem.c:
/* * Hash table bucket */ static struct page_address_slot { struct list_head lh; /* List of page_address_maps */ spinlock_t lock; /* Protect this bucket's list */ } ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER]; |
There is a very important data structure:
struct page_address_map, this structure's main purpose is to maintain the association of struct page and its virtual memory. However, this will be wasteful if the page has a linear association with its virtual memory. This becomes necessary when the addressing is hashed.
// mm\highmem.c:
/* * Describes one page->virtual association */ struct page_address_map { struct page *page; void *virtual; struct list_head list; };
|
Summary:
1. The main purpose of page_address_init() is to initiate global variable
page_address_pool, which is used to support high memory that cannot be directly mapped.
page_address_pool is a list header pointing to lots of
struct page_address_map connected each other using list.
2.
page_address_htable[] is used to hold the list of entry that hash to the same bucket. page_address_init() initiates it.