Kernel/armv7 - Added IRQ stack, changed IRQs to be disabled until after handling
[tpg/acess2.git] / Kernel / arch / x86 / time.c
1 /*
2  * Acess2 Kernel
3  * Timekeeping
4  * arch/x86/time.c
5  */
6 #include <acess.h>
7
8 // === MACROS ===
9 #define TIMER_QUANTUM   100
10 // 2^(15-rate), 15: 1HZ, 5: 1024Hz, 2: 8192Hz
11 // (Max: 15, Min: 2) - 15 = 1Hz, 13 = 4Hz, 12 = 8Hz, 11 = 16Hz 10 = 32Hz, 2 = 8192Hz
12 //#define TIMER_RATE    10      // 32 Hz
13 //#define TIMER_RATE    12      // 8 Hz
14 #define TIMER_RATE      14      // 2Hz
15 //#define TIMER_RATE    15      // 1HZ
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
20 // === IMPORTS ===
21 extern volatile Sint64  giTimestamp;
22 extern volatile Uint64  giTicks;
23 extern volatile Uint64  giPartMiliseconds;
24 extern void     Timer_CallTimers(void);
25
26 // === GLOBALS ===
27 volatile Uint64 giTime_TSCAtLastTick = 0;
28 volatile Uint64 giTime_TSCPerTick = 0;
29
30 // === PROTOTYPES ===
31 //Sint64        now(void);
32  int    Time_Setup(void);
33 void    Time_Interrupt(int IRQ, void *Ptr);
34 Uint64  Time_ReadTSC(void);
35
36 // === CODE ===
37 /**
38  * \fn Sint64 now()
39  * \brief Return the current timestamp
40  */
41 Sint64 now(void)
42 {
43         Uint64  tsc = Time_ReadTSC();
44         tsc -= giTime_TSCAtLastTick;
45         tsc *= MS_PER_TICK_WHOLE;
46         if( giTime_TSCPerTick ) {
47                 tsc /= giTime_TSCPerTick;
48         }
49         else
50                 tsc = 0;
51         return giTimestamp + tsc;
52 }
53
54 /**
55  * \fn int Time_Setup(void)
56  * \brief Sets the system time from the Realtime-Clock
57  */
58 int Time_Setup(void)
59 {
60         Uint8   val;
61         
62         Log_Log("Timer", "RTC Timer firing at %iHz (%i divisor), %i.0x%08x",
63                 TIMER_FREQ, TIMER_RATE, MS_PER_TICK_WHOLE, MS_PER_TICK_FRACT);
64         
65         outb(0x70, inb(0x70)&0x7F);     // Disable NMIs
66         __asm__ __volatile__ ("cli");   // Disable normal interrupts
67         
68         // Set IRQ8 firing rate
69         outb(0x70, 0x0A);       // Set the index to register A
70         val = inb(0x71); // Get the current value of register A
71         outb(0x70, 0x0A); // Reset index to A
72         val &= 0xF0;
73         val |= TIMER_RATE;
74         outb(0x71, val);        // Update the timer rate
75                 
76         // Enable IRQ8
77         outb(0x70, 0x0B);       // Set the index to register B
78         val = inb(0x71);        // Read the current value of register B
79         outb(0x70, 0x0B);       // Set the index again (a read will reset the index to register D)
80         outb(0x71, val | 0x40); // Write the previous value or'd with 0x40. This turns on bit 6 of register D
81         
82         __asm__ __volatile__ ("sti");   // Re-enable normal interrupts
83         outb(0x70, inb(0x70)|0x80);     // Re-enable NMIs
84         
85         // Install IRQ Handler
86         IRQ_AddHandler(8, Time_Interrupt, NULL);
87         
88         // Make sure the RTC actually fires
89         outb(0x70, 0x0C); // Select register C
90         inb(0x71);      // Just throw away contents.
91         
92         return 0;
93 }
94
95 /**
96  * \brief Called on the timekeeping IRQ
97  * \param irq   IRQ number (unused)
98  */
99 void Time_Interrupt(int IRQ, void *Ptr)
100 {
101         //Log("RTC Tick");
102         Uint64  curTSC = Time_ReadTSC();
103         
104         if( giTime_TSCAtLastTick )
105         {
106                 giTime_TSCPerTick = curTSC - giTime_TSCAtLastTick;
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 #if 0
126 /**
127  * \fn void Time_TimerThread(void)
128  */
129 void Time_TimerThread(void)
130 {
131         Sint64  next;
132         Threads_SetName("TIMER");
133         
134         next = giTimestamp + TIMER_QUANTUM;
135         for(;;)
136         {
137                 while(giTimestamp < next)       Threads_Yield();
138                 next = giTimestamp + TIMER_QUANTUM;     
139                 Timer_CallTimers();
140         }
141 }
142 #endif
143
144 Uint64 Time_ReadTSC(void)
145 {
146         Uint32  a, d;
147         __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
148         return ((Uint64)d << 32) | a;
149 }

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