Update on chapter 3 notes.
This commit is contained in:
parent
c8b60efd77
commit
4fdf4028a4
1 changed files with 60 additions and 5 deletions
|
@ -87,7 +87,7 @@ XV6 kernel page table:
|
||||||
to prevent memory corruption from stack overflows
|
to prevent memory corruption from stack overflows
|
||||||
|
|
||||||
Virtual memory functions:
|
Virtual memory functions:
|
||||||
- walk: find PTE for a virt@
|
- walk: find PTE for a virt@ (can allocate a PTE in a page table)
|
||||||
- mappages: install PTEs for new mappings
|
- mappages: install PTEs for new mappings
|
||||||
- kvm_* = kernel virtual memory functions (kernel page table)
|
- kvm_* = kernel virtual memory functions (kernel page table)
|
||||||
- uvm_* = same but for a user process
|
- uvm_* = same but for a user process
|
||||||
|
@ -99,18 +99,73 @@ Virtual memory functions:
|
||||||
- kvmmake creates a direct-map page table for the kernel
|
- kvmmake creates a direct-map page table for the kernel
|
||||||
1. create the root kernel page table with a call to `kalloc`
|
1. create the root kernel page table with a call to `kalloc`
|
||||||
(kalloc provides a pointer to a page, which is the type `pagetable_t`)
|
(kalloc provides a pointer to a page, which is the type `pagetable_t`)
|
||||||
2. call kvmmap multiple times to set a few direct-map pages
|
2. call kvmmap (an overlay of `mappages` to handle errors) multiple times to set a few direct-map pages
|
||||||
kvmmap adds mapping to the kernel page table (when booting only), doesn't flush TLB or enable paging
|
kvmmap adds mapping to the kernel page table (when booting only), doesn't flush TLB or enable paging
|
||||||
mapped stuff:
|
mapped stuff:
|
||||||
uart registers, virtio mmio disk interface, PLIC, kernel text and data
|
uart registers, virtio mmio disk interface, PLIC, kernel text and data
|
||||||
and trampoline (for trap entry/exit) is mapped to the highest virtual address in the kernel
|
and trampoline (for trap entry/exit) is mapped to the highest virtual address in the kernel
|
||||||
3. proc_mapstacks
|
3. proc_mapstacks allocates a kernel stack for each process in the `proc` (static) array of processes in `proc.c`
|
||||||
|
each kernel stack page is placed under the TRAMPOLINE kernel page with a following guard page (invalid page)
|
||||||
|
|
||||||
|
side note: the function is complex for no reason, it uses pointer arithmetics just to get an index (0-7)
|
||||||
|
|
||||||
|
TRAMPOLINE is a macro to get the phy@ of the trampoline page (MAXVA - PGSIZE)
|
||||||
|
KSTACK(p) is a macro to place a kernel page bellow the trampoline page with a guard page
|
||||||
|
KSTACK(p) = (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
|
||||||
|
|
||||||
|
TRAMPOLINE & KSTACK are macros in memlayout.h and are use in proc_mapstacks
|
||||||
|
- main calls kvminithart which sets satp to the kernel root page table so the CPU can start using it
|
||||||
|
- each CPU caches PTEs in a Translation Look-aside Buffer (TLB)
|
||||||
|
=> when xv6 changes a page table it must tell the CPU to invalidate cached entry in the TLB
|
||||||
|
=> RISC-V has an `sfence.vma` instruction to flush the current CPU's TLB
|
||||||
|
=> `kvminithart` uses it after initializing sapt
|
||||||
|
=> `sfence.vma` is also called before setting sapt
|
||||||
|
"to ensure that preceding updates to the page table have completed,
|
||||||
|
and ensures that preceding loads and stores use the old page table,
|
||||||
|
not the new one"
|
||||||
|
=> `TRAMPOLINE` page uses it before entering user space
|
||||||
|
=> RISC-V CPUs can have different TLBs for different address spaces
|
||||||
|
=> avoid flushing an entire TLB
|
||||||
|
=> xv6 doesn't use this feature
|
||||||
|
|
||||||
|
Physical memory management consists of handling memory pages from the `kmem.freelist` table.
|
||||||
|
An allocation is materialized by removing an entry from this table,
|
||||||
|
freeing a page is about adding back the page to the list.
|
||||||
|
|
||||||
|
sbrk is implemented with the function `growproc` (in prog.c) which calls either uvmalloc or uvmdealloc.
|
||||||
|
|
||||||
Function signatures (for reference):
|
Function signatures (for reference):
|
||||||
void kvminit(void); // set the kernel root page table
|
void kvminit(void); // set the kernel root page table
|
||||||
pagetable_t kvmmake(void); // create the kernel page table
|
pagetable_t kvmmake(void); // create the kernel page table
|
||||||
void kvmmap(pagetable_t, uint64 virt@, uint64 phy@, uint64 sz, int perm); // add PTEs to the kernel page table
|
void kvmmap(pagetable_t, uint64 virt@, uint64 phy@, uint64 sz, int perm); // add PTEs to the kernel page table
|
||||||
(this is only a call to mappages + a call to "panic" in case of an error)
|
=> `kvmmap` is a simple overlay for `mappages` (automatically calls `panic` if an error occurs)
|
||||||
int mappages(pagetable_t, uint64 virt@, uint64 size, uint64 phy@, int perm); // create PTEs
|
int mappages(pagetable_t, uint64 virt@, uint64 size, uint64 phy@, int perm); // create PTEs
|
||||||
pte_t * walk(pagetable_t pagetable, uint64 va, int alloc); // virt@ -> PTE
|
=> `kvmmap` is a simple overlay for this function (automatically calls `panic` if an error occurs)
|
||||||
|
=> uses walk to find a PTE based on a virt@ (`walk` can also allocate a page in a page table)
|
||||||
|
pte_t * walk(pagetable_t pagetable, uint64 va, int alloc); // virt@ -> PTE (can allocate it if 'alloc' is set)
|
||||||
|
=> return the address of the PTE in the lowest layer in the tree
|
||||||
uint64 walkaddr(pagetable_t pagetable, uint64 va); // virt@ -> phy@
|
uint64 walkaddr(pagetable_t pagetable, uint64 va); // virt@ -> phy@
|
||||||
|
void proc_mapstacks(pagetable_t kpgtbl); // allocate a kernel stack for a process
|
||||||
|
|
||||||
|
|
||||||
|
3.8 Code: exec
|
||||||
|
|
||||||
|
exec = syscall replacing a process's user address space with data read from a file
|
||||||
|
= related files: kernel/{elf.h,exec.c}
|
||||||
|
|
||||||
|
1. open a file with `namei`
|
||||||
|
2. read ELF header (see kernel/elf.h for more info) matching structure `elfhdr`
|
||||||
|
3. read subsequent ELF section headers corresponding to the `proghdr` structure
|
||||||
|
each of them describing a part of the application that must be loaded into memory
|
||||||
|
xv6 only has two program section headers: instructions and data
|
||||||
|
|
||||||
|
How exec works
|
||||||
|
|
||||||
|
1. check if the file actually is an ELF binary
|
||||||
|
2. allocate a new page table with no user mapping with `proc_pagetable` (kernel/exec.c:49)
|
||||||
|
3. allocate memory for each ELF segment with `uvmalloc` (kernel/exec.c:65)
|
||||||
|
4. load each segment with `loadseg` (kernel/exec.c:10)
|
||||||
|
`loadseg` uses `readi` to read from the file
|
||||||
|
`loadseg` uses `walkaddr` to find the phy@ of the allocated memory at which to write ELF segments
|
||||||
|
|
||||||
|
To read sections from a binary: objdump -p file
|
||||||
|
|
Loading…
Add table
Reference in a new issue