mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
ppc/xive: Check TIMA operations validity
Certain TIMA operations should only be performed when a ring is valid, others when the ring is invalid, and they are considered undefined if used incorrectly. Add checks for this condition. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Reviewed-by: Michael Kowal <kowal@linux.ibm.com> Tested-by: Gautam Menghani <gautam@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20250512031100.439842-44-npiggin@gmail.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
committed by
Cédric Le Goater
parent
565e6d4d21
commit
ca0081ef7e
+115
-81
@@ -25,6 +25,19 @@
|
||||
/*
|
||||
* XIVE Thread Interrupt Management context
|
||||
*/
|
||||
bool xive_ring_valid(XiveTCTX *tctx, uint8_t ring)
|
||||
{
|
||||
uint8_t cur_ring;
|
||||
|
||||
for (cur_ring = ring; cur_ring <= TM_QW3_HV_PHYS;
|
||||
cur_ring += XIVE_TM_RING_SIZE) {
|
||||
if (!(tctx->regs[cur_ring + TM_WORD2] & 0x80)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr)
|
||||
{
|
||||
switch (ring) {
|
||||
@@ -663,6 +676,8 @@ typedef struct XiveTmOp {
|
||||
uint8_t page_offset;
|
||||
uint32_t op_offset;
|
||||
unsigned size;
|
||||
bool hw_ok;
|
||||
bool sw_ok;
|
||||
void (*write_handler)(XivePresenter *xptr, XiveTCTX *tctx,
|
||||
hwaddr offset,
|
||||
uint64_t value, unsigned size);
|
||||
@@ -675,34 +690,34 @@ static const XiveTmOp xive_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, true, true,
|
||||
xive_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, true, true,
|
||||
xive_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, true, true,
|
||||
xive_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, false, true,
|
||||
xive_tm_vt_push, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, true, true,
|
||||
NULL, xive_tm_vt_poll },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, true, false,
|
||||
xive_tm_set_os_pending, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, true, false,
|
||||
NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, true, false,
|
||||
NULL, xive_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, true, false,
|
||||
NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, true, false,
|
||||
NULL, xive_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, true, false,
|
||||
NULL, xive_tm_pull_phys_ctx },
|
||||
};
|
||||
|
||||
static const XiveTmOp xive2_tm_operations[] = {
|
||||
@@ -710,52 +725,48 @@ static const XiveTmOp xive2_tm_operations[] = {
|
||||
* MMIOs below 2K : raw values and special operations without side
|
||||
* effects
|
||||
*/
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive2_tm_set_os_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, xive2_tm_push_os_ctx,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, xive_tm_set_os_lgs,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive2_tm_set_hv_cppr,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL,
|
||||
xive_tm_vt_poll },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, xive2_tm_set_hv_target,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, true, true,
|
||||
xive2_tm_set_os_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, true, true,
|
||||
xive2_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 8, true, true,
|
||||
xive2_tm_push_os_ctx, NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_QW1_OS + TM_LGS, 1, true, true,
|
||||
xive_tm_set_os_lgs, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, true, true,
|
||||
xive2_tm_set_hv_cppr, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, true, true,
|
||||
NULL, xive_tm_vt_poll },
|
||||
{ XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_T, 1, true, true,
|
||||
xive2_tm_set_hv_target, NULL },
|
||||
|
||||
/* MMIOs above 2K : special operations with side effects */
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL,
|
||||
xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL,
|
||||
xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL,
|
||||
xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, NULL,
|
||||
xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL,
|
||||
xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL,
|
||||
xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, xive2_tm_pull_os_ctx_ol,
|
||||
NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, NULL,
|
||||
xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, NULL,
|
||||
xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, xive2_tm_pull_phys_ctx_ol,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_EL, 1, xive2_tm_ack_os_el,
|
||||
NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_os_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, true, false,
|
||||
NULL, xive2_tm_pull_os_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, true, false,
|
||||
NULL, xive_tm_ack_hv_reg },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, true, false,
|
||||
NULL, xive2_tm_pull_pool_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX_OL, 1, true, false,
|
||||
xive2_tm_pull_os_ctx_ol, NULL },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_G2, 4, true, false,
|
||||
NULL, xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX, 1, true, false,
|
||||
NULL, xive2_tm_pull_phys_ctx },
|
||||
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_PHYS_CTX_OL, 1, true, false,
|
||||
xive2_tm_pull_phys_ctx_ol, NULL },
|
||||
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_EL, 1, true, false,
|
||||
xive2_tm_ack_os_el, NULL },
|
||||
};
|
||||
|
||||
static const XiveTmOp *xive_tm_find_op(XivePresenter *xptr, hwaddr offset,
|
||||
@@ -797,18 +808,28 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
const XiveTmOp *xto;
|
||||
uint8_t ring = offset & TM_RING_OFFSET;
|
||||
bool is_valid = xive_ring_valid(tctx, ring);
|
||||
bool hw_owned = is_valid;
|
||||
|
||||
trace_xive_tctx_tm_write(tctx->cs->cpu_index, offset, size, value);
|
||||
|
||||
/*
|
||||
* TODO: check V bit in Q[0-3]W2
|
||||
*/
|
||||
|
||||
/*
|
||||
* First, check for special operations in the 2K region
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (xto) {
|
||||
if (hw_owned && !xto->hw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
if (!hw_owned && !xto->sw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to SW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset & TM_SPECIAL_OP) {
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (!xto) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
@@ -821,7 +842,6 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Then, for special operations in the region below 2K.
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, true);
|
||||
if (xto) {
|
||||
xto->write_handler(xptr, tctx, offset, value, size);
|
||||
return;
|
||||
@@ -830,6 +850,11 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Finish with raw access to the register values
|
||||
*/
|
||||
if (hw_owned) {
|
||||
/* Store context operations are dangerous when context is valid */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined write to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
xive_tm_raw_write(tctx, offset, value, size);
|
||||
}
|
||||
|
||||
@@ -837,17 +862,27 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
const XiveTmOp *xto;
|
||||
uint8_t ring = offset & TM_RING_OFFSET;
|
||||
bool is_valid = xive_ring_valid(tctx, ring);
|
||||
bool hw_owned = is_valid;
|
||||
uint64_t ret;
|
||||
|
||||
/*
|
||||
* TODO: check V bit in Q[0-3]W2
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (xto) {
|
||||
if (hw_owned && !xto->hw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined read to HW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
if (!hw_owned && !xto->sw_ok) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: undefined read to SW TIMA "
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* First, check for special operations in the 2K region
|
||||
*/
|
||||
if (offset & TM_SPECIAL_OP) {
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (!xto) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access to TIMA"
|
||||
"@%"HWADDR_PRIx" size %d\n", offset, size);
|
||||
@@ -860,7 +895,6 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset,
|
||||
/*
|
||||
* Then, for special operations in the region below 2K.
|
||||
*/
|
||||
xto = xive_tm_find_op(tctx->xptr, offset, size, false);
|
||||
if (xto) {
|
||||
ret = xto->read_handler(xptr, tctx, offset, size);
|
||||
goto out;
|
||||
|
||||
@@ -365,6 +365,7 @@ static inline uint32_t xive_tctx_word2(uint8_t *ring)
|
||||
return *((uint32_t *) &ring[TM_WORD2]);
|
||||
}
|
||||
|
||||
bool xive_ring_valid(XiveTCTX *tctx, uint8_t ring);
|
||||
bool xive_nsr_indicates_exception(uint8_t ring, uint8_t nsr);
|
||||
bool xive_nsr_indicates_group_exception(uint8_t ring, uint8_t nsr);
|
||||
uint8_t xive_nsr_exception_ring(uint8_t ring, uint8_t nsr);
|
||||
|
||||
Reference in New Issue
Block a user