1 | /*␊ |
2 | * platform_env.c␊ |
3 | * ␊ |
4 | * Copyright 2012 Cadet-petit Armel <armelcadetpetit@gmail.com>. All rights reserved.␊ |
5 | */␊ |
6 | ␊ |
7 | #include "libsaio.h"␊ |
8 | #include "bootstruct.h"␊ |
9 | #include "pci.h"␊ |
10 | #include "platform.h"␊ |
11 | #include "cpu.h"␊ |
12 | ␊ |
13 | #ifndef DEBUG_PLATFORM␊ |
14 | #define DEBUG_PLATFORM 0␊ |
15 | #endif␊ |
16 | ␊ |
17 | #if DEBUG_PLATFORM␊ |
18 | #define DBG(x...)␉printf(x)␊ |
19 | #else␊ |
20 | #define DBG(x...)␊ |
21 | #endif␊ |
22 | ␊ |
23 | static char *gboardproduct = NULL;␊ |
24 | static char *gPlatformName = NULL;␊ |
25 | static char *gRootDevice = NULL;␊ |
26 | ␊ |
27 | void SetgRootDevice(const char * str)␊ |
28 | {␊ |
29 | gRootDevice = (char*)str;␊ |
30 | }␊ |
31 | void Setgboardproduct(const char * str)␊ |
32 | {␊ |
33 | gboardproduct = (char*)str;␊ |
34 | }␊ |
35 | void SetgPlatformName(const char * str)␊ |
36 | {␊ |
37 | gPlatformName = (char*)str;␊ |
38 | }␊ |
39 | ␊ |
40 | char * GetgPlatformName(void)␊ |
41 | {␊ |
42 | return gPlatformName ;␊ |
43 | }␊ |
44 | char * Getgboardproduct(void)␊ |
45 | {␊ |
46 | return gboardproduct;␊ |
47 | }␊ |
48 | char * GetgRootDevice(void)␊ |
49 | {␊ |
50 | return gRootDevice;␊ |
51 | }␊ |
52 | ␊ |
53 | #ifdef rootpath␊ |
54 | static char gRootPath[ROOT_PATH_LEN];␊ |
55 | void SetgRootPath(const char * str)␊ |
56 | {␊ |
57 | bzero(gRootPath,sizeof(gRootPath));␊ |
58 | memcpy(gRootPath,str, sizeof(gRootPath));␊ |
59 | }␊ |
60 | char * GetgRootPath(void)␊ |
61 | {␊ |
62 | return gRootPath ;␊ |
63 | }␊ |
64 | #endif␊ |
65 | ␊ |
66 | typedef enum envtype {␊ |
67 | kEnvPtr = 0,␊ |
68 | kEnvValue = 1␊ |
69 | } envtype;␊ |
70 | ␊ |
71 | struct env_struct {␊ |
72 | unsigned long long value; ␊ |
73 | char name[10]; ␊ |
74 | void * ptr;␊ |
75 | //int lock;␊ |
76 | enum envtype Type;␊ |
77 | UT_hash_handle hh; /* makes this structure hashable */␊ |
78 | };␊ |
79 | ␊ |
80 | static void CopyVarPtr (struct env_struct *var, void* ptr, size_t size);␊ |
81 | static struct env_struct *find_env(const char *name);␊ |
82 | static void _re_set_env_copy(struct env_struct *var , void* ptr,size_t size);␊ |
83 | struct env_struct *platform_env = NULL;␊ |
84 | ␊ |
85 | ␊ |
86 | static void CopyVarPtr (struct env_struct *var, void* ptr, size_t size)␊ |
87 | {␊ |
88 | var->ptr = malloc(size);␊ |
89 | memcpy(var->ptr, ptr, size);␊ |
90 | }␊ |
91 | ␊ |
92 | static struct env_struct *find_env(const char *name) {␊ |
93 | struct env_struct *var;␊ |
94 | ␊ |
95 | ␉if (setjmp(h_buf_error) == -1) {␊ |
96 | #if DEBUG_PLATFORM␊ |
97 | ␉␉printf("find_env: Unable to find environement variable\n"); ␊ |
98 | getc();␊ |
99 | #endif␊ |
100 | ␉␉return NULL;␊ |
101 | ␉} else {␊ |
102 | ␉␉HASH_FIND_STR( platform_env, name, var ); ␊ |
103 | ␉}␊ |
104 | return var;␊ |
105 | }␊ |
106 | ␊ |
107 | static void _re_set_env_copy(struct env_struct *var , void* ptr,size_t size) {␊ |
108 | ␊ |
109 | ␉if (var->Type == kEnvPtr) {␊ |
110 | ␉␉return ;␊ |
111 | ␉} ␊ |
112 | ␊ |
113 | if (var->ptr) {␊ |
114 | free(var->ptr);␊ |
115 | var->ptr = NULL;␊ |
116 | }␊ |
117 | ␊ |
118 | CopyVarPtr(var, ptr, size);␊ |
119 | ␉␊ |
120 | ␉return; ␊ |
121 | }␊ |
122 | ␊ |
123 | void re_set_env_copy(const char *name , void* ptr,size_t size) {␊ |
124 | ␉struct env_struct *var;␊ |
125 | ␊ |
126 | ␉var = find_env(name);␊ |
127 | ␉if (!var|| (var->Type == kEnvPtr)) {␊ |
128 | ␉␉printf("re_set_env_copy: Unable to find environement variable %s\n",name);␊ |
129 | #if DEBUG_PLATFORM␊ |
130 | getc();␊ |
131 | #endif␊ |
132 | ␉␉return ;␊ |
133 | ␉} ␊ |
134 | ␊ |
135 | _re_set_env_copy(var , ptr, size);␊ |
136 | ␉␊ |
137 | ␉return; ␊ |
138 | }␊ |
139 | ␊ |
140 | static void _set_env(const char *name, unsigned long long value, enum envtype Type, void* ptr, size_t size ) {␊ |
141 | struct env_struct *var;␊ |
142 | ␊ |
143 | var = (struct env_struct*)malloc(sizeof(struct env_struct));␊ |
144 | if (Type == kEnvPtr) {␊ |
145 | CopyVarPtr( var, ptr, size);␊ |
146 | } ␊ |
147 | else if (Type == kEnvValue) ␊ |
148 | var->value = value;␊ |
149 | else␊ |
150 | return;␊ |
151 | ␊ |
152 | var->Type = Type;␊ |
153 | ␊ |
154 | strlcpy(var->name, name, sizeof(var->name));␊ |
155 | ␉␊ |
156 | ␉if (setjmp(h_buf_error) == -1) {␊ |
157 | ␉␉printf("_set_env: Unable to set environement variable"); // don't try to acces to the string 'name', ␊ |
158 | ␉␉//'cause we just returned from the longjump, stack as already changed state.␊ |
159 | #if DEBUG_PLATFORM␊ |
160 | ␉␉getc();␊ |
161 | #endif␊ |
162 | ␉␉return;␊ |
163 | ␉} else {␊ |
164 | ␉␉HASH_ADD_STR( platform_env, name, var );␊ |
165 | ␉}␊ |
166 | }␊ |
167 | ␊ |
168 | /* Warning: set_env will create a new variable each time it will be called, ␊ |
169 | * if you want to set again an existing variable, please use safe_set_env or re_set_env .␊ |
170 | * NOTE: If you set several times the "same variable" by using this function,␊ |
171 | * the HASH_COUNT will grow up, ␊ |
172 | * but hopefully find_env will return the last variable that you have set with the same name␊ |
173 | * ex: set_env("test",10);␊ |
174 | * set_env("test",20);␊ |
175 | *␊ |
176 | * HASH_COUNT will be equal to 2, get_env("test") will return 20␊ |
177 | *␊ |
178 | * safe_set_env("test",10);␊ |
179 | * safe_set_env("test",20);␊ |
180 | * ␊ |
181 | * HASH_COUNT will be equal to 1, get_env("test") will return 20␊ |
182 | *␊ |
183 | * set_env("test",10);␊ |
184 | * re_set_env("test",20);␊ |
185 | *␊ |
186 | * HASH_COUNT will be equal to 1, get_env("test") will return 20␊ |
187 | *␊ |
188 | */␊ |
189 | void set_env(const char *name, unsigned long long value ) {␊ |
190 | _set_env(name, value, kEnvValue,0,0);␊ |
191 | }␊ |
192 | ␊ |
193 | void set_env_copy(const char *name, void * ptr, size_t size ) {␊ |
194 | _set_env(name, 0, kEnvPtr,ptr,size);␊ |
195 | }␊ |
196 | ␊ |
197 | unsigned long long get_env_var(const char *name) {␊ |
198 | ␉struct env_struct *var;␊ |
199 | ␊ |
200 | ␉var = find_env(name);␊ |
201 | ␉if (!var) {␊ |
202 | #if DEBUG_PLATFORM␊ |
203 | ␉␉printf("get_env_var: Unable to find environement variable %s\n",name);␊ |
204 | getc();␊ |
205 | #endif␊ |
206 | ␉␉return 0;␊ |
207 | ␉}␊ |
208 | ␊ |
209 | if (var->Type != kEnvValue) {␊ |
210 | printf("get_env_var: Variable %s is not a value\n",name);␊ |
211 | #if DEBUG_PLATFORM␊ |
212 | getc();␊ |
213 | #endif␊ |
214 | return 0;␊ |
215 | }␊ |
216 | ␉␊ |
217 | ␉return var->value;␊ |
218 | ␊ |
219 | }␊ |
220 | ␊ |
221 | unsigned long long get_env(const char *name) {␉␊ |
222 | ␉␊ |
223 | ␉return get_env_var(name);;␊ |
224 | ␊ |
225 | }␊ |
226 | ␊ |
227 | void * get_env_ptr(const char *name) {␊ |
228 | ␉struct env_struct *var;␊ |
229 | ␊ |
230 | ␉var = find_env(name);␊ |
231 | ␉if (!var) {␊ |
232 | #if DEBUG_PLATFORM␊ |
233 | ␉␉printf("get_env_ptr: Unable to get environement ptr variable %s\n",name);␊ |
234 | getc();␊ |
235 | #endif␊ |
236 | ␉␉return 0;␊ |
237 | ␉}␊ |
238 | ␊ |
239 | if (var->Type != kEnvPtr) {␊ |
240 | printf("get_env_ptr: Variable %s is not a ptr\n",name);␊ |
241 | #if DEBUG_PLATFORM␊ |
242 | getc();␊ |
243 | #endif␊ |
244 | return 0;␊ |
245 | }␊ |
246 | ␉␊ |
247 | ␉return var->ptr;␊ |
248 | ␊ |
249 | }␊ |
250 | ␊ |
251 | /* If no specified variable exist, safe_set_env will create one, else it only modify the value */␊ |
252 | static void _safe_set_env(const char *name, unsigned long long value, enum envtype Type, void* ptr, size_t size )␊ |
253 | {␊ |
254 | ␉struct env_struct *var;␊ |
255 | ␊ |
256 | ␉var = find_env(name);␊ |
257 | ␊ |
258 | if (!var) {␊ |
259 | if (Type == kEnvPtr) {␊ |
260 | _set_env(name, 0, kEnvPtr,ptr,size);␊ |
261 | } ␊ |
262 | else if (Type == kEnvValue) {␊ |
263 | _set_env(name, value, kEnvValue,0,0);␊ |
264 | }␊ |
265 | } ␊ |
266 | else if (var->Type != Type) {␊ |
267 | return; ␊ |
268 | ␉} ␊ |
269 | else {␊ |
270 | if (Type == kEnvValue) ␊ |
271 | var->value = value;␊ |
272 | else if (Type == kEnvPtr)␊ |
273 | _re_set_env_copy(var,ptr,size); ␊ |
274 | }␊ |
275 | ␉␊ |
276 | ␉return; ␊ |
277 | }␊ |
278 | ␊ |
279 | void safe_set_env_copy(const char *name , void * ptr, size_t size ) {␊ |
280 | ␊ |
281 | _safe_set_env(name, 0, kEnvPtr,ptr,size);␊ |
282 | ␉␊ |
283 | ␉return; ␊ |
284 | }␊ |
285 | ␊ |
286 | void safe_set_env(const char *name , unsigned long long value) {␊ |
287 | ␊ |
288 | _safe_set_env(name, value, kEnvValue,0,0);␊ |
289 | ␉␊ |
290 | ␉return; ␊ |
291 | }␊ |
292 | ␊ |
293 | void re_set_env(const char *name , unsigned long long value) {␊ |
294 | ␉struct env_struct *var;␊ |
295 | ␊ |
296 | ␉var = find_env(name);␊ |
297 | ␉if (!var || (var->Type == kEnvValue)) {␊ |
298 | ␉␉printf("re_set_env: Unable to reset environement value variable %s\n",name);␊ |
299 | #if DEBUG_PLATFORM␊ |
300 | getc();␊ |
301 | #endif␊ |
302 | ␉␉return ;␊ |
303 | ␉} ␊ |
304 | ␊ |
305 | var->value = value;␊ |
306 | ␉␊ |
307 | ␉return; ␊ |
308 | }␊ |
309 | ␊ |
310 | static void delete_env(struct env_struct *var) {␊ |
311 | ␉␊ |
312 | ␉if (setjmp(h_buf_error) == -1) {␊ |
313 | ␉␉printf("delete_env: Unable to delete environement variable\n");␊ |
314 | #if DEBUG_PLATFORM␊ |
315 | getc();␉␊ |
316 | #endif␊ |
317 | ␉␉return;␊ |
318 | ␉} else {␊ |
319 | ␉␉HASH_DEL( platform_env, var); ␊ |
320 | ␉}␊ |
321 | free(var);␊ |
322 | }␊ |
323 | ␊ |
324 | void unset_env(const char *name) {␊ |
325 | struct env_struct *var;␊ |
326 | ␊ |
327 | if ((var = find_env(name))) {␊ |
328 | delete_env(var);␊ |
329 | } ␊ |
330 | }␊ |
331 | ␊ |
332 | void free_platform_env(void) {␊ |
333 | struct env_struct *current_var, *tmp; ␊ |
334 | ␊ |
335 | ␉if (setjmp(h_buf_error) == -1) {␊ |
336 | ␉␉printf("free_platform_env: Unable to delete all environement variables\n"); ␊ |
337 | #if DEBUG_PLATFORM␊ |
338 | ␉␉getc();␊ |
339 | #endif␊ |
340 | ␉␉return;␊ |
341 | ␉} else {␊ |
342 | ␉␉HASH_ITER(hh, platform_env, current_var, tmp) { ␊ |
343 | ␉␉␉HASH_DEL(platform_env,current_var);␊ |
344 | ␉␉␉free(current_var); ␊ |
345 | ␉␉}␊ |
346 | ␉} ␊ |
347 | }␊ |
348 | ␊ |
349 | #if DEBUG_PLATFORM␊ |
350 | void debug_platform_env(void)␊ |
351 | {␊ |
352 | struct env_struct *current_var = platform_env;␊ |
353 | for(current_var=platform_env;current_var;current_var=(struct env_struct*)(current_var->hh.next)) ␊ |
354 | {␊ |
355 | if (current_var->Type == kEnvValue)␊ |
356 | printf(" Name = %s | Type = VALUE | Value = 0x%04x\n",current_var->name,(uint32_t)current_var->value);␊ |
357 | else if (current_var->Type == kEnvPtr )␊ |
358 | printf(" Name = %s | Type = PTR(Copy) | Value = 0x%x\n",current_var->name,(uint32_t)current_var->ptr);␊ |
359 | ␊ |
360 | }␊ |
361 | getc();␊ |
362 | }␊ |
363 | #endif␊ |
364 | ␊ |
365 | /** ␊ |
366 | Scan platform hardware information, called by the main entry point (common_boot() ) ␊ |
367 | _before_ bootConfig xml parsing settings are loaded␊ |
368 | */␊ |
369 | void scan_platform(void)␊ |
370 | {␉␊ |
371 | ␉//memset(&Platform, 0, sizeof(PlatformInfo_t));␊ |
372 | ␉build_pci_dt();␊ |
373 | ␉scan_cpu();␊ |
374 | ␊ |
375 | #if DEBUG_PLATFORM␊ |
376 | DBG("CPU: %s\n", (char*)get_env_ptr(envBrandString));␊ |
377 | if (get_env(envVendor) == CPUID_VENDOR_AMD)␊ |
378 | ␉DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", (uint32_t)get_env(envVendor), (uint32_t)get_env(envModel), (uint32_t)get_env(envExtModel));␊ |
379 | ␉DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", (uint32_t)get_env(envFamily), (uint32_t)get_env(envExtFamily));␊ |
380 | if (get_env(envVendor) == CPUID_VENDOR_AMD) {␊ |
381 | DBG("CPU (AMD): TSCFreq: %dMHz\n", (uint32_t)(get_env(envTSCFreq) / 1000000));␊ |
382 | DBG("CPU (AMD): FSBFreq: %dMHz\n", (uint32_t)(get_env(envFSBFreq) / 1000000));␊ |
383 | DBG("CPU (AMD): CPUFreq: %dMHz\n", (uint32_t)(get_env(envCPUFreq) / 1000000));␊ |
384 | DBG("CPU (AMD): MaxCoef/CurrCoef: 0x%x/0x%x\n", (uint32_t)get_env(envMaxCoef), (uint32_t)get_env(envCurrCoef));␊ |
385 | DBG("CPU (AMD): MaxDiv/CurrDiv: 0x%x/0x%x\n", (uint32_t)get_env(envMaxDiv), (uint32_t)get_env(envCurrDiv));␊ |
386 | } else if (get_env(envVendor) == CPUID_VENDOR_INTEL){␊ |
387 | DBG("CPU: TSCFreq: %dMHz\n", (uint32_t)(get_env(envTSCFreq) / 1000000));␊ |
388 | DBG("CPU: FSBFreq: %dMHz\n", (uint32_t)(get_env(envFSBFreq) / 1000000));␊ |
389 | DBG("CPU: CPUFreq: %dMHz\n", (uint32_t)(get_env(envCPUFreq) / 1000000));␊ |
390 | DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", (uint32_t)(get_env(envMaxCoef)), (uint32_t)(get_env(envCurrCoef)));␊ |
391 | DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", (uint32_t)(get_env(envMaxDiv)), (uint32_t)(get_env(envCurrDiv)));␊ |
392 | }␉␉␉␊ |
393 | ␉␊ |
394 | ␉DBG("CPU: NoCores/NoThreads: %d/%d\n", (uint32_t)(get_env(envNoCores)), (uint32_t)(get_env(envNoThreads)));␊ |
395 | ␉DBG("CPU: Features: 0x%08x\n", (uint32_t)(get_env(envFeatures)));␊ |
396 | DBG("CPU: ExtFeatures: 0x%08x\n", (uint32_t)(get_env(envExtFeatures)));␊ |
397 | #ifndef AMD_SUPPORT␊ |
398 | DBG("CPU: MicrocodeVersion: %d\n", (uint32_t)(get_env(envMicrocodeVersion)));␊ |
399 | #endif␊ |
400 | pause();␊ |
401 | #endif␊ |
402 | }␊ |
403 | ␊ |
404 | #ifdef ShowCurrentDate␊ |
405 | ␊ |
406 | // shamefully ripped to http://wiki.osdev.org/CMOS␊ |
407 | ␊ |
408 | /*␊ |
409 | * http://wiki.osdev.org/OSDev_Wiki:General_disclaimer␊ |
410 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR␊ |
411 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,␊ |
412 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE␊ |
413 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER␊ |
414 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,␊ |
415 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN␊ |
416 | * THE SOFTWARE.␊ |
417 | */␊ |
418 | ␊ |
419 | #define CURRENT_YEAR 2012 // Change this each year!␊ |
420 | ␊ |
421 | static int century_register = 0x00; // Set by ACPI table parsing code if possible(... in FADT table)␊ |
422 | ␊ |
423 | enum {␊ |
424 | cmos_address = 0x70,␊ |
425 | cmos_data = 0x71␊ |
426 | };␊ |
427 | ␊ |
428 | ␊ |
429 | static int get_update_in_progress_flag() {␊ |
430 | outb(cmos_address, 0x0A);␊ |
431 | return (inb(cmos_data) & 0x80);␊ |
432 | }␊ |
433 | ␊ |
434 | ␊ |
435 | static unsigned char get_RTC_register(int reg) {␊ |
436 | outb(cmos_address, reg);␊ |
437 | return inb(cmos_data);␊ |
438 | }␊ |
439 | ␊ |
440 | static void read_rtc(EFI_TIME *time) {␊ |
441 | unsigned char century;␊ |
442 | unsigned char last_second;␊ |
443 | unsigned char last_minute;␊ |
444 | unsigned char last_hour;␊ |
445 | unsigned char last_day;␊ |
446 | unsigned char last_month;␊ |
447 | unsigned char last_year;␊ |
448 | unsigned char last_century;␊ |
449 | unsigned char registerB;␊ |
450 | ␊ |
451 | unsigned char second;␊ |
452 | unsigned char minute;␊ |
453 | unsigned char hour;␊ |
454 | unsigned char day;␊ |
455 | unsigned char month;␊ |
456 | unsigned int year;␊ |
457 | // Note: This uses the "read registers until you get the same values twice in a row" technique␊ |
458 | // to avoid getting dodgy/inconsistent values due to RTC updates␊ |
459 | ␊ |
460 | while (get_update_in_progress_flag()); // Make sure an update isn't in progress␊ |
461 | second = get_RTC_register(0x00);␊ |
462 | minute = get_RTC_register(0x02);␊ |
463 | hour = get_RTC_register(0x04);␊ |
464 | day = get_RTC_register(0x07);␊ |
465 | month = get_RTC_register(0x08);␊ |
466 | year = get_RTC_register(0x09);␊ |
467 | if(century_register != 0) {␊ |
468 | century = get_RTC_register(century_register);␊ |
469 | }␊ |
470 | ␊ |
471 | do {␊ |
472 | last_second = second;␊ |
473 | last_minute = minute;␊ |
474 | last_hour = hour;␊ |
475 | last_day = day;␊ |
476 | last_month = month;␊ |
477 | last_year = year;␊ |
478 | last_century = century;␊ |
479 | ␊ |
480 | while (get_update_in_progress_flag()); // Make sure an update isn't in progress␊ |
481 | second = get_RTC_register(0x00);␊ |
482 | minute = get_RTC_register(0x02);␊ |
483 | hour = get_RTC_register(0x04);␊ |
484 | day = get_RTC_register(0x07);␊ |
485 | month = get_RTC_register(0x08);␊ |
486 | year = get_RTC_register(0x09);␊ |
487 | if(century_register != 0) {␊ |
488 | century = get_RTC_register(century_register);␊ |
489 | }␊ |
490 | } while( (last_second == second) && (last_minute == minute) && (last_hour == hour) &&␊ |
491 | (last_day == day) && (last_month == month) && (last_year == year) &&␊ |
492 | (last_century == century) );␊ |
493 | ␊ |
494 | registerB = get_RTC_register(0x0B);␊ |
495 | ␊ |
496 | // Convert BCD to binary values if necessary␊ |
497 | ␊ |
498 | if (!(registerB & 0x04)) {␊ |
499 | second = (second & 0x0F) + ((second / 16) * 10);␊ |
500 | minute = (minute & 0x0F) + ((minute / 16) * 10);␊ |
501 | hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);␊ |
502 | day = (day & 0x0F) + ((day / 16) * 10);␊ |
503 | month = (month & 0x0F) + ((month / 16) * 10);␊ |
504 | year = (year & 0x0F) + ((year / 16) * 10);␊ |
505 | if(century_register != 0) {␊ |
506 | century = (century & 0x0F) + ((century / 16) * 10);␊ |
507 | }␊ |
508 | } ␊ |
509 | ␊ |
510 | // Calculate the full (4-digit) year␊ |
511 | ␊ |
512 | if(century_register != 0) {␊ |
513 | year += century * 100;␊ |
514 | } else {␊ |
515 | //year += (CURRENT_YEAR / 100) * 100;␊ |
516 | //if(year < CURRENT_YEAR) year += 100; ␊ |
517 | ␊ |
518 | if ((year += 1900) < 1970)␊ |
519 | year += 100;␊ |
520 | }␊ |
521 | ␊ |
522 | time->Second = second;␊ |
523 | time->Minute = minute;␊ |
524 | time->Hour = hour;␊ |
525 | time->Day = day;␊ |
526 | time->Month = month;␊ |
527 | time->Year = year;␊ |
528 | }␊ |
529 | ␊ |
530 | void rtc_time(EFI_TIME *time) {␊ |
531 | ␊ |
532 | read_rtc(time); ␊ |
533 | ␊ |
534 | return ;␊ |
535 | }␊ |
536 | ␊ |
537 | char * Date(void)␊ |
538 | {␊ |
539 | EFI_TIME rtctime; ␊ |
540 | rtc_time(&rtctime);␊ |
541 | ␊ |
542 | return newStringWithFormat("%02d/%02d/%04d %02d:%02d:%02d",rtctime.Month,rtctime.Day,rtctime.Year,␊ |
543 | rtctime.Hour,rtctime.Minute,rtctime.Second));␊ |
544 | }␊ |
545 | #endif |