Reworks memlayout (XCC)
[akaros.git] / kern / arch / x86 / ros / mmu64.h
1 #ifndef ROS_INC_ARCH_MMU64_H
2 #define ROS_INC_ARCH_MMU64_H
3
4 #ifndef ROS_INC_ARCH_MMU_H
5 #error "Do not include include ros/arch/mmu64.h directly"
6 #endif
7
8 #ifndef __ASSEMBLER__
9 #include <ros/common.h>
10 typedef unsigned long pte_t;
11 typedef unsigned long pde_t;
12 #endif
13
14 /* Virtual memory map:                                  Virt Addresses
15  *                                                      perms: kernel/user
16  *
17  *                     +------------------------------+ 0xffffffffffffffff -+
18  *                     |                              |                     |
19  *                     |   Mapped to lowmem, unused   | RW/--               |
20  *                     |                              |                     |
21  *  "end" symbol  -->  +------------------------------+        PML3_PTE_REACH
22  *                     |                              |                     |
23  *                     |  Kernel link/load location   |                     |
24  *                     |    (mapped to 0, physical)   |                     |
25  *                     |                              |                     |
26  * KERN_LOAD_ADDR -->  +------------------------------+ 0xffffffffc0000000 -+
27  *                     |                              |
28  *                     |          Local APIC          | RW/--  PGSIZE
29  *                     |                              |
30  *    LAPIC_BASE  -->  +------------------------------+ 0xffffffffbffff000
31  *                     |                              |
32  *                     |            IOAPIC            | RW/--  PGSIZE
33  *                     |                              |
34  *  IOAPIC_BASE,  -->  +------------------------------+ 0xffffffffbfffe000
35  *  KERN_DYN_TOP       |   Kernel Dynamic Mappings    |
36  *                     |              .               |
37  *                     :              .               :
38  *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RW/--
39  *                     :                              :
40  *                     |          Unmapped            | --/--
41  *                     |                              |
42  *                     |  Kernel static linking limit |
43  *                     +------------------------------+ 0xffffffff80000000
44  *                     |                              |
45  *                     |                              |
46  *                     |                              |
47  *  VPT_TOP    ----->  +------------------------------+ 0xffffff0000000000 -+
48  *                     |                              |                     |
49  *                     |                              |                     |
50  *                     |  Cur. Page Table (Kern. RW)  | RW/--  P4ML_PTE_REACH
51  *                     |                              |                     |
52  *                     |                              |                     |
53  *    VPT,     ----->  +------------------------------+ 0xfffffe8000000000 -+
54  *  KERN_VMAP_TOP      |                              |
55  *                     :              .               :
56  *                     :              .               :
57  *                     :              .               :
58  *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
59  *                     |                              | RW/--
60  *                     |                              | RW/--
61  *                     |                              | RW/--
62  *                     |   Remapped Physical Memory   | RW/--
63  *                     |                              | RW/--
64  *                     |                              | RW/--
65  *                     |                              | RW/--
66  *    KERNBASE  ---->  +------------------------------+ 0xffff800000000000
67  *                     |                              |
68  *                     |                              |
69  *                     |                              |
70  *                     |   Non-canonical addresses    |
71  *                     |         (unusable)           |
72  *                     |                              |
73  *                     |                              |
74  * ULIM (not canon) -> +------------------------------+ 0x0000800000000000 -+
75  *                     +     Highest user address     + 0x00007fffffffffff  |
76  *                     |                              |                     |
77  *                     |  Cur. Page Table (User R-)   | R-/R-  PML4_PTE_REACH
78  *                     |                              |                     |
79  *    UVPT      ---->  +------------------------------+ 0x00007f8000000000 -+
80  *                     | Unmapped (expandable region) |                     |
81  *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|                     |
82  *                     |     Per-Process R/O Info     | R-/R-  PML2_PTE_REACH
83  *                     |         (procinfo)           |                     |
84  * UWLIM, UINFO ---->  +------------------------------+ 0x00007f7fffe00000 -+
85  *                     | Unmapped (expandable region) |                     |
86  *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|                     |
87  *                     |     Per-Process R/W Data     | RW/RW  PML2_PTE_REACH
88  *                     |         (procdata)           |                     |
89  *    UDATA     ---->  +------------------------------+ 0x00007f7fffc00000 -+
90  *                     |                              |
91  *                     |    Global Shared R/W Data    | RW/RW  PGSIZE
92  *                     |                              |
93  * UMAPTOP, UGDATA ->  +------------------------------+ 0x00007f7fffbff000
94  *    USTACKTOP        |                              |
95  *                     |      Normal User Stack       | RW/RW 256 * PGSIZE
96  *                     |                              |
97  *                     +------------------------------+ 0x00007f7fffbfb000
98  *                     |                              |
99  *                     |        Empty Memory          |
100  *                     |                              |
101  *                     .                              .
102  *                     .                              .
103  *    BRK_END   ---->  +------------------------------+ 0x0000400000000000
104  *                     .                              .
105  *                     .                              .
106  *                     |                              |
107  *                     |        Empty Memory          |
108  *                     |                              |
109  *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
110  *                     |                              |
111  *                     |     Program Data & Heap      |
112  *                     |                              |
113  *                     +------------------------------+ 0x0000000000400000
114  *                     |                              |
115  *                     |       Empty Memory (*)       |
116  *                     |                              |
117  *                     +------------------------------+ 0x0000000000000000
118  */
119
120 /* Physical Mapping symbols:
121  * At IOPHYSMEM (640K) there is a 384K hole for I/O.  From the kernel,
122  * IOPHYSMEM can be addressed at KERNBASE + IOPHYSMEM.  The hole ends
123  * at physical address EXTPHYSMEM. */
124 #define IOPHYSMEM               0x0A0000
125 #define VGAPHYSMEM              0x0A0000
126 #define DEVPHYSMEM              0x0C0000
127 #define BIOSPHYSMEM             0x0F0000
128 #define EXTPHYSMEM              0x100000
129
130 /* Kernel Virtual Memory Mapping */
131
132 /* The kernel needs to be loaded in the top 2 GB of memory, since we compile it
133  * with -mcmodel=kernel (helps with relocations).  We're actually loading it in
134  * the top 1 GB. */
135 #define KERN_LOAD_ADDR  0xffffffffc0000000
136 /* Static kernel mappings */
137 #define LAPIC_BASE              (KERN_LOAD_ADDR - PGSIZE)
138 #define IOAPIC_BASE             (LAPIC_BASE - PGSIZE)
139 /* All arches must define this, which is the lower limit of their static
140  * mappings, and where the dynamic mappings will start. */
141 #define KERN_DYN_TOP    IOAPIC_BASE
142
143 /* Virtual page table.  Every PML4 has a PTE at the slot (PML4(VPT))
144  * corresponding to VPT that points to that PML4's base.  In essence, the 512
145  * GB chunk of the VA space from VPT..VPT_TOP is a window into the paging
146  * structure.
147  *
148  * The VPT needs to be aligned on 39 bits.
149  *
150  * Ex: Say the VPT's entry in 9 bits is "9v".  If you construct a VA from:
151  * 9v9v9v9v000, the paging hardware will recurse 4 times, with the end result
152  * being the PML4.  That virtual address will map to the PML4 itself.
153  *
154  * If you want to see a specific PML3, figure out which entry it is in the
155  * PML4 (using PML3(va)), say 9 bits = "9X".  The VA 9v9v9v9X000 will map to
156  * that PML3. */
157 #define VPT_TOP                 0xffffff0000000000
158 #define VPT                             (VPT_TOP - PML4_PTE_REACH)
159 /* Helper to return the current outer pgdir via the VPT mapping. */
160 #define VPD (VPT + (VPT >> 9) + (VPT >> 18) + (VPT >> 27))
161 #define vpd VPD
162
163 /* Top of the kernel virtual mapping area (KERNBASE) */
164 #define KERN_VMAP_TOP   (VPT)
165 /* Base of the physical memory map. This maps from 0 physical to max_paddr */
166 #define KERNBASE        0xffff800000000000
167
168 /* Highest user address: 0x00007fffffffffff: 1 zero, 47 ones, sign extended.
169  * From here down to UWLIM is User Read-only */
170 #define ULIM            0x0000800000000000
171 /* Same as VPT but read-only for users */
172 #define UVPT                    (ULIM - PML4_PTE_REACH)
173 /* Arbitrary boundary between the break and the start of
174  * memory returned by calls to mmap with addr = 0 */
175 #define BRK_END                 0x0000400000000000
176
177 /* **************************************** */
178 /* Page table constants, macros, etc */
179
180 /* A linear address 'la' has a five-part structure as follows:
181  *
182  * +-----9------+-----9------+-----9------+-----9------+---------12----------+
183  * | PML4 bits  | PML3 bits  | PML2 bits  | PML1 bits  |     Page offset     |
184  * |   offset   |   offset   |   offset   |   offset   |                     |
185  * +------------+------------+------------+------------+---------------------+
186  *  \ PML4(la) / \ PML3(la) / \ PML2(la) / \ PML1(la) / \---- PGOFF(la) ----/
187  *  \------------------ LA2PPN(la) -------------------/
188  *
189  * The PMLx, PGOFF, and LA2PPN macros decompose linear addresses as shown.
190  * To construct a linear address la from these, use:
191  * PGADDR(PML4(la), PML3(la), PML2(la), PML1(la), PGOFF(la)).
192  * Careful, that's arch- and bit-specific.
193  *
194  * I'd somewhat like it if we started counting from the outer-most PT, though
195  * amd coined the term PML4 for the outermost, instead of PML1.  Incidentally,
196  * they also don't use numbers other than PML4, sticking with names like PDP. */
197
198 #define PML4_SHIFT              39
199 #define PML3_SHIFT              30
200 #define PML2_SHIFT              21
201 #define PML1_SHIFT              12
202
203 /* PTE reach is the amount of VM an entry can map, either as a jumbo or as
204  * further page tables.  I'd like to write these as shifts, but I can't please
205  * both the compiler and the assembler. */
206 #define PML4_PTE_REACH  (0x0000008000000000)    /* No jumbos available */
207 #define PML3_PTE_REACH  (0x0000000040000000)    /* 1 GB jumbos available */
208 #define PML2_PTE_REACH  (0x0000000000200000)    /* 2 MB jumbos available */
209 #define PML1_PTE_REACH  (0x0000000000001000)    /* aka, PGSIZE */
210
211 /* Reach is the amount of VM a table can map, counting all of its entries.
212  * Note that a PML(n)_PTE is a PML(n-1) table. */
213 #define PML3_REACH              (PML4_PTE_REACH)
214 #define PML2_REACH              (PML3_PTE_REACH)
215 #define PML1_REACH              (PML2_PTE_REACH)
216
217 /* PMLx(la) gives the 9 bits specifying the la's entry in PML x */
218 #define PML4(la)                (((uintptr_t)(la) >> PML4_SHIFT) & 0x1ff)
219 #define PML3(la)                (((uintptr_t)(la) >> PML3_SHIFT) & 0x1ff)
220 #define PML2(la)                (((uintptr_t)(la) >> PML2_SHIFT) & 0x1ff)
221 #define PML1(la)                (((uintptr_t)(la) >> PML1_SHIFT) & 0x1ff)
222
223 /* Common kernel helpers */
224 #define PGSHIFT                 PML1_SHIFT
225 #define PGSIZE                  PML1_PTE_REACH
226 #define LA2PPN(la)              ((uintptr_t)(la) >> PGSHIFT)
227 #define PTE2PPN(pte)    LA2PPN(pte)
228 #define PGOFF(la)               ((uintptr_t)(la) & (PGSIZE - 1))
229
230 /* construct PTE from PPN and flags */
231 #define PTE(ppn, flags) ((ppn) << PGSHIFT | PGOFF(flags))
232
233 /* construct linear address from indexes and offset */
234 #define PGADDR(p4, p3, p2, p1, o) ((void*)(((p4) << PML4_SHIFT) |              \
235                                            ((p3) << PML3_SHIFT) |              \
236                                            ((p2) << PML2_SHIFT) |              \
237                                            ((p1) << PML1_SHIFT) |(o)))
238
239 /* These are used in older code, referring to the outer-most page table */
240 #define PDX(la)                 PML4(la)
241 #define NPDENTRIES              512
242 /* This is used in places (procinfo) meaning "size of smallest jumbo page" */
243 #define PTSIZE PML2_PTE_REACH
244
245
246 /* TODO: not sure if we'll need these - limited to 64bit code */
247 /* this only gives us the L1 PML */
248 #define PTX(la)         ((((uintptr_t) (la)) >> 12) & 0x1ff)
249 #define JPGOFF(la)      (((uintptr_t) (la)) & 0x001FFFFF)
250 #define NPTENTRIES              512
251 #define JPGSIZE PTSIZE
252
253
254 /* Page table/directory entry flags. */
255
256 /* Some things to be careful of:  Global and PAT only apply to the last PTE in
257  * a chain: so either a PTE in PML1, or a Jumbo PTE in PML2 or 3.  When PAT
258  * applies, which bit we use depends on whether we are jumbo or not.  For PML1,
259  * PAT is bit 8.  For jumbo PTEs (and only when they are for a jumbo page), we
260  * use bit 12. */
261 #define PTE_P                   0x001   /* Present */
262 #define PTE_W                   0x002   /* Writeable */
263 #define PTE_U                   0x004   /* User */
264 #define PTE_PWT                 0x008   /* Write-Through */
265 #define PTE_PCD                 0x010   /* Cache-Disable */
266 #define PTE_A                   0x020   /* Accessed */
267 #define PTE_D                   0x040   /* Dirty */
268 #define PTE_PS                  0x080   /* Page Size */
269 #define PTE_PAT                 0x080   /* Page attribute table */
270 #define PTE_G                   0x100   /* Global Page */
271 #define PTE_JPAT                0x800   /* Jumbo PAT */
272
273 /* Permissions fields and common access modes.  These should be read as 'just
274  * kernel or user too' and 'RO or RW'.  USER_RO means read-only for everyone. */
275 #define PTE_PERM                (PTE_W | PTE_U)
276 #define PTE_KERN_RW             PTE_W           // Kernel Read/Write
277 #define PTE_KERN_RO             0               // Kernel Read-Only
278 #define PTE_USER_RW             (PTE_W | PTE_U) // Kernel/User Read/Write
279 #define PTE_USER_RO             PTE_U           // Kernel/User Read-Only
280
281 /* The PTE/translation part of a PTE/virtual(linear) address.  It's used
282  * frequently to be the page address of a virtual address. */
283 #define PTE_ADDR(pte)   ((physaddr_t) (pte) & ~(PGSIZE - 1))
284 /* More meaningful macro, same as PTE_ADDR */
285 #define PG_ADDR(la)     ((uintptr_t)(la) & ~(PGSIZE - 1))
286
287 /* we must guarantee that for any PTE, exactly one of the following is true */
288 #define PAGE_PRESENT(pte) ((pte) & PTE_P)
289 #define PAGE_UNMAPPED(pte) ((pte) == 0)
290 #define PAGE_PAGED_OUT(pte) (!PAGE_PRESENT(pte) && !PAGE_UNMAPPED(pte))
291
292
293 /* **************************************** */
294 /* Segmentation */
295 // XXX 64b: these all need redone
296
297 // Global descriptor numbers
298 #define GD_NULL   0x00     // NULL descriptor
299 #define GD_KT     0x08     // kernel text
300 #define GD_KD     0x10     // kernel data
301 #define GD_UT     0x18     // user text
302 #define GD_UD     0x20     // user data
303 #define GD_TSS    0x28     // Task segment selector
304 #define GD_LDT    0x30     // local descriptor table
305
306 #ifdef __ASSEMBLER__
307
308 /* Macros to build GDT entries in assembly. */
309 #define SEG_NULL                                                \
310         .word 0, 0;                                             \
311         .byte 0, 0, 0, 0
312
313 /* 64 bit code segment.  This is for long mode, no compatibility.  If we want
314  * to support 32 bit apps later, we'll want to adjust this. */
315 #define SEG_CODE_64(dpl)                                                    \
316         .word 0, 0;                                                             \
317         .byte 0;                                                                \
318         .byte (((1/*p*/) << 7) | ((dpl) << 5) | 0x18 | ((0/*c*/) << 2));        \
319         .byte (((0/*d*/) << 6) | ((1/*l*/) << 5));                              \
320         .byte 0;
321
322 /* 64 bit data segment.  These are pretty much completely ignored (except if we
323  * use them for fs/gs, or compatibility mode */
324 #define SEG_DATA_64                                                         \
325         .word 0, 0;                                                             \
326         .byte 0;                                                                \
327         .byte 0x90;                                                             \
328         .word 0;
329
330 /* Default segment (32 bit style).  Would work for fs/gs, if needed */
331 #define SEG(type, base, lim)                                                \
332         .word (((lim) >> 12) & 0xffff);                                         \
333         .word ((base) & 0xffff);                                                \
334         .byte (((base) >> 16) & 0xff);                                          \
335         .byte (0x90 | (type));                                                  \
336         .byte (0xC0 | (((lim) >> 28) & 0xf));                                   \
337         .byte (((base) >> 24) & 0xff)
338
339 #else   // not __ASSEMBLER__
340
341 /* TODO: consider removing this, if we're just using one asm GDT */
342 // Segment Descriptors
343 typedef struct Segdesc {
344         unsigned sd_lim_15_0 : 16;  // Low bits of segment limit
345         unsigned sd_base_15_0 : 16; // Low bits of segment base address
346         unsigned sd_base_23_16 : 8; // Middle bits of segment base address
347         unsigned sd_type : 4;       // Segment type (see STS_ constants)
348         unsigned sd_s : 1;          // 0 = system, 1 = application
349         unsigned sd_dpl : 2;        // Descriptor Privilege Level
350         unsigned sd_p : 1;          // Present
351         unsigned sd_lim_19_16 : 4;  // High bits of segment limit
352         unsigned sd_avl : 1;        // Unused (available for software use)
353         unsigned sd_rsv1 : 1;       // Reserved
354         unsigned sd_db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
355         unsigned sd_g : 1;          // Granularity: limit scaled by 4K when set
356         unsigned sd_base_31_24 : 8; // High bits of segment base address
357 } segdesc_t;
358 // Null segment
359 #define SEG_NULL        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
360 // Segment that is loadable but faults when used
361 #define SEG_FAULT       { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
362 // Normal segment
363 #define SEG(type, base, lim, dpl)                                                                       \
364 { ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,       \
365     type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                        \
366     (unsigned) (base) >> 24 }
367 // System segment (LDT)
368 #define SEG_SYS(type, base, lim, dpl)                                                                   \
369 { ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,       \
370     type, 0, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,                        \
371     (unsigned) (base) >> 24 }
372
373 #define SEG16(type, base, lim, dpl)                                                             \
374 { (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,                       \
375     type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,                        \
376     (unsigned) (base) >> 24 }
377
378 #define SEG16ROINIT(seg,type,base,lim,dpl) \
379         {\
380                 (seg).sd_lim_15_0 = SINIT((lim) & 0xffff);\
381                 (seg).sd_base_15_0 = SINIT((uintptr_t)(base)&0xffff);\
382                 (seg).sd_base_23_16 = SINIT(((uintptr_t)(base)>>16)&0xff);\
383                 (seg).sd_type = SINIT(type);\
384                 (seg).sd_s = SINIT(1);\
385                 (seg).sd_dpl = SINIT(dpl);\
386                 (seg).sd_p = SINIT(1);\
387                 (seg).sd_lim_19_16 = SINIT((unsigned)(lim)>>16);\
388                 (seg).sd_avl = SINIT(0);\
389                 (seg).sd_rsv1 = SINIT(0);\
390                 (seg).sd_db = SINIT(1);\
391                 (seg).sd_g = SINIT(0);\
392                 (seg).sd_base_31_24 = SINIT((uintptr_t)(base)>> 24);\
393         }
394
395 // Task state segment format (as described by the Pentium architecture book)
396 typedef struct Taskstate {
397         uintptr_t ts_link;      // Old ts selector
398         uintptr_t ts_esp0;      // Stack pointers and segment selectors
399         uint16_t ts_ss0;        //   after an increase in privilege level
400         uint16_t ts_padding1;
401         uintptr_t ts_esp1;
402         uint16_t ts_ss1;
403         uint16_t ts_padding2;
404         uintptr_t ts_esp2;
405         uint16_t ts_ss2;
406         uint16_t ts_padding3;
407         physaddr_t ts_cr3;      // Page directory base
408         uintptr_t ts_eip;       // Saved state from last task switch
409         uintptr_t ts_eflags;
410         uintptr_t ts_eax;       // More saved state (registers)
411         uintptr_t ts_ecx;
412         uintptr_t ts_edx;
413         uintptr_t ts_ebx;
414         uintptr_t ts_esp;
415         uintptr_t ts_ebp;
416         uintptr_t ts_esi;
417         uintptr_t ts_edi;
418         uint16_t ts_es;         // Even more saved state (segment selectors)
419         uint16_t ts_padding4;
420         uint16_t ts_cs;
421         uint16_t ts_padding5;
422         uint16_t ts_ss;
423         uint16_t ts_padding6;
424         uint16_t ts_ds;
425         uint16_t ts_padding7;
426         uint16_t ts_fs;
427         uint16_t ts_padding8;
428         uint16_t ts_gs;
429         uint16_t ts_padding9;
430         uint16_t ts_ldt;
431         uint16_t ts_padding10;
432         uint16_t ts_t;          // Trap on task switch
433         uint16_t ts_iomb;       // I/O map base address
434 } taskstate_t;
435
436 // Gate descriptors for interrupts and traps
437 typedef struct Gatedesc {
438         unsigned gd_off_15_0 : 16;   // low 16 bits of offset in segment
439         unsigned gd_ss : 16;         // segment selector
440         unsigned gd_args : 5;        // # args, 0 for interrupt/trap gates
441         unsigned gd_rsv1 : 3;        // reserved(should be zero I guess)
442         unsigned gd_type : 4;        // type(STS_{TG,IG32,TG32})
443         unsigned gd_s : 1;           // must be 0 (system)
444         unsigned gd_dpl : 2;         // DPL - highest ring allowed to use this
445         unsigned gd_p : 1;           // Present
446         unsigned gd_off_31_16 : 16;  // high bits of offset in segment
447 } gatedesc_t;
448
449 // Set up a normal interrupt/trap gate descriptor.
450 // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
451 //   - interrupt gates automatically disable interrupts (cli)
452 // - sel: Code segment selector for interrupt/trap handler
453 // - off: Offset in code segment for interrupt/trap handler
454 // - dpl: Descriptor Privilege Level -
455 //        the privilege level required for software to invoke
456 //        this interrupt/trap gate explicitly using an int instruction.
457 #define SETGATE(gate, istrap, sel, off, dpl)                    \
458 {                                                               \
459         (gate).gd_off_15_0 = (uintptr_t) (off) & 0xffff;                \
460         (gate).gd_ss = (sel);                                   \
461         (gate).gd_args = 0;                                     \
462         (gate).gd_rsv1 = 0;                                     \
463         (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32;        \
464         (gate).gd_s = 0;                                        \
465         (gate).gd_dpl = (dpl);                                  \
466         (gate).gd_p = 1;                                        \
467         (gate).gd_off_31_16 = (uintptr_t) (off) >> 16;          \
468 }
469
470 #define ROSETGATE(gate, istrap, sel, off, dpl)                  \
471 {                                                               \
472         (gate).gd_off_15_0 = SINIT((uintptr_t) (off) & 0xffff);         \
473         (gate).gd_ss = SINIT(sel);                                      \
474         (gate).gd_args = SINIT(0);                                      \
475         (gate).gd_rsv1 = SINIT(0);                                      \
476         (gate).gd_type = SINIT((istrap) ? STS_TG32 : STS_IG32); \
477         (gate).gd_s = SINIT(0);                                 \
478         (gate).gd_dpl = SINIT(dpl);                                     \
479         (gate).gd_p = SINIT(1);                                 \
480         (gate).gd_off_31_16 = SINIT((uintptr_t) (off) >> 16);           \
481 }
482
483 // Set up a call gate descriptor.
484 #define SETCALLGATE(gate, ss, off, dpl)                         \
485 {                                                               \
486         (gate).gd_off_15_0 = (uintptr_t) (off) & 0xffff;                \
487         (gate).gd_ss = (ss);                                    \
488         (gate).gd_args = 0;                                     \
489         (gate).gd_rsv1 = 0;                                     \
490         (gate).gd_type = STS_CG32;                              \
491         (gate).gd_s = 0;                                        \
492         (gate).gd_dpl = (dpl);                                  \
493         (gate).gd_p = 1;                                        \
494         (gate).gd_off_31_16 = (uintptr_t) (off) >> 16;          \
495 }
496
497 // Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
498 typedef struct Pseudodesc {
499         uint16_t pd_lim;                // Limit
500         uintptr_t pd_base;              // Base address
501 } __attribute__ ((packed)) pseudodesc_t;
502
503 extern segdesc_t (COUNT(SEG_COUNT) RO gdt)[];
504 extern pseudodesc_t gdt_pd;
505
506 #endif /* !__ASSEMBLER__ */
507
508 // Application segment type bits
509 #define STA_X           0x8         // Executable segment
510 #define STA_E           0x4         // Expand down (non-executable segments)
511 #define STA_C           0x4         // Conforming code segment (executable only)
512 #define STA_W           0x2         // Writeable (non-executable segments)
513 #define STA_R           0x2         // Readable (executable segments)
514 #define STA_A           0x1         // Accessed
515
516 // System segment type bits
517 #define STS_T16A        0x1         // Available 16-bit TSS
518 #define STS_LDT         0x2         // Local Descriptor Table
519 #define STS_T16B        0x3         // Busy 16-bit TSS
520 #define STS_CG16        0x4         // 16-bit Call Gate
521 #define STS_TG          0x5         // Task Gate / Coum Transmitions
522 #define STS_IG16        0x6         // 16-bit Interrupt Gate
523 #define STS_TG16        0x7         // 16-bit Trap Gate
524 #define STS_T32A        0x9         // Available 32-bit TSS
525 #define STS_T32B        0xB         // Busy 32-bit TSS
526 #define STS_CG32        0xC         // 32-bit Call Gate
527 #define STS_IG32        0xE         // 32-bit Interrupt Gate
528 #define STS_TG32        0xF         // 32-bit Trap Gate
529
530 #define SEG_COUNT       7               // Number of segments in the steady state
531 #define LDT_SIZE        (8192 * sizeof(segdesc_t))
532
533 #endif /* ROS_INC_ARCH_MMU64_H */