# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1168851172 -32400 # Node ID 9b0918c4332ef93b4352abf80a7c33a3b82b469f # Parent 2b50acbdf01bfadbaab60a6d15a9f6a878d0224c Use the guest's own p2m table instead of xc_get_pfn_list(), which cannot handle PFNs with no MFN. Dump a zeroed page for PFNs with no MFN. Clearly deprecate xc_get_pfn_list(). Do not include a P2M table with HVM domains. Refuse to dump HVM until we can map its pages with PFNs. Signed-off-by: John Levon PFN-GMFN table, ELF formatified. TODO: - Currently one program header per page. It's possible to collapse many program header. - HVM domain - IA64. PATCHNAME: xen_dump_core_elf Signed-off-by: Isaku Yamahata diff -r 2b50acbdf01b -r 9b0918c4332e tools/libxc/xc_core.c --- a/tools/libxc/xc_core.c Sun Jan 14 17:22:24 2007 +0000 +++ b/tools/libxc/xc_core.c Mon Jan 15 17:52:52 2007 +0900 @@ -1,10 +1,18 @@ +/* + * Elf format, (pfn, gmfn) table support. + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + */ + #include "xg_private.h" +#include "xc_elf.h" +#include "xc_core.h" #include #include /* number of pages to write at a time */ #define DUMP_INCREMENT (4 * 1024) -#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) static int copy_from_domain_page(int xc_handle, @@ -21,107 +29,334 @@ copy_from_domain_page(int xc_handle, return 0; } +static int +map_p2m(int xc_handle, xc_dominfo_t *info, xen_pfn_t **live_p2m, + unsigned long *pfnp) +{ + /* Double and single indirect references to the live P2M table */ + xen_pfn_t *live_p2m_frame_list_list = NULL; + xen_pfn_t *live_p2m_frame_list = NULL; + shared_info_t *live_shinfo = NULL; + uint32_t dom = info->domid; + unsigned long max_pfn = 0; + int ret = -1; + int err; + + /* Map the shared info frame */ + live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ, info->shared_info_frame); + + if ( !live_shinfo ) + { + PERROR("Couldn't map live_shinfo"); + goto out; + } + + max_pfn = live_shinfo->arch.max_pfn; + + if ( max_pfn < info->nr_pages ) + { + ERROR("max_pfn < nr_pages -1 (%lx < %lx", max_pfn, info->nr_pages - 1); + goto out; + } + + live_p2m_frame_list_list = + xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, + live_shinfo->arch.pfn_to_mfn_frame_list_list); + + if ( !live_p2m_frame_list_list ) + { + PERROR("Couldn't map p2m_frame_list_list (errno %d)", errno); + goto out; + } + + live_p2m_frame_list = + xc_map_foreign_batch(xc_handle, dom, PROT_READ, + live_p2m_frame_list_list, + P2M_FLL_ENTRIES); + + if ( !live_p2m_frame_list ) + { + PERROR("Couldn't map p2m_frame_list"); + goto out; + } + + *live_p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ, + live_p2m_frame_list, + P2M_FL_ENTRIES); + + if ( !live_p2m ) + { + PERROR("Couldn't map p2m table"); + goto out; + } + + *pfnp = max_pfn; + + + ret = 0; + +out: + err = errno; + + if ( live_shinfo ) + munmap(live_shinfo, PAGE_SIZE); + + if ( live_p2m_frame_list_list ) + munmap(live_p2m_frame_list_list, PAGE_SIZE); + + if ( live_p2m_frame_list ) + munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE); + + errno = err; + return ret; +} + int xc_domain_dumpcore_via_callback(int xc_handle, uint32_t domid, void *args, dumpcore_rtn_t dump_rtn) { - unsigned long nr_pages; - xen_pfn_t *page_array = NULL; xc_dominfo_t info; - int i, nr_vcpus = 0; + int nr_vcpus = 0; char *dump_mem, *dump_mem_start = NULL; - struct xc_core_header header; vcpu_guest_context_t ctxt[MAX_VIRT_CPUS]; char dummy[PAGE_SIZE]; int dummy_len; - int sts; + int sts = -1; + + unsigned long filesz; + unsigned long i; + unsigned long j; + unsigned long nr_pages; + xen_pfn_t *p2m; + unsigned long max_pfn; + struct p2m *p2m_array = NULL; + unsigned long offset; + + Elf_Ehdr ehdr; + Elf_Phdr phdr; + struct xen_note note; + struct xen_core_header_desc core_header; if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL ) { PERROR("Could not allocate dump_mem"); - goto error_out; + goto out; } if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 ) { PERROR("Could not get info for domain"); - goto error_out; + goto out; + } + + if ( info.hvm ) + { + ERROR("Cannot dump HVM domains"); + goto out; } if ( domid != info.domid ) { PERROR("Domain %d does not exist", domid); - goto error_out; + goto out; } for ( i = 0; i <= info.max_vcpu_id; i++ ) if ( xc_vcpu_getcontext(xc_handle, domid, i, &ctxt[nr_vcpus]) == 0) nr_vcpus++; + if ( nr_vcpus == 0 ) + { + PERROR("No VCPU context could be grabbed"); + goto out; + } nr_pages = info.nr_pages; - - header.xch_magic = info.hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC; - header.xch_nr_vcpus = nr_vcpus; - header.xch_nr_pages = nr_pages; - header.xch_ctxt_offset = sizeof(struct xc_core_header); - header.xch_index_offset = sizeof(struct xc_core_header) + - sizeof(vcpu_guest_context_t)*nr_vcpus; - dummy_len = (sizeof(struct xc_core_header) + - (sizeof(vcpu_guest_context_t) * nr_vcpus) + - (nr_pages * sizeof(xen_pfn_t))); - header.xch_pages_offset = round_pgup(dummy_len); - - sts = dump_rtn(args, (char *)&header, sizeof(struct xc_core_header)); - if ( sts != 0 ) - goto error_out; - + p2m_array = malloc(nr_pages * sizeof(struct p2m)); + if ( p2m_array == NULL ) + { + PERROR("Count not allocate p2m array"); + goto out; + } + + /* obtain p2m table */ + if ( !info.hvm ) + { + sts = map_p2m(xc_handle, &info, &p2m, &max_pfn); + if ( sts != 0 ) + goto out; + } + + memset(&ehdr, 0, sizeof(ehdr)); + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_CLASS] = ELFCLASS; + + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; /* XXX */ + //ehdr.e_ident[EI_DATA] = ELFDATA2MSB; + + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_ident[EI_OSABI] = ELFOSABI_LINUX; + ehdr.e_ident[EI_ABIVERSION] = EV_CURRENT; + + ehdr.e_type = ET_CORE; + ehdr.e_machine = +#if defined(__i386__) + EM_386 +#elif defined(__x86_64__) + EM_X86_64 +#else +# error "unsupported archtecture" +#endif + ; + + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = 0; + ehdr.e_phoff = sizeof(ehdr); + ehdr.e_shoff = 0; +#ifndef ELF_CORE_EFLAGS +#define ELF_CORE_EFLAGS 0 +#endif + ehdr.e_flags = ELF_CORE_EFLAGS; + ehdr.e_ehsize = sizeof(ehdr); + ehdr.e_phentsize = sizeof(Elf_Phdr); + ehdr.e_phnum = nr_pages + 1; /* notes */ + ehdr.e_shentsize = 0; + ehdr.e_shnum = 0; + ehdr.e_shstrndx = 0; + sts = dump_rtn(args, (char*)&ehdr, sizeof(ehdr)); + if ( sts != 0 ) + goto out; + + /* create program header */ + offset = sizeof(ehdr); + + /* note section */ + offset += (1 + nr_pages) * sizeof(phdr); /* note section + nr_pages */ + filesz = sizeof(struct xen_core_header) + /* core header */ + sizeof(struct xen_note) + sizeof(ctxt[0]) * nr_vcpus + /* vcpu context */ + sizeof(struct xen_note_p2m) + sizeof(p2m_array[0]) * nr_pages; /* p2m table */ + + memset(&phdr, 0, sizeof(phdr)); + phdr.p_type = PT_NOTE; + phdr.p_flags = 0; + phdr.p_offset = offset; + phdr.p_vaddr = 0; + phdr.p_paddr = 0; + phdr.p_filesz = filesz; + phdr.p_memsz = 0; + phdr.p_align = 0; + + sts = dump_rtn(args, (char*)&phdr, sizeof(phdr)); + if ( sts != 0) + goto out; + + offset += filesz; + dummy_len = ROUNDUP(offset, PAGE_SHIFT) - offset; /* padding length */ + offset = ROUNDUP(offset, PAGE_SHIFT); + j = 0; + for (i = 0; i < max_pfn && j < nr_pages; i++) + { + if (p2m[i] == INVALID_P2M_ENTRY) + continue; + + memset(&phdr, 0, sizeof(phdr)); + phdr.p_type = PT_LOAD; + phdr.p_flags = PF_X | PF_W | PF_R; + phdr.p_offset = offset; + phdr.p_vaddr = 0; + phdr.p_paddr = i * PAGE_SIZE; + phdr.p_filesz = PAGE_SIZE; + phdr.p_memsz = PAGE_SIZE; + phdr.p_align = 0; + sts = dump_rtn(args, (char*)&phdr, sizeof(phdr)); + if ( sts != 0) + goto out; + + offset += PAGE_SIZE; + p2m_array[j].pfn = i; + p2m_array[j].gmfn = p2m[i]; + j++; + } + if ( j != nr_pages ) + PERROR("j(%ld) != nr_pages (%ld)", j, nr_pages); + + /* note section */ + memset(¬e, 0, sizeof(note)); + note.namesz = strlen(XEN_NOTES) + 1; + strncpy(note.name, XEN_NOTES, sizeof(note.name)); + + /* note section:xen core header */ + note.descsz = sizeof(core_header); + note.type = NT_XEN_HEADER; + core_header.xch_magic = info.hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC; + core_header.xch_nr_vcpus = nr_vcpus; + core_header.xch_nr_pages = nr_pages; + core_header.xch_page_size = PAGE_SIZE; + sts = dump_rtn(args, (char*)¬e, sizeof(note)); + if ( sts != 0) + goto out; + sts = dump_rtn(args, (char*)&core_header, sizeof(core_header)); + if ( sts != 0) + goto out; + + /* note section:xen vcpu prstatus */ + note.descsz = sizeof(ctxt[0]) * nr_vcpus; + note.type = NT_XEN_PRSTATUS; + sts = dump_rtn(args, (char*)¬e, sizeof(note)); + if ( sts != 0) + goto out; sts = dump_rtn(args, (char *)&ctxt, sizeof(ctxt[0]) * nr_vcpus); if ( sts != 0 ) - goto error_out; - - if ( (page_array = malloc(nr_pages * sizeof(xen_pfn_t))) == NULL ) - { - IPRINTF("Could not allocate memory\n"); - goto error_out; - } - if ( xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages ) - { - IPRINTF("Could not get the page frame list\n"); - goto error_out; - } - sts = dump_rtn(args, (char *)page_array, nr_pages * sizeof(xen_pfn_t)); - if ( sts != 0 ) - goto error_out; - + goto out; + + /* note section:create p2m table */ + note.descsz = sizeof(p2m_array[0]) * nr_pages; + note.type = NT_XEN_P2M; + sts = dump_rtn(args, (char*)¬e, sizeof(note)); + if ( sts != 0 ) + goto out; + sts = dump_rtn(args, (char *)p2m_array, sizeof(p2m_array[0]) * nr_pages); + if ( sts != 0 ) + goto out; + /* Pad the output data to page alignment. */ memset(dummy, 0, PAGE_SIZE); - sts = dump_rtn(args, dummy, header.xch_pages_offset - dummy_len); - if ( sts != 0 ) - goto error_out; - + sts = dump_rtn(args, dummy, dummy_len); + if ( sts != 0 ) + goto out; + + /* dump pages */ for ( dump_mem = dump_mem_start, i = 0; i < nr_pages; i++ ) { - copy_from_domain_page(xc_handle, domid, page_array[i], dump_mem); + copy_from_domain_page(xc_handle, domid, p2m_array[i].gmfn, dump_mem); dump_mem += PAGE_SIZE; if ( ((i + 1) % DUMP_INCREMENT == 0) || ((i + 1) == nr_pages) ) { sts = dump_rtn(args, dump_mem_start, dump_mem - dump_mem_start); if ( sts != 0 ) - goto error_out; + goto out; dump_mem = dump_mem_start; } } + sts = 0; + +out: + if ( p2m ) + { + if ( info.hvm ) + free( p2m ); + else + munmap(p2m, P2M_SIZE); + } free(dump_mem_start); - free(page_array); - return 0; - - error_out: - free(dump_mem_start); - free(page_array); - return -1; + free(p2m_array); + return sts; } /* Callback args for writing to a local dump file. */ diff -r 2b50acbdf01b -r 9b0918c4332e tools/libxc/xc_core.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_core.h Mon Jan 15 17:52:52 2007 +0900 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * 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. 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef XC_CORE_H +#define XC_CORE_H + +#define XEN_NOTES "XEN CORE" + +/* Notes used in xen core*/ +#define NT_XEN_HEADER 7 +#define NT_XEN_PRSTATUS 8 +#define NT_XEN_P2M 9 + + +struct xen_note { + uint32_t namesz; + uint32_t descsz; + uint32_t type; + char name[12]; /* to hold XEN_NOTES and 64bit aligned. + * 8 <= sizeof(XEN_NOTES) < 12 + */ +}; + + +struct xen_core_header_desc { + uint64_t xch_magic; + uint64_t xch_nr_vcpus; + uint64_t xch_nr_pages; + uint64_t xch_page_size; +}; + +struct p2m { + xen_pfn_t pfn; + xen_pfn_t gmfn; +}; + + +struct xen_core_header { + struct xen_note note; + struct xen_core_header_desc core_header; +}; + +struct xen_note_prstatus { + struct xen_note note; + vcpu_guest_context_t ctxt[0]; +}; + +struct xen_note_p2m { + struct xen_note note; + struct p2m p2m[0]; +}; + +#endif /* XC_CORE_H */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 2b50acbdf01b -r 9b0918c4332e tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Sun Jan 14 17:22:24 2007 +0000 +++ b/tools/libxc/xenctrl.h Mon Jan 15 17:52:52 2007 +0900 @@ -513,6 +513,10 @@ unsigned long xc_translate_foreign_addre unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom, int vcpu, unsigned long long virt); +/** + * DEPRECATED. Avoid using this, as it does not correctly account for PFNs + * without a backing MFN. + */ int xc_get_pfn_list(int xc_handle, uint32_t domid, xen_pfn_t *pfn_buf, unsigned long max_pfns); diff -r 2b50acbdf01b -r 9b0918c4332e tools/libxc/xg_private.h --- a/tools/libxc/xg_private.h Sun Jan 14 17:22:24 2007 +0000 +++ b/tools/libxc/xg_private.h Mon Jan 15 17:52:52 2007 +0900 @@ -119,6 +119,25 @@ typedef unsigned long l4_pgentry_t; (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1)) #endif +#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) + +/* Size in bytes of the P2M (rounded up to the nearest PAGE_SIZE bytes) */ +#define P2M_SIZE ROUNDUP((max_pfn * sizeof(xen_pfn_t)), PAGE_SHIFT) + +/* Number of xen_pfn_t in a page */ +#define fpp (PAGE_SIZE/sizeof(xen_pfn_t)) + +/* Number of entries in the pfn_to_mfn_frame_list_list */ +#define P2M_FLL_ENTRIES (((max_pfn)+(fpp*fpp)-1)/(fpp*fpp)) + +/* Number of entries in the pfn_to_mfn_frame_list */ +#define P2M_FL_ENTRIES (((max_pfn)+fpp-1)/fpp) + +/* Size in bytes of the pfn_to_mfn_frame_list */ +#define P2M_FL_SIZE ((P2M_FL_ENTRIES)*sizeof(unsigned long)) + +#define INVALID_P2M_ENTRY (~0UL) + struct domain_setup_info { uint64_t v_start; diff -r 2b50acbdf01b -r 9b0918c4332e tools/libxc/xg_save_restore.h --- a/tools/libxc/xg_save_restore.h Sun Jan 14 17:22:24 2007 +0000 +++ b/tools/libxc/xg_save_restore.h Mon Jan 15 17:52:52 2007 +0900 @@ -82,7 +82,6 @@ static int get_platform_info(int xc_hand */ #define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10)) -#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) /* @@ -95,25 +94,5 @@ static int get_platform_info(int xc_hand #define M2P_SIZE(_m) ROUNDUP(((_m) * sizeof(xen_pfn_t)), M2P_SHIFT) #define M2P_CHUNKS(_m) (M2P_SIZE((_m)) >> M2P_SHIFT) -/* Size in bytes of the P2M (rounded up to the nearest PAGE_SIZE bytes) */ -#define P2M_SIZE ROUNDUP((max_pfn * sizeof(xen_pfn_t)), PAGE_SHIFT) - -/* Number of xen_pfn_t in a page */ -#define fpp (PAGE_SIZE/sizeof(xen_pfn_t)) - -/* Number of entries in the pfn_to_mfn_frame_list */ -#define P2M_FL_ENTRIES (((max_pfn)+fpp-1)/fpp) - -/* Size in bytes of the pfn_to_mfn_frame_list */ -#define P2M_FL_SIZE ((P2M_FL_ENTRIES)*sizeof(unsigned long)) - -/* Number of entries in the pfn_to_mfn_frame_list_list */ -#define P2M_FLL_ENTRIES (((max_pfn)+(fpp*fpp)-1)/(fpp*fpp)) - /* Returns TRUE if the PFN is currently mapped */ #define is_mapped(pfn_type) (!((pfn_type) & 0x80000000UL)) - -#define INVALID_P2M_ENTRY (~0UL) - - -