Linux0.11 kernel-Memory Management 2. With fork, linux0.11fork

Source: Internet
Author: User

Linux0.11 kernel-Memory Management 2. With fork, linux0.11fork

[All Rights Reserved. For more information, see the source. Source: http://www.cnblogs.com/joey-hua/p/5598451.html]

In the previous fork function, first, call get_free_page to apply for a page of memory for the data structure of the new task. In memory. c:

/** Obtain the first (actually the last) idle page and mark it as used. If no idle page exists, * returns 0. * //// Obtain the idle page. If no memory is available, 0 is returned. // Input: % 1 (ax = 0)-0; % 2 (LOW_MEM); % 3 (cx = paging pages); % 4 (edi = mem_map + PAGING_PAGES-1 ). // Output: Return % 0 (ax = start address of the page ). // The above % 4 registers actually point to the last byte of the mem_map [] memory byte graph. This function starts scanning forward from the end of the byte graph // All page signs (the total number of pages is PAGING_PAGES). If the page is idle (the memory image byte is 0), the page address is returned. // Note! This function only indicates an idle page in the primary memory area, but does not map it to the linear address of a process. The put_page () function following // is used for ing. Unsigned longget_free_page (void) {register unsigned long _ res asm ("ax"); _ asm _ ("std; repne; scasb \ n \ t "// direction position, compare al (0) with the (di) content corresponding to each page, "jne 1f \ n \ t" // if there is no byte equal to 0, the jump ends (0 is returned ). "Movb $ (% edi) \ n \ t" // set the memory image location of the corresponding page to 1. "Sall $12, % ecx \ n \ t" // Number of pages * 4 K = relative start address of the page. "Addl % 2, % ecx \ n \ t" // Add the low-end memory address to obtain the actual physical start address of the page. "Movl % ecx, % edx \ n \ t" // set the actual starting address of the page ?? Edx register. "Movl $1024, % ecx \ n \ t" // register ecx sets the Count value to 1024. "Leal 4092 (% edx), % edi \ n \ t" // Add a 4092 + edx location ?? Edi (the end of the page ). "Rep; stosl \ n \ t" // clears the memory indicated by edi (in the opposite direction, this page will also be cleared ). "Movl % edx, % eax \ n" // set the starting address of the page ?? Eax (return value ). "1:": "= a" (_ res): "" (0), "I" (LOW_MEM), "c" (PAGING_PAGES ), "D" (mem_map + PAGING_PAGES-1): "di", "cx", "dx"); return _ res; // return the idle page address (if there is no idle page, return 0 ).}

There are several commands that are unfamiliar. First, we will introduce repne scasb. The corresponding equivalent commands are:

scans:inc edi    dec ecx    je loopdone    cmp byte [edi-1],al    jne scansloopdone:

Sall $12, % eax indicates to shift the value of % eax to 12 places left, equivalent to eax = eax * 4096.

The STOSL command saves the value in EAX to the address pointed to by ES: EDI.

So the first command means to compare the value of al (% 0) 0 with di content (inverted), edi is mem_map + PAGING_PAGES-1, that is, the last pagination subscript of the memory ing array. If there are bytes equal to 0 that are not used yet, the memory image location of the corresponding page is 1.

Then, multiply the value of ecx, instead of PAGING_PAGES, by 4096 to get the starting address of the relative page, and add LOW_MEM to get the actual physical starting address of the page. Then clear the entire page of memory 0. Finally, return the starting address of the page.

Next, let's look at the most critical copy_page_tables function:

// Refresh the page to change the high-speed buffer macro function. // To improve address translation efficiency, the CPU stores recently used page table data in the chip for high-speed buffering. After modifying the page table // information, you need to refresh the buffer. Here, refresh the page Directory base address register C3. // The following eax = 0 is the base address of the page Directory. # Define invalidate () \__ asm _ ("movl % eax, % H6": "a" (0)/** OK, the following is one of the most complex programs in memory management mm. It copies the content of a linear address within a certain range by copying only the memory page. I hope there is no error in the code, because I don't want to * debug this code again ?. ** Note! Instead of simply copying any memory block, the address of the memory block must be a multiple of 4 Mb (exactly * the memory size corresponding to a page Directory), because such processing can make the function very simple. In any case, * It is used only by fork () (fork. c 56th rows ). ** Note 2 !! When from = 0, it is used to copy the kernel space for the first fork () call. In this case, we * do not want to copy the memory corresponding to the entire page Directory, because this will cause a serious waste of memory-We * only copy the first 160 pages-corresponding to 640kB. Even copying these pages has exceeded our needs * but this does not occupy more memory-we do not perform the copy-on-write operation within 1 Mb of memory, therefore, * these pages can be shared with the kernel. Therefore, this is a special case of nr = xxxx (nr indicates the number of pages in the program ). * //// Copy the page Directory items and page tables corresponding to the specified linear address and length (number of page tables) memory, the copied page Directory and the original physical memory zone corresponding to the // page table are shared. // Copy the page Directory items and page table items corresponding to the specified address and length of memory. You need to apply for a page to store the new page table, and the original memory zone is shared; // the two processes will share the memory zone until one process performs the write operation, to allocate a new memory page (write-time replication mechanism ). Aggregate (unsigned long from, unsigned long to, long size) {unsigned long * from_page_table; unsigned long * to_page_table; unsigned long this_page; unsigned long * from_dir, * to_dir; unsigned long nr; // both the source address and destination address must be at the 4 Mb memory boundary address. Otherwise, an error occurs. If (from & 0x3fffff) | (to & 0x3fffff) panic ("copy_page_tables called with wrong alignment "); // obtain the directory items (from_dir and to_dir) of the source and target addresses ). For more information, see comments to the 115 sentence. From_dir = (unsigned long *) (from> 20) & 0 xffc);/* _ pg_dir = 0 */to_dir = (unsigned long *) (to> 20) & 0 xffc); // calculate the number of page tables (that is, the number of directory items) occupied by the memory block to be copied ). Size = (unsigned) (size + 0x3fffff)> 22; // copy each occupied page table in sequence. For (; size --> 0; from_dir ++, to_dir ++) {// If the page table specified by the target directory item already exists (P = 1), an error occurs and the system crashes. If (1 & * to_dir) panic ("copy_page_tables: already exist"); // if this source directory item is not used, you do not need to copy the corresponding page table and skip it. If (! (1 & * from_dir) continue; // get the address of the page table in the current source directory item ?? From_page_table. From_page_table = (unsigned long *) (0xfffff000 & * from_dir); // retrieves one page of idle memory for the target page table. If the returned result is 0, the idle Memory Page is not applied. Return Value =-1. Exit. If (! (To_page_table = (unsigned long *) get_free_page () return-1;/* Out of memory, see freeing * // set the target directory item information. 7 indicates the Flag Information (Usr, R/W, Present ). * To_dir = (unsigned long) to_page_table) | 7; // set the number of pages to be copied for the currently processed page table. If it is in the kernel space, you only need to copy the first 160 pages; otherwise, you need to // copy all 1024 pages in one page table. Nr = (from = 0 )? 0xA0: 1024; // for the current page table, the specified number of nr memory pages are copied. For (; nr --> 0; from_page_table ++, to_page_table ++) {this_page = * from_page_table; // retrieve the content of the source page table item. If (! (1 & this_page) // if the current source page is not used, you do not need to copy it. Continue; // reset the R/W mark in the page table item (set to 0 ). (If the U/S bit is 0, R/W does not work. If U/S is 1, R/W is 0, // The code running on the user layer can only read the page. If U/S and R/W are both set, the write permission is granted .) This_page & = ~ 2; * to_page_table = this_page; // copy the page table entry to the target page table. // If the address of the page indicated by this page table item is more than 1 MB, you need to set the Memory Page ing array mem_map [], so the page number is calculated, and use it as the index to increase the number of references in the corresponding items of the page ing array. For pages smaller than 1 MB, the description // is the kernel page. Therefore, you do not need to set mem_map. Because mem_map [] is only used to manage page usage in the main memory zone. Therefore, when the kernel is moved to task 0 and fork () is called to create Task 1 (used to run init ()), because the pages are still in the kernel code area, the statements in the following judgment will not be executed. It is executed only when the parent process that calls fork () is in the primary memory (the page location is greater than 1 MB. This situation occurs only when the process calls execve () and loads and // executes the new program code. If (this_page> LOW_MEM) {// The following sentence indicates that the memory page referred to by the source page table item is also read-only. Because now there are two processes in the shared memory zone. // If one of the memory needs to be written, you can use the write protection of page exceptions to allocate a new idle page for the write process, that is, the copy operation during write. * From_page_table = this_page; // read-only entries in the source page table. This_page-= LOW_MEM; this_page >>=12; mem_map [this_page] ++ ;}} invalidate (); // refresh the page to change the cache speed. Return 0 ;}

Remember that the three parameters passed from fork are old_data_base, new_data_base, and data_limit. Here, old_data_base is the base address (linear address space) of the data segment in the Local Descriptor Table of the original process, and new_data_base is the base address (Task Number * 64 MB) of the new process in the linear address space ), data_limit is the segment length limit in the data segment descriptor in the Local Descriptor Table of the original process.

First, retrieve the page Directory items of the source address and target address. Because the page memory is 4 kb, 4096 corresponds to a page table item. Because a page table has 4096 table items, therefore, a page table is 1024*4096 = 4194304. Because a complete page table corresponds to a page DirectoryPage directory numberDivide the address by 4194304 (22 digits to the right ). Because each item occupies 4 bytes, and the page Directory starts from the physical address 0 (head. s), so the actual page Directory item pointer = page Directory Number * 4 (that is, move left 2 ). And 0 xffc (4092) and indicate that the range cannot exceed the range of 1024 page Directory items.

Then calculate the number of page Directory items with a limited length, that is, the number of page tables (size + 4 M)/4 M.

Then, use a for loop to copy each occupied page table in sequence. First, take the page table address 0xfffff000 & * from_dir in the source directory item. According to the structure of the PDE, the 12-31 bits are the base addresses of the page table, 0-11 bits are various attributes. Therefore, use 0xfffff000 to clear 12 low bits and obtain the base address of the 20-bit high page table.

NextTarget page tableApply for a blank page of memory. The starting address of the table on this page exists in to_page_table, and the first three digits are set to 1. Then, assign the address value to the target page Directory.

Then, we use a for loop to copy the content of the entire page table with from_page_table as the starting address of the page table. First, we take the content of the first source page table item * from_page_table, it is actually the address and attributes of a page. Then, assign the this_page value to * to_page_table.

The code below is to set read-only.

The last sentence is to refresh the page and change the high-speed buffer. There is nothing to say.

If the preceding function execution fails, free_page_tables is called to release the applied memory:

/** The following function releases consecutive memory blocks in the page table. 'exit () 'requires this function. Similar to copy_page_tables () *, this function only processes 4 Mb memory blocks. * //// Based on the specified linear address and limit length (number of page tables), release the memory block specified by the corresponding memory page table and set the table item to idle. // The page Directory is located at the beginning of the physical address 0, with a total of 1024 items, 4 K bytes. Each directory item specifies a page table. // The page table starts from the physical address 0x1000 (followed by the Directory space). Each page table has 1024 items, which also occupies 4 K of memory. // Each page table item corresponds to a page of physical memory (4 K ). The directory and page table items are 4 bytes in size. // Parameter: from-start base address; size-release length. Intfree_page_tables (unsigned long from, unsigned long size) {unsigned long * pg_table; unsigned long * dir, nr; if (from & 0x3fffff) // The address of the memory block to be released must be 4 MB. // It cannot be <4 M, and smaller than 4 M is equal to itself, and greater than 4 M is equal to 0 panic ("free_page_tables called with wrong alignment"); if (! From) // error, trying to release the space occupied by the kernel and buffer. Panic ("Trying to free up swapper memory space"); // calculate the number of page Directory items occupied (4 MB of carry integer times), that is, the number of page tables occupied. (Size + 4 M)/4 M // a page is 4 kb, and an entire page table has 1024 pages, therefore, 4 kb * 1024 = 4 m is the size of the entire page table. // then, the entire page table corresponds to a page Directory item size = (size + 0x3fffff)> 22; // calculate the start directory item in the following sentence. The corresponding directory item number = from> 22, because each item occupies 4 bytes, and because the page Directory starts from // physical address 0, therefore, the actual directory item pointer = directory item number <2, that is, (from> 20 ). And the above 0 xffc ensure that the // directory item pointer range is valid. Dir = (unsigned long *) (from> 20) & 0 xffc);/* _ pg_dir = 0 */for (; size --> 0; dir ++) {// size is the number of directory items to be released. If (! (1 & * dir) // if this directory item is invalid (P bit = 0), continue. Continue; // The position 0 (P) of the Directory item indicates whether the corresponding page table exists. Pg_table = (unsigned long *) (0xfffff000 & * dir); // retrieve the address of the page table in the directory. For (nr = 0; nr <1024; nr ++) {// each page table has 1024 page items. If (1 & * pg_table) // if this page table item is valid (P bit = 1), the corresponding Memory Page is released. Free_page (0xfffff000 & * pg_table); * pg_table = 0; // The items in the table on this page are cleared. Pg_table ++; // point to the next item in the page table .} Free_page (0xfffff000 & * dir); // release the Memory Page occupied by the page table. However, this statement is not used because the page table is within 1 MB of the // physical address. * Dir = 0; // clear the directory items of the corresponding page table.} Invalidate (); // refresh the page to change the cache speed. Return 0 ;}

This function is similar to the above function. First, calculate the number of page Directory items and then calculate the start directory item address.

Then, use a for loop to get the address of the page table in the directory items, and then use a for loop to clear the 1024 page items in the page table. Here, a function free_page is used:

/** Release the page memory starting with the physical address 'addr. The function 'free _ page_tables ()'. * ///// Release the page memory starting with the physical address addr. // Memory less than 1 MB is used for Kernel programs and buffering, and is not used as the memory space for page allocation. // A = I --; // first a = I; then I = I-1; voidfree_page (unsigned long addr) {if (addr <LOW_MEM) return; // if the physical address addr is smaller than the low-end memory (1 MB), return. If (addr> = HIGH_MEMORY) // if the physical address addr> = memory is the highest, an error message is displayed. Panic ("trying to free nonexistent page"); addr-= LOW_MEM; // the physical address minus the low-end memory location and divide it by 4 kb to get the page number. Addr> = 12; if (mem_map [addr] --) return; // if the ing byte of the corresponding memory page is not equal to 0, 1 is subtracted to return. Mem_map [addr] = 0; // otherwise, the corresponding page ing byte is set to 0 and an error message is displayed. Panic ("trying to free page ");}

This function is used to release one page of memory. First, we get the page number, and then subtract 1 from the content corresponding to the memory ing array.

Therefore, free_page (0xfffff000 & * pg_table); First retrieves the content of the page table item, that is, the address of the corresponding page memory, and then releases the page memory.

After the page memory is released, the table items on the page are cleared * pg_table = 0.

Then release the Memory Page (4 K) occupied by the page table, and finally release the contents of the Directory items on the page.

Now the analysis is complete!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.