blob: 82ca679a066530515cb2e839d026be9a08e92048 [file] [log] [blame]
/*
* Copyright 2019 The Hafnium Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hf/dlog.h"
#include "vmapi/hf/call.h"
#include "../msr.h"
#include "sysregs.h"
#include "test/hftest.h"
/**
* Tracks the number of times the exception handler has been invoked.
*/
static int exception_handler_exception_count = 0;
/**
* Sends the number of exceptions handled to the Primary VM.
*/
void exception_handler_send_exception_count(void)
{
void *send_buf = SERVICE_SEND_BUFFER();
dlog("Sending exception_count %d to primary VM\n",
exception_handler_exception_count);
memcpy_s(send_buf, FFA_MSG_PAYLOAD_MAX,
(const void *)&exception_handler_exception_count,
sizeof(exception_handler_exception_count));
EXPECT_EQ(ffa_msg_send(hf_vm_get_id(), HF_PRIMARY_VM_ID,
sizeof(exception_handler_exception_count), 0)
.func,
FFA_SUCCESS_32);
}
/**
* Receives the number of exceptions handled.
*/
int exception_handler_receive_exception_count(
const struct ffa_value *send_res,
const struct ffa_memory_region *recv_buf)
{
int exception_count = *((const int *)recv_buf);
EXPECT_EQ(send_res->func, FFA_MSG_SEND_32);
EXPECT_EQ(ffa_msg_send_size(*send_res), sizeof(exception_count));
EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
return exception_count;
}
/**
* EL1 exception handler to use in unit test VMs.
* Skips the instruction that triggered the exception.
*/
bool exception_handler_skip_instruction(void)
{
dlog("%s function is triggered!\n", __func__);
++exception_handler_exception_count;
/* Skip instruction that triggered the exception. */
uint64_t next_pc = read_msr(elr_el1);
next_pc += 4UL;
write_msr(elr_el1, next_pc);
/* Indicate that elr_el1 should not be restored. */
return true;
}
/**
* EL1 exception handler to use in unit test VMs.
* Yields control back to the hypervisor and sends the number of exceptions.
*/
static bool exception_handler_yield(void)
{
dlog("%s function is triggered!\n", __func__);
++exception_handler_exception_count;
exception_handler_send_exception_count();
/* Indicate that elr_el1 should not be restored. */
return true;
}
/**
* EL1 exception handler to use in unit test VMs.
* Yields control back to the hypervisor and sends the number of exceptions.
* Asserts that the Exception Class is Unknown.
*/
bool exception_handler_yield_unknown(void)
{
uintreg_t esr_el1 = read_msr(ESR_EL1);
EXPECT_EQ(GET_ESR_EC(esr_el1), EC_UNKNOWN);
return exception_handler_yield();
}
/**
* EL1 exception handler to use in unit test VMs.
* Yields control back to the hypervisor and sends the number of exceptions.
* Asserts that the Exception Class is Data Abort (same EL).
*/
bool exception_handler_yield_data_abort(void)
{
uintreg_t esr_el1 = read_msr(ESR_EL1);
EXPECT_EQ(GET_ESR_EC(esr_el1), EC_DATA_ABORT_SAME_EL);
return exception_handler_yield();
}
/**
* EL1 exception handler to use in unit test VMs.
* Yields control back to the hypervisor and sends the number of exceptions.
* Asserts that the Exception Class is Instruction Abort (same EL).
*/
bool exception_handler_yield_instruction_abort(void)
{
uintreg_t esr_el1 = read_msr(ESR_EL1);
EXPECT_EQ(GET_ESR_EC(esr_el1), EC_INSTRUCTION_ABORT_SAME_EL);
return exception_handler_yield();
}
/**
* Returns the number of times the instruction handler was invoked.
*/
int exception_handler_get_num(void)
{
return exception_handler_exception_count;
}
/**
* Resets the number of exceptions counter;
*/
void exception_handler_reset(void)
{
exception_handler_exception_count = 0;
}