All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86: improve output resulting from sending '0' over serial
@ 2009-06-10 14:57 Jan Beulich
  0 siblings, 0 replies; only message in thread
From: Jan Beulich @ 2009-06-10 14:57 UTC (permalink / raw)
  To: xen-devel

While the original logic already implied that the kernel part of the
guest's address space is identical on all vCPU-s (i.e. for all guest
processes), it didn't fully leverage the potential here: As long as
the top page table currently active is owned by the subject domain
(currently only Dom0), the stack dump can be done without extra
effort.

For x86-64, additionally add page table traversal so that the stack
can be dumped in all cases (unless it's invalid or user space).

I left the 32-bit variant of do_page_walk() unimplemented for the
moment as I couldn't convince myself using map_domain_page() there is
a good idea, and didn't want to introduce new fixmap entries either.

Signed-off-by: Jan Beulich <jbeulich@novell.com>

--- 2009-06-10.orig/xen/arch/x86/traps.c	2009-06-10 10:48:29.000000000 +0200
+++ 2009-06-10/xen/arch/x86/traps.c	2009-06-10 11:15:26.000000000 +0200
@@ -129,18 +129,18 @@ boolean_param("ler", opt_ler);
 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
 #endif
 
-static void show_guest_stack(struct cpu_user_regs *regs)
+static void show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs)
 {
     int i;
-    struct vcpu *curr = current;
     unsigned long *stack, addr;
+    unsigned long mask = STACK_SIZE;
 
-    if ( is_hvm_vcpu(curr) )
+    if ( is_hvm_vcpu(v) )
         return;
 
-    if ( is_pv_32on64_vcpu(curr) )
+    if ( is_pv_32on64_vcpu(v) )
     {
-        compat_show_guest_stack(regs, debug_stack_lines);
+        compat_show_guest_stack(v, regs, debug_stack_lines);
         return;
     }
 
@@ -156,11 +156,42 @@ static void show_guest_stack(struct cpu_
         printk("Guest stack trace from "__OP"sp=%p:\n  ", stack);
     }
 
+    if ( !access_ok(stack, sizeof(*stack)) )
+    {
+        printk("Guest-inaccessible memory.\n");
+        return;
+    }
+
+    if ( v != current )
+    {
+        struct vcpu *vcpu;
+
+        ASSERT(guest_kernel_mode(v, regs));
+#ifndef __x86_64__
+        addr = read_cr3();
+        for_each_vcpu( v->domain, vcpu )
+            if ( vcpu->arch.cr3 == addr )
+                break;
+#else
+        vcpu = maddr_get_owner(read_cr3()) == v->domain ? v : NULL;
+#endif
+        if ( !vcpu )
+        {
+            stack = do_page_walk(v, (unsigned long)stack);
+            if ( (unsigned long)stack < PAGE_SIZE )
+            {
+                printk("Inaccessible guest memory.\n");
+                return;
+            }
+            mask = PAGE_SIZE;
+        }
+    }
+
     for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ )
     {
-        if ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) == 0 )
+        if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & mask )
             break;
-        if ( get_user(addr, stack) )
+        if ( __get_user(addr, stack) )
         {
             if ( i != 0 )
                 printk("\n    ");
@@ -264,7 +295,7 @@ void show_stack(struct cpu_user_regs *re
     int i;
 
     if ( guest_mode(regs) )
-        return show_guest_stack(regs);
+        return show_guest_stack(current, regs);
 
     printk("Xen stack trace from "__OP"sp=%p:\n  ", stack);
 
@@ -346,10 +377,8 @@ void vcpu_show_execution_state(struct vc
     vcpu_pause(v); /* acceptably dangerous */
 
     vcpu_show_registers(v);
-    /* Todo: map arbitrary vcpu's top guest stack page here. */
-    if ( (v->domain == current->domain) &&
-         guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
-        show_guest_stack(&v->arch.guest_context.user_regs);
+    if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
+        show_guest_stack(v, &v->arch.guest_context.user_regs);
 
     vcpu_unpause(v);
 }
--- 2009-06-10.orig/xen/arch/x86/x86_32/mm.c	2009-05-20 08:45:59.000000000 +0200
+++ 2009-06-10/xen/arch/x86/x86_32/mm.c	2009-06-10 11:15:26.000000000 +0200
@@ -63,6 +63,11 @@ l2_pgentry_t *virt_to_xen_l2e(unsigned l
     return &idle_pg_table_l2[l2_linear_offset(v)];
 }
 
+void *do_page_walk(struct vcpu *v, unsigned long addr)
+{
+    return NULL;
+}
+
 void __init paging_init(void)
 {
     unsigned long v;
--- 2009-06-10.orig/xen/arch/x86/x86_64/compat/traps.c	2008-07-18 16:19:34.000000000 +0200
+++ 2009-06-10/xen/arch/x86/x86_64/compat/traps.c	2009-06-10 11:15:26.000000000 +0200
@@ -5,18 +5,46 @@
 #include <compat/callback.h>
 #include <compat/arch-x86_32.h>
 
-void compat_show_guest_stack(struct cpu_user_regs *regs, int debug_stack_lines)
+void compat_show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs,
+                             int debug_stack_lines)
 {
-    unsigned int i, *stack, addr;
+    unsigned int i, *stack, addr, mask = STACK_SIZE;
 
     stack = (unsigned int *)(unsigned long)regs->_esp;
     printk("Guest stack trace from esp=%08lx:\n ", (unsigned long)stack);
 
+    if ( !__compat_access_ok(v->domain, stack, sizeof(*stack)) )
+    {
+        printk("Guest-inaccessible memory.\n");
+        return;
+    }
+
+    if ( v != current )
+    {
+        struct vcpu *vcpu;
+
+        ASSERT(guest_kernel_mode(v, regs));
+        addr = read_cr3() >> PAGE_SHIFT;
+        for_each_vcpu( v->domain, vcpu )
+            if ( pagetable_get_pfn(vcpu->arch.guest_table) == addr )
+                break;
+        if ( !vcpu )
+        {
+            stack = do_page_walk(v, (unsigned long)stack);
+            if ( (unsigned long)stack < PAGE_SIZE )
+            {
+                printk("Inaccessible guest memory.\n");
+                return;
+            }
+            mask = PAGE_SIZE;
+        }
+    }
+
     for ( i = 0; i < debug_stack_lines * 8; i++ )
     {
-        if ( (((long)stack + 3) & (STACK_SIZE - 4)) == 0 )
+        if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & mask )
             break;
-        if ( get_user(addr, stack) )
+        if ( __get_user(addr, stack) )
         {
             if ( i != 0 )
                 printk("\n    ");
--- 2009-06-10.orig/xen/arch/x86/x86_64/mm.c	2009-05-20 08:45:59.000000000 +0200
+++ 2009-06-10/xen/arch/x86/x86_64/mm.c	2009-06-10 11:15:26.000000000 +0200
@@ -103,6 +103,47 @@ l2_pgentry_t *virt_to_xen_l2e(unsigned l
     return l3e_to_l2e(*pl3e) + l2_table_offset(v);
 }
 
+void *do_page_walk(struct vcpu *v, unsigned long addr)
+{
+    unsigned long mfn = pagetable_get_pfn(v->arch.guest_table);
+    l4_pgentry_t l4e, *l4t;
+    l3_pgentry_t l3e, *l3t;
+    l2_pgentry_t l2e, *l2t;
+    l1_pgentry_t l1e, *l1t;
+
+    if ( is_hvm_vcpu(v) )
+        return NULL;
+
+    l4t = mfn_to_virt(mfn);
+    l4e = l4t[l4_table_offset(addr)];
+    mfn = l4e_get_pfn(l4e);
+    if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
+        return NULL;
+
+    l3t = mfn_to_virt(mfn);
+    l3e = l3t[l3_table_offset(addr)];
+    mfn = l3e_get_pfn(l3e);
+    if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
+    if ( (l3e_get_flags(l3e) & _PAGE_PSE) )
+        return mfn_to_virt(mfn) + (addr & ((1UL << L3_PAGETABLE_SHIFT) - 1));
+
+    l2t = mfn_to_virt(mfn);
+    l2e = l2t[l2_table_offset(addr)];
+    mfn = l2e_get_pfn(l2e);
+    if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
+        return NULL;
+    if ( (l2e_get_flags(l2e) & _PAGE_PSE) )
+        return mfn_to_virt(mfn) + (addr & ((1UL << L2_PAGETABLE_SHIFT) - 1));
+
+    l1t = mfn_to_virt(mfn);
+    l1e = l1t[l1_table_offset(addr)];
+    mfn = l1e_get_pfn(l1e);
+    if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) || !mfn_valid(mfn) )
+        return NULL;
+
+    return mfn_to_virt(mfn) + (addr & ~PAGE_MASK);
+}
+
 void __init paging_init(void)
 {
     unsigned long i, mpt_size, va;
--- 2009-06-10.orig/xen/include/asm-x86/mm.h	2009-06-05 11:59:48.000000000 +0200
+++ 2009-06-10/xen/include/asm-x86/mm.h	2009-06-10 11:15:26.000000000 +0200
@@ -475,6 +475,7 @@ int new_guest_cr3(unsigned long pfn);
 void make_cr3(struct vcpu *v, unsigned long mfn);
 void update_cr3(struct vcpu *v);
 void propagate_page_fault(unsigned long addr, u16 error_code);
+void *do_page_walk(struct vcpu *v, unsigned long addr);
 
 int __sync_lazy_execstate(void);
 
--- 2009-06-10.orig/xen/include/asm-x86/processor.h	2009-03-16 16:09:07.000000000 +0100
+++ 2009-06-10/xen/include/asm-x86/processor.h	2009-06-10 11:15:26.000000000 +0200
@@ -536,9 +536,9 @@ void show_page_walk(unsigned long addr);
 asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs);
 
 #ifdef CONFIG_COMPAT
-void compat_show_guest_stack(struct cpu_user_regs *, int lines);
+void compat_show_guest_stack(struct vcpu *, struct cpu_user_regs *, int lines);
 #else
-#define compat_show_guest_stack(regs, lines) ((void)0)
+#define compat_show_guest_stack(vcpu, regs, lines) ((void)0)
 #endif
 
 extern void mtrr_ap_init(void);
--- 2009-06-10.orig/xen/include/asm-x86/x86_64/uaccess.h	2008-06-16 10:43:34.000000000 +0200
+++ 2009-06-10/xen/include/asm-x86/x86_64/uaccess.h	2009-06-10 11:15:26.000000000 +0200
@@ -27,11 +27,14 @@ DECLARE_PER_CPU(char, compat_arg_xlat[CO
 #define array_access_ok(addr, count, size) \
     (access_ok(addr, (count)*(size)))
 
-#define __compat_addr_ok(addr) \
-    ((unsigned long)(addr) < HYPERVISOR_COMPAT_VIRT_START(current->domain))
+#define __compat_addr_ok(d, addr) \
+    ((unsigned long)(addr) < HYPERVISOR_COMPAT_VIRT_START(d))
+
+#define __compat_access_ok(d, addr, size) \
+    __compat_addr_ok(d, (unsigned long)(addr) + ((size) ? (size) - 1 : 0))
 
 #define compat_access_ok(addr, size) \
-    __compat_addr_ok((unsigned long)(addr) + ((size) ? (size) - 1 : 0))
+    __compat_access_ok(current->domain, addr, size)
 
 #define compat_array_access_ok(addr,count,size) \
     (likely((count) < (~0U / (size))) && \

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-06-10 14:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-10 14:57 [PATCH] x86: improve output resulting from sending '0' over serial Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.