Where are struct page* initialized in Linux?
Maybe try mm_init
, called by start_kernel()
in /init/main.c/
and the corresponding mem_init
in /arch/x86/mm/init_64.c
:
void __init mem_init(void)
1286 {
1287 pci_iommu_alloc();
1288
1289 /* clear_bss() already clear the empty_zero_page */
1290
1291 /* this will put all memory onto the freelists */
1292 memblock_free_all();
1293 after_bootmem = 1;
1294 x86_init.hyper.init_after_bootmem();
1295
1296 /*
1297 * Must be done after boot memory is put on freelist, because here we
1298 * might set fields in deferred struct pages that have not yet been
1299 * initialized, and memblock_free_all() initializes all the reserved
1300 * deferred pages for us.
1301 */
1302 register_page_bootmem_info();
Details for PTE and struct page
when an userspace process accesses to some virtual address, the MMU tries to find the PTE for the requested virtual address
Yes, this is correct. The page table is walked down to the specific PTE (if any).
In the PTE there is the encoded
struct page
's PFN and some flags.
Not really. The PTE contains the PFN (Page Frame Number) of the actual physical memory page that the virtual address translates to. In other words, it points to the actual page in physical memory, not to the corresponding struct page
.
if the translated address points to a
struct page
, how exactly is physical memory is accessed? I thinkstruct page
is just page descriptor, not a empty physical memory region.
The translated address does not point to a struct page
, it points to physical memory. Indeed, the struct page
is just a "descriptor" used by the system to keep track of the nature and state of a page, and is stored somewhere else.
All the struct page
structures are stored in some specific memory area which depends on the underlying architecture. You can read more about it in Chapter 2: Describing Physical Memory of Mel Gorman's book "Understanding the Linux Virtual Memory Manager".
Once you have a PTE (pte_t
), the pte_page()
macro can be used to get the address of the corresponding struct page
. This address is calculated using a set of macros (e.g. __pfn_to_page()
) which basically end up indexing a mem_section
which contains a pointer to an array of struct page
(.section_mem_map
). There is a global array of struct mem_section
, and each PTE PFN has a section index encoded in it, which is used to select the correct section.
Where is the payload of a page struct
You could use page_address() to get virtual address of a page.
But the return address might be NULL due to the fact that not all pages have mapped virtual addresses.
void *page_address(const struct page *page);
You could use kmap to map a highmen page to a virtual address.
Also, remember to use kunmap to unmap this page when you don't need to access it.
struct page *page = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
if (page) {
void *addr = kmap(page);
if (addr) {
memset(addr, 0, PAGE_SIZE);
kunmap(addr);
}
}
How to get the physical address of the associated data from a struct page?
You need to map a page
into the kernel memory as follows:
void * mapping = kmap_atomic(page, KM_USER0);
// work with mapping...
kunmap_atomic(mapping, KM_USER0);
This trick is required as there is a HighMemory
concept in Linux (see this link for ex.).
UPD: You can use kmap
instead of kmap_atomic
in non-atomic contexts.
Can we access memory through a struct page structure
Yes we can access the page belonging to highmem through struct page's virtual field. But in your case you can't access as you mentioned that highmem page is not mapped into kernel virtual memory.
To access it you need to create mapping either permanent or temporary mappping.
To create permanent mapping map page through kmap.
void *kmap(struct page *page)
This function works on either high or low memory. If the page structure belongs to a page in low memory, the page’s virtual address is simply returned. If the page resides in high memory, a permanent mapping is created and the address is returned.The function may sleep, so kmap() works only in process context. Because the number of permanent mappings are limited (if not, we would not be in this mess and could just permanently map all memory), high memory should be unmapped when no longer needed.This is done via the following function, which unmaps the given page:
void kunmap(struct page *page)
The temporary mapping can be created via:
void *kmap_atomic(struct page *page, enum km_type type)
This is an atomic function so you can't sleep and can be called in interrupt context. It is called temporary because next call to kmap_atomic will overwrite the previous mapping.
How can I get contents of page with page structure?
Not sure but perhaps safer approach is using kmap()
from linux/highmem.h
which will return associated virtual address if the page is already mapped, or else will create a mapping for the given page and return the address for the same that you can dereference from your module.
Related Topics
Add Timestamp to Cat Output from Shell Script
Linux Awk Comparing Two CSV Files and Creating a New File with a Flag
How to Lock The Cursor to The Inside of a Window on Linux
How to Execute a Command in a Bash Script and Then Focus The Appearing Window
Matching Third Field in a CSV with Pattern File in Gnu Linux (Awk/Sed/Grep)
Linux Kernel Code in Memory Check with Sha256 Sum
Linux Directory Starting with Dot
See What Process Last Touched a File
Elf File Tls and Load Program Sections
Incorrect Rendering in Anaconda + Spyder (Wrong Colours in Text)
How to Get Pyinstaller to Working on Ubuntu
Problem of Understanding Clock_Gettime
Starting Multiple Firefox Profiles with Batch File in Linux
.Net Core 3.1 Deploy on Centos 7