1bdb9ab0dSMark Johnston /*- 2bdb9ab0dSMark Johnston * Copyright (c) 2002 Marcel Moolenaar 3bdb9ab0dSMark Johnston * All rights reserved. 4bdb9ab0dSMark Johnston * 5bdb9ab0dSMark Johnston * Redistribution and use in source and binary forms, with or without 6bdb9ab0dSMark Johnston * modification, are permitted provided that the following conditions 7bdb9ab0dSMark Johnston * are met: 8bdb9ab0dSMark Johnston * 9bdb9ab0dSMark Johnston * 1. Redistributions of source code must retain the above copyright 10bdb9ab0dSMark Johnston * notice, this list of conditions and the following disclaimer. 11bdb9ab0dSMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 12bdb9ab0dSMark Johnston * notice, this list of conditions and the following disclaimer in the 13bdb9ab0dSMark Johnston * documentation and/or other materials provided with the distribution. 14bdb9ab0dSMark Johnston * 15bdb9ab0dSMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16bdb9ab0dSMark Johnston * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17bdb9ab0dSMark Johnston * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18bdb9ab0dSMark Johnston * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19bdb9ab0dSMark Johnston * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20bdb9ab0dSMark Johnston * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21bdb9ab0dSMark Johnston * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22bdb9ab0dSMark Johnston * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23bdb9ab0dSMark Johnston * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24bdb9ab0dSMark Johnston * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bdb9ab0dSMark Johnston */ 26bdb9ab0dSMark Johnston 27bdb9ab0dSMark Johnston #include <sys/param.h> 28bdb9ab0dSMark Johnston #include <sys/systm.h> 29bdb9ab0dSMark Johnston #include <sys/conf.h> 30bdb9ab0dSMark Johnston #include <sys/cons.h> 31588ab3c7SMitchell Horne #include <sys/kdb.h> 32bdb9ab0dSMark Johnston #include <sys/kernel.h> 33bdb9ab0dSMark Johnston #include <sys/kerneldump.h> 34588ab3c7SMitchell Horne #include <sys/malloc.h> 351adebe3cSMitchell Horne #include <sys/msgbuf.h> 361adebe3cSMitchell Horne #include <sys/proc.h> 37bdb9ab0dSMark Johnston #include <sys/watchdog.h> 381adebe3cSMitchell Horne 39bdb9ab0dSMark Johnston #include <vm/vm.h> 40bdb9ab0dSMark Johnston #include <vm/vm_param.h> 4121943937SJeff Roberson #include <vm/vm_page.h> 4221943937SJeff Roberson #include <vm/vm_phys.h> 436f3b523cSKonstantin Belousov #include <vm/vm_dumpset.h> 44bdb9ab0dSMark Johnston #include <vm/pmap.h> 451adebe3cSMitchell Horne 46bdb9ab0dSMark Johnston #include <machine/dump.h> 47bdb9ab0dSMark Johnston #include <machine/elf.h> 48bdb9ab0dSMark Johnston #include <machine/md_var.h> 49bdb9ab0dSMark Johnston #include <machine/pcb.h> 50bdb9ab0dSMark Johnston 51bdb9ab0dSMark Johnston CTASSERT(sizeof(struct kerneldumpheader) == 512); 52bdb9ab0dSMark Johnston 535dc5dab6SConrad Meyer #define MD_ALIGN(x) roundup2((off_t)(x), PAGE_SIZE) 54bdb9ab0dSMark Johnston 55bdb9ab0dSMark Johnston /* Handle buffered writes. */ 56bdb9ab0dSMark Johnston static size_t fragsz; 57bdb9ab0dSMark Johnston 58bdb9ab0dSMark Johnston struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; 59bdb9ab0dSMark Johnston 608f11c997SYoshihiro Takahashi #if !defined(__powerpc__) 61bdb9ab0dSMark Johnston void 62bdb9ab0dSMark Johnston dumpsys_gen_pa_init(void) 63bdb9ab0dSMark Johnston { 64bdb9ab0dSMark Johnston int n, idx; 65bdb9ab0dSMark Johnston 66bdb9ab0dSMark Johnston bzero(dump_map, sizeof(dump_map)); 6702abd400SPedro F. Giffuni for (n = 0; n < nitems(dump_map); n++) { 68bdb9ab0dSMark Johnston idx = n * 2; 69bdb9ab0dSMark Johnston if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0) 70bdb9ab0dSMark Johnston break; 71bdb9ab0dSMark Johnston dump_map[n].pa_start = dump_avail[idx]; 72bdb9ab0dSMark Johnston dump_map[n].pa_size = dump_avail[idx + 1] - dump_avail[idx]; 73bdb9ab0dSMark Johnston } 74bdb9ab0dSMark Johnston } 757888a51fSMarius Strobl #endif 76bdb9ab0dSMark Johnston 77bdb9ab0dSMark Johnston struct dump_pa * 78bdb9ab0dSMark Johnston dumpsys_gen_pa_next(struct dump_pa *mdp) 79bdb9ab0dSMark Johnston { 80bdb9ab0dSMark Johnston 81bdb9ab0dSMark Johnston if (mdp == NULL) 82bdb9ab0dSMark Johnston return (&dump_map[0]); 83bdb9ab0dSMark Johnston 84bdb9ab0dSMark Johnston mdp++; 85bdb9ab0dSMark Johnston if (mdp->pa_size == 0) 86bdb9ab0dSMark Johnston mdp = NULL; 87bdb9ab0dSMark Johnston return (mdp); 88bdb9ab0dSMark Johnston } 89bdb9ab0dSMark Johnston 90bdb9ab0dSMark Johnston void 91bdb9ab0dSMark Johnston dumpsys_gen_wbinv_all(void) 92bdb9ab0dSMark Johnston { 937888a51fSMarius Strobl 94bdb9ab0dSMark Johnston } 95bdb9ab0dSMark Johnston 96bdb9ab0dSMark Johnston void 97bdb9ab0dSMark Johnston dumpsys_gen_unmap_chunk(vm_paddr_t pa __unused, size_t chunk __unused, 98bdb9ab0dSMark Johnston void *va __unused) 99bdb9ab0dSMark Johnston { 1007888a51fSMarius Strobl 101bdb9ab0dSMark Johnston } 102bdb9ab0dSMark Johnston 103bdb9ab0dSMark Johnston int 104bdb9ab0dSMark Johnston dumpsys_gen_write_aux_headers(struct dumperinfo *di) 105bdb9ab0dSMark Johnston { 106bdb9ab0dSMark Johnston 107bdb9ab0dSMark Johnston return (0); 108bdb9ab0dSMark Johnston } 109bdb9ab0dSMark Johnston 110bdb9ab0dSMark Johnston int 111480f31c2SKonrad Witaszczyk dumpsys_buf_seek(struct dumperinfo *di, size_t sz) 112480f31c2SKonrad Witaszczyk { 113480f31c2SKonrad Witaszczyk static uint8_t buf[DEV_BSIZE]; 114480f31c2SKonrad Witaszczyk size_t nbytes; 115480f31c2SKonrad Witaszczyk int error; 116480f31c2SKonrad Witaszczyk 117480f31c2SKonrad Witaszczyk bzero(buf, sizeof(buf)); 118480f31c2SKonrad Witaszczyk 119480f31c2SKonrad Witaszczyk while (sz > 0) { 120480f31c2SKonrad Witaszczyk nbytes = MIN(sz, sizeof(buf)); 121480f31c2SKonrad Witaszczyk 122db71383bSMitchell Horne error = dump_append(di, buf, nbytes); 123480f31c2SKonrad Witaszczyk if (error) 124480f31c2SKonrad Witaszczyk return (error); 125480f31c2SKonrad Witaszczyk sz -= nbytes; 126480f31c2SKonrad Witaszczyk } 127480f31c2SKonrad Witaszczyk 128480f31c2SKonrad Witaszczyk return (0); 129480f31c2SKonrad Witaszczyk } 130480f31c2SKonrad Witaszczyk 131480f31c2SKonrad Witaszczyk int 132bdb9ab0dSMark Johnston dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz) 133bdb9ab0dSMark Johnston { 134bdb9ab0dSMark Johnston size_t len; 135bdb9ab0dSMark Johnston int error; 136bdb9ab0dSMark Johnston 137bdb9ab0dSMark Johnston while (sz) { 1385dc5dab6SConrad Meyer len = di->blocksize - fragsz; 139bdb9ab0dSMark Johnston if (len > sz) 140bdb9ab0dSMark Johnston len = sz; 1415dc5dab6SConrad Meyer memcpy((char *)di->blockbuf + fragsz, ptr, len); 142bdb9ab0dSMark Johnston fragsz += len; 143bdb9ab0dSMark Johnston ptr += len; 144bdb9ab0dSMark Johnston sz -= len; 1455dc5dab6SConrad Meyer if (fragsz == di->blocksize) { 146db71383bSMitchell Horne error = dump_append(di, di->blockbuf, di->blocksize); 147bdb9ab0dSMark Johnston if (error) 148bdb9ab0dSMark Johnston return (error); 149bdb9ab0dSMark Johnston fragsz = 0; 150bdb9ab0dSMark Johnston } 151bdb9ab0dSMark Johnston } 152bdb9ab0dSMark Johnston return (0); 153bdb9ab0dSMark Johnston } 154bdb9ab0dSMark Johnston 155bdb9ab0dSMark Johnston int 156bdb9ab0dSMark Johnston dumpsys_buf_flush(struct dumperinfo *di) 157bdb9ab0dSMark Johnston { 158bdb9ab0dSMark Johnston int error; 159bdb9ab0dSMark Johnston 160bdb9ab0dSMark Johnston if (fragsz == 0) 161bdb9ab0dSMark Johnston return (0); 162bdb9ab0dSMark Johnston 163db71383bSMitchell Horne error = dump_append(di, di->blockbuf, di->blocksize); 164bdb9ab0dSMark Johnston fragsz = 0; 165bdb9ab0dSMark Johnston return (error); 166bdb9ab0dSMark Johnston } 167bdb9ab0dSMark Johnston 168bdb9ab0dSMark Johnston CTASSERT(PAGE_SHIFT < 20); 169bdb9ab0dSMark Johnston #define PG2MB(pgs) ((pgs + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT)) 170bdb9ab0dSMark Johnston 171bdb9ab0dSMark Johnston int 172bdb9ab0dSMark Johnston dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg) 173bdb9ab0dSMark Johnston { 174bdb9ab0dSMark Johnston struct dumperinfo *di = (struct dumperinfo*)arg; 175bdb9ab0dSMark Johnston vm_paddr_t pa; 176bdb9ab0dSMark Johnston void *va; 177bdb9ab0dSMark Johnston uint64_t pgs; 178bdb9ab0dSMark Johnston size_t counter, sz, chunk; 179bdb9ab0dSMark Johnston int c, error; 180bdb9ab0dSMark Johnston u_int maxdumppgs; 181bdb9ab0dSMark Johnston 182bdb9ab0dSMark Johnston error = 0; /* catch case in which chunk size is 0 */ 183bdb9ab0dSMark Johnston counter = 0; /* Update twiddle every 16MB */ 184b85f65afSPedro F. Giffuni va = NULL; 185bdb9ab0dSMark Johnston pgs = mdp->pa_size / PAGE_SIZE; 186bdb9ab0dSMark Johnston pa = mdp->pa_start; 187bdb9ab0dSMark Johnston maxdumppgs = min(di->maxiosize / PAGE_SIZE, MAXDUMPPGS); 188bdb9ab0dSMark Johnston if (maxdumppgs == 0) /* seatbelt */ 189bdb9ab0dSMark Johnston maxdumppgs = 1; 190bdb9ab0dSMark Johnston 191bdb9ab0dSMark Johnston printf(" chunk %d: %juMB (%ju pages)", seqnr, (uintmax_t)PG2MB(pgs), 192bdb9ab0dSMark Johnston (uintmax_t)pgs); 193bdb9ab0dSMark Johnston 194bdb9ab0dSMark Johnston dumpsys_wbinv_all(); 195bdb9ab0dSMark Johnston while (pgs) { 196bdb9ab0dSMark Johnston chunk = pgs; 197bdb9ab0dSMark Johnston if (chunk > maxdumppgs) 198bdb9ab0dSMark Johnston chunk = maxdumppgs; 199bdb9ab0dSMark Johnston sz = chunk << PAGE_SHIFT; 200bdb9ab0dSMark Johnston counter += sz; 201bdb9ab0dSMark Johnston if (counter >> 24) { 202bdb9ab0dSMark Johnston printf(" %ju", (uintmax_t)PG2MB(pgs)); 203bdb9ab0dSMark Johnston counter &= (1 << 24) - 1; 204bdb9ab0dSMark Johnston } 205bdb9ab0dSMark Johnston 206bdb9ab0dSMark Johnston dumpsys_map_chunk(pa, chunk, &va); 207bdb9ab0dSMark Johnston wdog_kern_pat(WD_LASTVAL); 208bdb9ab0dSMark Johnston 209db71383bSMitchell Horne error = dump_append(di, va, sz); 210bdb9ab0dSMark Johnston dumpsys_unmap_chunk(pa, chunk, va); 211bdb9ab0dSMark Johnston if (error) 212bdb9ab0dSMark Johnston break; 213bdb9ab0dSMark Johnston pgs -= chunk; 214bdb9ab0dSMark Johnston pa += sz; 215bdb9ab0dSMark Johnston 216bdb9ab0dSMark Johnston /* Check for user abort. */ 217bdb9ab0dSMark Johnston c = cncheckc(); 218bdb9ab0dSMark Johnston if (c == 0x03) 219bdb9ab0dSMark Johnston return (ECANCELED); 220bdb9ab0dSMark Johnston if (c != -1) 221bdb9ab0dSMark Johnston printf(" (CTRL-C to abort) "); 222bdb9ab0dSMark Johnston } 223bdb9ab0dSMark Johnston printf(" ... %s\n", (error) ? "fail" : "ok"); 224bdb9ab0dSMark Johnston return (error); 225bdb9ab0dSMark Johnston } 226bdb9ab0dSMark Johnston 227bdb9ab0dSMark Johnston int 228bdb9ab0dSMark Johnston dumpsys_foreach_chunk(dumpsys_callback_t cb, void *arg) 229bdb9ab0dSMark Johnston { 230bdb9ab0dSMark Johnston struct dump_pa *mdp; 231bdb9ab0dSMark Johnston int error, seqnr; 232bdb9ab0dSMark Johnston 233bdb9ab0dSMark Johnston seqnr = 0; 234bdb9ab0dSMark Johnston mdp = dumpsys_pa_next(NULL); 235bdb9ab0dSMark Johnston while (mdp != NULL) { 236bdb9ab0dSMark Johnston error = (*cb)(mdp, seqnr++, arg); 237bdb9ab0dSMark Johnston if (error) 238bdb9ab0dSMark Johnston return (-error); 239bdb9ab0dSMark Johnston mdp = dumpsys_pa_next(mdp); 240bdb9ab0dSMark Johnston } 241bdb9ab0dSMark Johnston return (seqnr); 242bdb9ab0dSMark Johnston } 243bdb9ab0dSMark Johnston 244bdb9ab0dSMark Johnston static off_t fileofs; 245bdb9ab0dSMark Johnston 246bdb9ab0dSMark Johnston static int 247bdb9ab0dSMark Johnston cb_dumphdr(struct dump_pa *mdp, int seqnr, void *arg) 248bdb9ab0dSMark Johnston { 249bdb9ab0dSMark Johnston struct dumperinfo *di = (struct dumperinfo*)arg; 250bdb9ab0dSMark Johnston Elf_Phdr phdr; 251bdb9ab0dSMark Johnston uint64_t size; 252bdb9ab0dSMark Johnston int error; 253bdb9ab0dSMark Johnston 254bdb9ab0dSMark Johnston size = mdp->pa_size; 255bdb9ab0dSMark Johnston bzero(&phdr, sizeof(phdr)); 256bdb9ab0dSMark Johnston phdr.p_type = PT_LOAD; 257bdb9ab0dSMark Johnston phdr.p_flags = PF_R; /* XXX */ 258bdb9ab0dSMark Johnston phdr.p_offset = fileofs; 259bdb9ab0dSMark Johnston #ifdef __powerpc__ 260bdb9ab0dSMark Johnston phdr.p_vaddr = (do_minidump? mdp->pa_start : ~0L); 261bdb9ab0dSMark Johnston phdr.p_paddr = (do_minidump? ~0L : mdp->pa_start); 262bdb9ab0dSMark Johnston #else 263bdb9ab0dSMark Johnston phdr.p_vaddr = mdp->pa_start; 264bdb9ab0dSMark Johnston phdr.p_paddr = mdp->pa_start; 265bdb9ab0dSMark Johnston #endif 266bdb9ab0dSMark Johnston phdr.p_filesz = size; 267bdb9ab0dSMark Johnston phdr.p_memsz = size; 268bdb9ab0dSMark Johnston phdr.p_align = PAGE_SIZE; 269bdb9ab0dSMark Johnston 270bdb9ab0dSMark Johnston error = dumpsys_buf_write(di, (char*)&phdr, sizeof(phdr)); 271bdb9ab0dSMark Johnston fileofs += phdr.p_filesz; 272bdb9ab0dSMark Johnston return (error); 273bdb9ab0dSMark Johnston } 274bdb9ab0dSMark Johnston 275bdb9ab0dSMark Johnston static int 276bdb9ab0dSMark Johnston cb_size(struct dump_pa *mdp, int seqnr, void *arg) 277bdb9ab0dSMark Johnston { 278bdb9ab0dSMark Johnston uint64_t *sz; 279bdb9ab0dSMark Johnston 280bdb9ab0dSMark Johnston sz = (uint64_t *)arg; 281bdb9ab0dSMark Johnston *sz += (uint64_t)mdp->pa_size; 282bdb9ab0dSMark Johnston return (0); 283bdb9ab0dSMark Johnston } 284bdb9ab0dSMark Johnston 285bdb9ab0dSMark Johnston int 286bdb9ab0dSMark Johnston dumpsys_generic(struct dumperinfo *di) 287bdb9ab0dSMark Johnston { 288bdb9ab0dSMark Johnston static struct kerneldumpheader kdh; 289bdb9ab0dSMark Johnston Elf_Ehdr ehdr; 290bdb9ab0dSMark Johnston uint64_t dumpsize; 291bdb9ab0dSMark Johnston off_t hdrgap; 292480f31c2SKonrad Witaszczyk size_t hdrsz; 293bdb9ab0dSMark Johnston int error; 294bdb9ab0dSMark Johnston 295b957b185SMark Johnston #if MINIDUMP_PAGE_TRACKING == 1 296bdb9ab0dSMark Johnston if (do_minidump) 297588ab3c7SMitchell Horne return (minidumpsys(di, false)); 298bdb9ab0dSMark Johnston #endif 299bdb9ab0dSMark Johnston 300bdb9ab0dSMark Johnston bzero(&ehdr, sizeof(ehdr)); 301bdb9ab0dSMark Johnston ehdr.e_ident[EI_MAG0] = ELFMAG0; 302bdb9ab0dSMark Johnston ehdr.e_ident[EI_MAG1] = ELFMAG1; 303bdb9ab0dSMark Johnston ehdr.e_ident[EI_MAG2] = ELFMAG2; 304bdb9ab0dSMark Johnston ehdr.e_ident[EI_MAG3] = ELFMAG3; 305bdb9ab0dSMark Johnston ehdr.e_ident[EI_CLASS] = ELF_CLASS; 306bdb9ab0dSMark Johnston #if BYTE_ORDER == LITTLE_ENDIAN 307bdb9ab0dSMark Johnston ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 308bdb9ab0dSMark Johnston #else 309bdb9ab0dSMark Johnston ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 310bdb9ab0dSMark Johnston #endif 311bdb9ab0dSMark Johnston ehdr.e_ident[EI_VERSION] = EV_CURRENT; 312bdb9ab0dSMark Johnston ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE; /* XXX big picture? */ 313bdb9ab0dSMark Johnston ehdr.e_type = ET_CORE; 314bdb9ab0dSMark Johnston ehdr.e_machine = EM_VALUE; 315bdb9ab0dSMark Johnston ehdr.e_phoff = sizeof(ehdr); 316bdb9ab0dSMark Johnston ehdr.e_flags = 0; 317bdb9ab0dSMark Johnston ehdr.e_ehsize = sizeof(ehdr); 318bdb9ab0dSMark Johnston ehdr.e_phentsize = sizeof(Elf_Phdr); 319bdb9ab0dSMark Johnston ehdr.e_shentsize = sizeof(Elf_Shdr); 320bdb9ab0dSMark Johnston 321bdb9ab0dSMark Johnston dumpsys_pa_init(); 322bdb9ab0dSMark Johnston 323bdb9ab0dSMark Johnston /* Calculate dump size. */ 324bdb9ab0dSMark Johnston dumpsize = 0L; 325bdb9ab0dSMark Johnston ehdr.e_phnum = dumpsys_foreach_chunk(cb_size, &dumpsize) + 326bdb9ab0dSMark Johnston DUMPSYS_NUM_AUX_HDRS; 327bdb9ab0dSMark Johnston hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; 328bdb9ab0dSMark Johnston fileofs = MD_ALIGN(hdrsz); 329bdb9ab0dSMark Johnston dumpsize += fileofs; 3305dc5dab6SConrad Meyer hdrgap = fileofs - roundup2((off_t)hdrsz, di->blocksize); 331bdb9ab0dSMark Johnston 33201938d36SMark Johnston dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, 33301938d36SMark Johnston dumpsize); 334bdb9ab0dSMark Johnston 33546fcd1afSMark Johnston error = dump_start(di, &kdh); 33650ef60daSMark Johnston if (error != 0) 337bdb9ab0dSMark Johnston goto fail; 338bdb9ab0dSMark Johnston 33920f85b1dSMark Johnston printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, 34020f85b1dSMark Johnston ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); 34120f85b1dSMark Johnston 342bdb9ab0dSMark Johnston /* Dump ELF header */ 343bdb9ab0dSMark Johnston error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr)); 344bdb9ab0dSMark Johnston if (error) 345bdb9ab0dSMark Johnston goto fail; 346bdb9ab0dSMark Johnston 347bdb9ab0dSMark Johnston /* Dump program headers */ 348bdb9ab0dSMark Johnston error = dumpsys_foreach_chunk(cb_dumphdr, di); 349bdb9ab0dSMark Johnston if (error < 0) 350bdb9ab0dSMark Johnston goto fail; 351bdb9ab0dSMark Johnston error = dumpsys_write_aux_headers(di); 352bdb9ab0dSMark Johnston if (error < 0) 353bdb9ab0dSMark Johnston goto fail; 354bdb9ab0dSMark Johnston dumpsys_buf_flush(di); 355bdb9ab0dSMark Johnston 356bdb9ab0dSMark Johnston /* 357bdb9ab0dSMark Johnston * All headers are written using blocked I/O, so we know the 358bdb9ab0dSMark Johnston * current offset is (still) block aligned. Skip the alignement 359bdb9ab0dSMark Johnston * in the file to have the segment contents aligned at page 36046fcd1afSMark Johnston * boundary. 361bdb9ab0dSMark Johnston */ 362480f31c2SKonrad Witaszczyk error = dumpsys_buf_seek(di, (size_t)hdrgap); 363480f31c2SKonrad Witaszczyk if (error) 364480f31c2SKonrad Witaszczyk goto fail; 365bdb9ab0dSMark Johnston 36646fcd1afSMark Johnston /* Dump memory chunks. */ 367bdb9ab0dSMark Johnston error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); 368bdb9ab0dSMark Johnston if (error < 0) 369bdb9ab0dSMark Johnston goto fail; 370bdb9ab0dSMark Johnston 37146fcd1afSMark Johnston error = dump_finish(di, &kdh); 37250ef60daSMark Johnston if (error != 0) 373bdb9ab0dSMark Johnston goto fail; 374bdb9ab0dSMark Johnston 375bdb9ab0dSMark Johnston printf("\nDump complete\n"); 376bdb9ab0dSMark Johnston return (0); 377bdb9ab0dSMark Johnston 378bdb9ab0dSMark Johnston fail: 379bdb9ab0dSMark Johnston if (error < 0) 380bdb9ab0dSMark Johnston error = -error; 381bdb9ab0dSMark Johnston 382bdb9ab0dSMark Johnston if (error == ECANCELED) 383bdb9ab0dSMark Johnston printf("\nDump aborted\n"); 38450ef60daSMark Johnston else if (error == E2BIG || error == ENOSPC) 385bdb9ab0dSMark Johnston printf("\nDump failed. Partition too small.\n"); 386bdb9ab0dSMark Johnston else 387bdb9ab0dSMark Johnston printf("\n** DUMP FAILED (ERROR %d) **\n", error); 388bdb9ab0dSMark Johnston return (error); 389bdb9ab0dSMark Johnston } 390ab4ed843SMitchell Horne 3911adebe3cSMitchell Horne #if MINIDUMP_PAGE_TRACKING == 1 3921adebe3cSMitchell Horne 393ab4ed843SMitchell Horne /* Minidump progress bar */ 394ab4ed843SMitchell Horne static struct { 395ab4ed843SMitchell Horne const int min_per; 396ab4ed843SMitchell Horne const int max_per; 397ab4ed843SMitchell Horne bool visited; 398ab4ed843SMitchell Horne } progress_track[10] = { 399ab4ed843SMitchell Horne { 0, 10, false}, 400ab4ed843SMitchell Horne { 10, 20, false}, 401ab4ed843SMitchell Horne { 20, 30, false}, 402ab4ed843SMitchell Horne { 30, 40, false}, 403ab4ed843SMitchell Horne { 40, 50, false}, 404ab4ed843SMitchell Horne { 50, 60, false}, 405ab4ed843SMitchell Horne { 60, 70, false}, 406ab4ed843SMitchell Horne { 70, 80, false}, 407ab4ed843SMitchell Horne { 80, 90, false}, 408ab4ed843SMitchell Horne { 90, 100, false} 409ab4ed843SMitchell Horne }; 410ab4ed843SMitchell Horne 411ab4ed843SMitchell Horne static uint64_t dumpsys_pb_size; 412ab4ed843SMitchell Horne static uint64_t dumpsys_pb_remaining; 413ab4ed843SMitchell Horne static uint64_t dumpsys_pb_check; 414ab4ed843SMitchell Horne 415ab4ed843SMitchell Horne /* Reset the progress bar for a dump of dumpsize. */ 416ab4ed843SMitchell Horne void 417ab4ed843SMitchell Horne dumpsys_pb_init(uint64_t dumpsize) 418ab4ed843SMitchell Horne { 419ab4ed843SMitchell Horne int i; 420ab4ed843SMitchell Horne 421ab4ed843SMitchell Horne dumpsys_pb_size = dumpsys_pb_remaining = dumpsize; 422ab4ed843SMitchell Horne dumpsys_pb_check = 0; 423ab4ed843SMitchell Horne 424ab4ed843SMitchell Horne for (i = 0; i < nitems(progress_track); i++) 425ab4ed843SMitchell Horne progress_track[i].visited = false; 426ab4ed843SMitchell Horne } 427ab4ed843SMitchell Horne 428ab4ed843SMitchell Horne /* 429ab4ed843SMitchell Horne * Update the progress according to the delta bytes that were written out. 430ab4ed843SMitchell Horne * Check and print the progress percentage. 431ab4ed843SMitchell Horne */ 432ab4ed843SMitchell Horne void 433ab4ed843SMitchell Horne dumpsys_pb_progress(size_t delta) 434ab4ed843SMitchell Horne { 435ab4ed843SMitchell Horne int sofar, i; 436ab4ed843SMitchell Horne 437ab4ed843SMitchell Horne dumpsys_pb_remaining -= delta; 438ab4ed843SMitchell Horne dumpsys_pb_check += delta; 439ab4ed843SMitchell Horne 440ab4ed843SMitchell Horne /* 441ab4ed843SMitchell Horne * To save time while dumping, only loop through progress_track 442ab4ed843SMitchell Horne * occasionally. 443ab4ed843SMitchell Horne */ 444ab4ed843SMitchell Horne if ((dumpsys_pb_check >> DUMPSYS_PB_CHECK_BITS) == 0) 445ab4ed843SMitchell Horne return; 446ab4ed843SMitchell Horne else 447ab4ed843SMitchell Horne dumpsys_pb_check &= (1 << DUMPSYS_PB_CHECK_BITS) - 1; 448ab4ed843SMitchell Horne 449ab4ed843SMitchell Horne sofar = 100 - ((dumpsys_pb_remaining * 100) / dumpsys_pb_size); 450ab4ed843SMitchell Horne for (i = 0; i < nitems(progress_track); i++) { 451ab4ed843SMitchell Horne if (sofar < progress_track[i].min_per || 452ab4ed843SMitchell Horne sofar > progress_track[i].max_per) 453ab4ed843SMitchell Horne continue; 454ab4ed843SMitchell Horne if (!progress_track[i].visited) { 455ab4ed843SMitchell Horne progress_track[i].visited = true; 456ab4ed843SMitchell Horne printf("..%d%%", sofar); 457ab4ed843SMitchell Horne } 458ab4ed843SMitchell Horne break; 459ab4ed843SMitchell Horne } 460ab4ed843SMitchell Horne } 4611adebe3cSMitchell Horne 4621adebe3cSMitchell Horne int 463588ab3c7SMitchell Horne minidumpsys(struct dumperinfo *di, bool livedump) 4641adebe3cSMitchell Horne { 4651adebe3cSMitchell Horne struct minidumpstate state; 466588ab3c7SMitchell Horne struct msgbuf mb_copy; 467588ab3c7SMitchell Horne char *msg_ptr; 4681adebe3cSMitchell Horne int error; 4691adebe3cSMitchell Horne 470588ab3c7SMitchell Horne if (livedump) { 471588ab3c7SMitchell Horne KASSERT(!dumping, ("live dump invoked from incorrect context")); 472588ab3c7SMitchell Horne 473588ab3c7SMitchell Horne /* 474588ab3c7SMitchell Horne * Before invoking cpu_minidumpsys() on the live system, we 475588ab3c7SMitchell Horne * must snapshot some required global state: the message 476588ab3c7SMitchell Horne * buffer, and the page dump bitset. They may be modified at 477588ab3c7SMitchell Horne * any moment, so for the sake of the live dump it is best to 478588ab3c7SMitchell Horne * have an unchanging snapshot to work with. Both are included 479588ab3c7SMitchell Horne * as part of the dump and consumed by userspace tools. 480588ab3c7SMitchell Horne * 481588ab3c7SMitchell Horne * Other global state important to the minidump code is the 482588ab3c7SMitchell Horne * dump_avail array and the kernel's page tables, but snapshots 483588ab3c7SMitchell Horne * are not taken of these. For one, dump_avail[] is expected 484588ab3c7SMitchell Horne * not to change after boot. Snapshotting the kernel page 485588ab3c7SMitchell Horne * tables would involve an additional walk, so this is avoided 486588ab3c7SMitchell Horne * too. 487588ab3c7SMitchell Horne * 488588ab3c7SMitchell Horne * This means live dumps are best effort, and the result may or 489588ab3c7SMitchell Horne * may not be usable; there are no guarantees about the 490588ab3c7SMitchell Horne * consistency of the dump's contents. Any of the following 491588ab3c7SMitchell Horne * (and likely more) may affect the live dump: 492588ab3c7SMitchell Horne * 493588ab3c7SMitchell Horne * - Data may be modified, freed, or remapped during the 494588ab3c7SMitchell Horne * course of the dump, such that the contents written out 495588ab3c7SMitchell Horne * are partially or entirely unrecognizable. This means 496588ab3c7SMitchell Horne * valid references may point to destroyed/mangled objects, 497588ab3c7SMitchell Horne * and vice versa. 498588ab3c7SMitchell Horne * 499588ab3c7SMitchell Horne * - The dumped context of any threads that ran during the 500588ab3c7SMitchell Horne * dump process may be unreliable. 501588ab3c7SMitchell Horne * 502588ab3c7SMitchell Horne * - The set of kernel page tables included in the dump likely 503588ab3c7SMitchell Horne * won't correspond exactly to the copy of the dump bitset. 504588ab3c7SMitchell Horne * This means some pages will be dumped without any way to 505588ab3c7SMitchell Horne * locate them, and some pages may not have been dumped 506588ab3c7SMitchell Horne * despite appearing as if they should. 507588ab3c7SMitchell Horne */ 508588ab3c7SMitchell Horne msg_ptr = malloc(msgbufsize, M_TEMP, M_WAITOK); 509588ab3c7SMitchell Horne msgbuf_duplicate(msgbufp, &mb_copy, msg_ptr); 510588ab3c7SMitchell Horne state.msgbufp = &mb_copy; 511588ab3c7SMitchell Horne 512*9ad8116bSKa Ho Ng state.dump_bitset = BITSET_ALLOC(vm_page_dump_pages, M_TEMP, 513*9ad8116bSKa Ho Ng M_WAITOK); 514*9ad8116bSKa Ho Ng BIT_COPY_STORE_REL(vm_page_dump_pages, vm_page_dump, 515*9ad8116bSKa Ho Ng state.dump_bitset); 516588ab3c7SMitchell Horne } else { 517588ab3c7SMitchell Horne KASSERT(dumping, ("minidump invoked outside of doadump()")); 518588ab3c7SMitchell Horne 519588ab3c7SMitchell Horne /* Use the globals. */ 5201adebe3cSMitchell Horne state.msgbufp = msgbufp; 5211adebe3cSMitchell Horne state.dump_bitset = vm_page_dump; 522588ab3c7SMitchell Horne } 5231adebe3cSMitchell Horne 5241adebe3cSMitchell Horne error = cpu_minidumpsys(di, &state); 525588ab3c7SMitchell Horne if (livedump) { 526588ab3c7SMitchell Horne free(msg_ptr, M_TEMP); 527*9ad8116bSKa Ho Ng BITSET_FREE(state.dump_bitset, M_TEMP); 528588ab3c7SMitchell Horne } 5291adebe3cSMitchell Horne 5301adebe3cSMitchell Horne return (error); 5311adebe3cSMitchell Horne } 5321adebe3cSMitchell Horne #endif /* MINIDUMP_PAGE_TRACKING == 1 */ 533