mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00
Fix race in GIC IPRIORITY and ITARGET accessors
GICD_IPRIORITYR and GICD_ITARGETSR specifically support byte addressing so that individual interrupt priorities can be atomically updated by issuing a single byte write. The previous implementation of gicd_set_ipriority() and gicd_set_itargetsr() used 32-bit register accesses, modifying values for 4 interrupts at a time, using a read-modify-write approach. This potentially may cause concurrent changes by other CPUs to the adjacent interrupts to be corrupted. This patch fixes the issue by modifying these accessors to use byte addressing. Fixes ARM-software/tf-issues#343 Change-Id: Iec28b5f5074045b00dfb8d5f5339b685f9425915
This commit is contained in:
parent
dbc807179f
commit
a91e12fbea
2 changed files with 5 additions and 17 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -261,10 +261,6 @@ void gicd_set_icactiver(uintptr_t base, unsigned int id)
|
||||||
*/
|
*/
|
||||||
void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
|
void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
|
||||||
{
|
{
|
||||||
unsigned int reg = base + GICD_IPRIORITYR + (id & ~3);
|
|
||||||
unsigned int shift = (id & 3) << 3;
|
|
||||||
unsigned int reg_val = mmio_read_32(reg);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enforce ARM recommendation to manage priority values such
|
* Enforce ARM recommendation to manage priority values such
|
||||||
* that group1 interrupts always have a lower priority than
|
* that group1 interrupts always have a lower priority than
|
||||||
|
@ -278,17 +274,12 @@ void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
|
||||||
pri >= GIC_HIGHEST_SEC_PRIORITY &&
|
pri >= GIC_HIGHEST_SEC_PRIORITY &&
|
||||||
pri <= GIC_LOWEST_SEC_PRIORITY);
|
pri <= GIC_LOWEST_SEC_PRIORITY);
|
||||||
|
|
||||||
reg_val &= ~(GIC_PRI_MASK << shift);
|
mmio_write_8(base + GICD_IPRIORITYR + id, pri & GIC_PRI_MASK);
|
||||||
reg_val |= (pri & GIC_PRI_MASK) << shift;
|
|
||||||
mmio_write_32(reg, reg_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
|
void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
|
||||||
{
|
{
|
||||||
unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
|
mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
|
||||||
unsigned int reg_val = gicd_read_itargetsr(base, id);
|
|
||||||
|
|
||||||
gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
@ -101,10 +101,7 @@ void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
|
||||||
*/
|
*/
|
||||||
void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
|
void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
|
||||||
{
|
{
|
||||||
unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
|
mmio_write_8(base + GICD_ITARGETSR + id, target & GIC_TARGET_CPU_MASK);
|
||||||
unsigned int reg_val = gicd_read_itargetsr(base, id);
|
|
||||||
|
|
||||||
gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
Loading…
Add table
Reference in a new issue