-
Notifications
You must be signed in to change notification settings - Fork 114
/
timer.go
91 lines (78 loc) · 1.68 KB
/
timer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package kernel
import (
"github.com/icexin/eggos/drivers/pic"
"github.com/icexin/eggos/kernel/sys"
"github.com/icexin/eggos/kernel/trap"
"gvisor.dev/gvisor/pkg/abi/linux"
)
const (
_PIT_HZ = 1193180
_HZ = 100
_IRQ_TIMER = pic.IRQ_BASE + pic.LINE_TIMER
)
const (
ns = 1
ms = 1000000 * ns
second = 1000 * ms
)
var (
// the counter of sched clock
counter int64 = 1
// the unix time of cmos read time
baseUnixTime int64
// the counter of cmos read time
clockBaseCounter int64
sleeplock uintptr
)
// pitCounter return the current counter of 8259a
//go:nosplit
func pitCounter() int32 {
const div = (_PIT_HZ / _HZ)
// Send the latch command to channel 0
sys.Outb(0x43, 0)
lo := sys.Inb(0x40)
hi := sys.Inb(0x40)
ax := (int32(hi)<<8 | int32(lo))
return div - ax
}
//go:nosplit
func nanosecond() int64 {
var t int64 = counter * (second / _HZ)
elapse := int64(pitCounter()) * (second / _PIT_HZ)
t += elapse
return t
}
//go:nosplit
func clocktime() linux.Timespec {
var ts linux.Timespec
n := counter - clockBaseCounter
ts.Sec = n/_HZ + baseUnixTime
ts.Nsec = n % _HZ * (second / _HZ)
ts.Nsec += int64(pitCounter()) * (second / _PIT_HZ)
return ts
}
//go:nosplit
func nanosleep(tc *linux.Timespec) {
deadline := nanosecond() + int64(tc.Nsec+tc.Sec*second)
now := nanosecond()
for now < deadline {
sleepon(&sleeplock)
now = nanosecond()
}
}
//go:nosplit
func timerIntr() {
counter++
wakeup(&sleeplock, -1)
pic.EOI(_IRQ_TIMER)
Yield()
}
//go:nosplit
func timerInit() {
div := int(_PIT_HZ / _HZ)
sys.Outb(0x43, 0x36)
sys.Outb(0x40, byte(div&0xff))
sys.Outb(0x40, byte((div>>8)&0xff))
trap.Register(_IRQ_TIMER, timerIntr)
pic.EnableIRQ(pic.LINE_TIMER)
}