]> pd.if.org Git - zos/blob - timer.c
add a readme with a public domain note
[zos] / timer.c
1 #include <stdint.h>
2
3 #include "interrupt.h"
4 #include "kernel.h"
5 #include "timer.h"
6
7 #include "ioport.h"
8 #include "cpu.h"
9
10 #include <time.h>
11
12 static struct interrupt_handler timer;
13
14 /* This will keep track of how many ticks that the system
15 *  has been running for */
16 volatile uint64_t timer_ticks = 0;
17 static int timer_hz = 18;
18
19 static uint64_t timer_ns; /* nanoseconds per time tick */
20
21 struct timespec system_time; /* global system time */
22
23 #define ONE_BILLION 1000000000ULL
24
25 /* See http://wiki.osdev.org/Programmable_Interval_Timer
26  * for a possibly better algorithm
27  */
28 static void setfreq(int hz) {
29         int enable;
30         unsigned int divisor;
31
32         if (hz < 18) hz = 18;
33         divisor = 1193182/hz;
34
35         timer_hz = 1193182 / divisor;
36
37 #if 0
38         printk("timer hz %llu\n", (uint64_t)hz);
39         printk("timer divisor %u\n", divisor);
40         printk("timer hz actual %llu\n", (uint64_t)timer_hz);
41 #endif
42
43         enable = interrupts_enabled();
44         if (enable) disable_interrupts();
45         outport8(0x43, 0x34);
46         outport8(0x40, (uint8_t)(divisor & 0xFF));   /* Set low byte of divisor */
47         outport8(0x40, (uint8_t)(divisor >> 8 & 0xFF));     /* Set high byte of divisor */
48
49         timer_ns = (uint64_t)1000000000ULL / timer_hz;
50         /* now, let's disable the pit and use the RTC */
51         if (enable) enable_interrupts();
52 }
53
54 static void timer_handler(struct interrupt_context *c, void *unused) {
55         timer_ticks++;
56         system_time.tv_nsec += timer_ns;
57         while (system_time.tv_nsec >= ONE_BILLION) {
58                 system_time.tv_sec++;
59                 system_time.tv_nsec -= ONE_BILLION;
60         }
61 }
62
63 void init_timer(int hz) {
64         int enable;
65         timer.handler = timer_handler;
66         timer.context = 0;
67         system_time.tv_sec = 0;
68         system_time.tv_nsec = 0;
69
70         enable = interrupts_enabled();
71         if (enable) disable_interrupts();
72         interrupt_add_handler(IRQ0, &timer);
73         setfreq(hz);
74         if (enable) enable_interrupts();
75 }