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