35#include <sys/kernel.h>
36#include <sys/kerneldump.h>
37#include <sys/malloc.h>
38#include <sys/msgbuf.h>
40#include <sys/watchdog.h>
43#include <vm/vm_param.h>
44#include <vm/vm_page.h>
45#include <vm/vm_phys.h>
46#include <vm/vm_dumpset.h>
49#include <machine/dump.h>
50#include <machine/elf.h>
51#include <machine/md_var.h>
52#include <machine/pcb.h>
54CTASSERT(
sizeof(
struct kerneldumpheader) == 512);
56#define MD_ALIGN(x) roundup2((off_t)(x), PAGE_SIZE)
63#if !defined(__powerpc__)
70 for (n = 0; n < nitems(
dump_map); n++) {
72 if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0)
74 dump_map[n].pa_start = dump_avail[idx];
75 dump_map[n].pa_size = dump_avail[idx + 1] - dump_avail[idx];
88 if (mdp->pa_size == 0)
116 static uint8_t
buf[DEV_BSIZE];
141 len = di->blocksize -
fragsz;
144 memcpy((
char *)di->blockbuf +
fragsz, ptr, len);
148 if (
fragsz == di->blocksize) {
149 error =
dump_append(di, di->blockbuf, 0, di->blocksize);
166 error =
dump_append(di, di->blockbuf, 0, di->blocksize);
172#define PG2MB(pgs) ((pgs + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT))
177 struct dumperinfo *di = (
struct dumperinfo*)arg;
181 size_t counter, sz, chunk;
188 pgs = mdp->pa_size / PAGE_SIZE;
190 maxdumppgs = min(di->maxiosize / PAGE_SIZE, MAXDUMPPGS);
194 printf(
" chunk %d: %juMB (%ju pages)", seqnr, (uintmax_t)
PG2MB(pgs),
200 if (chunk > maxdumppgs)
202 sz = chunk << PAGE_SHIFT;
206 counter &= (1 << 24) - 1;
209 dumpsys_map_chunk(pa, chunk, &va);
210 wdog_kern_pat(WD_LASTVAL);
213 dumpsys_unmap_chunk(pa, chunk, va);
224 printf(
" (CTRL-C to abort) ");
226 printf(
" ... %s\n", (error) ?
"fail" :
"ok");
237 mdp = dumpsys_pa_next(NULL);
238 while (mdp != NULL) {
239 error = (*cb)(mdp, seqnr++, arg);
242 mdp = dumpsys_pa_next(mdp);
252 struct dumperinfo *di = (
struct dumperinfo*)arg;
258 bzero(&phdr,
sizeof(phdr));
259 phdr.p_type = PT_LOAD;
263 phdr.p_vaddr = (do_minidump? mdp->pa_start : ~0L);
264 phdr.p_paddr = (do_minidump? ~0L : mdp->pa_start);
266 phdr.p_vaddr = mdp->pa_start;
267 phdr.p_paddr = mdp->pa_start;
269 phdr.p_filesz = size;
271 phdr.p_align = PAGE_SIZE;
279cb_size(
struct dump_pa *mdp,
int seqnr,
void *arg)
283 sz = (uint64_t *)arg;
284 *sz += (uint64_t)mdp->pa_size;
291 static struct kerneldumpheader kdh;
298#if MINIDUMP_PAGE_TRACKING == 1
300 return (minidumpsys(di,
false));
303 bzero(&ehdr,
sizeof(ehdr));
304 ehdr.e_ident[EI_MAG0] = ELFMAG0;
305 ehdr.e_ident[EI_MAG1] = ELFMAG1;
306 ehdr.e_ident[EI_MAG2] = ELFMAG2;
307 ehdr.e_ident[EI_MAG3] = ELFMAG3;
308 ehdr.e_ident[EI_CLASS] = ELF_CLASS;
309#if BYTE_ORDER == LITTLE_ENDIAN
310 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
312 ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
314 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
315 ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE;
316 ehdr.e_type = ET_CORE;
317 ehdr.e_machine = EM_VALUE;
318 ehdr.e_phoff =
sizeof(ehdr);
320 ehdr.e_ehsize =
sizeof(ehdr);
321 ehdr.e_phentsize =
sizeof(Elf_Phdr);
322 ehdr.e_shentsize =
sizeof(Elf_Shdr);
329 DUMPSYS_NUM_AUX_HDRS;
330 hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
333 hdrgap =
fileofs - roundup2((off_t)hdrsz, di->blocksize);
342 printf(
"Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20,
343 ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS);
354 error = dumpsys_write_aux_headers(di);
378 printf(
"\nDump complete\n");
385 if (error == ECANCELED)
386 printf(
"\nDump aborted\n");
387 else if (error == E2BIG || error == ENOSPC)
388 printf(
"\nDump failed. Partition too small.\n");
390 printf(
"\n** DUMP FAILED (ERROR %d) **\n", error);
394#if MINIDUMP_PAGE_TRACKING == 1
401} progress_track[10] = {
414static uint64_t dumpsys_pb_size;
415static uint64_t dumpsys_pb_remaining;
416static uint64_t dumpsys_pb_check;
420dumpsys_pb_init(uint64_t dumpsize)
424 dumpsys_pb_size = dumpsys_pb_remaining = dumpsize;
425 dumpsys_pb_check = 0;
427 for (i = 0; i < nitems(progress_track); i++)
428 progress_track[i].visited =
false;
436dumpsys_pb_progress(
size_t delta)
440 dumpsys_pb_remaining -= delta;
441 dumpsys_pb_check += delta;
447 if ((dumpsys_pb_check >> DUMPSYS_PB_CHECK_BITS) == 0)
450 dumpsys_pb_check &= (1 << DUMPSYS_PB_CHECK_BITS) - 1;
452 sofar = 100 - ((dumpsys_pb_remaining * 100) / dumpsys_pb_size);
453 for (i = 0; i < nitems(progress_track); i++) {
454 if (sofar < progress_track[i].min_per ||
455 sofar > progress_track[i].max_per)
457 if (!progress_track[i].visited) {
458 progress_track[i].visited =
true;
466minidumpsys(
struct dumperinfo *di,
bool livedump)
468 struct minidumpstate state;
469 struct msgbuf mb_copy;
475 KASSERT(!
dumping, (
"live dump invoked from incorrect context"));
514 state.msgbufp = &mb_copy;
516 sz = BITSET_SIZE(vm_page_dump_pages);
517 state.dump_bitset =
malloc(sz, M_TEMP, M_WAITOK);
518 BIT_COPY_STORE_REL(sz, vm_page_dump, state.dump_bitset);
520 KASSERT(
dumping, (
"minidump invoked outside of doadump()"));
524 state.dump_bitset = vm_page_dump;
527 error = cpu_minidumpsys(di, &state);
529 free(msg_ptr, M_TEMP);
530 free(state.dump_bitset, M_TEMP);
void dumpsys_gen_unmap_chunk(vm_paddr_t pa __unused, size_t chunk __unused, void *va __unused)
int dumpsys_generic(struct dumperinfo *di)
int dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz)
int dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg)
int dumpsys_foreach_chunk(dumpsys_callback_t cb, void *arg)
struct dump_pa * dumpsys_gen_pa_next(struct dump_pa *mdp)
struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]
static int cb_dumphdr(struct dump_pa *mdp, int seqnr, void *arg)
int dumpsys_buf_seek(struct dumperinfo *di, size_t sz)
int dumpsys_gen_write_aux_headers(struct dumperinfo *di)
void dumpsys_gen_wbinv_all(void)
CTASSERT(sizeof(struct kerneldumpheader)==512)
void dumpsys_gen_pa_init(void)
static int cb_size(struct dump_pa *mdp, int seqnr, void *arg)
int dumpsys_buf_flush(struct dumperinfo *di)
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void free(void *addr, struct malloc_type *mtp)
int dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh)
int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh)
int __read_mostly dumping
void dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, const char *magic, uint32_t archver, uint64_t dumplen)
int dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, size_t length)
void msgbuf_duplicate(struct msgbuf *src, struct msgbuf *dst, char *dst_msgptr)
int printf(const char *fmt,...)