CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Toggle main menu visibility
Loading...
Searching...
No Matches
sdk
include
platform
generic-riscv
platform-timer.hh
1
// Copyright Microsoft and CHERIoT Contributors.
2
// SPDX-License-Identifier: MIT
3
4
#pragma once
5
6
#include <
cheri.hh
>
7
#include <stdint.h>
8
#include <
utils.hh
>
9
10
/**
11
* Driver for using the (old) RISC-V Core-Local Interrupt (CLINT)
12
* controller (as opposed to the newer CLIC) to provide timer signals.
13
* Note that CLIC can run in CLINT-compatible mode, so we don't need to
14
* support CLIC for a while, it has a lot of features that are overkill for
15
* most embedded devices.
16
*/
17
class
StandardClint
:
private
utils::NoCopyNoMove
18
{
19
public
:
20
/**
21
* Initialise the interface.
22
*/
23
static
void
init
()
24
{
25
// This needs to be csr_read(mhartid) if we support multicore
26
// systems, but we don't plan to any time soon.
27
constexpr
uint32_t HartId = 0;
28
29
auto
setField = [&](
auto
&field,
size_t
offset,
size_t
size) {
30
CHERI::Capability
capability{
MMIO_CAPABILITY
(uint32_t, clint)};
31
capability.
address
() += offset;
32
capability.
bounds
() = size;
33
field = capability;
34
};
35
setField(pmtimer, StandardClint::ClintMtime, 2 *
sizeof
(uint32_t));
36
setField(pmtimercmp,
37
StandardClint::ClintMtimecmp + HartId * 8,
38
2 *
sizeof
(uint32_t));
39
}
40
41
static
uint64_t time()
42
{
43
// The timer is little endian, so the high 32 bits are after the low 32
44
// bits. We can't do atomic 64-bit loads and so we have to read these
45
// separately.
46
volatile
uint32_t *timerHigh = pmtimer + 1;
47
uint32_t timeLow, timeHigh;
48
49
// Read the current time. Loop until the high 32 bits are stable.
50
do
51
{
52
timeHigh = *timerHigh;
53
timeLow = *pmtimer;
54
}
while
(timeHigh != *timerHigh);
55
return
(
static_cast<
uint64_t
>
(timeHigh) << 32) | timeLow;
56
}
57
58
/**
59
* Set the timer comparison for next interrupt to given value.
60
* Note that CLINT does not need any action to acknowledge the
61
* interrupt. Writing to it is enough to clear the interrupt.
62
* Interrupts must be disabled when calling this function.
63
*/
64
static
void
setnext
(uint64_t nextTime)
65
{
66
/// the high 32 bits of the 64-bit MTIME register
67
volatile
uint32_t *pmtimercmphigh = pmtimercmp + 1;
68
69
// Attempt to prevent spurious interrupts by writing -1 to mtimeh. The
70
// RISC-V spec actually says to do this by writing to the low 32-bits,
71
// but writing -1 to the high bits also works if we assume that mtimeh
72
// will never reach its maximum value, which it had better not because
73
// the >= comparison makes it impossible to handle wrap around of the
74
// mtime counter anyway. This may be unnecessary given that that we
75
// should have interrupts disabled anyway...
76
*pmtimercmphigh = -1;
77
// Write the new MTIMECMP value, at which the next interrupt fires.
78
*pmtimercmp = nextTime;
79
*pmtimercmphigh = nextTime >> 32;
80
}
81
82
/**
83
* Returns the time at which the next timer is scheduled.
84
*/
85
static
uint64_t
next
()
86
{
87
volatile
uint32_t *pmtimercmphigh = pmtimercmp + 1;
88
uint64_t nextTimer = *pmtimercmphigh;
89
nextTimer <<= 32;
90
nextTimer |= *pmtimercmp;
91
return
nextTimer;
92
}
93
94
/**
95
* Set the timer comparator to a value that should never trigger an
96
* interrupt.
97
*
98
* Note: we rely on the fact that mtimeh should never reach maximum value in
99
* plausible time-frame.
100
*/
101
static
void
clear
()
102
{
103
volatile
uint32_t *pmtimercmphigh = pmtimercmp + 1;
104
*pmtimercmphigh = -1;
// Prevent spurious interrupts.
105
}
106
107
private
:
108
#ifdef MICROSOFT_CHERIOT_SAFE
109
/**
110
* The Microsoft SAFE platform doesn't implement a complete CLINT, only the
111
* timer part (which is all that we use). Its offsets within the CLINT
112
* region are different.
113
*/
114
static
constexpr
size_t
ClintMtime = 0x10;
115
static
constexpr
size_t
ClintMtimecmp = 0x18;
116
#else
117
/**
118
* The standard RISC-V CLINT is a large memory-mapped device and places the
119
* timers a long way in.
120
*/
121
static
constexpr
size_t
ClintMtimecmp = 0x4000U;
122
static
constexpr
size_t
ClintMtime = 0xbff8U;
123
#endif
124
125
static
inline
volatile
uint32_t *pmtimercmp;
126
static
inline
volatile
uint32_t *pmtimer;
127
};
128
129
using
TimerCore =
StandardClint
;
cheri.hh
C++ helpers for operating on capabilities.
CHERI::Capability
Helper class for accessing capability properties on pointers.
Definition
cheri.hh:482
CHERI::Capability::address
AddressProxy address()
Access the address of the capability.
Definition
cheri.hh:851
CHERI::Capability::bounds
BoundsProxy bounds()
Access (read, set) the capability's bounds.
Definition
cheri.hh:867
StandardClint
Driver for using the (old) RISC-V Core-Local Interrupt (CLINT) controller (as opposed to the newer CL...
Definition
platform-timer.hh:18
StandardClint::next
static uint64_t next()
Returns the time at which the next timer is scheduled.
Definition
platform-timer.hh:85
StandardClint::init
static void init()
Initialise the interface.
Definition
platform-timer.hh:23
StandardClint::clear
static void clear()
Set the timer comparator to a value that should never trigger an interrupt.
Definition
platform-timer.hh:101
StandardClint::setnext
static void setnext(uint64_t nextTime)
Set the timer comparison for next interrupt to given value.
Definition
platform-timer.hh:64
utils::NoCopyNoMove
Utility class to delete copy and move contructors.
Definition
utils.hh:53
MMIO_CAPABILITY
#define MMIO_CAPABILITY(type, name)
Provide a capability of the type volatile type * referring to the MMIO region exported in the linker ...
Definition
compartment-macros.h:90
utils.hh
Miscellaneous utility functions and classes.
Generated by
1.18.0