|
|
1.1 root 1: // 16bit code to handle system clocks.
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
4: // Copyright (C) 2002 MandrakeSoft S.A.
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 license.
7:
8: #include "biosvar.h" // SET_BDA
9: #include "util.h" // debug_enter
10: #include "disk.h" // floppy_tick
11: #include "cmos.h" // inb_cmos
12: #include "pic.h" // eoi_pic1
13: #include "bregs.h" // struct bregs
14: #include "biosvar.h" // GET_GLOBAL
15: #include "usb-hid.h" // usb_check_key
16:
17: // RTC register flags
18: #define RTC_A_UIP 0x80
19:
20: #define RTC_B_SET 0x80
21: #define RTC_B_PIE 0x40
22: #define RTC_B_AIE 0x20
23: #define RTC_B_UIE 0x10
24: #define RTC_B_BIN 0x04
25: #define RTC_B_24HR 0x02
26: #define RTC_B_DSE 0x01
27:
28:
29: // Bits for PORT_PS2_CTRLB
30: #define PPCB_T2GATE (1<<0)
31: #define PPCB_SPKR (1<<1)
32: #define PPCB_T2OUT (1<<5)
33:
34: // Bits for PORT_PIT_MODE
35: #define PM_SEL_TIMER0 (0<<6)
36: #define PM_SEL_TIMER1 (1<<6)
37: #define PM_SEL_TIMER2 (2<<6)
38: #define PM_SEL_READBACK (3<<6)
39: #define PM_ACCESS_LATCH (0<<4)
40: #define PM_ACCESS_LOBYTE (1<<4)
41: #define PM_ACCESS_HIBYTE (2<<4)
42: #define PM_ACCESS_WORD (3<<4)
43: #define PM_MODE0 (0<<1)
44: #define PM_MODE1 (1<<1)
45: #define PM_MODE2 (2<<1)
46: #define PM_MODE3 (3<<1)
47: #define PM_MODE4 (4<<1)
48: #define PM_MODE5 (5<<1)
49: #define PM_CNT_BINARY (0<<0)
50: #define PM_CNT_BCD (1<<0)
51:
52:
53: /****************************************************************
54: * TSC timer
55: ****************************************************************/
56:
57: #define PIT_TICK_RATE 1193180 // Underlying HZ of PIT
58: #define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
59: #define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
60: #define CALIBRATE_COUNT 0x800 // Approx 1.7ms
61:
62: u32 cpu_khz VAR16VISIBLE;
63:
64: static void
65: calibrate_tsc()
66: {
67: // Setup "timer2"
68: u8 orig = inb(PORT_PS2_CTRLB);
69: outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
70: /* binary, mode 0, LSB/MSB, Ch 2 */
71: outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
72: /* LSB of ticks */
73: outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
74: /* MSB of ticks */
75: outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
76:
77: u64 start = rdtscll();
78: while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
79: ;
80: u64 end = rdtscll();
81:
82: // Restore PORT_PS2_CTRLB
83: outb(orig, PORT_PS2_CTRLB);
84:
85: // Store calibrated cpu khz.
86: u64 diff = end - start;
87: dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
88: , (u32)start, (u32)end, (u32)diff);
89: u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
90: SET_GLOBAL(cpu_khz, hz / 1000);
91:
92: dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
93: }
94:
95: static void
96: tscdelay(u64 diff)
97: {
98: u64 start = rdtscll();
99: u64 end = start + diff;
100: while (!check_time(end))
101: cpu_relax();
102: }
103:
104: static void
105: tscsleep(u64 diff)
106: {
107: u64 start = rdtscll();
108: u64 end = start + diff;
109: while (!check_time(end))
110: yield();
111: }
112:
113: void ndelay(u32 count) {
114: tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
115: }
116: void udelay(u32 count) {
117: tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
118: }
119: void mdelay(u32 count) {
120: tscdelay(count * GET_GLOBAL(cpu_khz));
121: }
122:
123: void nsleep(u32 count) {
124: tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
125: }
126: void usleep(u32 count) {
127: tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
128: }
129: void msleep(u32 count) {
130: tscsleep(count * GET_GLOBAL(cpu_khz));
131: }
132:
133: // Return the TSC value that is 'msecs' time in the future.
134: u64
135: calc_future_tsc(u32 msecs)
136: {
137: u32 khz = GET_GLOBAL(cpu_khz);
138: return rdtscll() + ((u64)khz * msecs);
139: }
140: u64
141: calc_future_tsc_usec(u32 usecs)
142: {
143: u32 khz = GET_GLOBAL(cpu_khz);
144: return rdtscll() + ((u64)(khz/1000) * usecs);
145: }
146:
147:
148: /****************************************************************
149: * Init
150: ****************************************************************/
151:
152: static int
153: rtc_updating()
154: {
155: // This function checks to see if the update-in-progress bit
156: // is set in CMOS Status Register A. If not, it returns 0.
157: // If it is set, it tries to wait until there is a transition
158: // to 0, and will return 0 if such a transition occurs. A -1
159: // is returned only after timing out. The maximum period
160: // that this bit should be set is constrained to (1984+244)
161: // useconds, so we wait for 3 msec max.
162:
163: if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
164: return 0;
165: u64 end = calc_future_tsc(3);
166: do {
167: if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
168: return 0;
169: } while (!check_time(end));
170:
171: // update-in-progress never transitioned to 0
172: return -1;
173: }
174:
175: static void
176: pit_setup()
177: {
178: // timer0: binary count, 16bit count, mode 2
179: outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
180: // maximum count of 0000H = 18.2Hz
181: outb(0x0, PORT_PIT_COUNTER0);
182: outb(0x0, PORT_PIT_COUNTER0);
183: }
184:
185: static void
186: init_rtc()
187: {
188: outb_cmos(0x26, CMOS_STATUS_A); // 32,768Khz src, 976.5625us updates
189: u8 regB = inb_cmos(CMOS_STATUS_B);
190: outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B);
191: inb_cmos(CMOS_STATUS_C);
192: inb_cmos(CMOS_STATUS_D);
193: }
194:
195: static u32
196: bcd2bin(u8 val)
197: {
198: return (val & 0xf) + ((val >> 4) * 10);
199: }
200:
201: void
202: timer_setup()
203: {
204: dprintf(3, "init timer\n");
205: calibrate_tsc();
206: pit_setup();
207:
208: init_rtc();
209: rtc_updating();
210: u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
211: u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
212: u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
213: u32 ticks = (hours * 60 + minutes) * 60 + seconds;
214: ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
215: SET_BDA(timer_counter, ticks);
216: SET_BDA(timer_rollover, 0);
217:
218: enable_hwirq(0, entry_08);
219: enable_hwirq(8, entry_70);
220: }
221:
222:
223: /****************************************************************
224: * Standard clock functions
225: ****************************************************************/
226:
227: // get current clock count
228: static void
229: handle_1a00(struct bregs *regs)
230: {
231: u32 ticks = GET_BDA(timer_counter);
232: regs->cx = ticks >> 16;
233: regs->dx = ticks;
234: regs->al = GET_BDA(timer_rollover);
235: SET_BDA(timer_rollover, 0); // reset flag
236: set_success(regs);
237: }
238:
239: // Set Current Clock Count
240: static void
241: handle_1a01(struct bregs *regs)
242: {
243: u32 ticks = (regs->cx << 16) | regs->dx;
244: SET_BDA(timer_counter, ticks);
245: SET_BDA(timer_rollover, 0); // reset flag
246: // XXX - should use set_code_success()?
247: regs->ah = 0;
248: set_success(regs);
249: }
250:
251: // Read CMOS Time
252: static void
253: handle_1a02(struct bregs *regs)
254: {
255: if (rtc_updating()) {
256: set_invalid(regs);
257: return;
258: }
259:
260: regs->dh = inb_cmos(CMOS_RTC_SECONDS);
261: regs->cl = inb_cmos(CMOS_RTC_MINUTES);
262: regs->ch = inb_cmos(CMOS_RTC_HOURS);
263: regs->dl = inb_cmos(CMOS_STATUS_B) & RTC_B_DSE;
264: regs->ah = 0;
265: regs->al = regs->ch;
266: set_success(regs);
267: }
268:
269: // Set CMOS Time
270: static void
271: handle_1a03(struct bregs *regs)
272: {
273: // Using a debugger, I notice the following masking/setting
274: // of bits in Status Register B, by setting Reg B to
275: // a few values and getting its value after INT 1A was called.
276: //
277: // try#1 try#2 try#3
278: // before 1111 1101 0111 1101 0000 0000
279: // after 0110 0010 0110 0010 0000 0010
280: //
281: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
282: // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
283: if (rtc_updating()) {
284: init_rtc();
285: // fall through as if an update were not in progress
286: }
287: outb_cmos(regs->dh, CMOS_RTC_SECONDS);
288: outb_cmos(regs->cl, CMOS_RTC_MINUTES);
289: outb_cmos(regs->ch, CMOS_RTC_HOURS);
290: // Set Daylight Savings time enabled bit to requested value
291: u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE))
292: | RTC_B_24HR | (regs->dl & RTC_B_DSE));
293: outb_cmos(val8, CMOS_STATUS_B);
294: regs->ah = 0;
295: regs->al = val8; // val last written to Reg B
296: set_success(regs);
297: }
298:
299: // Read CMOS Date
300: static void
301: handle_1a04(struct bregs *regs)
302: {
303: regs->ah = 0;
304: if (rtc_updating()) {
305: set_invalid(regs);
306: return;
307: }
308: regs->cl = inb_cmos(CMOS_RTC_YEAR);
309: regs->dh = inb_cmos(CMOS_RTC_MONTH);
310: regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH);
311: if (CONFIG_COREBOOT) {
312: if (regs->cl > 0x80)
313: regs->ch = 0x19;
314: else
315: regs->ch = 0x20;
316: } else {
317: regs->ch = inb_cmos(CMOS_CENTURY);
318: }
319: regs->al = regs->ch;
320: set_success(regs);
321: }
322:
323: // Set CMOS Date
324: static void
325: handle_1a05(struct bregs *regs)
326: {
327: // Using a debugger, I notice the following masking/setting
328: // of bits in Status Register B, by setting Reg B to
329: // a few values and getting its value after INT 1A was called.
330: //
331: // try#1 try#2 try#3 try#4
332: // before 1111 1101 0111 1101 0000 0010 0000 0000
333: // after 0110 1101 0111 1101 0000 0010 0000 0000
334: //
335: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
336: // My assumption: RegB = (RegB & 01111111b)
337: if (rtc_updating()) {
338: init_rtc();
339: set_invalid(regs);
340: return;
341: }
342: outb_cmos(regs->cl, CMOS_RTC_YEAR);
343: outb_cmos(regs->dh, CMOS_RTC_MONTH);
344: outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH);
345: if (!CONFIG_COREBOOT)
346: outb_cmos(regs->ch, CMOS_CENTURY);
347: // clear halt-clock bit
348: u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET;
349: outb_cmos(val8, CMOS_STATUS_B);
350: regs->ah = 0;
351: regs->al = val8; // AL = val last written to Reg B
352: set_success(regs);
353: }
354:
355: // Set Alarm Time in CMOS
356: static void
357: handle_1a06(struct bregs *regs)
358: {
359: // Using a debugger, I notice the following masking/setting
360: // of bits in Status Register B, by setting Reg B to
361: // a few values and getting its value after INT 1A was called.
362: //
363: // try#1 try#2 try#3
364: // before 1101 1111 0101 1111 0000 0000
365: // after 0110 1111 0111 1111 0010 0000
366: //
367: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
368: // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
369: u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
370: regs->ax = 0;
371: if (val8 & RTC_B_AIE) {
372: // Alarm interrupt enabled already
373: set_invalid(regs);
374: return;
375: }
376: if (rtc_updating()) {
377: init_rtc();
378: // fall through as if an update were not in progress
379: }
380: outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
381: outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
382: outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
383: // enable Status Reg B alarm bit, clear halt clock bit
384: outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B);
385: set_success(regs);
386: }
387:
388: // Turn off Alarm
389: static void
390: handle_1a07(struct bregs *regs)
391: {
392: // Using a debugger, I notice the following masking/setting
393: // of bits in Status Register B, by setting Reg B to
394: // a few values and getting its value after INT 1A was called.
395: //
396: // try#1 try#2 try#3 try#4
397: // before 1111 1101 0111 1101 0010 0000 0010 0010
398: // after 0100 0101 0101 0101 0000 0000 0000 0010
399: //
400: // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
401: // My assumption: RegB = (RegB & 01010111b)
402: u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
403: // clear clock-halt bit, disable alarm bit
404: outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B);
405: regs->ah = 0;
406: regs->al = val8; // val last written to Reg B
407: set_success(regs);
408: }
409:
410: // Unsupported
411: static void
412: handle_1aXX(struct bregs *regs)
413: {
414: set_unimplemented(regs);
415: }
416:
417: // INT 1Ah Time-of-day Service Entry Point
418: void VISIBLE16
419: handle_1a(struct bregs *regs)
420: {
421: debug_enter(regs, DEBUG_HDL_1a);
422: switch (regs->ah) {
423: case 0x00: handle_1a00(regs); break;
424: case 0x01: handle_1a01(regs); break;
425: case 0x02: handle_1a02(regs); break;
426: case 0x03: handle_1a03(regs); break;
427: case 0x04: handle_1a04(regs); break;
428: case 0x05: handle_1a05(regs); break;
429: case 0x06: handle_1a06(regs); break;
430: case 0x07: handle_1a07(regs); break;
431: case 0xb1: handle_1ab1(regs); break;
432: default: handle_1aXX(regs); break;
433: }
434: }
435:
436: // INT 08h System Timer ISR Entry Point
437: void VISIBLE16
438: handle_08()
439: {
440: debug_isr(DEBUG_ISR_08);
441:
442: floppy_tick();
443:
444: u32 counter = GET_BDA(timer_counter);
445: counter++;
446: // compare to one days worth of timer ticks at 18.2 hz
447: if (counter >= TICKS_PER_DAY) {
448: // there has been a midnight rollover at this point
449: counter = 0;
450: SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
451: }
452:
453: SET_BDA(timer_counter, counter);
454:
455: usb_check_key();
456:
457: // chain to user timer tick INT #0x1c
458: u32 eax=0, flags;
459: call16_simpint(0x1c, &eax, &flags);
460:
461: eoi_pic1();
462: }
463:
464:
465: /****************************************************************
466: * Periodic timer
467: ****************************************************************/
468:
469: void
470: useRTC()
471: {
472: u16 ebda_seg = get_ebda_seg();
473: int count = GET_EBDA2(ebda_seg, RTCusers);
474: SET_EBDA2(ebda_seg, RTCusers, count+1);
475: if (count)
476: return;
477: // Turn on the Periodic Interrupt timer
478: u8 bRegister = inb_cmos(CMOS_STATUS_B);
479: outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
480: }
481:
482: void
483: releaseRTC()
484: {
485: u16 ebda_seg = get_ebda_seg();
486: int count = GET_EBDA2(ebda_seg, RTCusers);
487: SET_EBDA2(ebda_seg, RTCusers, count-1);
488: if (count != 1)
489: return;
490: // Clear the Periodic Interrupt.
491: u8 bRegister = inb_cmos(CMOS_STATUS_B);
492: outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
493: }
494:
495: static int
496: set_usertimer(u32 usecs, u16 seg, u16 offset)
497: {
498: if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)
499: return -1;
500:
501: // Interval not already set.
502: SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte.
503: SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset));
504: SET_BDA(user_wait_timeout, usecs);
505: useRTC();
506: return 0;
507: }
508:
509: static void
510: clear_usertimer()
511: {
512: if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING))
513: return;
514: // Turn off status byte.
515: SET_BDA(rtc_wait_flag, 0);
516: releaseRTC();
517: }
518:
519: #define RET_ECLOCKINUSE 0x83
520:
521: // Wait for CX:DX microseconds
522: void
523: handle_1586(struct bregs *regs)
524: {
525: // Use the rtc to wait for the specified time.
526: u8 statusflag = 0;
527: u32 count = (regs->cx << 16) | regs->dx;
528: int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag);
529: if (ret) {
530: set_code_invalid(regs, RET_ECLOCKINUSE);
531: return;
532: }
533: while (!statusflag)
534: wait_irq();
535: set_success(regs);
536: }
537:
538: // Set Interval requested.
539: static void
540: handle_158300(struct bregs *regs)
541: {
542: int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx);
543: if (ret)
544: // Interval already set.
545: set_code_invalid(regs, RET_EUNSUPPORTED);
546: else
547: set_success(regs);
548: }
549:
550: // Clear interval requested
551: static void
552: handle_158301(struct bregs *regs)
553: {
554: clear_usertimer();
555: set_success(regs);
556: }
557:
558: static void
559: handle_1583XX(struct bregs *regs)
560: {
561: set_code_unimplemented(regs, RET_EUNSUPPORTED);
562: regs->al--;
563: }
564:
565: void
566: handle_1583(struct bregs *regs)
567: {
568: switch (regs->al) {
569: case 0x00: handle_158300(regs); break;
570: case 0x01: handle_158301(regs); break;
571: default: handle_1583XX(regs); break;
572: }
573: }
574:
575: #define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024)
576:
577: // int70h: IRQ8 - CMOS RTC
578: void VISIBLE16
579: handle_70()
580: {
581: debug_isr(DEBUG_ISR_70);
582:
583: // Check which modes are enabled and have occurred.
584: u8 registerB = inb_cmos(CMOS_STATUS_B);
585: u8 registerC = inb_cmos(CMOS_STATUS_C);
586:
587: if (!(registerB & (RTC_B_PIE|RTC_B_AIE)))
588: goto done;
589: if (registerC & RTC_B_AIE) {
590: // Handle Alarm Interrupt.
591: u32 eax=0, flags;
592: call16_simpint(0x4a, &eax, &flags);
593: }
594: if (!(registerC & RTC_B_PIE))
595: goto done;
596:
597: // Handle Periodic Interrupt.
598:
599: check_preempt();
600:
601: if (!GET_BDA(rtc_wait_flag))
602: goto done;
603:
604: // Wait Interval (Int 15, AH=83) active.
605: u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds.
606: if (time < USEC_PER_RTC) {
607: // Done waiting - write to specified flag byte.
608: struct segoff_s segoff = GET_BDA(user_wait_complete_flag);
609: u16 ptr_seg = segoff.seg;
610: u8 *ptr_far = (u8*)(segoff.offset+0);
611: u8 oldval = GET_FARVAR(ptr_seg, *ptr_far);
612: SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80);
613:
614: clear_usertimer();
615: } else {
616: // Continue waiting.
617: time -= USEC_PER_RTC;
618: SET_BDA(user_wait_timeout, time);
619: }
620:
621: done:
622: eoi_pic2();
623: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.