summaryrefslogtreecommitdiff
path: root/mmu.h
diff options
context:
space:
mode:
Diffstat (limited to 'mmu.h')
-rw-r--r--mmu.h236
1 files changed, 114 insertions, 122 deletions
diff --git a/mmu.h b/mmu.h
index a82d8e2..9450d90 100644
--- a/mmu.h
+++ b/mmu.h
@@ -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