54e59a5d2d9ac520ebaa8dedbddda239304db8ae
[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         }
107         giTime_TSCAtLastTick = curTSC;
108         
109         giTicks ++;
110         giTimestamp += MS_PER_TICK_WHOLE;
111         giPartMiliseconds += MS_PER_TICK_FRACT;
112         if(giPartMiliseconds > 0x80000000) {
113                 giTimestamp ++;
114                 giPartMiliseconds -= 0x80000000;
115         }
116         
117         Timer_CallTimers();
118
119         // Make sure the RTC Fires again
120         outb(0x70, 0x0C); // Select register C
121         inb(0x71);      // Just throw away contents.
122 }
123
124 void Time_MicroSleep(Uint16 Microsecs)  // max 64 ms
125 {
126         Uint64  cur_tsc = Time_ReadTSC();
127         // tsc_per_us * Microsec
128         Uint64  delta_tsc = (Uint64)Microsecs * giTime_TSCPerTick / US_PER_TICK;
129         Uint64  tgt_tsc = cur_tsc + delta_tsc;
130
131         if( tgt_tsc < cur_tsc )
132                 while(Time_ReadTSC() > cur_tsc)
133                         ;       
134
135         while( Time_ReadTSC() < tgt_tsc )
136                 ;
137 }
138
139 Uint64 Time_ReadTSC(void)
140 {
141         Uint32  a, d;
142         __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
143         return ((Uint64)d << 32) | a;
144 }

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