Snap for 12359238 from 68a2b1e376d177bf3773ac8a2f17630e61c0c284 to android15-tests-release
Change-Id: Ia502b8d1473fb263a1332c64bd66b0364f649259
diff --git a/app/memorylatencybench/main.c b/app/memorylatencybench/main.c
index 7139896..a6015ac 100644
--- a/app/memorylatencybench/main.c
+++ b/app/memorylatencybench/main.c
@@ -81,7 +81,11 @@
}
}
+static uint64_t mem_lat_pmu_evt_arr[] = {PMU_EV_CPU_CYCLES,
+ PMU_EV_INST_RETIRED};
+
BENCH_SETUP(memlatency) {
+ BENCH_INIT_PMU(mem_lat_pmu_evt_arr);
trusty_bench_get_param_name_cb = &get_param_name_cb_fixed;
trusty_bench_get_formatted_value_cb = &get_formatted_value_cb;
memlatency_state_start =
@@ -163,4 +167,16 @@
return bench_get_duration_ns();
}
+BENCH_RESULT(memlatency, latency_read, cycle_counter_0) {
+ return bench_get_pmu_cnt(0);
+}
+
+BENCH_RESULT(memlatency, latency_read, cycle_counter) {
+ return bench_get_pmu_cnt(1);
+}
+
+BENCH_RESULT(memlatency, latency_read, inst_retired) {
+ return bench_get_pmu_cnt(2);
+}
+
PORT_TEST(memlatency, "com.android.kernel.memorylatency.bench");
diff --git a/app/trusty/user-tasks.mk b/app/trusty/user-tasks.mk
index abbad19..535cf64 100644
--- a/app/trusty/user-tasks.mk
+++ b/app/trusty/user-tasks.mk
@@ -109,10 +109,13 @@
# account for differing licenses across projects.
TRUSTY_SDK_MODULES := \
external/boringssl \
+ external/open-dice \
trusty/kernel/lib/libc-ext \
trusty/kernel/lib/ubsan \
trusty/user/base/interface/hwaes \
+ trusty/user/base/interface/hwbcc \
trusty/user/base/interface/hwkey \
+ trusty/user/base/interface/keybox \
trusty/user/base/interface/keymaster \
trusty/user/base/interface/spi \
trusty/user/base/interface/storage \
@@ -120,9 +123,11 @@
trusty/user/base/lib/dlmalloc \
trusty/user/base/lib/googletest \
trusty/user/base/lib/hwaes \
+ trusty/user/base/lib/hwbcc/client \
trusty/user/base/lib/hwbcc/rust \
trusty/user/base/lib/hwkey \
trusty/user/base/lib/hwkey/rust \
+ trusty/user/base/lib/keybox/client \
trusty/user/base/lib/keymaster \
trusty/user/base/lib/libc-trusty \
trusty/user/base/lib/libcxxabi-trusty \
diff --git a/include/shared/lk/trusty_bench_common.h b/include/shared/lk/trusty_bench_common.h
index 629392e..0b55c5d 100644
--- a/include/shared/lk/trusty_bench_common.h
+++ b/include/shared/lk/trusty_bench_common.h
@@ -94,6 +94,7 @@
int64_t (*bench_result)(void);
trusty_bench_get_formatted_value_callback_t formatted_value_cb;
trusty_bench_get_param_name_callback_t param_name_cb;
+ trusty_bench_check_results_callback_t check_results_cb;
};
/*
@@ -182,15 +183,20 @@
* @metric_name: Name of the metric for which this value is to be
* formatted
*/
-static inline void trusty_bench_sprint_col_stat(char* buffer,
- size_t buffer_len,
- int64_t val,
- const char* metric_name) {
- if (trusty_bench_get_formatted_value_cb == NULL) {
+static inline void trusty_bench_sprint_col_stat(
+ char* buffer,
+ size_t buffer_len,
+ int64_t val,
+ const char* metric_name,
+ trusty_bench_get_formatted_value_callback_t value_format_cb) {
+ if (value_format_cb == NULL) {
+ value_format_cb = trusty_bench_get_formatted_value_cb;
+ }
+
+ if (value_format_cb == NULL) {
snprintf(buffer, buffer_len, "%" PRId64, val);
} else {
- trusty_bench_get_formatted_value_cb(buffer, buffer_len, val,
- metric_name);
+ value_format_cb(buffer, buffer_len, val, metric_name);
EXPECT_EQ(trusty_bench_validate_numeric(buffer), true,
"%s is not a valid double representation.\n", buffer);
}
diff --git a/include/shared/lk/trusty_bench_json_print.h b/include/shared/lk/trusty_bench_json_print.h
index e2636ba..58e9214 100644
--- a/include/shared/lk/trusty_bench_json_print.h
+++ b/include/shared/lk/trusty_bench_json_print.h
@@ -81,18 +81,18 @@
/* print formatted values */
trusty_bench_sprint_col_stat(
buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MIN],
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_unittest_printf("\"min\": \"%s\",", buf);
trusty_bench_sprint_col_stat(
buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MAX],
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_unittest_printf("\"max\": \"%s\",", buf);
trusty_bench_sprint_col_stat(
buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_AVG],
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_unittest_printf("\"avg\": \"%s\",", buf);
trusty_bench_sprint_col_stat(buf, sizeof(buf), entry->metric.cold,
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_unittest_printf("\"cold\": \"%s\",", buf);
/* Formatting is conditional to Metric Name, so we always print raw
diff --git a/include/shared/lk/trusty_bench_option_cb.h b/include/shared/lk/trusty_bench_option_cb.h
index fa350a0..33697ba 100644
--- a/include/shared/lk/trusty_bench_option_cb.h
+++ b/include/shared/lk/trusty_bench_option_cb.h
@@ -51,6 +51,17 @@
*/
static trusty_bench_get_param_name_callback_t trusty_bench_get_param_name_cb;
+// Forward declaration for the trusty_bench_check_results_callback_t definition
+struct bench_metric_list_node;
+
+/**
+ * typedef trusty_bench_check_results_callback_t - Type of the callback to
+ * check if aggregate values are in desired range
+ * @metric_node: The metric node to be validated
+ */
+typedef bool (*trusty_bench_check_results_callback_t)(
+ struct bench_metric_list_node* metric_node);
+
/**
* typedef trusty_bench_get_formatted_value_callback - Type of the callback to
* customize value printing
diff --git a/include/shared/lk/trusty_bench_print_tables.h b/include/shared/lk/trusty_bench_print_tables.h
index 0c6c944..97eef58 100644
--- a/include/shared/lk/trusty_bench_print_tables.h
+++ b/include/shared/lk/trusty_bench_print_tables.h
@@ -212,7 +212,7 @@
/* Get the size of the max value */
trusty_bench_sprint_col_stat(
buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MAX],
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_bench_max_column_width =
MAX(strnlen(buf, sizeof(buf)), trusty_bench_max_column_width);
trusty_bench_max_metric_digit_width = MAX(
@@ -221,11 +221,12 @@
/* Get the size of the min value, because aggregates are signed */
trusty_bench_sprint_col_stat(
buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MIN],
- entry->name);
+ entry->name, entry->formatted_value_cb);
trusty_bench_max_column_width =
MAX(strnlen(buf, sizeof(buf)), trusty_bench_max_column_width);
trusty_bench_max_metric_digit_width = MAX(
trusty_bench_max_metric_digit_width, strnlen(buf, sizeof(buf)));
+ column_width = MAX(column_width, trusty_bench_max_metric_digit_width);
/* Check Column is not too big */
if (trusty_bench_max_column_width > BENCH_MAX_COL_SIZE) {
diff --git a/include/shared/lk/trusty_benchmark.h b/include/shared/lk/trusty_benchmark.h
index 1bb4728..8a1019c 100644
--- a/include/shared/lk/trusty_benchmark.h
+++ b/include/shared/lk/trusty_benchmark.h
@@ -125,6 +125,7 @@
#include <stdarg.h>
#include <stdlib.h>
+#include <lib/pmu/pmu_arch.h>
#include <lib/unittest/unittest.h>
#include <trusty_log.h>
#include "trusty_bench_common.h"
@@ -141,6 +142,10 @@
#endif
#include <uapi/err.h>
+#ifdef WITH_TEST_PMU
+#include <lib/pmu/pmu.h>
+#endif
+
/*
* A few helper macros for static dispatch
*/
@@ -159,10 +164,14 @@
* @last_bench_body_duration: nanoseconds duration of the last execution of
* the bench body.
* @cur_param_idx: index of current parameter in param_array.
+ * @pmu: state of pmu counters
*/
static struct benchmark_internal_state {
int64_t last_bench_body_duration;
size_t cur_param_idx;
+#ifdef WITH_TEST_PMU
+ struct trusty_pmu_state pmu;
+#endif
} bench_state;
/**
@@ -300,6 +309,29 @@
}
/**
+ * trusty_bench_check_metrics - Check if All Metric are within range
+ * after one iteration of bench function for all param/metric in the last BENCH.
+ * @metric_list: List of metrics aggregated during all BENCH runs.
+ * @param_idx: Index of the current parameter in the param_array of
+ * BENCH.
+ */
+static inline bool trusty_bench_check_metrics(struct list_node* metric_list,
+ size_t param_idx) {
+ struct bench_metric_list_node* entry;
+
+ list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
+ node) {
+ if (param_idx == entry->param_idx) {
+ if (entry->check_results_cb != NULL &&
+ !entry->check_results_cb(entry)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
* trusty_bench_reset_metrics - Run All Metric Updaters after one
* iteration of bench function for all param/metric in the last BENCH.
* @metric_list: List of metrics aggregated during all BENCH runs.
@@ -344,14 +376,20 @@
* @suite_name: Identifier of the current suite.
* @bench_name: Unique identifier of the Bench in the suite.
* @metric_name: Name of the metric to print in the result table.
- * @formatted_value_cb: [optional] A callback of
- * trusty_bench_get_formatted_value_callback_t type for formatting the result
- * value to a string
- * @param_name_cb: [optional] A callback of
- * trusty_bench_get_param_name_callback_t type for formatting the param name
+ * @formatted_value_cb: [optional] A callback of
+ * trusty_bench_get_formatted_value_callback_t type
+ * for formatting the result
+ * value to a string
+ * @param_name_cb: [optional] A callback of
+ * trusty_bench_get_param_name_callback_t type
+ * for formatting the param name
+ * @check_results_cb: [optional] A callback of
+ * trusty_bench_check_results_callback_t
+ * type for formatting the param name
*/
#define BENCH_RESULT_INNER(suite_name, bench_name, metric_name, \
- formatted_value_cb_, param_name_cb_) \
+ formatted_value_cb_, param_name_cb_, \
+ check_results_cb_) \
static int64_t update_##suite_name##_##bench_name##_##metric_name(void); \
static struct bench_metric_list_node \
suite_name##_##bench_name##_##metric_name##_node = { \
@@ -363,7 +401,8 @@
.bench_result = \
update_##suite_name##_##bench_name##_##metric_name, \
.formatted_value_cb = formatted_value_cb_, \
- .param_name_cb = param_name_cb_}; \
+ .param_name_cb = param_name_cb_, \
+ .check_results_cb = check_results_cb_}; \
__attribute__((constructor)) void \
suite_name##_##bench_name##_##metric_name##_add(void) { \
list_add_tail(&suite_name##_##bench_name##_metric_list, \
@@ -374,16 +413,38 @@
/* Dispatch Mechanics for BENCH_RESULT */
#define BENCH_RESULT_3(suite_name, bench_name, metric_name) \
- BENCH_RESULT_INNER(suite_name, bench_name, metric_name, 0, 0)
+ BENCH_RESULT_INNER(suite_name, bench_name, metric_name, 0, 0, 0)
+
#define BENCH_RESULT_4(suite_name, bench_name, metric_name, \
formatted_value_cb) \
BENCH_RESULT_INNER(suite_name, bench_name, metric_name, \
- formatted_value_cb, 0)
+ formatted_value_cb, 0, 0)
+
#define BENCH_RESULT_5(suite_name, bench_name, metric_name, \
formatted_value_cb, param_name_cb) \
BENCH_RESULT_INNER(suite_name, bench_name, metric_name, \
- formatted_value_cb, param_name_cb)
+ formatted_value_cb, param_name_cb, 0)
+#define BENCH_RESULT_6(suite_name, bench_name, metric_name, \
+ formatted_value_cb, param_name_cb, check_results_cb) \
+ BENCH_RESULT_INNER(suite_name, bench_name, metric_name, \
+ formatted_value_cb, param_name_cb, check_results_cb)
+
+#ifdef WITH_TEST_PMU
+/**
+ * bench_get_pmu_cnt - convenience function to use in BENCH_RESULT to get
+ * the value of a pmu counter for the last bench body execution.
+ *
+ * Return: The value of a pmu counter of the last completed BENCH body.
+ */
+static inline int64_t bench_get_pmu_cnt(size_t idx) {
+ return bench_state.pmu.vals[idx];
+}
+#else
+static inline int64_t bench_get_pmu_cnt(size_t idx) {
+ return 0;
+}
+#endif
/**
* BENCH_RESULT Dispatch BENCH_RESULT Called 3, 4 or 5 parameters.
* @suite_name: Identifier of the current suite.
@@ -468,6 +529,14 @@
TLOGE("Failed to Allocate memory for bench_metric_list_node!");
return NULL;
}
+
+ // clear parameterized_list from previous runs
+ struct list_node* node = NULL;
+ do {
+ node = list_remove_head(parameterized_list);
+ free(node);
+ } while (node != NULL);
+
list_for_every_entry(unparameterized_list, entry,
struct bench_metric_list_node, node) {
for (size_t idx_param = 0; idx_param < nb_params; ++idx_param) {
@@ -480,6 +549,7 @@
list_pool[idx].bench_result = entry->bench_result;
list_pool[idx].formatted_value_cb = entry->formatted_value_cb;
list_pool[idx].param_name_cb = entry->param_name_cb;
+ list_pool[idx].check_results_cb = entry->check_results_cb;
list_add_tail(parameterized_list, &(list_pool[idx].node));
++idx;
}
@@ -538,6 +608,21 @@
return 0;
}
+#ifdef WITH_TEST_PMU
+#define BENCH_INIT_PMU(evt_arr) \
+ init_pmu_state(evt_arr, countof(evt_arr), &bench_state.pmu)
+#define PMU_START() pmu_start(&bench_state.pmu);
+#define PMU_STOP() pmu_stop(&bench_state.pmu);
+#define RESET_PMU() reset_pmu_cnts(&bench_state.pmu)
+#define CLEAN_PMU() clean_pmu(&bench_state.pmu)
+#else
+#define BENCH_INIT_PMU(evt_arr) (void)(evt_arr)
+#define PMU_START()
+#define PMU_STOP()
+#define RESET_PMU()
+#define CLEAN_PMU()
+#endif
+
/**
* BENCH_CORE - Called by both parametrized and unparameterized
* BENCH for their common part
@@ -589,6 +674,7 @@
} \
int64_t overhead = trusty_bench_get_overhead(); \
\
+ PMU_START(); \
/* Cold Run */ \
int64_t start_time; \
int64_t end_time; \
@@ -596,6 +682,8 @@
int64_t res = suite_name##_##bench_name##_inner_##params(); \
end_time = get_current_time_ns(); \
\
+ PMU_STOP(); \
+ \
if (res != NO_ERROR) { \
TLOGE("ERROR During Cold Run%" PRId64 "\n", res); \
_test_context.all_ok = false; \
@@ -615,13 +703,17 @@
\
if (!_test_context.hard_fail && _test_context.all_ok) { \
trusty_bench_run_metrics(&metric_list, idx_param, true); \
+ RESET_PMU(); \
} \
\
for (size_t idx_run = 0; idx_run < nb_runs; ++idx_run) { \
if (!_test_context.hard_fail && _test_context.all_ok) { \
+ PMU_START(); \
start_time = get_current_time_ns(); \
res = suite_name##_##bench_name##_inner_##params(); \
end_time = get_current_time_ns(); \
+ PMU_STOP(); \
+ \
bench_state.last_bench_body_duration = end_time - start_time; \
if (overhead >= bench_state.last_bench_body_duration) { \
TLOGE("Benchmark internal function is too fast %" PRId64 \
@@ -637,6 +729,7 @@
} \
if (!_test_context.hard_fail && _test_context.all_ok) { \
trusty_bench_run_metrics(&metric_list, idx_param, false); \
+ RESET_PMU(); \
} \
} \
suite_name##_teardown(); \
@@ -644,6 +737,11 @@
if (rc != NO_ERROR) { \
TLOGW("failed to reset CPU affinity: %d\n", rc); \
} \
+ \
+ if (!trusty_bench_check_metrics(&metric_list, idx_param)) { \
+ _test_context.all_ok = false; \
+ _test_context.tests_failed++; \
+ } \
TEST_END_FUNC(); \
free(extended_test_name); \
extended_test_name = NULL; \
@@ -652,7 +750,8 @@
STRINGIFY(suite_name), \
STRINGIFY(bench_name##_##params)); \
trusty_bench_get_param_name_cb = NULL; \
- trusty_bench_get_formatted_value_cb = NULL
+ trusty_bench_get_formatted_value_cb = NULL; \
+ CLEAN_PMU();
/**
* BENCH_PARAMETERIZED_PTR -Called when BENCH has 5 parameters. This allows
diff --git a/lib/pmu/include/lib/pmu/pmu.h b/lib/pmu/include/lib/pmu/pmu.h
new file mode 100644
index 0000000..1a00ece
--- /dev/null
+++ b/lib/pmu/include/lib/pmu/pmu.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "pmu_arch.h"
+
+#ifndef ARM64_READ_SYSREG
+#define DSB __asm__ volatile("dsb sy" ::: "memory")
+#define ISB __asm__ volatile("isb" ::: "memory")
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+#define ARM64_READ_SYSREG(reg) \
+ ({ \
+ uint64_t _val; \
+ __asm__ volatile("mrs %0," TOSTRING(reg) : "=r"(_val)); \
+ _val; \
+ })
+
+#define ARM64_WRITE_SYSREG_RAW(reg, val) \
+ ({ __asm__ volatile("msr " TOSTRING(reg) ", %0" ::"r"(val)); })
+
+#define ARM64_WRITE_SYSREG(reg, val) \
+ ({ \
+ ARM64_WRITE_SYSREG_RAW(reg, val); \
+ ISB; \
+ })
+#endif
+
+static uint64_t set_bit(uint64_t reg, uint64_t bit_number) {
+ return reg | bit_number;
+}
+
+static uint64_t clear_bit(uint64_t reg, uint64_t bit_number) {
+ return reg & (~bit_number);
+}
+
+/**
+ * get_pmu_feat - Returns ID_DFR0_EL1.PerfMon Bits
+ *
+ * Return: ID_DFR0_EL1.PerfMon Bits
+ */
+static uint64_t get_pmu_feat(void) {
+ uint64_t id_dfr0_el1 = ARM64_READ_SYSREG(ID_DFR0_EL1);
+ id_dfr0_el1 = id_dfr0_el1 >> 24; /* Shift PerfMon field down to bit 0 */
+ id_dfr0_el1 &= 0x7; /* Mask to leave just the PerfMon bits */
+ return id_dfr0_el1;
+}
+
+/**
+ * get_pmn - Returns the number of programmable counters
+ *
+ * Return: The number of available programmable counters
+ */
+static uint64_t get_pmn(void) {
+ uint64_t pmcr_el0 = ARM64_READ_SYSREG(PMCR_EL0);
+ pmcr_el0 = pmcr_el0 >> 11; /* Shift N field down to bit 0 */
+ pmcr_el0 &= 0x1F; /* Mask to leave just the 5 N bits */
+ return pmcr_el0;
+}
+
+/**
+ * pmn_config - Sets the event for a programmable counter to record
+ * @counter: r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1)
+ * @event: r1 = The event code (from appropriate TRM or ARM Architecture
+ * Reference Manual)
+ */
+static void pmn_config(uint64_t counter, uint64_t event) {
+ ARM64_WRITE_SYSREG(PMSELR_EL0, counter);
+ ARM64_WRITE_SYSREG(PMXEVTYPER_EL0, event);
+}
+
+/**
+ * set_pmu_filters - Set Event Counter Filters
+ *
+ * @counter: the index of the programmable counter slot to which the filter
+ * applies
+ * @filter_flags: filters to be applied to the programmable counter slot
+ */
+static void set_pmu_filters(uint64_t counter, uint64_t filter_flags) {
+ ARM64_WRITE_SYSREG(PMSELR_EL0, counter);
+ ARM64_WRITE_SYSREG(PMCCFILTR_EL0, filter_flags);
+}
+
+/**
+ * ccnt_divider - Enables/disables the divider (1/64) on CCNT
+ * @divider: r0 = If 0 disable divider, else enable dvider
+ */
+static void ccnt_divider(bool divider) {
+ if (divider) {
+ uint64_t reg = ARM64_READ_SYSREG(PMSELR_EL0);
+ reg = clear_bit(reg, PMCR_EL0_D_BIT);
+ ARM64_WRITE_SYSREG(PMSELR_EL0, reg);
+ } else {
+ uint64_t reg = ARM64_READ_SYSREG(PMSELR_EL0);
+ reg = set_bit(reg, PMCR_EL0_D_BIT);
+ ARM64_WRITE_SYSREG(PMSELR_EL0, reg);
+ }
+}
+
+/**
+ * enable_pmu - Global PMU enable
+ * On ARM11 this enables the PMU, and the counters start immediately
+ * On Cortex this enables the PMU, there are individual enables for the counters
+ */
+static void enable_pmu(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCR_EL0);
+ reg = set_bit(reg, PMCR_EL0_E_BIT);
+ ARM64_WRITE_SYSREG(PMCR_EL0, reg);
+}
+
+/**
+ * disable_pmu - Global PMU disable
+ * On Cortex, this overrides the enable state of the individual counters
+ */
+static void disable_pmu(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCR_EL0);
+ reg = clear_bit(reg, PMCR_EL0_E_BIT);
+ ARM64_WRITE_SYSREG(PMCR_EL0, reg);
+}
+
+/**
+ * enable_ccnt - Enable the CCNT
+ */
+static void enable_ccnt(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCNTENSET_EL0);
+ reg = set_bit(reg, PMCNTENSET_EL0_C_BIT);
+ ARM64_WRITE_SYSREG(PMCNTENSET_EL0, reg);
+}
+
+/**
+ * disable_ccnt - Disable the CCNT
+ */
+static void disable_ccnt(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCNTENSET_EL0);
+ reg = clear_bit(reg, PMCNTENSET_EL0_C_BIT);
+ ARM64_WRITE_SYSREG(PMCNTENSET_EL0, reg);
+}
+
+/**
+ * enable_pmn - Enable PMN{n}
+ * @counter: The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
+ */
+static void enable_pmn(uint64_t counter) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCNTENSET_EL0);
+ reg = set_bit(reg, (uint64_t)1 << counter);
+ ARM64_WRITE_SYSREG(PMCNTENSET_EL0, reg);
+}
+
+/**
+ * disable_pmn - Disable PMN{n}
+ * @counter: The counter to disable (e.g. 0 for PMN0, 1 for PMN1)
+ */
+static void disable_pmn(uint64_t counter) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCNTENSET_EL0);
+ reg = clear_bit(reg, (uint64_t)1 << counter);
+ ARM64_WRITE_SYSREG(PMCNTENSET_EL0, reg);
+}
+
+/**
+ * read_ccnt - Returns the value of CCNT
+ *
+ * Return: the value to PMCCNTR_EL0
+ */
+static uint64_t read_ccnt(void) {
+ return ARM64_READ_SYSREG(PMCCNTR_EL0);
+}
+
+/**
+ * read_pmn - Returns the value of PMN{n}
+ * @counter: The counter to read (e.g. 0 for PMN0, 1 for PMN1)
+ *
+ * Return: the value to PMXEVCNTR_EL0 after selecting event
+ */
+static uint64_t read_pmn(uint64_t counter) {
+ counter &= 0x1F;
+ ARM64_WRITE_SYSREG(PMSELR_EL0, counter);
+ return ARM64_READ_SYSREG(PMXEVCNTR_EL0);
+}
+
+/**
+ * read_flags - Returns the value of the overflow flags
+ *
+ * Return: the value of PmovSCLR_EL0
+ */
+static uint64_t read_flags(void) {
+ return ARM64_READ_SYSREG(PmovSCLR_EL0);
+}
+
+/**
+ * write_flags - Writes the overflow flags
+ * @flags: value of the flags to write to PmovSSET_EL0
+ */
+static void write_flags(uint64_t flags) {
+ ARM64_WRITE_SYSREG(PmovSCLR_EL0, flags);
+}
+
+/**
+ * reset_pmn - Resets the programmable counters
+ */
+static void reset_pmn(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCR_EL0);
+ reg = set_bit(reg, PMCR_EL0_P_BIT);
+ ARM64_WRITE_SYSREG(PMCR_EL0, reg);
+}
+
+/**
+ * reset_ccnt - Resets the CCNT
+ */
+static void reset_ccnt(void) {
+ uint64_t reg = ARM64_READ_SYSREG(PMCR_EL0);
+ reg = set_bit(reg, PMCR_EL0_C_BIT);
+ ARM64_WRITE_SYSREG(PMCR_EL0, reg);
+}
+/**
+ * get_event_code_string - Get the code name for a given PMU event
+ *
+ * @event: current states of the pmu counters
+ *
+ * Return: The Code of the event as a String
+ */
+static const char* get_event_code_string(int event) {
+ switch (event) {
+ case PMU_EV_SW_INCR:
+ return "SW_INCR";
+ case PMU_EV_L1I_CACHE_REFILL:
+ return "L1I_CACHE_REFILL";
+ case PMU_EV_L1I_TLB_REFILL:
+ return "L1I_TLB_REFILL";
+ case PMU_EV_L1D_CACHE_REFILL:
+ return "L1D_CACHE_REFILL";
+ case PMU_EV_L1D_CACHE:
+ return "L1D_CACHE";
+ case PMU_EV_L1D_TLB_REFILL:
+ return "L1D_TLB_REFILL";
+ case PMU_EV_LD_RETIRED:
+ return "LD_RETIRED";
+ case PMU_EV_ST_RETIRED:
+ return "ST_RETIRED";
+ case PMU_EV_INST_RETIRED:
+ return "INST_RETIRED";
+ case PMU_EV_EXC_TAKEN:
+ return "EXC_TAKEN";
+ case PMU_EV_EXC_RETURN:
+ return "EXC_RETURN";
+ case PMU_EV_CID_WRITE_RETIRED:
+ return "CID_WRITE_RETIRED";
+ case PMU_EV_PC_WRITE_RETIRED:
+ return "PC_WRITE_RETIRED";
+ case PMU_EV_BR_IMMED_RETIRED:
+ return "BR_IMMED_RETIRED";
+ case PMU_EV_UNALIGNED_LDST_RETIRED:
+ return "UNALIGNED_LDST_RETIRED";
+ case PMU_EV_BR_MIS_PRED:
+ return "BR_MIS_PRED";
+ case PMU_EV_CPU_CYCLES:
+ return "CPU_CYCLES";
+ case PMU_EV_BR_PRED:
+ return "BR_PRED";
+ case PMU_EV_MEM_ACCESS:
+ return "MEM_ACCESS";
+ case PMU_EV_L1I_CACHE:
+ return "L1I_CACHE";
+ case PMU_EV_L1D_CACHE_WB:
+ return "L1D_CACHE_WB";
+ case PMU_EV_L2D_CACHE:
+ return "L2D_CACHE";
+ case PMU_EV_L2D_CACHE_REFILL:
+ return "L2D_CACHE_REFILL";
+ case PMU_EV_L2D_CACHE_WB:
+ return "L2D_CACHE_WB";
+ case PMU_EV_BUS_ACCESS:
+ return "BUS_ACCESS";
+ case PMU_EV_MEMORY_ERROR:
+ return "MEMORY_ERROR";
+ case PMU_EV_BUS_CYCLES:
+ return "BUS_CYCLES";
+ case PMU_EV_CHAIN:
+ return "CHAIN";
+ case PMU_EV_BUS_ACCESS_LD:
+ return "BUS_ACCESS_LD";
+ case PMU_EV_BUS_ACCESS_ST:
+ return "BUS_ACCESS_ST";
+ case PMU_EV_BR_INDIRECT_SPEC:
+ return "BR_INDIRECT_SPEC";
+ case PMU_EV_EXC_IRQ:
+ return "EXC_IRQ";
+ case PMU_EV_EXC_FIQ:
+ return "EXC_FIQ";
+ case -1:
+ return "CCNT";
+ default:
+ return "UNKNOWN_EVENT";
+ }
+}
+
+#define RECORD_SEL1 (U(0) | PMCCFILTR_EL0_U_BIT | PMCCFILTR_EL0_NSK_BIT)
+#define RECORD_EL3 \
+ (U(0) | PMCCFILTR_EL0_U_BIT | PMCCFILTR_EL0_P_BIT | PMCCFILTR_EL0_M_BIT)
+#define RECORD_ALL (U(0) | PMCCFILTR_EL0_NSH_BIT)
+
+/**
+ * struct trusty_pmu_state - Holds the current state of pmu slots and counters.
+ * @evts: array of pmu counter events codes with which respective
+ * slot have to be programmed
+ * @vals: array of pmu counter current values
+ * @evt_cnt: number of events/values
+ */
+struct trusty_pmu_state {
+ uint64_t* evts;
+ uint64_t* vals;
+ uint64_t evt_cnt;
+};
+
+/**
+ * pmu_start - Setup events slots and Start recording
+ *
+ * @state: current states of the pmu counters
+ */
+static void pmu_start(struct trusty_pmu_state* state) {
+ if (state == NULL || state->evts == NULL) {
+ return;
+ }
+
+ uint64_t nb_counters = get_pmn();
+
+ if (nb_counters < state->evt_cnt) {
+ fprintf(stderr,
+ "ERROR: There are only %" PRIu64
+ " Programmable Counters, yet you are trying to record %" PRIu64
+ " events.\n",
+ nb_counters, state->evt_cnt);
+
+ return;
+ }
+
+ enable_pmu(); // Enable the PMU
+ reset_ccnt(); // Reset the CCNT (cycle counter)
+ reset_pmn(); // Reset the configurable counters
+ write_flags((1 << 31) | 0xf); // Reset overflow flags
+
+ for (size_t i = 0; i < state->evt_cnt; i++) {
+ pmn_config(i, state->evts[i] | RECORD_ALL);
+ set_pmu_filters(i, 0U | RECORD_ALL);
+ }
+ ccnt_divider(0); // Enable divide by 64
+ enable_ccnt(); // Enable CCNT
+
+ for (size_t i = 0; i < state->evt_cnt; i++)
+ enable_pmn(i);
+}
+
+/**
+ * pmu_stop - Stop recording
+ *
+ * @state: current states of the pmu counters
+ */
+static void pmu_stop(struct trusty_pmu_state* state) {
+ if (state == NULL || state->evts == NULL) {
+ return;
+ }
+ disable_ccnt();
+
+ for (size_t i = 0; i < state->evt_cnt; i++)
+ disable_pmn(i);
+
+ for (size_t i = 0; i < state->evt_cnt; i++) {
+ state->vals[i + 1] = read_pmn(i);
+ }
+ state->vals[0] = read_ccnt(); // Read CCNT
+}
+
+/**
+ * init_pmu_state - Allocate memory for values and bind events to be programmed
+ *
+ * @evt_arr: array of events on whiches to program into the slots
+ * @evt_arr_sz: countof/nb_elements of evt_arr
+ * @pmu_state: current states of the pmu counters
+ */
+static inline void init_pmu_state(uint64_t* evt_arr,
+ size_t evt_arr_sz,
+ struct trusty_pmu_state* pmu_state) {
+ pmu_state->vals = calloc(evt_arr_sz + 1, sizeof(uint64_t));
+ pmu_state->evts = evt_arr;
+ pmu_state->evt_cnt = evt_arr_sz;
+}
+
+/**
+ * clean_pmu - Frees memory of value array and reset size
+ *
+ * @pmu_state: current states of the pmu counters
+ */
+static inline void clean_pmu(struct trusty_pmu_state* pmu_state) {
+ free(pmu_state->vals);
+ pmu_state->vals = NULL;
+ pmu_state->evt_cnt = 0;
+}
+
+/**
+ * reset_pmu_cnts - Resets all pmu counters to 0
+ *
+ * @pmu_state: current states of the pmu counters
+ */
+static inline void reset_pmu_cnts(struct trusty_pmu_state* pmu_state) {
+ memset(pmu_state->vals, 0, sizeof(uint64_t) * pmu_state->evt_cnt);
+}
diff --git a/lib/pmu/include/lib/pmu/pmu_arch.h b/lib/pmu/include/lib/pmu/pmu_arch.h
new file mode 100644
index 0000000..689f640
--- /dev/null
+++ b/lib/pmu/include/lib/pmu/pmu_arch.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PMU_ARCH_H
+#define PMU_ARCH_H
+
+#define U(_x) (_x##U)
+
+/*******************************************************************************
+ * Definitions of register offsets and fields in the CNTBaseN Frame of the
+ * system level implementation of the Generic Timer.
+ ******************************************************************************/
+/* Physical Count register. */
+#define CNTPCT_LO U(0x0)
+/* Counter Frequency register. */
+#define CNTBASEN_CNTFRQ U(0x10)
+/* Physical Timer CompareValue register. */
+#define CNTP_CVAL_LO U(0x20)
+/* Physical Timer Control register. */
+#define CNTP_CTL U(0x2c)
+
+/* PMCR_EL0 definitions */
+#define PMCR_EL0_RESET_VAL U(0x0)
+#define PMCR_EL0_N_SHIFT U(11)
+#define PMCR_EL0_N_MASK U(0x1f)
+#define PMCR_EL0_N_BITS (PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT (U(1) << 6)
+#define PMCR_EL0_DP_BIT (U(1) << 5)
+#define PMCR_EL0_X_BIT (U(1) << 4)
+#define PMCR_EL0_D_BIT (U(1) << 3)
+#define PMCR_EL0_C_BIT (U(1) << 2)
+#define PMCR_EL0_P_BIT (U(1) << 1)
+#define PMCR_EL0_E_BIT (U(1) << 0)
+
+/* PMCNTENSET_EL0 definitions */
+#define PMCNTENSET_EL0_C_BIT (U(1) << 31)
+#define PMCNTENSET_EL0_P_BIT(x) (U(1) << x)
+
+/* PMEVTYPER<n>_EL0 definitions */
+#define PMEVTYPER_EL0_P_BIT (U(1) << 31)
+#define PMEVTYPER_EL0_NSK_BIT (U(1) << 29)
+#define PMEVTYPER_EL0_NSH_BIT (U(1) << 27)
+#define PMEVTYPER_EL0_M_BIT (U(1) << 26)
+#define PMEVTYPER_EL0_MT_BIT (U(1) << 25)
+#define PMEVTYPER_EL0_SH_BIT (U(1) << 24)
+#define PMEVTYPER_EL0_EVTCOUNT_BITS U(0x000003FF)
+
+/* PMCCFILTR_EL0 definitions */
+#define PMCCFILTR_EL0_P_BIT (U(1) << 31)
+#define PMCCFILTR_EL0_U_BIT (U(1) << 30)
+#define PMCCFILTR_EL0_NSK_BIT (U(1) << 29)
+#define PMCCFILTR_EL0_NSH_BIT (U(1) << 27)
+#define PMCCFILTR_EL0_M_BIT (U(1) << 26)
+#define PMCCFILTR_EL0_MT_BIT (U(1) << 25)
+#define PMCCFILTR_EL0_SH_BIT (U(1) << 24)
+#define PMCCFILTR_EL0_T_BIT (U(1) << 23)
+#define PMCCFILTR_EL0_RLK_BIT (U(1) << 22)
+#define PMCCFILTR_EL0_RLU_BIT (U(1) << 21)
+#define PMCCFILTR_EL0_RLH_BIT (U(1) << 20)
+
+/* PMU event counter ID definitions */
+#define PMU_EV_SW_INCR U(0x00)
+#define PMU_EV_L1I_CACHE_REFILL U(0x01)
+#define PMU_EV_L1I_TLB_REFILL U(0x02)
+#define PMU_EV_L1D_CACHE_REFILL U(0x03)
+#define PMU_EV_L1D_CACHE U(0x04)
+#define PMU_EV_L1D_TLB_REFILL U(0x05)
+#define PMU_EV_LD_RETIRED U(0x06)
+#define PMU_EV_ST_RETIRED U(0x07)
+#define PMU_EV_INST_RETIRED U(0x08)
+#define PMU_EV_EXC_TAKEN U(0x09)
+#define PMU_EV_EXC_RETURN U(0x0A)
+#define PMU_EV_CID_WRITE_RETIRED U(0x0B)
+#define PMU_EV_PC_WRITE_RETIRED U(0x0C)
+#define PMU_EV_BR_IMMED_RETIRED U(0x0D)
+#define PMU_EV_BR_RETURN_RETIRED U(0x0E)
+#define PMU_EV_UNALIGNED_LDST_RETIRED U(0x0F)
+#define PMU_EV_BR_MIS_PRED U(0x10)
+#define PMU_EV_CPU_CYCLES U(0x11)
+#define PMU_EV_BR_PRED U(0x12)
+#define PMU_EV_MEM_ACCESS U(0x13)
+#define PMU_EV_L1I_CACHE U(0x14)
+#define PMU_EV_L1D_CACHE_WB U(0x15)
+#define PMU_EV_L2D_CACHE U(0x16)
+#define PMU_EV_L2D_CACHE_REFILL U(0x17)
+#define PMU_EV_L2D_CACHE_WB U(0x18)
+#define PMU_EV_BUS_ACCESS U(0x19)
+#define PMU_EV_MEMORY_ERROR U(0x1A)
+#define PMU_EV_BUS_CYCLES U(0x1D)
+#define PMU_EV_CHAIN U(0x1E)
+#define PMU_EV_BUS_ACCESS_LD U(0x60)
+#define PMU_EV_BUS_ACCESS_ST U(0x61)
+#define PMU_EV_BR_INDIRECT_SPEC U(0x7A)
+#define PMU_EV_EXC_IRQ U(0x86)
+#define PMU_EV_EXC_FIQ U(0x87)
+
+#endif /* PMU_ARCH_H */
diff --git a/lib/pmu/rules.mk b/lib/pmu/rules.mk
new file mode 100644
index 0000000..7050fd5
--- /dev/null
+++ b/lib/pmu/rules.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+GLOBAL_INCLUDES += $(LOCAL_DIR)/include/
+
+include make/module.mk
diff --git a/lib/trusty/trusty_virtio.c b/lib/trusty/trusty_virtio.c
index 615b9ff..7f8616d 100644
--- a/lib/trusty/trusty_virtio.c
+++ b/lib/trusty/trusty_virtio.c
@@ -504,7 +504,7 @@
goto err_bad_state;
}
- if ((size_t)descr_sz != vb->descr_size) {
+ if ((size_t)descr_sz != vb->descr_size || descr_sz == 0) {
LTRACEF("unexpected descriptor size (%zd vs. %zd)\n", (size_t)descr_sz,
vb->descr_size);
ret = ERR_INVALID_ARGS;
diff --git a/lib/unittest/rules.mk b/lib/unittest/rules.mk
index e6baedd..bf73fb7 100644
--- a/lib/unittest/rules.mk
+++ b/lib/unittest/rules.mk
@@ -24,9 +24,11 @@
MODULE := $(LOCAL_DIR)
-MODULE_SRCS := \
- $(LOCAL_DIR)/unittest.c
+MODULE_SRCS := $(LOCAL_DIR)/unittest.c
-GLOBAL_INCLUDES += $(LOCAL_DIR)/include/
+GLOBAL_INCLUDES += $(LOCAL_DIR)/include/ \
+ $(LOCAL_DIR)/../pmu/include/
+
+MODULE_DEPS += trusty/kernel/lib/pmu
include make/module.mk
diff --git a/platform/generic-x86_64/rules.mk b/platform/generic-x86_64/rules.mk
index c32ef81..ca9811a 100644
--- a/platform/generic-x86_64/rules.mk
+++ b/platform/generic-x86_64/rules.mk
@@ -30,6 +30,5 @@
$(LOCAL_DIR)/rust \
dev/interrupt/x86_lapic \
dev/timer/x86_generic \
- dev/virtio/vsock-rust \
include make/module.mk
diff --git a/platform/generic-x86_64/rust/rules.mk b/platform/generic-x86_64/rust/rules.mk
index 6a71969..40c05fd 100644
--- a/platform/generic-x86_64/rust/rules.mk
+++ b/platform/generic-x86_64/rust/rules.mk
@@ -10,5 +10,6 @@
MODULE_LIBRARY_DEPS += \
external/rust/crates/acpi \
external/rust/crates/log \
+ dev/virtio/vsock-rust \
include make/library.mk
diff --git a/platform/generic-x86_64/rust/src/lib.rs b/platform/generic-x86_64/rust/src/lib.rs
index 67b3ca0..2c78b62 100644
--- a/platform/generic-x86_64/rust/src/lib.rs
+++ b/platform/generic-x86_64/rust/src/lib.rs
@@ -86,7 +86,14 @@
}
}
-extern "C" fn platform_acpi_init_func(_level: c_uint) {
+/// Search the ACPI tables for the physical address which is the base of the MMIO
+/// region and pass it to `pci_init_mmio` to initialize the virtio-vsock bridge.
+///
+/// # Safety
+///
+/// A caller must ensure that this function is called exactly once during kernel
+/// initialization on a system which has a BIOS (as opposed to UEFI systems).
+unsafe extern "C" fn platform_acpi_init_func(_level: c_uint) {
// SAFETY: search_for_rsdp_bios searches for a RSDP on BIOS systems.
// It is not safe to call on a UEFI system. crosvm currently emulates
// a BIOS system.
@@ -109,10 +116,10 @@
let entry_size = (1 + entry.bus_number_end as usize - entry.bus_number_start as usize) << 20;
- log::error!(
- "TODO: call init function for pci bus at {:#x}, size {entry_size:#x}",
- entry.base_address as usize
- );
+ // SAFETY: the first argument must be a valid physical address pointing to the base of the MMIO region.
+ // The second argument must be the size of the MMIO region and be valid under the PCI express version
+ // implemented by the system. `pci_init_mmio` must not have been called previously.
+ unsafe { vsock::pci_init_mmio(entry.base_address as usize, entry_size, 1usize << 15) };
}
LK_INIT_HOOK!(platform_acpi_init, platform_acpi_init_func, lk_init_level::LK_INIT_LEVEL_THREADING);