From patchwork Fri Nov 16 12:43:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sumit Garg X-Patchwork-Id: 151336 Delivered-To: patches@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp379692ljp; Fri, 16 Nov 2018 04:43:30 -0800 (PST) X-Received: by 2002:a62:2bd4:: with SMTP id r203-v6mr10939686pfr.105.1542372210089; Fri, 16 Nov 2018 04:43:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1542372210; cv=none; d=google.com; s=arc-20160816; b=d8NV9sWdp0aPcKG9Zpk1YQDqH511YYMORheEccvWv/tRKLarLo9RlBef/SS4g+H6AZ xDbPU9Lxx1gLRINLIf7AfGPGzhSRViYoQtqlghhkM+ToQHBaunhtj/64fzGW0uZQowgA Tqn3IClLxotwT9+vH8z8adUBcOEpKm5Gmz4sUWM/WcsZVwQCTl6aC9gl61vh2uhNlBlm RJn1RGL4aexf/OgersGy8xnCP04RKO8hqGtup2lfv89DcobCiaAw5CKLEHU36MsPfk1O p7H0ieXrPdpidbSAFa3D8ToKKnS53zk+IGd0tjhcUSCZD5RJKklu1eqgtdYUK6P/ltQK 2CtA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=VfZo6ySimzu6HHeCWFqyZAVp5wOp4/pgfWu8ICjeamE=; b=A2kWdX1NOScbaTMB8DWfmvBMaNDjKP+TeWQYmCiF0Zp0zyU+wPaCu1XFoKAkYXAzt/ XqxHNQ0+bm4CkO4e4y8+72KBZs2FCC0WwTRRsPh2Iu9KxoTy1X9sYX+6a8pXlQc3Ju8i 3aPoa3SvQSL6QBg22ZWi4Y2iMRHqqkY26TveRxZObG2zfa04r1o1pTY2XQsjfv5Ki1tA LbfZOQto3vTV40PIZg4pyq3VrVVw5AVBywAsaPy4GKevk+oCg+KHwqKN9CvdhGOX4FnR CWxuAtZ4by4hP0NSusM7O+COLZWRonPCRal54GRmCVo/zkxakGXXiWB6feB60A7+gG4L M/BQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YmMz9U1z; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id f1-v6sor38263387pfn.68.2018.11.16.04.43.29 for (Google Transport Security); Fri, 16 Nov 2018 04:43:30 -0800 (PST) Received-SPF: pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YmMz9U1z; spf=pass (google.com: domain of sumit.garg@linaro.org designates 209.85.220.65 as permitted sender) smtp.mailfrom=sumit.garg@linaro.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VfZo6ySimzu6HHeCWFqyZAVp5wOp4/pgfWu8ICjeamE=; b=YmMz9U1zpdYOpa0aRgcN7RqjWGLcezBUvH2gljjczx0h45Rh+bcbnXplAAwkq55POg zVeg2uW6Gbz+bxBR9aM8oDDuwOsRyIvO7CnDqAxlSeWehcv6eVI9bxCJMS2x0t3w5QpT BVH4aIsaNwJ6VaaIi6oDD2srgUlBxZJtNGt/w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VfZo6ySimzu6HHeCWFqyZAVp5wOp4/pgfWu8ICjeamE=; b=jngwJYlDcgQsihzLn+OgkIIKiD1dDP+ilv2YHG4VP0zCnzavXYAlyj10YAlJ32HPgs 5bK3w/sxUeSA60Fl3xqq4LLfNq+FMRd66fMFjIp9mQGnkOxHoWFW2ETblDU/t87TTgRY E69JvQx5Nn0yztGBrhoENEGPhvOckCVIsh/pq4A9TwIlKVdMFS7hfKqnIooAe5rAR3zf nd3z7NKIrBuLirjuZ6OhNx55+UgrwdeYfUR7rFXhEq9cdvZHuajwDE14UBG55kd1fhQK Xb3ARZWQMfQoEHUITB5V/XGhR3Q8HwKBEhpQxX4mvZBMWng1NUFtkcK7vnteHrc70+jE p4kQ== X-Gm-Message-State: AGRZ1gIZ7iBKTj6Gb1Y1foxS0ZATcD8bl4ynw4MviKhLphVXtUsU/SKA qd00brQqtn9Pi2pNYuKUOz1dzxSD X-Google-Smtp-Source: AJdET5cqXQZHn2WFfbXxnX2DTYr2EzHyBOjNRPT55uFVQNUU+nrrc4y2ttO5kNNZt/mXyi76tN7+NA== X-Received: by 2002:a62:5c6:: with SMTP id 189-v6mr11203260pff.193.1542372209436; Fri, 16 Nov 2018 04:43:29 -0800 (PST) Return-Path: Received: from localhost.localdomain ([117.252.66.84]) by smtp.gmail.com with ESMTPSA id i193sm39735672pgc.22.2018.11.16.04.43.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 16 Nov 2018 04:43:28 -0800 (PST) From: Sumit Garg To: daniel.thompson@linaro.org Cc: patches@linaro.org, Sumit Garg Subject: [PATCH v2 2/2] synquacer: Add RNG pseudo TA Date: Fri, 16 Nov 2018 18:13:02 +0530 Message-Id: <1542372182-26682-2-git-send-email-sumit.garg@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1542372182-26682-1-git-send-email-sumit.garg@linaro.org> References: <1542372182-26682-1-git-send-email-sumit.garg@linaro.org> This platform provides 7 on-chip thermal sensors accessible from secure world only. So, using randomness from these sensors we have created a True RNG as a pseudo TA. Signed-off-by: Sumit Garg --- core/arch/arm/include/arm64.h | 4 + core/arch/arm/plat-synquacer/main.c | 38 +++- core/arch/arm/plat-synquacer/platform_config.h | 3 + core/arch/arm/plat-synquacer/rng_pta.c | 270 +++++++++++++++++++++++++ core/arch/arm/plat-synquacer/rng_pta.h | 37 ++++ core/arch/arm/plat-synquacer/rng_pta_client.h | 22 ++ core/arch/arm/plat-synquacer/sub.mk | 2 + core/arch/arm/plat-synquacer/timer_fiq.c | 43 ++++ 8 files changed, 414 insertions(+), 5 deletions(-) create mode 100644 core/arch/arm/plat-synquacer/rng_pta.c create mode 100644 core/arch/arm/plat-synquacer/rng_pta.h create mode 100644 core/arch/arm/plat-synquacer/rng_pta_client.h create mode 100644 core/arch/arm/plat-synquacer/timer_fiq.c -- 2.7.4 diff --git a/core/arch/arm/include/arm64.h b/core/arch/arm/include/arm64.h index 2c1fd8c..0cf14c0 100644 --- a/core/arch/arm/include/arm64.h +++ b/core/arch/arm/include/arm64.h @@ -305,6 +305,10 @@ DEFINE_REG_READ_FUNC_(cntfrq, uint32_t, cntfrq_el0) DEFINE_REG_READ_FUNC_(cntpct, uint64_t, cntpct_el0) DEFINE_REG_READ_FUNC_(cntkctl, uint32_t, cntkctl_el1) DEFINE_REG_WRITE_FUNC_(cntkctl, uint32_t, cntkctl_el1) +DEFINE_REG_READ_FUNC_(cntps_ctl, uint32_t, cntps_ctl_el1) +DEFINE_REG_WRITE_FUNC_(cntps_ctl, uint32_t, cntps_ctl_el1) +DEFINE_REG_READ_FUNC_(cntps_cval, uint32_t, cntps_cval_el1) +DEFINE_REG_WRITE_FUNC_(cntps_cval, uint32_t, cntps_cval_el1) DEFINE_REG_READ_FUNC_(pmccntr, uint64_t, pmccntr_el0) diff --git a/core/arch/arm/plat-synquacer/main.c b/core/arch/arm/plat-synquacer/main.c index c3aac4c..7c3a6bc 100644 --- a/core/arch/arm/plat-synquacer/main.c +++ b/core/arch/arm/plat-synquacer/main.c @@ -18,6 +18,7 @@ #include #include #include +#include static void main_fiq(void); @@ -38,6 +39,7 @@ static struct pl011_data console_data; register_phys_mem(MEM_AREA_IO_NSEC, CONSOLE_UART_BASE, CORE_MMU_DEVICE_SIZE); register_phys_mem(MEM_AREA_IO_SEC, GIC_BASE, CORE_MMU_DEVICE_SIZE); +register_phys_mem(MEM_AREA_IO_SEC, THERMAL_SENSOR_BASE, CORE_MMU_DEVICE_SIZE); const struct thread_handlers *generic_boot_get_handlers(void) { @@ -46,7 +48,7 @@ const struct thread_handlers *generic_boot_get_handlers(void) static void main_fiq(void) { - panic(); + gic_it_handle(&gic_data); } void console_init(void) @@ -66,12 +68,38 @@ void main_init_gic(void) if (!gicd_base) panic(); - /* Initialize GIC */ - gic_init(&gic_data, 0, gicd_base); + /* On ARMv8-A, GIC configuration is initialized in TF-A */ + gic_init_base_addr(&gic_data, 0, gicd_base); + itr_init(&gic_data.chip); } -void main_secondary_init_gic(void) +static enum itr_return timer_itr_cb(struct itr_handler *h __unused) +{ + /* Reset timer for next FIQ */ + generic_timer_handler(); + + /* Collect entropy on each timer FIQ */ + rng_collect_entropy(); + + return ITRR_HANDLED; +} + +static struct itr_handler timer_itr = { + .it = IT_SEC_TIMER, + .flags = ITRF_TRIGGER_LEVEL, + .handler = timer_itr_cb, +}; + +static TEE_Result init_timer_itr(void) { - gic_cpu_init(&gic_data); + itr_add(&timer_itr); + itr_enable(IT_SEC_TIMER); + + /* Enable timer FIQ to fetch entropy required during boot */ + generic_timer_start(); + timer_fiq_running = true; + + return TEE_SUCCESS; } +driver_init(init_timer_itr); diff --git a/core/arch/arm/plat-synquacer/platform_config.h b/core/arch/arm/plat-synquacer/platform_config.h index 4d6d545..8a91ddb 100644 --- a/core/arch/arm/plat-synquacer/platform_config.h +++ b/core/arch/arm/plat-synquacer/platform_config.h @@ -19,6 +19,9 @@ #define CONSOLE_UART_CLK_IN_HZ 62500000 #define CONSOLE_BAUDRATE 115200 +#define THERMAL_SENSOR_BASE 0x54190000 +#define IT_SEC_TIMER 29 + #define DRAM0_BASE 0x80000000 /* Platform specific defines */ diff --git a/core/arch/arm/plat-synquacer/rng_pta.c b/core/arch/arm/plat-synquacer/rng_pta.c new file mode 100644 index 0000000..a760b54 --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2018, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint8_t entropy_pool[ENTROPY_POOL_SIZE] = {0}; +static uint32_t entropy_size; + +/* Current sensor data */ +static uint8_t sensor_data[NUM_OF_SENSORS][SENSOR_DATA_SIZE] = {0}; +static uint8_t s; + +/* Sensor data that passed health test */ +static uint8_t sensor_data_pass[NUM_OF_SENSORS][SENSOR_DATA_SIZE] = {0}; +static uint8_t num_sensors_pass; + +static uint8_t rest_data_pass[NUM_OF_SENSORS][SENSOR_DATA_SIZE] = {0}; + +static uint32_t health_test_fail_cnt; + +static unsigned int entropy_lock = SPINLOCK_UNLOCK; + +static void pool_add_entropy(uint8_t *entropy, uint32_t size) +{ + uint32_t copy_size; + + if (entropy_size >= ENTROPY_POOL_SIZE) + return; + + if ((ENTROPY_POOL_SIZE - entropy_size) >= size) + copy_size = size; + else + copy_size = ENTROPY_POOL_SIZE - entropy_size; + + memcpy((entropy_pool + entropy_size), entropy, copy_size); + + entropy_size += copy_size; +} + +static void pool_get_entropy(uint8_t *buf, uint32_t size) +{ + uint32_t off; + + if (size > entropy_size) + return; + + off = entropy_size - size; + + memcpy(buf, &entropy_pool[off], size); + entropy_size -= size; +} + +static bool health_test(uint8_t sensor_id) +{ + bool result = true; + uint8_t bit_flip_1_0 = 0, bit_flip_0_1 = 0; + uint8_t i; + + /* + * Heatlh test to check if count of bit flips 1-0 or 0-1 lies in 12.5% + * to 37.5% of 128 bytes raw data from particular sensor reading. In + * ideal scenario either of bit flips should be around 25%. + */ + for (i = 0; i < (SENSOR_DATA_SIZE - 1); i++) { + if ((sensor_data[sensor_id][i] ^ + sensor_data[sensor_id][i + 1]) & 0x1) { + bit_flip_1_0 += sensor_data[sensor_id][i] & 0x1; + bit_flip_0_1 += sensor_data[sensor_id][i + 1] & 0x1; + } + } + + if (bit_flip_1_0 > bit_flip_0_1) { + if (bit_flip_0_1 < MIN_BIT_FLIP_COUNT) + result = false; + if (bit_flip_1_0 > MAX_BIT_FLIP_COUNT) + result = false; + } else { + if (bit_flip_1_0 < MIN_BIT_FLIP_COUNT) + result = false; + if (bit_flip_0_1 > MAX_BIT_FLIP_COUNT) + result = false; + } + + return result; +} + +static void pool_check_add_entropy(void) +{ + uint32_t i; + uint8_t entropy_sha512_256[TEE_SHA256_HASH_SIZE]; + uint8_t rest_sensors_pass = 0; + TEE_Result res; + + for (i = 0; i < NUM_OF_SENSORS; i++) { + /* Check if particular sensor data passes health test */ + if (health_test(i) == true) { + if (num_sensors_pass < NUM_OF_SENSORS) { + memcpy(sensor_data_pass[num_sensors_pass], + sensor_data[i], SENSOR_DATA_SIZE); + num_sensors_pass++; + } else { + memcpy(rest_data_pass[rest_sensors_pass], + sensor_data[i], SENSOR_DATA_SIZE); + rest_sensors_pass++; + } + } else { + health_test_fail_cnt++; + /* + * Report health test failures if it exceeds certain + * threshold. + */ + if (health_test_fail_cnt >= THRESHOLD_REPORT_FAILURE) { + IMSG("Health test failed %d times\n", + health_test_fail_cnt); + health_test_fail_cnt = 0; + } + } + } + + /* Check if sensor_data_pass is full */ + if (num_sensors_pass == NUM_OF_SENSORS) { + /* + * Use vetted conditioner SHA512/256 as per + * NIST.SP.800-90B to condition raw data from entropy + * source. + * Here we have assumed that entropy source provides + * 4 bits per 7 sensor readings per sample. + * Also as per NIST.SP.800-90B, to get full entropy + * from vetted conditioner, we need to supply double of + * input entropy. So with full entropy (8 bits per byte) + * we will get yield as one byte of output data for + * every 28 sensor readings. + * For 32 bytes of SHA512/256 output data, we need to + * supply 896 bytes of raw input data. + */ + res = hash_sha512_256_compute(entropy_sha512_256, + (uint8_t *)sensor_data_pass, + CONDITIONER_PAYLOAD); + if (res == TEE_SUCCESS) + pool_add_entropy(entropy_sha512_256, + TEE_SHA256_HASH_SIZE); + } + + if (rest_sensors_pass) + memcpy((uint8_t *)sensor_data_pass, (uint8_t *)rest_data_pass, + (rest_sensors_pass * SENSOR_DATA_SIZE)); + + num_sensors_pass = rest_sensors_pass; +} + +void rng_collect_entropy(void) +{ + uint8_t i; + void *vaddr; + uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); + + cpu_spin_lock(&entropy_lock); + + for (i = 0; i < NUM_OF_SENSORS; i++) { + vaddr = phys_to_virt_io(THERMAL_SENSOR_BASE0 + + (THERMAL_SENSOR_OFFSET * i) + + TEMP_DATA_REG_OFFSET); + sensor_data[i][s] = (uint8_t)read32((vaddr_t)vaddr); + } + + s++; + + if (s >= SENSOR_DATA_SIZE) { + pool_check_add_entropy(); + s = 0; + } + + if (entropy_size >= ENTROPY_POOL_SIZE) { + generic_timer_stop(); + timer_fiq_running = false; + } + + cpu_spin_unlock(&entropy_lock); + thread_set_exceptions(exceptions); +} + +static TEE_Result rng_get_entropy(uint32_t types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + uint8_t *e = NULL; + uint32_t pool_size = 0, rq_size = 0; + uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL); + + cpu_spin_lock(&entropy_lock); + + if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) { + EMSG("bad parameters types: 0x%" PRIx32, types); + return TEE_ERROR_BAD_PARAMETERS; + } + + rq_size = params[0].memref.size; + + if ((rq_size == 0) || (rq_size > ENTROPY_POOL_SIZE)) + return TEE_ERROR_NOT_SUPPORTED; + + e = (uint8_t *)params[0].memref.buffer; + if (!e) + return TEE_ERROR_BAD_PARAMETERS; + + pool_size = entropy_size; + + if (pool_size < rq_size) { + params[0].memref.size = pool_size; + pool_get_entropy(e, pool_size); + } else { + params[0].memref.size = rq_size; + pool_get_entropy(e, rq_size); + } + + if (timer_fiq_running == false) { + /* Enable timer FIQ to fetch entropy */ + generic_timer_start(); + timer_fiq_running = true; + } + + cpu_spin_unlock(&entropy_lock); + thread_set_exceptions(exceptions); + + return TEE_SUCCESS; +} + +/* + * Trusted Application Entry Points + */ +static TEE_Result open_session(uint32_t param_types __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused, + void **session_context __unused) +{ + DMSG("open entry point for pseudo-TA \"%s\"", PTA_NAME); + return TEE_SUCCESS; +} + +static TEE_Result invoke_command(void *pSessionContext __unused, + uint32_t nCommandID, uint32_t nParamTypes, + TEE_Param pParams[TEE_NUM_PARAMS]) +{ + FMSG("command entry point for pseudo-TA \"%s\"", PTA_NAME); + + switch (nCommandID) { + case PTA_CMD_GET_ENTROPY: + return rng_get_entropy(nParamTypes, pParams); + default: + break; + } + + return TEE_ERROR_NOT_IMPLEMENTED; +} + +pseudo_ta_register(.uuid = PTA_RNG_UUID, .name = PTA_NAME, + .flags = PTA_DEFAULT_FLAGS, + .open_session_entry_point = open_session, + .invoke_command_entry_point = invoke_command); diff --git a/core/arch/arm/plat-synquacer/rng_pta.h b/core/arch/arm/plat-synquacer/rng_pta.h new file mode 100644 index 0000000..e238c57 --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2018, Linaro Limited + */ + +#ifndef __RNG_PTA_H +#define __RNG_PTA_H + +#define PTA_NAME "rng.pta" + +#define THERMAL_SENSOR_BASE0 0x54190800 +#define THERMAL_SENSOR_OFFSET 0x80 +#define NUM_OF_SENSORS 7 + +#define TEMP_DATA_REG_OFFSET 0x34 + +#define ENTROPY_POOL_SIZE 4096 + +#define SENSOR_DATA_SIZE 128 +#define CONDITIONER_PAYLOAD (SENSOR_DATA_SIZE * NUM_OF_SENSORS) + +#define LSB_MASK 0x1 + +#define MAX_BIT_FLIP_COUNT 48 +#define MIN_BIT_FLIP_COUNT 16 + +#define THRESHOLD_REPORT_FAILURE 10 + +extern bool timer_fiq_running; + +void rng_collect_entropy(void); + +void generic_timer_start(void); +void generic_timer_stop(void); +void generic_timer_handler(void); + +#endif /* __RNG_PTA_H */ diff --git a/core/arch/arm/plat-synquacer/rng_pta_client.h b/core/arch/arm/plat-synquacer/rng_pta_client.h new file mode 100644 index 0000000..ddd398c --- /dev/null +++ b/core/arch/arm/plat-synquacer/rng_pta_client.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2018, Linaro Limited + */ + +#ifndef __RNG_PTA_CLIENT_H +#define __RNG_PTA_CLIENT_H + +#define PTA_RNG_UUID { 0xab7a617c, 0xb8e7, 0x4d8f, \ + { 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64 } } + +/* + * PTA_CMD_GET_ENTROPY - Get Entropy from RNG using Thermal Sensor + * + * param[0] (inout memref) - Entropy buffer memory reference + * param[1] unused + * param[2] unused + * param[3] unused + */ +#define PTA_CMD_GET_ENTROPY 0x0 + +#endif /* __RNG_PTA_CLIENT_H */ diff --git a/core/arch/arm/plat-synquacer/sub.mk b/core/arch/arm/plat-synquacer/sub.mk index 8ddc2fd..013e57d 100644 --- a/core/arch/arm/plat-synquacer/sub.mk +++ b/core/arch/arm/plat-synquacer/sub.mk @@ -1,2 +1,4 @@ global-incdirs-y += . srcs-y += main.c +srcs-y += rng_pta.c +srcs-y += timer_fiq.c diff --git a/core/arch/arm/plat-synquacer/timer_fiq.c b/core/arch/arm/plat-synquacer/timer_fiq.c new file mode 100644 index 0000000..e25a676 --- /dev/null +++ b/core/arch/arm/plat-synquacer/timer_fiq.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2018, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +bool timer_fiq_running = false; + +void generic_timer_start(void) +{ + uint64_t cval; + uint32_t ctl = 1; + + /* The timer will fire every 2 ms */ + cval = read_cntpct() + (read_cntfrq() / 500); + write_cntps_cval(cval); + + /* Enable the secure physical timer */ + write_cntps_ctl(ctl); +} + +void generic_timer_stop(void) +{ + /* Disable the timer */ + write_cntps_ctl(0); +} + +void generic_timer_handler(void) +{ + /* Ensure that the timer did assert the interrupt */ + assert((read_cntps_ctl() >> 2)); + + /* Disable the timer and reprogram it */ + write_cntps_ctl(0); + generic_timer_start(); +}