Commit 4d37e7e3fd851428dede4d05d3e69d03795a744a
Committed by
Linus Torvalds
1 parent
245067d167
Exists in
master
and in
4 other branches
[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
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 |