Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_dump.c
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <machine/dump.h> | #include <machine/dump.h> | ||||
#include <machine/elf.h> | #include <machine/elf.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
CTASSERT(sizeof(struct kerneldumpheader) == 512); | CTASSERT(sizeof(struct kerneldumpheader) == 512); | ||||
#define DEV_BSIZE_MAX 4096 | |||||
/* | /* | ||||
* Don't touch the first SIZEOF_METADATA bytes on the dump device. This | * 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. | * is to protect us from metadata and to protect metadata from us. | ||||
*/ | */ | ||||
#define SIZEOF_METADATA (64*1024) | #define SIZEOF_METADATA (64*1024) | ||||
#define MD_ALIGN(x) (((off_t)(x) + PAGE_MASK) & ~PAGE_MASK) | #define MD_ALIGN(x) (((off_t)(x) + PAGE_MASK) & ~PAGE_MASK) | ||||
#define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) | #define DEV_ALIGN(x) (((off_t)(x) + (di->blocksize-1)) & ~(di->blocksize-1)) | ||||
rpokala: These defines are duplicated in sys/amd64/amd64/minidump_machdep.c (and i386). They should… | |||||
cemAuthorUnsubmitted Not Done Inline ActionsThey aren't used in minidump — I just removed them. They both seem to be a duplicate of roundup2() though. DEV_ALIGN(x) = roundup2(x, di->blocksize); cem: They aren't used in minidump — I just removed them. They both seem to be a duplicate of… | |||||
off_t dumplo; | off_t dumplo; | ||||
/* Handle buffered writes. */ | /* Handle buffered writes. */ | ||||
static char buffer[DEV_BSIZE]; | static char buffer[DEV_BSIZE_MAX]; | ||||
cemAuthorUnsubmitted Done Inline ActionsThis is fine for now. I think we could also malloc a buffer (at runtime, not during panic/dump) based on the observed di->blocksize when a dumper is registered. cem: This is fine for now. I think we could also malloc a buffer (at runtime, not during… | |||||
static size_t fragsz; | static size_t fragsz; | ||||
struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; | struct dump_pa dump_map[DUMPSYS_MD_PA_NPAIRS]; | ||||
#if !defined(__powerpc__) && !defined(__sparc__) | #if !defined(__powerpc__) && !defined(__sparc__) | ||||
void | void | ||||
dumpsys_gen_pa_init(void) | dumpsys_gen_pa_init(void) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz) | dumpsys_buf_write(struct dumperinfo *di, char *ptr, size_t sz) | ||||
{ | { | ||||
size_t len; | size_t len; | ||||
int error; | int error; | ||||
while (sz) { | while (sz) { | ||||
len = DEV_BSIZE - fragsz; | KASSERT(di->blocksize <= DEV_BSIZE_MAX, ("%u dump block size " | ||||
"is larger then max block size %d", di->blocksize, | |||||
DEV_BSIZE_MAX)); | |||||
cemAuthorUnsubmitted Not Done Inline ActionsWe can move this out of the loop. cem: We can move this out of the loop. | |||||
len = di->blocksize - fragsz; | |||||
if (len > sz) | if (len > sz) | ||||
len = sz; | len = sz; | ||||
bcopy(ptr, buffer + fragsz, len); | bcopy(ptr, buffer + fragsz, len); | ||||
fragsz += len; | fragsz += len; | ||||
ptr += len; | ptr += len; | ||||
sz -= len; | sz -= len; | ||||
if (fragsz == DEV_BSIZE) { | if (fragsz == di->blocksize) { | ||||
error = dump_write(di, buffer, 0, dumplo, | error = dump_write(di, buffer, 0, dumplo, | ||||
DEV_BSIZE); | di->blocksize); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
dumplo += DEV_BSIZE; | dumplo += di->blocksize; | ||||
fragsz = 0; | fragsz = 0; | ||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
dumpsys_buf_flush(struct dumperinfo *di) | dumpsys_buf_flush(struct dumperinfo *di) | ||||
{ | { | ||||
int error; | int error; | ||||
if (fragsz == 0) | if (fragsz == 0) | ||||
return (0); | return (0); | ||||
error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); | error = dump_write(di, buffer, 0, dumplo, di->blocksize); | ||||
dumplo += DEV_BSIZE; | dumplo += di->blocksize; | ||||
fragsz = 0; | fragsz = 0; | ||||
return (error); | return (error); | ||||
} | } | ||||
CTASSERT(PAGE_SHIFT < 20); | CTASSERT(PAGE_SHIFT < 20); | ||||
#define PG2MB(pgs) ((pgs + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT)) | #define PG2MB(pgs) ((pgs + (1 << (20 - PAGE_SHIFT)) - 1) >> (20 - PAGE_SHIFT)) | ||||
int | int | ||||
dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg) | dumpsys_cb_dumpdata(struct dump_pa *mdp, int seqnr, void *arg) | ||||
{ | { | ||||
struct dumperinfo *di = (struct dumperinfo*)arg; | struct dumperinfo *di = (struct dumperinfo*)arg; | ||||
vm_paddr_t pa; | vm_paddr_t pa; | ||||
void *va; | void *va; | ||||
uint64_t pgs; | uint64_t pgs; | ||||
size_t counter, sz, chunk; | size_t counter, sz, chunk, size; | ||||
cemAuthorUnsubmitted Done Inline Actionssz and size is potentially confusing :). cem: sz and size is potentially confusing :). | |||||
int c, error; | int c, error; | ||||
u_int maxdumppgs; | u_int maxdumppgs; | ||||
error = 0; /* catch case in which chunk size is 0 */ | error = 0; /* catch case in which chunk size is 0 */ | ||||
counter = 0; /* Update twiddle every 16MB */ | counter = 0; /* Update twiddle every 16MB */ | ||||
va = 0; | va = 0; | ||||
pgs = mdp->pa_size / PAGE_SIZE; | pgs = mdp->pa_size / PAGE_SIZE; | ||||
pa = mdp->pa_start; | pa = mdp->pa_start; | ||||
Show All 16 Lines | if (counter >> 24) { | ||||
counter &= (1 << 24) - 1; | counter &= (1 << 24) - 1; | ||||
} | } | ||||
dumpsys_map_chunk(pa, chunk, &va); | dumpsys_map_chunk(pa, chunk, &va); | ||||
#ifdef SW_WATCHDOG | #ifdef SW_WATCHDOG | ||||
wdog_kern_pat(WD_LASTVAL); | wdog_kern_pat(WD_LASTVAL); | ||||
#endif | #endif | ||||
error = dump_write(di, va, 0, dumplo, sz); | error = dump_write_pad(di, va, 0, dumplo, sz, &size); | ||||
cemAuthorUnsubmitted Done Inline ActionsDoes savecore really support page sizes that require padding relative to the native block size? I would just leave this as dump_write() for now. cem: Does savecore really support page sizes that require padding relative to the native block size? | |||||
dumpsys_unmap_chunk(pa, chunk, va); | dumpsys_unmap_chunk(pa, chunk, va); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
dumplo += sz; | dumplo += size; | ||||
pgs -= chunk; | pgs -= chunk; | ||||
pa += sz; | pa += sz; | ||||
/* Check for user abort. */ | /* Check for user abort. */ | ||||
c = cncheckc(); | c = cncheckc(); | ||||
if (c == 0x03) | if (c == 0x03) | ||||
return (ECANCELED); | return (ECANCELED); | ||||
if (c != -1) | if (c != -1) | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
dumpsys_generic(struct dumperinfo *di) | dumpsys_generic(struct dumperinfo *di) | ||||
{ | { | ||||
static struct kerneldumpheader kdh; | static struct kerneldumpheader kdh; | ||||
Elf_Ehdr ehdr; | Elf_Ehdr ehdr; | ||||
uint64_t dumpsize; | uint64_t dumpsize; | ||||
off_t hdrgap; | off_t hdrgap; | ||||
size_t hdrsz; | size_t hdrsz, size; | ||||
int error; | int error; | ||||
#ifndef __powerpc__ | #ifndef __powerpc__ | ||||
if (do_minidump) | if (do_minidump) | ||||
return (minidumpsys(di)); | return (minidumpsys(di)); | ||||
#endif | #endif | ||||
bzero(&ehdr, sizeof(ehdr)); | bzero(&ehdr, sizeof(ehdr)); | ||||
Show All 24 Lines | #endif | ||||
ehdr.e_phnum = dumpsys_foreach_chunk(cb_size, &dumpsize) + | ehdr.e_phnum = dumpsys_foreach_chunk(cb_size, &dumpsize) + | ||||
DUMPSYS_NUM_AUX_HDRS; | DUMPSYS_NUM_AUX_HDRS; | ||||
hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; | hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize; | ||||
fileofs = MD_ALIGN(hdrsz); | fileofs = MD_ALIGN(hdrsz); | ||||
dumpsize += fileofs; | dumpsize += fileofs; | ||||
hdrgap = fileofs - DEV_ALIGN(hdrsz); | hdrgap = fileofs - DEV_ALIGN(hdrsz); | ||||
/* Determine dump offset on device. */ | /* Determine dump offset on device. */ | ||||
if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { | if (di->mediasize < SIZEOF_METADATA + dumpsize + di->blocksize * 2) { | ||||
error = ENOSPC; | error = ENOSPC; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
dumplo = di->mediaoffset + di->mediasize - dumpsize; | dumplo = di->mediaoffset + di->mediasize - dumpsize; | ||||
dumplo -= sizeof(kdh) * 2; | dumplo -= di->blocksize * 2; | ||||
mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize, | mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARCH_VERSION, dumpsize, | ||||
di->blocksize); | di->blocksize); | ||||
printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, | printf("Dumping %ju MB (%d chunks)\n", (uintmax_t)dumpsize >> 20, | ||||
ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); | ehdr.e_phnum - DUMPSYS_NUM_AUX_HDRS); | ||||
/* Dump leader */ | /* Dump leader */ | ||||
error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); | error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
dumplo += sizeof(kdh); | dumplo += size; | ||||
/* Dump ELF header */ | /* Dump ELF header */ | ||||
error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr)); | error = dumpsys_buf_write(di, (char*)&ehdr, sizeof(ehdr)); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
/* Dump program headers */ | /* Dump program headers */ | ||||
error = dumpsys_foreach_chunk(cb_dumphdr, di); | error = dumpsys_foreach_chunk(cb_dumphdr, di); | ||||
Show All 14 Lines | #endif | ||||
dumplo += hdrgap; | dumplo += hdrgap; | ||||
/* Dump memory chunks (updates dumplo) */ | /* Dump memory chunks (updates dumplo) */ | ||||
error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); | error = dumpsys_foreach_chunk(dumpsys_cb_dumpdata, di); | ||||
if (error < 0) | if (error < 0) | ||||
goto fail; | goto fail; | ||||
/* Dump trailer */ | /* Dump trailer */ | ||||
error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); | error = dump_write_pad(di, &kdh, 0, dumplo, sizeof(kdh), &size); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
/* Signal completion, signoff and exit stage left. */ | /* Signal completion, signoff and exit stage left. */ | ||||
dump_write(di, NULL, 0, 0, 0); | dump_write(di, NULL, 0, 0, 0); | ||||
printf("\nDump complete\n"); | printf("\nDump complete\n"); | ||||
return (0); | return (0); | ||||
Show All 13 Lines |
These defines are duplicated in sys/amd64/amd64/minidump_machdep.c (and i386). They should probably be consolidated in a header somewhere; perhaps 'sys/x86/include/dump.h'?