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