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 int previewTotalSectors;␊ |
21 | extern int previewLoadedSectors;␊ |
22 | extern uint8_t *previewSaveunder;␊ |
23 | ␊ |
24 | static unsigned long␊ |
25 | getmemorylimit(void)␊ |
26 | {␊ |
27 | int line;␊ |
28 | int i;␊ |
29 | MemoryRange *mp = bootInfo->memoryMap;␊ |
30 | ␊ |
31 | // Activate and clear page 1␊ |
32 | line = 1;␊ |
33 | for (i = 0; i < bootInfo->memoryMapCount; i++)␊ |
34 | {␊ |
35 | if((mp->type == 1) && ((unsigned long)mp->base == 0x100000))␊ |
36 | {␊ |
37 | return (unsigned long)(mp->base + mp->length);␊ |
38 | }␊ |
39 | mp++;␊ |
40 | }␊ |
41 | return 0x10000000;␊ |
42 | }␊ |
43 | ␊ |
44 | static void WakeKernel(IOHibernateImageHeader * header)␊ |
45 | {␊ |
46 | ␉uint32_t proc;␊ |
47 | ␉unsigned long cnt, newSP;␊ |
48 | ␉unsigned long *src, *dst;␊ |
49 | ␉unsigned int ␉count;␊ |
50 | ␉unsigned int ␉page;␊ |
51 | ␉unsigned int ␉compressedSize;␊ |
52 | ␉int32_t ␉byteCnt;␊ |
53 | ␉u_int32_t ␉lowHalf, highHalf;␊ |
54 | ␉u_int32_t ␉sum;␊ |
55 | ␉␊ |
56 | ␉printf("\nWake Kernel!\n");␊ |
57 | ␉␊ |
58 | ␉dst = (unsigned long *) (header->restore1CodePage << 12);␊ |
59 | ␉count = header->restore1PageCount;␊ |
60 | ␉proc = (header->restore1CodeOffset + ((uint32_t) dst));␊ |
61 | ␉newSP = header->restore1StackOffset + (header->restore1CodePage << 12);␊ |
62 | ␉␊ |
63 | ␉src = (unsigned long *) (((u_int32_t) &header->fileExtentMap[0]) ␊ |
64 | ␉␉␉␉␉␉␉ + header->fileExtentMapSize);␊ |
65 | ␉sum = 0;␊ |
66 | ␉␊ |
67 | ␉for (page = 0; page < count; page++)␊ |
68 | ␉{␊ |
69 | ␉␉compressedSize = 4096;␊ |
70 | ␉␉␊ |
71 | ␉␉lowHalf = 1;␊ |
72 | ␉␉highHalf = 0;␊ |
73 | ␉␉␊ |
74 | ␉␉for (cnt = 0; cnt < compressedSize; cnt += 0x20) {␊ |
75 | ␉␉␉dst[0] = src[0];␊ |
76 | ␉␉␉dst[1] = src[1];␊ |
77 | ␉␉␉dst[2] = src[2];␊ |
78 | ␉␉␉dst[3] = src[3];␊ |
79 | ␉␉␉dst[4] = src[4];␊ |
80 | ␉␉␉dst[5] = src[5];␊ |
81 | ␉␉␉dst[6] = src[6];␊ |
82 | ␉␉␉dst[7] = src[7];␊ |
83 | ␉␉␉for (byteCnt = 0; byteCnt < 0x20; byteCnt++) {␊ |
84 | ␉␉␉␉lowHalf += ((u_int8_t *) dst)[byteCnt];␊ |
85 | ␉␉␉␉highHalf += lowHalf;␊ |
86 | ␉␉␉}␊ |
87 | ␉␉␉src += 8;␊ |
88 | ␉␉␉dst += 8;␊ |
89 | ␉␉}␊ |
90 | ␉␉␊ |
91 | ␉␉lowHalf %= 65521L;␊ |
92 | ␉␉highHalf %= 65521L;␊ |
93 | ␉␉sum += (highHalf << 16) | lowHalf;␊ |
94 | ␉}␊ |
95 | ␉header->actualRestore1Sum = sum;␊ |
96 | ␉startprog (proc, header);␊ |
97 | ␉␊ |
98 | ␉return;␊ |
99 | }␊ |
100 | ␊ |
101 | void HibernateBoot(char *image_filename)␊ |
102 | {␊ |
103 | ␉long long size, imageSize, codeSize, allocSize;␊ |
104 | ␉long mem_base;␊ |
105 | ␉IOHibernateImageHeader _header;␊ |
106 | ␉IOHibernateImageHeader * header = &_header;␊ |
107 | ␉long buffer;␊ |
108 | ␉␊ |
109 | ␉size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader));␊ |
110 | ␉printf("header read size %x\n", size);␊ |
111 | ␉␉␊ |
112 | ␉imageSize = header->image1Size;␊ |
113 | ␉codeSize = header->restore1PageCount << 12;␊ |
114 | ␉if (kIOHibernateHeaderSignature != header->signature)␊ |
115 | ␉{␊ |
116 | ␉␉printf ("Incorrect image signature\n");␊ |
117 | ␉␉return;␊ |
118 | ␉}␊ |
119 | ␉if (header->encryptStart)␊ |
120 | ␉{␊ |
121 | ␉␉printf ("Resuming from Encrypted image is unsupported.\n"␊ |
122 | ␉␉␉␉"Uncheck \"Use secure virtual memory\" in \"Security\" pane on system preferences.\n"␊ |
123 | ␉␉␉␉"Press any key to proceed with normal boot.\n");␊ |
124 | ␉␉getc ();␊ |
125 | ␉␉return;␊ |
126 | ␉}␊ |
127 | // depends on NVRAM␊ |
128 | #if 0␊ |
129 | ␉{␊ |
130 | ␉␉uint32_t machineSignature;␊ |
131 | ␉␉size = GetProp(gChosenPH, kIOHibernateMachineSignatureKey, ␊ |
132 | ␉␉␉␉␉ (char *)&machineSignature, sizeof(machineSignature));␊ |
133 | ␉␉if (size != sizeof(machineSignature)) machineSignature = 0;␊ |
134 | ␉␉if (machineSignature != header->machineSignature)␊ |
135 | ␉␉␉break;␊ |
136 | ␉}␊ |
137 | #endif␊ |
138 | ␉␉␊ |
139 | ␉allocSize = imageSize + ((4095 + sizeof(hibernate_graphics_t)) & ~4095);␊ |
140 | ␊ |
141 | ␉mem_base = getmemorylimit() - allocSize;//TODO: lower this␊ |
142 | ␉␉␊ |
143 | ␉printf("mem_base %x\n", mem_base);␊ |
144 | ␉// Rek : hibernate fix ␊ |
145 | ␉if (!((long long)mem_base+allocSize<1024*bootInfo->extmem+0x100000))␊ |
146 | ␉{␊ |
147 | ␉␉printf ("Not enough space to restore image. Press any key to proceed with normal boot.\n");␊ |
148 | ␉␉getc ();␊ |
149 | ␉␉return;␊ |
150 | ␉}␊ |
151 | ␉␉␊ |
152 | ␉bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader));␊ |
153 | ␉header = (IOHibernateImageHeader *) mem_base;␊ |
154 | ␉␉␊ |
155 | ␉imageSize -= sizeof(IOHibernateImageHeader);␊ |
156 | ␉buffer = (long)(header + 1);␊ |
157 | ␉␊ |
158 | ␉if (header->previewSize)␊ |
159 | ␉{␊ |
160 | ␉␉uint64_t preview_offset = header->fileExtentMapSize - sizeof(header->fileExtentMap) + codeSize;␊ |
161 | ␉␉uint8_t progressSaveUnder[kIOHibernateProgressCount][kIOHibernateProgressSaveUnderSize];␊ |
162 | ␉␉␉␊ |
163 | ␉␉ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), preview_offset+header->previewSize);␊ |
164 | ␉␉drawPreview ((void *)(long)(buffer+preview_offset + header->previewPageListSize), &(progressSaveUnder[0][0]));␊ |
165 | ␉␉previewTotalSectors = (imageSize-(preview_offset+header->previewSize))/512;␊ |
166 | ␉␉previewLoadedSectors = 0;␊ |
167 | ␉␉previewSaveunder = &(progressSaveUnder[0][0]);␊ |
168 | ␉␉if (preview_offset+header->previewSize<imageSize)␊ |
169 | ␉␉␉ReadFileAtOffset (image_filename, (char *)(long)(buffer+preview_offset+header->previewSize), ␊ |
170 | ␉␉␉␉␉␉␉ sizeof(IOHibernateImageHeader)+preview_offset+header->previewSize,␊ |
171 | ␉␉␉␉␉␉␉ imageSize-(preview_offset+header->previewSize));␊ |
172 | ␉␉previewTotalSectors = 0;␊ |
173 | ␉␉previewLoadedSectors = 0;␊ |
174 | ␉␉previewSaveunder = 0;␉␉␊ |
175 | #if 0␊ |
176 | ␉␉AsereBLN:␊ |
177 | ␉␉check_vga_nvidia() didn''t work as expected (recursion level > 0 & return value).␊ |
178 | ␉␉Unforutnaltely I cannot find a note why to switch back to text mode for nVidia cards only␊ |
179 | ␉␉and because it check_vga_nvidia does not work (cards normally are behind a bridge) I will␊ |
180 | ␉␉remove it completely␊ |
181 | #if UNUSED␊ |
182 | ␉␉setVideoMode(VGA_TEXT_MODE, 0);␊ |
183 | #else␊ |
184 | ␉␉setVideoMode(VGA_TEXT_MODE);␊ |
185 | #endif␉␉␉␉␉␊ |
186 | ␉␉␊ |
187 | #endif␊ |
188 | ␉}␊ |
189 | ␉else␊ |
190 | ␉␉ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), imageSize);␊ |
191 | ␉␊ |
192 | // Depends on NVRAM␊ |
193 | #if 0␊ |
194 | ␉if (header->encryptStart) {␊ |
195 | ␉␉// decryption data␊ |
196 | ␉␉static const unsigned char first_iv[AES_BLOCK_SIZE]␊ |
197 | ␉␉= { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,␊ |
198 | ␉␉0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };␊ |
199 | ␉␉hibernate_cryptvars_t _cryptvars;␊ |
200 | ␉␉hibernate_cryptvars_t * cryptvars = &_cryptvars;␊ |
201 | ␉␉␊ |
202 | ␉␉aes_decrypt_key(&decryptkey,␊ |
203 | ␉␉␉␉␉␉decryptkeysize,␊ |
204 | ␉␉␉␉␉␉&cryptvars->ctx.decrypt);␊ |
205 | ␉␉␉␊ |
206 | ␉␉// set the vector for the following decryptions␊ |
207 | ␉␉bcopy(((uint8_t *) header) + header->image1Size - AES_BLOCK_SIZE, ␊ |
208 | ␉␉␉␉&cryptvars->aes_iv[0], AES_BLOCK_SIZE);␊ |
209 | ␉␉␉␊ |
210 | ␉␉// decrypt the buffer␊ |
211 | ␉␉uint32_t len = (uint32_t)(header->image1Size - header->encryptStart);␊ |
212 | ␉␉aes_decrypt_cbc(((uint8_t *) header) + header->encryptStart,␊ |
213 | ␉␉␉␉␉␉&first_iv[0],␊ |
214 | ␉␉␉␉␉␉len >> 4,␊ |
215 | ␉␉␉␉␉␉((uint8_t *) header) + header->encryptStart,␊ |
216 | ␉␉␉␉␉␉&cryptvars->ctx.decrypt);␊ |
217 | ␉␉bzero(&cryptvars->aes_iv[0], sizeof(cryptvars));␊ |
218 | ␉␉bzero(&decryptkey, sizeof(decryptkey));␊ |
219 | ␉}␊ |
220 | #endif␊ |
221 | ␉WakeKernel(header);␊ |
222 | }␊ |
223 | |