Discussion:
[Xen-changelog] [xen master] x86: make traps.c build with !CONFIG_PV
p***@xen.org
2018-11-19 11:45:15 UTC
Permalink
commit aa0816b74f1dffe2d9f3e159915f9a399379278a
Author: Wei Liu <***@citrix.com>
AuthorDate: Fri Nov 2 15:55:39 2018 +0000
Commit: Wei Liu <***@citrix.com>
CommitDate: Mon Nov 5 16:08:03 2018 +0000

x86: make traps.c build with !CONFIG_PV

Provide a stub for pv_inject_event. Put code that accesses PV fields
and GDT / LDT fault handling code under CONFIG_PV. Move set_debugreg
to pv/misc-hypercalls.c.

Signed-off-by: Wei Liu <***@citrix.com>
Reviewed-by: Andrew Cooper <***@citrix.com>
---
xen/arch/x86/pv/misc-hypercalls.c | 116 ++++++++++++++++++++++++++++++++++
xen/arch/x86/traps.c | 130 ++++----------------------------------
xen/include/asm-x86/domain.h | 7 ++
3 files changed, 137 insertions(+), 116 deletions(-)

diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c
index 9f61f3db3c..136fa10c96 100644
--- a/xen/arch/x86/pv/misc-hypercalls.c
+++ b/xen/arch/x86/pv/misc-hypercalls.c
@@ -56,6 +56,122 @@ long do_fpu_taskswitch(int set)
}

/*
+ * Used by hypercalls and the emulator.
+ * -ENODEV => #UD
+ * -EINVAL => #GP Invalid bit
+ * -EPERM => #GP Valid bit, but not permitted to use
+ */
+long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
+{
+ struct vcpu *curr = current;
+
+ switch ( reg )
+ {
+ case 0 ... 3:
+ if ( !access_ok(value, sizeof(long)) )
+ return -EPERM;
+
+ v->arch.dr[reg] = value;
+ if ( v == curr )
+ {
+ switch ( reg )
+ {
+ case 0: write_debugreg(0, value); break;
+ case 1: write_debugreg(1, value); break;
+ case 2: write_debugreg(2, value); break;
+ case 3: write_debugreg(3, value); break;
+ }
+ }
+ break;
+
+ case 4:
+ if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
+ return -ENODEV;
+
+ /* Fallthrough */
+ case 6:
+ /* The upper 32 bits are strictly reserved. */
+ if ( value != (uint32_t)value )
+ return -EINVAL;
+
+ /*
+ * DR6: Bits 4-11,16-31 reserved (set to 1).
+ * Bit 12 reserved (set to 0).
+ */
+ value &= ~DR_STATUS_RESERVED_ZERO; /* reserved bits => 0 */
+ value |= DR_STATUS_RESERVED_ONE; /* reserved bits => 1 */
+
+ v->arch.dr6 = value;
+ if ( v == curr )
+ write_debugreg(6, value);
+ break;
+
+ case 5:
+ if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
+ return -ENODEV;
+
+ /* Fallthrough */
+ case 7:
+ /* The upper 32 bits are strictly reserved. */
+ if ( value != (uint32_t)value )
+ return -EINVAL;
+
+ /*
+ * DR7: Bit 10 reserved (set to 1).
+ * Bits 11-12,14-15 reserved (set to 0).
+ */
+ value &= ~DR_CONTROL_RESERVED_ZERO; /* reserved bits => 0 */
+ value |= DR_CONTROL_RESERVED_ONE; /* reserved bits => 1 */
+ /*
+ * Privileged bits:
+ * GD (bit 13): must be 0.
+ */
+ if ( value & DR_GENERAL_DETECT )
+ return -EPERM;
+
+ /* DR7.{G,L}E = 0 => debugging disabled for this domain. */
+ if ( value & DR7_ACTIVE_MASK )
+ {
+ unsigned int i, io_enable = 0;
+
+ for ( i = DR_CONTROL_SHIFT; i < 32; i += DR_CONTROL_SIZE )
+ {
+ if ( ((value >> i) & 3) == DR_IO )
+ {
+ if ( !(v->arch.pv.ctrlreg[4] & X86_CR4_DE) )
+ return -EPERM;
+ io_enable |= value & (3 << ((i - 16) >> 1));
+ }
+ }
+
+ v->arch.pv.dr7_emul = io_enable;
+ value &= ~io_enable;
+
+ /*
+ * If DR7 was previously clear then we need to load all other
+ * debug registers at this point as they were not restored during
+ * context switch. Updating DR7 itself happens later.
+ */
+ if ( (v == curr) && !(v->arch.dr7 & DR7_ACTIVE_MASK) )
+ activate_debugregs(v);
+ }
+ else
+ /* Zero the emulated controls if %dr7 isn't active. */
+ v->arch.pv.dr7_emul = 0;
+
+ v->arch.dr7 = value;
+ if ( v == curr )
+ write_debugreg(7, value);
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
* Local variables:
* mode: C
* c-file-style: "BSD"
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index c60c8f5c2a..7765f9a5d7 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1115,6 +1115,7 @@ static void reserved_bit_page_fault(unsigned long addr,
show_execution_state(regs);
}

+#ifdef CONFIG_PV
static int handle_ldt_mapping_fault(unsigned int offset,
struct cpu_user_regs *regs)
{
@@ -1185,6 +1186,7 @@ static int handle_gdt_ldt_mapping_fault(unsigned long offset,

return EXCRET_fault_fixed;
}
+#endif

#define IN_HYPERVISOR_RANGE(va) \
(((va) >= HYPERVISOR_VIRT_START) && ((va) < HYPERVISOR_VIRT_END))
@@ -1335,10 +1337,12 @@ static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)

if ( unlikely(IN_HYPERVISOR_RANGE(addr)) )
{
+#ifdef CONFIG_PV
if ( !(regs->error_code & (PFEC_user_mode | PFEC_reserved_bit)) &&
(addr >= GDT_LDT_VIRT_START) && (addr < GDT_LDT_VIRT_END) )
return handle_gdt_ldt_mapping_fault(
addr - GDT_LDT_VIRT_START, regs);
+#endif
return 0;
}

@@ -1494,7 +1498,9 @@ void __init do_early_page_fault(struct cpu_user_regs *regs)

void do_general_protection(struct cpu_user_regs *regs)
{
+#ifdef CONFIG_PV
struct vcpu *v = current;
+#endif
unsigned long fixup;

if ( debugger_trap_entry(TRAP_gp_fault, regs) )
@@ -1506,6 +1512,7 @@ void do_general_protection(struct cpu_user_regs *regs)
if ( !guest_mode(regs) )
goto gp_in_kernel;

+#ifdef CONFIG_PV
/*
* Cunning trick to allow arbitrary "INT n" handling.
*
@@ -1557,6 +1564,7 @@ void do_general_protection(struct cpu_user_regs *regs)
/* Pass on GPF as is. */
pv_inject_hw_exception(TRAP_gp_fault, regs->error_code);
return;
+#endif

gp_in_kernel:

@@ -1744,7 +1752,9 @@ void unset_nmi_callback(void)

void do_device_not_available(struct cpu_user_regs *regs)
{
+#ifdef CONFIG_PV
struct vcpu *curr = current;
+#endif

if ( !guest_mode(regs) )
{
@@ -1762,6 +1772,7 @@ void do_device_not_available(struct cpu_user_regs *regs)
return;
}

+#ifdef CONFIG_PV
vcpu_restore_fpu_lazy(curr);

if ( curr->arch.pv.ctrlreg[0] & X86_CR0_TS )
@@ -1771,6 +1782,9 @@ void do_device_not_available(struct cpu_user_regs *regs)
}
else
TRACE_0D(TRC_PV_MATH_STATE_RESTORE);
+#else
+ ASSERT_UNREACHABLE();
+#endif

return;
}
@@ -2078,122 +2092,6 @@ void activate_debugregs(const struct vcpu *curr)
}
}

-/*
- * Used by hypercalls and the emulator.
- * -ENODEV => #UD
- * -EINVAL => #GP Invalid bit
- * -EPERM => #GP Valid bit, but not permitted to use
- */
-long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
-{
- struct vcpu *curr = current;
-
- switch ( reg )
- {
- case 0 ... 3:
- if ( !access_ok(value, sizeof(long)) )
- return -EPERM;
-
- v->arch.dr[reg] = value;
- if ( v == curr )
- {
- switch ( reg )
- {
- case 0: write_debugreg(0, value); break;
- case 1: write_debugreg(1, value); break;
- case 2: write_debugreg(2, value); break;
- case 3: write_debugreg(3, value); break;
- }
- }
- break;
-
- case 4:
- if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
- return -ENODEV;
-
- /* Fallthrough */
- case 6:
- /* The upper 32 bits are strictly reserved. */
- if ( value != (uint32_t)value )
- return -EINVAL;
-
- /*
- * DR6: Bits 4-11,16-31 reserved (set to 1).
- * Bit 12 reserved (set to 0).
- */
- value &= ~DR_STATUS_RESERVED_ZERO; /* reserved bits => 0 */
- value |= DR_STATUS_RESERVED_ONE; /* reserved bits => 1 */
-
- v->arch.dr6 = value;
- if ( v == curr )
- write_debugreg(6, value);
- break;
-
- case 5:
- if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
- return -ENODEV;
-
- /* Fallthrough */
- case 7:
- /* The upper 32 bits are strictly reserved. */
- if ( value != (uint32_t)value )
- return -EINVAL;
-
- /*
- * DR7: Bit 10 reserved (set to 1).
- * Bits 11-12,14-15 reserved (set to 0).
- */
- value &= ~DR_CONTROL_RESERVED_ZERO; /* reserved bits => 0 */
- value |= DR_CONTROL_RESERVED_ONE; /* reserved bits => 1 */
- /*
- * Privileged bits:
- * GD (bit 13): must be 0.
- */
- if ( value & DR_GENERAL_DETECT )
- return -EPERM;
-
- /* DR7.{G,L}E = 0 => debugging disabled for this domain. */
- if ( value & DR7_ACTIVE_MASK )
- {
- unsigned int i, io_enable = 0;
-
- for ( i = DR_CONTROL_SHIFT; i < 32; i += DR_CONTROL_SIZE )
- {
- if ( ((value >> i) & 3) == DR_IO )
- {
- if ( !(v->arch.pv.ctrlreg[4] & X86_CR4_DE) )
- return -EPERM;
- io_enable |= value & (3 << ((i - 16) >> 1));
- }
- }
-
- v->arch.pv.dr7_emul = io_enable;
- value &= ~io_enable;
-
- /*
- * If DR7 was previously clear then we need to load all other
- * debug registers at this point as they were not restored during
- * context switch. Updating DR7 itself happens later.
- */
- if ( (v == curr) && !(v->arch.dr7 & DR7_ACTIVE_MASK) )
- activate_debugregs(v);
- }
- else
- /* Zero the emulated controls if %dr7 isn't active. */
- v->arch.pv.dr7_emul = 0;
-
- v->arch.dr7 = value;
- if ( v == curr )
- write_debugreg(7, value);
- break;
-
- default:
- return -ENODEV;
- }
-
- return 0;
-}
-
void asm_domain_crash_synchronous(unsigned long addr)
{
/*
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 7214037820..643e69acf9 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -681,7 +681,14 @@ void arch_vcpu_regs_init(struct vcpu *v);
struct vcpu_hvm_context;
int arch_set_info_hvm_guest(struct vcpu *v, const struct vcpu_hvm_context *ctx);

+#ifdef CONFIG_PV
void pv_inject_event(const struct x86_event *event);
+#else
+static inline void pv_inject_event(const struct x86_event *event)
+{
+ ASSERT_UNREACHABLE();
+}
+#endif

static inline void pv_inject_hw_exception(unsigned int vector, int errcode)
{
--
generated by git-patchbot for /home/xen/git/xen.git#master

Loading...