b367c50ae2facdd8851ca09e6fb080fa642800ff
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / time.c
1 /*
2  * Acess2 Kernel
3  * Timekeeping
4  * arch/x86/time.c
5  */
6 #include <acess.h>
7 #include <timers.h>
8
9 // === MACROS ===
10 #define TIMER_QUANTUM   100
11 // 2^(15-rate), 14: 2Hz, 5: 1024Hz, 2: 8192Hz
12 // (Max: 14, Min: 2) - 14 = 2Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
13 //#define TIMER_RATE    10      // 32 Hz
14 //#define TIMER_RATE    12      // 8 Hz
15 #define TIMER_RATE      14      // 2 Hz - Lowest
16 #define TIMER_FREQ      (0x8000>>TIMER_RATE)    //Hz
17 #define MS_PER_TICK_WHOLE       (1000/(TIMER_FREQ))
18 #define MS_PER_TICK_FRACT       ((0x80000000*(1000%TIMER_FREQ))/TIMER_FREQ)
19 #define US_PER_TICK     (1000*1000/(TIMER_FREQ))
20
21 // === IMPORTS ===
22 extern volatile Sint64  giTimestamp;
23 extern volatile Uint64  giTicks;
24 extern volatile Uint64  giPartMiliseconds;
25 extern void     Timer_CallTimers(void);
26
27 // === GLOBALS ===
28 volatile Uint64 giTime_TSCAtLastTick = 0;
29 volatile Uint64 giTime_TSCPerTick = 0;
30
31 // === PROTOTYPES ===
32 //Sint64        now(void);
33  int    Time_Setup(void);
34 void    Time_Interrupt(int IRQ, void *Ptr);
35 Uint64  Time_ReadTSC(void);
36
37 // === CODE ===
38 /**
39  * \fn Sint64 now()
40  * \brief Return the current timestamp
41  */
42 Sint64 now(void)
43 {
44         Uint64  tsc = Time_ReadTSC();
45         tsc -= giTime_TSCAtLastTick;
46         tsc *= MS_PER_TICK_WHOLE;
47         if( giTime_TSCPerTick ) {
48                 tsc /= giTime_TSCPerTick;
49         }
50         else
51                 tsc = 0;
52         return giTimestamp + tsc;
53 }
54
55 /**
56  * \fn int Time_Setup(void)
57  * \brief Sets the system time from the Realtime-Clock
58  */
59 int Time_Setup(void)
60 {
61         Uint8   val;
62         
63         Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
64                 TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
65         
66         outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
67         __asm__ __volatile__ ("cli");   // Disable normal interrupts
68         
69         // Set IRQ8 firing rate
70         outb(0x70, 0x0A);       // Set the index to register A
71         val = inb(0x71); // Get the current value of register A
72         val &= 0xF0;
73         val |= TIMER_RATE+1;
74         outb(0x70, 0x0A); // Reset index to A
75         outb(0x71, val);        // Update the timer rate
76                 
77         // Enable IRQ8
78         outb(0x70, 0x0B);       // Set the index to register B
79         val = inb(0x71);        // Read the current value of register B
80         outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
81         outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
82         
83         __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
84         outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
85         
86         // Install IRQ Handler
87         IRQ_AddHandler(8, Time_Interrupt, NULL);
88         
89         // Make sure the RTC actually fires
90         outb(0x70, 0x0C); // Select register C
91         inb(0x71);      // Just throw away contents.
92         
93         return 0;
94 }
95
96 /**
97  * \brief Called on the timekeeping IRQ
98  */
99 void Time_Interrupt(int IRQ, void *Ptr)
100 {
101         Uint64  curTSC = Time_ReadTSC();
102         
103         if( giTime_TSCAtLastTick )
104         {
105                 giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
106                 //Debug("TSC Frequency is %llu-%llu = %llu Hz", curTSC, giTime_TSCAtLastTick, giTime_TSCPerTick*2);
107         }
108         giTime_TSCAtLastTick = curTSC;
109         
110         giTicks ++;
111         giTimestamp += MS_PER_TICK_WHOLE;
112         giPartMiliseconds += MS_PER_TICK_FRACT;
113         if(giPartMiliseconds > 0x80000000) {
114                 giTimestamp ++;
115                 giPartMiliseconds -= 0x80000000;
116         }
117         
118         Timer_CallTimers();
119
120         // Make sure the RTC Fires again
121         outb(0x70, 0x0C); // Select register C
122         inb(0x71);      // Just throw away contents.
123 }
124
125 void Time_MicroSleep(Uint16 Microsecs)  // max 64 ms
126 {
127         Uint64  cur_tsc = Time_ReadTSC();
128         // tsc_per_us * Microsec
129         Uint64  delta_tsc = (Uint64)Microsecs * giTime_TSCPerTick / US_PER_TICK;
130         Uint64  tgt_tsc = cur_tsc + delta_tsc;
131
132         if( tgt_tsc < cur_tsc )
133                 while(Time_ReadTSC() > cur_tsc)
134                         ;       
135
136         while( Time_ReadTSC() < tgt_tsc )
137                 ;
138 }
139
140 Uint64 Time_ReadTSC(void)
141 {
142         Uint32  a, d;
143         __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
144         return ((Uint64)d << 32) | a;
145 }

UCC git Repository :: git.ucc.asn.au