AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
i386.c File Reference

i386: page tables, with 32-bit paging (two levels, 4 KiB pages). More...

#include <core/arch.h>
#include <core/panic.h>
#include <core/printk.h>
#include <core/string.h>
#include <core/system.h>
#include <cpu/cpu.h>
#include <sys/cpu.h>
#include <mm/pmap.h>
#include <mm/buddy.h>
#include <mm/mm.h>
#include <mm/vm.h>

Go to the source code of this file.

Macros

#define PG_PRESENT   0x001
#define PG_WRITE   0x002
#define PG_USER   0x004
#define PG_PWT   0x008
#define PG_PCD   0x010
#define PG_ADDR(e)
#define VDIR(va)
#define VTBL(va)
#define KERNEL_PDE   768
#define cur_pmap   (curcpu()->arch.pmap)

Functions

static uint32_t * table (paddr_t paddr)
 Returns a page table's kernel address, in the direct map.
static paddr_t table_alloc (void)
 Allocates an empty page table.
static paddr_t table_alloc_boot (void)
 Allocates a page table that the kernel can't boot without: it panics if there is no memory.
static void table_free (paddr_t paddr)
 Frees a page table.
static uint32_t * pte_get (struct pmap *pmap, vaddr_t va, int make)
 Returns the page table entry that maps va in pmap.
struct pmap * pmap_switch (struct pmap *pmap)
 Switches this CPU to an address space's page tables.
void pmap_init (void)
 Takes over the boot page tables as the kernel's, at boot, and makes the page tables of the kernel's half, which every address space shares.
static struct pmap * pmap_alloc (void)
 Allocates a struct pmap.
static void pmap_release (struct pmap *pmap)
 Frees an address space's page directory, once no CPU has it loaded.
struct pmap * pmap_create (void)
 Makes the page tables of a new address space: an empty user half, and the kernel's half, which every address space shares.
void pmap_incref (struct pmap *pmap)
 Adds a reference to an address space's page tables.
void pmap_decref (struct pmap *pmap)
 Drops a reference to an address space's page tables, freeing them with the last one.
static uint32_t pte_flags (uint32_t flags)
 Returns the page table entry bits for the VM_* flags flags.
int pmap_add (struct pmap *pmap, vaddr_t va, paddr_t pa, uint32_t flags)
 Maps a page in an address space, replacing what was mapped there.
void pmap_remove (struct pmap *pmap, vaddr_t sva, vaddr_t eva)
 Unmaps the pages of a range of an address space, and flushes them from the TLBs that may have them.
void pmap_remove_all (struct pmap *pmap)
 Unmaps the whole user half of an address space, and frees its page tables.
void pmap_protect (struct pmap *pmap, vaddr_t sva, vaddr_t eva, uint32_t prot)
 Changes the permissions of the mapped pages of a range of an address space.
void pmap_copy (struct pmap *dst_map, struct pmap *src_map, vaddr_t dst_addr, size_t len, vaddr_t src_addr)
 Does nothing: the generic pmap_copy() isn't used on x86.
void pmap_update (struct pmap *pmap)
 Makes the changes to an address space's page tables take effect.
void pmap_page_copy (paddr_t src, paddr_t dst)
 Copies a page of physical memory to another.
void pmap_page_protect (struct vm_page *pg, uint32_t flags)
 Not implemented on x86 (it does nothing), and nothing uses it.
int pmap_clear_modify (struct vm_page *pg)
 Not implemented on x86, and nothing uses it.
int pmap_clear_reference (struct vm_page *pg)
 Not implemented on x86, and nothing uses it.
int pmap_is_modified (struct vm_page *pg)
 Not implemented on x86, and nothing uses it.
int pmap_is_referenced (struct vm_page *pg)
 Not implemented on x86, and nothing uses it.
paddr_t arch_page_get_mapping (struct pmap *pmap, vaddr_t vaddr)
 Finds the page mapped at a virtual address of an address space.
int arch_page_unmap (vaddr_t vaddr)
 Unmaps a page of the running CPU's address space.
int arch_mm_page_fault (vaddr_t vaddr, int err)
 Handles a page fault: turns the CPU's error code into the kernel's PF_* flags, and calls mm_page_fault() (mm/i386.c, mm/x86_64.c).
int pmap_page_read (paddr_t paddr, off_t off, size_t size, void *buf)
 Reads from a page of physical memory, through the kernel's mapping.
int pmap_page_write (paddr_t paddr, off_t off, size_t size, void *buf)
 Writes to a page of physical memory, through the kernel's mapping.
static void * phys_window_map (uintptr_t paddr, size_t size, uint32_t flags)
 Maps a range of physical memory in the window, with flags.
void * arch_phys_map (uintptr_t paddr, size_t size)
 Returns a kernel address for a range of physical memory: its address in the direct map if it's there, or a mapping made in a window.
void * arch_mmio_map (uintptr_t paddr, size_t size)
 Maps a device's registers into the kernel's address space, uncached (memory-mapped I/O).

Variables

static struct pmap k_pmap
static vaddr_t phys_window_next = ARCH_PHYS_WINDOW_BASE

Detailed Description

i386: page tables, with 32-bit paging (two levels, 4 KiB pages).

RAM is mapped from 0xC0000000 (ARCH_DMAP_BASE, the direct map, 768 MiB at most), and page tables and pages are reached there. Every address space has its own page directory. The page tables of the kernel's half (from KERNEL_PDE) are all made at boot and shared by every directory, so the kernel's mappings are the same in every address space, and a directory's kernel entries never change. Switching address spaces is loading CR3.

References: [1] - Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 3 (System Programming Guide), Chapter 4 (Paging)

Definition in file i386.c.

Macro Definition Documentation

◆ cur_pmap

#define cur_pmap   (curcpu()->arch.pmap)

Definition at line 50 of file i386.c.

◆ KERNEL_PDE

#define KERNEL_PDE   768

Definition at line 45 of file i386.c.

Referenced by pmap_create(), pmap_init(), pmap_remove_all(), and pte_get().

◆ PG_ADDR

#define PG_ADDR ( e)
Value:
((e) & ~(uint32_t) PAGE_MASK)
#define PAGE_MASK
Definition system.h:8
unsigned int uint32_t
Definition stddef.h:22

Definition at line 39 of file i386.c.

Referenced by arch_page_get_mapping(), pmap_init(), pmap_protect(), pmap_remove_all(), pte_get(), pte_get(), and tables_free().

◆ PG_PCD

#define PG_PCD   0x010

Definition at line 37 of file i386.c.

Referenced by pte_flags(), and pte_flags().

◆ PG_PRESENT

#define PG_PRESENT   0x001

Definition at line 33 of file i386.c.

◆ PG_PWT

#define PG_PWT   0x008

Definition at line 36 of file i386.c.

Referenced by pte_flags(), and pte_flags().

◆ PG_USER

#define PG_USER   0x004

Definition at line 35 of file i386.c.

Referenced by pte_flags(), pte_flags(), pte_get(), and pte_get().

◆ PG_WRITE

#define PG_WRITE   0x002

Definition at line 34 of file i386.c.

◆ VDIR

#define VDIR ( va)
Value:
(((va) >> 22) & 0x3FF)

Definition at line 41 of file i386.c.

Referenced by pte_get().

◆ VTBL

#define VTBL ( va)
Value:
(((va) >> 12) & 0x3FF)

Definition at line 42 of file i386.c.

Referenced by pte_get().

Function Documentation

◆ arch_mm_page_fault()

int arch_mm_page_fault ( vaddr_t vaddr,
int err )

Handles a page fault: turns the CPU's error code into the kernel's PF_* flags, and calls mm_page_fault() (mm/i386.c, mm/x86_64.c).

Parameters
vaddrthe address that faulted (CR2)
errthe CPU's error code
Returns
0 if the fault is resolved, or -EFAULT if it isn't

Definition at line 449 of file i386.c.

◆ arch_mmio_map()

void * arch_mmio_map ( uintptr_t paddr,
size_t size )

Maps a device's registers into the kernel's address space, uncached (memory-mapped I/O).

Parameters
paddrthe registers' physical address
sizetheir size, in bytes
Returns
their kernel address, or NULL if they couldn't be mapped

Definition at line 529 of file i386.c.

References arch_mmio_map(), phys_window_map(), VM_KRW, and VM_NOCACHE.

◆ arch_page_get_mapping()

paddr_t arch_page_get_mapping ( struct pmap * pmap,
vaddr_t vaddr )

Finds the page mapped at a virtual address of an address space.

Parameters
pmapthe address space's page tables
vaddrthe virtual address
Returns
the page's physical address, or 0 if none is mapped there

Definition at line 423 of file i386.c.

References arch_page_get_mapping(), PG_ADDR, PG_PRESENT, and pte_get().

◆ arch_page_unmap()

int arch_page_unmap ( vaddr_t vaddr)

Unmaps a page of the running CPU's address space.

Parameters
vaddrthe page's virtual address, page-aligned
Returns
0, or -EINVAL if it isn't page-aligned

Definition at line 436 of file i386.c.

References arch_page_unmap(), cur_pmap, PAGE_MASK, PAGE_SIZE, and pmap_remove().

Referenced by arch_page_unmap().

◆ arch_phys_map()

void * arch_phys_map ( uintptr_t paddr,
size_t size )

Returns a kernel address for a range of physical memory: its address in the direct map if it's there, or a mapping made in a window.

Parameters
paddrthe range's physical address
sizeits size, in bytes
Returns
its kernel address, or NULL if it couldn't be mapped

Definition at line 518 of file i386.c.

References arch_phys_map(), PHYS2VIRT, phys_window_map(), and VM_KRW.

◆ phys_window_map()

void * phys_window_map ( uintptr_t paddr,
size_t size,
uint32_t flags )
static

Maps a range of physical memory in the window, with flags.

Returns its kernel address, or NULL if there's no room left in the window, or no memory for a page table. The window's addresses are never reused.

Definition at line 491 of file i386.c.

References k_pmap, NULL, PAGE_ALIGN, PAGE_ROUND, PAGE_SIZE, phys_window_map(), phys_window_next, pmap_add(), and pmap_remove().

Referenced by arch_mmio_map(), arch_phys_map(), and phys_window_map().

◆ pmap_add()

int pmap_add ( struct pmap * pmap,
vaddr_t va,
paddr_t pa,
uint32_t flags )

Maps a page in an address space, replacing what was mapped there.

Parameters
pmapthe page tables (an address in the kernel's half is mapped in every address space)
vathe virtual address, page-aligned
pathe page's physical address, page-aligned
flagsthe mapping's permissions and caching (VM_*)
Returns
0, -EINVAL for an address that isn't page-aligned (or that can't be mapped page by page, in the direct map), or -ENOMEM if there was no memory for a page table

Definition at line 242 of file i386.c.

References PAGE_MASK, PAGE_SIZE, PG_PRESENT, pmap_add(), pte_flags(), pte_get(), and tlb_shootdown().

◆ pmap_alloc()

struct pmap * pmap_alloc ( void )
static

Allocates a struct pmap.

Definition at line 157 of file i386.c.

References kmalloc(), and pmap_alloc().

Referenced by pmap_alloc(), pmap_alloc(), and pmap_create().

◆ pmap_clear_modify()

int pmap_clear_modify ( struct vm_page * pg)

Not implemented on x86, and nothing uses it.

Parameters
pgthe page
Returns
-1

Definition at line 382 of file i386.c.

References pmap_clear_modify().

Referenced by pmap_clear_modify().

◆ pmap_clear_reference()

int pmap_clear_reference ( struct vm_page * pg)

Not implemented on x86, and nothing uses it.

Parameters
pgthe page
Returns
-1

Definition at line 393 of file i386.c.

References pmap_clear_reference().

Referenced by pmap_clear_reference().

◆ pmap_copy()

void pmap_copy ( struct pmap * dst_map,
struct pmap * src_map,
vaddr_t dst_addr,
size_t len,
vaddr_t src_addr )

Does nothing: the generic pmap_copy() isn't used on x86.

Definition at line 340 of file i386.c.

References pmap_copy().

Referenced by pmap_copy().

◆ pmap_create()

struct pmap * pmap_create ( void )

Makes the page tables of a new address space: an empty user half, and the kernel's half, which every address space shares.

Returns
the new page tables, or NULL if there was no memory for them

Definition at line 178 of file i386.c.

References k_pmap, KERNEL_PDE, kfree(), pmap::map, memset(), NULL, pmap_alloc(), pmap_create(), pmap::ref, table(), and table_alloc().

◆ pmap_decref()

void pmap_decref ( struct pmap * pmap)

Drops a reference to an address space's page tables, freeing them with the last one.

Parameters
pmapthe page tables

Definition at line 215 of file i386.c.

References pmap_decref(), pmap_release(), and pmap::ref.

◆ pmap_incref()

void pmap_incref ( struct pmap * pmap)

Adds a reference to an address space's page tables.

Parameters
pmapthe page tables

Definition at line 206 of file i386.c.

References pmap_incref(), and pmap::ref.

◆ pmap_init()

void pmap_init ( void )

Takes over the boot page tables as the kernel's, at boot, and makes the page tables of the kernel's half, which every address space shares.

Definition at line 132 of file i386.c.

References cur_pmap, k_pmap, KERNEL_PDE, kvm_space, pmap::map, NULL, PAGE_MASK, PG_PRESENT, PG_WRITE, vm_space::pmap, pmap_init(), pmap_loaded(), read_cr3(), pmap::ref, table(), table_alloc_boot(), and tlb_flush().

◆ pmap_is_modified()

int pmap_is_modified ( struct vm_page * pg)

Not implemented on x86, and nothing uses it.

Parameters
pgthe page
Returns
-1

Definition at line 404 of file i386.c.

References pmap_is_modified().

Referenced by pmap_is_modified().

◆ pmap_is_referenced()

int pmap_is_referenced ( struct vm_page * pg)

Not implemented on x86, and nothing uses it.

Parameters
pgthe page
Returns
-1

Definition at line 415 of file i386.c.

References pmap_is_referenced().

Referenced by pmap_is_referenced().

◆ pmap_page_copy()

void pmap_page_copy ( paddr_t src,
paddr_t dst )

Copies a page of physical memory to another.

Parameters
srcthe physical address of the page to copy
dstthe physical address of the page to copy it to

Definition at line 360 of file i386.c.

References memcpy(), PAGE_SIZE, PHYS2VIRT, and pmap_page_copy().

◆ pmap_page_protect()

void pmap_page_protect ( struct vm_page * pg,
uint32_t flags )

Not implemented on x86 (it does nothing), and nothing uses it.

Parameters
pgthe page
flagsthe permissions

Definition at line 371 of file i386.c.

References pmap_page_protect().

Referenced by pmap_page_protect().

◆ pmap_page_read()

int pmap_page_read ( paddr_t paddr,
off_t off,
size_t size,
void * buf )

Reads from a page of physical memory, through the kernel's mapping.

Parameters
paddrthe page's physical address
offthe offset to read from, in the page
sizehow much to read, at most what's left of the page
bufwhere to put it
Returns
0, or -EINVAL if off isn't in the page

Definition at line 464 of file i386.c.

References memcpy(), MIN, PAGE_SIZE, PHYS2VIRT, and pmap_page_read().

◆ pmap_page_write()

int pmap_page_write ( paddr_t paddr,
off_t off,
size_t size,
void * buf )

Writes to a page of physical memory, through the kernel's mapping.

Parameters
paddrthe page's physical address
offthe offset to write at, in the page
sizehow much to write, at most what's left of the page
bufwhat to write
Returns
0, or -EINVAL if off isn't in the page

Definition at line 476 of file i386.c.

References memcpy(), MIN, PAGE_SIZE, PHYS2VIRT, and pmap_page_write().

◆ pmap_protect()

void pmap_protect ( struct pmap * pmap,
vaddr_t sva,
vaddr_t eva,
uint32_t prot )

Changes the permissions of the mapped pages of a range of an address space.

Pages that aren't mapped stay unmapped.

Parameters
pmapthe page tables
svathe range's start, page-aligned
evaits end
protthe new permissions (VM_*)

Definition at line 318 of file i386.c.

References MIN, PAGE_MASK, PAGE_SIZE, PG_ADDR, PG_PRESENT, pmap_protect(), pte_flags(), pte_get(), and tlb_shootdown().

◆ pmap_release()

void pmap_release ( struct pmap * pmap)
static

Frees an address space's page directory, once no CPU has it loaded.

Definition at line 163 of file i386.c.

References kfree(), pmap::map, pmap_release(), table_free(), and tlb_shootdown().

◆ pmap_remove()

void pmap_remove ( struct pmap * pmap,
vaddr_t sva,
vaddr_t eva )

Unmaps the pages of a range of an address space, and flushes them from the TLBs that may have them.

The pages lose no references.

Parameters
pmapthe page tables
svathe range's start, page-aligned
evaits end, page-aligned

Definition at line 267 of file i386.c.

References MIN, PAGE_MASK, PAGE_SIZE, PG_PRESENT, pmap_remove(), pte_get(), and tlb_shootdown().

◆ pmap_remove_all()

void pmap_remove_all ( struct pmap * pmap)

Unmaps the whole user half of an address space, and frees its page tables.

The pages it mapped lose the reference that the page fault handler gave them (mm_page_incref()).

Parameters
pmapthe page tables

Definition at line 293 of file i386.c.

References KERNEL_PDE, pmap::map, mm_page_decref(), PG_ADDR, PG_PRESENT, pmap_remove_all(), table(), table_free(), tlb_shootdown(), and USER_STACK.

◆ pmap_switch()

struct pmap * pmap_switch ( struct pmap * pmap)

Switches this CPU to an address space's page tables.

Parameters
pmapthe page tables to switch to
Returns
the page tables the CPU had before

Definition at line 111 of file i386.c.

References cur_pmap, pmap::map, panic, pmap_loaded(), and pmap_switch().

◆ pmap_update()

void pmap_update ( struct pmap * pmap)

Makes the changes to an address space's page tables take effect.

It does nothing on x86, where they take effect at once.

Parameters
pmapthe page tables

Definition at line 352 of file i386.c.

References pmap_update().

Referenced by pmap_update().

◆ pte_flags()

uint32_t pte_flags ( uint32_t flags)
static

Returns the page table entry bits for the VM_* flags flags.

Definition at line 222 of file i386.c.

References PG_PCD, PG_PRESENT, PG_PWT, PG_USER, PG_WRITE, pte_flags(), VM_KW, VM_NOCACHE, VM_URWX, and VM_UW.

◆ pte_get()

uint32_t * pte_get ( struct pmap * pmap,
vaddr_t va,
int make )
static

Returns the page table entry that maps va in pmap.

With make, the page table is made if there's none (NULL if there's no memory for it); without it, NULL if there's no page table.

Definition at line 92 of file i386.c.

References KERNEL_PDE, pmap::map, NULL, PG_ADDR, PG_PRESENT, PG_USER, PG_WRITE, pte_get(), table(), table_alloc(), VDIR, and VTBL.

◆ table()

uint32_t * table ( paddr_t paddr)
inlinestatic

Returns a page table's kernel address, in the direct map.

Definition at line 53 of file i386.c.

References PHYS2VIRT, and table().

◆ table_alloc()

paddr_t table_alloc ( void )
static

Allocates an empty page table.

Returns its physical address, or 0 if there is no memory for it.

Definition at line 60 of file i386.c.

References memset(), mm_page_alloc(), vm_page::paddr, PAGE_SIZE, table(), and table_alloc().

◆ table_alloc_boot()

paddr_t table_alloc_boot ( void )
static

Allocates a page table that the kernel can't boot without: it panics if there is no memory.

Definition at line 73 of file i386.c.

References vm_page::paddr, panic, table_alloc(), and table_alloc_boot().

Referenced by pmap_init(), table_alloc_boot(), and table_alloc_boot().

◆ table_free()

void table_free ( paddr_t paddr)
static

Frees a page table.

Definition at line 84 of file i386.c.

References mm_page_dealloc(), vm_page::paddr, and table_free().

Variable Documentation

◆ k_pmap

struct pmap k_pmap
static

Definition at line 47 of file i386.c.

◆ phys_window_next

vaddr_t phys_window_next = ARCH_PHYS_WINDOW_BASE
static

Definition at line 486 of file i386.c.

Referenced by phys_window_map().