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