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