1 #ifndef __ARCH_DESC_H
2 #define __ARCH_DESC_H
3 
4 /*
5  * Xen reserves a memory page of GDT entries.
6  * No guest GDT entries exist beyond the Xen reserved area.
7  */
8 #define NR_RESERVED_GDT_PAGES   1
9 #define NR_RESERVED_GDT_BYTES   (NR_RESERVED_GDT_PAGES * PAGE_SIZE)
10 #define NR_RESERVED_GDT_ENTRIES (NR_RESERVED_GDT_BYTES / 8)
11 
12 #define LAST_RESERVED_GDT_PAGE  \
13     (FIRST_RESERVED_GDT_PAGE + NR_RESERVED_GDT_PAGES - 1)
14 #define LAST_RESERVED_GDT_BYTE  \
15     (FIRST_RESERVED_GDT_BYTE + NR_RESERVED_GDT_BYTES - 1)
16 #define LAST_RESERVED_GDT_ENTRY \
17     (FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
18 
19 #define LDT_ENTRY_SIZE 8
20 
21 #define FLAT_COMPAT_RING1_CS 0xe019  /* GDT index 259 */
22 #define FLAT_COMPAT_RING1_DS 0xe021  /* GDT index 260 */
23 #define FLAT_COMPAT_RING1_SS 0xe021  /* GDT index 260 */
24 #define FLAT_COMPAT_RING3_CS 0xe02b  /* GDT index 261 */
25 #define FLAT_COMPAT_RING3_DS 0xe033  /* GDT index 262 */
26 #define FLAT_COMPAT_RING3_SS 0xe033  /* GDT index 262 */
27 
28 #define FLAT_COMPAT_KERNEL_DS FLAT_COMPAT_RING1_DS
29 #define FLAT_COMPAT_KERNEL_CS FLAT_COMPAT_RING1_CS
30 #define FLAT_COMPAT_KERNEL_SS FLAT_COMPAT_RING1_SS
31 #define FLAT_COMPAT_USER_DS   FLAT_COMPAT_RING3_DS
32 #define FLAT_COMPAT_USER_CS   FLAT_COMPAT_RING3_CS
33 #define FLAT_COMPAT_USER_SS   FLAT_COMPAT_RING3_SS
34 
35 #define TSS_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
36 #define LDT_ENTRY (TSS_ENTRY + 2)
37 #define PER_CPU_GDT_ENTRY (LDT_ENTRY + 2)
38 
39 #define TSS_SELECTOR     (TSS_ENTRY << 3)
40 #define LDT_SELECTOR     (LDT_ENTRY << 3)
41 #define PER_CPU_SELECTOR (PER_CPU_GDT_ENTRY << 3)
42 
43 #ifndef __ASSEMBLY__
44 
45 #define GUEST_KERNEL_RPL(d) (is_pv_32bit_domain(d) ? 1 : 3)
46 
47 /* Fix up the RPL of a guest segment selector. */
48 #define __fixup_guest_selector(d, sel)                             \
49 ({                                                                 \
50     uint16_t _rpl = GUEST_KERNEL_RPL(d);                           \
51     (sel) = (((sel) & 3) >= _rpl) ? (sel) : (((sel) & ~3) | _rpl); \
52 })
53 
54 #define fixup_guest_stack_selector(d, ss) __fixup_guest_selector(d, ss)
55 #define fixup_guest_code_selector(d, cs)  __fixup_guest_selector(d, cs)
56 
57 /*
58  * We need this function because enforcing the correct guest kernel RPL is
59  * unsufficient if the selector is poked into an interrupt, trap or call gate.
60  * The selector RPL is ignored when a gate is accessed. We must therefore make
61  * sure that the selector does not reference a Xen-private segment.
62  *
63  * Note that selectors used only by IRET do not need to be checked. If the
64  * descriptor DPL fiffers from CS RPL then we'll #GP.
65  *
66  * Stack and data selectors do not need to be checked. If DS, ES, FS, GS are
67  * DPL < CPL then they'll be cleared automatically. If SS RPL or DPL differs
68  * from CS RPL then we'll #GP.
69  */
70 #define guest_gate_selector_okay(d, sel)                                \
71     ((((sel)>>3) < FIRST_RESERVED_GDT_ENTRY) || /* Guest seg? */        \
72      ((sel) == (!is_pv_32bit_domain(d) ?                                \
73                 FLAT_KERNEL_CS :                /* Xen default seg? */  \
74                 FLAT_COMPAT_KERNEL_CS)) ||                              \
75      ((sel) & 4))                               /* LDT seg? */
76 
77 #endif /* __ASSEMBLY__ */
78 
79 /* These are bitmasks for the high 32 bits of a descriptor table entry. */
80 #define _SEGMENT_TYPE    (15<< 8)
81 #define _SEGMENT_WR      ( 1<< 9) /* Writeable (data) or Readable (code)
82                                      segment */
83 #define _SEGMENT_EC      ( 1<<10) /* Expand-down or Conforming segment */
84 #define _SEGMENT_CODE    ( 1<<11) /* Code (vs data) segment for non-system
85                                      segments */
86 #define _SEGMENT_S       ( 1<<12) /* System descriptor (yes iff S==0) */
87 #define _SEGMENT_DPL     ( 3<<13) /* Descriptor Privilege Level */
88 #define _SEGMENT_P       ( 1<<15) /* Segment Present */
89 #define _SEGMENT_L       ( 1<<21) /* 64-bit segment */
90 #define _SEGMENT_DB      ( 1<<22) /* 16- or 32-bit segment */
91 #define _SEGMENT_G       ( 1<<23) /* Granularity */
92 
93 #ifndef __ASSEMBLY__
94 
95 /* System Descriptor types for GDT and IDT entries. */
96 #define SYS_DESC_tss16_avail  1
97 #define SYS_DESC_ldt          2
98 #define SYS_DESC_tss16_busy   3
99 #define SYS_DESC_call_gate16  4
100 #define SYS_DESC_task_gate    5
101 #define SYS_DESC_irq_gate16   6
102 #define SYS_DESC_trap_gate16  7
103 #define SYS_DESC_tss_avail    9
104 #define SYS_DESC_tss_busy     11
105 #define SYS_DESC_call_gate    12
106 #define SYS_DESC_irq_gate     14
107 #define SYS_DESC_trap_gate    15
108 
109 typedef union {
110     uint64_t raw;
111     struct {
112         uint32_t a, b;
113     };
114 } seg_desc_t;
115 
116 typedef union {
117     struct {
118         uint64_t a, b;
119     };
120     struct {
121         uint16_t addr0;
122         uint16_t cs;
123         uint8_t  ist; /* :3, 5 bits rsvd, but this yields far better code. */
124         uint8_t  type:4, s:1, dpl:2, p:1;
125         uint16_t addr1;
126         uint32_t addr2;
127         /* 32 bits rsvd. */
128     };
129 } idt_entry_t;
130 
131 /* Write the lower 64 bits of an IDT Entry. This relies on the upper 32
132  * bits of the address not changing, which is a safe assumption as all
133  * functions we are likely to load will live inside the 1GB
134  * code/data/bss address range.
135  *
136  * Ideally, we would use cmpxchg16b, but this is not supported on some
137  * old AMD 64bit capable processors, and has no safe equivalent.
138  */
_write_gate_lower(volatile idt_entry_t * gate,const idt_entry_t * new)139 static inline void _write_gate_lower(volatile idt_entry_t *gate,
140                                      const idt_entry_t *new)
141 {
142     ASSERT(gate->b == new->b);
143     gate->a = new->a;
144 }
145 
146 #define _set_gate(gate_addr,type,dpl,addr)               \
147 do {                                                     \
148     (gate_addr)->a = 0;                                  \
149     smp_wmb(); /* disable gate /then/ rewrite */         \
150     (gate_addr)->b =                                     \
151         ((unsigned long)(addr) >> 32);                   \
152     smp_wmb(); /* rewrite /then/ enable gate */          \
153     (gate_addr)->a =                                     \
154         (((unsigned long)(addr) & 0xFFFF0000UL) << 32) | \
155         ((unsigned long)(dpl) << 45) |                   \
156         ((unsigned long)(type) << 40) |                  \
157         ((unsigned long)(addr) & 0xFFFFUL) |             \
158         ((unsigned long)__HYPERVISOR_CS << 16) |         \
159         (1UL << 47);                                     \
160 } while (0)
161 
_set_gate_lower(idt_entry_t * gate,unsigned long type,unsigned long dpl,void * addr)162 static inline void _set_gate_lower(idt_entry_t *gate, unsigned long type,
163                                    unsigned long dpl, void *addr)
164 {
165     idt_entry_t idte;
166     idte.b = gate->b;
167     idte.a =
168         (((unsigned long)(addr) & 0xFFFF0000UL) << 32) |
169         ((unsigned long)(dpl) << 45) |
170         ((unsigned long)(type) << 40) |
171         ((unsigned long)(addr) & 0xFFFFUL) |
172         ((unsigned long)__HYPERVISOR_CS << 16) |
173         (1UL << 47);
174     _write_gate_lower(gate, &idte);
175 }
176 
177 /* Update the lower half handler of an IDT Entry, without changing any
178  * other configuration. */
_update_gate_addr_lower(idt_entry_t * gate,void * addr)179 static inline void _update_gate_addr_lower(idt_entry_t *gate, void *addr)
180 {
181     idt_entry_t idte;
182     idte.a = gate->a;
183 
184     idte.b = ((unsigned long)(addr) >> 32);
185     idte.a &= 0x0000FFFFFFFF0000ULL;
186     idte.a |= (((unsigned long)(addr) & 0xFFFF0000UL) << 32) |
187         ((unsigned long)(addr) & 0xFFFFUL);
188 
189     _write_gate_lower(gate, &idte);
190 }
191 
192 #define _set_tssldt_desc(desc,addr,limit,type)           \
193 do {                                                     \
194     (desc)[0].b = (desc)[1].b = 0;                       \
195     smp_wmb(); /* disable entry /then/ rewrite */        \
196     (desc)[0].a =                                        \
197         ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF);   \
198     (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32);  \
199     smp_wmb(); /* rewrite /then/ enable entry */         \
200     (desc)[0].b =                                        \
201         ((u32)(addr) & 0xFF000000U) |                    \
202         ((u32)(type) << 8) | 0x8000U |                   \
203         (((u32)(addr) & 0x00FF0000U) >> 16);             \
204 } while (0)
205 
206 struct __packed desc_ptr {
207 	unsigned short limit;
208 	unsigned long base;
209 };
210 
211 extern seg_desc_t boot_gdt[];
212 DECLARE_PER_CPU(seg_desc_t *, gdt);
213 DECLARE_PER_CPU(l1_pgentry_t, gdt_l1e);
214 extern seg_desc_t boot_compat_gdt[];
215 DECLARE_PER_CPU(seg_desc_t *, compat_gdt);
216 DECLARE_PER_CPU(l1_pgentry_t, compat_gdt_l1e);
217 DECLARE_PER_CPU(bool, full_gdt_loaded);
218 
lgdt(const struct desc_ptr * gdtr)219 static inline void lgdt(const struct desc_ptr *gdtr)
220 {
221     __asm__ __volatile__ ( "lgdt %0" :: "m" (*gdtr) : "memory" );
222 }
223 
lidt(const struct desc_ptr * idtr)224 static inline void lidt(const struct desc_ptr *idtr)
225 {
226     __asm__ __volatile__ ( "lidt %0" :: "m" (*idtr) : "memory" );
227 }
228 
lldt(unsigned int sel)229 static inline void lldt(unsigned int sel)
230 {
231     __asm__ __volatile__ ( "lldt %w0" :: "rm" (sel) : "memory" );
232 }
233 
ltr(unsigned int sel)234 static inline void ltr(unsigned int sel)
235 {
236     __asm__ __volatile__ ( "ltr %w0" :: "rm" (sel) : "memory" );
237 }
238 
239 #endif /* !__ASSEMBLY__ */
240 
241 #endif /* __ARCH_DESC_H */
242