# Memory Management Walk Through

## Page Tables

Page tables determine what memory address mean, what part of physical memory can be accessed.

A page table gives the operating system control over virtual to-physical address translations at the granularity of aligned chunks of 4096 (2^12) bytes.

{% content-ref url="/pages/-M4buQB1aiw0Dq3OY-Lw" %}
[Page Table](/build_a_os/virtual-memory/page-table.md)
{% endcontent-ref %}

### Creating kernel address space

See process allocation section.

### Allocate a kernel stack for each process

`procinit` (kernel/proc.c:24), which is called from `main`, allocates a kernel stack for each process. It maps each stack at the virtual address generated by KSTACK, which leaves room for the invalid stack-guard pages. `kvmmap` adds the mapping PTEs to the kernel page table, and the call to `kvminithart`reloads the kernel page table into `satp` so that the hardware knows about the new PTEs.

```c
void
procinit(void)
{
  struct proc *p;

  initlock(&pid_lock, “nextpid”);
  for(p = proc; p < &proc[NPROC]; p++) {
      initlock(&p->lock, “proc”);

      // Allocate a page for the process’s kernel stack.
      // Map it high in memory, followed by an invalid
      // guard page.
      char *pa = kalloc();
      if(pa == 0)
        panic(“kalloc”);
      uint64 va = KSTACK((int) (p - proc));
      kvmmap(va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
      p->kstack = va;
  }
  kvminithart();
}
```

```c
// map kernel stacks beneath the trampoline,
// each surrounded by invalid guard pages.
#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
```

Diagram of kernel stack address space

![](/files/-M4bxTwvVlfiUW5jnfD7)

Stack grows downwards.

### TLB cache

Each RISC-V core caches page table entries in a Translation Look-aside Buffer (TLB), and when xv6 changes a page table, it must tell the CPU to invalidate corresponding cached TLB entries.

The RISC-V has an instruction `sfence.vma` that flushes the current core’s TLB. xv6 executes `sfence.vma` in `kvminithart` after reloading the `satp` register, and in the trampoline code that switches to a user page table before returning to user space (kernel/trampoline.S:79).

## Physical Memory Allocation

The allocator sometimes treats addresses as integers in order to perform arithmetic on them (e.g., traversing all pages in `freerange`), and sometimes uses addresses as pointers to read and write memory (e.g., manipulating the `run` structure stored in each page).

{% content-ref url="/pages/-M4buQ2FJD5qIfirC7BC" %}
[xv6 buddy allocator](/build_a_os/virtual-memory/untitled-1.md)
{% endcontent-ref %}

## Process Address Space

TODO

## How `exec` works

{% content-ref url="/pages/-M4fDUURc-qZ9I\_ytOp8" %}
[How exec() works](/build_a_os/traps-and-interrupts/how-exec-works.md)
{% endcontent-ref %}

1. Find `inode` by path
2. Check ELF header
3. Load program by memory. `uvmalloc` to allocate new size.
4. `loadseg` load file to memory address at `ph.vaddr`. Note: Exec loads bytes from the ELF file into memory at addresses specified by the ELF file.
5. Allocate 2 pages. 2nd one is user stack.
6. Push args to stack. Prepare `ustack` to save each argument with its address.
7. Push the array of argv\[] pointers (`ustack`) to stack.
8. Set `sp` to `a1`.
9. Commit to user image. Free old process’ page table.
10. Set `epc`, `sp`, `sz`.
11. `return argc` which set `argc` in reg `a0`. Now we have `main(args, args)` from `entry, a0, a1`.

### How stack look after pushing args?

![](/files/-M4by0QmCzfNz-va-U6G)

### Find PA from VA

```c
  uint64 off = va % PGSIZE;
  pte_t *pte;
  uint64 pa;

  pte = walk(kernel_pagetable, va, 0);
  pa = PTE2PA(*pte);
  return pa+off;
```

This code is to find a physical address from virtual address. The PA from `*pte` is at start of page. We also need to **add offset to it** when return.

## Exercises

Explain how the following functions work:

```c
int     mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm);
uint64  walkaddr(pagetable_t pagetable, uint64 va);

static pte_t *
walk(pagetable_t pagetable, uint64 va, int alloc)
```

```c
int     copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len);
int     copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len);
```

```c
void    uvmunmap(pagetable_t pagetable, uint64 va, uint64 size, int do_free);
void    freewalk(pagetable_t pagetable)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiayingp.gitbook.io/build_a_os/virtual-memory/untitled.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
