desc_64.h 5.2 KB
Newer Older
1
/* Written 2000 by Andi Kleen */
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9 10
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H

#include <linux/threads.h>
#include <asm/ldt.h>

#ifndef __ASSEMBLY__

#include <linux/string.h>
11
#include <linux/smp.h>
12
#include <asm/desc_defs.h>
13

L
Linus Torvalds 已提交
14 15 16
#include <asm/segment.h>
#include <asm/mmu.h>

17
extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
L
Linus Torvalds 已提交
18 19 20 21 22

#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
#define clear_LDT()  asm volatile("lldt %w0"::"r" (0))

23 24 25 26 27 28 29 30 31 32
static inline unsigned long __store_tr(void)
{
       unsigned long tr;

       asm volatile ("str %w0":"=r" (tr));
       return tr;
}

#define store_tr(tr) (tr) = __store_tr()

L
Linus Torvalds 已提交
33 34 35 36 37
/*
 * This is the ldt that every process will get unless we need
 * something other than this.
 */
extern struct desc_struct default_ldt[];
38
extern struct gate_struct idt_table[];
39
extern struct desc_ptr cpu_gdt_descr[];
L
Linus Torvalds 已提交
40

41 42 43 44 45 46 47 48 49
static inline void write_ldt_entry(struct desc_struct *ldt,
				   int entry, u32 entry_low, u32 entry_high)
{
	__u32 *lp = (__u32 *)((entry << 3) + (char *)ldt);

	lp[0] = entry_low;
	lp[1] = entry_high;
}

50 51 52
/* the cpu gdt accessor */
#define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address)

53 54 55 56 57 58 59 60 61 62
static inline void load_gdt(const struct desc_ptr *ptr)
{
	asm volatile("lgdt %w0"::"m" (*ptr));
}

static inline void store_gdt(struct desc_ptr *ptr)
{
       asm("sgdt %w0":"=m" (*ptr));
}

63 64
static inline void _set_gate(void *adr, unsigned type, unsigned long func,
			     unsigned dpl, unsigned ist)
L
Linus Torvalds 已提交
65
{
66 67 68
	struct gate_struct s;

	s.offset_low = PTR_LOW(func);
L
Linus Torvalds 已提交
69
	s.segment = __KERNEL_CS;
70
	s.ist = ist;
L
Linus Torvalds 已提交
71
	s.p = 1;
72
	s.dpl = dpl;
L
Linus Torvalds 已提交
73
	s.zero0 = 0;
74 75 76 77 78 79 80 81 82 83 84 85 86
	s.zero1 = 0;
	s.type = type;
	s.offset_middle = PTR_MIDDLE(func);
	s.offset_high = PTR_HIGH(func);
	/*
	 * does not need to be atomic because it is only done once at
	 * setup time
	 */
	memcpy(adr, &s, 16);
}

static inline void set_intr_gate(int nr, void *func)
{
87
	BUG_ON((unsigned)nr > 0xFF);
88 89
	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0);
}
L
Linus Torvalds 已提交
90

91 92
static inline void set_intr_gate_ist(int nr, void *func, unsigned ist)
{
93
	BUG_ON((unsigned)nr > 0xFF);
94 95
	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist);
}
L
Linus Torvalds 已提交
96

97 98
static inline void set_system_gate(int nr, void *func)
{
99
	BUG_ON((unsigned)nr > 0xFF);
100 101
	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0);
}
L
Linus Torvalds 已提交
102

103 104 105 106 107
static inline void set_system_gate_ist(int nr, void *func, unsigned ist)
{
	_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist);
}

108 109 110 111 112 113 114 115 116 117
static inline void load_idt(const struct desc_ptr *ptr)
{
	asm volatile("lidt %w0"::"m" (*ptr));
}

static inline void store_idt(struct desc_ptr *dtr)
{
       asm("sidt %w0":"=m" (*dtr));
}

118 119 120
static inline void set_tssldt_descriptor(void *ptr, unsigned long tss,
					 unsigned type, unsigned size)
{
L
Linus Torvalds 已提交
121
	struct ldttss_desc d;
122 123

	memset(&d, 0, sizeof(d));
L
Linus Torvalds 已提交
124
	d.limit0 = size & 0xFFFF;
125 126
	d.base0 = PTR_LOW(tss);
	d.base1 = PTR_MIDDLE(tss) & 0xFF;
L
Linus Torvalds 已提交
127
	d.type = type;
128
	d.p = 1;
L
Linus Torvalds 已提交
129
	d.limit1 = (size >> 16) & 0xF;
130 131 132
	d.base2 = (PTR_MIDDLE(tss) >> 8) & 0xFF;
	d.base3 = PTR_HIGH(tss);
	memcpy(ptr, &d, 16);
L
Linus Torvalds 已提交
133 134 135
}

static inline void set_tss_desc(unsigned cpu, void *addr)
136
{
S
Siddha, Suresh B 已提交
137 138 139 140 141 142 143
	/*
	 * sizeof(unsigned long) coming from an extra "long" at the end
	 * of the iobitmap. See tss_struct definition in processor.h
	 *
	 * -1? seg base+limit should be pointing to the address of the
	 * last valid byte
	 */
144
	set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_TSS],
S
Siddha, Suresh B 已提交
145 146
		(unsigned long)addr, DESC_TSS,
		IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
147
}
L
Linus Torvalds 已提交
148 149

static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
150
{
151
	set_tssldt_descriptor(&cpu_gdt(cpu)[GDT_ENTRY_LDT], (unsigned long)addr,
L
Linus Torvalds 已提交
152 153 154 155 156
			      DESC_LDT, size * 8 - 1);
}

#define LDT_entry_a(info) \
	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
157 158
/* Don't allow setting of the lm bit. It is useless anyways because
   64bit system calls require __USER_CS. */
L
Linus Torvalds 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
#define LDT_entry_b(info) \
	(((info)->base_addr & 0xff000000) | \
	(((info)->base_addr & 0x00ff0000) >> 16) | \
	((info)->limit & 0xf0000) | \
	(((info)->read_exec_only ^ 1) << 9) | \
	((info)->contents << 10) | \
	(((info)->seg_not_present ^ 1) << 15) | \
	((info)->seg_32bit << 22) | \
	((info)->limit_in_pages << 23) | \
	((info)->useable << 20) | \
	/* ((info)->lm << 21) | */ \
	0x7000)

#define LDT_empty(info) (\
	(info)->base_addr	== 0	&& \
	(info)->limit		== 0	&& \
	(info)->contents	== 0	&& \
	(info)->read_exec_only	== 1	&& \
	(info)->seg_32bit	== 0	&& \
	(info)->limit_in_pages	== 0	&& \
	(info)->seg_not_present	== 1	&& \
	(info)->useable		== 0	&& \
	(info)->lm		== 0)

static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
185
	unsigned int i;
186
	u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
187 188 189

	for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
		gdt[i] = t->tls_array[i];
190
}
L
Linus Torvalds 已提交
191 192 193 194

/*
 * load one particular LDT into the current CPU
 */
195
static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
L
Linus Torvalds 已提交
196 197 198 199 200 201 202
{
	int count = pc->size;

	if (likely(!count)) {
		clear_LDT();
		return;
	}
203

L
Linus Torvalds 已提交
204 205 206 207 208 209 210
	set_ldt_desc(cpu, pc->ldt, count);
	load_LDT_desc();
}

static inline void load_LDT(mm_context_t *pc)
{
	int cpu = get_cpu();
211

L
Linus Torvalds 已提交
212 213 214 215 216 217 218 219 220
	load_LDT_nolock(pc, cpu);
	put_cpu();
}

extern struct desc_ptr idt_descr;

#endif /* !__ASSEMBLY__ */

#endif