Linux-0.11 kernel source code analysis series: Memory Management copy_page_tables () function analysis,
/** Author: David Lin * Date: 2014-11-22pm * Email: linpeng1577@163.com or linpeng1577@gmail.com * world: the city of SZ, in China * Ver: 000.000.001 * history: editor time do * 1) linPeng 2014-11-22 created this file! * 2) * // ** Well, here is one of the most complicated functions in mm. it * copies a range of linerar addresses by copying only the pages. * Let's hope this is bug-free, 'cause this one I don't want to debug :-) ** Note! We don't copy just any chunks of memory-addresses have to * be divisible by 4 Mb (one page-directory entry), as this makes the * function easier. it's used only by fork anyway. ** NOTE 2 !! When from = 0 we are copying kernel space for the first * fork (). then we DONT want to copy a full page-directory entry, as * that wocould lead to some serous memory waste-we just copy the * first 160 pages-640kB. even that is more than we need, but it * doesn't take any more memory-we don't copy-on-write in the low * 1 Mb-range, so the pages can be shared with the kernel. thus the * special c Ase for nr = xxxx. * // * Linus considers the copy_page_tables () function below as one of the most difficult parts of memory management. * The copy_page_tables () function is called only by the fork function. * copying only copies a page table, page tables manage 4 m addresses. Therefore, they are 4 m aligned. * Physical page content is not copied. When a copy occurs, the physical page content managed by the page table is copied. * for processes 0 and 1, only copy the first 160 pages of a total of KB. For efficiency consideration, * 0-1M is used as the kernel resident address area. Write overwrite is prohibited * parameter from, to is a 0-4g linear address, size is in bytes */int copy_page_tables (unsigned long from, unsigned long to, long size) {unsigned long * from_page_table; // used to manage the source page table unsigned long * to_page_table; // used Manage the target page table unsigned long this_page; // used to save the page table unsigned long * from_dir, * to_dir; // used to manage the source page Directory items and the target page Directory item unsigned long nr; // used to save the number of items in the page table if (from & 0x3fffff) | (to & 0x3fffff) // 4 m alignment detection, otherwise diepanic ("copy_page_tables called with wrong alignment "); from_dir = (unsigned long *) (from> 20) & 0 xffc);/* _ pg_dir = 0 * // source page Directory item to_dir = (unsigned long *) (to> 20) & 0 xffc); // target page Directory item size = (unsigned) (size + 0x3fffff)> 22; // The number of page table items is the number of bytes divided by 4 Mfor (; size --> 0; from_dir ++, to_dir ++) {if (1 & * to_dir) // if the directory item on the target page has been used, diepanic ("copy_page_tables: already exist"); if (! (1 & * from_dir) continue; // if the source page Directory item is not used, skip it and do not copy from_page_table = (unsigned long *) (0xfffff000 & * from_dir ); // obtain the source page table if (! (To_page_table = (unsigned long *) get_free_page () return-1;/* Out of memory, see freeing * // take the free physical page and assign a value to to_page_table // if there is no idle physical page, die * to_dir = (unsigned long) to_page_table) | 7; // Save the page table to the corresponding page Directory, // 7 indicates read/write. // think about the commonly used chmod 777 anyfile nr = (from = 0 )? 0xA0: 1024; // if the address is 0, copy only the 160 page, otherwise, copy 1024 pages/one page Directory table to manage 1024 page Directory items/one page table to manage 1024 page table items/one page table item to manage 4 K physical addresses (; nr --> 0; from_page_table ++, to_page_table ++) {this_page = * from_page_table; // retrieve the source page table item from the source page table if (! (1 & this_page) // if the source page table item is not used, skip continue; this_page & = ~ 2; // read/write bit of the target page table item, // set to read-only * to_page_table = this_page; // Save the source page table item to the target page table item if (this_page> LOW_MEM) {// if the primary memory zone * from_page_table = this_page; // The Source Page table item must also be set to read-only this_page-= LOW_MEM; // take the offset address this_page> = 12 relative to the primary memory; // take the primary memory management array index mem_map [this_page] ++; // The number of physical page references plus 1 }}invalidate (); // refresh cache return 0; // return 0 indicates success}