1 | /*␊ |
2 | * resume.c␊ |
3 | * ␊ |
4 | *␊ |
5 | * Created by mackerintel on 1/22/09.␊ |
6 | * Copyright 2009 mackerintel. All rights reserved.␊ |
7 | *␊ |
8 | */␊ |
9 | ␊ |
10 | #include "libsa.h"␊ |
11 | #include "saio_internal.h"␊ |
12 | #include "IOHibernatePrivate.h"␊ |
13 | #include "memory.h"␊ |
14 | #include "bootstruct.h"␊ |
15 | #include "platform.h"␊ |
16 | #include "pci.h"␊ |
17 | #include "resume.h"␊ |
18 | #include "graphic_utils.h"␊ |
19 | ␊ |
20 | extern int previewTotalSectors;␊ |
21 | extern int previewLoadedSectors;␊ |
22 | extern uint8_t *previewSaveunder;␊ |
23 | static unsigned long␊ |
24 | getmemorylimit(void);␊ |
25 | static void WakeKernel(IOHibernateImageHeader * header);␊ |
26 | ␊ |
27 | ␊ |
28 | static unsigned long␊ |
29 | getmemorylimit(void)␊ |
30 | {␊ |
31 | #if UNUSED␊ |
32 | int line;␊ |
33 | #endif␊ |
34 | int i;␊ |
35 | ␊ |
36 | MemoryRange *mp = (MemoryRange*)(uint32_t)get_env(envMemoryMap);␊ |
37 | int MemMapCnt = (int)get_env(envMemoryMapCnt);␊ |
38 | ␊ |
39 | #if UNUSED␊ |
40 | // Activate and clear page 1␊ |
41 | line = 1;␊ |
42 | #endif␊ |
43 | ␊ |
44 | for (i = 0; i < MemMapCnt; i++)␊ |
45 | {␊ |
46 | if((mp->type == 1) && ((unsigned long)mp->base == 0x100000))␊ |
47 | {␊ |
48 | return (unsigned long)(mp->base + mp->length);␊ |
49 | }␊ |
50 | mp++;␊ |
51 | }␊ |
52 | return 0x10000000;␊ |
53 | }␊ |
54 | ␊ |
55 | static void WakeKernel(IOHibernateImageHeader * header)␊ |
56 | {␊ |
57 | ␉uint32_t proc;␊ |
58 | unsigned long cnt;␊ |
59 | #if UNUSED␊ |
60 | unsigned long newSP;␊ |
61 | #endif ␊ |
62 | ␉unsigned long *src, *dst;␊ |
63 | ␉unsigned int ␉count;␊ |
64 | ␉unsigned int ␉page;␊ |
65 | ␉unsigned int ␉compressedSize;␊ |
66 | ␉int32_t ␉byteCnt;␊ |
67 | ␉u_int32_t ␉lowHalf, highHalf;␊ |
68 | ␉u_int32_t ␉sum;␊ |
69 | ␉␊ |
70 | ␉printf("\nWake Kernel!\n");␊ |
71 | ␉␊ |
72 | ␉dst = (unsigned long *) (header->restore1CodePage << 12);␊ |
73 | ␉count = header->restore1PageCount;␊ |
74 | ␉proc = (header->restore1CodeOffset + ((uint32_t) dst));␊ |
75 | #if UNUSED␊ |
76 | ␉newSP = header->restore1StackOffset + (header->restore1CodePage << 12);␊ |
77 | #endif␊ |
78 | ␉src = (unsigned long *) (((u_int32_t) &header->fileExtentMap[0]) ␊ |
79 | ␉␉␉␉␉␉␉ + header->fileExtentMapSize);␊ |
80 | ␉sum = 0;␊ |
81 | ␉␊ |
82 | ␉for (page = 0; page < count; page++)␊ |
83 | ␉{␊ |
84 | ␉␉compressedSize = 4096;␊ |
85 | ␉␉␊ |
86 | ␉␉lowHalf = 1;␊ |
87 | ␉␉highHalf = 0;␊ |
88 | ␉␉␊ |
89 | ␉␉for (cnt = 0; cnt < compressedSize; cnt += 0x20)␊ |
90 | ␉␉{␊ |
91 | ␉␉␉dst[0] = src[0];␊ |
92 | ␉␉␉dst[1] = src[1];␊ |
93 | ␉␉␉dst[2] = src[2];␊ |
94 | ␉␉␉dst[3] = src[3];␊ |
95 | ␉␉␉dst[4] = src[4];␊ |
96 | ␉␉␉dst[5] = src[5];␊ |
97 | ␉␉␉dst[6] = src[6];␊ |
98 | ␉␉␉dst[7] = src[7];␊ |
99 | ␉␉␉for (byteCnt = 0; byteCnt < 0x20; byteCnt++)␊ |
100 | ␉␉␉{␊ |
101 | ␉␉␉␉lowHalf += ((u_int8_t *) dst)[byteCnt];␊ |
102 | ␉␉␉␉highHalf += lowHalf;␊ |
103 | ␉␉␉}␊ |
104 | ␉␉␉src += 8;␊ |
105 | ␉␉␉dst += 8;␊ |
106 | ␉␉}␊ |
107 | ␉␉␊ |
108 | ␉␉lowHalf %= 65521L;␊ |
109 | ␉␉highHalf %= 65521L;␊ |
110 | ␉␉sum += (highHalf << 16) | lowHalf;␊ |
111 | ␉}␊ |
112 | ␉header->actualRestore1Sum = sum;␊ |
113 | ␉startprog (proc, header);␊ |
114 | ␉␊ |
115 | ␉return;␊ |
116 | }␊ |
117 | ␊ |
118 | static void WakeKernel107(IOHibernateImageHeader107 * header)␊ |
119 | {␊ |
120 | uint32_t proc;␊ |
121 | unsigned long cnt;␊ |
122 | #if UNUSED␊ |
123 | unsigned long newSP;␊ |
124 | #endif ␊ |
125 | unsigned long *src, *dst;␊ |
126 | unsigned int ␉count;␊ |
127 | unsigned int ␉page;␊ |
128 | unsigned int ␉compressedSize;␊ |
129 | int32_t ␉byteCnt;␊ |
130 | u_int32_t ␉lowHalf, highHalf;␊ |
131 | u_int32_t ␉sum;␊ |
132 | ␊ |
133 | printf("\nWake Kernel!\n");␊ |
134 | ␊ |
135 | dst = (unsigned long *) (header->restore1CodePhysPage << 12);␊ |
136 | count = header->restore1PageCount;␊ |
137 | proc = (header->restore1CodeOffset + ((uint32_t) dst));␊ |
138 | #if UNUSED␊ |
139 | newSP = header->restore1StackOffset + (header->restore1CodePhysPage << 12);␊ |
140 | #endif␊ |
141 | src = (unsigned long *) (((u_int32_t) &header->fileExtentMap[0]) ␊ |
142 | + header->fileExtentMapSize);␊ |
143 | sum = 0;␊ |
144 | ␊ |
145 | for (page = 0; page < count; page++)␊ |
146 | {␊ |
147 | compressedSize = 4096;␊ |
148 | ␊ |
149 | lowHalf = 1;␊ |
150 | highHalf = 0;␊ |
151 | ␊ |
152 | for (cnt = 0; cnt < compressedSize; cnt += 0x20) {␊ |
153 | dst[0] = src[0];␊ |
154 | dst[1] = src[1];␊ |
155 | dst[2] = src[2];␊ |
156 | dst[3] = src[3];␊ |
157 | dst[4] = src[4];␊ |
158 | dst[5] = src[5];␊ |
159 | dst[6] = src[6];␊ |
160 | dst[7] = src[7];␊ |
161 | for (byteCnt = 0; byteCnt < 0x20; byteCnt++) {␊ |
162 | lowHalf += ((u_int8_t *) dst)[byteCnt];␊ |
163 | highHalf += lowHalf;␊ |
164 | }␊ |
165 | src += 8;␊ |
166 | dst += 8;␊ |
167 | }␊ |
168 | ␊ |
169 | lowHalf %= 65521L;␊ |
170 | highHalf %= 65521L;␊ |
171 | sum += (highHalf << 16) | lowHalf;␊ |
172 | }␊ |
173 | header->actualRestore1Sum = sum;␊ |
174 | startprog (proc, header);␊ |
175 | ␊ |
176 | return;␊ |
177 | }␊ |
178 | ␊ |
179 | static void HibernateBoot107(char *image_filename)␊ |
180 | {␊ |
181 | long long size, imageSize, codeSize, allocSize;␊ |
182 | long mem_base;␊ |
183 | IOHibernateImageHeader107 _header;␊ |
184 | IOHibernateImageHeader107 * header = &_header;␊ |
185 | long buffer;␊ |
186 | ␊ |
187 | size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader107));␊ |
188 | printf("header read size %x\n", size);␊ |
189 | ␊ |
190 | imageSize = header->image1Size;␊ |
191 | codeSize = header->restore1PageCount << 12;␊ |
192 | if (kIOHibernateHeaderSignature != header->signature)␊ |
193 | {␊ |
194 | printf ("Incorrect image signature, expected version 10.7\n");␊ |
195 | getchar();␊ |
196 | return;␊ |
197 | }␊ |
198 | if (header->encryptStart)␊ |
199 | {␊ |
200 | printf ("Resuming from Encrypted image is unsupported.\n"␊ |
201 | "Uncheck \"Use secure virtual memory\" in \"Security\" pane on system preferences.\n"␊ |
202 | "Press any key to proceed with normal boot.\n");␊ |
203 | getchar();␊ |
204 | return;␊ |
205 | }␊ |
206 | // depends on NVRAM␊ |
207 | #if 0␊ |
208 | {␊ |
209 | uint32_t machineSignature;␊ |
210 | size = GetProp(gChosenPH, kIOHibernateMachineSignatureKey,␊ |
211 | (char *)&machineSignature, sizeof(machineSignature));␊ |
212 | if (size != sizeof(machineSignature)) machineSignature = 0;␊ |
213 | if (machineSignature != header->machineSignature)␊ |
214 | break;␊ |
215 | }␊ |
216 | #endif␊ |
217 | ␊ |
218 | allocSize = imageSize + ((4095 + sizeof(hibernate_graphics_t)) & ~4095);␊ |
219 | ␊ |
220 | mem_base = (long)(getmemorylimit() - allocSize);//TODO: lower this␊ |
221 | ␊ |
222 | printf("mem_base %x\n", mem_base);␊ |
223 | ␊ |
224 | bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader107));␊ |
225 | header = (IOHibernateImageHeader107 *) mem_base;␊ |
226 | ␊ |
227 | imageSize -= sizeof(IOHibernateImageHeader107);␊ |
228 | buffer = (long)(header + 1);␊ |
229 | ␊ |
230 | if (header->previewSize)␊ |
231 | {␊ |
232 | uint64_t preview_offset = header->fileExtentMapSize - sizeof(header->fileExtentMap) + codeSize;␊ |
233 | uint8_t progressSaveUnder[kIOHibernateProgressCount][kIOHibernateProgressSaveUnderSize];␊ |
234 | ␊ |
235 | ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader107), preview_offset+header->previewSize);␊ |
236 | drawPreview ((void *)(long)(buffer+preview_offset + header->previewPageListSize), &(progressSaveUnder[0][0]));␊ |
237 | previewTotalSectors = (int)(imageSize-(preview_offset+header->previewSize))/512;␊ |
238 | previewLoadedSectors = 0;␊ |
239 | previewSaveunder = &(progressSaveUnder[0][0]);␊ |
240 | if (preview_offset+header->previewSize<imageSize)␊ |
241 | ReadFileAtOffset (image_filename, (char *)(long)(buffer+preview_offset+header->previewSize),␊ |
242 | sizeof(IOHibernateImageHeader107)+preview_offset+header->previewSize,␊ |
243 | imageSize-(preview_offset+header->previewSize));␊ |
244 | previewTotalSectors = 0;␊ |
245 | previewLoadedSectors = 0;␊ |
246 | previewSaveunder = 0;␊ |
247 | #if 0␊ |
248 | /* AsereBLN:␊ |
249 | check_vga_nvidia() didn't work as expected (recursion level > 0 & return value).␊ |
250 | Unforutnaltely I cannot find a note why to switch back to text mode for nVidia cards only␊ |
251 | and because it check_vga_nvidia does not work (cards normally are behind a bridge) I will␊ |
252 | remove it completely */␊ |
253 | setVideoMode( VGA_TEXT_MODE, 0 );␊ |
254 | #endif␊ |
255 | }␊ |
256 | else␊ |
257 | ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader107), imageSize);␊ |
258 | ␊ |
259 | // Depends on NVRAM␊ |
260 | #if 0␊ |
261 | if (header->encryptStart) {␊ |
262 | // decryption data␊ |
263 | static const unsigned char first_iv[AES_BLOCK_SIZE]␊ |
264 | = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,␊ |
265 | 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };␊ |
266 | hibernate_cryptvars_t _cryptvars;␊ |
267 | hibernate_cryptvars_t * cryptvars = &_cryptvars;␊ |
268 | ␊ |
269 | aes_decrypt_key(&decryptkey,␊ |
270 | decryptkeysize,␊ |
271 | &cryptvars->ctx.decrypt);␊ |
272 | ␊ |
273 | // set the vector for the following decryptions␊ |
274 | bcopy(((uint8_t *) header) + header->image1Size - AES_BLOCK_SIZE,␊ |
275 | &cryptvars->aes_iv[0], AES_BLOCK_SIZE);␊ |
276 | ␊ |
277 | // decrypt the buffer␊ |
278 | uint32_t len = (uint32_t)(header->image1Size - header->encryptStart);␊ |
279 | aes_decrypt_cbc(((uint8_t *) header) + header->encryptStart,␊ |
280 | &first_iv[0],␊ |
281 | len >> 4,␊ |
282 | ((uint8_t *) header) + header->encryptStart,␊ |
283 | &cryptvars->ctx.decrypt);␊ |
284 | bzero(&cryptvars->aes_iv[0], sizeof(cryptvars));␊ |
285 | bzero(&decryptkey, sizeof(decryptkey));␊ |
286 | }␊ |
287 | #endif␊ |
288 | ␊ |
289 | WakeKernel107(header);␊ |
290 | }␊ |
291 | ␊ |
292 | void HibernateBoot(char *image_filename)␊ |
293 | {␊ |
294 | ␉long long size, imageSize, codeSize, allocSize;␊ |
295 | ␉long mem_base;␊ |
296 | ␉IOHibernateImageHeader _header;␊ |
297 | ␉IOHibernateImageHeader * header = &_header;␊ |
298 | ␉long buffer;␊ |
299 | ␉␊ |
300 | if(((BVRef)(uint32_t)get_env(envgBootVolume))->OSVersion[3] >= '7') // TODO: unlocked, but please check the compatibility with the 10.8␊ |
301 | {␊ |
302 | HibernateBoot107(image_filename);␊ |
303 | return;␊ |
304 | }␊ |
305 | ␊ |
306 | ␉size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader));␊ |
307 | ␉printf("header read size %x\n", size);␊ |
308 | ␊ |
309 | ␉imageSize = header->image1Size;␊ |
310 | ␉codeSize = header->restore1PageCount << 12;␊ |
311 | ␉if (kIOHibernateHeaderSignature != header->signature)␊ |
312 | ␉{␊ |
313 | ␉␉printf ("Incorrect image signature\n");␊ |
314 | ␉␉return;␊ |
315 | ␉}␊ |
316 | ␉if (header->encryptStart)␊ |
317 | ␉{␊ |
318 | ␉␉printf ("Resuming from Encrypted image is unsupported.\n"␊ |
319 | ␉␉␉␉"Uncheck \"Use secure virtual memory\" in \"Security\" pane on system preferences.\n"␊ |
320 | ␉␉␉␉"Press any key to proceed with normal boot.\n");␊ |
321 | ␉␉getc ();␊ |
322 | ␉␉return;␊ |
323 | ␉}␊ |
324 | // depends on NVRAM␊ |
325 | #if 0␊ |
326 | ␉{␊ |
327 | ␉␉uint32_t machineSignature;␊ |
328 | ␉␉size = GetProp(gChosenPH, kIOHibernateMachineSignatureKey, ␊ |
329 | ␉␉␉␉␉ (char *)&machineSignature, sizeof(machineSignature));␊ |
330 | ␉␉if (size != sizeof(machineSignature)) machineSignature = 0;␊ |
331 | ␉␉if (machineSignature != header->machineSignature)␊ |
332 | ␉␉␉break;␊ |
333 | ␉}␊ |
334 | #endif␊ |
335 | ␊ |
336 | ␉allocSize = imageSize + ((4095 + sizeof(hibernate_graphics_t)) & ~4095);␊ |
337 | ␊ |
338 | ␉mem_base = (long)(getmemorylimit() - allocSize);//TODO: lower this␊ |
339 | ␊ |
340 | ␉printf("mem_base %ld\n", mem_base);␊ |
341 | ␊ |
342 | ␉bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader));␊ |
343 | ␉header = (IOHibernateImageHeader *) mem_base;␊ |
344 | ␊ |
345 | ␉imageSize -= sizeof(IOHibernateImageHeader);␊ |
346 | ␉buffer = (long)(header + 1);␊ |
347 | ␉␊ |
348 | ␉if (header->previewSize)␊ |
349 | ␉{␊ |
350 | ␉␉uint64_t preview_offset = header->fileExtentMapSize - sizeof(header->fileExtentMap) + codeSize;␊ |
351 | ␉␉uint8_t progressSaveUnder[kIOHibernateProgressCount][kIOHibernateProgressSaveUnderSize];␊ |
352 | ␊ |
353 | ␉␉ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), preview_offset+header->previewSize);␊ |
354 | ␉␉drawPreview ((void *)(long)(buffer+preview_offset + header->previewPageListSize), &(progressSaveUnder[0][0]));␊ |
355 | ␉␉previewTotalSectors = (imageSize-(preview_offset+header->previewSize))/512;␊ |
356 | ␉␉previewLoadedSectors = 0;␊ |
357 | ␉␉previewSaveunder = &(progressSaveUnder[0][0]);␊ |
358 | ␉␉if (preview_offset+header->previewSize<imageSize)␊ |
359 | ␉␉␉ReadFileAtOffset (image_filename, (char *)(long)(buffer+preview_offset+header->previewSize), ␊ |
360 | ␉␉␉␉␉␉␉ sizeof(IOHibernateImageHeader)+preview_offset+header->previewSize,␊ |
361 | ␉␉␉␉␉␉␉ imageSize-(preview_offset+header->previewSize));␊ |
362 | ␉␉previewTotalSectors = 0;␊ |
363 | ␉␉previewLoadedSectors = 0;␊ |
364 | ␉␉previewSaveunder = 0;␉␉␊ |
365 | #if 0␊ |
366 | ␉␉/*AsereBLN:␊ |
367 | check_vga_nvidia() didn''t work as expected (recursion level > 0 & return value).␊ |
368 | Unforutnaltely I cannot find a note why to switch back to text mode for nVidia cards only␊ |
369 | and because it check_vga_nvidia does not work (cards normally are behind a bridge) I will␊ |
370 | remove it completely*/␊ |
371 | ␊ |
372 | ␉␉setVideoMode(VGA_TEXT_MODE);␊ |
373 | ␉␉␊ |
374 | #endif␊ |
375 | ␉}␊ |
376 | ␉else␊ |
377 | ␉␉ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), imageSize);␊ |
378 | ␉␊ |
379 | // Depends on NVRAM␊ |
380 | #if 0␊ |
381 | ␉if (header->encryptStart)␊ |
382 | ␉{␊ |
383 | ␉␉// decryption data␊ |
384 | ␉␉static const unsigned char first_iv[AES_BLOCK_SIZE]␊ |
385 | ␉␉= { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,␊ |
386 | 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };␊ |
387 | ␉␉hibernate_cryptvars_t _cryptvars;␊ |
388 | ␉␉hibernate_cryptvars_t * cryptvars = &_cryptvars;␊ |
389 | ␉␉␊ |
390 | ␉␉aes_decrypt_key(&decryptkey,␊ |
391 | ␉␉␉␉␉␉decryptkeysize,␊ |
392 | ␉␉␉␉␉␉&cryptvars->ctx.decrypt);␊ |
393 | ␊ |
394 | ␉␉// set the vector for the following decryptions␊ |
395 | ␉␉bcopy(((uint8_t *) header) + header->image1Size - AES_BLOCK_SIZE, ␊ |
396 | &cryptvars->aes_iv[0], AES_BLOCK_SIZE);␊ |
397 | ␊ |
398 | ␉␉// decrypt the buffer␊ |
399 | ␉␉uint32_t len = (uint32_t)(header->image1Size - header->encryptStart);␊ |
400 | ␉␉aes_decrypt_cbc(((uint8_t *) header) + header->encryptStart,␊ |
401 | ␉␉␉␉␉␉&first_iv[0],␊ |
402 | ␉␉␉␉␉␉len >> 4,␊ |
403 | ␉␉␉␉␉␉((uint8_t *) header) + header->encryptStart,␊ |
404 | ␉␉␉␉␉␉&cryptvars->ctx.decrypt);␊ |
405 | ␉␉bzero(&cryptvars->aes_iv[0], sizeof(cryptvars));␊ |
406 | ␉␉bzero(&decryptkey, sizeof(decryptkey));␊ |
407 | ␉}␊ |
408 | #endif␊ |
409 | ␉WakeKernel(header);␊ |
410 | }␊ |
411 | |