#include "payload_common.h"
#include "payload_utils.h"
#define HEAP_LIMIT 0x200000
#define MSR_APICBASE 0x01b
#define IOP_ICU1 0x20
#define ADDR_IOAPIC_BASE 0xfec00000
typedef struct test_data {
uint32_t count;
uint64_t *data;
} test_data_t;
static void
zero_data(const test_data_t *td)
{
for (uint32_t i = 0; i < td->count; i++) {
td->data[i] = 0;
}
}
static void
output_data(const test_data_t *td, uint64_t tsc_start)
{
for (uint32_t i = td->count - 1; i > 0; i--) {
td->data[i] -= td->data[i - 1];
}
td->data[0] -= tsc_start;
outl(IOP_TEST_VALUE, (uint32_t)(uintptr_t)td->data);
}
static uint32_t
mmio_read4(volatile uint32_t *ptr)
{
return (*ptr);
}
static void
do_test_rdmsr(const test_data_t *td)
{
zero_data(td);
const uint64_t tsc_start = rdtsc();
for (uint32_t i = 0; i < td->count; i++) {
(void) rdmsr(MSR_APICBASE);
td->data[i] = rdtsc();
}
output_data(td, tsc_start);
}
static void
do_test_inb(const test_data_t *td)
{
zero_data(td);
const uint64_t tsc_start = rdtsc();
for (uint32_t i = 0; i < td->count; i++) {
(void) inb(IOP_ICU1);
td->data[i] = rdtsc();
}
output_data(td, tsc_start);
}
static void
do_test_mmio_cheap(const test_data_t *td)
{
zero_data(td);
volatile uint32_t *ioapic_regsel = (void *)(uintptr_t)ADDR_IOAPIC_BASE;
const uint64_t tsc_start = rdtsc();
for (uint32_t i = 0; i < td->count; i++) {
(void) mmio_read4(ioapic_regsel);
td->data[i] = rdtsc();
}
output_data(td, tsc_start);
}
void
start(void)
{
const uint32_t count = inl(IOP_TEST_PARAM0);
if (count * sizeof (uint64_t) > HEAP_LIMIT) {
test_msg("excessive test count for memory sz");
test_result_fail();
return;
}
test_data_t td = {
.count = count,
.data = (uint64_t *)(uintptr_t)MEM_LOC_HEAP,
};
do_test_rdmsr(&td);
do_test_inb(&td);
do_test_mmio_cheap(&td);
test_result_pass();
}