xref: /xv6-public/mmu.h (revision 55e95b16)
1 /*
2  * This file contains definitions for the x86 memory management unit (MMU),
3  * including paging- and segmentation-related data structures and constants,
4  * the %cr0, %cr4, and %eflags registers, and traps.
5  */
6 
7 /*
8  *
9  *	Part 1.  Paging data structures and constants.
10  *
11  */
12 
13 // A linear address 'la' has a three-part structure as follows:
14 //
15 // +--------10------+-------10-------+---------12----------+
16 // | Page Directory |   Page Table   | Offset within Page  |
17 // |      Index     |      Index     |                     |
18 // +----------------+----------------+---------------------+
19 //  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
20 //  \----------- PPN(la) -----------/
21 //
22 // The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown.
23 // To construct a linear address la from PDX(la), PTX(la), and PGOFF(la),
24 // use PGADDR(PDX(la), PTX(la), PGOFF(la)).
25 
26 // page number field of address
27 #define PPN(la)		(((uintptr_t) (la)) >> PTXSHIFT)
28 #define VPN(la)		PPN(la)		// used to index into vpt[]
29 
30 // page directory index
31 #define PDX(la)		((((uintptr_t) (la)) >> PDXSHIFT) & 0x3FF)
32 #define VPD(la)		PDX(la)		// used to index into vpd[]
33 
34 // page table index
35 #define PTX(la)		((((uintptr_t) (la)) >> PTXSHIFT) & 0x3FF)
36 
37 // offset in page
38 #define PGOFF(la)	(((uintptr_t) (la)) & 0xFFF)
39 
40 // construct linear address from indexes and offset
41 #define PGADDR(d, t, o)	((void*) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
42 
43 // Page directory and page table constants.
44 #define NPDENTRIES	1024		// page directory entries per page directory
45 #define NPTENTRIES	1024		// page table entries per page table
46 
47 #define PGSIZE		4096		// bytes mapped by a page
48 #define PGSHIFT		12		// log2(PGSIZE)
49 
50 #define PTSIZE		(PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry
51 #define PTSHIFT		22		// log2(PTSIZE)
52 
53 #define PTXSHIFT	12		// offset of PTX in a linear address
54 #define PDXSHIFT	22		// offset of PDX in a linear address
55 
56 // Page table/directory entry flags.
57 #define PTE_P		0x001	// Present
58 #define PTE_W		0x002	// Writeable
59 #define PTE_U		0x004	// User
60 #define PTE_PWT		0x008	// Write-Through
61 #define PTE_PCD		0x010	// Cache-Disable
62 #define PTE_A		0x020	// Accessed
63 #define PTE_D		0x040	// Dirty
64 #define PTE_PS		0x080	// Page Size
65 #define PTE_MBZ		0x180	// Bits must be zero
66 
67 // The PTE_AVAIL bits aren't used by the kernel or interpreted by the
68 // hardware, so user processes are allowed to set them arbitrarily.
69 #define PTE_AVAIL	0xE00	// Available for software use
70 
71 // Only flags in PTE_USER may be used in system calls.
72 #define PTE_USER	(PTE_AVAIL | PTE_P | PTE_W | PTE_U)
73 
74 // address in page table entry
75 #define PTE_ADDR(pte)	((physaddr_t) (pte) & ~0xFFF)
76 
77 // Control Register flags
78 #define CR0_PE		0x00000001	// Protection Enable
79 #define CR0_MP		0x00000002	// Monitor coProcessor
80 #define CR0_EM		0x00000004	// Emulation
81 #define CR0_TS		0x00000008	// Task Switched
82 #define CR0_ET		0x00000010	// Extension Type
83 #define CR0_NE		0x00000020	// Numeric Errror
84 #define CR0_WP		0x00010000	// Write Protect
85 #define CR0_AM		0x00040000	// Alignment Mask
86 #define CR0_NW		0x20000000	// Not Writethrough
87 #define CR0_CD		0x40000000	// Cache Disable
88 #define CR0_PG		0x80000000	// Paging
89 
90 #define CR4_PCE		0x00000100	// Performance counter enable
91 #define CR4_MCE		0x00000040	// Machine Check Enable
92 #define CR4_PSE		0x00000010	// Page Size Extensions
93 #define CR4_DE		0x00000008	// Debugging Extensions
94 #define CR4_TSD		0x00000004	// Time Stamp Disable
95 #define CR4_PVI		0x00000002	// Protected-Mode Virtual Interrupts
96 #define CR4_VME		0x00000001	// V86 Mode Extensions
97 
98 // Eflags register
99 #define FL_CF		0x00000001	// Carry Flag
100 #define FL_PF		0x00000004	// Parity Flag
101 #define FL_AF		0x00000010	// Auxiliary carry Flag
102 #define FL_ZF		0x00000040	// Zero Flag
103 #define FL_SF		0x00000080	// Sign Flag
104 #define FL_TF		0x00000100	// Trap Flag
105 #define FL_IF		0x00000200	// Interrupt Flag
106 #define FL_DF		0x00000400	// Direction Flag
107 #define FL_OF		0x00000800	// Overflow Flag
108 #define FL_IOPL_MASK	0x00003000	// I/O Privilege Level bitmask
109 #define FL_IOPL_0	0x00000000	//   IOPL == 0
110 #define FL_IOPL_1	0x00001000	//   IOPL == 1
111 #define FL_IOPL_2	0x00002000	//   IOPL == 2
112 #define FL_IOPL_3	0x00003000	//   IOPL == 3
113 #define FL_NT		0x00004000	// Nested Task
114 #define FL_RF		0x00010000	// Resume Flag
115 #define FL_VM		0x00020000	// Virtual 8086 mode
116 #define FL_AC		0x00040000	// Alignment Check
117 #define FL_VIF		0x00080000	// Virtual Interrupt Flag
118 #define FL_VIP		0x00100000	// Virtual Interrupt Pending
119 #define FL_ID		0x00200000	// ID flag
120 
121 // Page fault error codes
122 #define FEC_PR		0x1	// Page fault caused by protection violation
123 #define FEC_WR		0x2	// Page fault caused by a write
124 #define FEC_U		0x4	// Page fault occured while in user mode
125 
126 
127 /*
128  *
129  *	Part 2.  Segmentation data structures and constants.
130  *
131  */
132 
133 #ifdef __ASSEMBLER__
134 
135 /*
136  * Macros to build GDT entries in assembly.
137  */
138 #define SEG_NULL						\
139 	.word 0, 0;						\
140 	.byte 0, 0, 0, 0
141 #define SEG(type,base,lim)					\
142 	.word (((lim) >> 12) & 0xffff), ((base) & 0xffff);	\
143 	.byte (((base) >> 16) & 0xff), (0x90 | (type)),		\
144 		(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
145 
146 #else	// not __ASSEMBLER__
147 
148 // Segment Descriptors
149 struct Segdesc {
150 	unsigned sd_lim_15_0 : 16;  // Low bits of segment limit
151 	unsigned sd_base_15_0 : 16; // Low bits of segment base address
152 	unsigned sd_base_23_16 : 8; // Middle bits of segment base address
153 	unsigned sd_type : 4;       // Segment type (see STS_ constants)
154 	unsigned sd_s : 1;          // 0 = system, 1 = application
155 	unsigned sd_dpl : 2;        // Descriptor Privilege Level
156 	unsigned sd_p : 1;          // Present
157 	unsigned sd_lim_19_16 : 4;  // High bits of segment limit
158 	unsigned sd_avl : 1;        // Unused (available for software use)
159 	unsigned sd_rsv1 : 1;       // Reserved
160 	unsigned sd_db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
161 	unsigned sd_g : 1;          // Granularity: limit scaled by 4K when set
162 	unsigned sd_base_31_24 : 8; // High bits of segment base address
163 };
164 // Null segment
165 #define SEG_NULL	(struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
166 // Segment that is loadable but faults when used
167 #define SEG_FAULT	(struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
168 // Normal segment
169 #define SEG(type, base, lim, dpl) (struct Segdesc)			\
170 { ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,	\
171     type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,		\
172     (unsigned) (base) >> 24 }
173 #define SEG16(type, base, lim, dpl) (struct Segdesc)			\
174 { (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,		\
175     type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,		\
176     (unsigned) (base) >> 24 }
177 
178 #endif /* !__ASSEMBLER__ */
179 
180 // Application segment type bits
181 #define STA_X		0x8	    // Executable segment
182 #define STA_E		0x4	    // Expand down (non-executable segments)
183 #define STA_C		0x4	    // Conforming code segment (executable only)
184 #define STA_W		0x2	    // Writeable (non-executable segments)
185 #define STA_R		0x2	    // Readable (executable segments)
186 #define STA_A		0x1	    // Accessed
187 
188 // System segment type bits
189 #define STS_T16A	0x1	    // Available 16-bit TSS
190 #define STS_LDT		0x2	    // Local Descriptor Table
191 #define STS_T16B	0x3	    // Busy 16-bit TSS
192 #define STS_CG16	0x4	    // 16-bit Call Gate
193 #define STS_TG		0x5	    // Task Gate / Coum Transmitions
194 #define STS_IG16	0x6	    // 16-bit Interrupt Gate
195 #define STS_TG16	0x7	    // 16-bit Trap Gate
196 #define STS_T32A	0x9	    // Available 32-bit TSS
197 #define STS_T32B	0xB	    // Busy 32-bit TSS
198 #define STS_CG32	0xC	    // 32-bit Call Gate
199 #define STS_IG32	0xE	    // 32-bit Interrupt Gate
200 #define STS_TG32	0xF	    // 32-bit Trap Gate
201 
202 
203 /*
204  *
205  *	Part 3.  Traps.
206  *
207  */
208 
209 #ifndef __ASSEMBLER__
210 
211 // Task state segment format (as described by the Pentium architecture book)
212 struct Taskstate {
213 	uint32_t ts_link;	// Old ts selector
214 	uintptr_t ts_esp0;	// Stack pointers and segment selectors
215 	uint16_t ts_ss0;	//   after an increase in privilege level
216 	uint16_t ts_padding1;
217 	uintptr_t ts_esp1;
218 	uint16_t ts_ss1;
219 	uint16_t ts_padding2;
220 	uintptr_t ts_esp2;
221 	uint16_t ts_ss2;
222 	uint16_t ts_padding3;
223 	physaddr_t ts_cr3;	// Page directory base
224 	uintptr_t ts_eip;	// Saved state from last task switch
225 	uint32_t ts_eflags;
226 	uint32_t ts_eax;	// More saved state (registers)
227 	uint32_t ts_ecx;
228 	uint32_t ts_edx;
229 	uint32_t ts_ebx;
230 	uintptr_t ts_esp;
231 	uintptr_t ts_ebp;
232 	uint32_t ts_esi;
233 	uint32_t ts_edi;
234 	uint16_t ts_es;		// Even more saved state (segment selectors)
235 	uint16_t ts_padding4;
236 	uint16_t ts_cs;
237 	uint16_t ts_padding5;
238 	uint16_t ts_ss;
239 	uint16_t ts_padding6;
240 	uint16_t ts_ds;
241 	uint16_t ts_padding7;
242 	uint16_t ts_fs;
243 	uint16_t ts_padding8;
244 	uint16_t ts_gs;
245 	uint16_t ts_padding9;
246 	uint16_t ts_ldt;
247 	uint16_t ts_padding10;
248 	uint16_t ts_t;		// Trap on task switch
249 	uint16_t ts_iomb;	// I/O map base address
250 };
251 
252 // Gate descriptors for interrupts and traps
253 struct Gatedesc {
254 	unsigned gd_off_15_0 : 16;   // low 16 bits of offset in segment
255 	unsigned gd_ss : 16;         // segment selector
256 	unsigned gd_args : 5;        // # args, 0 for interrupt/trap gates
257 	unsigned gd_rsv1 : 3;        // reserved(should be zero I guess)
258 	unsigned gd_type : 4;        // type(STS_{TG,IG32,TG32})
259 	unsigned gd_s : 1;           // must be 0 (system)
260 	unsigned gd_dpl : 2;         // descriptor(meaning new) privilege level
261 	unsigned gd_p : 1;           // Present
262 	unsigned gd_off_31_16 : 16;  // high bits of offset in segment
263 };
264 
265 // Set up a normal interrupt/trap gate descriptor.
266 // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
267 // - sel: Code segment selector for interrupt/trap handler
268 // - off: Offset in code segment for interrupt/trap handler
269 // - dpl: Descriptor Privilege Level -
270 //	  the privilege level required for software to invoke
271 //	  this interrupt/trap gate explicitly using an int instruction.
272 #define SETGATE(gate, istrap, sel, off, dpl)			\
273 {								\
274 	(gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;		\
275 	(gate).gd_ss = (sel);					\
276 	(gate).gd_args = 0;					\
277 	(gate).gd_rsv1 = 0;					\
278 	(gate).gd_type = (istrap) ? STS_TG32 : STS_IG32;	\
279 	(gate).gd_s = 0;					\
280 	(gate).gd_dpl = (dpl);					\
281 	(gate).gd_p = 1;					\
282 	(gate).gd_off_31_16 = (uint32_t) (off) >> 16;		\
283 }
284 
285 // Set up a call gate descriptor.
286 #define SETCALLGATE(gate, ss, off, dpl)           	        \
287 {								\
288 	(gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;		\
289 	(gate).gd_ss = (ss);					\
290 	(gate).gd_args = 0;					\
291 	(gate).gd_rsv1 = 0;					\
292 	(gate).gd_type = STS_CG32;				\
293 	(gate).gd_s = 0;					\
294 	(gate).gd_dpl = (dpl);					\
295 	(gate).gd_p = 1;					\
296 	(gate).gd_off_31_16 = (uint32_t) (off) >> 16;		\
297 }
298 
299 // Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
300 struct Pseudodesc {
301 	uint16_t pd__garbage;         // LGDT supposed to be from address 4N+2
302 	uint16_t pd_lim;              // Limit
303 	uint32_t pd_base __attribute__ ((packed));       // Base address
304 };
305 #define PD_ADDR(desc)	(&(desc).pd_lim)
306 
307 #endif /* !__ASSEMBLER__ */
308 
309