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 = dpm_list.prev;
192
193 while (entry != &dpm_list) {
194 struct device * dev = to_device(entry);
195 unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
196 if (hash == value) {
197 dev_info(dev, "hash matches\n");
198 match++;
199 }
200 entry = entry->prev;
201 }
202 return match;
203}
204
205static unsigned int hash_value_early_read;
206
207static int early_resume_init(void)
208{
209 hash_value_early_read = read_magic_time();
210 return 0;
211}
212
213static int late_resume_init(void)
214{
215 unsigned int val = hash_value_early_read;
216 unsigned int user, file, dev;
217
218 user = val % USERHASH;
219 val = val / USERHASH;
220 file = val % FILEHASH;
221 val = val / FILEHASH;
222 dev = val ;
223
224 printk(" Magic number: %d:%d:%d\n", user, file, dev);
225 show_file_hash(file);
226 show_dev_hash(dev);
227 return 0;
228}
229
230core_initcall(early_resume_init);
231late_initcall(late_resume_init);
232