First of all the memory of the overall distribution map, not yet fully understand
After LAB1, the state of the physical memory that is formed is the following
After the mapping mechanism is manually turned on, the memory starting from 0xf0100000 is mapped to the location of the 0x0100000
Part1: Physical Memory Allocator
The first is to write a physical memory allocator, which allocates physical memory, to track what physical memory is available in memory and which is not.
The list of free physical memory in XV6 is stored in the free page, because there is no content in it. However, Jos is a separate storage management.
The Jos uses two physical memory allocators, Boot_alloc and Page_alloc
Boot_alloc is only run once when the system is loaded, it is no longer called after Page_Init, and the physical memory allocations thereafter are all done by Page_alloc.
The reason for the use of two memory allocators in XV6 book is: After loading, there is no allocator, most of the code is not able to use locks and more than 4MB of memory, and the first allocator in 4MB space do not need to lock the memory allocation, and the second can use the lock, So that more memory can be used to allocate
But the Jos seems to be different. Because the kernel continues to run after the memory mapping is turned on, you need to turn on the page mechanism, create a page table, and so on. However, when the page table is not yet established, the allocation of memory also needs to follow the page, so that after the page mechanism is enabled to smooth transition, so the use of boot_alloc such a function, and then set up a physical page memory table, the physical page management
This is the call graph, and you can see that only two places have been called Boot_alloc
Looking back at the last experiment, the first is the bootloader load kernel, the first instruction of the kernel starts from 0x010000c, in fact, the Jos system loads the address from the 0x0100000, and extends to the high address, before opening the memory map manually, The virtual address is the physical address, so the kernel is loaded in this place, then the mapping is turned on, and the virtual address 0xf0100000 maps to the 0x0100000 location.
But this simple mapping is not enough, the need to create a page mechanism, then the first thing to do is the physical memory allocator
- Boot_alloc function
The Boot_alloc function receives a parameter n, if the argument is 0, returns the address of the currently available free page, greater than 0, then allocates enough pages to load n bytes.
However, when Boot_alloc first runs, it also needs to initialize the first available idle address, which is quite concise in Jos, using the static local variable
This will be empty at the first run, and then it won't.
As for end, a picture can be seen clearly.
Elf format executable, BSS is a global variable that is not initialized, is loaded into the last part of memory, followed by the end tag
So the first time you run it, it actually points to the Nextfree. BSS back
And then it's going to be assigned.
Roundup is to find the nearest Nextfree+n address above nextfree can be divisible pgsize address, update Nextfree, and then return the result is ready
In the Mem_init, there is the following sentence
This call Boot_alloc generates a 4KB size space that is used to present the page table directory.
In other words, the actual state in memory should now be the following
- Mem_init function
This function is to establish the kernel address space, while the user space is not implemented
The main function is to probe how many pages of the current available memory, create the page table directory, and initialize the 1024*4096 byte at the highest address (that is, a page table can map the maximum address range) corresponding to the table directory entry, which points to the page table directory location, that is, The page table directory is stored in the user-accessible maximum virtual address, which is the following sentence
The next step is to establish a management mechanism for physical memory pages, using an array of pageinfo to manage each physical memory page
I actually used the new method, and not that the new method C standard branch does not support, this method itself can not be used in this, because new is in the heap memory to find a usable area, but now we need to do is obviously not the page table directory in the heap Ah, but to apply for space to do this thing
Looking at the design of PageInfo, it is important to note that reference counting is used
After allocating pages, the resulting memory status should be the following
and the actual kernel is running at the low address, so the following is shown
So the two blank places above are added to the list, including a small piece of the front and a section behind Pagedir and pages
- Page_Init function
The function is to initialize the physical memory page based on the memory graph used above. I started to look at this part of the time a little confused, was trapped in the implementation of the details, more and more dizzy, but later found that I forgot what is currently doing, why do this thing.
The current is to page all of the physical memory, and then determine which pages are currently occupied, which pages are idle, and connect the free pages to a single table.
The notes here are very clear, the available location is the white area in the image above, the middle part must be marked as already used
- Page_alloc function
This function returns a physical page that is currently idle and handles it accordingly.
It is important to note that the pageinfo of the corresponding page needs to be pp_link NULL to detect the problem of double free
- Page_free function
A physical page is recycled, but it needs to be noted that the reference number is 0 and that the Pp_link field must be empty, if the reference number is nonzero, there is currently a process using the page, if Pp_link is not empty, the description is already in the idle list, and the release is double free
Part2:virtual Memory
The C pointer actually corresponds to the offset entry in the virtual address
Unfortunately, Jos also abandoned the paragraph ....
All segments are start address 0, size limit is 0XFFFFFFFF
Once the kernel is started to boot the protection mode, all addresses are converted through the MMU, there is no way to directly use a linear address or physical address, so the address references are resolved to the virtual address, and then sent to the MMU to parse
Pointers, for example, are virtual addresses, so pointer in *pointer operations must be virtual addresses
Jos is a distinction between a virtual address and a physical address.
In the Jos operating system, it is sometimes necessary to know the physical memory, such as the Map page table
But above said, we do not know the actual physical address is how much, so Jos choose to map 0xf0000000 address all to 0 address, is to help Jos Read and write the physical memory area, in order to read and write a physical region, the current known physical address needs to be addr, Need to add addr to 0xf0000000, after the address map and then become the addr
Similarly, know the virtual address to solve the physical address, the direct reduction can be
Reference counting
For various reasons, the same physical page box may be mapped by more than one virtual page, in which case the PP_REF value is required, when this value becomes 0, it means that no program needs this memory, so it can be released
However, this reference count is typically equal to the number of times the physical page box appears in all page tables, that is, the number of processes that use the page, but generally only references to pages that are below Utop are counted
Does not include the page table above the Utop, because the page table above is built by Boot_alloc, belongs to the kernel, and should not be released at any time, so there is no
Page Table Management
Problems with TLB failure
TLB is designed for high-speed address translation, where a process's page table exists in both memory and TLB (partly), so that if the programmer modifies the page table, the page table in the TLB is inconsistent with the actual page table, which results in an incorrect translation of the address.
Therefore, in order to prevent the occurrence of this phenomenon, after the page table changes, you need to overload the CR3, so that the entire TLB data is invalidated, and then reloaded, or using the INVLPG command
Logical address-linear address-Physical Address note distinction
Before the page mapping mechanism, the system still uses the Segment address transformation, the logical address +base= linear address (here base is negative 0xf0000000), and this linear address is directly equal to the physical address
The page mapping mechanism deals with the transformation of the linear address to the physical address, the address that is obtained after the logical address is transformed, and cannot be confused
Pgdir_walk () function
This function I wrote for a long time, all feel written uncomfortable, turned back to the document, only to find that they understand not deep
In this diagram above, the page Table directory and table format are the same
The first 20 bits are the high 20 bits of the physical address, and if it is a page directory, the content is the high 20 bits of the address of the corresponding page table, and if it is a page table, then the actual page has a high 20-bit address
In addition, the kernel in the Middle Ages to deal with the virtual address, so need to wander
The main function of this function is to give a page table directory and virtual address, you want to return to the table of Level two page table item of the corresponding pointer
There are a few places to be aware of
- Both the page table directory and the page table are the physical addresses, and the actual code operation is the virtual address, this must be converted, such as the Memset function in the code above, already in the two-level page table pointer, must use the virtual address
- After getting the page table directory, be sure to check if it already exists, and if it doesn't exist, decide whether to wear a new page table based on the value of Create
- If you create a new page table, insert into the page table directory, you need to pay attention to the full permission, because the page table directory of a table item corresponding to the 1024 physical pages, the control permissions of these physical pages may be different, so the current can do is not its read and write permissions to make any restrictions, but in the page table to restrict
boot_map_region function
The functions and implementations of this function are as follows
For a given virtual address, use the Pgdir_walk function implemented above to find the table entry for the corresponding virtual page, and then populate the table entry content.
Page_lookup function
The function is given a virtual address and returns a struct that describes the physical address that the virtual address points to
Page_remove function
This function is to de-map a given virtual address to the corresponding physical page
The issues to consider when releasing a map are: Reference counting needs to be maintained, reference count is 0, then the physical page can be freed.
At first I thought that only the reference count of the physical page was 0, the TLB failed function would need to be called, but then it was obviously wrong, because the physical page needs to be mapped to the corresponding virtual address in a process space, as long as the contents of the page table in the process have changed. The TLB will fail.
Page_insert function
Map a virtual address to an actual physical page
The implementation of this function is very careful to do, because the function of the call may have a number of cases, if the same structure, the same virtual address multiple calls to do, this time obviously can not be processed repeatedly, especially the reference count; In addition, if the address has been mapped to a physical page, Then you need to remove it.
The above several functions correspond to the page map often need to use, such as a given virtual Address return page table entries, de-mapping, add mapping and so on, have to say, here a few functions of the design is very superb, not only the function is perfect, and each part of the function is clear, separate reasonable
Part3:kernel address Space
Jos divides the memory into two parts, a user space, a virtual low address, and a kernel space running in a high virtual address space
Split Line is Ulim
To protect the kernel's code and data, you need to add permission restrictions on the page so that user-space code can only access the user-space memory, so that the user's code generates bugs that do not harm the kernel space
Within the scope of [Utop, Ulim], both user code and kernel code are accessible, but neither can be written. This part of the space is set up primarily to allow users to read some of the data structures in the kernel
Notice the change in permissions
This part is to complete the code within the Mem_init function, which is actually using the previously implemented boot_map_region to map the given virtual address to the physical address.
The first is the mapping of the physical page table array, which is the user does not have permission to operate, the kernel can read and write
The actual address of this part is the kernel code and data area and the section after the page table directory area, want to map from the virtual address pages
Next is the kernel stack mapping
The virtual address of the kernel stack is [kstacktop-kstksize, Kstacktop], and the physical memory address mapped to is Bootstack
This is done with the protection page, that is, after the specified stack size, to prevent the memory portion of the invalid, so when the stack overflow when the error, rather than destroy the memory of the lower address
Finally, map the base address of the kernel to 0 addresses.
After you've set up the above, you can start the page mechanism.
The final mapping relationship is as follows
I'm tired of writing this experiment ....
MIT 6.828-jos-xv6-lab2:memory Management