--- /dev/null
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ *
+ * (C) 2016 - Juergen Gross, SUSE Linux GmbH
+ * based on some header files from Xen Test Framework by Andrew Cooper
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DESC_H_
+#define _DESC_H_
+
+/*
+ * Count the number of varadic arguments provided.
+ *
+ * <pre>
+ * VA_NARGS() => 0
+ * VA_NARGS(x) => 1
+ * VA_NARGS(x, y) => 2
+ * </pre>
+ *
+ * Currently functions for 0 to 11 arguments.
+ */
+#define VA_NARGS_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
+#define VA_NARGS(...) \
+ VA_NARGS_(X,##__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+
+/*
+ * Call a macro variation, based on the number of varadic arguments.
+ *
+ * @param macro Partial token to call a variation of.
+ * @param c1 Constant parameter to pass through.
+ * @param ... Varadic arguments to pass through.
+ *
+ * Tokenises 'macro' with the count of varadic arguments, passing 'c1' and the
+ * varadic arguments.
+ *
+ * <pre>
+ * VAR_MACRO_C1(m, c) => m0(c)
+ * VAR_MACRO_C1(m, c, x) => m1(c, x)
+ * VAR_MACRO_C1(m, c, x, y) => m2(c, x, y)
+ * VAR_MACRO_C1(m, c, x, y, z) => m3(c, x, y, z)
+ * </pre>
+ */
+#define VAR_MACRO_C1__(macro, c1, count, ...) macro##count(c1, ##__VA_ARGS__)
+#define VAR_MACRO_C1_(macro, c1, count, ...) \
+ VAR_MACRO_C1__(macro, c1, count, ##__VA_ARGS__)
+#define VAR_MACRO_C1(macro, c1, ...) \
+ VAR_MACRO_C1_(macro, c1, VA_NARGS(__VA_ARGS__), ##__VA_ARGS__)
+
+/*
+ * GDT layout:
+ *
+ * 0 - null
+ * 1 - 64bit supervisor code
+ * 2 - 32bit supervisor code
+ * 3 - 32bit supervisor data
+ * 4 - 64bit userspace code
+ * 5 - 32bit userspace code
+ * 6 - 32bit userspace data
+ * 7 - TSS (two slots in long mode)
+ *
+ * 9-12 - Available for test use
+ */
+
+#define GDTE_CS64_DPL0 1
+#define GDTE_CS32_DPL0 2
+#define GDTE_DS32_DPL0 3
+#define GDTE_CS64_DPL3 4
+#define GDTE_CS32_DPL3 5
+#define GDTE_DS32_DPL3 6
+
+#define GDTE_TSS 7
+
+#define GDTE_AVAIL0 9
+#define GDTE_AVAIL1 10
+#define GDTE_AVAIL2 11
+#define GDTE_AVAIL3 12
+
+#define NR_GDT_ENTRIES 13
+
+#ifdef __x86_64__
+
+#define __KERN_CS (GDTE_CS64_DPL0 * 8)
+#define __KERN_DS (0)
+#define __USER_CS (GDTE_CS64_DPL3 * 8 + 3)
+#define __USER_DS (GDTE_DS32_DPL3 * 8 + 3)
+
+#else /* __x86_64__ */
+
+#define __KERN_CS (GDTE_CS32_DPL0 * 8)
+#define __KERN_DS (GDTE_DS32_DPL0 * 8)
+#define __USER_CS (GDTE_CS32_DPL3 * 8 + 3)
+#define __USER_DS (GDTE_DS32_DPL3 * 8 + 3)
+
+#endif /* __x86_64__ */
+
+#ifndef __ASSEMBLY__
+/* 8 byte user segment descriptor (GDT/LDT entries with .s = 1) */
+struct __packed seg_desc32 {
+ union {
+ /* Raw backing integers. */
+ struct {
+ uint32_t lo, hi;
+ };
+ /* Common named fields. */
+ struct {
+ uint16_t limit0;
+ uint16_t base0;
+ uint8_t base1;
+ unsigned type: 4;
+ unsigned s: 1, dpl: 2, p: 1;
+ unsigned limit: 4;
+ unsigned avl: 1, l: 1, d: 1, g: 1;
+ uint8_t base2;
+ };
+ /* Code segment specific field names. */
+ struct {
+ uint16_t limit0;
+ uint16_t base0;
+ uint8_t base1;
+ unsigned a: 1, r: 1, c: 1, x: 1;
+ unsigned s: 1, dpl: 2, p: 1;
+ unsigned limit: 4;
+ unsigned avl: 1, l: 1, d: 1, g: 1;
+ uint8_t base2;
+ } code;
+ /* Data segment specific field names. */
+ struct {
+ uint16_t limit0;
+ uint16_t base0;
+ uint8_t base1;
+ unsigned a: 1, w: 1, e: 1, x: 1;
+ unsigned s: 1, dpl: 2, p: 1;
+ unsigned limit: 4;
+ unsigned avl: 1, _r0: 1, b: 1, g: 1;
+ uint8_t base2;
+ } data;
+ };
+};
+
+/* 8-byte gate - Protected mode IDT entry, GDT task/call gate. */
+struct __packed seg_gate32 {
+ union {
+ struct {
+ uint32_t lo, hi;
+ };
+ struct {
+ uint16_t offset0;
+ uint16_t selector;
+ uint8_t _r0;
+ unsigned type: 4, s: 1, dpl: 2, p: 1;
+ uint16_t offset1;
+ };
+ };
+};
+
+/* 16-byte gate - Long mode IDT entry. */
+struct __packed seg_gate64 {
+ union {
+ struct {
+ uint64_t lo, hi;
+ };
+ struct {
+ uint16_t offset0;
+ uint16_t selector;
+ unsigned ist: 3, _r0: 5, type: 4, s: 1, dpl: 2, p: 1;
+ uint16_t offset1;
+ uint32_t offset2;
+ uint32_t _r1;
+ };
+ };
+};
+
+/* GDT/LDT attribute flags for user segments */
+
+/* Common */
+#define SEG_ATTR_G 0x8000 /* Granularity of limit (0 = 1, 1 = 4K) */
+#define SEG_ATTR_AVL 0x1000 /* Available for software use */
+#define SEG_ATTR_P 0x0080 /* Present? */
+#define SEG_ATTR_S 0x0010 /* !System desc (0 = system, 1 = user) */
+#define SEG_ATTR_A 0x0001 /* Accessed? (set by hardware) */
+
+#define SEG_ATTR_COMMON 0x8091 /* Commonly set bits (G P S A) */
+
+#define SEG_ATTR_DPL0 0x0000 /* Descriptor privilege level 0 */
+#define SEG_ATTR_DPL1 0x0020 /* Descriptor privilege level 1 */
+#define SEG_ATTR_DPL2 0x0040 /* Descriptor privilege level 2 */
+#define SEG_ATTR_DPL3 0x0060 /* Descriptor privilege level 3 */
+#define SEG_ATTR_CODE 0x0008 /* Type (0 = data, 1 = code) */
+#define SEG_ATTR_DATA 0x0000 /* Type (0 = data, 1 = code) */
+
+/* Code segments */
+#define SEG_ATTR_D 0x4000 /* Default operand size (0 = 16bit, 1 = 32bit) */
+#define SEG_ATTR_L 0x2000 /* Long segment? (1 = 64bit) */
+#define SEG_ATTR_C 0x0004 /* Conforming? (0 = non, 1 = conforming) */
+#define SEG_ATTR_R 0x0002 /* Readable? (0 = XO seg, 1 = RX seg) */
+
+/* Data segments */
+#define SEG_ATTR_B 0x4000 /* 'Big' flag.
+ * - For %ss, default operand size.
+ * - For expand-down segment, sets upper bound. */
+#define SEG_ATTR_E 0x0004 /* Expand-down? (0 = normal, 1 = expand-down) */
+#define SEG_ATTR_W 0x0002 /* Writable? (0 = RO seg, 1 = RW seg) */
+
+/*
+ * Initialise an LDT/GDT entry using a raw attribute number.
+ *
+ * @param base Segment base.
+ * @param limit Segment limit.
+ * @param attr Segment attributes.
+ */
+#define INIT_GDTE(base, limit, attr) { { { \
+ .lo = (((base) & 0xffff) << 16) | ((limit) & 0xffff), \
+ .hi = ((base) & 0xff000000) | ((limit) & 0xf0000) | \
+ (((attr) & 0xf0ff) << 8) | (((base) & 0xff0000) >> 16) \
+ } } }
+
+/*
+ * Tokenise and OR together.
+ *
+ * For each varadic parameter, tokenise with 't' and OR together.
+ *
+ * @param t Common stem partial token.
+ * @param ... Partial tokens.
+ *
+ * Example:
+ * <pre>
+ * TOK_OR(t, x, y) => (t ## x | t ## y)
+ * TOK_OR(t, x, y, z) => (t ## x | t ## y | t ## z)
+ * </pre>
+ */
+#define TOK_OR0(t) (0)
+#define TOK_OR1(t, x) (t ## x)
+#define TOK_OR2(t, x, ...) (t ## x | TOK_OR1(t, ##__VA_ARGS__))
+#define TOK_OR3(t, x, ...) (t ## x | TOK_OR2(t, ##__VA_ARGS__))
+#define TOK_OR4(t, x, ...) (t ## x | TOK_OR3(t, ##__VA_ARGS__))
+#define TOK_OR5(t, x, ...) (t ## x | TOK_OR4(t, ##__VA_ARGS__))
+#define TOK_OR6(t, x, ...) (t ## x | TOK_OR5(t, ##__VA_ARGS__))
+#define TOK_OR7(t, x, ...) (t ## x | TOK_OR6(t, ##__VA_ARGS__))
+#define TOK_OR8(t, x, ...) (t ## x | TOK_OR7(t, ##__VA_ARGS__))
+#define TOK_OR(t, ...) VAR_MACRO_C1(TOK_OR, t, ##__VA_ARGS__)
+
+/*
+ * Initialise an LDT/GDT entry using SEG_ATTR_ mnemonics.
+ *
+ * @param base Segment base.
+ * @param limit Segment limit.
+ * @param ... Partial SEG_ATTR_ tokens for attributes.
+ *
+ * Example usage:
+ * - INIT_GDTE_SYM(0, 0xfffff, P)
+ * - uses @ref SEG_ATTR_P
+ *
+ * - INIT_GDTE_SYM(0, 0xfffff, CODE, L)
+ * - uses @ref SEG_ATTR_CODE and @ref SEG_ATTR_L
+ */
+#define INIT_GDTE_SYM(base, limit, ...) \
+ INIT_GDTE(base, limit, TOK_OR(SEG_ATTR_, ##__VA_ARGS__))
+
+/* Long mode lgdt/lidt table pointer. */
+struct __packed desc_ptr64 {
+ uint16_t limit;
+ uint64_t base;
+};
+
+/* Protected mode lgdt/lidt table pointer. */
+struct __packed desc_ptr32 {
+ uint16_t limit;
+ uint32_t base;
+};
+
+struct __packed hw_tss32 {
+ uint16_t link; uint16_t _r0;
+
+ uint32_t esp0;
+ uint16_t ss0; uint16_t _r1;
+
+ uint32_t esp1;
+ uint16_t ss1; uint16_t _r2;
+
+ uint32_t esp2;
+ uint16_t ss2; uint16_t _r3;
+
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+
+ uint16_t es; uint16_t _r4;
+ uint16_t cs; uint16_t _r5;
+ uint16_t ss; uint16_t _r6;
+ uint16_t ds; uint16_t _r7;
+ uint16_t fs; uint16_t _r8;
+ uint16_t gs; uint16_t _r9;
+ uint16_t ldtr; uint16_t _r10;
+ uint16_t t; uint16_t iopb;
+};
+
+struct __packed hw_tss64 {
+ uint16_t link; uint16_t _r0;
+
+ uint64_t rsp0;
+ uint64_t rsp1;
+ uint64_t rsp2;
+
+ uint64_t _r1;
+
+ uint64_t ist[7]; /* 1-based structure */
+
+ uint64_t _r2;
+
+ uint16_t t;
+ uint16_t iopb;
+};
+
+#define X86_TSS_INVALID_IO_BITMAP 0x8000
+
+#if defined(__x86_64__)
+
+typedef struct desc_ptr64 desc_ptr;
+typedef struct seg_desc32 user_desc;
+typedef struct seg_gate64 gate_desc;
+typedef struct hw_tss64 hw_tss;
+
+#elif defined(__i386__)
+
+typedef struct desc_ptr32 desc_ptr;
+typedef struct seg_desc32 user_desc;
+typedef struct seg_gate32 gate_desc;
+typedef struct hw_tss32 hw_tss;
+
+#endif
+
+extern user_desc gdt[NR_GDT_ENTRIES];
+extern desc_ptr gdt_ptr;
+
+extern gate_desc idt[256];
+extern desc_ptr idt_ptr;
+
+extern hw_tss tss;
+
+#endif
+
+#endif /* _DESC_H_ */