x86: Lock interrupts when connecting interrupts
When dyanmicaly connecting an interrupt via irq_connect(), interrupts must be locked both when allocating a dynamic interrupt stub and when updating the interrupt descriptor table (IDT) to prevent race conditions. Change-Id: I9c68c1f73dda478880f1a32793a84cb6eb87735e Signed-off-by: Peter Mitsis <peter.mitsis@windriver.com>
This commit is contained in:
parent
ae448ff6ca
commit
616ca21599
1 changed files with 25 additions and 9 deletions
|
@ -168,14 +168,22 @@ static NANO_INT_STUB dynamic_stubs[ALL_DYNAMIC_STUBS] = {
|
||||||
static int _int_stub_alloc(void)
|
static int _int_stub_alloc(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int rv = -1;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
for (i = 0; i < ALL_DYNAMIC_STUBS &&
|
for (i = 0; i < ALL_DYNAMIC_STUBS &&
|
||||||
dynamic_stubs[i][0] != _STUB_AVAIL; i++) {
|
dynamic_stubs[i][0] != _STUB_AVAIL; i++) {
|
||||||
}
|
}
|
||||||
if (i == ALL_DYNAMIC_STUBS) {
|
|
||||||
return -1;
|
/* Mark the stub as allocated by using the CALL opcode */
|
||||||
} else {
|
if (i != ALL_DYNAMIC_STUBS) {
|
||||||
return i;
|
dynamic_stubs[i][0] = IA32_CALL_OPCODE;
|
||||||
|
rv = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irq_unlock(key);
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
#endif /* ALL_DYNAMIC_STUBS > 0 */
|
#endif /* ALL_DYNAMIC_STUBS > 0 */
|
||||||
|
|
||||||
|
@ -209,21 +217,27 @@ void _IntVecSet(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
unsigned long long *pIdtEntry;
|
unsigned long long *pIdtEntry;
|
||||||
|
unsigned int key;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The <vector> parameter must be less than the value of the
|
* The <vector> parameter must be less than the value of the
|
||||||
* CONFIG_IDT_NUM_VECTORS configuration parameter, however,
|
* CONFIG_IDT_NUM_VECTORS configuration parameter, however,
|
||||||
* explicit
|
* explicit validation will not be performed in this primitive.
|
||||||
* validation will not be performed in this primitive.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pIdtEntry = (unsigned long long *)(_idt_base_address + (vector << 3));
|
pIdtEntry = (unsigned long long *)(_idt_base_address + (vector << 3));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock interrupts to protect the IDT entry to which _IdtEntryCreate() will
|
||||||
|
* write. They must be locked here because the _IdtEntryCreate() code is
|
||||||
|
* shared with the 'gen_idt' host tool.
|
||||||
|
*/
|
||||||
|
|
||||||
|
key = irq_lock();
|
||||||
_IdtEntCreate(pIdtEntry, routine, dpl);
|
_IdtEntCreate(pIdtEntry, routine, dpl);
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
/* not required to synchronize the instruction and data caches */
|
/* not required to synchronize the instruction and data caches */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -349,9 +363,11 @@ int irq_connect(
|
||||||
* values of <boiRtn>, <eoiRtn>, <boiRtnParm>, <eoiRtnParm>,
|
* values of <boiRtn>, <eoiRtn>, <boiRtnParm>, <eoiRtnParm>,
|
||||||
* <boiParamRequired>, and <eoiParamRequired>. The invocation of
|
* <boiParamRequired>, and <eoiParamRequired>. The invocation of
|
||||||
* _IntEnt() and _IntExit() will always be required.
|
* _IntEnt() and _IntExit() will always be required.
|
||||||
|
*
|
||||||
|
* NOTE: The 'call' opcode for the call to _IntEnt() has already been
|
||||||
|
* written by _int_stub_alloc() to mark the stub as allocated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
STUB_PTR[0] = IA32_CALL_OPCODE;
|
|
||||||
UNALIGNED_WRITE((unsigned int *)&STUB_PTR[1],
|
UNALIGNED_WRITE((unsigned int *)&STUB_PTR[1],
|
||||||
(unsigned int)&_IntEnt - (unsigned int)&STUB_PTR[5]);
|
(unsigned int)&_IntEnt - (unsigned int)&STUB_PTR[5]);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue