Библиотека сайта rus-linux.net
The book is available and called simply "Understanding The Linux Virtual Memory Manager". There is a lot of additional material in the book that is not available here, including details on later 2.4 kernels, introductions to 2.6, a whole new chapter on the shared memory filesystem, coverage of TLB management, a lot more code commentary, countless other additions and clarifications and a CD with lots of cool stuff on it. This material (although now dated and lacking in comparison to the book) will remain available although I obviously encourge you to buy the book from your favourite book store :-) . As the book is under the Bruce Perens Open Book Series, it will be available 90 days after appearing on the book shelves which means it is not available right now. When it is available, it will be downloadable from http://www.phptr.com/perens so check there for more information.
To be fully clear, this webpage is not the actual book.
Next: 5. Process Address Space Up: 4. Page Table Management Previous: 4.6 Kernel Page Tables   Contents   Index
Subsections
- 4.7.1 Mapping Physical to Virtual Kernel Addresses
- 4.7.2 Mapping
struct page
s to Physical Addresses - 4.7.3 Initialising
mem_map
4.7 Mapping addresses to struct page
s
There is a requirement for Linux to have a fast method of mapping virtual
addresses to physical addresses and for mapping struct page
s
to their physical address. Linux achieves this by knowing where in both
virtual and physical memory the global mem_map
array is as the
global array has pointers to all struct pages representing physical memory
in the system. All architectures achieve this with similar mechanisms but
for illustration purposes, we will only examine the x86 carefully. This
section will first discuss how physical addresses are mapped to kernel
virtual addresses and then what this means to the mem_map
array.
4.7.1 Mapping Physical to Virtual Kernel Addresses
As we saw in Section 4.6, Linux sets up a
direct mapping from the physical address 0 to the virtual address
PAGE_OFFSET
at 3GiB on the x86. This means that on the x86, any
virtual address can be translated to the physical address by simply
subtracting PAGE_OFFSET
which is essentially what the function
virt_to_phys()
with the macro __pa()
does:
/* from <asm-i386/page.h> */ 132 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) /* from <asm-i386/io.h> */ 76 static inline unsigned long virt_to_phys(volatile void * address) 77 { 78 return __pa(address); 79 }
Obviously the reverse operation involves simply adding PAGE_OFFSET
which is carried out by the function phys_to_virt()
with
the macro __va()
. Next we see how this helps the mapping of
struct page
s to physical addresses.
There is one exception where virt_to_phys()
cannot be
used to convert virtual addresses to physical ones4.3. Specifically,
on the PPC and ARM architectures, virt_to_phys()
cannot
be used to convert address that have been returned by the function
consistent_alloc()
. consistent_alloc()
is used on PPC
and ARM architectures to return memory from non-cached for use with DMA.
4.7.2 Mapping struct page
s to Physical Addresses
As we saw in Section 4.6.1, the kernel image is located at
the physical address 1MiB, which of course translates to the virtual address
PAGE_OFFSET + 0x00100000
and a virtual region totaling about 8MiB
is reserved for the image which is the region that can be addressed by two
PGDs. This would imply that the first available memory to use is located
at 0xC0800000 but that is not the case. Linux tries to reserve the first
16MiB of memory for ZONE_ DMA
. This means the first virtual area used
for kernel allocations is 0xC1000000
which is where the global
mem_map
is usually located. ZONE_ DMA
will still get used,
but only when absolutely necessary.
Physical addresses are translated to struct page
s by treating
them as an index into the mem_map
array. Shifting a physical address
PAGE_SHIFT
bits to the right will treat it as a PFN from physical
address 0 which is also an index within the mem_map
array.
This is exactly what the macro virt_to_page()
does which is
declared as follows in asm-i386/page.h
:
#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
virt_to_page()
takes the virtual address kaddr
, converts
it to the physical address with __pa()
, converts it into an array
index by bit shifting it right PAGE_SHIFT
bits and indexing
into the mem_map
by simply adding them together. No macro is
available for converting struct page
s to physical addresses
but at this stage, it should be obvious to see how it could be calculated.
4.7.3 Initialising mem_map
The mem_map
area is created during system startup in one of two
fashions. On NUMA systems, the function free_area_init_node()
is called for each active node in the system and on UMA systems,
free_area_init()
is used. Both use the core function
free_area_init_core()
to perform the actual task of
allocating memory for the mem_map
portions and initialising
the zones. Predictably, UMA calls the core function directly with
contig_page_data
and the global mem_map
as
parameters.
The core function free_area_init_core()
allocates a local
lmem_map
for the node being initialised. The memory for the array is
allocated from the boot memory allocator with alloc_bootmem_node()
(see Chapter 6). With UMA architectures,
this newly allocated memory becomes the global mem_map
but it is
slightly different for NUMA.
NUMA architectures allocate the memory for lmem_map
within
their own memory node. The global mem_map
never gets explicitly
allocated but instead is set to PAGE_OFFSET
where it is
treated as a virtual array. The address of the local map is stored in
pg_data_t
node_mem_map
which exists somewhere within
the virtual mem_map
. For each zone that exists in the node, the
address within the virtual mem_map
for the zone is stored in
zone_t
zone_mem_map
. All the rest of the code then
treats mem_map
as a real array as only valid regions within it
will be used by nodes.
Footnotes
Next: 5. Process Address Space Up: 4. Page Table Management Previous: 4.6 Kernel Page Tables   Contents   Index Mel 2004-02-15