1 /*- 2 * Copyright (c) 2008 Semihalf, Grzegorz Bernacki 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * from: FreeBSD: src/sys/i386/i386/minidump_machdep.c,v 1.6 2008/08/17 23:27:27 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_watchdog.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/cons.h> 38 #include <sys/kernel.h> 39 #include <sys/kerneldump.h> 40 #include <sys/msgbuf.h> 41 #ifdef SW_WATCHDOG 42 #include <sys/watchdog.h> 43 #endif 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 #include <machine/atomic.h> 47 #include <machine/elf.h> 48 #include <machine/md_var.h> 49 #include <machine/vmparam.h> 50 #include <machine/minidump.h> 51 #include <machine/cpufunc.h> 52 53 CTASSERT(sizeof(struct kerneldumpheader) == 512); 54 55 /* 56 * Don't touch the first SIZEOF_METADATA bytes on the dump device. This 57 * is to protect us from metadata and to protect metadata from us. 58 */ 59 #define SIZEOF_METADATA (64*1024) 60 61 uint32_t *vm_page_dump; 62 int vm_page_dump_size; 63 64 #ifndef ARM_NEW_PMAP 65 66 static struct kerneldumpheader kdh; 67 68 static off_t dumplo; 69 70 /* Handle chunked writes. */ 71 static size_t fragsz, offset; 72 static void *dump_va; 73 static uint64_t counter, progress; 74 75 CTASSERT(sizeof(*vm_page_dump) == 4); 76 77 static int 78 is_dumpable(vm_paddr_t pa) 79 { 80 int i; 81 82 for (i = 0; dump_avail[i] != 0 || dump_avail[i + 1] != 0; i += 2) { 83 if (pa >= dump_avail[i] && pa < dump_avail[i + 1]) 84 return (1); 85 } 86 return (0); 87 } 88 89 #define PG2MB(pgs) (((pgs) + (1 << 8) - 1) >> 8) 90 91 static int 92 blk_flush(struct dumperinfo *di) 93 { 94 int error; 95 96 if (fragsz == 0) 97 return (0); 98 99 error = dump_write(di, (char*)dump_va + offset, 0, dumplo, fragsz - offset); 100 dumplo += (fragsz - offset); 101 fragsz = 0; 102 offset = 0; 103 return (error); 104 } 105 106 static int 107 blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) 108 { 109 size_t len; 110 int error, i, c; 111 u_int maxdumpsz; 112 113 maxdumpsz = di->maxiosize; 114 115 if (maxdumpsz == 0) /* seatbelt */ 116 maxdumpsz = PAGE_SIZE; 117 118 error = 0; 119 120 if (ptr != NULL && pa != 0) { 121 printf("cant have both va and pa!\n"); 122 return (EINVAL); 123 } 124 125 if (ptr != NULL) { 126 /* If we're doing a virtual dump, flush any pre-existing pa pages */ 127 error = blk_flush(di); 128 if (error) 129 return (error); 130 } 131 132 while (sz) { 133 if (fragsz == 0) { 134 offset = pa & PAGE_MASK; 135 fragsz += offset; 136 } 137 len = maxdumpsz - fragsz; 138 if (len > sz) 139 len = sz; 140 counter += len; 141 progress -= len; 142 143 if (counter >> 22) { 144 printf(" %lld", PG2MB(progress >> PAGE_SHIFT)); 145 counter &= (1<<22) - 1; 146 } 147 148 #ifdef SW_WATCHDOG 149 wdog_kern_pat(WD_LASTVAL); 150 #endif 151 if (ptr) { 152 error = dump_write(di, ptr, 0, dumplo, len); 153 if (error) 154 return (error); 155 dumplo += len; 156 ptr += len; 157 sz -= len; 158 } else { 159 for (i = 0; i < len; i += PAGE_SIZE) 160 dump_va = pmap_kenter_temporary(pa + i, 161 (i + fragsz) >> PAGE_SHIFT); 162 fragsz += len; 163 pa += len; 164 sz -= len; 165 if (fragsz == maxdumpsz) { 166 error = blk_flush(di); 167 if (error) 168 return (error); 169 } 170 } 171 172 /* Check for user abort. */ 173 c = cncheckc(); 174 if (c == 0x03) 175 return (ECANCELED); 176 if (c != -1) 177 printf(" (CTRL-C to abort) "); 178 } 179 180 return (0); 181 } 182 183 static int 184 blk_write_cont(struct dumperinfo *di, vm_paddr_t pa, size_t sz) 185 { 186 int error; 187 188 error = blk_write(di, 0, pa, sz); 189 if (error) 190 return (error); 191 192 error = blk_flush(di); 193 if (error) 194 return (error); 195 196 return (0); 197 } 198 199 /* A fake page table page, to avoid having to handle both 4K and 2M pages */ 200 static pt_entry_t fakept[NPTEPG]; 201 202 int 203 minidumpsys(struct dumperinfo *di) 204 { 205 struct minidumphdr mdhdr; 206 uint64_t dumpsize; 207 uint32_t ptesize; 208 uint32_t bits; 209 uint32_t pa, prev_pa = 0, count = 0; 210 vm_offset_t va; 211 pd_entry_t *pdp; 212 pt_entry_t *pt, *ptp; 213 int i, k, bit, error; 214 char *addr; 215 216 /* 217 * Flush caches. Note that in the SMP case this operates only on the 218 * current CPU's L1 cache. Before we reach this point, code in either 219 * the system shutdown or kernel debugger has called stop_cpus() to stop 220 * all cores other than this one. Part of the ARM handling of 221 * stop_cpus() is to call wbinv_all() on that core's local L1 cache. So 222 * by time we get to here, all that remains is to flush the L1 for the 223 * current CPU, then the L2. 224 */ 225 cpu_idcache_wbinv_all(); 226 cpu_l2cache_wbinv_all(); 227 228 counter = 0; 229 /* Walk page table pages, set bits in vm_page_dump */ 230 ptesize = 0; 231 for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) { 232 /* 233 * We always write a page, even if it is zero. Each 234 * page written corresponds to 2MB of space 235 */ 236 ptesize += L2_TABLE_SIZE_REAL; 237 pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp); 238 if (pmap_pde_v(pdp) && pmap_pde_section(pdp)) { 239 /* This is a section mapping 1M page. */ 240 pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK); 241 for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) { 242 if (is_dumpable(pa)) 243 dump_add_page(pa); 244 pa += PAGE_SIZE; 245 } 246 continue; 247 } 248 if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) { 249 /* Set bit for each valid page in this 1MB block */ 250 addr = pmap_kenter_temporary(*pdp & L1_C_ADDR_MASK, 0); 251 pt = (pt_entry_t*)(addr + 252 (((uint32_t)*pdp & L1_C_ADDR_MASK) & PAGE_MASK)); 253 for (k = 0; k < 256; k++) { 254 if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_L) { 255 pa = (pt[k] & L2_L_FRAME) | 256 (va & L2_L_OFFSET); 257 for (i = 0; i < 16; i++) { 258 if (is_dumpable(pa)) 259 dump_add_page(pa); 260 k++; 261 pa += PAGE_SIZE; 262 } 263 } else if ((pt[k] & L2_TYPE_MASK) == L2_TYPE_S) { 264 pa = (pt[k] & L2_S_FRAME) | 265 (va & L2_S_OFFSET); 266 if (is_dumpable(pa)) 267 dump_add_page(pa); 268 } 269 } 270 } else { 271 /* Nothing, we're going to dump a null page */ 272 } 273 } 274 275 /* Calculate dump size. */ 276 dumpsize = ptesize; 277 dumpsize += round_page(msgbufp->msg_size); 278 dumpsize += round_page(vm_page_dump_size); 279 280 for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { 281 bits = vm_page_dump[i]; 282 while (bits) { 283 bit = ffs(bits) - 1; 284 pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + 285 bit) * PAGE_SIZE; 286 /* Clear out undumpable pages now if needed */ 287 if (is_dumpable(pa)) 288 dumpsize += PAGE_SIZE; 289 else 290 dump_drop_page(pa); 291 bits &= ~(1ul << bit); 292 } 293 } 294 295 dumpsize += PAGE_SIZE; 296 297 /* Determine dump offset on device. */ 298 if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) { 299 error = ENOSPC; 300 goto fail; 301 } 302 303 dumplo = di->mediaoffset + di->mediasize - dumpsize; 304 dumplo -= sizeof(kdh) * 2; 305 progress = dumpsize; 306 307 /* Initialize mdhdr */ 308 bzero(&mdhdr, sizeof(mdhdr)); 309 strcpy(mdhdr.magic, MINIDUMP_MAGIC); 310 mdhdr.version = MINIDUMP_VERSION; 311 mdhdr.msgbufsize = msgbufp->msg_size; 312 mdhdr.bitmapsize = vm_page_dump_size; 313 mdhdr.ptesize = ptesize; 314 mdhdr.kernbase = KERNBASE; 315 mdhdr.arch = __ARM_ARCH; 316 #if __ARM_ARCH >= 6 317 mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V6; 318 #else 319 mdhdr.mmuformat = MINIDUMP_MMU_FORMAT_V4; 320 #endif 321 mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize, 322 di->blocksize); 323 324 printf("Physical memory: %u MB\n", ptoa((uintmax_t)physmem) / 1048576); 325 printf("Dumping %llu MB:", (long long)dumpsize >> 20); 326 327 /* Dump leader */ 328 error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 329 if (error) 330 goto fail; 331 dumplo += sizeof(kdh); 332 333 /* Dump my header */ 334 bzero(&fakept, sizeof(fakept)); 335 bcopy(&mdhdr, &fakept, sizeof(mdhdr)); 336 error = blk_write(di, (char *)&fakept, 0, PAGE_SIZE); 337 if (error) 338 goto fail; 339 340 /* Dump msgbuf up front */ 341 error = blk_write(di, (char *)msgbufp->msg_ptr, 0, round_page(msgbufp->msg_size)); 342 if (error) 343 goto fail; 344 345 /* Dump bitmap */ 346 error = blk_write(di, (char *)vm_page_dump, 0, 347 round_page(vm_page_dump_size)); 348 if (error) 349 goto fail; 350 351 /* Dump kernel page table pages */ 352 for (va = KERNBASE; va < kernel_vm_end; va += NBPDR) { 353 /* We always write a page, even if it is zero */ 354 pmap_get_pde_pte(pmap_kernel(), va, &pdp, &ptp); 355 356 if (pmap_pde_v(pdp) && pmap_pde_section(pdp)) { 357 if (count) { 358 error = blk_write_cont(di, prev_pa, 359 count * L2_TABLE_SIZE_REAL); 360 if (error) 361 goto fail; 362 count = 0; 363 prev_pa = 0; 364 } 365 /* This is a single 2M block. Generate a fake PTP */ 366 pa = (*pdp & L1_S_ADDR_MASK) | (va & ~L1_S_ADDR_MASK); 367 for (k = 0; k < (L1_S_SIZE / PAGE_SIZE); k++) { 368 fakept[k] = L2_S_PROTO | (pa + (k * PAGE_SIZE)) | 369 L2_S_PROT(PTE_KERNEL, 370 VM_PROT_READ | VM_PROT_WRITE); 371 } 372 error = blk_write(di, (char *)&fakept, 0, 373 L2_TABLE_SIZE_REAL); 374 if (error) 375 goto fail; 376 /* Flush, in case we reuse fakept in the same block */ 377 error = blk_flush(di); 378 if (error) 379 goto fail; 380 continue; 381 } 382 if (pmap_pde_v(pdp) && pmap_pde_page(pdp)) { 383 pa = *pdp & L1_C_ADDR_MASK; 384 if (!count) { 385 prev_pa = pa; 386 count++; 387 } 388 else { 389 if (pa == (prev_pa + count * L2_TABLE_SIZE_REAL)) 390 count++; 391 else { 392 error = blk_write_cont(di, prev_pa, 393 count * L2_TABLE_SIZE_REAL); 394 if (error) 395 goto fail; 396 count = 1; 397 prev_pa = pa; 398 } 399 } 400 } else { 401 if (count) { 402 error = blk_write_cont(di, prev_pa, 403 count * L2_TABLE_SIZE_REAL); 404 if (error) 405 goto fail; 406 count = 0; 407 prev_pa = 0; 408 } 409 bzero(fakept, sizeof(fakept)); 410 error = blk_write(di, (char *)&fakept, 0, 411 L2_TABLE_SIZE_REAL); 412 if (error) 413 goto fail; 414 /* Flush, in case we reuse fakept in the same block */ 415 error = blk_flush(di); 416 if (error) 417 goto fail; 418 } 419 } 420 421 if (count) { 422 error = blk_write_cont(di, prev_pa, count * L2_TABLE_SIZE_REAL); 423 if (error) 424 goto fail; 425 count = 0; 426 prev_pa = 0; 427 } 428 429 /* Dump memory chunks */ 430 for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { 431 bits = vm_page_dump[i]; 432 while (bits) { 433 bit = ffs(bits) - 1; 434 pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + 435 bit) * PAGE_SIZE; 436 if (!count) { 437 prev_pa = pa; 438 count++; 439 } else { 440 if (pa == (prev_pa + count * PAGE_SIZE)) 441 count++; 442 else { 443 error = blk_write_cont(di, prev_pa, 444 count * PAGE_SIZE); 445 if (error) 446 goto fail; 447 count = 1; 448 prev_pa = pa; 449 } 450 } 451 bits &= ~(1ul << bit); 452 } 453 } 454 if (count) { 455 error = blk_write_cont(di, prev_pa, count * PAGE_SIZE); 456 if (error) 457 goto fail; 458 count = 0; 459 prev_pa = 0; 460 } 461 462 /* Dump trailer */ 463 error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 464 if (error) 465 goto fail; 466 dumplo += sizeof(kdh); 467 468 /* Signal completion, signoff and exit stage left. */ 469 dump_write(di, NULL, 0, 0, 0); 470 printf("\nDump complete\n"); 471 return (0); 472 473 fail: 474 if (error < 0) 475 error = -error; 476 477 if (error == ECANCELED) 478 printf("\nDump aborted\n"); 479 else if (error == ENOSPC) 480 printf("\nDump failed. Partition too small.\n"); 481 else 482 printf("\n** DUMP FAILED (ERROR %d) **\n", error); 483 return (error); 484 return (0); 485 } 486 487 #else /* ARM_NEW_PMAP */ 488 489 int 490 minidumpsys(struct dumperinfo *di) 491 { 492 493 return (0); 494 } 495 496 #endif 497 498 void 499 dump_add_page(vm_paddr_t pa) 500 { 501 int idx, bit; 502 503 pa >>= PAGE_SHIFT; 504 idx = pa >> 5; /* 2^5 = 32 */ 505 bit = pa & 31; 506 atomic_set_int(&vm_page_dump[idx], 1ul << bit); 507 } 508 509 void 510 dump_drop_page(vm_paddr_t pa) 511 { 512 int idx, bit; 513 514 pa >>= PAGE_SHIFT; 515 idx = pa >> 5; /* 2^5 = 32 */ 516 bit = pa & 31; 517 atomic_clear_int(&vm_page_dump[idx], 1ul << bit); 518 } 519