diff options
author | Freya Murphy <freya@freyacat.org> | 2025-04-03 12:31:21 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2025-04-03 12:31:21 -0400 |
commit | a524eb3846aac4d1b38f08cba49ff3503107042f (patch) | |
tree | dbe81fccf975f646a681e4fdcebd227cdfb98774 /kernel/old/include/vm.h | |
parent | new libs (diff) | |
download | comus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.gz comus-a524eb3846aac4d1b38f08cba49ff3503107042f.tar.bz2 comus-a524eb3846aac4d1b38f08cba49ff3503107042f.zip |
move old kernel code (for now) into kernel/old, trying to get long mode
Diffstat (limited to 'kernel/old/include/vm.h')
-rw-r--r-- | kernel/old/include/vm.h | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/kernel/old/include/vm.h b/kernel/old/include/vm.h new file mode 100644 index 0000000..dc12568 --- /dev/null +++ b/kernel/old/include/vm.h @@ -0,0 +1,501 @@ +/** +** @file vm.h +** +** @author CSCI-452 class of 20245 +** +** @brief Virtual memory-related declarations. +*/ + +#ifndef VM_H_ +#define VM_H_ + +#include <defs.h> +#include <types.h> + +#include <procs.h> + +/* +** VM layout of the system +** +** User processes use the first 4MB of the 32-bit address space; see the +** next comment for details. +** +** Kernel virtual addresses are in the "higher half" range, beginning +** at 0x80000000. We define our mapping such that virtual address +** 0x8nnnnnnn maps to physical address 0x0nnnnnnn, so converting between +** the two is trivial. +*/ + +/* +** VM layout of process' address space +** +** Processes are limited to the first 4MB of the 32-bit address space: +** +** Address Range Contents +** ======================= ================================ +** 0x00000000 - 0x00000fff page 0 is inaccessible +** 0x00001000 - 0x000..fff text occupies pages 1 - N +** 0x000..000 - 0x000..fff data occupies pages N+1 - N+d +** 0x000..000 - 0x000..fff bss occupies pages N+d+1 - N+d+b +** 0x000..000 - 0x003fdfff unusable +** 0x003fe000 - 0x003fffff stack occupies last two pages +** +** This gives us the following page table structure: +** +** Page directory: +** Entries Contents +** ======== ============================== +** 0 point to PMT for address space +** 1 - 1023 invalid +** +** Page map table: +** Entries Contents +** ======== ============================== +** 0 invalid +** 1 - N text frames +** N+1 - N+d data frames +** N+d+1 - N+d+b bss frames +** N+d+b+1 - 1021 invalid +** 1022 - 1023 stack frames +*/ + +/* +** General (C and/or assembly) definitions +*/ + +// user virtual addresses +#define USER_BASE 0x00000000 +#define USER_MAX 0x003fffff +#define USER_TEXT 0x00001000 +#define USER_STACK 0x003fe000 +#define USER_STACK_P1 USER_STACK +#define USER_STACK_P2 0x003ff000 +#define USER_STK_END 0x00400000 + +// how to find the addresses of the stack pages in the VM hierarchy +// user address space is the first 4MB of virtual memory +#define USER_PDE 0 +// the stack occupies this range of pages in the user address space +#define USER_STK_FIRST_PTE 1022 +#define USER_STK_LAST_PTE 1023 + +// some important memory addresses +#define KERN_BASE 0x80000000 // start of "kernel" memory +#define EXT_BASE 0x00100000 // start of "extended" memory (1MB) +#define DEV_BASE 0xfe000000 // "device" memory +#define PHYS_TOP 0x3fffffff // last usable physical address (1GB - 1) + +// where the kernel actually lives +#define KERN_PLINK 0x00010000 +#define KERN_VLINK (KERN_BASE + KERN_PLINK) + +// number of entries in a page directory or page table +#define N_PDE 1024 +#define N_PTE 1024 + +// index field shift counts and masks +#define PDIX_SHIFT 22 +#define PTIX_SHIFT 12 +#define PIX2I_MASK 0x3ff + +// physical/virtual converters that don't use casting +// (usable from anywhere) +#define V2PNC(a) ((a) - KERN_BASE) +#define P2VNC(a) ((a) + KERN_BASE) + +// page-size address rounding macros +#define SZ_PG_M1 MOD4K_BITS +#define SZ_PG_MASK MOD4K_MASK +#define PGUP(a) (((a) + SZ_PG_M1) & SZ_PG_MASK) +#define PGDOWN(a) ((a) & SZ_PG_MASK) + +// page directory entry bit fields +#define PDE_P 0x00000001 // 1 = present +#define PDE_RW 0x00000002 // 1 = writable +#define PDE_US 0x00000004 // 1 = user and system usable +#define PDE_PWT 0x00000008 // cache: 1 = write-through +#define PDE_PCD 0x00000010 // cache: 1 = disabled +#define PDE_A 0x00000020 // accessed +#define PDE_D 0x00000040 // dirty (4MB pages) +#define PDE_AVL1 0x00000040 // ignored (4KB pages) +#define PDE_PS 0x00000080 // 1 = 4MB page size +#define PDE_G 0x00000100 // global +#define PDE_AVL2 0x00000e00 // ignored +#define PDE_PAT 0x00001000 // (4MB pages) use page attribute table +#define PDE_PTA 0xfffff000 // page table address field (4KB pages) +#define PDE_FA 0xffc00000 // frame address field (4MB pages) + +// page table entry bit fields +#define PTE_P 0x00000001 // present +#define PTE_RW 0x00000002 // 1 = writable +#define PTE_US 0x00000004 // 1 = user and system usable +#define PTE_PWT 0x00000008 // cache: 1 = write-through +#define PTE_PCD 0x00000010 // cache: 1 = disabled +#define PTE_A 0x00000020 // accessed +#define PTE_D 0x00000040 // dirty +#define PTE_PAT 0x00000080 // use page attribute table +#define PTE_G 0x00000100 // global +#define PTE_AVL2 0x00000e00 // ignored +#define PTE_FA 0xfffff000 // frame address field + +// error code bit assignments for page faults +#define PFLT_P 0x00000001 +#define PFLT_W 0x00000002 +#define PFLT_US 0x00000004 +#define PFLT_RSVD 0x00000008 +#define PFLT_ID 0x00000010 +#define PFLT_PK 0x00000020 +#define PFLT_SS 0x00000040 +#define PFLT_HLAT 0x00000080 +#define PFLT_SGX 0x00008000 +#define PFLT_UNUSED 0xffff7f00 + +#ifndef ASM_SRC + +/* +** Start of C-only definitions +*/ + +// physical/virtual converters that do use casting +// (not usable from assembly) +#define V2P(a) (((uint32_t)(a)) - KERN_BASE) +#define P2V(a) (((uint32_t)(a)) + KERN_BASE) + +// create a pde/pte from an integer frame number and permission bits +#define MKPDE(f, p) ((pde_t)(TO_FRAME((f)) | (p))) +#define MKPTE(f, p) ((pte_t)(TO_FRAME((f)) | (p))) + +// is a PDE/PTE present? +// (P bit is in the same place in both) +#define IS_PRESENT(entry) (((entry) & PDE_P) != 0) + +// is a PDE a 4MB page entry? +#define IS_LARGE(pde) (((pde) & PDE_PS) != 0) + +// is this entry "system only" or "system and user"? +#define IS_SYSTEM(entry) (((entry) & PDE_US) == 0) +#define IS_USER(entry) (((entry) & PDE_US) != 0) + +// low-order nine bits of PDEs and PTEs hold "permission" flag bits +#define PERMS_MASK MOD4K_BITS + +// 4KB frame numbers are 20 bits wide +#define FRAME_4K_SHIFT 12 +#define FRAME2I_4K_MASK 0x000fffff +#define TO_4KFRAME(n) (((n) & FRAME2I_4K_MASK) << FRAME_4K_SHIFT) +#define GET_4KFRAME(n) (((n) >> FRAME_4K_SHIFT) & FRAME2I_4K_MASK) +#define PDE_4K_ADDR(n) ((n) & MOD4K_MASK) +#define PTE_4K_ADDR(n) ((n) & MOD4K_MASK) + +// 4MB frame numbers are 10 bits wide +#define FRAME_4M_SHIFT 22 +#define FRAME2I_4M_MASK 0x000003ff +#define TO_4MFRAME(n) (((n) & FRAME2I_4M_MASK) << FRAME_4M_SHIFT) +#define GET_4MFRAME(n) (((n) >> FRAME_4M_SHIFT) & FRAME2I_4M_MASK) +#define PDE_4M_ADDR(n) ((n) & MOD4M_MASK) +#define PTE_4M_ADDR(n) ((n) & MOD4M_MASK) + +// extract the PMT address or frame address from a table entry +// PDEs could point to 4MB pages, or 4KB PMTs +#define PDE_ADDR(p) \ + (IS_LARGE(p) ? (((uint32_t)p) & PDE_FA) : (((uint32_t)p) & PDE_PTA)) +// PTEs always point to 4KB pages +#define PTE_ADDR(p) (((uint32_t)(p)) & PTE_FA) +// everything has nine bits of permission flags +#define PERMS(p) (((uint32_t)(p)) & PERMS_MASK) + +// extract the table indices from a 32-bit VA +#define PDIX(v) ((((uint32_t)(v)) >> PDIX_SHIFT) & PIX2I_MASK) +#define PTIX(v) ((((uint32_t)(v)) >> PTIX_SHIFT) & PIX2I_MASK) + +// extract the byte offset from a 32-bit VA +#define OFFSET_4K(v) (((uint32_t)(v)) & MOD4K_BITS) +#define OFFSET_4M(v) (((uint32_t)(v)) & MOD4M_BITS) + +/* +** Types +*/ + +// page directory entries + +// as a 32-bit word, in types.h +// typedef uint32_t pde_t; + +// PDE for 4KB pages +typedef struct pdek_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t avl1 : 1; // 6: ignored (available) + uint_t ps : 1; // 7: page size (must be 0) + uint_t avl2 : 4; // 11-8: ignored (available) + uint_t fa : 20; // 31-12: frame address +} pdek_f_t; + +// PDE for 4MB pages +typedef struct pdem_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t d : 1; // 6: dirty + uint_t ps : 1; // 7: page size (must be 1) + uint_t g : 1; // 8: global + uint_t avl : 3; // 11-9: ignored (available) + uint_t pat : 1; // 12: page attribute table in use + uint_t fa2 : 4; // 16-13: bits 35-32 of frame address (36-bit addrs) + uint_t rsv : 5; // 21-17: reserved - must be zero + uint_t fa : 10; // 31-22: bits 31-22 of frame address +} pdem_f_t; + +// page table entries + +// as a 32-bit word, in types.h +// typedef uint32_t pte_t; + +// broken out into fields +typedef struct pte_s { + uint_t p : 1; // 0: present + uint_t rw : 1; // 1: writable + uint_t us : 1; // 2: user/supervisor + uint_t pwt : 1; // 3: cache write-through + uint_t pcd : 1; // 4: cache disable + uint_t a : 1; // 5: accessed + uint_t d : 1; // 6: dirty + uint_t pat : 1; // 7: page attribute table in use + uint_t g : 1; // 8: global + uint_t avl : 3; // 11-9: ignored (available) + uint_t fa : 20; // 31-12: frame address +} ptef_t; + +// page fault error code bits +// comment: meaning when 1 / meaning when 0 +struct pfec_s { + uint_t p : 1; // page-level protection violation / !present + uint_t w : 1; // write / read + uint_t us : 1; // user-mode access / supervisor-mode access + uint_t rsvd : 1; // reserved bit violation / not + uint_t id : 1; // instruction fetch / data fetch + uint_t pk : 1; // protection-key violation / !pk + uint_t ss : 1; // shadow stack access / !ss + uint_t hlat : 1; // HLAT paging / ordinary paging or access rights + uint_t xtr1 : 7; // unused + uint_t sgz : 1; // SGX-specific access control violation / !SGX + uint_t xtr2 : 16; // more unused +}; + +typedef union pfec_u { + uint32_t u; + struct pfec_s s; +} pfec_t; + +// Mapping descriptor for VA::PA mappings +typedef struct mapping_t { + uint32_t va_start; // starting virtual address for this range + uint32_t pa_start; // first physical address in the range + uint32_t pa_end; // last physical address in the range + uint32_t perm; // access control +} mapping_t; + +// Modes for dumping out page hierarchies +enum vmmode_e { + Simple = 0, // just count 'present' entries at each level + OneLevel, // top-level only: count entries, decode 'present' + TwoLevel, // count entries & decode at each level + Full // ??? in case we need more? + // sentinel + , + N_VMMODES +}; + +/* +** Globals +*/ + +// created page directory for the kernel +extern pde_t *kpdir; + +/* +** Prototypes +*/ + +/** +** Name: vm_init +** +** Initialize the VM module +** +** Note: should not be called until after the memory free list has +** been set up. +*/ +void vm_init(void); + +/** +** Name: vm_uva2kva +** +** Convert a user VA into a kernel address. Works for all addresses - +** if the address is a page address, the low-order nine bits will be +** zeroes; otherwise, they is the offset into the page, which is +** unchanged within the address spaces. +** +** @param pdir Pointer to the page directory to examine +** @param va Virtual address to check +*/ +void *vm_uva2kva(pde_t *pdir, void *va); + +/** +** Name: vm_pagedup +** +** Duplicate a page of memory +** +** @param old Pointer to the first byte of a page +** +** @return a pointer to the new, duplicate page, or NULL +*/ +void *vm_pagedup(void *old); + +/** +** Name: vm_pdedup +** +** Duplicate a page directory entry +** +** @param entry The entry to be duplicated +** +** @return the new entry, or -1 on error. +*/ +pde_t vm_pdedup(pde_t entry); + +/** +** Name: vm_ptdup +** +** Duplicate a page directory entry +** +** @param dst Pointer to where the duplicate should go +** @param curr Pointer to the entry to be duplicated +** +** @return true on success, else false +*/ +bool_t vm_ptdup(pde_t *dst, pde_t *curr); + +/** +** Name: vm_getpte +** +** Return the address of the PTE corresponding to the virtual address +** 'va' within the address space controlled by 'pgdir'. If there is no +** page table for that VA and 'alloc' is true, create the necessary +** page table entries. +** +** @param pdir Pointer to the page directory to be searched +** @param va The virtual address we're looking for +** @param alloc Should we allocate a page table if there isn't one? +** +** @return A pointer to the page table entry for this VA, or NULL +*/ +pte_t *vm_getpte(pde_t *pdir, const void *va, bool_t alloc); + +/** +** Name: vm_mkkvm +** +** Create the kernel's page table hierarchy +*/ +pde_t *vm_mkkvm(void); + +/** +** Name: vm_mkuvm +** +** Create the page table hierarchy for a user process +*/ +pde_t *vm_mkuvm(void); + +/** +** Name: vm_set_kvm +** +** Switch the page table register to the kernel's page directory +*/ +void vm_set_kvm(void); + +/** +** Name: vm_set_uvm +** +** Switch the page table register to the page directory for a user process. +** +** @param p The PCB of the user process +*/ +void vm_set_uvm(pcb_t *p); + +/** +** Name: vm_add +** +** Add pages to the page hierarchy for a process, copying data into +** them if necessary. +** +** @param pdir Pointer to the page directory to modify +** @param wr "Writable" flag for the PTE +** @param sys "System" flag for the PTE +** @param va Starting VA of the range +** @param size Amount of physical memory to allocate +** @param data Pointer to data to copy, or NULL +** @param bytes Number of bytes to copy +** +** @return status of the allocation attempt +*/ +int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size, + char *data, uint32_t bytes); + +/** +** Name: vm_free +** +** Deallocate a page table hierarchy and all physical memory frames +** in the user portion. +** +** @param pdir Pointer to the page directory +*/ +void vm_free(pde_t *pdir); + +/* +** Name: vm_map +** +** Create PTEs for virtual addresses starting at 'va' that refer to +** physical addresses in the range [pa, pa+size-1]. We aren't guaranteed +** that va is page-aligned. +** +** @param pdir Page directory for this address space +** @param va The starting virtual address +** @param pa The starting physical address +** @param size Length of the range to be mapped +** @param perm Permission bits for the PTEs +*/ +int vm_map(pde_t *pdir, void *va, uint32_t pa, uint32_t size, int perm); + +/** +** Name: vm_uvmdup +** +** Create a duplicate of the user portio of an existing page table +** hierarchy. We assume that the "new" page directory exists and +** the system portions of it should not be touched. +** +** @param new New page directory +** @param old Existing page directory +** +** @return status of the duplication attempt +*/ +int vm_uvmdup(pde_t *new, pde_t *old); + +/** +** Name: vm_print +** +** Print out a paging hierarchy. +** +** @param pt Page table to display +** @param dir Is it a page directory (vs. a page table)? +** @param mode How to display the entries +*/ +void vm_print(void *pt, bool_t dir, enum vmmode_e mode); + +#endif /* !ASM_SRC */ + +#endif |