diff options
author | markj <markj@FreeBSD.org> | 2015-01-07 01:01:39 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2015-01-07 01:01:39 +0000 |
commit | 7e7e145818dbebec11d3fb1dded0452f0c3d99f9 (patch) | |
tree | 6d50f1ee65f4ceaf3fa5c14faf47e9ecd3aae3e5 /sys/powerpc | |
parent | d7969594c9a8a347e4914f5381da2436c1a93710 (diff) | |
download | FreeBSD-src-7e7e145818dbebec11d3fb1dded0452f0c3d99f9.zip FreeBSD-src-7e7e145818dbebec11d3fb1dded0452f0c3d99f9.tar.gz |
Factor out duplicated code from dumpsys() on each architecture into generic
code in sys/kern/kern_dump.c. Most dumpsys() implementations are nearly
identical and simply redefine a number of constants and helper subroutines;
a generic implementation will make it easier to implement features around
kernel core dumps. This change does not alter any minidump code and should
have no functional impact.
PR: 193873
Differential Revision: https://reviews.freebsd.org/D904
Submitted by: Conrad Meyer <conrad.meyer@isilon.com>
Reviewed by: jhibbits (earlier version)
Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'sys/powerpc')
-rw-r--r-- | sys/powerpc/aim/mmu_oea.c | 155 | ||||
-rw-r--r-- | sys/powerpc/aim/mmu_oea64.c | 150 | ||||
-rw-r--r-- | sys/powerpc/booke/pmap.c | 216 | ||||
-rw-r--r-- | sys/powerpc/include/dump.h | 69 | ||||
-rw-r--r-- | sys/powerpc/include/pmap.h | 12 | ||||
-rw-r--r-- | sys/powerpc/powerpc/dump_machdep.c | 283 | ||||
-rw-r--r-- | sys/powerpc/powerpc/mmu_if.m | 43 | ||||
-rw-r--r-- | sys/powerpc/powerpc/pmap_dispatch.c | 26 |
8 files changed, 329 insertions, 625 deletions
diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 742dd70..96628f71 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -106,8 +106,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/conf.h> #include <sys/queue.h> #include <sys/cpuset.h> +#include <sys/kerneldump.h> #include <sys/ktr.h> #include <sys/lock.h> #include <sys/msgbuf.h> @@ -163,8 +165,6 @@ struct ofw_map { extern unsigned char _etext[]; extern unsigned char _end[]; -extern int dumpsys_minidump; - /* * Map of physical memory regions. */ @@ -314,9 +314,8 @@ void moea_kenter(mmu_t, vm_offset_t, vm_paddr_t); void moea_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma); boolean_t moea_dev_direct_mapped(mmu_t, vm_paddr_t, vm_size_t); static void moea_sync_icache(mmu_t, pmap_t, vm_offset_t, vm_size_t); -vm_offset_t moea_dumpsys_map(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_size_t *sz); -struct pmap_md * moea_scan_md(mmu_t mmu, struct pmap_md *prev); +void moea_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t sz, void **va); +void moea_scan_init(mmu_t mmu); static mmu_method_t moea_methods[] = { MMUMETHOD(mmu_clear_modify, moea_clear_modify), @@ -363,7 +362,7 @@ static mmu_method_t moea_methods[] = { MMUMETHOD(mmu_kenter, moea_kenter), MMUMETHOD(mmu_kenter_attr, moea_kenter_attr), MMUMETHOD(mmu_dev_direct_mapped,moea_dev_direct_mapped), - MMUMETHOD(mmu_scan_md, moea_scan_md), + MMUMETHOD(mmu_scan_init, moea_scan_init), MMUMETHOD(mmu_dumpsys_map, moea_dumpsys_map), { 0, 0 } @@ -2628,100 +2627,74 @@ moea_sync_icache(mmu_t mmu, pmap_t pm, vm_offset_t va, vm_size_t sz) PMAP_UNLOCK(pm); } -vm_offset_t -moea_dumpsys_map(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_size_t *sz) +void +moea_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t sz, void **va) { - if (md->md_vaddr == ~0UL) - return (md->md_paddr + ofs); - else - return (md->md_vaddr + ofs); + + *va = (void *)pa; } -struct pmap_md * -moea_scan_md(mmu_t mmu, struct pmap_md *prev) +extern struct dump_pa dump_map[PHYS_AVAIL_SZ + 1]; + +void +moea_scan_init(mmu_t mmu) { - static struct pmap_md md; struct pvo_entry *pvo; vm_offset_t va; - - if (dumpsys_minidump) { - md.md_paddr = ~0UL; /* Minidumps use virtual addresses. */ - if (prev == NULL) { - /* 1st: kernel .data and .bss. */ - md.md_index = 1; - md.md_vaddr = trunc_page((uintptr_t)_etext); - md.md_size = round_page((uintptr_t)_end) - md.md_vaddr; - return (&md); + int i; + + if (!do_minidump) { + /* Initialize phys. segments for dumpsys(). */ + memset(&dump_map, 0, sizeof(dump_map)); + mem_regions(&pregions, &pregions_sz, ®ions, ®ions_sz); + for (i = 0; i < pregions_sz; i++) { + dump_map[i].pa_start = pregions[i].mr_start; + dump_map[i].pa_size = pregions[i].mr_size; + } + return; + } + + /* Virtual segments for minidumps: */ + memset(&dump_map, 0, sizeof(dump_map)); + + /* 1st: kernel .data and .bss. */ + dump_map[0].pa_start = trunc_page((uintptr_t)_etext); + dump_map[0].pa_size = + round_page((uintptr_t)_end) - dump_map[0].pa_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].pa_start = (vm_paddr_t)msgbufp->msg_ptr; + dump_map[1].pa_size = round_page(msgbufp->msg_size); + + /* 3rd: kernel VM. */ + va = dump_map[1].pa_start + dump_map[1].pa_size; + /* Find start of next chunk (from va). */ + while (va < virtual_end) { + /* Don't dump the buffer cache. */ + if (va >= kmi.buffer_sva && va < kmi.buffer_eva) { + va = kmi.buffer_eva; + continue; } - switch (prev->md_index) { - case 1: - /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ - md.md_index = 2; - md.md_vaddr = (vm_offset_t)msgbufp->msg_ptr; - md.md_size = round_page(msgbufp->msg_size); + pvo = moea_pvo_find_va(kernel_pmap, va & ~ADDR_POFF, NULL); + if (pvo != NULL && (pvo->pvo_pte.pte.pte_hi & PTE_VALID)) break; - case 2: - /* 3rd: kernel VM. */ - va = prev->md_vaddr + prev->md_size; - /* Find start of next chunk (from va). */ - while (va < virtual_end) { - /* Don't dump the buffer cache. */ - if (va >= kmi.buffer_sva && - va < kmi.buffer_eva) { - va = kmi.buffer_eva; - continue; - } - pvo = moea_pvo_find_va(kernel_pmap, - va & ~ADDR_POFF, NULL); - if (pvo != NULL && - (pvo->pvo_pte.pte.pte_hi & PTE_VALID)) - break; - va += PAGE_SIZE; - } - if (va < virtual_end) { - md.md_vaddr = va; - va += PAGE_SIZE; - /* Find last page in chunk. */ - while (va < virtual_end) { - /* Don't run into the buffer cache. */ - if (va == kmi.buffer_sva) - break; - pvo = moea_pvo_find_va(kernel_pmap, - va & ~ADDR_POFF, NULL); - if (pvo == NULL || - !(pvo->pvo_pte.pte.pte_hi & PTE_VALID)) - break; - va += PAGE_SIZE; - } - md.md_size = va - md.md_vaddr; + va += PAGE_SIZE; + } + if (va < virtual_end) { + dump_map[2].pa_start = va; + va += PAGE_SIZE; + /* Find last page in chunk. */ + while (va < virtual_end) { + /* Don't run into the buffer cache. */ + if (va == kmi.buffer_sva) break; - } - md.md_index = 3; - /* FALLTHROUGH */ - default: - return (NULL); - } - } else { /* minidumps */ - mem_regions(&pregions, &pregions_sz, - ®ions, ®ions_sz); - - if (prev == NULL) { - /* first physical chunk. */ - md.md_paddr = pregions[0].mr_start; - md.md_size = pregions[0].mr_size; - md.md_vaddr = ~0UL; - md.md_index = 1; - } else if (md.md_index < pregions_sz) { - md.md_paddr = pregions[md.md_index].mr_start; - md.md_size = pregions[md.md_index].mr_size; - md.md_vaddr = ~0UL; - md.md_index++; - } else { - /* There's no next physical chunk. */ - return (NULL); + pvo = moea_pvo_find_va(kernel_pmap, va & ~ADDR_POFF, + NULL); + if (pvo == NULL || + !(pvo->pvo_pte.pte.pte_hi & PTE_VALID)) + break; + va += PAGE_SIZE; } + dump_map[2].pa_size = va - dump_map[2].pa_start; } - - return (&md); } diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 9677b52..180321f 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -107,8 +107,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/conf.h> #include <sys/queue.h> #include <sys/cpuset.h> +#include <sys/kerneldump.h> #include <sys/ktr.h> #include <sys/lock.h> #include <sys/msgbuf.h> @@ -187,7 +189,6 @@ struct ofw_map { extern unsigned char _etext[]; extern unsigned char _end[]; -extern int dumpsys_minidump; extern int ofw_real_mode; /* @@ -328,9 +329,9 @@ void moea64_kenter_attr(mmu_t, vm_offset_t, vm_offset_t, vm_memattr_t ma); void moea64_kenter(mmu_t, vm_offset_t, vm_paddr_t); boolean_t moea64_dev_direct_mapped(mmu_t, vm_paddr_t, vm_size_t); static void moea64_sync_icache(mmu_t, pmap_t, vm_offset_t, vm_size_t); -vm_offset_t moea64_dumpsys_map(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_size_t *sz); -struct pmap_md * moea64_scan_md(mmu_t mmu, struct pmap_md *prev); +void moea64_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t sz, + void **va); +void moea64_scan_init(mmu_t mmu); static mmu_method_t moea64_methods[] = { MMUMETHOD(mmu_clear_modify, moea64_clear_modify), @@ -376,7 +377,7 @@ static mmu_method_t moea64_methods[] = { MMUMETHOD(mmu_kenter, moea64_kenter), MMUMETHOD(mmu_kenter_attr, moea64_kenter_attr), MMUMETHOD(mmu_dev_direct_mapped,moea64_dev_direct_mapped), - MMUMETHOD(mmu_scan_md, moea64_scan_md), + MMUMETHOD(mmu_scan_init, moea64_scan_init), MMUMETHOD(mmu_dumpsys_map, moea64_dumpsys_map), { 0, 0 } @@ -2615,97 +2616,72 @@ moea64_sync_icache(mmu_t mmu, pmap_t pm, vm_offset_t va, vm_size_t sz) PMAP_UNLOCK(pm); } -vm_offset_t -moea64_dumpsys_map(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_size_t *sz) +void +moea64_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t sz, void **va) { - if (md->md_vaddr == ~0UL) - return (md->md_paddr + ofs); - else - return (md->md_vaddr + ofs); + + *va = (void *)pa; } -struct pmap_md * -moea64_scan_md(mmu_t mmu, struct pmap_md *prev) +extern struct dump_pa dump_map[PHYS_AVAIL_SZ + 1]; + +void +moea64_scan_init(mmu_t mmu) { - static struct pmap_md md; struct pvo_entry *pvo; vm_offset_t va; - - if (dumpsys_minidump) { - md.md_paddr = ~0UL; /* Minidumps use virtual addresses. */ - if (prev == NULL) { - /* 1st: kernel .data and .bss. */ - md.md_index = 1; - md.md_vaddr = trunc_page((uintptr_t)_etext); - md.md_size = round_page((uintptr_t)_end) - md.md_vaddr; - return (&md); + int i; + + if (!do_minidump) { + /* Initialize phys. segments for dumpsys(). */ + memset(&dump_map, 0, sizeof(dump_map)); + mem_regions(&pregions, &pregions_sz, ®ions, ®ions_sz); + for (i = 0; i < pregions_sz; i++) { + dump_map[i].pa_start = pregions[i].mr_start; + dump_map[i].pa_size = pregions[i].mr_size; + } + return; + } + + /* Virtual segments for minidumps: */ + memset(&dump_map, 0, sizeof(dump_map)); + + /* 1st: kernel .data and .bss. */ + dump_map[0].pa_start = trunc_page((uintptr_t)_etext); + dump_map[0].pa_size = round_page((uintptr_t)_end) - dump_map[0].pa_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].pa_start = (vm_paddr_t)msgbufp->msg_ptr; + dump_map[1].pa_size = round_page(msgbufp->msg_size); + + /* 3rd: kernel VM. */ + va = dump_map[1].pa_start + dump_map[1].pa_size; + /* Find start of next chunk (from va). */ + while (va < virtual_end) { + /* Don't dump the buffer cache. */ + if (va >= kmi.buffer_sva && va < kmi.buffer_eva) { + va = kmi.buffer_eva; + continue; } - switch (prev->md_index) { - case 1: - /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ - md.md_index = 2; - md.md_vaddr = (vm_offset_t)msgbufp->msg_ptr; - md.md_size = round_page(msgbufp->msg_size); + pvo = moea64_pvo_find_va(kernel_pmap, va & ~ADDR_POFF); + if (pvo != NULL && (pvo->pvo_pte.lpte.pte_hi & LPTE_VALID)) break; - case 2: - /* 3rd: kernel VM. */ - va = prev->md_vaddr + prev->md_size; - /* Find start of next chunk (from va). */ - while (va < virtual_end) { - /* Don't dump the buffer cache. */ - if (va >= kmi.buffer_sva && - va < kmi.buffer_eva) { - va = kmi.buffer_eva; - continue; - } - pvo = moea64_pvo_find_va(kernel_pmap, - va & ~ADDR_POFF); - if (pvo != NULL && - (pvo->pvo_pte.lpte.pte_hi & LPTE_VALID)) - break; - va += PAGE_SIZE; - } - if (va < virtual_end) { - md.md_vaddr = va; - va += PAGE_SIZE; - /* Find last page in chunk. */ - while (va < virtual_end) { - /* Don't run into the buffer cache. */ - if (va == kmi.buffer_sva) - break; - pvo = moea64_pvo_find_va(kernel_pmap, - va & ~ADDR_POFF); - if (pvo == NULL || - !(pvo->pvo_pte.lpte.pte_hi & LPTE_VALID)) - break; - va += PAGE_SIZE; - } - md.md_size = va - md.md_vaddr; + va += PAGE_SIZE; + } + if (va < virtual_end) { + dump_map[2].pa_start = va; + va += PAGE_SIZE; + /* Find last page in chunk. */ + while (va < virtual_end) { + /* Don't run into the buffer cache. */ + if (va == kmi.buffer_sva) break; - } - md.md_index = 3; - /* FALLTHROUGH */ - default: - return (NULL); - } - } else { /* minidumps */ - if (prev == NULL) { - /* first physical chunk. */ - md.md_paddr = pregions[0].mr_start; - md.md_size = pregions[0].mr_size; - md.md_vaddr = ~0UL; - md.md_index = 1; - } else if (md.md_index < pregions_sz) { - md.md_paddr = pregions[md.md_index].mr_start; - md.md_size = pregions[md.md_index].mr_size; - md.md_vaddr = ~0UL; - md.md_index++; - } else { - /* There's no next physical chunk. */ - return (NULL); + pvo = moea64_pvo_find_va(kernel_pmap, va & ~ADDR_POFF); + if (pvo == NULL || + !(pvo->pvo_pte.lpte.pte_hi & LPTE_VALID)) + break; + va += PAGE_SIZE; } + dump_map[2].pa_size = va - dump_map[2].pa_start; } - - return (&md); } diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index 942ad12..061704f 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/conf.h> #include <sys/malloc.h> #include <sys/ktr.h> #include <sys/proc.h> @@ -59,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <sys/queue.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/kerneldump.h> #include <sys/linker.h> #include <sys/msgbuf.h> #include <sys/lock.h> @@ -100,8 +102,6 @@ __FBSDID("$FreeBSD$"); #define TODO panic("%s: not implemented", __func__); -extern int dumpsys_minidump; - extern unsigned char _etext[]; extern unsigned char _end[]; @@ -322,11 +322,11 @@ static void mmu_booke_kremove(mmu_t, vm_offset_t); static boolean_t mmu_booke_dev_direct_mapped(mmu_t, vm_paddr_t, vm_size_t); static void mmu_booke_sync_icache(mmu_t, pmap_t, vm_offset_t, vm_size_t); -static vm_offset_t mmu_booke_dumpsys_map(mmu_t, struct pmap_md *, - vm_size_t, vm_size_t *); -static void mmu_booke_dumpsys_unmap(mmu_t, struct pmap_md *, - vm_size_t, vm_offset_t); -static struct pmap_md *mmu_booke_scan_md(mmu_t, struct pmap_md *); +static void mmu_booke_dumpsys_map(mmu_t, vm_paddr_t pa, size_t, + void **); +static void mmu_booke_dumpsys_unmap(mmu_t, vm_paddr_t pa, size_t, + void *); +static void mmu_booke_scan_init(mmu_t); static mmu_method_t mmu_booke_methods[] = { /* pmap dispatcher interface */ @@ -381,7 +381,7 @@ static mmu_method_t mmu_booke_methods[] = { /* dumpsys() support */ MMUMETHOD(mmu_dumpsys_map, mmu_booke_dumpsys_map), MMUMETHOD(mmu_dumpsys_unmap, mmu_booke_dumpsys_unmap), - MMUMETHOD(mmu_scan_md, mmu_booke_scan_md), + MMUMETHOD(mmu_scan_init, mmu_booke_scan_init), { 0, 0 } }; @@ -2534,139 +2534,125 @@ mmu_booke_dev_direct_mapped(mmu_t mmu, vm_paddr_t pa, vm_size_t size) return (EFAULT); } -vm_offset_t -mmu_booke_dumpsys_map(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_size_t *sz) +void +mmu_booke_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t sz, void **va) { - vm_paddr_t pa, ppa; - vm_offset_t va; + vm_paddr_t ppa; + vm_offset_t ofs; vm_size_t gran; - /* Raw physical memory dumps don't have a virtual address. */ - if (md->md_vaddr == ~0UL) { - /* We always map a 256MB page at 256M. */ - gran = 256 * 1024 * 1024; - pa = md->md_paddr + ofs; - ppa = pa & ~(gran - 1); - ofs = pa - ppa; - va = gran; - tlb1_set_entry(va, ppa, gran, _TLB_ENTRY_IO); - if (*sz > (gran - ofs)) - *sz = gran - ofs; - return (va + ofs); - } - /* Minidumps are based on virtual memory addresses. */ - va = md->md_vaddr + ofs; - if (va >= kernstart + kernsize) { - gran = PAGE_SIZE - (va & PAGE_MASK); - if (*sz > gran) - *sz = gran; + if (do_minidump) { + *va = (void *)pa; + return; } - return (va); + + /* Raw physical memory dumps don't have a virtual address. */ + /* We always map a 256MB page at 256M. */ + gran = 256 * 1024 * 1024; + ppa = pa & ~(gran - 1); + ofs = pa - ppa; + *va = (void *)gran; + tlb1_set_entry((vm_offset_t)va, ppa, gran, _TLB_ENTRY_IO); + + if (sz > (gran - ofs)) + tlb1_set_entry((vm_offset_t)(va + gran), ppa + gran, gran, + _TLB_ENTRY_IO); } void -mmu_booke_dumpsys_unmap(mmu_t mmu, struct pmap_md *md, vm_size_t ofs, - vm_offset_t va) +mmu_booke_dumpsys_unmap(mmu_t mmu, vm_paddr_t pa, size_t sz, void *va) { + vm_paddr_t ppa; + vm_offset_t ofs; + vm_size_t gran; + + /* Minidumps are based on virtual memory addresses. */ + /* Nothing to do... */ + if (do_minidump) + return; /* Raw physical memory dumps don't have a virtual address. */ - if (md->md_vaddr == ~0UL) { + tlb1_idx--; + tlb1[tlb1_idx].mas1 = 0; + tlb1[tlb1_idx].mas2 = 0; + tlb1[tlb1_idx].mas3 = 0; + tlb1_write_entry(tlb1_idx); + + gran = 256 * 1024 * 1024; + ppa = pa & ~(gran - 1); + ofs = pa - ppa; + if (sz > (gran - ofs)) { tlb1_idx--; tlb1[tlb1_idx].mas1 = 0; tlb1[tlb1_idx].mas2 = 0; tlb1[tlb1_idx].mas3 = 0; tlb1_write_entry(tlb1_idx); - return; } - - /* Minidumps are based on virtual memory addresses. */ - /* Nothing to do... */ } -struct pmap_md * -mmu_booke_scan_md(mmu_t mmu, struct pmap_md *prev) +extern struct dump_pa dump_map[PHYS_AVAIL_SZ + 1]; + +void +mmu_booke_scan_init(mmu_t mmu) { - static struct pmap_md md; - pte_t *pte; vm_offset_t va; - - if (dumpsys_minidump) { - md.md_paddr = ~0UL; /* Minidumps use virtual addresses. */ - if (prev == NULL) { - /* 1st: kernel .data and .bss. */ - md.md_index = 1; - md.md_vaddr = trunc_page((uintptr_t)_etext); - md.md_size = round_page((uintptr_t)_end) - md.md_vaddr; - return (&md); + pte_t *pte; + int i; + + if (!do_minidump) { + /* Initialize phys. segments for dumpsys(). */ + memset(&dump_map, 0, sizeof(dump_map)); + mem_regions(&physmem_regions, &physmem_regions_sz, &availmem_regions, + &availmem_regions_sz); + for (i = 0; i < physmem_regions_sz; i++) { + dump_map[i].pa_start = physmem_regions[i].mr_start; + dump_map[i].pa_size = physmem_regions[i].mr_size; + } + return; + } + + /* Virtual segments for minidumps: */ + memset(&dump_map, 0, sizeof(dump_map)); + + /* 1st: kernel .data and .bss. */ + dump_map[0].pa_start = trunc_page((uintptr_t)_etext); + dump_map[0].pa_size = + round_page((uintptr_t)_end) - dump_map[0].pa_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].pa_start = data_start; + dump_map[1].pa_size = data_end - data_start; + + /* 3rd: kernel VM. */ + va = dump_map[1].pa_start + dump_map[1].pa_size; + /* Find start of next chunk (from va). */ + while (va < virtual_end) { + /* Don't dump the buffer cache. */ + if (va >= kmi.buffer_sva && va < kmi.buffer_eva) { + va = kmi.buffer_eva; + continue; } - switch (prev->md_index) { - case 1: - /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ - md.md_index = 2; - md.md_vaddr = data_start; - md.md_size = data_end - data_start; + pte = pte_find(mmu, kernel_pmap, va); + if (pte != NULL && PTE_ISVALID(pte)) break; - case 2: - /* 3rd: kernel VM. */ - va = prev->md_vaddr + prev->md_size; - /* Find start of next chunk (from va). */ - while (va < virtual_end) { - /* Don't dump the buffer cache. */ - if (va >= kmi.buffer_sva && - va < kmi.buffer_eva) { - va = kmi.buffer_eva; - continue; - } - pte = pte_find(mmu, kernel_pmap, va); - if (pte != NULL && PTE_ISVALID(pte)) - break; - va += PAGE_SIZE; - } - if (va < virtual_end) { - md.md_vaddr = va; - va += PAGE_SIZE; - /* Find last page in chunk. */ - while (va < virtual_end) { - /* Don't run into the buffer cache. */ - if (va == kmi.buffer_sva) - break; - pte = pte_find(mmu, kernel_pmap, va); - if (pte == NULL || !PTE_ISVALID(pte)) - break; - va += PAGE_SIZE; - } - md.md_size = va - md.md_vaddr; + va += PAGE_SIZE; + } + if (va < virtual_end) { + dump_map[2].pa_start = va; + va += PAGE_SIZE; + /* Find last page in chunk. */ + while (va < virtual_end) { + /* Don't run into the buffer cache. */ + if (va == kmi.buffer_sva) break; - } - md.md_index = 3; - /* FALLTHROUGH */ - default: - return (NULL); - } - } else { /* minidumps */ - mem_regions(&physmem_regions, &physmem_regions_sz, - &availmem_regions, &availmem_regions_sz); - - if (prev == NULL) { - /* first physical chunk. */ - md.md_paddr = physmem_regions[0].mr_start; - md.md_size = physmem_regions[0].mr_size; - md.md_vaddr = ~0UL; - md.md_index = 1; - } else if (md.md_index < physmem_regions_sz) { - md.md_paddr = physmem_regions[md.md_index].mr_start; - md.md_size = physmem_regions[md.md_index].mr_size; - md.md_vaddr = ~0UL; - md.md_index++; - } else { - /* There's no next physical chunk. */ - return (NULL); + pte = pte_find(mmu, kernel_pmap, va); + if (pte == NULL || !PTE_ISVALID(pte)) + break; + va += PAGE_SIZE; } + dump_map[2].pa_size = va - dump_map[2].pa_start; } - - return (&md); } /* diff --git a/sys/powerpc/include/dump.h b/sys/powerpc/include/dump.h new file mode 100644 index 0000000..5a9a72a --- /dev/null +++ b/sys/powerpc/include/dump.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Author: Conrad Meyer <conrad.meyer@isilon.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_DUMP_H_ +#define _MACHINE_DUMP_H_ + +#define KERNELDUMP_ARCH_VERSION KERNELDUMP_POWERPC_VERSION +#define EM_VALUE ELF_ARCH /* Defined in powerpc/include/elf.h */ +#define DUMPSYS_MD_PA_NPAIRS (PHYS_AVAIL_SZ + 1) +#define DUMPSYS_NUM_AUX_HDRS 0 + +void dumpsys_pa_init(void); +void dumpsys_unmap_chunk(vm_paddr_t, size_t, void *); + +static inline struct dump_pa * +dumpsys_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_pa_next(p)); +} + +static inline void +dumpsys_wbinv_all(void) +{ + + dumpsys_gen_wbinv_all(); +} + +static inline int +dumpsys_write_aux_headers(struct dumperinfo *di) +{ + + return (dumpsys_gen_write_aux_headers(di)); +} + +static inline int +dumpsys(struct dumperinfo *di) +{ + + return (dumpsys_generic(di)); +} + +#endif /* !_MACHINE_DUMP_H_ */ diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h index 663cd1a..9a853f6 100644 --- a/sys/powerpc/include/pmap.h +++ b/sys/powerpc/include/pmap.h @@ -74,13 +74,6 @@ #include <machine/slb.h> #include <machine/tlb.h> -struct pmap_md { - u_int md_index; - vm_paddr_t md_paddr; - vm_offset_t md_vaddr; - vm_size_t md_size; -}; - #if defined(AIM) #if !defined(NPMAPS) @@ -252,11 +245,6 @@ extern vm_offset_t msgbuf_phys; extern int pmap_bootstrapped; -extern vm_offset_t pmap_dumpsys_map(struct pmap_md *, vm_size_t, vm_size_t *); -extern void pmap_dumpsys_unmap(struct pmap_md *, vm_size_t, vm_offset_t); - -extern struct pmap_md *pmap_scan_md(struct pmap_md *); - vm_offset_t pmap_early_io_map(vm_paddr_t pa, vm_size_t size); #endif diff --git a/sys/powerpc/powerpc/dump_machdep.c b/sys/powerpc/powerpc/dump_machdep.c index 14e2f0f..573ed1c 100644 --- a/sys/powerpc/powerpc/dump_machdep.c +++ b/sys/powerpc/powerpc/dump_machdep.c @@ -27,289 +27,12 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_watchdog.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> -#include <sys/cons.h> -#include <sys/kernel.h> #include <sys/kerneldump.h> #include <sys/sysctl.h> -#ifdef SW_WATCHDOG -#include <sys/watchdog.h> -#endif -#include <vm/vm.h> -#include <vm/pmap.h> -#include <machine/elf.h> -#include <machine/md_var.h> - -CTASSERT(sizeof(struct kerneldumpheader) == 512); - -/* - * Don't touch the first SIZEOF_METADATA bytes on the dump device. This - * is to protect us from metadata and to protect metadata from us. - */ -#define SIZEOF_METADATA (64*1024) - -#define MD_ALIGN(x) (((off_t)(x) + PAGE_MASK) & ~PAGE_MASK) -#define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) - -typedef int callback_t(struct pmap_md *, int, void *); - -static struct kerneldumpheader kdh; -static off_t dumplo, fileofs; - -/* Handle buffered writes. */ -static char buffer[DEV_BSIZE]; -static size_t fragsz; - -int dumpsys_minidump = 1; -SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RD, &dumpsys_minidump, 0, - "Kernel makes compressed crash dumps"); - -static int -buf_write(struct dumperinfo *di, char *ptr, size_t sz) -{ - size_t len; - int error; - - while (sz) { - len = DEV_BSIZE - fragsz; - if (len > sz) - len = sz; - bcopy(ptr, buffer + fragsz, len); - fragsz += len; - ptr += len; - sz -= len; - if (fragsz == DEV_BSIZE) { - error = di->dumper(di->priv, buffer, 0, dumplo, - DEV_BSIZE); - if (error) - return error; - dumplo += DEV_BSIZE; - fragsz = 0; - } - } - - return (0); -} - -static int -buf_flush(struct dumperinfo *di) -{ - int error; - - if (fragsz == 0) - return (0); - - error = di->dumper(di->priv, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; - fragsz = 0; - return (error); -} - -static int -cb_dumpdata(struct pmap_md *md, int seqnr, void *arg) -{ - struct dumperinfo *di = (struct dumperinfo*)arg; - vm_offset_t va; - size_t counter, ofs, resid, sz, maxsz; - int c, error, twiddle; - - error = 0; - counter = 0; /* Update twiddle every 16MB */ - twiddle = 0; - - ofs = 0; /* Logical offset within the chunk */ - resid = md->md_size; - maxsz = min(DFLTPHYS, di->maxiosize); - - printf(" chunk %d: %lu bytes ", seqnr, (u_long)resid); - - while (resid) { - sz = min(resid, maxsz); - va = pmap_dumpsys_map(md, ofs, &sz); - counter += sz; - if (counter >> 24) { - printf("%c\b", "|/-\\"[twiddle++ & 3]); - counter &= (1<<24) - 1; - } -#ifdef SW_WATCHDOG - wdog_kern_pat(WD_LASTVAL); -#endif - error = di->dumper(di->priv, (void*)va, 0, dumplo, sz); - pmap_dumpsys_unmap(md, ofs, va); - if (error) - break; - dumplo += sz; - resid -= sz; - ofs += sz; - - /* Check for user abort. */ - c = cncheckc(); - if (c == 0x03) - return (ECANCELED); - if (c != -1) - printf("(CTRL-C to abort) "); - } - printf("... %s\n", (error) ? "fail" : "ok"); - return (error); -} - -static int -cb_dumphdr(struct pmap_md *md, int seqnr, void *arg) -{ - struct dumperinfo *di = (struct dumperinfo*)arg; - Elf_Phdr phdr; - int error; - - bzero(&phdr, sizeof(phdr)); - phdr.p_type = PT_LOAD; - phdr.p_flags = PF_R; /* XXX */ - phdr.p_offset = fileofs; - phdr.p_vaddr = md->md_vaddr; - phdr.p_paddr = md->md_paddr; - phdr.p_filesz = md->md_size; - phdr.p_memsz = md->md_size; - phdr.p_align = PAGE_SIZE; - - error = buf_write(di, (char*)&phdr, sizeof(phdr)); - fileofs += phdr.p_filesz; - return (error); -} - -static int -cb_size(struct pmap_md *md, int seqnr, void *arg) -{ - uint32_t *sz = (uint32_t*)arg; - - *sz += md->md_size; - return (0); -} - -static int -foreach_chunk(callback_t cb, void *arg) -{ - struct pmap_md *md; - int error, seqnr; - - seqnr = 0; - md = pmap_scan_md(NULL); - while (md != NULL) { - error = (*cb)(md, seqnr++, arg); - if (error) - return (-error); - md = pmap_scan_md(md); - } - return (seqnr); -} - -int -dumpsys(struct dumperinfo *di) -{ - Elf_Ehdr ehdr; - uint32_t dumpsize; - off_t hdrgap; - size_t hdrsz; - int error; - - bzero(&ehdr, 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] = ELF_TARG_CLASS; -#if BYTE_ORDER == LITTLE_ENDIAN - ehdr.e_ident[EI_DATA] = ELFDATA2LSB; -#else - ehdr.e_ident[EI_DATA] = ELFDATA2MSB; -#endif - ehdr.e_ident[EI_VERSION] = EV_CURRENT; - ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE; /* XXX big picture? */ - ehdr.e_type = ET_CORE; - ehdr.e_machine = ELF_ARCH; /* Defined in powerpc/include/elf.h */ - ehdr.e_phoff = sizeof(ehdr); - ehdr.e_ehsize = sizeof(ehdr); - ehdr.e_phentsize = sizeof(Elf_Phdr); - ehdr.e_shentsize = sizeof(Elf_Shdr); - - /* Calculate dump size. */ - dumpsize = 0L; - ehdr.e_phnum = foreach_chunk(cb_size, &dumpsize); - hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; - fileofs = MD_ALIGN(hdrsz); - dumpsize += fileofs; - hdrgap = fileofs - DEV_ALIGN(hdrsz); - - /* For block devices, determine the dump offset on the device. */ - if (di->mediasize > 0) { - if (di->mediasize < - SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; - } else - dumplo = 0; - - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_POWERPC_VERSION, dumpsize, - di->blocksize); - - printf("Dumping %u MB (%d chunks)\n", dumpsize >> 20, - ehdr.e_phnum); - - /* Dump leader */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); - if (error) - goto fail; - dumplo += sizeof(kdh); - - /* Dump ELF header */ - error = buf_write(di, (char*)&ehdr, sizeof(ehdr)); - if (error) - goto fail; - - /* Dump program headers */ - error = foreach_chunk(cb_dumphdr, di); - if (error < 0) - goto fail; - buf_flush(di); - - /* - * All headers are written using blocked I/O, so we know the - * current offset is (still) block aligned. Skip the alignement - * in the file to have the segment contents aligned at page - * boundary. We cannot use MD_ALIGN on dumplo, because we don't - * care and may very well be unaligned within the dump device. - */ - dumplo += hdrgap; - - /* Dump memory chunks (updates dumplo) */ - error = foreach_chunk(cb_dumpdata, di); - if (error < 0) - goto fail; - - /* Dump trailer */ - error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); - if (error) - goto fail; - - /* Signal completion, signoff and exit stage left. */ - dump_write(di, NULL, 0, 0, 0); - printf("\nDump complete\n"); - return (0); - - fail: - if (error < 0) - error = -error; - if (error == ECANCELED) - printf("\nDump aborted\n"); - else if (error == ENOSPC) - printf("\nDump failed. Partition too small.\n"); - else - printf("\n** DUMP FAILED (ERROR %d) **\n", error); - return (error); -} +int do_minidump = 1; +SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RWTUN, &do_minidump, 0, + "Enable mini crash dumps"); diff --git a/sys/powerpc/powerpc/mmu_if.m b/sys/powerpc/powerpc/mmu_if.m index 5c44b71..caf0fb0 100644 --- a/sys/powerpc/powerpc/mmu_if.m +++ b/sys/powerpc/powerpc/mmu_if.m @@ -107,11 +107,6 @@ CODE { return; } - static struct pmap_md *mmu_null_scan_md(mmu_t mmu, struct pmap_md *p) - { - return (NULL); - } - static void *mmu_null_mapdev_attr(mmu_t mmu, vm_offset_t pa, vm_size_t size, vm_memattr_t ma) { @@ -905,46 +900,36 @@ METHOD void sync_icache { /** * @brief Create temporary memory mapping for use by dumpsys(). * - * @param _md The memory chunk in which the mapping lies. - * @param _ofs The offset within the chunk of the mapping. + * @param _pa The physical page to map. * @param _sz The requested size of the mapping. - * - * @retval vm_offset_t The virtual address of the mapping. - * - * The sz argument is modified to reflect the actual size of the - * mapping. + * @param _va The virtual address of the mapping. */ -METHOD vm_offset_t dumpsys_map { +METHOD void dumpsys_map { mmu_t _mmu; - struct pmap_md *_md; - vm_size_t _ofs; - vm_size_t *_sz; + vm_paddr_t _pa; + size_t _sz; + void **_va; }; /** * @brief Remove temporary dumpsys() mapping. * - * @param _md The memory chunk in which the mapping lies. - * @param _ofs The offset within the chunk of the mapping. + * @param _pa The physical page to map. + * @param _sz The requested size of the mapping. * @param _va The virtual address of the mapping. */ METHOD void dumpsys_unmap { mmu_t _mmu; - struct pmap_md *_md; - vm_size_t _ofs; - vm_offset_t _va; + vm_paddr_t _pa; + size_t _sz; + void *_va; }; /** - * @brief Scan/iterate memory chunks. - * - * @param _prev The previously returned chunk or NULL. - * - * @retval The next (or first when _prev is NULL) chunk. + * @brief Initialize memory chunks for dumpsys. */ -METHOD struct pmap_md * scan_md { +METHOD void scan_init { mmu_t _mmu; - struct pmap_md *_prev; -} DEFAULT mmu_null_scan_md; +}; diff --git a/sys/powerpc/powerpc/pmap_dispatch.c b/sys/powerpc/powerpc/pmap_dispatch.c index 7f3f913..a27eb82 100644 --- a/sys/powerpc/powerpc/pmap_dispatch.c +++ b/sys/powerpc/powerpc/pmap_dispatch.c @@ -43,7 +43,9 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> +#include <sys/conf.h> #include <sys/lock.h> +#include <sys/kerneldump.h> #include <sys/ktr.h> #include <sys/mutex.h> #include <sys/systm.h> @@ -51,6 +53,8 @@ __FBSDID("$FreeBSD$"); #include <vm/vm.h> #include <vm/vm_page.h> +#include <machine/dump.h> +#include <machine/md_var.h> #include <machine/mmuvar.h> #include <machine/smp.h> @@ -522,28 +526,28 @@ pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz) return (MMU_SYNC_ICACHE(mmu_obj, pm, va, sz)); } -vm_offset_t -pmap_dumpsys_map(struct pmap_md *md, vm_size_t ofs, vm_size_t *sz) +void +dumpsys_map_chunk(vm_paddr_t pa, size_t sz, void **va) { - CTR4(KTR_PMAP, "%s(%p, %#x, %#x)", __func__, md, ofs, *sz); - return (MMU_DUMPSYS_MAP(mmu_obj, md, ofs, sz)); + CTR4(KTR_PMAP, "%s(%#jx, %#zx, %p)", __func__, (uintmax_t)pa, sz, va); + return (MMU_DUMPSYS_MAP(mmu_obj, pa, sz, va)); } void -pmap_dumpsys_unmap(struct pmap_md *md, vm_size_t ofs, vm_offset_t va) +dumpsys_unmap_chunk(vm_paddr_t pa, size_t sz, void *va) { - CTR4(KTR_PMAP, "%s(%p, %#x, %#x)", __func__, md, ofs, va); - return (MMU_DUMPSYS_UNMAP(mmu_obj, md, ofs, va)); + CTR4(KTR_PMAP, "%s(%#jx, %#zx, %p)", __func__, (uintmax_t)pa, sz, va); + return (MMU_DUMPSYS_UNMAP(mmu_obj, pa, sz, va)); } -struct pmap_md * -pmap_scan_md(struct pmap_md *prev) +void +dumpsys_pa_init(void) { - CTR2(KTR_PMAP, "%s(%p)", __func__, prev); - return (MMU_SCAN_MD(mmu_obj, prev)); + CTR1(KTR_PMAP, "%s()", __func__); + return (MMU_SCAN_INIT(mmu_obj)); } /* |