summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2002-04-02 10:51:32 +0000
committermarcel <marcel@FreeBSD.org>2002-04-02 10:51:32 +0000
commitb09f57883b0ea400be19cba5da214dbe0f17c98d (patch)
treebea0438bda5938a5da20ebe31bc0fd2910755d2c /sys/ia64
parent2af98633b5a43a3473d8551d81a144aaca0f132f (diff)
downloadFreeBSD-src-b09f57883b0ea400be19cba5da214dbe0f17c98d.zip
FreeBSD-src-b09f57883b0ea400be19cba5da214dbe0f17c98d.tar.gz
Initial implementation of the ia64 kernel dumper. The dumper
constructs an ELF image, consisting of the ELF header, for each memory region a program header, followed by the memory contents for each region. It does blocked I/O for the headers as they are typically smaller than DEV_BSIZE.
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/dump_machdep.c282
-rw-r--r--sys/ia64/ia64/ia64dump.c282
2 files changed, 564 insertions, 0 deletions
diff --git a/sys/ia64/ia64/dump_machdep.c b/sys/ia64/ia64/dump_machdep.c
new file mode 100644
index 0000000..a407070
--- /dev/null
+++ b/sys/ia64/ia64/dump_machdep.c
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/bootinfo.h>
+#include <machine/efi.h>
+#include <machine/elf.h>
+#include <machine/md_var.h>
+
+#define MD_ALIGN(x) (((off_t)(x) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK)
+
+typedef int callback_t(EFI_MEMORY_DESCRIPTOR*, int, void*);
+
+static struct kerneldumpheader kdh;
+static off_t dumplo, fileofs;
+
+/* Handle buffered writes. */
+static char buffer[DEV_BSIZE];
+static size_t fragsz;
+
+/* XXX should be MI */
+static void
+mkdumpheader(struct kerneldumpheader *kdh, uint32_t archver, uint64_t dumplen,
+ uint32_t blksz)
+{
+
+ if (sizeof(*kdh) != DEV_BSIZE) {
+ printf(
+ "Compiled struct kerneldumpheader is %d, not %d bytes\n",
+ sizeof(*kdh), DEV_BSIZE);
+ return;
+ }
+
+ bzero(kdh, sizeof(*kdh));
+ strncpy(kdh->magic, KERNELDUMPMAGIC, sizeof(kdh->magic));
+ strncpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture));
+ kdh->version = KERNELDUMPVERSION;
+ kdh->architectureversion = archver;
+ kdh->dumplength = dumplen;
+ kdh->blocksize = blksz;
+ kdh->dumptime = time_second;
+ strncpy(kdh->hostname, hostname, sizeof(kdh->hostname));
+ strncpy(kdh->versionstring, version, sizeof(kdh->versionstring));
+ if (panicstr != NULL)
+ strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring));
+ kdh->parity = kerneldump_parity(kdh);
+}
+
+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, NULL, 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, NULL, dumplo, DEV_BSIZE);
+ dumplo += DEV_BSIZE;
+ return (error);
+}
+
+static int
+cb_dumpdata(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ struct dumperinfo *di = (struct dumperinfo*)arg;
+ vm_offset_t pa;
+ uint64_t pgs;
+ size_t sz;
+ int error;
+
+ printf(" region %d:", seqnr);
+
+ error = 0; /* catch case in which mdp->NumberOfPages is 0 */
+ pgs = mdp->NumberOfPages;
+ pa = IA64_PHYS_TO_RR7(mdp->PhysicalStart);
+ while (pgs) {
+ sz = (pgs > (DFLTPHYS >> EFI_PAGE_SHIFT))
+ ? DFLTPHYS : pgs << EFI_PAGE_SHIFT;
+ printf(" %lld", pgs);
+ error = di->dumper(di->priv, (void*)pa, NULL, dumplo, sz);
+ if (error)
+ break;
+ dumplo += sz;
+ pgs -= sz >> EFI_PAGE_SHIFT;
+ pa += sz;
+ }
+ printf("\n");
+ return (error);
+}
+
+static int
+cb_dumphdr(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ struct dumperinfo *di = (struct dumperinfo*)arg;
+ Elf64_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 = mdp->VirtualStart; /* XXX probably bogus. */
+ phdr.p_paddr = mdp->PhysicalStart;
+ phdr.p_filesz = mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ phdr.p_memsz = mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ phdr.p_align = EFI_PAGE_SIZE;
+
+ error = buf_write(di->priv, (char*)&phdr, sizeof(phdr));
+ fileofs += phdr.p_filesz;
+ return (error);
+}
+
+static int
+cb_size(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ uint64_t *sz = (uint64_t*)arg;
+
+ *sz += (uint64_t)mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ return (0);
+}
+
+static int
+foreach_region(callback_t cb, void *arg)
+{
+ EFI_MEMORY_DESCRIPTOR *mdp;
+ int error, i, mdcount, seqnr;
+
+ mdp = (EFI_MEMORY_DESCRIPTOR *)IA64_PHYS_TO_RR7(bootinfo.bi_memmap);
+ mdcount = bootinfo.bi_memmap_size / bootinfo.bi_memdesc_size;
+
+ if (mdp == NULL || mdcount == 0)
+ return (0);
+
+ for (i = 0, seqnr = 0; i < mdcount; i++) {
+ if (mdp->Type == EfiConventionalMemory) {
+ error = (*cb)(mdp, seqnr++, arg);
+ if (error)
+ return (-error);
+ }
+ mdp = NextMemoryDescriptor(mdp, bootinfo.bi_memdesc_size);
+ }
+
+ return (seqnr);
+}
+
+void
+dumpsys(struct dumperinfo *di)
+{
+ Elf64_Ehdr ehdr;
+ uint64_t dumpsize;
+ 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] = ELFCLASS64;
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ 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_IA_64;
+ ehdr.e_phoff = sizeof(ehdr);
+ ehdr.e_flags = EF_IA_64_ABSOLUTE; /* XXX misuse? */
+ ehdr.e_ehsize = sizeof(ehdr);
+ ehdr.e_phentsize = sizeof(Elf64_Phdr);
+ ehdr.e_shentsize = sizeof(Elf64_Shdr);
+
+ /* Calculate dump size. */
+ dumpsize = 0L;
+ ehdr.e_phnum = foreach_region(cb_size, &dumpsize);
+ hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
+ fileofs = MD_ALIGN(hdrsz);
+ dumpsize += fileofs;
+
+ /* Determine dump offset on device. */
+ dumplo = di->mediaoffset + di->mediasize - dumpsize;
+ dumplo -= sizeof(kdh) * 2;
+
+ mkdumpheader(&kdh, KERNELDUMP_IA64_VERSION, dumpsize, di->blocksize);
+
+ printf("Dumping %llu MB (%d regions)\n", dumpsize >> 20, ehdr.e_phnum);
+
+ /* Dump leader */
+ error = di->dumper(di->priv, &kdh, NULL, 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_region(cb_dumphdr, di);
+ if (error < 0)
+ goto fail;
+ buf_flush(di);
+ dumplo += MD_ALIGN(hdrsz);
+
+ /* Dump region data (updates dumplo) */
+ error = foreach_region(cb_dumpdata, di);
+ if (error < 0)
+ goto fail;
+
+ /* Dump trailer */
+ error = di->dumper(di->priv, &kdh, NULL, dumplo, sizeof(kdh));
+ if (error)
+ goto fail;
+
+ /* Signal completion, signoff and exit stage left. */
+ di->dumper(di->priv, NULL, NULL, 0, 0);
+ printf("\nDump complete\n");
+ return;
+
+ fail:
+ if (error < 0)
+ error = -error;
+ /* XXX It should look more like VMS :-) */
+ printf("** DUMP FAILED (ERROR %d) **\n", error);
+}
diff --git a/sys/ia64/ia64/ia64dump.c b/sys/ia64/ia64/ia64dump.c
new file mode 100644
index 0000000..a407070
--- /dev/null
+++ b/sys/ia64/ia64/ia64dump.c
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/bootinfo.h>
+#include <machine/efi.h>
+#include <machine/elf.h>
+#include <machine/md_var.h>
+
+#define MD_ALIGN(x) (((off_t)(x) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK)
+
+typedef int callback_t(EFI_MEMORY_DESCRIPTOR*, int, void*);
+
+static struct kerneldumpheader kdh;
+static off_t dumplo, fileofs;
+
+/* Handle buffered writes. */
+static char buffer[DEV_BSIZE];
+static size_t fragsz;
+
+/* XXX should be MI */
+static void
+mkdumpheader(struct kerneldumpheader *kdh, uint32_t archver, uint64_t dumplen,
+ uint32_t blksz)
+{
+
+ if (sizeof(*kdh) != DEV_BSIZE) {
+ printf(
+ "Compiled struct kerneldumpheader is %d, not %d bytes\n",
+ sizeof(*kdh), DEV_BSIZE);
+ return;
+ }
+
+ bzero(kdh, sizeof(*kdh));
+ strncpy(kdh->magic, KERNELDUMPMAGIC, sizeof(kdh->magic));
+ strncpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture));
+ kdh->version = KERNELDUMPVERSION;
+ kdh->architectureversion = archver;
+ kdh->dumplength = dumplen;
+ kdh->blocksize = blksz;
+ kdh->dumptime = time_second;
+ strncpy(kdh->hostname, hostname, sizeof(kdh->hostname));
+ strncpy(kdh->versionstring, version, sizeof(kdh->versionstring));
+ if (panicstr != NULL)
+ strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring));
+ kdh->parity = kerneldump_parity(kdh);
+}
+
+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, NULL, 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, NULL, dumplo, DEV_BSIZE);
+ dumplo += DEV_BSIZE;
+ return (error);
+}
+
+static int
+cb_dumpdata(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ struct dumperinfo *di = (struct dumperinfo*)arg;
+ vm_offset_t pa;
+ uint64_t pgs;
+ size_t sz;
+ int error;
+
+ printf(" region %d:", seqnr);
+
+ error = 0; /* catch case in which mdp->NumberOfPages is 0 */
+ pgs = mdp->NumberOfPages;
+ pa = IA64_PHYS_TO_RR7(mdp->PhysicalStart);
+ while (pgs) {
+ sz = (pgs > (DFLTPHYS >> EFI_PAGE_SHIFT))
+ ? DFLTPHYS : pgs << EFI_PAGE_SHIFT;
+ printf(" %lld", pgs);
+ error = di->dumper(di->priv, (void*)pa, NULL, dumplo, sz);
+ if (error)
+ break;
+ dumplo += sz;
+ pgs -= sz >> EFI_PAGE_SHIFT;
+ pa += sz;
+ }
+ printf("\n");
+ return (error);
+}
+
+static int
+cb_dumphdr(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ struct dumperinfo *di = (struct dumperinfo*)arg;
+ Elf64_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 = mdp->VirtualStart; /* XXX probably bogus. */
+ phdr.p_paddr = mdp->PhysicalStart;
+ phdr.p_filesz = mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ phdr.p_memsz = mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ phdr.p_align = EFI_PAGE_SIZE;
+
+ error = buf_write(di->priv, (char*)&phdr, sizeof(phdr));
+ fileofs += phdr.p_filesz;
+ return (error);
+}
+
+static int
+cb_size(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg)
+{
+ uint64_t *sz = (uint64_t*)arg;
+
+ *sz += (uint64_t)mdp->NumberOfPages << EFI_PAGE_SHIFT;
+ return (0);
+}
+
+static int
+foreach_region(callback_t cb, void *arg)
+{
+ EFI_MEMORY_DESCRIPTOR *mdp;
+ int error, i, mdcount, seqnr;
+
+ mdp = (EFI_MEMORY_DESCRIPTOR *)IA64_PHYS_TO_RR7(bootinfo.bi_memmap);
+ mdcount = bootinfo.bi_memmap_size / bootinfo.bi_memdesc_size;
+
+ if (mdp == NULL || mdcount == 0)
+ return (0);
+
+ for (i = 0, seqnr = 0; i < mdcount; i++) {
+ if (mdp->Type == EfiConventionalMemory) {
+ error = (*cb)(mdp, seqnr++, arg);
+ if (error)
+ return (-error);
+ }
+ mdp = NextMemoryDescriptor(mdp, bootinfo.bi_memdesc_size);
+ }
+
+ return (seqnr);
+}
+
+void
+dumpsys(struct dumperinfo *di)
+{
+ Elf64_Ehdr ehdr;
+ uint64_t dumpsize;
+ 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] = ELFCLASS64;
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ 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_IA_64;
+ ehdr.e_phoff = sizeof(ehdr);
+ ehdr.e_flags = EF_IA_64_ABSOLUTE; /* XXX misuse? */
+ ehdr.e_ehsize = sizeof(ehdr);
+ ehdr.e_phentsize = sizeof(Elf64_Phdr);
+ ehdr.e_shentsize = sizeof(Elf64_Shdr);
+
+ /* Calculate dump size. */
+ dumpsize = 0L;
+ ehdr.e_phnum = foreach_region(cb_size, &dumpsize);
+ hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
+ fileofs = MD_ALIGN(hdrsz);
+ dumpsize += fileofs;
+
+ /* Determine dump offset on device. */
+ dumplo = di->mediaoffset + di->mediasize - dumpsize;
+ dumplo -= sizeof(kdh) * 2;
+
+ mkdumpheader(&kdh, KERNELDUMP_IA64_VERSION, dumpsize, di->blocksize);
+
+ printf("Dumping %llu MB (%d regions)\n", dumpsize >> 20, ehdr.e_phnum);
+
+ /* Dump leader */
+ error = di->dumper(di->priv, &kdh, NULL, 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_region(cb_dumphdr, di);
+ if (error < 0)
+ goto fail;
+ buf_flush(di);
+ dumplo += MD_ALIGN(hdrsz);
+
+ /* Dump region data (updates dumplo) */
+ error = foreach_region(cb_dumpdata, di);
+ if (error < 0)
+ goto fail;
+
+ /* Dump trailer */
+ error = di->dumper(di->priv, &kdh, NULL, dumplo, sizeof(kdh));
+ if (error)
+ goto fail;
+
+ /* Signal completion, signoff and exit stage left. */
+ di->dumper(di->priv, NULL, NULL, 0, 0);
+ printf("\nDump complete\n");
+ return;
+
+ fail:
+ if (error < 0)
+ error = -error;
+ /* XXX It should look more like VMS :-) */
+ printf("** DUMP FAILED (ERROR %d) **\n", error);
+}
OpenPOWER on IntegriCloud