diff options
| -rw-r--r-- | sys/conf/files.sparc64 | 1 | ||||
| -rw-r--r-- | sys/kern/kern_shutdown.c | 2 | ||||
| -rw-r--r-- | sys/sparc64/include/kerneldump.h | 51 | ||||
| -rw-r--r-- | sys/sparc64/include/ofw_mem.h | 43 | ||||
| -rw-r--r-- | sys/sparc64/sparc64/dump_machdep.c | 252 | ||||
| -rw-r--r-- | sys/sparc64/sparc64/pmap.c | 53 | ||||
| -rw-r--r-- | sys/sys/kerneldump.h | 1 |
7 files changed, 234 insertions, 169 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 6956b995ba4b..8562b26c9c0c 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -40,6 +40,7 @@ sparc64/sparc64/db_disasm.c optional ddb sparc64/sparc64/db_interface.c optional ddb sparc64/sparc64/db_trace.c optional ddb sparc64/sparc64/db_hwwatch.c optional ddb +sparc64/sparc64/dump_machdep.c standard sparc64/sparc64/elf_machdep.c standard # locore.S and exception.S need to be handled in the Makefile to put them # first. Otherwise they're normal. diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index f8f676e6a04c..16eaae601a2a 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -572,7 +572,7 @@ set_dumper(struct dumperinfo *di) return (0); } -#if defined(__powerpc__) || defined(__sparc64__) +#if defined(__powerpc__) void dumpsys(struct dumperinfo *di __unused) { diff --git a/sys/sparc64/include/kerneldump.h b/sys/sparc64/include/kerneldump.h new file mode 100644 index 000000000000..9ee7db509b3f --- /dev/null +++ b/sys/sparc64/include/kerneldump.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>. + * 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 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_KERNELDUMP_H_ +#define _MACHINE_KERNELDUMP_H_ + +struct sparc64_dump_reg { + vm_offset_t dr_pa; + vm_offset_t dr_size; + vm_offset_t dr_offs; +}; + +/* + * Kernel dump format for sparc64. This does not use ELF because it is of no + * avail (only libkvm knows how to translate addresses properly anyway) and + * would require some ugly hacks. + */ +struct sparc64_dump_hdr { + vm_offset_t dh_hdr_size; + vm_offset_t dh_tsb_pa; + vm_size_t dh_tsb_size; + vm_size_t dh_tsb_mask; + int dh_nregions; + struct sparc64_dump_reg dh_regions[]; +}; + +#endif /* _MACHINE_KERNELDUMP_H_ */ diff --git a/sys/sparc64/include/ofw_mem.h b/sys/sparc64/include/ofw_mem.h new file mode 100644 index 000000000000..36e734764a11 --- /dev/null +++ b/sys/sparc64/include/ofw_mem.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2001 Jake Burkholder. + * 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_OFW_MEM_H_ +#define _MACHINE_OFW_MEM_H_ + +struct ofw_mem_region { + vm_offset_t mr_start; + vm_offset_t mr_size; +}; + +struct ofw_map { + vm_offset_t om_start; + vm_offset_t om_size; + u_long om_tte; +}; + +#endif diff --git a/sys/sparc64/sparc64/dump_machdep.c b/sys/sparc64/sparc64/dump_machdep.c index 4afa31f11814..b42cb855f802 100644 --- a/sys/sparc64/sparc64/dump_machdep.c +++ b/sys/sparc64/sparc64/dump_machdep.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2002 Marcel Moolenaar + * Copyright (c) 2002 Thomas Moestl * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,28 +30,31 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> +#include <sys/cons.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> -CTASSERT(sizeof(struct kerneldumpheader) == 512); +#include <machine/metadata.h> +#include <machine/kerneldump.h> +#include <machine/ofw_mem.h> +#include <machine/tsb.h> -#define MD_ALIGN(x) (((off_t)(x) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK) -#define DEV_ALIGN(x) (((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1)) +CTASSERT(sizeof(struct kerneldumpheader) == DEV_BSIZE); -typedef int callback_t(EFI_MEMORY_DESCRIPTOR*, int, void*); +extern struct ofw_mem_region sparc64_memreg[]; +extern int sparc64_nmemreg; static struct kerneldumpheader kdh; -static off_t dumplo, fileofs; +static off_t dumplo, dumppos; /* Handle buffered writes. */ static char buffer[DEV_BSIZE]; -static size_t fragsz; +static vm_size_t fragsz; + +#define MAXDUMPSZ (MAXDUMPPGS << PAGE_SHIFT) /* XXX should be MI */ static void @@ -88,7 +92,7 @@ buf_write(struct dumperinfo *di, char *ptr, size_t sz) ptr += len; sz -= len; if (fragsz == DEV_BSIZE) { - error = di->dumper(di->priv, buffer, NULL, dumplo, + error = di->dumper(di->priv, buffer, 0, dumplo, DEV_BSIZE); if (error) return error; @@ -108,192 +112,136 @@ buf_flush(struct dumperinfo *di) if (fragsz == 0) return (0); - error = di->dumper(di->priv, buffer, NULL, dumplo, DEV_BSIZE); + error = di->dumper(di->priv, buffer, 0, dumplo, DEV_BSIZE); dumplo += DEV_BSIZE; return (error); } static int -cb_dumpdata(EFI_MEMORY_DESCRIPTOR *mdp, int seqnr, void *arg) +reg_write(struct dumperinfo *di, vm_offset_t pa, vm_size_t size) { - struct dumperinfo *di = (struct dumperinfo*)arg; - vm_offset_t pa; - uint64_t pgs; - size_t counter, sz; - int error, twiddle; - - error = 0; /* catch case in which mdp->NumberOfPages is 0 */ - counter = 0; /* Update twiddle every 16MB */ - twiddle = 0; - pgs = mdp->NumberOfPages; - pa = IA64_PHYS_TO_RR7(mdp->PhysicalStart); - - printf(" chunk %d: %ld pages ", seqnr, (long)pgs); - - while (pgs) { - sz = (pgs > (DFLTPHYS >> EFI_PAGE_SHIFT)) - ? DFLTPHYS : pgs << EFI_PAGE_SHIFT; - counter += sz; - if (counter >> 24) { - printf("%c\b", "|/-\\"[twiddle++ & 3]); - counter &= (1<<24) - 1; - } - error = di->dumper(di->priv, (void*)pa, NULL, dumplo, sz); - if (error) - break; - dumplo += sz; - pgs -= sz >> EFI_PAGE_SHIFT; - pa += sz; - } - printf("... %s\n", (error) ? "fail" : "ok"); - return (error); -} + struct sparc64_dump_reg r; -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); + r.dr_pa = pa; + r.dr_size = size; + r.dr_offs = dumppos; + dumppos += size; + return (buf_write(di, (char *)&r, sizeof(r))); } static int -foreach_chunk(callback_t cb, void *arg) +blk_dump(struct dumperinfo *di, vm_offset_t pa, vm_size_t size) { - EFI_MEMORY_DESCRIPTOR *mdp; - int error, i, mdcount, seqnr; + vm_size_t pos, npg, rsz; + void *va; + int c, counter, error, i, twiddle; - mdp = (EFI_MEMORY_DESCRIPTOR *)IA64_PHYS_TO_RR7(bootinfo.bi_memmap); - mdcount = bootinfo.bi_memmap_size / bootinfo.bi_memdesc_size; + printf(" chunk at %#lx: %ld bytes ", (u_long)pa, (long)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); + va = NULL; + 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; + npg = rsz >> PAGE_SHIFT; + for (i = 0; i < npg; i++) + va = pmap_kenter_temporary(pa + pos + i * PAGE_SIZE, i); + error = di->dumper(di->priv, 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) "); } - - return (seqnr); + printf("... %s\n", (error) ? "fail" : "ok"); + return (error); } void dumpsys(struct dumperinfo *di) { - Elf64_Ehdr ehdr; - uint64_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] = ELFCLASS64; -#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_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); + struct sparc64_dump_hdr hdr; + vm_size_t size, totsize, hdrsize; + int error, i, nreg; /* 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); + size = 0; + nreg = sparc64_nmemreg; + for (i = 0; i < sparc64_nmemreg; i++) + size += sparc64_memreg[i].mr_size; + /* Account for the header size. */ + hdrsize = roundup2(sizeof(hdr) + sizeof(struct sparc64_dump_reg) * nreg, + DEV_BSIZE); + size += hdrsize; + + totsize = size + 2 * sizeof(kdh); + if (totsize > di->mediasize) { + printf("Insufficient space on device (need %ld, have %ld), " + "refusing to dump.\n", (long)totsize, + (long)di->mediasize); + error = ENOSPC; + goto fail; + } /* Determine dump offset on device. */ - dumplo = di->mediaoffset + di->mediasize - dumpsize; - dumplo -= sizeof(kdh) * 2; + dumplo = di->mediaoffset + di->mediasize - totsize; - mkdumpheader(&kdh, KERNELDUMP_IA64_VERSION, dumpsize, di->blocksize); + mkdumpheader(&kdh, KERNELDUMP_SPARC64_VERSION, size, di->blocksize); - printf("Dumping %llu MB (%d chunks)\n", dumpsize >> 20, ehdr.e_phnum); + printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); /* Dump leader */ - error = di->dumper(di->priv, &kdh, NULL, dumplo, sizeof(kdh)); + error = di->dumper(di->priv, &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 the private header. */ + hdr.dh_hdr_size = hdrsize; + hdr.dh_tsb_pa = tsb_kernel_phys; + hdr.dh_tsb_size = tsb_kernel_size; + hdr.dh_tsb_mask = tsb_kernel_mask; + hdr.dh_nregions = nreg; - /* Dump program headers */ - error = foreach_chunk(cb_dumphdr, di); - if (error < 0) + if (buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) goto fail; + + dumppos = hdrsize; + /* Now, write out the region descriptors. */ + for (i = 0; i < sparc64_nmemreg; i++) { + error = reg_write(di, sparc64_memreg[i].mr_start, + sparc64_memreg[i].mr_size); + 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 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; + } /* Dump trailer */ - error = di->dumper(di->priv, &kdh, NULL, dumplo, sizeof(kdh)); + error = di->dumper(di->priv, &kdh, 0, dumplo, sizeof(kdh)); if (error) goto fail; /* Signal completion, signoff and exit stage left. */ - di->dumper(di->priv, NULL, NULL, 0, 0); + di->dumper(di->priv, NULL, 0, 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/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c index 586435e41962..485349cceb99 100644 --- a/sys/sparc64/sparc64/pmap.c +++ b/sys/sparc64/sparc64/pmap.c @@ -96,6 +96,7 @@ #include <machine/instr.h> #include <machine/md_var.h> #include <machine/metadata.h> +#include <machine/ofw_mem.h> #include <machine/smp.h> #include <machine/tlb.h> #include <machine/tte.h> @@ -107,17 +108,6 @@ #define PMAP_SHPGPERPROC 200 #endif -struct mem_region { - vm_offset_t mr_start; - vm_offset_t mr_size; -}; - -struct ofw_map { - vm_offset_t om_start; - vm_offset_t om_size; - u_long om_tte; -}; - /* * Virtual and physical address of message buffer. */ @@ -136,7 +126,9 @@ int pmap_pagedaemon_waken; * Map of physical memory reagions. */ vm_offset_t phys_avail[128]; -static struct mem_region mra[128]; +static struct ofw_mem_region mra[128]; +struct ofw_mem_region sparc64_memreg[128]; +int sparc64_nmemreg; static struct ofw_map translations[128]; static int translations_size; @@ -149,6 +141,8 @@ vm_offset_t kernel_vm_end; vm_offset_t vm_max_kernel_address; +static vm_offset_t crashdumpmap; + /* * Kernel pmap. */ @@ -235,8 +229,8 @@ static int om_cmp(const void *a, const void *b); static int mr_cmp(const void *a, const void *b) { - const struct mem_region *mra; - const struct mem_region *mrb; + const struct ofw_mem_region *mra; + const struct ofw_mem_region *mrb; mra = a; mrb = b; @@ -317,6 +311,19 @@ pmap_bootstrap(vm_offset_t ekva) tsb_kernel_mask = (tsb_kernel_size >> TTE_SHIFT) - 1; /* + * Get the available physical memory ranges from /memory/reg. These + * are only used for kernel dumps, but it may not be wise to do prom + * calls in that situation. + */ + if ((sz = OF_getproplen(pmem, "reg")) == -1) + panic("pmap_bootstrap: getproplen /memory/reg"); + if (sizeof(sparc64_memreg) < sz) + panic("pmap_bootstrap: sparc64_memreg too small"); + if (OF_getprop(pmem, "reg", sparc64_memreg, sz) == -1) + panic("pmap_bootstrap: getprop /memory/reg"); + sparc64_nmemreg = sz / sizeof(*sparc64_memreg); + + /* * Set the start and end of kva. The kernel is loaded at the first * available 4 meg super page, so round up to the end of the page. */ @@ -460,6 +467,12 @@ pmap_bootstrap(vm_offset_t ekva) virtual_avail += round_page(MSGBUF_SIZE); /* + * Allocate virtual address space to map pages during a kernel dump. + */ + crashdumpmap = virtual_avail; + virtual_avail += MAXDUMPPGS * PAGE_SIZE; + + /* * Initialize the kernel pmap (which is statically allocated). */ pm = kernel_pmap; @@ -813,13 +826,21 @@ pmap_kenter_flags(vm_offset_t va, vm_offset_t pa, u_long flags) /* * Make a temporary mapping for a physical address. This is only intended - * to be used for panic dumps. + * to be used for panic dumps. Caching issues can be ignored completely here, + * because pages mapped this way are only read. */ void * pmap_kenter_temporary(vm_offset_t pa, int i) { + struct tte *tp; + vm_offset_t va; - panic("pmap_kenter_temporary"); + va = crashdumpmap + i * PAGE_SIZE; + tlb_page_demap(kernel_pmap, va); + tp = tsb_kvtotte(va); + tp->tte_vpn = TV_VPN(va, TS_8K); + tp->tte_data = TD_V | TD_8K | TD_PA(pa) | TD_REF | TD_CP | TD_CV | TD_P; + return ((void *)crashdumpmap); } /* diff --git a/sys/sys/kerneldump.h b/sys/sys/kerneldump.h index 6ab3854fa247..ae49ad5776cf 100644 --- a/sys/sys/kerneldump.h +++ b/sys/sys/kerneldump.h @@ -68,6 +68,7 @@ struct kerneldumpheader { #define KERNELDUMP_ALPHA_VERSION 1 #define KERNELDUMP_I386_VERSION 1 #define KERNELDUMP_IA64_VERSION 1 +#define KERNELDUMP_SPARC64_VERSION 1 uint64_t dumplength; /* excl headers */ uint64_t dumptime; uint32_t blocksize; |
