diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2006-09-26 04:52:35 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:35 -0400 |
commit | 522e93e3fcdbf00ba85c72fde6df28cfc0486a65 (patch) | |
tree | c6d1d0fd3109a667ca4ee0c0f8dc8a2fe4767240 | |
parent | 02ba1a32dbd3d406530a17a2643a8f0f8cbf3acc (diff) |
[PATCH] i386: Descriptor and trap table cleanups.
The implementation comes from Zach's [RFC, PATCH 10/24] i386 Vmi
descriptor changes:
Descriptor and trap table cleanups. Add cleanly written accessors for
IDT and GDT gates so the subarch may override them. Note that this
allows the hypervisor to transparently tweak the DPL of the descriptors
as well as the RPL of segments in those descriptors, with no unnecessary
kernel code modification. It also allows the hypervisor implementation
of the VMI to tweak the gates, allowing for custom exception frames or
extra layers of indirection above the guest fault / IRQ handlers.
Signed-off-by: Zachary Amsden <zach@vmware.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andi Kleen <ak@suse.de>
-rw-r--r-- | arch/i386/kernel/traps.c | 24 | ||||
-rw-r--r-- | include/asm-i386/desc.h | 121 |
2 files changed, 81 insertions, 64 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index bdf949c30c7c..00d643f3de41 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -1165,20 +1165,6 @@ void __init trap_init_f00f_bug(void) | |||
1165 | } | 1165 | } |
1166 | #endif | 1166 | #endif |
1167 | 1167 | ||
1168 | #define _set_gate(gate_addr,type,dpl,addr,seg) \ | ||
1169 | do { \ | ||
1170 | int __d0, __d1; \ | ||
1171 | __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ | ||
1172 | "movw %4,%%dx\n\t" \ | ||
1173 | "movl %%eax,%0\n\t" \ | ||
1174 | "movl %%edx,%1" \ | ||
1175 | :"=m" (*((long *) (gate_addr))), \ | ||
1176 | "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ | ||
1177 | :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ | ||
1178 | "3" ((char *) (addr)),"2" ((seg) << 16)); \ | ||
1179 | } while (0) | ||
1180 | |||
1181 | |||
1182 | /* | 1168 | /* |
1183 | * This needs to use 'idt_table' rather than 'idt', and | 1169 | * This needs to use 'idt_table' rather than 'idt', and |
1184 | * thus use the _nonmapped_ version of the IDT, as the | 1170 | * thus use the _nonmapped_ version of the IDT, as the |
@@ -1187,7 +1173,7 @@ do { \ | |||
1187 | */ | 1173 | */ |
1188 | void set_intr_gate(unsigned int n, void *addr) | 1174 | void set_intr_gate(unsigned int n, void *addr) |
1189 | { | 1175 | { |
1190 | _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); | 1176 | _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS); |
1191 | } | 1177 | } |
1192 | 1178 | ||
1193 | /* | 1179 | /* |
@@ -1195,22 +1181,22 @@ void set_intr_gate(unsigned int n, void *addr) | |||
1195 | */ | 1181 | */ |
1196 | static inline void set_system_intr_gate(unsigned int n, void *addr) | 1182 | static inline void set_system_intr_gate(unsigned int n, void *addr) |
1197 | { | 1183 | { |
1198 | _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS); | 1184 | _set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS); |
1199 | } | 1185 | } |
1200 | 1186 | ||
1201 | static void __init set_trap_gate(unsigned int n, void *addr) | 1187 | static void __init set_trap_gate(unsigned int n, void *addr) |
1202 | { | 1188 | { |
1203 | _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); | 1189 | _set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS); |
1204 | } | 1190 | } |
1205 | 1191 | ||
1206 | static void __init set_system_gate(unsigned int n, void *addr) | 1192 | static void __init set_system_gate(unsigned int n, void *addr) |
1207 | { | 1193 | { |
1208 | _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); | 1194 | _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS); |
1209 | } | 1195 | } |
1210 | 1196 | ||
1211 | static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) | 1197 | static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) |
1212 | { | 1198 | { |
1213 | _set_gate(idt_table+n,5,0,0,(gdt_entry<<3)); | 1199 | _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3)); |
1214 | } | 1200 | } |
1215 | 1201 | ||
1216 | 1202 | ||
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h index 89b8b82c82b3..5db9e96e8dc1 100644 --- a/include/asm-i386/desc.h +++ b/include/asm-i386/desc.h | |||
@@ -33,50 +33,99 @@ static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) | |||
33 | return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; | 33 | return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; |
34 | } | 34 | } |
35 | 35 | ||
36 | /* | ||
37 | * This is the ldt that every process will get unless we need | ||
38 | * something other than this. | ||
39 | */ | ||
40 | extern struct desc_struct default_ldt[]; | ||
41 | extern struct desc_struct idt_table[]; | ||
42 | extern void set_intr_gate(unsigned int irq, void * addr); | ||
43 | |||
44 | static inline void pack_descriptor(__u32 *a, __u32 *b, | ||
45 | unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) | ||
46 | { | ||
47 | *a = ((base & 0xffff) << 16) | (limit & 0xffff); | ||
48 | *b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | | ||
49 | ((type & 0xff) << 8) | ((flags & 0xf) << 12); | ||
50 | } | ||
51 | |||
52 | static inline void pack_gate(__u32 *a, __u32 *b, | ||
53 | unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) | ||
54 | { | ||
55 | *a = (seg << 16) | (base & 0xffff); | ||
56 | *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); | ||
57 | } | ||
58 | |||
59 | #define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ | ||
60 | #define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ | ||
61 | #define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ | ||
62 | #define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ | ||
63 | #define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ | ||
64 | #define DESCTYPE_DPL3 0x60 /* DPL-3 */ | ||
65 | #define DESCTYPE_S 0x10 /* !system */ | ||
66 | |||
36 | #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) | 67 | #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) |
37 | #define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)) | 68 | #define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)) |
38 | 69 | ||
39 | #define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) | 70 | #define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) |
40 | #define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) | 71 | #define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) |
41 | #define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr)) | 72 | #define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) |
42 | #define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt)) | 73 | #define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) |
43 | 74 | ||
44 | #define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) | 75 | #define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) |
45 | #define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) | 76 | #define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) |
46 | #define store_tr(tr) __asm__ ("str %0":"=mr" (tr)) | 77 | #define store_tr(tr) __asm__ ("str %0":"=m" (tr)) |
47 | #define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt)) | 78 | #define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) |
48 | 79 | ||
49 | /* | 80 | #if TLS_SIZE != 24 |
50 | * This is the ldt that every process will get unless we need | 81 | # error update this code. |
51 | * something other than this. | 82 | #endif |
52 | */ | ||
53 | extern struct desc_struct default_ldt[]; | ||
54 | extern void set_intr_gate(unsigned int irq, void * addr); | ||
55 | 83 | ||
56 | #define _set_tssldt_desc(n,addr,limit,type) \ | 84 | static inline void load_TLS(struct thread_struct *t, unsigned int cpu) |
57 | __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ | ||
58 | "movw %w1,2(%2)\n\t" \ | ||
59 | "rorl $16,%1\n\t" \ | ||
60 | "movb %b1,4(%2)\n\t" \ | ||
61 | "movb %4,5(%2)\n\t" \ | ||
62 | "movb $0,6(%2)\n\t" \ | ||
63 | "movb %h1,7(%2)\n\t" \ | ||
64 | "rorl $16,%1" \ | ||
65 | : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type)) | ||
66 | |||
67 | static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr) | ||
68 | { | 85 | { |
69 | _set_tssldt_desc(&get_cpu_gdt_table(cpu)[entry], (int)addr, | 86 | #define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] |
70 | offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89); | 87 | C(0); C(1); C(2); |
88 | #undef C | ||
71 | } | 89 | } |
72 | 90 | ||
73 | #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) | 91 | static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b) |
92 | { | ||
93 | __u32 *lp = (__u32 *)((char *)dt + entry*8); | ||
94 | *lp = entry_a; | ||
95 | *(lp+1) = entry_b; | ||
96 | } | ||
97 | |||
98 | #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) | ||
99 | #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) | ||
100 | #define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) | ||
101 | |||
102 | static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) | ||
103 | { | ||
104 | __u32 a, b; | ||
105 | pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); | ||
106 | write_idt_entry(idt_table, gate, a, b); | ||
107 | } | ||
74 | 108 | ||
75 | static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size) | 109 | static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) |
76 | { | 110 | { |
77 | _set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82); | 111 | __u32 a, b; |
112 | pack_descriptor(&a, &b, (unsigned long)addr, | ||
113 | offsetof(struct tss_struct, __cacheline_filler) - 1, | ||
114 | DESCTYPE_TSS, 0); | ||
115 | write_gdt_entry(get_cpu_gdt_table(cpu), entry, a, b); | ||
78 | } | 116 | } |
79 | 117 | ||
118 | static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int entries) | ||
119 | { | ||
120 | __u32 a, b; | ||
121 | pack_descriptor(&a, &b, (unsigned long)addr, | ||
122 | entries * sizeof(struct desc_struct) - 1, | ||
123 | DESCTYPE_LDT, 0); | ||
124 | write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, a, b); | ||
125 | } | ||
126 | |||
127 | #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) | ||
128 | |||
80 | #define LDT_entry_a(info) \ | 129 | #define LDT_entry_a(info) \ |
81 | ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) | 130 | ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) |
82 | 131 | ||
@@ -102,24 +151,6 @@ static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size) | |||
102 | (info)->seg_not_present == 1 && \ | 151 | (info)->seg_not_present == 1 && \ |
103 | (info)->useable == 0 ) | 152 | (info)->useable == 0 ) |
104 | 153 | ||
105 | static inline void write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b) | ||
106 | { | ||
107 | __u32 *lp = (__u32 *)((char *)ldt + entry*8); | ||
108 | *lp = entry_a; | ||
109 | *(lp+1) = entry_b; | ||
110 | } | ||
111 | |||
112 | #if TLS_SIZE != 24 | ||
113 | # error update this code. | ||
114 | #endif | ||
115 | |||
116 | static inline void load_TLS(struct thread_struct *t, unsigned int cpu) | ||
117 | { | ||
118 | #define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] | ||
119 | C(0); C(1); C(2); | ||
120 | #undef C | ||
121 | } | ||
122 | |||
123 | static inline void clear_LDT(void) | 154 | static inline void clear_LDT(void) |
124 | { | 155 | { |
125 | int cpu = get_cpu(); | 156 | int cpu = get_cpu(); |