1
2
3
4
5
6
7
8
9
10#include <linux/resume-trace.h>
11#include <linux/rtc.h>
12
13#include <asm/rtc.h>
14
15#include "power.h"
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#define USERHASH (16)
71#define FILEHASH (997)
72#define DEVHASH (1009)
73
74#define DEVSEED (7919)
75
76static unsigned int dev_hash_value;
77
78static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
79{
80 unsigned int n = user + USERHASH*(file + FILEHASH*device);
81
82
83 static struct rtc_time time = {
84 .tm_sec = 0,
85 .tm_min = 0,
86 .tm_hour = 0,
87 .tm_mday = 7,
88 .tm_mon = 5,
89 .tm_year = 106,
90 .tm_wday = 3,
91 .tm_yday = 160,
92 .tm_isdst = 1
93 };
94
95 time.tm_year = (n % 100);
96 n /= 100;
97 time.tm_mon = (n % 12);
98 n /= 12;
99 time.tm_mday = (n % 28) + 1;
100 n /= 28;
101 time.tm_hour = (n % 24);
102 n /= 24;
103 time.tm_min = (n % 20) * 3;
104 n /= 20;
105 set_rtc_time(&time);
106 return n ? -1 : 0;
107}
108
109static unsigned int read_magic_time(void)
110{
111 struct rtc_time time;
112 unsigned int val;
113
114 get_rtc_time(&time);
115 printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
116 time.tm_hour, time.tm_min, time.tm_sec,
117 time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
118 val = time.tm_year;
119 if (val > 100)
120 val -= 100;
121 val += time.tm_mon * 100;
122 val += (time.tm_mday-1) * 100 * 12;
123 val += time.tm_hour * 100 * 12 * 28;
124 val += (time.tm_min / 3) * 100 * 12 * 28 * 24;
125 return val;
126}
127
128
129
130
131
132static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod)
133{
134 unsigned char c;
135 while ((c = *data++) != 0) {
136 seed = (seed << 16) + (seed << 6) - seed + c;
137 }
138 return seed % mod;
139}
140
141void set_trace_device(struct device *dev)
142{
143 dev_hash_value = hash_string(DEVSEED, dev_name(dev), DEVHASH);
144}
145EXPORT_SYMBOL(set_trace_device);
146
147
148
149
150
151
152
153
154
155
156void generate_resume_trace(const void *tracedata, unsigned int user)
157{
158 unsigned short lineno = *(unsigned short *)tracedata;
159 const char *file = *(const char **)(tracedata + 2);
160 unsigned int user_hash_value, file_hash_value;
161
162 user_hash_value = user % USERHASH;
163 file_hash_value = hash_string(lineno, file, FILEHASH);
164 set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
165}
166EXPORT_SYMBOL(generate_resume_trace);
167
168extern char __tracedata_start, __tracedata_end;
169static int show_file_hash(unsigned int value)
170{
171 int match;
172 char *tracedata;
173
174 match = 0;
175 for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
176 tracedata += 2 + sizeof(unsigned long)) {
177 unsigned short lineno = *(unsigned short *)tracedata;
178 const char *file = *(const char **)(tracedata + 2);
179 unsigned int hash = hash_string(lineno, file, FILEHASH);
180 if (hash != value)
181 continue;
182 printk(" hash matches %s:%u\n", file, lineno);
183 match++;
184 }
185 return match;
186}
187
188static int show_dev_hash(unsigned int value)
189{
190 int match = 0;
191 struct list_head *entry;
192
193 device_pm_lock();
194 entry = dpm_list.prev;
195 while (entry != &dpm_list) {
196 struct device * dev = to_device(entry);
197 unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
198 if (hash == value) {
199 dev_info(dev, "hash matches\n");
200 match++;
201 }
202 entry = entry->prev;
203 }
204 device_pm_unlock();
205 return match;
206}
207
208static unsigned int hash_value_early_read;
209
210int show_trace_dev_match(char *buf, size_t size)
211{
212 unsigned int value = hash_value_early_read / (USERHASH * FILEHASH);
213 int ret = 0;
214 struct list_head *entry;
215
216
217
218
219
220 device_pm_lock();
221 entry = dpm_list.prev;
222 while (size && entry != &dpm_list) {
223 struct device *dev = to_device(entry);
224 unsigned int hash = hash_string(DEVSEED, dev_name(dev),
225 DEVHASH);
226 if (hash == value) {
227 int len = snprintf(buf, size, "%s\n",
228 dev_driver_string(dev));
229 if (len > size)
230 len = size;
231 buf += len;
232 ret += len;
233 size -= len;
234 }
235 entry = entry->prev;
236 }
237 device_pm_unlock();
238 return ret;
239}
240
241static int early_resume_init(void)
242{
243 hash_value_early_read = read_magic_time();
244 return 0;
245}
246
247static int late_resume_init(void)
248{
249 unsigned int val = hash_value_early_read;
250 unsigned int user, file, dev;
251
252 user = val % USERHASH;
253 val = val / USERHASH;
254 file = val % FILEHASH;
255 val = val / FILEHASH;
256 dev = val ;
257
258 printk(" Magic number: %d:%d:%d\n", user, file, dev);
259 show_file_hash(file);
260 show_dev_hash(dev);
261 return 0;
262}
263
264core_initcall(early_resume_init);
265late_initcall(late_resume_init);
266