]> xenbits.xensource.com Git - people/liuw/xtf.git/commitdiff
Helpers to retrieve %ss and %esp from cpu_regs
authorAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 27 May 2016 07:53:53 +0000 (08:53 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 16 Jun 2016 13:29:17 +0000 (14:29 +0100)
In 32bit, if not stack switch occurs, this information isn't present in an
exception frame.  As a result, regs->sp and regs->ss may actually alias the
interrupted stack frame.  To avoid accidental incorrect use, prefix the names
in cpu_regs with an underscore.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/traps.c
include/arch/x86/regs.h
include/arch/x86/traps.h

index cad7ea603500a952ccd86281cf80f70ad5a969d1..74d5c5448e5688657b22efb6d095bc0835585228 100644 (file)
@@ -55,6 +55,34 @@ static bool is_trap_or_interrupt(const struct cpu_regs *regs)
     return true;
 }
 
+unsigned long cpu_regs_sp(const struct cpu_regs *regs)
+{
+#ifdef __x86_64__
+    return regs->_sp;
+#else
+    unsigned int cs = read_cs();
+
+    if ( (regs->cs & 3) > (cs & 3) )
+        return regs->_sp;
+
+    return (unsigned long)regs + offsetof(struct cpu_regs, _sp);
+#endif
+}
+
+unsigned int cpu_regs_ss(const struct cpu_regs *regs)
+{
+#ifdef __x86_64__
+    return regs->_ss;
+#else
+    unsigned int cs = read_cs();
+
+    if ( (regs->cs & 3) > (cs & 3) )
+        return regs->_ss;
+
+    return read_ss();
+#endif
+}
+
 /*
  * C entry-point for exceptions, after the per-environment stubs have suitably
  * adjusted the stack.
index 1fb534056e5884c13054241629cb27e79090d944..618b5624afce9f4fc6b5bdec49ae6a6ee0555786 100644 (file)
@@ -7,6 +7,8 @@
 
 #define DECL_REG(n)                             \
     union { uint32_t e ## n; unsigned long n; }
+#define _DECL_REG(n)                            \
+    union { uint32_t _e ## n; unsigned long _ ## n; }
 
 struct cpu_regs {
     DECL_REG(bp);
@@ -24,8 +26,8 @@ struct cpu_regs {
     DECL_REG(ip);
     uint16_t cs, _pad1[1];
     DECL_REG(flags);
-    DECL_REG(sp);          /* Won't be valid if stack */
-    uint16_t ss, _pad0[1]; /* switch didn't occur.    */
+    _DECL_REG(sp);          /* Won't be valid if stack */
+    uint16_t _ss, _pad0[1]; /* switch didn't occur.    */
 /* Top of stack. */
 };
 
@@ -33,6 +35,8 @@ struct cpu_regs {
 
 #define DECL_REG(n)                             \
     union { uint64_t r ## n; uint32_t e ## n; unsigned long n; }
+#define _DECL_REG(n)                                                \
+    union { uint64_t _r ## n; uint32_t _e ## n; unsigned long _ ## n; }
 
 struct cpu_regs {
     uint64_t r15;
@@ -58,8 +62,8 @@ struct cpu_regs {
     DECL_REG(ip);
     uint16_t cs, _pad1[3];
     DECL_REG(flags);
-    DECL_REG(sp);
-    uint16_t ss, _pad0[3];
+    _DECL_REG(sp);
+    uint16_t _ss, _pad0[3];
 /* Top of stack. */
 };
 
index 600aa763179b19aea59d085c569300ac4337c655..48687f6135eb3467dbba417d2ec68593a8bd4d70 100644 (file)
@@ -16,6 +16,13 @@ void arch_init_traps(void);
  */
 void __noreturn arch_crash_hard(void);
 
+/*
+ * Return the correct %ss/%esp from an exception.  In 32bit if no stack switch
+ * occurs, an exception frame doesn't contain this information.
+ */
+unsigned long cpu_regs_sp(const struct cpu_regs *regs);
+unsigned int  cpu_regs_ss(const struct cpu_regs *regs);
+
 extern uint8_t boot_stack[2 * PAGE_SIZE];
 
 #if defined(CONFIG_PV)