1 From 4ce00daa904a40701ab6bed44506fe97b8f1da47 Mon Sep 17 00:00:00 2001
2 From: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
3 Date: Fri, 19 May 2017 14:48:38 +0900
4 Subject: [PATCH 3/4] Add Hibernation swsuspmem command support
6 Signed-off-by: Yuichi Kusakabe <yuichi.kusakabe@jp.fujitsu.com>
9 common/cmd_swsuspmem.c | 944 +++++++++++++++++++++++++++++++++++++++++++++
10 include/swsuspmem.h | 24 ++
11 lib/lzo/lzo1x_decompress.c | 12 +-
12 4 files changed, 980 insertions(+), 2 deletions(-)
13 create mode 100644 common/cmd_swsuspmem.c
14 create mode 100644 include/swsuspmem.h
16 diff --git a/common/Makefile b/common/Makefile
17 index 54fcc81..7a18486 100644
20 @@ -160,6 +160,8 @@ COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o
21 COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o
22 COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o
23 COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o
24 +COBJS-$(CONFIG_CMD_SWSUSP) += cmd_swsusp.o
25 +COBJS-$(CONFIG_CMD_SWSUSPMEM) += cmd_swsuspmem.o
26 COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o
27 COBJS-$(CONFIG_CMD_TIME) += cmd_time.o
28 COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o
29 diff --git a/common/cmd_swsuspmem.c b/common/cmd_swsuspmem.c
31 index 0000000..6980aaf
33 +++ b/common/cmd_swsuspmem.c
36 + * This program is free software; you can redistribute it and/or modify
37 + * it under the terms of the GNU General Public License as published by
38 + * the Free Software Foundation; either version 2 of the License, or
39 + * (at your option) any later version.
41 + * This program is distributed in the hope that it will be useful,
42 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 + * GNU General Public License for more details.
46 + * You should have received a copy of the GNU General Public License
47 + * along with this program; if not, write to the Free Software
48 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
56 +#include <linux/lzo.h>
57 +#include "../arch/arm/cpu/armv7/rmobile/crc32_word4.h"
58 +#include <swsuspmem.h>
60 +/* Note for Renesas--based boards:
61 + * We have the following memory split here:
62 + * 0x40000000 - u_boot_lowest - used to store pfns at physical addresses
63 + * u_boot_lowest - 0x8000000 - pfns are relocated, and then later put
64 + * on physical addresses (swsusp_finish)
65 + * 0x8000000 - 0xc0000000 - used to store pfns with physical address
66 + * of 0x200000000 (long address), we have to change offset for them.
67 + * Any pfn with address > 0x8000000 but less than 0x200000000
69 + * For boards which do not have memory above first GB, that will
70 + * still work, as they won't have anything above 0x80000000
71 + * in their image, so for standard 2GB setup ou should put
72 + * your secong GB in 0x80000000-0xC0000000 range, you can
73 + * use MMU for that or if your RAM is continous, it will
74 + * naturally be there. */
76 +DECLARE_GLOBAL_DATA_PTR;
78 +/* #define PAGEMAP_DEBUG */
81 +#define SWSUSP_DEBUG_INFO
84 +#define SWSUSP_KEEP_IMAGE
87 +# define likely(x) __builtin_expect(!!(x), 1)
88 +# define unlikely(x) __builtin_expect(!!(x), 0)
91 +#define HIBERNATE_SIG "S1SUSPEND"
92 +#define PAGE_SIZE (4096)
93 +/* Define depending on CONFIG_LBDAF in kernel */
95 +typedef u64 sector_t;
97 +struct swsusp_header {
98 + char reserved[PAGE_SIZE - 20
99 + - sizeof(sector_t) - sizeof(int) - sizeof(u32)
100 + - sizeof(CRC32_WORD4_t) - sizeof(u32)];
101 + CRC32_WORD4_t comp_crc32;
102 + u32 img_size; /* append */
105 + unsigned int flags;
110 +#define __NEW_UTS_LEN 64
112 +struct new_utsname {
113 + char sysname[__NEW_UTS_LEN + 1];
114 + char nodename[__NEW_UTS_LEN + 1];
115 + char release[__NEW_UTS_LEN + 1];
116 + char version[__NEW_UTS_LEN + 1];
117 + char machine[__NEW_UTS_LEN + 1];
118 + char domainname[__NEW_UTS_LEN + 1];
121 +struct swsusp_archdata {
122 + u32 nosave_backup_phys;
123 + u32 nosave_begin_phys;
124 + u32 nosave_end_phys;
125 + void (*cpu_resume_restore_nosave)(u32, u32, u32);
128 +struct swsusp_info {
129 + struct new_utsname uts;
131 + unsigned long num_physpages;
133 + unsigned long image_pages;
134 + unsigned long pages;
135 + unsigned long size;
136 + char archdata[1024];
139 +struct swap_map_page {
140 + u64 entries[PAGE_SIZE / sizeof(u64) - 1];
144 +struct swsusp_finish_context {
145 + void *remap_orig_page;
146 + void *remap_temp_page;
147 + struct swsusp_archdata archdata;
149 +#ifdef FTEN_SPF_SDRAM_BASE
150 +#define USED_ADDRESS_TOP (CONFIG_SYS_SDRAM_BASE)
151 +#define USED_ADDRESS_END (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_LOAD_OFFSET)
153 +#define USED_ADDRESS_TOP (0x40000000)
154 +#define USED_ADDRESS_END (0x48000000)
156 +#define PG_UB2ZERO(pg) ((pg) - CONFIG_SYS_SDRAM_BASE / PAGE_SIZE)
157 +static u32 const exclude_min_page =
158 + (USED_ADDRESS_TOP) / PAGE_SIZE;
159 +static u32 const exclude_max_page =
160 + (USED_ADDRESS_END - 1) / PAGE_SIZE;
161 +static u32 const exclude_min_page_ub =
162 + PG_UB2ZERO((USED_ADDRESS_TOP) / PAGE_SIZE);
163 +static u32 const exclude_max_page_ub =
164 + PG_UB2ZERO((USED_ADDRESS_END-1) / PAGE_SIZE);
167 + #define SD_PLATFORM_MODE 1
168 + #define SD_CRC32_MODE 4
170 +#define SF_NOCOMPRESS_MODE 2
172 +#define LZO_HEADER sizeof(size_t)
174 +/* Number of pages/bytes we'll compress at one time. */
175 +#define LZO_UNC_PAGES 32
176 +#define LZO_UNC_SIZE (LZO_UNC_PAGES * PAGE_SIZE)
178 +/* Number of pages/bytes we need for compressed data (worst case). */
179 +#define LZO_CMP_PAGES DIV_ROUND_UP(lzo1x_worst_compress(LZO_UNC_SIZE) + \
180 + LZO_HEADER, PAGE_SIZE)
181 +#define LZO_CMP_SIZE (LZO_CMP_PAGES * PAGE_SIZE)
183 +static struct swsuspmem_hook *_hook;
185 +#define CALL_HOOK(f, param) \
187 + if (_hook != NULL) { \
188 + if (_hook->f != NULL) \
193 +#ifdef PAGEMAP_DEBUG
194 +static int debugout;
195 +static int _last_read_pages;
196 +#define PAGEMAP_INFO(_msg, ...) \
198 + if (debugout == 1) \
199 + printf(_msg, ## __VA_ARGS__); \
203 +#define HIGHMEM_PHYS_ADDR 0x200000000ULL
204 +#define HIGHMEM_VA 0x80000000UL
205 +#define HIGHMEM_PFN (HIGHMEM_PHYS_ADDR / PAGE_SIZE)
206 +#define LOW_TOP 0x80000000
207 +#define LOW_TOP_PFN (LOW_TOP / PAGE_SIZE)
208 +#define LOW_BOTTOM CONFIG_SYS_SDRAM_BASE
209 +#define LOW_BOTTOM_PFN (LOW_BOTTOM / PAGE_SIZE)
210 +#define TOP_ADDRESS 0x240000000ULL
212 +static inline int pfn_is_low(u32 pfn)
214 + return ((pfn >= LOW_BOTTOM_PFN) && (pfn < LOW_TOP_PFN));
217 +static inline int pfn_is_high(u32 pfn)
219 + return (pfn >= HIGHMEM_PFN);
222 +#define pfn_is_valid(p) (pfn_is_low(p) || pfn_is_high(p))
224 +static inline int pfn_is_excluded(u32 pfn)
226 + /* Allow bottom 2 pages for exception vectors */
227 + if (pfn < (LOW_BOTTOM_PFN + 2))
229 + else if (exclude_min_page >= exclude_max_page)
232 + return (pfn >= exclude_min_page) && (pfn <= exclude_max_page);
234 +/* PFN to zero-counted page */
235 +static inline u32 pg_ub2zero(u32 pg)
237 + return pg - LOW_BOTTOM_PFN;
240 +/* zero-counted page to PFN */
241 +static inline u32 pg_zero2ub(u32 pg)
243 + return pg + LOW_BOTTOM_PFN;
246 +/* PFN to physical address (64-bit (40-bit)) */
247 +static inline u64 pg2phys(u32 page)
249 + return (u64) page * PAGE_SIZE;
252 +/* PFN to virtual address */
253 +static inline void *pg2addr(u32 page)
256 + if (page >= HIGHMEM_PFN)
257 + addr = (void *) (u32)(pg2phys(page - HIGHMEM_PFN) + HIGHMEM_VA);
259 + addr = (void *) (u32)pg2phys(page);
263 +/* Virtual address to PFN */
264 +static inline u32 addr2pg(void *addr)
266 + return ((u32)(addr)) / PAGE_SIZE;
268 +static void *offt_addr = (void *)0x44000000;
269 +static int page_read_mem(u64 page, void *addr)
271 + memcpy(addr, (u8 *)offt_addr + page * PAGE_SIZE, PAGE_SIZE);
275 +#ifndef SWSUSP_KEEP_IMAGE
276 +static int page_write_mem(u32 page, void *addr)
278 + memcpy((u8 *)offt_addr + page * PAGE_SIZE, addr, PAGE_SIZE);
284 +static void __attribute__((section(".rodata")))
285 + __attribute__((optimize("O6", "unroll-loops")))
286 +swsusp_finish(void *userdata)
288 + struct swsusp_finish_context *context = userdata;
292 + const int lastidx = PAGE_SIZE / sizeof(u32) - 1;
294 + remap_orig = context->remap_orig_page;
295 + remap_temp = context->remap_temp_page;
297 + __asm__ volatile ("" : : : "memory");
302 + /* Linked list to next page */
303 + if (idx == lastidx) {
304 + remap_orig = (u32 **)remap_orig[idx];
305 + remap_temp = (u32 **)remap_temp[idx];
308 + if (unlikely(!remap_orig || remap_orig[idx] == (u32 *)~0UL))
310 + orig = remap_orig[idx];
311 + temp = remap_temp[idx];
313 + count = PAGE_SIZE / sizeof(u32) / 32;
316 + "ldmia %[rtemp]!, {r0-r7}\n"
317 + "stmia %[rorig]!, {r0-r7}\n"
318 + "ldmia %[rtemp]!, {r0-r7}\n"
319 + "stmia %[rorig]!, {r0-r7}\n"
320 + "ldmia %[rtemp]!, {r0-r7}\n"
321 + "stmia %[rorig]!, {r0-r7}\n"
322 + "ldmia %[rtemp]!, {r0-r7}\n"
323 + "subs %[count], %[count], #1\n"
324 + "stmia %[rorig]!, {r0-r7}\n"
331 + : "r0", "r1", "r2", "r3",
332 + "r4", "r5", "r6", "r7",
336 + count = PAGE_SIZE / sizeof(u32);
340 +#ifdef SWSUSP_CHECK_COPY_RESULT
341 + count = PAGE_SIZE / sizeof(u32);
342 + orig = remap_orig[idx];
343 + temp = remap_temp[idx];
346 + "ldr r3, [%[rorig]]\n"
347 + "ldr r4, [%[rtemp]]\n"
350 + "add %[rorig], %[rorig], #4\n"
351 + "add %[rtemp], %[rtemp], #4\n"
352 + "subs %[count], %[count], #1\n"
358 + [rorig]"+r" (orig),
359 + [rtemp]"+r" (temp),
360 + [count]"+r" (count)
362 + : "r3", "r4", "cc", "memory"
367 + context->archdata.cpu_resume_restore_nosave(
368 + context->archdata.nosave_backup_phys,
369 + context->archdata.nosave_begin_phys,
370 + context->archdata.nosave_end_phys);
373 +static struct swap_map_page *meta_map;
374 +static u64 meta_map_next;
375 +static u64 meta_map_curr;
376 +static u64 meta_map_start;
377 +static int meta_idx;
379 +static int raw_page_init(u64 start)
381 + meta_map = malloc(PAGE_SIZE);
386 + meta_map_start = start;
390 +static void raw_page_start(void)
392 + meta_idx = ARRAY_SIZE(meta_map->entries);
393 + meta_map_next = meta_map_start;
396 +static int raw_page_get_next(void *buffer)
398 + if (meta_idx == ARRAY_SIZE(meta_map->entries)) {
399 + if (!meta_map_next)
401 + if (meta_map_curr != meta_map_next) {
402 +#ifdef PAGEMAP_DEBUG
403 + PAGEMAP_INFO("META: %d (%08x)\n", (int)meta_map_next,
404 + (unsigned int)(meta_map_next
407 + if (page_read_mem(meta_map_next, meta_map))
409 + meta_map_curr = meta_map_next;
410 + meta_map_next = meta_map->next_swap;
414 +#ifdef PAGEMAP_DEBUG
416 + static unsigned int pre;
417 + if ((pre + 1) != meta_map->entries[meta_idx]) {
418 + PAGEMAP_INFO("DATA-Skiped: %d->%d (%08x->%08x)\n",
419 + pre, (unsigned int)meta_map->entries[meta_idx],
421 + (unsigned int)(meta_map->entries[meta_idx]
424 + pre = meta_map->entries[meta_idx];
425 + _last_read_pages = pre;
428 + if (page_read_mem(meta_map->entries[meta_idx++], buffer))
434 +static void raw_page_exit(void)
440 +static int image_pages_avail;
441 +static unsigned char *unc_buf, *cmp_buf;
442 +static int unc_offset;
444 +static int image_page_init(int compressed)
449 + unc_buf = malloc(LZO_UNC_SIZE);
450 + cmp_buf = malloc(LZO_CMP_SIZE);
451 + if (!unc_buf || !cmp_buf) {
452 + printf("not enogh memory\n");
458 +static void image_page_start(void)
460 + image_pages_avail = 0;
463 +static int image_page_get_next(void *buffer)
466 + if (!image_pages_avail) {
468 + size_t unc_len, cmp_len, cmp_avail;
470 + ret = raw_page_get_next(cmp_buf);
474 + cmp_len = *(size_t *) cmp_buf;
475 + cmp_avail = PAGE_SIZE;
477 + while (cmp_avail < cmp_len + LZO_HEADER) {
478 + ret = raw_page_get_next(cmp_buf + cmp_avail);
479 + if (unlikely(ret <= 0))
481 + cmp_avail += PAGE_SIZE;
484 + unc_len = LZO_UNC_SIZE;
485 + ret = lzo1x_decompress_safe(cmp_buf + LZO_HEADER,
486 + cmp_len, unc_buf, &unc_len);
487 + if (unlikely(ret != LZO_E_OK)) {
488 + printf("Decompression failure: %d,"
490 + " cmp_len = %d, unc_len = %d\n",
491 + ret, cmp_buf + LZO_HEADER, cmp_len,
495 + image_pages_avail = unc_len / PAGE_SIZE;
499 + memcpy(buffer, unc_buf + unc_offset, PAGE_SIZE);
500 + unc_offset += PAGE_SIZE;
501 + image_pages_avail--;
504 + printf("No LZO support in u-boot.\n");
509 +static void image_page_exit(void)
513 + unc_buf = cmp_buf = NULL;
516 +static void bitmap_set(u32 *bm, unsigned int bit)
518 + bm[bit >> 5] |= (1 << (bit & 0x1f));
521 +static int bitmap_is_set(u32 *bm, unsigned int bit)
523 + return !!(bm[bit >> 5] & (1 << (bit & 0x1f)));
526 +static u32 *used_bitmap;
527 +static u32 next_free_page;
528 +static u32 total_pages;
530 +static int free_page_init(void)
532 + total_pages = (u32)((TOP_ADDRESS -
533 + LOW_BOTTOM) / PAGE_SIZE); /* 2GB */
534 + used_bitmap = malloc(total_pages * sizeof(u32) / 32);
540 +static void free_page_start(int offset)
542 + memset(used_bitmap, 0, total_pages * sizeof(u32) / 32);
543 + next_free_page = pg_ub2zero(offset);
546 +static void free_page_mark_used(u32 page);
547 +/* Returns full-address based pages */
548 +static int free_page_get_next(void)
550 + while (bitmap_is_set(used_bitmap, next_free_page))
552 + free_page_mark_used(next_free_page);
553 + return pg_zero2ub(next_free_page++);
556 +static void free_page_mark_used(u32 page)
558 + bitmap_set(used_bitmap, page);
561 +static void free_page_exit(void)
564 + used_bitmap = NULL;
567 +void set_swsuspmem_hook(struct swsuspmem_hook *hook)
573 + * rtn = 1 : Hibernation image OK.
574 + * rtn = 0 : Hibernation image NG.
576 +int do_checksnapimage(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
579 + void *spare_page = NULL;
580 + struct swsusp_header *swsusp_header;
581 + CRC32_WORD4_t calc_crc;
586 + offt_addr = (void *)simple_strtoul(argv[1], &ep, 16);
588 + printf("Invalid address\n");
593 + spare_page = malloc(PAGE_SIZE);
597 + swsusp_header = spare_page;
598 + if (page_read_mem(offset, swsusp_header))
601 +#ifdef SWSUSP_DEBUG_INFO
602 + PAGEMAP_INFO("swssp_header:%x\n", swsusp_header);
603 + PAGEMAP_INFO(" comp_crc: <snip>\n");
604 + PAGEMAP_INFO(" img_size: %d\n", swsusp_header->img_size);
605 + PAGEMAP_INFO(" image(swap firest sector): %08x\n",
606 + (unsigned int)swsusp_header->image);
607 + PAGEMAP_INFO(" flags: %08x\n", swsusp_header->flags);
608 + PAGEMAP_INFO(" orig_sig:%s\n", swsusp_header->orig_sig);
609 + PAGEMAP_INFO(" sig:%s\n", swsusp_header->sig);
610 +#endif /* SWSUSP_DEBUG_INFO */
612 + if (memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)
613 + || (swsusp_header->img_size == 0)
614 + || (swsusp_header->img_size > 0x03fff000)) {
615 + printf("No hibernation image present\n");
616 + CALL_HOOK(err_hook, SWSUSPMEM_BROKENIMAGE);
619 + memset(&calc_crc, 0, sizeof(calc_crc));
621 + calc_crc32x4((u8 *)((unsigned long)offt_addr + PAGE_SIZE),
622 + swsusp_header->img_size, &calc_crc);
624 + if (memcmp(&calc_crc, &swsusp_header->comp_crc32,
625 + sizeof(CRC32_WORD4_t))) {
626 + printf("Bad CRC for image, image: %08x:%08x:"
627 + "%08x:%08x, calc: %08x:%08x:%08x:%08x\n",
628 + swsusp_header->comp_crc32.crc_w[0],
629 + swsusp_header->comp_crc32.crc_w[1],
630 + swsusp_header->comp_crc32.crc_w[2],
631 + swsusp_header->comp_crc32.crc_w[3],
632 + calc_crc.crc_w[0], calc_crc.crc_w[1],
633 + calc_crc.crc_w[2], calc_crc.crc_w[3]);
634 + CALL_HOOK(err_hook, SWSUSPMEM_BROKENIMAGE);
638 + printf("Hibernation image OK!.\n");
643 + printf("Not enough memory.\n");
644 + CALL_HOOK(err_hook, SWSUSPMEM_ENOMEM);
648 + printf("Read error while restoring image.\n");
653 + "mcr p15, 0, r0, c7, c5, 0 @ invalidate icache\n"
654 + "mcr p15, 0, r0, c7, c10, 4 @ DSB\n"
655 + "mcr p15, 0, r0, c7, c5, 4 @ ISB\n"
656 + : : : "r0", "memory");
660 + CALL_HOOK(err_hook, SWSUSPMEM_RESTOREFAIL);
664 +U_BOOT_CMD(checksnapimage, 2, 2, do_checksnapimage,
665 + "Check hibernation image data from memory",
669 +int do_swsuspmem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
672 + void *spare_page = NULL;
673 + struct swsusp_header *swsusp_header;
674 + struct swsusp_info *swsusp_info;
675 + struct swsusp_finish_context *context;
679 + u32 **pfn_pages = NULL;
680 + u32 *remap_orig_page;
681 + u32 *remap_temp_page;
685 + void (*swsusp_finish_copy)(void *);
688 + CRC32_WORD4_t calc_crc;
691 +#ifdef PAGEMAP_DEBUG
692 + int high_page_images = 0;
693 + int total_remap = 0;
694 + if (getenv("hybdebug") != NULL)
698 + void *swsusp_finish_p = (void *)((u32)swsusp_finish & ~0x1);
701 + offt_addr = (void *)simple_strtoul(argv[1], &ep, 16);
703 + printf("Invalid address\n");
708 + /* Allow for 16 pages of stack */
709 + max_page = gd->start_addr_sp / PAGE_SIZE - 32;
710 + high_page = (((gd->relocaddr + _bss_end_ofs)
711 + + (PAGE_SIZE - 1)) / PAGE_SIZE) + 1;
712 +#define pfn_is_occupied(pfn) (page > max_page && page <= high_page)
713 +#ifdef PAGEMAP_DEBUG
714 + PAGEMAP_INFO(" *gd->start_addr_sp:%p\n",
715 + (void *)gd->start_addr_sp);
716 + PAGEMAP_INFO(" *gd->relocaddr:%p\n",
717 + (void *)gd->relocaddr);
718 + PAGEMAP_INFO(" *bss_start_offset:%d bss_end_offset:%d\n",
719 + (int)_bss_start_ofs, (int)_bss_end_ofs);
720 + PAGEMAP_INFO(" UBOOT own memory [%p-%p]\n",
721 + pg2addr(max_page), pg2addr(high_page));
723 + if (free_page_init())
725 + free_page_start(exclude_max_page + 1);
727 + spare_page = malloc(PAGE_SIZE);
731 + swsusp_header = spare_page;
732 + if (page_read_mem(offset, swsusp_header))
735 +#ifdef SWSUSP_DEBUG_INFO
736 + PAGEMAP_INFO("swssp_header:\n");
737 + PAGEMAP_INFO(" comp_crc: <snip>\n");
738 + PAGEMAP_INFO(" img_size: %d\n", swsusp_header->img_size);
739 + PAGEMAP_INFO(" image(swap firest sector): %08x\n",
740 + (unsigned int)swsusp_header->image);
741 + PAGEMAP_INFO(" flags: %08x\n", swsusp_header->flags);
742 + PAGEMAP_INFO(" orig_sig:%s\n", swsusp_header->orig_sig);
743 + PAGEMAP_INFO(" sig:%s\n", swsusp_header->sig);
744 +#endif /* SWSUSP_DEBUG_INFO */
746 + if (memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)
747 + || (swsusp_header->img_size == 0)
748 + || (swsusp_header->img_size > 0x03fff000)) {
749 + printf("No hibernation image present\n");
750 + CALL_HOOK(err_hook, SWSUSPMEM_BROKENIMAGE);
753 + memset(&calc_crc, 0, sizeof(calc_crc));
755 + calc_crc32x4((u8 *)((unsigned long)offt_addr + PAGE_SIZE),
756 + swsusp_header->img_size, &calc_crc);
758 + if (memcmp(&calc_crc, &swsusp_header->comp_crc32,
759 + sizeof(CRC32_WORD4_t))) {
760 + printf("Bad CRC for image, image: %08x:%08x:"
761 + "%08x:%08x, calc: %08x:%08x:%08x:%08x\n",
762 + swsusp_header->comp_crc32.crc_w[0],
763 + swsusp_header->comp_crc32.crc_w[1],
764 + swsusp_header->comp_crc32.crc_w[2],
765 + swsusp_header->comp_crc32.crc_w[3],
766 + calc_crc.crc_w[0], calc_crc.crc_w[1],
767 + calc_crc.crc_w[2], calc_crc.crc_w[3]);
768 + CALL_HOOK(err_hook, SWSUSPMEM_BROKENIMAGE);
772 + /* Overwrite header if necessary */
773 +#ifndef SWSUSP_KEEP_IMAGE
774 + if (memcmp(swsusp_header->sig, swsusp_header->orig_sig, 10)) {
775 + memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
776 + if (page_write_mem(offset, swsusp_header))
777 + printf("Write error resetting header\n");
781 + if (raw_page_init(swsusp_header->image))
785 + if (image_page_init(!(swsusp_header->flags & SF_NOCOMPRESS_MODE)))
787 + image_page_start();
789 + swsusp_info = spare_page;
790 + if (raw_page_get_next(swsusp_info) <= 0)
793 +#ifdef SWSUSP_DEBUG_INFO
794 + PAGEMAP_INFO("swsup_info:\n");
795 + PAGEMAP_INFO(" utsname.sysname:%s\n",
796 + swsusp_info->uts.sysname);
797 + PAGEMAP_INFO(" nodename:%s\n",
798 + swsusp_info->uts.nodename);
799 + PAGEMAP_INFO(" release:%s\n",
800 + swsusp_info->uts.release);
801 + PAGEMAP_INFO(" version:%s\n",
802 + swsusp_info->uts.version);
803 + PAGEMAP_INFO(" machine:%s\n",
804 + swsusp_info->uts.machine);
805 + PAGEMAP_INFO(" vesion_code:%#08x\n",
806 + (unsigned int)swsusp_info->version_code);
807 + PAGEMAP_INFO(" num_physpages:%d\n",
808 + (unsigned int)swsusp_info->num_physpages);
809 + PAGEMAP_INFO(" pages :%d\n",
810 + (unsigned int)swsusp_info->pages);
811 + PAGEMAP_INFO(" size :%d\n",
812 + (unsigned int)swsusp_info->size);
815 + nr_pfn_pages = (swsusp_info->image_pages * 4 + PAGE_SIZE - 1) /
817 + pfn_pages = malloc(nr_pfn_pages * sizeof(u32 *));
820 + memset(pfn_pages, 0, nr_pfn_pages * sizeof(u32 *));
822 + /* UBOOT using memory */
823 + for (i = max_page; i <= high_page; i++)
824 + free_page_mark_used(pg_ub2zero(i));
826 + printf("Allocating %u bytes (nr_pfn_pages %u)\n",
827 + nr_pfn_pages * PAGE_SIZE, nr_pfn_pages);
829 + for (i = 0; i < nr_pfn_pages; i++) {
831 + pfn_pages[i] = malloc(PAGE_SIZE);
832 + memset(pfn_pages[i], 0xff, PAGE_SIZE);
833 + if (unlikely(!pfn_pages[i]))
835 + if (unlikely(image_page_get_next(pfn_pages[i]) <= 0))
837 + for (idx = 0; idx < PAGE_SIZE / sizeof(u32); idx++) {
838 + u32 page = pfn_pages[i][idx];
839 + if (page == ~0UL) /* End of list of pages */
841 + free_page_mark_used(pg_ub2zero(page));
845 + printf("Loading image data pages (%lu pages)\n",
846 + swsusp_info->image_pages);
848 + remap_orig_page = pg2addr(free_page_get_next());
849 + remap_temp_page = pg2addr(free_page_get_next());
851 + remap_orig = (u32 **)remap_orig_page;
852 + remap_temp = (u32 **)remap_temp_page;
855 + for (i = 0; i < swsusp_info->image_pages; i++) {
856 + u32 page = pfn_pages[i >> 10][i & 0x3ff];
857 + if (unlikely(!pfn_is_valid(page))) {
858 + printf("Attempt to restore invalid address %llx\n",
861 + } else if (unlikely(pfn_is_excluded(page))) {
862 + printf("Attempt to restore excluded address %llx\n",
865 + } else if (unlikely(pfn_is_low(page) &&
866 + pfn_is_occupied(page))) {
867 + remap_orig[remap_idx] = pg2addr(page);
868 + page = free_page_get_next();
869 + remap_temp[remap_idx] = pg2addr(page);
871 +#ifdef PAGEMAP_DEBUG
874 + /* If we fill our current page, allocate a new one */
875 + if (remap_idx + 1 == PAGE_SIZE / sizeof(u32)) {
878 + next = pg2addr(free_page_get_next());
879 + remap_orig[remap_idx] = next;
880 + remap_orig = (u32 **)next;
882 + next = pg2addr(free_page_get_next());
883 + remap_temp[remap_idx] = next;
884 + remap_temp = (u32 **)next;
889 + if (image_page_get_next(pg2addr(page)) <= 0)
893 + printf("Image loading done.\n");
894 + invalidate_icache_all();
896 + CALL_HOOK(resume_boot, SWSUSPMEM_IMAGEDONE);
897 + /* put end markers on the remap list */
898 + remap_orig[remap_idx] = (void *) ~0UL;
899 + remap_temp[remap_idx] = (void *) ~0UL;
901 +#ifdef PAGEMAP_DEBUG
902 + PAGEMAP_INFO("Number of remap pages:%d\n", total_remap);
903 + PAGEMAP_INFO("Number of high pages:%d\n", high_page_images);
904 + PAGEMAP_INFO("Last read page %d (%08x)\n",
905 + _last_read_pages, _last_read_pages * PAGE_SIZE);
907 + remap_orig = (u32 **)remap_orig_page;
908 + remap_temp = (u32 **)remap_temp_page;
910 + /* Make a copy of swsusp_finish in a free data page */
911 + data_page = pg2addr(free_page_get_next());
912 + memcpy(data_page, swsusp_finish_p, PAGE_SIZE);
913 + swsusp_finish_copy = (void *) data_page;
915 + /* Setup context for swsusp_finish at the end of the data_page */
916 + context = (struct swsusp_finish_context *) (data_page + PAGE_SIZE -
917 + sizeof(struct swsusp_finish_context));
918 + context->remap_orig_page = remap_orig_page;
919 + context->remap_temp_page = remap_temp_page;
920 + memcpy((void *)&context->archdata, (void *)swsusp_info->archdata,
921 + sizeof(struct swsusp_archdata));
923 + /* Get a stack pointer for swsusp_finish, growing down from context */
924 + stack_addr = (char *) context;
926 +#ifdef CONFIG_NETCONSOLE
928 + * Stop the ethernet stack if NetConsole could have
933 +#ifdef CONFIG_USB_DEVICE
937 + cleanup_before_linux();
939 + CALL_HOOK(resume_boot, SWSUSPMEM_RESUME);
940 + /* Copy the final data from a safe place */
941 + call_with_stack(swsusp_finish_copy, context, stack_addr);
946 + printf("Not enough memory.\n");
947 + CALL_HOOK(err_hook, SWSUSPMEM_ENOMEM);
951 + printf("Read error while restoring image.\n");
956 + "mcr p15, 0, r0, c7, c5, 0 @ invalidate icache\n"
957 + "mcr p15, 0, r0, c7, c10, 4 @ DSB\n"
958 + "mcr p15, 0, r0, c7, c5, 4 @ ISB\n"
959 + : : : "r0", "memory");
965 + for (i = 0; i < nr_pfn_pages; i++)
966 + free(pfn_pages[i]);
971 + CALL_HOOK(err_hook, SWSUSPMEM_RESTOREFAIL);
975 +U_BOOT_CMD(swsuspmem, 2, 2, do_swsuspmem,
976 + "Restore SWSUSP hibernation image from memory",
979 diff --git a/include/swsuspmem.h b/include/swsuspmem.h
981 index 0000000..3b353ea
983 +++ b/include/swsuspmem.h
985 +#ifndef _SWSUSPMEM_H_
986 +#define _SWSUSPMEM_H_
988 +enum { SWSUSPMEM_NORM = 0,
989 + SWSUSPMEM_NOIMAGE = 0x01,
990 + SWSUSPMEM_BROKENIMAGE = 0x02,
991 + SWSUSPMEM_ENOMEM = 0x80,
992 + SWSUSPMEM_RESTOREFAIL = 0x81,
995 +enum { SWSUSPMEM_IMAGEDONE = 0x01,
996 + SWSUSPMEM_RESUME = 0x02
999 +struct swsuspmem_hook {
1000 + void (*err_hook)(int errcode);
1001 + void (*resume_boot)(int param);
1004 +void set_swsuspmem_hook(struct swsuspmem_hook *hook);
1005 +void arch_preboot_os(void);
1006 +void call_with_stack(void (*fn)(void *),
1007 + void *userdata, void *stack);
1009 diff --git a/lib/lzo/lzo1x_decompress.c b/lib/lzo/lzo1x_decompress.c
1010 index e6ff708..ebdf10b 100644
1011 --- a/lib/lzo/lzo1x_decompress.c
1012 +++ b/lib/lzo/lzo1x_decompress.c
1013 @@ -68,13 +68,14 @@ int lzop_decompress(const unsigned char *src, size_t src_len,
1014 unsigned char *start = dst;
1015 const unsigned char *send = src + src_len;
1018 + size_t tmp, remaining;
1021 src = parse_header(src);
1025 + remaining = *dst_len;
1026 while (src < send) {
1027 /* read uncompressed block size */
1028 dlen = get_unaligned_be32(src);
1029 @@ -93,18 +94,25 @@ int lzop_decompress(const unsigned char *src, size_t src_len,
1030 if (slen <= 0 || slen > dlen)
1033 + /* abort if buffer ran out of room */
1034 + if (dlen > remaining)
1035 + return LZO_E_OUTPUT_OVERRUN;
1039 r = lzo1x_decompress_safe((u8 *) src, slen, dst, &tmp);
1041 - if (r != LZO_E_OK)
1042 + if (r != LZO_E_OK) {
1043 + *dst_len = dst - start;
1052 + remaining -= dlen;
1055 return LZO_E_INPUT_OVERRUN;