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