diff options
Diffstat (limited to 'mmu.h')
-rw-r--r-- | mmu.h | 236 |
1 files changed, 114 insertions, 122 deletions
@@ -2,8 +2,10 @@ // 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 @@ -11,81 +13,104 @@ #define CR4_PSE 0x00000010 // Page size extension -// various segment selectors. -#define SEG_KCODE 1 // kernel code -#define SEG_KDATA 2 // kernel data+stack -#define SEG_UCODE 3 // user code -#define SEG_UDATA 4 // user data+stack -#define SEG_TSS 5 // this process's task state +// Segment selectors (indexes) in our GDTs. +// Defined by our convention, not the architecture. +#define KCSEG32 (1<<3) /* kernel 32-bit code segment */ +#define KCSEG (2<<3) /* kernel code segment */ +#define KDSEG (3<<3) /* kernel data segment */ +#define TSSSEG (4<<3) /* tss segment - takes two slots */ +#define UDSEG (6<<3) /* user data segment */ +#define UCSEG (7<<3) /* user code segment */ -// cpu->gdt[NSEGS] holds the above segments. -#define NSEGS 6 +#define NSEGS 8 #ifndef __ASSEMBLER__ -// Segment Descriptor struct segdesc { - uint lim_15_0 : 16; // Low bits of segment limit - uint base_15_0 : 16; // Low bits of segment base address - uint base_23_16 : 8; // Middle bits of segment base address - uint type : 4; // Segment type (see STS_ constants) - uint s : 1; // 0 = system, 1 = application - uint dpl : 2; // Descriptor Privilege Level - uint p : 1; // Present - uint lim_19_16 : 4; // High bits of segment limit - uint avl : 1; // Unused (available for software use) - uint rsv1 : 1; // Reserved - uint db : 1; // 0 = 16-bit segment, 1 = 32-bit segment - uint g : 1; // Granularity: limit scaled by 4K when set - uint base_31_24 : 8; // High bits of segment base address + uint16 limit0; + uint16 base0; + uint8 base1; + uint8 bits; + uint8 bitslimit1; + uint8 base2; }; -// Normal segment -#define SEG(type, base, lim, dpl) (struct segdesc) \ -{ ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ - ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ - (uint)(lim) >> 28, 0, 0, 1, 1, (uint)(base) >> 24 } -#define SEG16(type, base, lim, dpl) (struct segdesc) \ -{ (lim) & 0xffff, (uint)(base) & 0xffff, \ - ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ - (uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 } +// 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 STS_T32A 0x9 // Available 32-bit TSS -#define STS_IG32 0xE // 32-bit Interrupt Gate -#define STS_TG32 0xF // 32-bit Trap Gate - -// A virtual address 'la' has a three-part structure as follows: +#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: // -// +--------10------+-------10-------+---------12----------+ -// | Page Directory | Page Table | Offset within Page | -// | Index | Index | | -// +----------------+----------------+---------------------+ -// \--- PDX(va) --/ \--- PTX(va) --/ - +// +--16--+---9---+------9-------+-----9----+----9-------+----12-------+ +// | Sign | PML4 |Page Directory| Page Dir |Page Table | Offset Page | +// |Extend| Index | Pointer Index| Index | Index | in Page | +// +------+-------+--------------+----------+------------+-------------+ +// \-PMX(va)-/\-PDPX(va)--/ \-PDX(va)-/ \-PTX(va)-/ + +#define PMX(va) (((uint64)(va) >> PML4XSHIFT) & PXMASK) +#define PDPX(va) (((uint64)(va) >> PDPXSHIFT) & PXMASK) // page directory index -#define PDX(va) (((uint)(va) >> PDXSHIFT) & 0x3FF) - +#define PDX(va) (((uint64)(va) >> PDXSHIFT) & PXMASK) // page table index -#define PTX(va) (((uint)(va) >> PTXSHIFT) & 0x3FF) +#define PTX(va) (((uint64)(va) >> PTXSHIFT) & PXMASK) // construct virtual address from indexes and offset -#define PGADDR(d, t, o) ((uint)((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) +#define PGADDR(d, t, o) ((uint64)((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) // Page directory and page table constants. -#define NPDENTRIES 1024 // # directory entries per page directory -#define NPTENTRIES 1024 // # PTEs per page table +#define NPDENTRIES 512 // # directory entries per page directory +#define NPTENTRIES 512 // # PTEs per page table #define PGSIZE 4096 // bytes mapped by a page #define PTXSHIFT 12 // offset of PTX in a linear address -#define PDXSHIFT 22 // offset of PDX in a linear address +#define PDXSHIFT 21 // offset of PDX in a linear address +#define PDPXSHIFT 30 // offset of PDPX in a linear address +#define PML4XSHIFT 39 // offset of PML4X in a linear address +#define PXMASK 0X1FF #define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1)) #define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1)) @@ -95,87 +120,54 @@ struct segdesc { #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) ((uint)(pte) & ~0xFFF) -#define PTE_FLAGS(pte) ((uint)(pte) & 0xFFF) +#define PTE_ADDR(pte) ((uint64)(pte) & ~0xFFF) +#define PTE_FLAGS(pte) ((uint64)(pte) & 0xFFF) #ifndef __ASSEMBLER__ -typedef uint pte_t; -// Task state segment format -struct taskstate { - uint link; // Old ts selector - uint esp0; // Stack pointers and segment selectors - ushort ss0; // after an increase in privilege level - ushort padding1; - uint *esp1; - ushort ss1; - ushort padding2; - uint *esp2; - ushort ss2; - ushort padding3; - void *cr3; // Page directory base - uint *eip; // Saved state from last task switch - uint eflags; - uint eax; // More saved state (registers) - uint ecx; - uint edx; - uint ebx; - uint *esp; - uint *ebp; - uint esi; - uint edi; - ushort es; // Even more saved state (segment selectors) - ushort padding4; - ushort cs; - ushort padding5; - ushort ss; - ushort padding6; - ushort ds; - ushort padding7; - ushort fs; - ushort padding8; - ushort gs; - ushort padding9; - ushort ldt; - ushort padding10; - ushort t; // Trap on task switch - ushort iomb; // I/O map base address -}; +typedef uint64 pml4e_t; +typedef uint64 pdpe_t; +typedef uint64 pte_t; -// Gate descriptors for interrupts and traps -struct gatedesc { - uint off_15_0 : 16; // low 16 bits of offset in segment - uint cs : 16; // code segment selector - uint args : 5; // # args, 0 for interrupt/trap gates - uint rsv1 : 3; // reserved(should be zero I guess) - uint type : 4; // type(STS_{IG32,TG32}) - uint s : 1; // must be 0 (system) - uint dpl : 2; // descriptor(meaning new) privilege level - uint p : 1; // Present - uint off_31_16 : 16; // high bits of offset in segment +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; }; -// Set up a normal interrupt/trap gate descriptor. -// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate. -// interrupt gate clears FL_IF, trap gate leaves FL_IF alone -// - sel: Code segment selector for interrupt/trap handler -// - off: Offset in code segment for interrupt/trap handler -// - dpl: Descriptor Privilege Level - -// the privilege level required for software to invoke -// this interrupt/trap gate explicitly using an int instruction. -#define SETGATE(gate, istrap, sel, off, d) \ -{ \ - (gate).off_15_0 = (uint)(off) & 0xffff; \ - (gate).cs = (sel); \ - (gate).args = 0; \ - (gate).rsv1 = 0; \ - (gate).type = (istrap) ? STS_TG32 : STS_IG32; \ - (gate).s = 0; \ - (gate).dpl = (d); \ - (gate).p = 1; \ - (gate).off_31_16 = (uint)(off) >> 16; \ +// 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 |