From: Zachary Amsden 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 Signed-off-by: Andrew Morton --- arch/i386/kernel/cpu/common.c | 4 ++-- arch/i386/kernel/doublefault.c | 2 +- arch/i386/kernel/efi.c | 5 ++--- arch/i386/kernel/reboot.c | 9 +++++---- arch/i386/kernel/signal.c | 4 ++-- arch/i386/kernel/traps.c | 2 +- arch/i386/kernel/vm86.c | 4 ++-- arch/i386/math-emu/get_address.c | 13 +++---------- arch/i386/power/cpu.c | 26 +++++++++++++------------- include/asm-i386/desc.h | 10 ++++++++++ include/asm-i386/system.h | 4 ++-- 11 files changed, 43 insertions(+), 40 deletions(-) diff -puN arch/i386/kernel/cpu/common.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/cpu/common.c --- devel/arch/i386/kernel/cpu/common.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/cpu/common.c 2005-07-30 15:28:32.000000000 -0700 @@ -613,8 +613,8 @@ void __devinit cpu_init(void) memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), GDT_ENTRY_TLS_ENTRIES * 8); - __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu])); - __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); + load_gdt(&cpu_gdt_descr[cpu]); + load_idt(&idt_descr); /* * Delete NT diff -puN arch/i386/kernel/doublefault.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/doublefault.c --- devel/arch/i386/kernel/doublefault.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/doublefault.c 2005-07-30 15:28:32.000000000 -0700 @@ -20,7 +20,7 @@ static void doublefault_fn(void) struct Xgt_desc_struct gdt_desc = {0, 0}; unsigned long gdt, tss; - __asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory"); + store_gdt(&gdt_desc); gdt = gdt_desc.address; printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); diff -puN arch/i386/kernel/efi.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/efi.c --- devel/arch/i386/kernel/efi.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/efi.c 2005-07-30 15:31:26.000000000 -0700 @@ -104,8 +104,7 @@ static void efi_call_phys_prelog(void) local_flush_tlb(); cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address); - __asm__ __volatile__("lgdt %0":"=m" - (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0]))); + load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])); } static void efi_call_phys_epilog(void) @@ -114,7 +113,7 @@ static void efi_call_phys_epilog(void) cpu_gdt_descr[0].address = (unsigned long) __va(cpu_gdt_descr[0].address); - __asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr)); + load_gdt(&cpu_gdt_descr); cr4 = read_cr4(); if (cr4 & X86_CR4_PSE) { diff -puN arch/i386/kernel/reboot.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/reboot.c --- devel/arch/i386/kernel/reboot.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/reboot.c 2005-07-30 15:28:32.000000000 -0700 @@ -13,6 +13,7 @@ #include #include #include +#include #include "mach_reboot.h" #include @@ -242,13 +243,13 @@ void machine_real_restart(unsigned char /* Set up the IDT for real mode. */ - __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + load_idt(&real_mode_idt); /* Set up a GDT from which we can load segment descriptors for real mode. The GDT is not used in real mode; it is just needed here to prepare the descriptors. */ - __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + load_gdt(&real_mode_gdt); /* Load the data segment registers, and thus the descriptors ready for real mode. The base address of each segment is 0x100, 16 times the @@ -316,7 +317,7 @@ void machine_emergency_restart(void) if (!reboot_thru_bios) { if (efi_enabled) { efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); - __asm__ __volatile__("lidt %0": :"m" (no_idt)); + load_idt(&no_idt); __asm__ __volatile__("int3"); } /* rebooting needs to touch the page at absolute addr 0 */ @@ -325,7 +326,7 @@ void machine_emergency_restart(void) mach_reboot_fixups(); /* for board specific fixups */ mach_reboot(); /* That didn't work - force a triple fault.. */ - __asm__ __volatile__("lidt %0": :"m" (no_idt)); + load_idt(&no_idt); __asm__ __volatile__("int3"); } } diff -puN arch/i386/kernel/signal.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/signal.c --- devel/arch/i386/kernel/signal.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/signal.c 2005-07-30 15:28:32.000000000 -0700 @@ -278,9 +278,9 @@ setup_sigcontext(struct sigcontext __use int tmp, err = 0; tmp = 0; - __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); + savesegment(gs, tmp); err |= __put_user(tmp, (unsigned int __user *)&sc->gs); - __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); + savesegment(fs, tmp); err |= __put_user(tmp, (unsigned int __user *)&sc->fs); err |= __put_user(regs->xes, (unsigned int __user *)&sc->es); diff -puN arch/i386/kernel/traps.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/traps.c --- devel/arch/i386/kernel/traps.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/traps.c 2005-07-30 15:28:32.000000000 -0700 @@ -1006,7 +1006,7 @@ void __init trap_init_f00f_bug(void) * it uses the read-only mapped virtual address. */ idt_descr.address = fix_to_virt(FIX_F00F_IDT); - __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); + load_idt(&idt_descr); } #endif diff -puN arch/i386/kernel/vm86.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/kernel/vm86.c --- devel/arch/i386/kernel/vm86.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/kernel/vm86.c 2005-07-30 15:28:32.000000000 -0700 @@ -294,8 +294,8 @@ static void do_sys_vm86(struct kernel_vm */ info->regs32->eax = 0; tsk->thread.saved_esp0 = tsk->thread.esp0; - asm volatile("mov %%fs,%0":"=m" (tsk->thread.saved_fs)); - asm volatile("mov %%gs,%0":"=m" (tsk->thread.saved_gs)); + savesegment(fs, tsk->thread.saved_fs); + savesegment(gs, tsk->thread.saved_gs); tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; diff -puN arch/i386/math-emu/get_address.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/math-emu/get_address.c --- devel/arch/i386/math-emu/get_address.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/math-emu/get_address.c 2005-07-30 15:28:32.000000000 -0700 @@ -155,7 +155,6 @@ static long pm_address(u_char FPU_modrm, { struct desc_struct descriptor; unsigned long base_address, limit, address, seg_top; - unsigned short selector; segment--; @@ -173,17 +172,11 @@ static long pm_address(u_char FPU_modrm, /* fs and gs aren't used by the kernel, so they still have their user-space values. */ case PREFIX_FS_-1: - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register - in the assembler statement. */ - - __asm__("mov %%fs,%0":"=r" (selector)); - addr->selector = selector; + /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */ + savesegment(fs, addr->selector); break; case PREFIX_GS_-1: - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register - in the assembler statement. */ - __asm__("mov %%gs,%0":"=r" (selector)); - addr->selector = selector; + savesegment(gs, addr->selector); break; default: addr->selector = PM_REG_(segment); diff -puN arch/i386/power/cpu.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management arch/i386/power/cpu.c --- devel/arch/i386/power/cpu.c~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/arch/i386/power/cpu.c 2005-07-30 15:28:32.000000000 -0700 @@ -42,17 +42,17 @@ void __save_processor_state(struct saved /* * descriptor tables */ - asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit)); - asm volatile ("sidt %0" : "=m" (ctxt->idt_limit)); - asm volatile ("str %0" : "=m" (ctxt->tr)); + store_gdt(&ctxt->gdt_limit); + store_idt(&ctxt->idt_limit); + store_tr(ctxt->tr); /* * segment registers */ - asm volatile ("movw %%es, %0" : "=m" (ctxt->es)); - asm volatile ("movw %%fs, %0" : "=m" (ctxt->fs)); - asm volatile ("movw %%gs, %0" : "=m" (ctxt->gs)); - asm volatile ("movw %%ss, %0" : "=m" (ctxt->ss)); + savesegment(es, ctxt->es); + savesegment(fs, ctxt->fs); + savesegment(gs, ctxt->gs); + savesegment(ss, ctxt->ss); /* * control registers @@ -118,16 +118,16 @@ void __restore_processor_state(struct sa * now restore the descriptor tables to their proper values * ltr is done i fix_processor_context(). */ - asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit)); - asm volatile ("lidt %0" :: "m" (ctxt->idt_limit)); + load_gdt(&ctxt->gdt_limit); + load_idt(&ctxt->idt_limit); /* * segment registers */ - asm volatile ("movw %0, %%es" :: "r" (ctxt->es)); - asm volatile ("movw %0, %%fs" :: "r" (ctxt->fs)); - asm volatile ("movw %0, %%gs" :: "r" (ctxt->gs)); - asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss)); + loadsegment(es, ctxt->es); + loadsegment(fs, ctxt->fs); + loadsegment(gs, ctxt->gs); + loadsegment(ss, ctxt->ss); /* * sysenter MSRs diff -puN include/asm-i386/desc.h~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management include/asm-i386/desc.h --- devel/include/asm-i386/desc.h~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/include/asm-i386/desc.h 2005-07-30 15:32:57.000000000 -0700 @@ -30,6 +30,16 @@ extern struct Xgt_desc_struct idt_descr, #define load_TR_desc() __asm__ __volatile__("ltr %%ax"::"a" (GDT_ENTRY_TSS*8)) #define load_LDT_desc() __asm__ __volatile__("lldt %%ax"::"a" (GDT_ENTRY_LDT*8)) +#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) +#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt)) + +#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) +#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) +#define store_tr(tr) __asm__ ("str %0":"=mr" (tr)) +#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt)) + /* * This is the ldt that every process will get unless we need * something other than this. diff -puN include/asm-i386/system.h~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management include/asm-i386/system.h --- devel/include/asm-i386/system.h~i386-inline-assembler-cleanup-encapsulate-descriptor-and-task-register-management 2005-07-30 15:28:32.000000000 -0700 +++ devel-akpm/include/asm-i386/system.h 2005-07-30 15:28:32.000000000 -0700 @@ -93,13 +93,13 @@ static inline unsigned long _get_base(ch ".align 4\n\t" \ ".long 1b,3b\n" \ ".previous" \ - : :"m" (value)) + : :"rm" (value)) /* * Save a segment register away */ #define savesegment(seg, value) \ - asm volatile("mov %%" #seg ",%0":"=m" (value)) + asm volatile("mov %%" #seg ",%0":"=rm" (value)) /* * Clear and set 'TS' bit respectively _