aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swsusp.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r--kernel/power/swsusp.c202
1 files changed, 173 insertions, 29 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index f2bc71b9fe8b..d967e875ee82 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -31,6 +31,9 @@
31 * Alex Badea <vampire@go.ro>: 31 * Alex Badea <vampire@go.ro>:
32 * Fixed runaway init 32 * Fixed runaway init
33 * 33 *
34 * Andreas Steinmetz <ast@domdv.de>:
35 * Added encrypted suspend option
36 *
34 * More state savers are welcome. Especially for the scsi layer... 37 * More state savers are welcome. Especially for the scsi layer...
35 * 38 *
36 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt 39 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
@@ -71,8 +74,16 @@
71#include <asm/tlbflush.h> 74#include <asm/tlbflush.h>
72#include <asm/io.h> 75#include <asm/io.h>
73 76
77#include <linux/random.h>
78#include <linux/crypto.h>
79#include <asm/scatterlist.h>
80
74#include "power.h" 81#include "power.h"
75 82
83#define CIPHER "aes"
84#define MAXKEY 32
85#define MAXIV 32
86
76/* References to section boundaries */ 87/* References to section boundaries */
77extern const void __nosave_begin, __nosave_end; 88extern const void __nosave_begin, __nosave_end;
78 89
@@ -103,7 +114,8 @@ static suspend_pagedir_t *pagedir_save;
103#define SWSUSP_SIG "S1SUSPEND" 114#define SWSUSP_SIG "S1SUSPEND"
104 115
105static struct swsusp_header { 116static struct swsusp_header {
106 char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)]; 117 char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)];
118 u8 key_iv[MAXKEY+MAXIV];
107 swp_entry_t swsusp_info; 119 swp_entry_t swsusp_info;
108 char orig_sig[10]; 120 char orig_sig[10];
109 char sig[10]; 121 char sig[10];
@@ -129,6 +141,131 @@ static struct swsusp_info swsusp_info;
129static unsigned short swapfile_used[MAX_SWAPFILES]; 141static unsigned short swapfile_used[MAX_SWAPFILES];
130static unsigned short root_swap; 142static unsigned short root_swap;
131 143
144static int write_page(unsigned long addr, swp_entry_t * loc);
145static int bio_read_page(pgoff_t page_off, void * page);
146
147static u8 key_iv[MAXKEY+MAXIV];
148
149#ifdef CONFIG_SWSUSP_ENCRYPT
150
151static int crypto_init(int mode, void **mem)
152{
153 int error = 0;
154 int len;
155 char *modemsg;
156 struct crypto_tfm *tfm;
157
158 modemsg = mode ? "suspend not possible" : "resume not possible";
159
160 tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC);
161 if(!tfm) {
162 printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg);
163 error = -EINVAL;
164 goto out;
165 }
166
167 if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) {
168 printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg);
169 error = -ENOKEY;
170 goto fail;
171 }
172
173 if (mode)
174 get_random_bytes(key_iv, MAXKEY+MAXIV);
175
176 len = crypto_tfm_alg_max_keysize(tfm);
177 if (len > MAXKEY)
178 len = MAXKEY;
179
180 if (crypto_cipher_setkey(tfm, key_iv, len)) {
181 printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg);
182 error = -EKEYREJECTED;
183 goto fail;
184 }
185
186 len = crypto_tfm_alg_ivsize(tfm);
187
188 if (MAXIV < len) {
189 printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg);
190 error = -EOVERFLOW;
191 goto fail;
192 }
193
194 crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len);
195
196 *mem=(void *)tfm;
197
198 goto out;
199
200fail: crypto_free_tfm(tfm);
201out: return error;
202}
203
204static __inline__ void crypto_exit(void *mem)
205{
206 crypto_free_tfm((struct crypto_tfm *)mem);
207}
208
209static __inline__ int crypto_write(struct pbe *p, void *mem)
210{
211 int error = 0;
212 struct scatterlist src, dst;
213
214 src.page = virt_to_page(p->address);
215 src.offset = 0;
216 src.length = PAGE_SIZE;
217 dst.page = virt_to_page((void *)&swsusp_header);
218 dst.offset = 0;
219 dst.length = PAGE_SIZE;
220
221 error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src,
222 PAGE_SIZE);
223
224 if (!error)
225 error = write_page((unsigned long)&swsusp_header,
226 &(p->swap_address));
227 return error;
228}
229
230static __inline__ int crypto_read(struct pbe *p, void *mem)
231{
232 int error = 0;
233 struct scatterlist src, dst;
234
235 error = bio_read_page(swp_offset(p->swap_address), (void *)p->address);
236 if (!error) {
237 src.offset = 0;
238 src.length = PAGE_SIZE;
239 dst.offset = 0;
240 dst.length = PAGE_SIZE;
241 src.page = dst.page = virt_to_page((void *)p->address);
242
243 error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst,
244 &src, PAGE_SIZE);
245 }
246 return error;
247}
248#else
249static __inline__ int crypto_init(int mode, void *mem)
250{
251 return 0;
252}
253
254static __inline__ void crypto_exit(void *mem)
255{
256}
257
258static __inline__ int crypto_write(struct pbe *p, void *mem)
259{
260 return write_page(p->address, &(p->swap_address));
261}
262
263static __inline__ int crypto_read(struct pbe *p, void *mem)
264{
265 return bio_read_page(swp_offset(p->swap_address), (void *)p->address);
266}
267#endif
268
132static int mark_swapfiles(swp_entry_t prev) 269static int mark_swapfiles(swp_entry_t prev)
133{ 270{
134 int error; 271 int error;
@@ -140,6 +277,7 @@ static int mark_swapfiles(swp_entry_t prev)
140 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { 277 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
141 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); 278 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
142 memcpy(swsusp_header.sig,SWSUSP_SIG, 10); 279 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
280 memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV);
143 swsusp_header.swsusp_info = prev; 281 swsusp_header.swsusp_info = prev;
144 error = rw_swap_page_sync(WRITE, 282 error = rw_swap_page_sync(WRITE,
145 swp_entry(root_swap, 0), 283 swp_entry(root_swap, 0),
@@ -179,9 +317,9 @@ static int swsusp_swap_check(void) /* This is called before saving image */
179 len=strlen(resume_file); 317 len=strlen(resume_file);
180 root_swap = 0xFFFF; 318 root_swap = 0xFFFF;
181 319
182 swap_list_lock(); 320 spin_lock(&swap_lock);
183 for (i=0; i<MAX_SWAPFILES; i++) { 321 for (i=0; i<MAX_SWAPFILES; i++) {
184 if (swap_info[i].flags == 0) { 322 if (!(swap_info[i].flags & SWP_WRITEOK)) {
185 swapfile_used[i]=SWAPFILE_UNUSED; 323 swapfile_used[i]=SWAPFILE_UNUSED;
186 } else { 324 } else {
187 if (!len) { 325 if (!len) {
@@ -202,7 +340,7 @@ static int swsusp_swap_check(void) /* This is called before saving image */
202 } 340 }
203 } 341 }
204 } 342 }
205 swap_list_unlock(); 343 spin_unlock(&swap_lock);
206 return (root_swap != 0xffff) ? 0 : -ENODEV; 344 return (root_swap != 0xffff) ? 0 : -ENODEV;
207} 345}
208 346
@@ -216,12 +354,12 @@ static void lock_swapdevices(void)
216{ 354{
217 int i; 355 int i;
218 356
219 swap_list_lock(); 357 spin_lock(&swap_lock);
220 for (i = 0; i< MAX_SWAPFILES; i++) 358 for (i = 0; i< MAX_SWAPFILES; i++)
221 if (swapfile_used[i] == SWAPFILE_IGNORED) { 359 if (swapfile_used[i] == SWAPFILE_IGNORED) {
222 swap_info[i].flags ^= 0xFF; 360 swap_info[i].flags ^= SWP_WRITEOK;
223 } 361 }
224 swap_list_unlock(); 362 spin_unlock(&swap_lock);
225} 363}
226 364
227/** 365/**
@@ -286,6 +424,10 @@ static int data_write(void)
286 int error = 0, i = 0; 424 int error = 0, i = 0;
287 unsigned int mod = nr_copy_pages / 100; 425 unsigned int mod = nr_copy_pages / 100;
288 struct pbe *p; 426 struct pbe *p;
427 void *tfm;
428
429 if ((error = crypto_init(1, &tfm)))
430 return error;
289 431
290 if (!mod) 432 if (!mod)
291 mod = 1; 433 mod = 1;
@@ -294,11 +436,14 @@ static int data_write(void)
294 for_each_pbe (p, pagedir_nosave) { 436 for_each_pbe (p, pagedir_nosave) {
295 if (!(i%mod)) 437 if (!(i%mod))
296 printk( "\b\b\b\b%3d%%", i / mod ); 438 printk( "\b\b\b\b%3d%%", i / mod );
297 if ((error = write_page(p->address, &(p->swap_address)))) 439 if ((error = crypto_write(p, tfm))) {
440 crypto_exit(tfm);
298 return error; 441 return error;
442 }
299 i++; 443 i++;
300 } 444 }
301 printk("\b\b\b\bdone\n"); 445 printk("\b\b\b\bdone\n");
446 crypto_exit(tfm);
302 return error; 447 return error;
303} 448}
304 449
@@ -385,7 +530,6 @@ static int write_pagedir(void)
385 * write_suspend_image - Write entire image and metadata. 530 * write_suspend_image - Write entire image and metadata.
386 * 531 *
387 */ 532 */
388
389static int write_suspend_image(void) 533static int write_suspend_image(void)
390{ 534{
391 int error; 535 int error;
@@ -400,6 +544,7 @@ static int write_suspend_image(void)
400 if ((error = close_swap())) 544 if ((error = close_swap()))
401 goto FreePagedir; 545 goto FreePagedir;
402 Done: 546 Done:
547 memset(key_iv, 0, MAXKEY+MAXIV);
403 return error; 548 return error;
404 FreePagedir: 549 FreePagedir:
405 free_pagedir_entries(); 550 free_pagedir_entries();
@@ -591,18 +736,7 @@ static void copy_data_pages(void)
591 736
592static int calc_nr(int nr_copy) 737static int calc_nr(int nr_copy)
593{ 738{
594 int extra = 0; 739 return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1);
595 int mod = !!(nr_copy % PBES_PER_PAGE);
596 int diff = (nr_copy / PBES_PER_PAGE) + mod;
597
598 do {
599 extra += diff;
600 nr_copy += diff;
601 mod = !!(nr_copy % PBES_PER_PAGE);
602 diff = (nr_copy / PBES_PER_PAGE) + mod - extra;
603 } while (diff > 0);
604
605 return nr_copy;
606} 740}
607 741
608/** 742/**
@@ -886,20 +1020,21 @@ int swsusp_suspend(void)
886 * at resume time, and evil weirdness ensues. 1020 * at resume time, and evil weirdness ensues.
887 */ 1021 */
888 if ((error = device_power_down(PMSG_FREEZE))) { 1022 if ((error = device_power_down(PMSG_FREEZE))) {
1023 printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
889 local_irq_enable(); 1024 local_irq_enable();
890 return error; 1025 return error;
891 } 1026 }
892 1027
893 if ((error = swsusp_swap_check())) { 1028 if ((error = swsusp_swap_check())) {
894 printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try " 1029 printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
895 "swapon -a!\n"); 1030 device_power_up();
896 local_irq_enable(); 1031 local_irq_enable();
897 return error; 1032 return error;
898 } 1033 }
899 1034
900 save_processor_state(); 1035 save_processor_state();
901 if ((error = swsusp_arch_suspend())) 1036 if ((error = swsusp_arch_suspend()))
902 printk("Error %d suspending\n", error); 1037 printk(KERN_ERR "Error %d suspending\n", error);
903 /* Restore control flow magically appears here */ 1038 /* Restore control flow magically appears here */
904 restore_processor_state(); 1039 restore_processor_state();
905 BUG_ON (nr_copy_pages_check != nr_copy_pages); 1040 BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -924,6 +1059,7 @@ int swsusp_resume(void)
924 BUG_ON(!error); 1059 BUG_ON(!error);
925 restore_processor_state(); 1060 restore_processor_state();
926 restore_highmem(); 1061 restore_highmem();
1062 touch_softlockup_watchdog();
927 device_power_up(); 1063 device_power_up();
928 local_irq_enable(); 1064 local_irq_enable();
929 return error; 1065 return error;
@@ -1179,7 +1315,8 @@ static const char * sanity_check(void)
1179 if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) 1315 if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
1180 return "machine"; 1316 return "machine";
1181#if 0 1317#if 0
1182 if(swsusp_info.cpus != num_online_cpus()) 1318 /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
1319 if (swsusp_info.cpus != num_possible_cpus())
1183 return "number of cpus"; 1320 return "number of cpus";
1184#endif 1321#endif
1185 return NULL; 1322 return NULL;
@@ -1212,13 +1349,14 @@ static int check_sig(void)
1212 return error; 1349 return error;
1213 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { 1350 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
1214 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); 1351 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
1352 memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV);
1353 memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV);
1215 1354
1216 /* 1355 /*
1217 * Reset swap signature now. 1356 * Reset swap signature now.
1218 */ 1357 */
1219 error = bio_write_page(0, &swsusp_header); 1358 error = bio_write_page(0, &swsusp_header);
1220 } else { 1359 } else {
1221 printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
1222 return -EINVAL; 1360 return -EINVAL;
1223 } 1361 }
1224 if (!error) 1362 if (!error)
@@ -1239,6 +1377,10 @@ static int data_read(struct pbe *pblist)
1239 int error = 0; 1377 int error = 0;
1240 int i = 0; 1378 int i = 0;
1241 int mod = swsusp_info.image_pages / 100; 1379 int mod = swsusp_info.image_pages / 100;
1380 void *tfm;
1381
1382 if ((error = crypto_init(0, &tfm)))
1383 return error;
1242 1384
1243 if (!mod) 1385 if (!mod)
1244 mod = 1; 1386 mod = 1;
@@ -1250,14 +1392,15 @@ static int data_read(struct pbe *pblist)
1250 if (!(i % mod)) 1392 if (!(i % mod))
1251 printk("\b\b\b\b%3d%%", i / mod); 1393 printk("\b\b\b\b%3d%%", i / mod);
1252 1394
1253 error = bio_read_page(swp_offset(p->swap_address), 1395 if ((error = crypto_read(p, tfm))) {
1254 (void *)p->address); 1396 crypto_exit(tfm);
1255 if (error)
1256 return error; 1397 return error;
1398 }
1257 1399
1258 i++; 1400 i++;
1259 } 1401 }
1260 printk("\b\b\b\bdone\n"); 1402 printk("\b\b\b\bdone\n");
1403 crypto_exit(tfm);
1261 return error; 1404 return error;
1262} 1405}
1263 1406
@@ -1385,6 +1528,7 @@ int swsusp_read(void)
1385 1528
1386 error = read_suspend_image(); 1529 error = read_suspend_image();
1387 blkdev_put(resume_bdev); 1530 blkdev_put(resume_bdev);
1531 memset(key_iv, 0, MAXKEY+MAXIV);
1388 1532
1389 if (!error) 1533 if (!error)
1390 pr_debug("swsusp: Reading resume file was successful\n"); 1534 pr_debug("swsusp: Reading resume file was successful\n");