aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Ishiguro <arthuri@google.com>2017-10-02 16:16:15 -0700
committerArthur Ishiguro <arthuri@google.com>2017-10-03 10:09:41 -0700
commitb0bd0c2b3c1b0e7fb9c6652753a24de28809ff28 (patch)
treed49aabbd31e0b518458b0eeb58fd6612a35f40f7
parent38f8f210741a7c22fb5117fbaeb17e781be64bd8 (diff)
downloadchre-b0bd0c2b3c1b0e7fb9c6652753a24de28809ff28.tar.gz
Fix overflow in time sync offset calculation
Ticks to nanosecond conversion math in time sync offset calculation overflowed after 11 days. Bug: 67059655 Test: Compile and run on device, and verify that offset matches expected value based on the qTimer counter and elapsedRealtimenano() values. Change-Id: I659cde63bc4db75b6df57e6f62a4c32e0d78195f
-rw-r--r--host/msm/daemon/chre_daemon.cc57
1 files changed, 38 insertions, 19 deletions
diff --git a/host/msm/daemon/chre_daemon.cc b/host/msm/daemon/chre_daemon.cc
index b6563b5e..3c13f045 100644
--- a/host/msm/daemon/chre_daemon.cc
+++ b/host/msm/daemon/chre_daemon.cc
@@ -179,7 +179,7 @@ static void parseAndEmitLogMessages(unsigned char *message) {
}
}
-static int64_t getTimeOffset() {
+static int64_t getTimeOffset(bool *success) {
int64_t timeOffset = 0;
#if defined(__aarch64__)
@@ -191,18 +191,34 @@ static int64_t getTimeOffset() {
// Use uint64_t to store since the MRS instruction uses 64 bit (X) registers
// (http://infocenter.arm.com/help/topic/
// com.arm.doc.den0024a/ch06s05s02.html)
- uint64_t qTimerCount = 0, qTimerFreqKHz = 0;
+ uint64_t qTimerCount = 0, qTimerFreq = 0;
uint64_t hostTimeNano = elapsedRealtimeNano();
asm volatile("mrs %0, cntpct_el0" : "=r"(qTimerCount));
- asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreqKHz));
- qTimerFreqKHz /= 1000;
+ asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreq));
+
+ constexpr uint64_t kOneSecondInNanoseconds = 1000000000;
+ if (qTimerFreq != 0) {
+ // Get the seconds part first, then convert the remainder to prevent
+ // overflow
+ uint64_t qTimerNanos = (qTimerCount / qTimerFreq);
+ if (qTimerNanos > UINT64_MAX / kOneSecondInNanoseconds) {
+ LOGE("CNTPCT_EL0 conversion to nanoseconds overflowed during time sync."
+ " Aborting time sync.");
+ *success = false;
+ } else {
+ qTimerNanos *= kOneSecondInNanoseconds;
- if (qTimerFreqKHz != 0) {
- uint64_t qTimerNanos = (qTimerCount < UINT64_MAX / 1000000) ?
- (qTimerCount * 1000000) : UINT64_MAX;
- qTimerNanos /= qTimerFreqKHz;
+ // Round the remainder portion to the nearest nanosecond
+ uint64_t remainder = (qTimerCount % qTimerFreq);
+ qTimerNanos +=
+ (remainder * kOneSecondInNanoseconds + qTimerFreq / 2) / qTimerFreq;
- timeOffset = hostTimeNano - qTimerNanos;
+ timeOffset = hostTimeNano - qTimerNanos;
+ *success = true;
+ }
+ } else {
+ LOGE("CNTFRQ_EL0 had 0 value. Aborting time sync.");
+ *success = false;
}
#else
#error "Unsupported CPU architecture type"
@@ -212,16 +228,19 @@ static int64_t getTimeOffset() {
}
static void sendTimeSyncMessage() {
- int64_t timeOffset = getTimeOffset();
-
- flatbuffers::FlatBufferBuilder builder(64);
- HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
- int success = chre_slpi_deliver_message_from_host(
- static_cast<const unsigned char *>(builder.GetBufferPointer()),
- static_cast<int>(builder.GetSize()));
-
- if (success != 0) {
- LOGE("Failed to deliver timestamp message from host to CHRE: %d", success);
+ bool timeSyncSuccess = true;
+ int64_t timeOffset = getTimeOffset(&timeSyncSuccess);
+
+ if (timeSyncSuccess) {
+ flatbuffers::FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
+ int success = chre_slpi_deliver_message_from_host(
+ static_cast<const unsigned char *>(builder.GetBufferPointer()),
+ static_cast<int>(builder.GetSize()));
+
+ if (success != 0) {
+ LOGE("Failed to deliver timestamp message from host to CHRE: %d", success);
+ }
}
}