MIT Jos lab2
You can see this code in/Kern/kdebug. C. Follow the section _ stab_begin _ below.
_ Stab_begin _ stab_end _ is defined in/Kern/kernel. lD.
The main contents of kernel. LD are as follows:
ENTRY(_start)SECTIONS{/* Link the kernel at this address: "." means the current address */. = 0xF0100000;/* AT(...) gives the load address of this section, which tells the boot loader where to load the kernel in physical memory */.text : AT(0x100000) {*(.text .stub .text.* .gnu.linkonce.t.*)}揭示了内核被加载到0x100000线性地址处PROVIDE(etext = .);/* Define the 'etext' symbol to this value */.rodata : {*(.rodata .rodata.* .gnu.linkonce.r.*)}/* Include debugging information in kernel memory */.stab : {PROVIDE(__STAB_BEGIN__ = .);//这里也定义了__STAB_BEGIN__等变量是0xF0100000*(.stab);PROVIDE(__STAB_END__ = .);BYTE(0)/* Force the linker to allocate space for this section */}.stabstr : {PROVIDE(__STABSTR_BEGIN__ = .);*(.stabstr);PROVIDE(__STABSTR_END__ = .);BYTE(0)/* Force the linker to allocate space for this section */}/* Adjust the address for the data segment to the next page */. = ALIGN(0x1000); //把数据段和bss段放到下一页/* The data segment */.data : {*(.data)}PROVIDE(edata = .);.bss : {*(.bss)}PROVIDE(end = .); //下一页的起始就是kernel代码段的结束位置/DISCARD/ : {*(.eh_frame .note.GNU-stack)}}
First, you must understand that struct stab is a struct used to record debugging information.
I made an introduction to struct stab: http://blog.csdn.net/cinmyheart/article/details/39972701
The comments of kdebug. C are also very clear.
// stab_binsearch(stabs, region_left, region_right, type, addr)////Some stab types are arranged in increasing order by instruction//address. For example, N_FUN stabs (stab entries with n_type ==//N_FUN), which mark functions, and N_SO stabs, which mark source files.////Given an instruction address, this function finds the single stab//entry of type 'type' that contains that address.////The search takes place within the range [*region_left, *region_right].//Thus, to search an entire set of N stabs, you might do:////left = 0;//right = N - 1; /* rightmost stab *///stab_binsearch(stabs, &left, &right, type, addr);////The search modifies *region_left and *region_right to bracket the//'addr'. *region_left points to the matching stab that contains//'addr', and *region_right points just before the next stab. If//*region_left > *region_right, then 'addr' is not contained in any//matching stab.////For example, given these N_SO stabs://Index Type Address//0 SO f0100000//13 SO f0100040//117 SO f0100176//118 SO f0100178//555 SO f0100652//556 SO f0100654//657 SO f0100849//this code://left = 0, right = 657;//stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);//will exit setting left = 118, right = 554.//
This stab_binsearch function is called by the debuginfo_eip function, which exists to fill in the struct eipdebuginfo struct.
Keep this in mind. The debuginfo_eip is used to fill in the struct eipdebuginfo struct, so you will not feel lost when supplementing debuginfo_eip.
The above should be part of the old version of the experiment
In fact, the following is the first exercise 1 in version 14? It doesn't matter...
Exercise 1. In the file Kern/pmap. C, you must implement code for the following functions (probably in the order given ).
boot_alloc()mem_init() (only up to the call to check_page_free_list(1) )page_init()page_alloc()page_free()
Check_page_free_list () and check_page_alloc () test your physical page allocator. you shoshould boot Jos and see whether check_page_alloc () Reports success. fix your code so that it passes. you may find it helpful to add your own assert () s to verify that your assumptions are correct.
First, clear the Memory Distribution
It can be seen from/boot/Main. C that the elf header of the IMG of the kernel is read to the physical address 0x10000.
Here we can review a small question in Jos lab1. At that time, I asked how the bootloader could be accurate. How can I read the kernle image to the corresponding address?
Here is the role of Main. C.
Here, eight sectsize values are read to elfhdr, that is, 0x10000, from the comment // is this a valid elf? Start, the parts under bootmain start to read the kernel image to the physical memory pH-> p_pa
The corresponding disassembly knows to add the value (52) at 0x1001c and 0x10000 to get the pH, that is, the pointer to the struct proghdr.
This is the iron 0x100000, pH-> p_pa value, here the kernel image will be 0x100000 at the physical memory pH-> p_pa
This is the starting physical address of the kernel determined by kernel. lD.
52 is the offset of e_phoff In the struct proghdr, and 12 is the offset of p_pa In the struct proghdr.
Then, the last sentence of bootmain jumps to 0x0000c and runs the entry. s Code. If you don't remember it, go to Lab 1.
The memory distribution is clear.
Note that after the kernel ends, it is free memory, and pgdir is first stored in free memory. This memory is also applied by boot_alloc.
The experiment requires us to fill in the function boot_alloc ()
4 K page alignment
Required to open up the pageinfo space of the npages struct, which is directed by pages to this space
Then we start page_init ().
In page_init (), use the global intermediate variable page_free_list to point the pp_link of the next page to the previous page, so all pages are linked here.
What effect will it achieve? See the following figure.
Mark the colored (blue, red) part as used, and the white part as idle
voidpage_init(void){// The example code here marks all physical pages as free.// However this is not truly the case. What memory is free?// 1) Mark physical page 0 as in use.// This way we preserve the real-mode IDT and BIOS structures// in case we ever need them. (Currently we don't, but...)// 2) The rest of base memory, [PGSIZE, npages_basemem * PGSIZE)// is free.// 3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM), which must// never be allocated.// 4) Then extended memory [EXTPHYSMEM, ...).// Some of it is in use, some is free. Where is the kernel// in physical memory? Which pages are already in use for// page tables and other data structures?//// Change the code to reflect this.// NB: DO NOT actually touch the physical memory corresponding to// free pages!size_t i;uint32_t pa;page_free_list = NULL;for (i = 0; i < npages; i++) {if(i == 0){pages[0].pp_ref = 1;pages[0].pp_link = NULL;continue;}else if(i < npages_basemem){pages[i].pp_ref = 0;pages[i].pp_link = page_free_list;page_free_list = &pages[i];}else if(i <= (EXTPHYSMEM/PGSIZE) || i < (((uint32_t)boot_alloc(0) - KERNBASE) >> PGSHIFT)){pages[i].pp_ref++;pages[i].pp_link = NULL;}else{pages[i].pp_ref = 0;pages[i].pp_link = page_free_list;page_free_list = &pages[i];}pa = page2pa(&pages[i]);if((pa == 0 || (pa >= IOPHYSMEM && pa <= ((uint32_t)boot_alloc(0) - KERNBASE) >> PGSHIFT )) && (pages[i].pp_ref == 0)){cprintf("page error: i %d\n",i);}}}
The implementation of the page_alloc function is to release a free page in the current free list, and then update page_free_list so that TA can point to the next free page.
struct PageInfo *page_alloc(int alloc_flags){struct Page* pp = NULL;if(!page_free_list){return NULL;}pp = page_free_list;page_free_list = page_free_list->pp_link;if(alloc_flags & ALLOC_ZERO){memset(page2kva(pp),0,PGSIZE);}return pp;}
The corresponding page_free is to add the page described by PP to the Free List, making pp the latest page_free_list.
voidpage_free(struct PageInfo *pp){// Fill this function in// Hint: You may want to panic if pp->pp_ref is nonzero or// pp->pp_link is not NULL.assert(pp->pp_ref == 0 || pp->pp_link == NULL);pp->pp_link = page_free_list;page_free_list = pp;}
Pgdir_walk is a key function.
First, it is clear that pde_tpte_t is the physical memory address described.
Is the organization form of page Directory and page table
pte_t *pgdir_walk(pde_t *pgdir, const void *va, int create){//pgdir 本身是虚拟地址 解引用得到的是page directory的物理地址(QAQ 多么痛的领悟~)pde_t *pde = NULL;pte_t *pgtable = NULL;struct PageInfo *pp;pde = &pgdir[PDX(va)];if(*pde & PTE_P){pgtable = (KADDR(PTE_ADDR(*pde)));}else{if(!create || !(pp = page_alloc(ALLOC_ZERO)) || !(pgtable = (pte_t*)page2kva(pp))){return NULL;}pp->pp_ref++;*pde = PADDR(pgtable) | PTE_P |PTE_W | PTE_U;}return &pgtable[PTX(va)];}
The create flag is 1. If the page to which the current va address belongs does not exist, apply to open this page,
If the "Create" flag is 0, only query whether the page to which the VA address belongs exists. If yes, return the entry address of the corresponding page table. If no page exists, return null.
Boot_map_region this function maps the region of the Virtual Address [VA, VA + size) to the memory starting with the physical address Pa.
static voidboot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm){uintptr_t va_next = va;physaddr_t pa_next = pa;pte_t * pte = NULL;//page table entranceROUNDUP(size,PGSIZE);//page alignassert(size%PGSIZE == 0 || cprintf("size:%x \n",size));int temp = 0;for(temp = 0;temp < size/PGSIZE;temp++){pte = pgdir_walk(pgdir,va_next,1);if(!pte){return;}*pte = PTE_ADDR(pa_next) | perm | PTE_P;pa_next += PGSIZE;va_next += PGSIZE;}}
The page_lookup function checks whether the virtual page of the VA virtual address exists.
Null is returned if no data exists,
There is a pointer to the description structure pageinfo describing the virtual address associated with the physical memory page... (The pageinfo structure is only used to describe the physical memory page)
Do not check function parameters
struct PageInfo *page_lookup(pde_t *pgdir, void *va, pte_t **pte_store){pte_t* pte = pgdir_walk(pgdir,va,0);if(!pte){return NULL;}*pte_store = pte;return pa2page(PTE_ADDR(*pte));}
Familiarize yourself with this
Http://blog.csdn.net/cinmyheart/article/details/39994769
Otherwise, the code of the last line of the following function is not clear.
Page_remove: How does one clear the virtual memory page where va is located? Set the page table entrance of the physical page associated with this virtual page to null. (the original page table entrance obtained by unreferencing is the physical page address)
voidpage_remove(pde_t *pgdir, void *va){pte_t* pte = pgdir_walk(pgdir,va,0);pte_t** pte_store = &pte;struct PageInfo* pp = page_lookup(pgdir,va,pte_store);if(!pp){return ;}page_decref(pp);**pte_store = 0; //关键一步tlb_invalidate(pgdir,va);}
Page_insert associates physical pages described by PP with virtual address va
If the Virtual Memory Page of VA does not exist, create 1 for pgdir_walk to create this virtual page.
If the virtual memory page where va is located exists, cancel the association between the virtual memory page of the current VA and the previous physical page, and create a new physical page contact for va-the physical page described by PP
intpage_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm){pte_t* pte = pgdir_walk(pgdir,va,0);physaddr_t ppa = page2pa(pp);if(pte){if(*pte & PTE_P){page_remove(pgdir,va);//取消va与之物理页之间的关联}if(page_free_list == pp){page_free_list = page_free_list->pp_link;//update the new free_list header}}else{pte = pgdir_walk(pgdir,va,1);if(!pte){return -E_NO_MEM;}}*pte = page2pa(pp) | PTE_P | perm; //建立va与pp描述物理页的联系pp->pp_ref++;tlb_invalidate(pgdir,va);return 0;}
Part 2: Virtual Memory
Finally, Part 2 has arrived ....
Virtual, linear, and physical addresses
In x86 terminology, a virtual address consists of a segment selector and an offset within the segment.
Linear address is what you get after segment translation but before page translation. A physical address
Is what you finally get after both segment and page translation and what ultimately goes out on
Hardware bus to your RAM
A c pointer is the "offset" component of the virtual address.
Haha, I wrote the C language for a while. What is the essence of the pointer? intra-segment offset
From code executing on the CPU, once we're in Protected Mode (which we entered first thing in Boot/boot. s), there's no way to directly use a linear or physical address. all memory references are interpreted as virtual addresses and translated by the MMU, which means all pointers in C are virtual addresses.
* Dereferencing is performed on virtual addresses. If you dereference a physical address, the hardware regards TA as a virtual address.
If you cast a physaddr_t to a pointer and dereference it, you may be able to load and store to the resulting address (the hardware will interpret it as a virtual address ), but you probably won't get the memory location you intended.
This problem is also a little too simple... It must be uintptr_t :-)
Part 3: Kernel address space
Jos divides the processor's 32-bit linear address space into two parts. user environments (processes ),
Which we will begin loading and running in lab 3, will have control over the layout and contents of
Lower part, while the kernel always maintains complete control over the upper part.
Note that the following ulim is the dividing line. The ulim is the kernel address space, and the above is the user space.
This page layout indicates the virtual memory layout that is displayed after address translation is enabled, regardless of the operating system or user program.
The operating system and user program use the same page Directory and page table.
Note that the pointer to function parameters in the kernel cannot be directly returned for "regular type check". I am using this bug .... from pm to now (pm)
First release the previous part, and then the challenge part waiting for update.
MIT operating system experiment mit Jos lab2