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  }