// This file contains definitions for the // x86 memory management unit (MMU). // Eflags register #define FL_TF 0x00000100 // Trap Flag #define FL_IF 0x00000200 // Interrupt Enable // Control Register flags #define CR0_PE 0x00000001 // Protection Enable #define CR0_WP 0x00010000 // Write Protect #define CR0_PG 0x80000000 // Paging #define CR4_PSE 0x00000010 // Page size extension // Segment selectors (indexes) in our GDTs. // Defined by our convention, not the architecture. #define SEG_KCODE32 (1<<3) // kernel 32-bit code segment #define SEG_KCODE (2<<3) // kernel code segment #define SEG_KDATA (3<<3) // kernel data segment #define SEG_TSS (4<<3) // tss segment - takes two slots #define SEG_UDATA (6<<3) // user data segment #define SEG_UCODE (7<<3) // user code segment #define NSEGS 8 #ifndef __ASSEMBLER__ struct segdesc { uint16 limit0; uint16 base0; uint8 base1; uint8 bits; uint8 bitslimit1; uint8 base2; }; // SEGDESC constructs a segment descriptor literal // with the given, base, limit, and type bits. #define SEGDESC(base, limit, bits) (struct segdesc){ \ (limit)&0xffff, (base)&0xffff, \ ((base)>>16)&0xff, \ (bits)&0xff, \ (((bits)>>4)&0xf0) | ((limit>>16)&0xf), \ ((base)>>24)&0xff, \ } // SEGDESCHI constructs an extension segment descriptor // literal that records the high bits of base. #define SEGDESCHI(base) (struct segdesc) { \ (((base)>>32)&0xffff), (((base)>>48)&0xffff), \ } #endif #define DPL_USER 0x3 // User DPL #define SEG_A (1<<0) // segment accessed bit #define SEG_R (1<<1) // readable (code) #define SEG_W (1<<1) // writable (data) #define SEG_C (1<<2) // conforming segment (code) #define SEG_E (1<<2) // expand-down bit (data) #define SEG_CODE (1<<3) // code segment (instead of data) // User and system segment bits. #define SEG_S (1<<4) // if 0, system descriptor #define SEG_DPL(x) ((x)<<5) // descriptor privilege level (2 bits) #define SEG_P (1<<7) // segment present #define SEG_AVL (1<<8) // available for operating system use #define SEG_L (1<<9) // long mode #define SEG_D (1<<10) // default operation size 32-bit #define SEG_G (1<<11) // granularity // Application segment type bits #define STA_X 0x8 // Executable segment #define STA_W 0x2 // Writeable (non-executable segments) #define STA_R 0x2 // Readable (executable segments) // System segment type bits #define SEG_LDT (2<<0) // local descriptor table #define SEG_TSS64A (9<<0) // available 64-bit TSS #define SEG_TSS64B (11<<0) // busy 64-bit TSS #define SEG_CALL64 (12<<0) // 64-bit call gate #define SEG_INTR64 (14<<0) // 64-bit interrupt gate #define SEG_TRAP64 (15<<0) // 64-bit trap gate // A virtual address 'la' has a six-part structure as follows: // // +--16--+---9---+------9-------+-----9----+----9-------+----12-------+ // | Sign | PML4 |Page Directory| Page Dir |Page Table | Offset Page | // |Extend| Index | Pointer Index| Index | Index | in Page | // +------+-------+--------------+----------+------------+-------------+ // L3 pgtab L2 pgtab L1 pgtab L0 pgtab // Page directory and page table constants. #define NPDENTRIES 512 // # directory entries per page directory #define PGSIZE 4096 // bytes mapped by a page #define PGSHIFT 12 // offset of PTX in a linear address #define PXMASK 0x1FF #define PXSHIFT(n) (PGSHIFT+(9*(n))) // shift for index into level n page table #define PX(n, va) ((((uint64) (va)) >> PXSHIFT(n)) & PXMASK) #define L_PML4 3 #define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1)) #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1)) // Page table/directory entry flags. #define PTE_P 0x001 // Present #define PTE_W 0x002 // Writeable #define PTE_U 0x004 // User #define PTE_PS 0x080 // Page Size #define PTE_PWT 0x008 // Write-Through #define PTE_PCD 0x010 // Cache-Disable // Address in page table or page directory entry #define PTE_ADDR(pte) ((uint64)(pte) & ~0xFFF) #define PTE_FLAGS(pte) ((uint64)(pte) & 0xFFF) #ifndef __ASSEMBLER__ typedef uint64 pte_t; struct taskstate { uint8 reserved0[4]; uint64 rsp[3]; uint64 ist[8]; uint8 reserved1[10]; uint16 iomba; uint8 iopb[0]; } __attribute__ ((packed)); #define INT_P (1<<7) // interrupt descriptor present struct intgate { uint16 rip0; uint16 cs; uint8 reserved0; uint8 bits; uint16 rip1; uint32 rip2; uint32 reserved1; }; // INTDESC constructs an interrupt descriptor literal // that records the given code segment, instruction pointer, // and type bits. #define INTDESC(cs, rip, bits) (struct intgate){ \ (rip)&0xffff, (cs), 0, bits, ((rip)>>16)&0xffff, \ (uint64)(rip)>>32, 0, \ } // See section 4.6 of amd64 vol2 struct desctr { uint16 limit; uint64 base; } __attribute__((packed, aligned(16))); // important! #endif