1 /* $OpenBSD: subr_hibernate.c,v 1.11 2011/07/09 01:30:39 mlarkin Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/hibernate.h> 20 #include <sys/malloc.h> 21 #include <sys/param.h> 22 #include <sys/tree.h> 23 #include <sys/types.h> 24 #include <sys/systm.h> 25 #include <sys/disklabel.h> 26 #include <sys/conf.h> 27 #include <uvm/uvm.h> 28 #include <machine/hibernate.h> 29 30 extern char *disk_readlabel(struct disklabel *, dev_t, char *, size_t); 31 32 struct hibernate_state *hibernate_state; 33 34 /* 35 * Hib alloc enforced alignment. 36 */ 37 #define HIB_ALIGN 8 /* bytes alignment */ 38 39 /* 40 * sizeof builtin operation, but with alignment constraint. 41 */ 42 #define HIB_SIZEOF(_type) roundup(sizeof(_type), HIB_ALIGN) 43 44 struct hiballoc_entry 45 { 46 size_t hibe_use; 47 size_t hibe_space; 48 RB_ENTRY(hiballoc_entry) hibe_entry; 49 }; 50 51 /* 52 * Compare hiballoc entries based on the address they manage. 53 * 54 * Since the address is fixed, relative to struct hiballoc_entry, 55 * we just compare the hiballoc_entry pointers. 56 */ 57 static __inline int 58 hibe_cmp(struct hiballoc_entry *l, struct hiballoc_entry *r) 59 { 60 return l < r ? -1 : (l > r); 61 } 62 63 RB_PROTOTYPE(hiballoc_addr, hiballoc_entry, hibe_entry, hibe_cmp) 64 65 /* 66 * Given a hiballoc entry, return the address it manages. 67 */ 68 static __inline void* 69 hib_entry_to_addr(struct hiballoc_entry *entry) 70 { 71 caddr_t addr; 72 73 addr = (caddr_t)entry; 74 addr += HIB_SIZEOF(struct hiballoc_entry); 75 return addr; 76 } 77 78 /* 79 * Given an address, find the hiballoc that corresponds. 80 */ 81 static __inline struct hiballoc_entry* 82 hib_addr_to_entry(void* addr_param) 83 { 84 caddr_t addr; 85 86 addr = (caddr_t)addr_param; 87 addr -= HIB_SIZEOF(struct hiballoc_entry); 88 return (struct hiballoc_entry*)addr; 89 } 90 91 RB_GENERATE(hiballoc_addr, hiballoc_entry, hibe_entry, hibe_cmp) 92 93 /* 94 * Allocate memory from the arena. 95 * 96 * Returns NULL if no memory is available. 97 */ 98 void* 99 hib_alloc(struct hiballoc_arena *arena, size_t alloc_sz) 100 { 101 struct hiballoc_entry *entry, *new_entry; 102 size_t find_sz; 103 104 /* 105 * Enforce alignment of HIB_ALIGN bytes. 106 * 107 * Note that, because the entry is put in front of the allocation, 108 * 0-byte allocations are guaranteed a unique address. 109 */ 110 alloc_sz = roundup(alloc_sz, HIB_ALIGN); 111 112 /* 113 * Find an entry with hibe_space >= find_sz. 114 * 115 * If the root node is not large enough, we switch to tree traversal. 116 * Because all entries are made at the bottom of the free space, 117 * traversal from the end has a slightly better chance of yielding 118 * a sufficiently large space. 119 */ 120 find_sz = alloc_sz + HIB_SIZEOF(struct hiballoc_entry); 121 entry = RB_ROOT(&arena->hib_addrs); 122 if (entry != NULL && entry->hibe_space < find_sz) { 123 RB_FOREACH_REVERSE(entry, hiballoc_addr, &arena->hib_addrs) { 124 if (entry->hibe_space >= find_sz) 125 break; 126 } 127 } 128 129 /* 130 * Insufficient or too fragmented memory. 131 */ 132 if (entry == NULL) 133 return NULL; 134 135 /* 136 * Create new entry in allocated space. 137 */ 138 new_entry = (struct hiballoc_entry*)( 139 (caddr_t)hib_entry_to_addr(entry) + entry->hibe_use); 140 new_entry->hibe_space = entry->hibe_space - find_sz; 141 new_entry->hibe_use = alloc_sz; 142 143 /* 144 * Insert entry. 145 */ 146 if (RB_INSERT(hiballoc_addr, &arena->hib_addrs, new_entry) != NULL) 147 panic("hib_alloc: insert failure"); 148 entry->hibe_space = 0; 149 150 /* Return address managed by entry. */ 151 return hib_entry_to_addr(new_entry); 152 } 153 154 /* 155 * Free a pointer previously allocated from this arena. 156 * 157 * If addr is NULL, this will be silently accepted. 158 */ 159 void 160 hib_free(struct hiballoc_arena *arena, void *addr) 161 { 162 struct hiballoc_entry *entry, *prev; 163 164 if (addr == NULL) 165 return; 166 167 /* 168 * Derive entry from addr and check it is really in this arena. 169 */ 170 entry = hib_addr_to_entry(addr); 171 if (RB_FIND(hiballoc_addr, &arena->hib_addrs, entry) != entry) 172 panic("hib_free: freed item %p not in hib arena", addr); 173 174 /* 175 * Give the space in entry to its predecessor. 176 * 177 * If entry has no predecessor, change its used space into free space 178 * instead. 179 */ 180 prev = RB_PREV(hiballoc_addr, &arena->hib_addrs, entry); 181 if (prev != NULL && 182 (void*)((caddr_t)prev + HIB_SIZEOF(struct hiballoc_entry) + 183 prev->hibe_use + prev->hibe_space) == entry) { 184 /* Merge entry. */ 185 RB_REMOVE(hiballoc_addr, &arena->hib_addrs, entry); 186 prev->hibe_space += HIB_SIZEOF(struct hiballoc_entry) + 187 entry->hibe_use + entry->hibe_space; 188 } else { 189 /* Flip used memory to free space. */ 190 entry->hibe_space += entry->hibe_use; 191 entry->hibe_use = 0; 192 } 193 } 194 195 /* 196 * Initialize hiballoc. 197 * 198 * The allocator will manage memmory at ptr, which is len bytes. 199 */ 200 int 201 hiballoc_init(struct hiballoc_arena *arena, void *p_ptr, size_t p_len) 202 { 203 struct hiballoc_entry *entry; 204 caddr_t ptr; 205 size_t len; 206 207 RB_INIT(&arena->hib_addrs); 208 209 /* 210 * Hib allocator enforces HIB_ALIGN alignment. 211 * Fixup ptr and len. 212 */ 213 ptr = (caddr_t)roundup((vaddr_t)p_ptr, HIB_ALIGN); 214 len = p_len - ((size_t)ptr - (size_t)p_ptr); 215 len &= ~((size_t)HIB_ALIGN - 1); 216 217 /* 218 * Insufficient memory to be able to allocate and also do bookkeeping. 219 */ 220 if (len <= HIB_SIZEOF(struct hiballoc_entry)) 221 return ENOMEM; 222 223 /* 224 * Create entry describing space. 225 */ 226 entry = (struct hiballoc_entry*)ptr; 227 entry->hibe_use = 0; 228 entry->hibe_space = len - HIB_SIZEOF(struct hiballoc_entry); 229 RB_INSERT(hiballoc_addr, &arena->hib_addrs, entry); 230 231 return 0; 232 } 233 234 235 /* 236 * Zero all free memory. 237 */ 238 void 239 uvm_pmr_zero_everything(void) 240 { 241 struct uvm_pmemrange *pmr; 242 struct vm_page *pg; 243 int i; 244 245 uvm_lock_fpageq(); 246 TAILQ_FOREACH(pmr, &uvm.pmr_control.use, pmr_use) { 247 /* Zero single pages. */ 248 while ((pg = TAILQ_FIRST(&pmr->single[UVM_PMR_MEMTYPE_DIRTY])) 249 != NULL) { 250 uvm_pmr_remove(pmr, pg); 251 uvm_pagezero(pg); 252 atomic_setbits_int(&pg->pg_flags, PG_ZERO); 253 uvmexp.zeropages++; 254 uvm_pmr_insert(pmr, pg, 0); 255 } 256 257 /* Zero multi page ranges. */ 258 while ((pg = RB_ROOT(&pmr->size[UVM_PMR_MEMTYPE_DIRTY])) 259 != NULL) { 260 pg--; /* Size tree always has second page. */ 261 uvm_pmr_remove(pmr, pg); 262 for (i = 0; i < pg->fpgsz; i++) { 263 uvm_pagezero(&pg[i]); 264 atomic_setbits_int(&pg[i].pg_flags, PG_ZERO); 265 uvmexp.zeropages++; 266 } 267 uvm_pmr_insert(pmr, pg, 0); 268 } 269 } 270 uvm_unlock_fpageq(); 271 } 272 273 /* 274 * Mark all memory as dirty. 275 * 276 * Used to inform the system that the clean memory isn't clean for some 277 * reason, for example because we just came back from hibernate. 278 */ 279 void 280 uvm_pmr_dirty_everything(void) 281 { 282 struct uvm_pmemrange *pmr; 283 struct vm_page *pg; 284 int i; 285 286 uvm_lock_fpageq(); 287 TAILQ_FOREACH(pmr, &uvm.pmr_control.use, pmr_use) { 288 /* Dirty single pages. */ 289 while ((pg = TAILQ_FIRST(&pmr->single[UVM_PMR_MEMTYPE_ZERO])) 290 != NULL) { 291 uvm_pmr_remove(pmr, pg); 292 atomic_clearbits_int(&pg->pg_flags, PG_ZERO); 293 uvm_pmr_insert(pmr, pg, 0); 294 } 295 296 /* Dirty multi page ranges. */ 297 while ((pg = RB_ROOT(&pmr->size[UVM_PMR_MEMTYPE_ZERO])) 298 != NULL) { 299 pg--; /* Size tree always has second page. */ 300 uvm_pmr_remove(pmr, pg); 301 for (i = 0; i < pg->fpgsz; i++) 302 atomic_clearbits_int(&pg[i].pg_flags, PG_ZERO); 303 uvm_pmr_insert(pmr, pg, 0); 304 } 305 } 306 307 uvmexp.zeropages = 0; 308 uvm_unlock_fpageq(); 309 } 310 311 /* 312 * Allocate the highest address that can hold sz. 313 * 314 * sz in bytes. 315 */ 316 int 317 uvm_pmr_alloc_pig(paddr_t *addr, psize_t sz) 318 { 319 struct uvm_pmemrange *pmr; 320 struct vm_page *pig_pg, *pg; 321 322 /* 323 * Convert sz to pages, since that is what pmemrange uses internally. 324 */ 325 sz = atop(round_page(sz)); 326 327 uvm_lock_fpageq(); 328 329 TAILQ_FOREACH(pmr, &uvm.pmr_control.use, pmr_use) { 330 RB_FOREACH_REVERSE(pig_pg, uvm_pmr_addr, &pmr->addr) { 331 if (pig_pg->fpgsz >= sz) { 332 goto found; 333 } 334 } 335 } 336 337 /* 338 * Allocation failure. 339 */ 340 uvm_unlock_pageq(); 341 return ENOMEM; 342 343 found: 344 /* Remove page from freelist. */ 345 uvm_pmr_remove_size(pmr, pig_pg); 346 pig_pg->fpgsz -= sz; 347 pg = pig_pg + pig_pg->fpgsz; 348 if (pig_pg->fpgsz == 0) 349 uvm_pmr_remove_addr(pmr, pig_pg); 350 else 351 uvm_pmr_insert_size(pmr, pig_pg); 352 353 uvmexp.free -= sz; 354 *addr = VM_PAGE_TO_PHYS(pg); 355 356 /* 357 * Update pg flags. 358 * 359 * Note that we trash the sz argument now. 360 */ 361 while (sz > 0) { 362 KASSERT(pg->pg_flags & PQ_FREE); 363 364 atomic_clearbits_int(&pg->pg_flags, 365 PG_PMAP0|PG_PMAP1|PG_PMAP2|PG_PMAP3); 366 367 if (pg->pg_flags & PG_ZERO) 368 uvmexp.zeropages -= sz; 369 atomic_clearbits_int(&pg->pg_flags, 370 PG_ZERO|PQ_FREE); 371 372 pg->uobject = NULL; 373 pg->uanon = NULL; 374 pg->pg_version++; 375 376 /* 377 * Next. 378 */ 379 pg++; 380 sz--; 381 } 382 383 /* Return. */ 384 uvm_unlock_fpageq(); 385 return 0; 386 } 387 388 /* 389 * Allocate a piglet area. 390 * 391 * This is as low as possible. 392 * Piglets are aligned. 393 * 394 * sz and align in bytes. 395 * 396 * The call will sleep for the pagedaemon to attempt to free memory. 397 * The pagedaemon may decide its not possible to free enough memory, causing 398 * the allocation to fail. 399 */ 400 int 401 uvm_pmr_alloc_piglet(paddr_t *addr, psize_t sz, paddr_t align) 402 { 403 vaddr_t pg_addr, piglet_addr; 404 struct uvm_pmemrange *pmr; 405 struct vm_page *pig_pg, *pg; 406 struct pglist pageq; 407 int pdaemon_woken; 408 409 KASSERT((align & (align - 1)) == 0); 410 pdaemon_woken = 0; /* Didn't wake the pagedaemon. */ 411 412 /* 413 * Fixup arguments: align must be at least PAGE_SIZE, 414 * sz will be converted to pagecount, since that is what 415 * pmemrange uses internally. 416 */ 417 if (align < PAGE_SIZE) 418 align = PAGE_SIZE; 419 sz = atop(round_page(sz)); 420 421 uvm_lock_fpageq(); 422 423 TAILQ_FOREACH_REVERSE(pmr, &uvm.pmr_control.use, uvm_pmemrange_use, 424 pmr_use) { 425 retry: 426 /* 427 * Search for a range with enough space. 428 * Use the address tree, to ensure the range is as low as 429 * possible. 430 */ 431 RB_FOREACH(pig_pg, uvm_pmr_addr, &pmr->addr) { 432 pg_addr = VM_PAGE_TO_PHYS(pig_pg); 433 piglet_addr = (pg_addr + (align - 1)) & ~(align - 1); 434 435 if (pig_pg->fpgsz >= sz) { 436 goto found; 437 } 438 439 if (atop(pg_addr) + pig_pg->fpgsz > 440 atop(piglet_addr) + sz) { 441 goto found; 442 } 443 } 444 445 /* 446 * Try to coerse the pagedaemon into freeing memory 447 * for the piglet. 448 * 449 * pdaemon_woken is set to prevent the code from 450 * falling into an endless loop. 451 */ 452 if (!pdaemon_woken) { 453 pdaemon_woken = 1; 454 if (uvm_wait_pla(ptoa(pmr->low), ptoa(pmr->high) - 1, 455 ptoa(sz), UVM_PLA_FAILOK) == 0) 456 goto retry; 457 } 458 } 459 460 /* Return failure. */ 461 uvm_unlock_fpageq(); 462 return ENOMEM; 463 464 found: 465 /* 466 * Extract piglet from pigpen. 467 */ 468 TAILQ_INIT(&pageq); 469 uvm_pmr_extract_range(pmr, pig_pg, 470 atop(piglet_addr), atop(piglet_addr) + sz, &pageq); 471 472 *addr = piglet_addr; 473 uvmexp.free -= sz; 474 475 /* 476 * Update pg flags. 477 * 478 * Note that we trash the sz argument now. 479 */ 480 TAILQ_FOREACH(pg, &pageq, pageq) { 481 KASSERT(pg->pg_flags & PQ_FREE); 482 483 atomic_clearbits_int(&pg->pg_flags, 484 PG_PMAP0|PG_PMAP1|PG_PMAP2|PG_PMAP3); 485 486 if (pg->pg_flags & PG_ZERO) 487 uvmexp.zeropages--; 488 atomic_clearbits_int(&pg->pg_flags, 489 PG_ZERO|PQ_FREE); 490 491 pg->uobject = NULL; 492 pg->uanon = NULL; 493 pg->pg_version++; 494 } 495 496 uvm_unlock_fpageq(); 497 return 0; 498 } 499 500 /* 501 * Physmem RLE compression support. 502 * 503 * Given a physical page address, it will return the number of pages 504 * starting at the address, that are free. 505 * Returns 0 if the page at addr is not free. 506 */ 507 psize_t 508 uvm_page_rle(paddr_t addr) 509 { 510 struct vm_page *pg, *pg_end; 511 struct vm_physseg *vmp; 512 int pseg_idx, off_idx; 513 514 pseg_idx = vm_physseg_find(atop(addr), &off_idx); 515 if (pseg_idx == -1) 516 return 0; 517 518 vmp = &vm_physmem[pseg_idx]; 519 pg = &vmp->pgs[off_idx]; 520 if (!(pg->pg_flags & PQ_FREE)) 521 return 0; 522 523 /* 524 * Search for the first non-free page after pg. 525 * Note that the page may not be the first page in a free pmemrange, 526 * therefore pg->fpgsz cannot be used. 527 */ 528 for (pg_end = pg; pg_end <= vmp->lastpg && 529 (pg_end->pg_flags & PQ_FREE) == PQ_FREE; pg_end++); 530 return pg_end - pg; 531 } 532 533 /* 534 * get_hibernate_info 535 * 536 * Fills out the hibernate_info union pointed to by hiber_info 537 * with information about this machine (swap signature block 538 * offsets, number of memory ranges, kernel in use, etc) 539 * 540 */ 541 int 542 get_hibernate_info(union hibernate_info *hiber_info) 543 { 544 int chunktable_size; 545 struct disklabel dl; 546 char err_string[128], *dl_ret; 547 548 /* Determine I/O function to use */ 549 hiber_info->io_func = get_hibernate_io_function(); 550 if (hiber_info->io_func == NULL) 551 return (1); 552 553 /* Calculate hibernate device */ 554 hiber_info->device = swdevt[0].sw_dev; 555 556 /* Read disklabel (used to calculate signature and image offsets) */ 557 dl_ret = disk_readlabel(&dl, hiber_info->device, err_string, 128); 558 559 if (dl_ret) { 560 printf("Hibernate error reading disklabel: %s\n", dl_ret); 561 return (1); 562 } 563 564 hiber_info->secsize = dl.d_secsize; 565 566 /* Make sure the signature can fit in one block */ 567 KASSERT(sizeof(union hibernate_info)/hiber_info->secsize == 1); 568 569 /* Calculate swap offset from start of disk */ 570 hiber_info->swap_offset = dl.d_partitions[1].p_offset; 571 572 /* Calculate signature block location */ 573 hiber_info->sig_offset = dl.d_partitions[1].p_offset + 574 dl.d_partitions[1].p_size - 575 sizeof(union hibernate_info)/hiber_info->secsize; 576 577 chunktable_size = HIBERNATE_CHUNK_TABLE_SIZE / hiber_info->secsize; 578 579 /* Calculate memory image location */ 580 hiber_info->image_offset = dl.d_partitions[1].p_offset + 581 dl.d_partitions[1].p_size - 582 (hiber_info->image_size / hiber_info->secsize) - 583 sizeof(union hibernate_info)/hiber_info->secsize - 584 chunktable_size; 585 586 /* Stash kernel version information */ 587 bzero(&hiber_info->kernel_version, 128); 588 bcopy(version, &hiber_info->kernel_version, 589 min(strlen(version), sizeof(hiber_info->kernel_version)-1)); 590 591 /* Allocate piglet region */ 592 if (uvm_pmr_alloc_piglet(&hiber_info->piglet_base, HIBERNATE_CHUNK_SIZE, 593 HIBERNATE_CHUNK_SIZE)) { 594 printf("Hibernate failed to allocate the piglet\n"); 595 return (1); 596 } 597 598 return get_hibernate_info_md(hiber_info); 599 } 600 601 /* 602 * hibernate_zlib_alloc 603 * 604 * Allocate nitems*size bytes from the hiballoc area presently in use 605 * 606 */ 607 void 608 *hibernate_zlib_alloc(void *unused, int nitems, int size) 609 { 610 return hib_alloc(&hibernate_state->hiballoc_arena, nitems*size); 611 } 612 613 /* 614 * hibernate_zlib_free 615 * 616 * Free the memory pointed to by addr in the hiballoc area presently in 617 * use 618 * 619 */ 620 void 621 hibernate_zlib_free(void *unused, void *addr) 622 { 623 hib_free(&hibernate_state->hiballoc_arena, addr); 624 } 625 626 /* 627 * hibernate_inflate 628 * 629 * Inflate size bytes from src into dest, skipping any pages in 630 * [src..dest] that are special (see hibernate_inflate_skip) 631 * 632 * For each page of output data, we map HIBERNATE_TEMP_PAGE 633 * to the current output page, and tell inflate() to inflate 634 * its data there, resulting in the inflated data being placed 635 * at the proper paddr. 636 * 637 * This function executes while using the resume-time stack 638 * and pmap, and therefore cannot use ddb/printf/etc. Doing so 639 * will likely hang or reset the machine. 640 * 641 */ 642 void 643 hibernate_inflate(paddr_t dest, paddr_t src, size_t size) 644 { 645 int i; 646 647 hibernate_state->hib_stream.avail_in = size; 648 hibernate_state->hib_stream.next_in = (char *)src; 649 650 do { 651 /* Flush cache and TLB */ 652 hibernate_flush(); 653 654 /* 655 * Is this a special page? If yes, redirect the 656 * inflate output to a scratch page (eg, discard it) 657 */ 658 if (hibernate_inflate_skip(dest)) 659 hibernate_enter_resume_mapping(HIBERNATE_TEMP_PAGE, 660 HIBERNATE_TEMP_PAGE, 0); 661 else 662 hibernate_enter_resume_mapping(HIBERNATE_TEMP_PAGE, 663 dest, 0); 664 665 /* Set up the stream for inflate */ 666 hibernate_state->hib_stream.avail_out = PAGE_SIZE; 667 hibernate_state->hib_stream.next_out = 668 (char *)HIBERNATE_TEMP_PAGE; 669 670 /* Process next block of data */ 671 i = inflate(&hibernate_state->hib_stream, Z_PARTIAL_FLUSH); 672 if (i != Z_OK && i != Z_STREAM_END) { 673 /* 674 * XXX - this will likely reboot/hang most machines, 675 * but there's not much else we can do here. 676 */ 677 panic("inflate error"); 678 } 679 680 dest += PAGE_SIZE - hibernate_state->hib_stream.avail_out; 681 } while (i != Z_STREAM_END); 682 } 683 684 /* 685 * hibernate_deflate 686 * 687 * deflate from src into the I/O page, up to 'remaining' bytes 688 * 689 * Returns number of input bytes consumed, and may reset 690 * the 'remaining' parameter if not all the output space was consumed 691 * (this information is needed to know how much to write to disk 692 * 693 */ 694 size_t 695 hibernate_deflate(paddr_t src, size_t *remaining) 696 { 697 /* Set up the stream for deflate */ 698 hibernate_state->hib_stream.avail_in = PAGE_SIZE - 699 (src & PAGE_MASK); 700 hibernate_state->hib_stream.avail_out = *remaining; 701 hibernate_state->hib_stream.next_in = (caddr_t)src; 702 hibernate_state->hib_stream.next_out = (caddr_t)HIBERNATE_IO_PAGE + 703 (PAGE_SIZE - *remaining); 704 705 /* Process next block of data */ 706 if (deflate(&hibernate_state->hib_stream, Z_PARTIAL_FLUSH) != Z_OK) 707 panic("hibernate zlib deflate error\n"); 708 709 /* Update pointers and return number of bytes consumed */ 710 *remaining = hibernate_state->hib_stream.avail_out; 711 return (PAGE_SIZE - (src & PAGE_MASK)) - 712 hibernate_state->hib_stream.avail_in; 713 } 714 715 /* 716 * hibernate_write_signature 717 * 718 * Write the hibernation information specified in hiber_info 719 * to the location in swap previously calculated (last block of 720 * swap), called the "signature block". 721 * 722 * Write the memory chunk table to the area in swap immediately 723 * preceding the signature block. 724 */ 725 int 726 hibernate_write_signature(union hibernate_info *hiber_info) 727 { 728 u_int8_t *io_page; 729 daddr_t chunkbase; 730 size_t i; 731 732 io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 733 if (!io_page) 734 return (1); 735 736 /* Write hibernate info to disk */ 737 if( hiber_info->io_func(hiber_info->device, hiber_info->sig_offset, 738 (vaddr_t)hiber_info, hiber_info->secsize, 1, io_page)) 739 panic("error in hibernate write sig\n"); 740 741 chunkbase = hiber_info->sig_offset - 742 (HIBERNATE_CHUNK_TABLE_SIZE / hiber_info->secsize); 743 744 /* Write chunk table */ 745 for(i=0; i < HIBERNATE_CHUNK_TABLE_SIZE; i += NBPG) { 746 if(hiber_info->io_func(hiber_info->device, 747 chunkbase + (i/hiber_info->secsize), 748 (vaddr_t)(HIBERNATE_CHUNK_TABLE_START + i), 749 NBPG, 750 1, 751 io_page)) 752 panic("error in hibernate write chunks\n"); 753 } 754 755 free(io_page, M_DEVBUF); 756 757 return (0); 758 } 759 760 /* 761 * hibernate_clear_signature 762 * 763 * Write an empty hiber_info to the swap signature block, which is 764 * guaranteed to not match any valid hiber_info. 765 */ 766 int 767 hibernate_clear_signature() 768 { 769 union hibernate_info blank_hiber_info; 770 union hibernate_info hiber_info; 771 u_int8_t *io_page; 772 773 /* Zero out a blank hiber_info */ 774 bzero(&blank_hiber_info, sizeof(hiber_info)); 775 776 if (get_hibernate_info(&hiber_info)) 777 return (1); 778 779 io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 780 if (!io_page) 781 return (1); 782 783 /* Write (zeroed) hibernate info to disk */ 784 if(hiber_info.io_func(hiber_info.device, hiber_info.sig_offset, 785 (vaddr_t)&blank_hiber_info, hiber_info.secsize, 1, io_page)) 786 panic("error hibernate write 6\n"); 787 788 free(io_page, M_DEVBUF); 789 790 return (0); 791 } 792 793 /* 794 * hibernate_check_overlap 795 * 796 * Check chunk range overlap when calculating whether or not to copy a 797 * compressed chunk to the piglet area before decompressing. 798 * 799 * returns zero if the ranges do not overlap, non-zero otherwise. 800 */ 801 int 802 hibernate_check_overlap(paddr_t r1s, paddr_t r1e, paddr_t r2s, paddr_t r2e) 803 { 804 /* case A : end of r1 overlaps start of r2 */ 805 if (r1s < r2s && r1e > r2s) 806 return (1); 807 808 /* case B : r1 entirely inside r2 */ 809 if (r1s >= r2s && r1e <= r2e) 810 return (1); 811 812 /* case C : r2 entirely inside r1 */ 813 if (r2s >= r1s && r2e <= r1e) 814 return (1); 815 816 /* case D : end of r2 overlaps start of r1 */ 817 if (r2s < r1s && r2e > r1s) 818 return (1); 819 820 return (0); 821 } 822