xref: /openbsd-src/sys/kern/subr_hibernate.c (revision 627cf4e552a6ccafa816c382d13929a52c39a225)
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