Index: sys/amd64/include/dump.h =================================================================== --- /dev/null +++ sys/amd64/include/dump.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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_VERSION KERNELDUMP_AMD64_VERSION +#define EM_VALUE EM_X86_64 +/* 20 phys_avail entry pairs correspond to 10 md_pa's */ +#define DUMPSYS_MD_PA_NPAIRS 10 +#define DUMPSYS_NUM_AUX_HDRS 0 + +static inline void +dumpsys_md_pa_init(void) +{ + + dumpsys_gen_md_pa_init(); +} + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_md_pa_next(p)); +} + +static inline void +dumpsys_wbinv_all(void) +{ + + dumpsys_gen_wbinv_all(); +} + +static inline void +dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va) +{ + + dumpsys_gen_unmap_chunk(pa, s, va); +} + +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_ */ Index: sys/arm/arm/dump_machdep.c =================================================================== --- sys/arm/arm/dump_machdep.c +++ sys/arm/arm/dump_machdep.c @@ -42,136 +42,19 @@ #endif #include #include +#include #include #include #include #include -CTASSERT(sizeof(struct kerneldumpheader) == 512); - int do_minidump = 1; SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RWTUN, &do_minidump, 0, "Enable mini crash dumps"); -/* - * 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)) -extern struct pcb dumppcb; - -struct md_pa { - vm_paddr_t md_start; - vm_paddr_t md_size; -}; - -typedef int callback_t(struct md_pa *, int, void *); - -static struct kerneldumpheader kdh; -static off_t dumplo, fileofs; - -/* Handle buffered writes. */ -static char buffer[DEV_BSIZE]; -static size_t fragsz; - -/* XXX: I suppose 20 should be enough. */ -static struct md_pa dump_map[20]; - -static void -md_pa_init(void) +void +dumpsys_wbinv_all(void) { - int n, idx; - - bzero(dump_map, sizeof(dump_map)); - for (n = 0; n < sizeof(dump_map) / sizeof(dump_map[0]); n++) { - idx = n * 2; - if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0) - break; - dump_map[n].md_start = dump_avail[idx]; - dump_map[n].md_size = dump_avail[idx + 1] - dump_avail[idx]; - } -} - -static struct md_pa * -md_pa_first(void) -{ - - return (&dump_map[0]); -} - -static struct md_pa * -md_pa_next(struct md_pa *mdp) -{ - - mdp++; - if (mdp->md_size == 0) - mdp = NULL; - return (mdp); -} - -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 = dump_write(di, 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 = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; - fragsz = 0; - return (error); -} - -extern vm_offset_t kernel_l1kva; -extern char *pouet2; - -static int -cb_dumpdata(struct md_pa *mdp, int seqnr, void *arg) -{ - struct dumperinfo *di = (struct dumperinfo*)arg; - vm_paddr_t pa; - uint32_t pgs; - size_t counter, sz, chunk; - int c, error; - - error = 0; /* catch case in which chunk size is 0 */ - counter = 0; - pgs = mdp->md_size / PAGE_SIZE; - pa = mdp->md_start; - - printf(" chunk %d: %dMB (%d pages)", seqnr, pgs * PAGE_SIZE / ( - 1024*1024), pgs); /* * Make sure we write coherent data. Note that in the SMP case this @@ -184,72 +67,25 @@ #ifdef __XSCALE__ xscale_cache_clean_minidata(); #endif - while (pgs) { - chunk = pgs; - if (chunk > MAXDUMPPGS) - chunk = MAXDUMPPGS; - sz = chunk << PAGE_SHIFT; - counter += sz; - if (counter >> 24) { - printf(" %d", pgs * PAGE_SIZE); - counter &= (1<<24) - 1; - } - if (pa == (pa & L1_ADDR_BITS)) { - pmap_kenter_section(0, pa & L1_ADDR_BITS, 0); - cpu_tlb_flushID_SE(0); - cpu_cpwait(); - } -#ifdef SW_WATCHDOG - wdog_kern_pat(WD_LASTVAL); -#endif - error = dump_write(di, - (void *)(pa - (pa & L1_ADDR_BITS)),0, dumplo, sz); - if (error) - break; - dumplo += sz; - pgs -= chunk; - pa += 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 md_pa *mdp, int seqnr, void *arg) +void +dumpsys_map_chunk(vm_paddr_t pa, size_t chunk __unused, void **va) { - struct dumperinfo *di = (struct dumperinfo*)arg; - Elf_Phdr phdr; - uint64_t size; - int error; - - size = mdp->md_size; - bzero(&phdr, sizeof(phdr)); - phdr.p_type = PT_LOAD; - phdr.p_flags = PF_R; /* XXX */ - phdr.p_offset = fileofs; - phdr.p_vaddr = mdp->md_start; - phdr.p_paddr = mdp->md_start; - phdr.p_filesz = size; - phdr.p_memsz = size; - phdr.p_align = PAGE_SIZE; - error = buf_write(di, (char*)&phdr, sizeof(phdr)); - fileofs += phdr.p_filesz; - return (error); + if (pa == (pa & L1_ADDR_BITS)) { + pmap_kenter_section(0, pa & L1_ADDR_BITS, 0); + cpu_tlb_flushID_SE(0); + cpu_cpwait(); + } + *va = (void *)(pa - (pa & L1_ADDR_BITS)); } /* * Add a header to be used by libkvm to get the va to pa delta */ -static int -dump_os_header(struct dumperinfo *di) +int +dumpsys_write_aux_headers(struct dumperinfo *di) { Elf_Phdr phdr; int error; @@ -264,144 +100,6 @@ phdr.p_memsz = 0; phdr.p_align = PAGE_SIZE; - error = buf_write(di, (char*)&phdr, sizeof(phdr)); - return (error); -} - -static int -cb_size(struct md_pa *mdp, int seqnr, void *arg) -{ - uint32_t *sz = (uint32_t*)arg; - - *sz += (uint32_t)mdp->md_size; - return (0); -} - -static int -foreach_chunk(callback_t cb, void *arg) -{ - struct md_pa *mdp; - int error, seqnr; - - seqnr = 0; - mdp = md_pa_first(); - while (mdp != NULL) { - error = (*cb)(mdp, seqnr++, arg); - if (error) - return (-error); - mdp = md_pa_next(mdp); - } - return (seqnr); -} - -int -dumpsys(struct dumperinfo *di) -{ - Elf_Ehdr ehdr; - uint32_t dumpsize; - off_t hdrgap; - size_t hdrsz; - int error; - - if (do_minidump) - return (minidumpsys(di)); - - 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_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 = EM_ARM; - ehdr.e_phoff = sizeof(ehdr); - ehdr.e_flags = 0; - ehdr.e_ehsize = sizeof(ehdr); - ehdr.e_phentsize = sizeof(Elf_Phdr); - ehdr.e_shentsize = sizeof(Elf_Shdr); - - md_pa_init(); - - /* Calculate dump size. */ - dumpsize = 0L; - ehdr.e_phnum = foreach_chunk(cb_size, &dumpsize) + 1; - hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; - fileofs = MD_ALIGN(hdrsz); - dumpsize += fileofs; - hdrgap = fileofs - DEV_ALIGN(hdrsz); - - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; - - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize, di->blocksize); - - printf("Dumping %llu MB (%d chunks)\n", (long long)dumpsize >> 20, - ehdr.e_phnum - 1); - - /* 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) - error = dump_os_header(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); + error = dumpsys_buf_write(di, (char*)&phdr, sizeof(phdr)); return (error); } Index: sys/arm/include/dump.h =================================================================== --- /dev/null +++ sys/arm/include/dump.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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_VERSION KERNELDUMP_ARM_VERSION +#define EM_VALUE EM_ARM +/* XXX: I suppose 20 should be enough. */ +#define DUMPSYS_MD_PA_NPAIRS 20 +#define DUMPSYS_NUM_AUX_HDRS 1 + +void dumpsys_wbinv_all(void); +int dumpsys_write_aux_headers(struct dumperinfo *di); + +static inline void +dumpsys_md_pa_init(void) +{ + + dumpsys_gen_md_pa_init(); +} + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_md_pa_next(p)); +} + +static inline void +dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va) +{ + + dumpsys_gen_unmap_chunk(pa, s, va); +} + +static inline int +dumpsys(struct dumperinfo *di) +{ + + return (dumpsys_generic(di)); +} + +#endif /* !_MACHINE_DUMP_H_ */ Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -2938,6 +2938,7 @@ kern/kern_context.c standard kern/kern_descrip.c standard kern/kern_dtrace.c optional kdtrace_hooks +kern/kern_dump.c standard kern/kern_environment.c standard kern/kern_et.c standard kern/kern_event.c standard Index: sys/i386/include/dump.h =================================================================== --- /dev/null +++ sys/i386/include/dump.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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_VERSION KERNELDUMP_I386_VERSION +#define EM_VALUE EM_386 +/* 20 phys_avail entry pairs correspond to 10 md_pa's */ +#define DUMPSYS_MD_PA_NPAIRS 10 +#define DUMPSYS_NUM_AUX_HDRS 0 + +static inline void +dumpsys_md_pa_init(void) +{ + + dumpsys_gen_md_pa_init(); +} + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_md_pa_next(p)); +} + +static inline void +dumpsys_wbinv_all(void) +{ + + dumpsys_gen_wbinv_all(); +} + +static inline void +dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va) +{ + + dumpsys_gen_unmap_chunk(pa, s, va); +} + +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_ */ Index: sys/kern/kern_dump.c =================================================================== --- /dev/null +++ sys/kern/kern_dump.c @@ -0,0 +1,398 @@ +/*- + * Copyright (c) 2002 Marcel Moolenaar + * 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 ``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 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_watchdog.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef SW_WATCHDOG +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +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)) + +off_t dumplo; + +/* Handle buffered writes. */ +static char buffer[DEV_BSIZE]; +static size_t fragsz; + +struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; + +void +dumpsys_gen_md_pa_init(void) +{ +#if !defined(__sparc__) && !defined(__powerpc__) + int n, idx; + + bzero(dump_map, sizeof(dump_map)); + for (n = 0; n < sizeof(dump_map) / sizeof(dump_map[0]); n++) { + idx = n * 2; + if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0) + break; + dump_map[n].md_start = dump_avail[idx]; + dump_map[n].md_size = dump_avail[idx + 1] - dump_avail[idx]; + } +#endif +} + +struct dump_pa * +dumpsys_gen_md_pa_next(struct dump_pa *mdp) +{ + + if (mdp == NULL) + return (&dump_map[0]); + + mdp++; + if (mdp->md_size == 0) + mdp = NULL; + return (mdp); +} + +void +dumpsys_gen_wbinv_all(void) +{ + + /* nop */; +} + +void +dumpsys_gen_unmap_chunk(vm_paddr_t pa __unused, size_t chunk __unused, + void *va __unused) +{ + + /* nop */; +} + +int +dumpsys_gen_write_aux_headers(struct dumperinfo *di) +{ + + /* nop */ + return (0); +} + +int +dumpsys_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 = dump_write(di, buffer, 0, dumplo, + DEV_BSIZE); + if (error) + return error; + dumplo += DEV_BSIZE; + fragsz = 0; + } + } + + return (0); +} + +int +dumpsys_buf_flush(struct dumperinfo *di) +{ + int error; + + if (fragsz == 0) + return (0); + + error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); + dumplo += DEV_BSIZE; + fragsz = 0; + return (error); +} + +CTASSERT(PAGE_SHIFT < 20); +#define PG2MB(pgs) ((pgs + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT)) + +int +dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg) +{ + struct dumperinfo *di = (struct dumperinfo*)arg; + vm_paddr_t pa; + void *va; + uint64_t pgs; + size_t counter, sz, chunk; + int c, error, twiddle; + u_int maxdumppgs; + + error = 0; /* catch case in which chunk size is 0 */ + counter = 0; /* Update twiddle every 16MB */ + twiddle = 0; + va = 0; + pgs = mdp->md_size / PAGE_SIZE; + pa = mdp->md_start; + maxdumppgs = min(di->maxiosize / PAGE_SIZE, MAXDUMPPGS); + if (maxdumppgs == 0) /* seatbelt */ + maxdumppgs = 1; + + printf(" chunk %d: %juMB (%ju pages)", seqnr, (uintmax_t)PG2MB(pgs), + (uintmax_t)pgs); + + dumpsys_wbinv_all(); + while (pgs) { + chunk = pgs; + if (chunk > maxdumppgs) + chunk = maxdumppgs; + sz = chunk << PAGE_SHIFT; + counter += sz; + if (counter >> 24) { + printf(" %ju", (uintmax_t)PG2MB(pgs)); + counter &= (1<<24) - 1; + } + + dumpsys_map_chunk(pa, chunk, &va); +#ifdef SW_WATCHDOG + wdog_kern_pat(WD_LASTVAL); +#endif + + error = dump_write(di, va, 0, dumplo, sz); + dumpsys_unmap_chunk(pa, chunk, va); + if (error) + break; + dumplo += sz; + pgs -= chunk; + pa += 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); +} + +int +dumpsys_foreach_chunk(dumpsys_callback_t cb, void *arg) +{ + struct dump_pa *mdp; + int error, seqnr; + + seqnr = 0; + mdp = dumpsys_md_pa_next(NULL); + while (mdp != NULL) { + error = (*cb)(mdp, seqnr++, arg); + if (error) + return (-error); + mdp = dumpsys_md_pa_next(mdp); + } + return (seqnr); +} + +static off_t fileofs; + +static int +cb_dumphdr(struct dump_pa *mdp, int seqnr, void *arg) +{ + struct dumperinfo *di = (struct dumperinfo*)arg; + Elf_Phdr phdr; + uint64_t size; + int error; + + size = mdp->md_size; + bzero(&phdr, sizeof(phdr)); + phdr.p_type = PT_LOAD; + phdr.p_flags = PF_R; /* XXX */ + phdr.p_offset = fileofs; +#ifdef __powerpc__ + phdr.p_vaddr = (do_minidump? mdp->md_start : ~0L); + phdr.p_paddr = (do_minidump? ~0L : mdp->md_start); +#else + phdr.p_vaddr = mdp->md_start; + phdr.p_paddr = mdp->md_start; +#endif + phdr.p_filesz = size; + phdr.p_memsz = size; + phdr.p_align = PAGE_SIZE; + + error = dumpsys_buf_write(di, (char*)&phdr, sizeof(phdr)); + fileofs += phdr.p_filesz; + return (error); +} + +static int +cb_size(struct dump_pa *mdp, int seqnr, void *arg) +{ + uint64_t *sz = (uint64_t*)arg; + + *sz += (uint64_t)mdp->md_size; + return (0); +} + +int +dumpsys_generic(struct dumperinfo *di) +{ + struct kerneldumpheader kdh; + Elf_Ehdr ehdr; + uint64_t dumpsize; + off_t hdrgap; + size_t hdrsz; + int error; + +#ifndef __powerpc__ + if (do_minidump) + return (minidumpsys(di)); +#endif + 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_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 = EM_VALUE; + ehdr.e_phoff = sizeof(ehdr); + ehdr.e_flags = 0; + ehdr.e_ehsize = sizeof(ehdr); + ehdr.e_phentsize = sizeof(Elf_Phdr); + ehdr.e_shentsize = sizeof(Elf_Shdr); + + dumpsys_md_pa_init(); + + /* Calculate dump size. */ + dumpsize = 0L; + ehdr.e_phnum = dumpsys_foreach_chunk(cb_size, &dumpsize) + + DUMPSYS_NUM_AUX_HDRS; + hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; + fileofs = MD_ALIGN(hdrsz); + dumpsize += fileofs; + hdrgap = fileofs - DEV_ALIGN(hdrsz); + + /* Determine dump offset on device. */ + if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { + error = ENOSPC; + goto fail; + } + dumplo = di->mediaoffset + di->mediasize - dumpsize; + dumplo -= sizeof(kdh) * 2; + + mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_VERSION, dumpsize, + di->blocksize); + + printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, + ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); + + /* Dump leader */ + error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); + if (error) + goto fail; + dumplo += sizeof(kdh); + + /* Dump ELF header */ + error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr)); + if (error) + goto fail; + + /* Dump program headers */ + error = dumpsys_foreach_chunk(cb_dumphdr, di); + if (error < 0) + goto fail; + error = dumpsys_write_aux_headers(di); + if (error < 0) + goto fail; + dumpsys_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 = dumpsys_foreach_chunk(dumpsys_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); +} Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -73,6 +73,7 @@ #include #include +#include #include #include Index: sys/mips/include/dump.h =================================================================== --- /dev/null +++ sys/mips/include/dump.h @@ -0,0 +1,76 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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_VERSION KERNELDUMP_MIPS_VERSION +#define EM_VALUE EM_MIPS +/* XXX: I suppose 20 should be enough. */ +#define DUMPSYS_MD_PA_NPAIRS 20 +#define DUMPSYS_NUM_AUX_HDRS 0 + +void dumpsys_wbinv_all(void); + +static inline void +dumpsys_md_pa_init(void) +{ + + dumpsys_gen_md_pa_init(); +} + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_md_pa_next(p)); +} + +static inline void +dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va) +{ + + dumpsys_gen_unmap_chunk(pa, s, va); +} + +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_ */ Index: sys/mips/include/md_var.h =================================================================== --- sys/mips/include/md_var.h +++ sys/mips/include/md_var.h @@ -80,4 +80,5 @@ void dump_add_page(vm_paddr_t); void dump_drop_page(vm_paddr_t); int minidumpsys(struct dumperinfo *); + #endif /* !_MACHINE_MD_VAR_H_ */ Index: sys/mips/mips/dump_machdep.c =================================================================== --- sys/mips/mips/dump_machdep.c +++ sys/mips/mips/dump_machdep.c @@ -27,342 +27,31 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_watchdog.h" - #include #include #include -#include -#include -#include -#include #include -#ifdef SW_WATCHDOG -#include -#endif -#include -#include -#include -#include -#include -#include +#include -CTASSERT(sizeof(struct kerneldumpheader) == 512); +#include +#include int do_minidump = 1; SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RWTUN, &do_minidump, 0, "Enable mini crash dumps"); -/* - * 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)) -extern struct pcb dumppcb; - -struct md_pa { - vm_paddr_t md_start; - vm_paddr_t md_size; -}; - -typedef int callback_t(struct md_pa *, int, void *); - -static struct kerneldumpheader kdh; -static off_t dumplo, fileofs; - -/* Handle buffered writes. */ -static char buffer[DEV_BSIZE]; -static size_t fragsz; - -/* XXX: I suppose 20 should be enough. */ -static struct md_pa dump_map[20]; - -static void -md_pa_init(void) -{ - int n, idx; - - bzero(dump_map, sizeof(dump_map)); - for (n = 0; n < sizeof(dump_map) / sizeof(dump_map[0]); n++) { - idx = n * 2; - if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0) - break; - dump_map[n].md_start = dump_avail[idx]; - dump_map[n].md_size = dump_avail[idx + 1] - dump_avail[idx]; - } -} - -static struct md_pa * -md_pa_first(void) -{ - - return (&dump_map[0]); -} - -static struct md_pa * -md_pa_next(struct md_pa *mdp) -{ - - mdp++; - if (mdp->md_size == 0) - mdp = NULL; - return (mdp); -} - -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 = dump_write(di, 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 = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; - fragsz = 0; - return (error); -} - -extern vm_offset_t kernel_l1kva; -extern char *pouet2; - -static int -cb_dumpdata(struct md_pa *mdp, int seqnr, void *arg) +void +dumpsys_wbinv_all(void) { - struct dumperinfo *di = (struct dumperinfo*)arg; - vm_paddr_t pa; - uint32_t pgs; - size_t counter, sz, chunk; - int c, error; - - error = 0; /* catch case in which chunk size is 0 */ - counter = 0; - pgs = mdp->md_size / PAGE_SIZE; - pa = mdp->md_start; - - printf(" chunk %d: %dMB (%d pages)", seqnr, pgs * PAGE_SIZE / ( - 1024*1024), pgs); /* Make sure we write coherent datas. */ mips_dcache_wbinv_all(); - while (pgs) { - chunk = pgs; - if (chunk > MAXDUMPPGS) - chunk = MAXDUMPPGS; - sz = chunk << PAGE_SHIFT; - counter += sz; - if (counter >> 24) { - printf(" %d", pgs * PAGE_SIZE); - counter &= (1<<24) - 1; - } - -#ifdef SW_WATCHDOG - wdog_kern_pat(WD_LASTVAL); -#endif - error = dump_write(di, (void *)(intptr_t)(pa),0, dumplo, sz); /* XXX fix PA */ - if (error) - break; - dumplo += sz; - pgs -= chunk; - pa += 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 md_pa *mdp, int seqnr, void *arg) -{ - struct dumperinfo *di = (struct dumperinfo*)arg; - Elf_Phdr phdr; - uint64_t size; - int error; - - size = mdp->md_size; - bzero(&phdr, sizeof(phdr)); - phdr.p_type = PT_LOAD; - phdr.p_flags = PF_R; /* XXX */ - phdr.p_offset = fileofs; - phdr.p_vaddr = mdp->md_start; - phdr.p_paddr = mdp->md_start; - phdr.p_filesz = size; - phdr.p_memsz = 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 md_pa *mdp, int seqnr, void *arg) -{ - uint32_t *sz = (uint32_t*)arg; - - *sz += (uint32_t)mdp->md_size; - return (0); -} - -static int -foreach_chunk(callback_t cb, void *arg) -{ - struct md_pa *mdp; - int error, seqnr; - - seqnr = 0; - mdp = md_pa_first(); - while (mdp != NULL) { - error = (*cb)(mdp, seqnr++, arg); - if (error) - return (-error); - mdp = md_pa_next(mdp); - } - return (seqnr); } -int -dumpsys(struct dumperinfo *di) +void +dumpsys_map_chunk(vm_paddr_t pa, size_t chunk __unused, void **va) { - Elf_Ehdr ehdr; - uint32_t dumpsize; - off_t hdrgap; - size_t hdrsz; - int error; - - if (do_minidump) - return (minidumpsys(di)); - - 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_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 = EM_MIPS; - ehdr.e_phoff = sizeof(ehdr); - ehdr.e_flags = 0; - ehdr.e_ehsize = sizeof(ehdr); - ehdr.e_phentsize = sizeof(Elf_Phdr); - ehdr.e_shentsize = sizeof(Elf_Shdr); - - md_pa_init(); - - /* 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); - - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; - - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_MIPS_VERSION, dumpsize, di->blocksize); - - printf("Dumping %llu MB (%d chunks)\n", (long long)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); + /* XXX fix PA */ + *va = (void*)(intptr_t)pa; } Index: sys/powerpc/aim/mmu_oea.c =================================================================== --- sys/powerpc/aim/mmu_oea.c +++ sys/powerpc/aim/mmu_oea.c @@ -106,8 +106,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -163,8 +165,6 @@ extern unsigned char _etext[]; extern unsigned char _end[]; -extern int dumpsys_minidump; - /* * Map of physical memory regions. */ @@ -314,9 +314,8 @@ 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 @@ 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,73 @@ 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].md_start = pregions[i].mr_start; + dump_map[i].md_size = pregions[i].mr_size; } - 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); + return; + } + + /* Virtual segments for minidumps: */ + memset(&dump_map, 0, sizeof(dump_map)); + + /* 1st: kernel .data and .bss. */ + dump_map[0].md_start = trunc_page((uintptr_t)_etext); + dump_map[0].md_size = round_page((uintptr_t)_end) - dump_map[0].md_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].md_start = (vm_paddr_t)msgbufp->msg_ptr; + dump_map[1].md_size = round_page(msgbufp->msg_size); + + /* 3rd: kernel VM. */ + va = dump_map[1].md_start + dump_map[1].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; - 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].md_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].md_size = va - dump_map[2].md_start; } - - return (&md); } Index: sys/powerpc/aim/mmu_oea64.c =================================================================== --- sys/powerpc/aim/mmu_oea64.c +++ sys/powerpc/aim/mmu_oea64.c @@ -107,8 +107,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -187,8 +189,6 @@ extern unsigned char _etext[]; extern unsigned char _end[]; -extern int dumpsys_minidump; - /* * Map of physical memory regions. */ @@ -327,9 +327,9 @@ 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), @@ -375,7 +375,7 @@ 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 } @@ -2612,97 +2612,72 @@ 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].md_start = pregions[i].mr_start; + dump_map[i].md_size = pregions[i].mr_size; } - 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); + return; + } + + /* Virtual segments for minidumps: */ + memset(&dump_map, 0, sizeof(dump_map)); + + /* 1st: kernel .data and .bss. */ + dump_map[0].md_start = trunc_page((uintptr_t)_etext); + dump_map[0].md_size = round_page((uintptr_t)_end) - dump_map[0].md_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].md_start = (vm_paddr_t)msgbufp->msg_ptr; + dump_map[1].md_size = round_page(msgbufp->msg_size); + + /* 3rd: kernel VM. */ + va = dump_map[1].md_start + dump_map[1].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; - 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].md_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].md_size = va - dump_map[2].md_start; } - - return (&md); } Index: sys/powerpc/booke/pmap.c =================================================================== --- sys/powerpc/booke/pmap.c +++ sys/powerpc/booke/pmap.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -100,8 +102,6 @@ #define TODO panic("%s: not implemented", __func__); -extern int dumpsys_minidump; - extern unsigned char _etext[]; extern unsigned char _end[]; @@ -322,11 +322,11 @@ 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 @@ /* 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,124 @@ 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].md_start = physmem_regions[i].mr_start; + dump_map[i].md_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].md_start = trunc_page((uintptr_t)_etext); + dump_map[0].md_size = round_page((uintptr_t)_end) - dump_map[0].md_start; + + /* 2nd: msgbuf and tables (see pmap_bootstrap()). */ + dump_map[1].md_start = data_start; + dump_map[1].md_size = data_end - data_start; + + /* 3rd: kernel VM. */ + va = dump_map[1].md_start + dump_map[1].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; } - 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].md_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].md_size = va - dump_map[2].md_start; } - - return (&md); } /* Index: sys/powerpc/include/dump.h =================================================================== --- /dev/null +++ sys/powerpc/include/dump.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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_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_md_pa_init(void); +void dumpsys_unmap_chunk(vm_paddr_t, size_t, void *); + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return dumpsys_gen_md_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_ */ Index: sys/powerpc/include/pmap.h =================================================================== --- sys/powerpc/include/pmap.h +++ sys/powerpc/include/pmap.h @@ -74,13 +74,6 @@ #include #include -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 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 Index: sys/powerpc/powerpc/dump_machdep.c =================================================================== --- sys/powerpc/powerpc/dump_machdep.c +++ sys/powerpc/powerpc/dump_machdep.c @@ -27,289 +27,12 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_watchdog.h" - #include #include #include -#include -#include #include #include -#ifdef SW_WATCHDOG -#include -#endif -#include -#include -#include -#include - -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"); Index: sys/powerpc/powerpc/mmu_if.m =================================================================== --- sys/powerpc/powerpc/mmu_if.m +++ sys/powerpc/powerpc/mmu_if.m @@ -107,11 +107,6 @@ 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 @@ /** * @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; +}; Index: sys/powerpc/powerpc/pmap_dispatch.c =================================================================== --- sys/powerpc/powerpc/pmap_dispatch.c +++ sys/powerpc/powerpc/pmap_dispatch.c @@ -43,7 +43,9 @@ #include #include +#include #include +#include #include #include #include @@ -51,6 +53,8 @@ #include #include +#include +#include #include #include @@ -522,28 +526,28 @@ 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_md_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)); } /* Index: sys/sparc64/include/dump.h =================================================================== --- /dev/null +++ sys/sparc64/include/dump.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * Copyright (c) 2014 Conrad Meyer + * 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 DUMPSYS_MD_PA_NPAIRS 128 +#define DUMPSYS_NUM_AUX_HDRS 0 +/* These are just dummy values: */ +#define KERNELDUMP_VERSION 0 +#define EM_VALUE 0 + +void dumpsys_md_pa_init(void); +int dumpsys(struct dumperinfo *); + +static inline struct dump_pa * +dumpsys_md_pa_next(struct dump_pa *p) +{ + + return (dumpsys_gen_md_pa_next(p)); +} + +static inline void +dumpsys_wbinv_all(void) +{ + + dumpsys_gen_wbinv_all(); +} + +static inline void +dumpsys_unmap_chunk(vm_paddr_t pa, size_t s, void *va) +{ + + dumpsys_gen_unmap_chunk(pa, s, va); +} + +static inline int +dumpsys_write_aux_headers(struct dumperinfo *di) +{ + + return (dumpsys_gen_write_aux_headers(di)); +} + +static inline int +minidumpsys(struct dumperinfo *di) +{ + + return (-ENOSYS); +} + +#endif /* !_MACHINE_DUMP_H_ */ Index: sys/sparc64/sparc64/dump_machdep.c =================================================================== --- sys/sparc64/sparc64/dump_machdep.c +++ sys/sparc64/sparc64/dump_machdep.c @@ -39,62 +39,38 @@ #include #include +#include #include +#include #include #include #include #include -CTASSERT(sizeof(struct kerneldumpheader) == DEV_BSIZE); +static off_t fileofs; -static struct kerneldumpheader kdh; -static off_t dumplo, dumppos; +extern off_t dumplo; +extern struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; -/* Handle buffered writes. */ -static char buffer[DEV_BSIZE]; -static vm_size_t fragsz; +int do_minidump = 0; -#define MAXDUMPSZ (MAXDUMPPGS << PAGE_SHIFT) - -static int -buf_write(struct dumperinfo *di, char *ptr, size_t sz) +void +dumpsys_md_pa_init(void) { - 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 = dump_write(di, buffer, 0, dumplo, - DEV_BSIZE); - if (error) - return error; - dumplo += DEV_BSIZE; - fragsz = 0; - } - } + int i; - return (0); + memset(dump_map, 0, sizeof(dump_map)); + for (i = 0; i < sparc64_nmemreg; i++) { + dump_map[i].md_start = sparc64_memreg[i].mr_start; + dump_map[i].md_size = sparc64_memreg[i].mr_size; + } } -static int -buf_flush(struct dumperinfo *di) +void +dumpsys_map_chunk(vm_paddr_t pa, size_t chunk __unused, void **va) { - int error; - - if (fragsz == 0) - return (0); - error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; - fragsz = 0; - return (error); + *va = (void*)TLB_PHYS_TO_DIRECT(pa); } static int @@ -104,47 +80,16 @@ r.dr_pa = pa; r.dr_size = size; - r.dr_offs = dumppos; - dumppos += size; - return (buf_write(di, (char *)&r, sizeof(r))); -} - -static int -blk_dump(struct dumperinfo *di, vm_paddr_t pa, vm_size_t size) -{ - vm_size_t pos, rsz; - vm_offset_t va; - int c, counter, error, twiddle; - - printf(" chunk at %#lx: %ld bytes ", (u_long)pa, (long)size); - - va = 0L; - error = counter = twiddle = 0; - for (pos = 0; pos < size; pos += MAXDUMPSZ, counter++) { - if (counter % 128 == 0) - printf("%c\b", "|/-\\"[twiddle++ & 3]); - rsz = size - pos; - rsz = (rsz > MAXDUMPSZ) ? MAXDUMPSZ : rsz; - va = TLB_PHYS_TO_DIRECT(pa + pos); - error = dump_write(di, (void *)va, 0, dumplo, rsz); - if (error) - break; - dumplo += rsz; - - /* 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); + r.dr_offs = fileofs; + fileofs += size; + return (dumpsys_buf_write(di, (char *)&r, sizeof(r))); } int dumpsys(struct dumperinfo *di) { + static struct kerneldumpheader kdh; + struct sparc64_dump_hdr hdr; vm_size_t size, totsize, hdrsize; int error, i, nreg; @@ -189,10 +134,10 @@ hdr.dh_tsb_mask = tsb_kernel_mask; hdr.dh_nregions = nreg; - if (buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) + if (dumpsys_buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) goto fail; - dumppos = hdrsize; + fileofs = hdrsize; /* Now, write out the region descriptors. */ for (i = 0; i < sparc64_nmemreg; i++) { error = reg_write(di, sparc64_memreg[i].mr_start, @@ -200,15 +145,12 @@ if (error != 0) goto fail; } - buf_flush(di); + dumpsys_buf_flush(di); /* Dump memory chunks. */ - for (i = 0; i < sparc64_nmemreg; i++) { - error = blk_dump(di, sparc64_memreg[i].mr_start, - sparc64_memreg[i].mr_size); - if (error != 0) - goto fail; - } + error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); + if (error < 0) + goto fail; /* Dump trailer */ error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); @@ -221,6 +163,9 @@ return (0); fail: + if (error < 0) + error = -error; + /* XXX It should look more like VMS :-) */ printf("** DUMP FAILED (ERROR %d) **\n", error); return (error); Index: sys/sys/conf.h =================================================================== --- sys/sys/conf.h +++ sys/sys/conf.h @@ -338,7 +338,6 @@ int set_dumper(struct dumperinfo *, const char *_devname, struct thread *td); int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); -int dumpsys(struct dumperinfo *); int doadump(boolean_t); extern int dumping; /* system is dumping */ Index: sys/sys/kerneldump.h =================================================================== --- sys/sys/kerneldump.h +++ sys/sys/kerneldump.h @@ -100,8 +100,31 @@ } #ifdef _KERNEL +struct dump_pa { + vm_paddr_t md_start; + vm_paddr_t md_size; +}; + void mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver, uint64_t dumplen, uint32_t blksz); + +int dumpsys_generic(struct dumperinfo *); + +void dumpsys_map_chunk(vm_paddr_t, size_t, void **); +typedef int dumpsys_callback_t(struct dump_pa *, int, void *); +int dumpsys_foreach_chunk(dumpsys_callback_t, void *); +int dumpsys_cb_dumpdata(struct dump_pa *, int, void *); +int dumpsys_buf_write(struct dumperinfo *, char *, size_t); +int dumpsys_buf_flush(struct dumperinfo *); + +void dumpsys_gen_md_pa_init(void); +struct dump_pa *dumpsys_gen_md_pa_next(struct dump_pa *); +void dumpsys_gen_wbinv_all(void); +void dumpsys_gen_unmap_chunk(vm_paddr_t, size_t, void *); +int dumpsys_gen_write_aux_headers(struct dumperinfo *); + +extern int do_minidump; + #endif #endif /* _SYS_KERNELDUMP_H */ Index: sys/x86/x86/dump_machdep.c =================================================================== --- sys/x86/x86/dump_machdep.c +++ sys/x86/x86/dump_machdep.c @@ -30,349 +30,25 @@ #include "opt_watchdog.h" #include -#include #include -#include -#include -#include #include -#include +#include +#include #include #include -#include -#include - -#ifdef __amd64__ -#define KERNELDUMP_VERSION KERNELDUMP_AMD64_VERSION -#define EM_VALUE EM_X86_64 -#else -#define KERNELDUMP_VERSION KERNELDUMP_I386_VERSION -#define EM_VALUE EM_386 -#endif - -CTASSERT(sizeof(struct kerneldumpheader) == 512); int do_minidump = 1; SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RWTUN, &do_minidump, 0, "Enable mini crash dumps"); -/* - * 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)) - -struct md_pa { - vm_paddr_t md_start; - vm_paddr_t md_size; -}; - -typedef int callback_t(struct md_pa *, int, void *); - -static struct kerneldumpheader kdh; -static off_t dumplo, fileofs; - -/* Handle buffered writes. */ -static char buffer[DEV_BSIZE]; -static size_t fragsz; - -/* 20 phys_avail entry pairs correspond to 10 md_pa's */ -static struct md_pa dump_map[10]; - -static void -md_pa_init(void) -{ - int n, idx; - - bzero(dump_map, sizeof(dump_map)); - for (n = 0; n < sizeof(dump_map) / sizeof(dump_map[0]); n++) { - idx = n * 2; - if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0) - break; - dump_map[n].md_start = dump_avail[idx]; - dump_map[n].md_size = dump_avail[idx + 1] - dump_avail[idx]; - } -} - -static struct md_pa * -md_pa_first(void) -{ - - return (&dump_map[0]); -} - -static struct md_pa * -md_pa_next(struct md_pa *mdp) -{ - - mdp++; - if (mdp->md_size == 0) - mdp = NULL; - return (mdp); -} - -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 = dump_write(di, 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 = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); - dumplo += DEV_BSIZE; - fragsz = 0; - return (error); -} - -#define PG2MB(pgs) ((pgs + (1 << 8) - 1) >> 8) - -static int -cb_dumpdata(struct md_pa *mdp, int seqnr, void *arg) +void +dumpsys_map_chunk(vm_paddr_t pa, size_t chunk, void **va) { - struct dumperinfo *di = (struct dumperinfo*)arg; - vm_paddr_t a, pa; - void *va; - uint64_t pgs; - size_t counter, sz, chunk; - int i, c, error, twiddle; - u_int maxdumppgs; + int i; + vm_paddr_t a; - error = 0; /* catch case in which chunk size is 0 */ - counter = 0; /* Update twiddle every 16MB */ - twiddle = 0; - va = 0; - pgs = mdp->md_size / PAGE_SIZE; - pa = mdp->md_start; - maxdumppgs = min(di->maxiosize / PAGE_SIZE, MAXDUMPPGS); - if (maxdumppgs == 0) /* seatbelt */ - maxdumppgs = 1; - - printf(" chunk %d: %juMB (%ju pages)", seqnr, (uintmax_t)PG2MB(pgs), - (uintmax_t)pgs); - - while (pgs) { - chunk = pgs; - if (chunk > maxdumppgs) - chunk = maxdumppgs; - sz = chunk << PAGE_SHIFT; - counter += sz; - if (counter >> 24) { - printf(" %ju", (uintmax_t)PG2MB(pgs)); - counter &= (1<<24) - 1; - } - for (i = 0; i < chunk; i++) { - a = pa + i * PAGE_SIZE; - va = pmap_kenter_temporary(trunc_page(a), i); - } - - wdog_kern_pat(WD_LASTVAL); - - error = dump_write(di, va, 0, dumplo, sz); - if (error) - break; - dumplo += sz; - pgs -= chunk; - pa += 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 md_pa *mdp, int seqnr, void *arg) -{ - struct dumperinfo *di = (struct dumperinfo*)arg; - Elf_Phdr phdr; - uint64_t size; - int error; - - size = mdp->md_size; - bzero(&phdr, sizeof(phdr)); - phdr.p_type = PT_LOAD; - phdr.p_flags = PF_R; /* XXX */ - phdr.p_offset = fileofs; - phdr.p_vaddr = mdp->md_start; - phdr.p_paddr = mdp->md_start; - phdr.p_filesz = size; - phdr.p_memsz = 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 md_pa *mdp, int seqnr, void *arg) -{ - uint64_t *sz = (uint64_t*)arg; - - *sz += (uint64_t)mdp->md_size; - return (0); -} - -static int -foreach_chunk(callback_t cb, void *arg) -{ - struct md_pa *mdp; - int error, seqnr; - - seqnr = 0; - mdp = md_pa_first(); - while (mdp != NULL) { - error = (*cb)(mdp, seqnr++, arg); - if (error) - return (-error); - mdp = md_pa_next(mdp); + for (i = 0; i < chunk; i++) { + a = pa + i * PAGE_SIZE; + *va = pmap_kenter_temporary(trunc_page(a), i); } - return (seqnr); -} - -int -dumpsys(struct dumperinfo *di) -{ - Elf_Ehdr ehdr; - uint64_t dumpsize; - off_t hdrgap; - size_t hdrsz; - int error; - - if (do_minidump) - return (minidumpsys(di)); - - 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_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 = EM_VALUE; - ehdr.e_phoff = sizeof(ehdr); - ehdr.e_flags = 0; - ehdr.e_ehsize = sizeof(ehdr); - ehdr.e_phentsize = sizeof(Elf_Phdr); - ehdr.e_shentsize = sizeof(Elf_Shdr); - - md_pa_init(); - - /* 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); - - /* Determine dump offset on device. */ - if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { - error = ENOSPC; - goto fail; - } - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; - - mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_VERSION, dumpsize, - di->blocksize); - - printf("Dumping %llu MB (%d chunks)\n", (long long)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); }