Commit 4d37e7e3fd851428dede4d05d3e69d03795a744a

Authored by Zachary Amsden
Committed by Linus Torvalds
1 parent 245067d167

[PATCH] i386: inline assembler: cleanup and encapsulate descriptor and task register management

i386 inline assembler cleanup.

This change encapsulates descriptor and task register management.  Also,
it is possible to improve assembler generation in two cases; savesegment
may store the value in a register instead of a memory location, which
allows GCC to optimize stack variables into registers, and MOV MEM, SEG
is always a 16-bit write to memory, making the casting in math-emu
unnecessary.

Signed-off-by: Zachary Amsden <zach@vmware.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 11 changed files with 43 additions and 40 deletions Side-by-side Diff

arch/i386/kernel/cpu/common.c
... ... @@ -613,8 +613,8 @@
613 613 memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu),
614 614 GDT_ENTRY_TLS_ENTRIES * 8);
615 615  
616   - __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu]));
617   - __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
  616 + load_gdt(&cpu_gdt_descr[cpu]);
  617 + load_idt(&idt_descr);
618 618  
619 619 /*
620 620 * Delete NT
arch/i386/kernel/doublefault.c
... ... @@ -20,7 +20,7 @@
20 20 struct Xgt_desc_struct gdt_desc = {0, 0};
21 21 unsigned long gdt, tss;
22 22  
23   - __asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
  23 + store_gdt(&gdt_desc);
24 24 gdt = gdt_desc.address;
25 25  
26 26 printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
arch/i386/kernel/efi.c
... ... @@ -104,8 +104,7 @@
104 104 local_flush_tlb();
105 105  
106 106 cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
107   - __asm__ __volatile__("lgdt %0":"=m"
108   - (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])));
  107 + load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]));
109 108 }
110 109  
111 110 static void efi_call_phys_epilog(void)
... ... @@ -114,7 +113,7 @@
114 113  
115 114 cpu_gdt_descr[0].address =
116 115 (unsigned long) __va(cpu_gdt_descr[0].address);
117   - __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr));
  116 + load_gdt(&cpu_gdt_descr[0]);
118 117 cr4 = read_cr4();
119 118  
120 119 if (cr4 & X86_CR4_PSE) {
arch/i386/kernel/reboot.c
... ... @@ -13,6 +13,7 @@
13 13 #include <linux/dmi.h>
14 14 #include <asm/uaccess.h>
15 15 #include <asm/apic.h>
  16 +#include <asm/desc.h>
16 17 #include "mach_reboot.h"
17 18 #include <linux/reboot_fixups.h>
18 19  
19 20  
... ... @@ -242,13 +243,13 @@
242 243  
243 244 /* Set up the IDT for real mode. */
244 245  
245   - __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
  246 + load_idt(&real_mode_idt);
246 247  
247 248 /* Set up a GDT from which we can load segment descriptors for real
248 249 mode. The GDT is not used in real mode; it is just needed here to
249 250 prepare the descriptors. */
250 251  
251   - __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
  252 + load_gdt(&real_mode_gdt);
252 253  
253 254 /* Load the data segment registers, and thus the descriptors ready for
254 255 real mode. The base address of each segment is 0x100, 16 times the
... ... @@ -316,7 +317,7 @@
316 317 if (!reboot_thru_bios) {
317 318 if (efi_enabled) {
318 319 efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
319   - __asm__ __volatile__("lidt %0": :"m" (no_idt));
  320 + load_idt(&no_idt);
320 321 __asm__ __volatile__("int3");
321 322 }
322 323 /* rebooting needs to touch the page at absolute addr 0 */
... ... @@ -325,7 +326,7 @@
325 326 mach_reboot_fixups(); /* for board specific fixups */
326 327 mach_reboot();
327 328 /* That didn't work - force a triple fault.. */
328   - __asm__ __volatile__("lidt %0": :"m" (no_idt));
  329 + load_idt(&no_idt);
329 330 __asm__ __volatile__("int3");
330 331 }
331 332 }
arch/i386/kernel/signal.c
... ... @@ -278,9 +278,9 @@
278 278 int tmp, err = 0;
279 279  
280 280 tmp = 0;
281   - __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
  281 + savesegment(gs, tmp);
282 282 err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
283   - __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
  283 + savesegment(fs, tmp);
284 284 err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
285 285  
286 286 err |= __put_user(regs->xes, (unsigned int __user *)&sc->es);
arch/i386/kernel/traps.c
... ... @@ -1008,7 +1008,7 @@
1008 1008 * it uses the read-only mapped virtual address.
1009 1009 */
1010 1010 idt_descr.address = fix_to_virt(FIX_F00F_IDT);
1011   - __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
  1011 + load_idt(&idt_descr);
1012 1012 }
1013 1013 #endif
1014 1014  
arch/i386/kernel/vm86.c
... ... @@ -294,8 +294,8 @@
294 294 */
295 295 info->regs32->eax = 0;
296 296 tsk->thread.saved_esp0 = tsk->thread.esp0;
297   - asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs));
298   - asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs));
  297 + savesegment(fs, tsk->thread.saved_fs);
  298 + savesegment(gs, tsk->thread.saved_gs);
299 299  
300 300 tss = &per_cpu(init_tss, get_cpu());
301 301 tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
arch/i386/math-emu/get_address.c
... ... @@ -155,7 +155,6 @@
155 155 {
156 156 struct desc_struct descriptor;
157 157 unsigned long base_address, limit, address, seg_top;
158   - unsigned short selector;
159 158  
160 159 segment--;
161 160  
162 161  
... ... @@ -173,17 +172,11 @@
173 172 /* fs and gs aren't used by the kernel, so they still have their
174 173 user-space values. */
175 174 case PREFIX_FS_-1:
176   - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
177   - in the assembler statement. */
178   -
179   - __asm__("mov %%fs,%0":"=r" (selector));
180   - addr->selector = selector;
  175 + /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
  176 + savesegment(fs, addr->selector);
181 177 break;
182 178 case PREFIX_GS_-1:
183   - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
184   - in the assembler statement. */
185   - __asm__("mov %%gs,%0":"=r" (selector));
186   - addr->selector = selector;
  179 + savesegment(gs, addr->selector);
187 180 break;
188 181 default:
189 182 addr->selector = PM_REG_(segment);
arch/i386/power/cpu.c
... ... @@ -42,17 +42,17 @@
42 42 /*
43 43 * descriptor tables
44 44 */
45   - asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
46   - asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
47   - asm volatile ("str %0" : "=m" (ctxt->tr));
  45 + store_gdt(&ctxt->gdt_limit);
  46 + store_idt(&ctxt->idt_limit);
  47 + store_tr(ctxt->tr);
48 48  
49 49 /*
50 50 * segment registers
51 51 */
52   - asm volatile ("movw %%es, %0" : "=m" (ctxt->es));
53   - asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs));
54   - asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs));
55   - asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss));
  52 + savesegment(es, ctxt->es);
  53 + savesegment(fs, ctxt->fs);
  54 + savesegment(gs, ctxt->gs);
  55 + savesegment(ss, ctxt->ss);
56 56  
57 57 /*
58 58 * control registers
59 59  
... ... @@ -118,16 +118,16 @@
118 118 * now restore the descriptor tables to their proper values
119 119 * ltr is done i fix_processor_context().
120 120 */
121   - asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
122   - asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
  121 + load_gdt(&ctxt->gdt_limit);
  122 + load_idt(&ctxt->idt_limit);
123 123  
124 124 /*
125 125 * segment registers
126 126 */
127   - asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
128   - asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs));
129   - asm volatile ("movw %0, %%gs" :: "r" (ctxt->gs));
130   - asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
  127 + loadsegment(es, ctxt->es);
  128 + loadsegment(fs, ctxt->fs);
  129 + loadsegment(gs, ctxt->gs);
  130 + loadsegment(ss, ctxt->ss);
131 131  
132 132 /*
133 133 * sysenter MSRs
include/asm-i386/desc.h
... ... @@ -30,6 +30,16 @@
30 30 #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8))
31 31 #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8))
32 32  
  33 +#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
  34 +#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
  35 +#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr))
  36 +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt))
  37 +
  38 +#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
  39 +#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
  40 +#define store_tr(tr) __asm__ ("str %0":"=mr" (tr))
  41 +#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt))
  42 +
33 43 /*
34 44 * This is the ldt that every process will get unless we need
35 45 * something other than this.
include/asm-i386/system.h
... ... @@ -93,13 +93,13 @@
93 93 ".align 4\n\t" \
94 94 ".long 1b,3b\n" \
95 95 ".previous" \
96   - : :"m" (value))
  96 + : :"rm" (value))
97 97  
98 98 /*
99 99 * Save a segment register away
100 100 */
101 101 #define savesegment(seg, value) \
102   - asm volatile("mov %%" #seg ",%0":"=m" (value))
  102 + asm volatile("mov %%" #seg ",%0":"=rm" (value))
103 103  
104 104 /*
105 105 * Clear and set 'TS' bit respectively