Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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