1 #include "devices/timer.h"
4 #include "threads/interrupt.h"
5 #include "threads/io.h"
8 #error 8254 timer requires TIMER_FREQ >= 19
11 #error TIMER_FREQ <= 1000 recommended
14 /* Number of timer ticks that a process gets before being
18 /* Number of timer ticks since OS booted. */
19 static volatile int64_t ticks;
21 static intr_handler_func timer_interrupt;
23 /* Sets up the 8254 Programmable Interrupt Timer (PIT) to
24 interrupt PIT_FREQ times per second, and registers the
25 corresponding interrupt. */
29 /* 8254 input frequency divided by TIMER_FREQ, rounded to
31 uint16_t count = (1193180 + TIMER_FREQ / 2) / TIMER_FREQ;
33 outb (0x43, 0x34); /* CW: counter 0, LSB then MSB, mode 2, binary. */
34 outb (0x40, count & 0xff);
35 outb (0x40, count >> 8);
37 intr_register (0x20, 0, INTR_OFF, timer_interrupt, "8254 Timer");
40 /* Returns the number of timer ticks since the OS booted. */
44 enum intr_level old_level = intr_disable ();
46 intr_set_level (old_level);
50 /* Returns the number of timer ticks elapsed since THEN, which
51 should be a value once returned by timer_ticks(). */
53 timer_elapsed (int64_t then)
55 return timer_ticks () - then;
58 /* Suspends execution for approximately MS milliseconds. */
60 timer_msleep (int64_t ms)
62 int64_t ticks = (int64_t) DIV_ROUND_UP (ms * TIMER_FREQ, 1000);
63 int64_t start = timer_ticks ();
65 while (timer_elapsed (start) < ticks)
69 /* Suspends execution for approximately US microseconds.
70 Note: this is ridiculously inaccurate. */
72 timer_usleep (int64_t us)
74 timer_msleep (us / 1000 + 1);
77 /* Suspends execution for approximately NS nanoseconds.
78 Note: this is ridiculously inaccurate. */
80 timer_nsleep (int64_t ns)
82 timer_msleep (ns / 1000000 + 1);
85 /* Timer interrupt handler. */
87 timer_interrupt (struct intr_frame *args UNUSED)
90 if (ticks % TIME_SLICE == 0)
91 intr_yield_on_return ();