2006-03-13 18:08:35

by Zachary Amsden

[permalink] [raw]
Subject: [RFC, PATCH 12/24] i386 Vmi processor header

Fairly straight code motion. Split non-virtualizable pieces of
processor.h into default and VMI subarches. CPUID is
non-virtualizable, since it doesn't trap, and very often the
hypervisor will want to hide specific feature bits from the
kernel. To provide a replacement for call sites that use
CPUID as a serializing instruction, the sync_core() macro is
still available.

Signed-off-by: Zachary Amsden <[email protected]>

Index: linux-2.6.16-rc5/include/asm-i386/processor.h
===================================================================
--- linux-2.6.16-rc5.orig/include/asm-i386/processor.h 2006-03-10 12:55:09.000000000 -0800
+++ linux-2.6.16-rc5/include/asm-i386/processor.h 2006-03-10 13:03:35.000000000 -0800
@@ -137,79 +137,6 @@ static inline void detect_ht(struct cpui
#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */

/*
- * Generic CPUID function
- * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
- * resulting in stale register contents being returned.
- */
-static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
-{
- __asm__("cpuid"
- : "=a" (*eax),
- "=b" (*ebx),
- "=c" (*ecx),
- "=d" (*edx)
- : "0" (op), "c"(0));
-}
-
-/* Some CPUID calls want 'count' to be placed in ecx */
-static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
- int *edx)
-{
- __asm__("cpuid"
- : "=a" (*eax),
- "=b" (*ebx),
- "=c" (*ecx),
- "=d" (*edx)
- : "0" (op), "c" (count));
-}
-
-/*
- * CPUID functions returning a single datum
- */
-static inline unsigned int cpuid_eax(unsigned int op)
-{
- unsigned int eax;
-
- __asm__("cpuid"
- : "=a" (eax)
- : "0" (op)
- : "bx", "cx", "dx");
- return eax;
-}
-static inline unsigned int cpuid_ebx(unsigned int op)
-{
- unsigned int eax, ebx;
-
- __asm__("cpuid"
- : "=a" (eax), "=b" (ebx)
- : "0" (op)
- : "cx", "dx" );
- return ebx;
-}
-static inline unsigned int cpuid_ecx(unsigned int op)
-{
- unsigned int eax, ecx;
-
- __asm__("cpuid"
- : "=a" (eax), "=c" (ecx)
- : "0" (op)
- : "bx", "dx" );
- return ecx;
-}
-static inline unsigned int cpuid_edx(unsigned int op)
-{
- unsigned int eax, edx;
-
- __asm__("cpuid"
- : "=a" (eax), "=d" (edx)
- : "0" (op)
- : "bx", "cx");
- return edx;
-}
-
-#define load_cr3(pgdir) write_cr3(__pa(pgdir))
-
-/*
* Intel CPU features in CR4
*/
#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
@@ -224,6 +151,8 @@ static inline unsigned int cpuid_edx(uns
#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */

+#include <mach_processor.h>
+
/*
* Save the cr4 feature set we're using (ie
* Pentium 4MB enable and PPro Global page
@@ -489,6 +418,7 @@ struct thread_struct {
static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
{
tss->esp0 = thread->esp0;
+ arch_update_kernel_stack(tss, thread->esp0);
/* This can only happen when SEP is enabled, no need to test "SEP"arately */
if (unlikely(tss->ss1 != thread->sysenter_cs)) {
tss->ss1 = thread->sysenter_cs;
@@ -507,33 +437,6 @@ static inline void load_esp0(struct tss_
regs->esp = new_esp; \
} while (0)

-/*
- * These special macros can be used to get or set a debugging register
- */
-#define get_debugreg(var, register) \
- __asm__("movl %%db" #register ", %0" \
- :"=r" (var))
-#define set_debugreg(value, register) \
- __asm__("movl %0,%%db" #register \
- : /* no output */ \
- :"r" (value))
-
-/*
- * Set IOPL bits in EFLAGS from given mask
- */
-static inline void set_iopl_mask(unsigned mask)
-{
- unsigned int reg;
- __asm__ __volatile__ ("pushfl;"
- "popl %0;"
- "andl %1, %0;"
- "orl %2, %0;"
- "pushl %0;"
- "popfl"
- : "=&r" (reg)
- : "i" (~X86_EFLAGS_IOPL), "r" (mask));
-}
-
/* Forward declaration, a strange C thing */
struct task_struct;
struct mm_struct;
@@ -740,4 +643,8 @@ extern void mcheck_init(struct cpuinfo_x
#define mcheck_init(c) do {} while(0)
#endif

+#include <mach_processor.h>
+
+#define stts() write_cr0(8 | read_cr0())
+
#endif /* __ASM_I386_PROCESSOR_H */
Index: linux-2.6.16-rc5/include/asm-i386/mach-vmi/mach_processor.h
===================================================================
--- linux-2.6.16-rc5.orig/include/asm-i386/mach-vmi/mach_processor.h 2006-03-10 13:03:35.000000000 -0800
+++ linux-2.6.16-rc5/include/asm-i386/mach-vmi/mach_processor.h 2006-03-10 13:03:35.000000000 -0800
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005, VMware, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to [email protected]
+ *
+ */
+
+
+#ifndef _MACH_PROCESSOR_H
+#define _MACH_PROCESSOR_H
+
+#include <vmi.h>
+
+static inline void vmi_cpuid(const int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ vmi_wrap_call(
+ CPUID, "cpuid",
+ XCONC("=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)),
+ 1, "a" (op),
+ VMI_CLOBBER(FOUR_RETURNS));
+}
+
+/*
+ * Generic CPUID function
+ */
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ vmi_cpuid(op, eax, ebx, ecx, edx);
+}
+
+
+/* Some CPUID calls want 'count' to be placed in ecx */
+static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+ int *edx)
+{
+ asm volatile(""::"c"(count));
+ vmi_cpuid(op, eax, ebx, ecx, edx);
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ vmi_cpuid(op, &eax, &ebx, &ecx, &edx);
+ return eax;
+}
+
+static inline unsigned int cpuid_ebx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ vmi_cpuid(op, &eax, &ebx, &ecx, &edx);
+ return ebx;
+}
+
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ vmi_cpuid(op, &eax, &ebx, &ecx, &edx);
+ return ecx;
+}
+
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ vmi_cpuid(op, &eax, &ebx, &ecx, &edx);
+ return edx;
+}
+
+#define flush_deferred_cpu_state() vmi_flush_deferred_calls(0)
+
+static inline void arch_update_kernel_stack(void *tss, u32 stack)
+{
+ vmi_wrap_call(
+ UpdateKernelStack, "",
+ VMI_NO_OUTPUT,
+ 2, XCONC(VMI_IREG1(tss), VMI_IREG2(stack)),
+ VMI_CLOBBER(ZERO_RETURNS));
+}
+
+static inline void set_debugreg(const u32 val, const int num)
+{
+ vmi_wrap_call(
+ SetDR, "movl %1, %%db%c2",
+ VMI_NO_OUTPUT,
+ 2, XCONC(VMI_IREG1(num), VMI_IREG2(val), VMI_IMM (num)),
+ VMI_CLOBBER(ZERO_RETURNS));
+}
+
+static inline u32 vmi_get_dr(const int num)
+{
+ VMI_UINT32 ret;
+ vmi_wrap_call(
+ GetDR, "movl %%db%c1, %%eax",
+ VMI_OREG1(ret),
+ 1, XCONC(VMI_IREG1(num), VMI_IMM (num)),
+ VMI_CLOBBER(ONE_RETURN));
+ return ret;
+}
+
+#define get_debugreg(var, register) do { var = vmi_get_dr(register); } while (0)
+
+static inline void set_iopl_mask(u32 mask)
+{
+ vmi_wrap_call(
+ SetIOPLMask, "pushfl;"
+ "andl $0xffffcfff, (%%esp);"
+ "orl %0, (%%esp);"
+ "popfl",
+ VMI_NO_OUTPUT,
+ 1, VMI_IREG1 (mask),
+ VMI_CLOBBER(ZERO_RETURNS));
+}
+
+#endif
Index: linux-2.6.16-rc5/include/asm-i386/mach-default/mach_processor.h
===================================================================
--- linux-2.6.16-rc5.orig/include/asm-i386/mach-default/mach_processor.h 2006-03-10 13:03:35.000000000 -0800
+++ linux-2.6.16-rc5/include/asm-i386/mach-default/mach_processor.h 2006-03-10 16:00:53.000000000 -0800
@@ -0,0 +1,108 @@
+#ifndef _MACH_PROCESSOR_H
+#define _MACH_PROCESSOR_H
+
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
+{
+ __asm__("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (op), "c"(0));
+}
+
+/* Some CPUID calls want 'count' to be placed in ecx */
+static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
+ int *edx)
+{
+ __asm__("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (op), "c" (count));
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax;
+
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (op)
+ : "bx", "cx", "dx");
+ return eax;
+}
+static inline unsigned int cpuid_ebx(unsigned int op)
+{
+ unsigned int eax, ebx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx)
+ : "0" (op)
+ : "cx", "dx" );
+ return ebx;
+}
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ecx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=c" (ecx)
+ : "0" (op)
+ : "bx", "dx" );
+ return ecx;
+}
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=d" (edx)
+ : "0" (op)
+ : "bx", "cx");
+ return edx;
+}
+
+#define load_cr3(pgdir) \
+ asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)))
+
+#define flush_deferred_cpu_state()
+#define arch_update_kernel_stack(t,s)
+
+/*
+ * These special macros can be used to get or set a debugging register
+ */
+#define get_debugreg(var, register) \
+ __asm__("movl %%db" #register ", %0" \
+ :"=r" (var))
+#define set_debugreg(value, register) \
+ __asm__("movl %0,%%db" #register \
+ : /* no output */ \
+ :"r" (value))
+
+/*
+ * Set IOPL bits in EFLAGS from given mask
+ */
+static inline void set_iopl_mask(unsigned mask)
+{
+ unsigned int reg;
+ __asm__ __volatile__ ("pushfl;"
+ "popl %0;"
+ "andl %1, %0;"
+ "orl %2, %0;"
+ "pushl %0;"
+ "popfl"
+ : "=&r" (reg)
+ : "i" (~X86_EFLAGS_IOPL), "r" (mask));
+}
+
+#endif


2006-03-16 16:33:53

by Chuck Ebbert

[permalink] [raw]
Subject: Re: [RFC, PATCH 12/24] i386 Vmi processor header

In-Reply-To: <[email protected]>

On Mon, 13 Mar 2006 10:08:20 -0800, Zachary Amsden wrote:

> Index: linux-2.6.16-rc5/include/asm-i386/mach-vmi/mach_processor.h
> ===================================================================
> --- linux-2.6.16-rc5.orig/include/asm-i386/mach-vmi/mach_processor.h 2006-03-10 13:03:35.000000000 -0800
> +++ linux-2.6.16-rc5/include/asm-i386/mach-vmi/mach_processor.h 2006-03-10 13:03:35.000000000 -0800
> @@ -0,0 +1,137 @@
> +/*
> + * Copyright (C) 2005, VMware, Inc.
> + *
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
> + * NON INFRINGEMENT. See the GNU General Public License for more
> + * details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * Send feedback to [email protected]
> + *
> + */
> +
> +
> +#ifndef _MACH_PROCESSOR_H
> +#define _MACH_PROCESSOR_H
> +
> +#include <vmi.h>
> +
> +static inline void vmi_cpuid(const int op, int *eax, int *ebx, int *ecx, int *edx)
> +{
> + vmi_wrap_call(
> + CPUID, "cpuid",
> + XCONC("=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)),
> + 1, "a" (op),
> + VMI_CLOBBER(FOUR_RETURNS));
> +}
> +
> +/*
> + * Generic CPUID function
> + */
> +static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
> +{
> + vmi_cpuid(op, eax, ebx, ecx, edx);
> +}
> +
> +
> +/* Some CPUID calls want 'count' to be placed in ecx */
> +static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
> + int *edx)
> +{
> + asm volatile(""::"c"(count));
> + vmi_cpuid(op, eax, ebx, ecx, edx);
> +}

You can't assume those last two statements will stay together.
>From the gcc 4.0.2 info file:

> <...> you can't expect a sequence of volatile `asm' instructions
> to remain perfectly consecutive. If you want consecutive output, use a
> single `asm'.

Maybe you could make vmi_cpuid always take a 'count' param, then just make cpuid
do:

vmi_cpuid(op, 0, eax, ebx, ecx, edx);

and cpuid_count do:

vmi_cpuid(op, count, eax, ebx, ecx, edx);


(And sorry about trimming the cc: but I'm reading from a digest and that list
is too long to enter manually.)

--
Chuck
"Penguins don't come from next door, they come from the Antarctic!"

2006-03-16 18:21:33

by Zachary Amsden

[permalink] [raw]
Subject: Re: [RFC, PATCH 12/24] i386 Vmi processor header

Chuck Ebbert wrote:
>
>> +/* Some CPUID calls want 'count' to be placed in ecx */
>> +static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx,
>> + int *edx)
>> +{
>> + asm volatile(""::"c"(count));
>> + vmi_cpuid(op, eax, ebx, ecx, edx);
>> +}
>>
>
> You can't assume those last two statements will stay together.
> >From the gcc 4.0.2 info file:
>

I know. I've abused this a bit. When we originally wrote the cpuid
call, there were no ecx dependencies on cpuid. Never got around to
fixing it properly.
>
>> <...> you can't expect a sequence of volatile `asm' instructions
>> to remain perfectly consecutive. If you want consecutive output, use a
>> single `asm'.
>>
>
> Maybe you could make vmi_cpuid always take a 'count' param, then just make cpuid
> do:
>
> vmi_cpuid(op, 0, eax, ebx, ecx, edx);
>
> and cpuid_count do:
>
> vmi_cpuid(op, count, eax, ebx, ecx, edx);
>

That is the proper fix. I'll put that in the next round.

>
> (And sorry about trimming the cc: but I'm reading from a digest and that list
> is too long to enter manually.)
>

N.P.

Thanks for looking at my code,
Zach