diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-08-28 07:30:34 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-08-28 07:30:34 -0600 |
commit | 85d420dc3ad7d6fb9a675ac60f77f182a7438483 (patch) | |
tree | f9effc3c6dfbf2a4ac90367e4426c3402d0b94d5 /nuttx/arch/x86 | |
parent | c6aca23cb29f4cc671bb885ee192b8452ae05e86 (diff) | |
download | nuttx-85d420dc3ad7d6fb9a675ac60f77f182a7438483.tar.gz nuttx-85d420dc3ad7d6fb9a675ac60f77f182a7438483.tar.bz2 nuttx-85d420dc3ad7d6fb9a675ac60f77f182a7438483.zip |
x86: Move address environment switch from the task switchers to the interrupt handler. That may save doing the action multiple times per interrupt
Diffstat (limited to 'nuttx/arch/x86')
-rw-r--r-- | nuttx/arch/x86/src/common/up_blocktask.c | 14 | ||||
-rw-r--r-- | nuttx/arch/x86/src/common/up_unblocktask.c | 14 | ||||
-rw-r--r-- | nuttx/arch/x86/src/qemu/qemu_handlers.c | 49 |
3 files changed, 41 insertions, 36 deletions
diff --git a/nuttx/arch/x86/src/common/up_blocktask.c b/nuttx/arch/x86/src/common/up_blocktask.c index 4e8687e60..680f3cfa6 100644 --- a/nuttx/arch/x86/src/common/up_blocktask.c +++ b/nuttx/arch/x86/src/common/up_blocktask.c @@ -136,19 +136,11 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state) rtcb = (struct tcb_s*)g_readytorun.head; - /* Then switch contexts */ + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ up_restorestate(rtcb->xcp.regs); - -#ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ - - (void)group_addrenv(rtcb); -#endif } /* Copy the user C context into the TCB at the (old) head of the diff --git a/nuttx/arch/x86/src/common/up_unblocktask.c b/nuttx/arch/x86/src/common/up_unblocktask.c index ddbe3e609..518a1f1d9 100644 --- a/nuttx/arch/x86/src/common/up_unblocktask.c +++ b/nuttx/arch/x86/src/common/up_unblocktask.c @@ -126,19 +126,11 @@ void up_unblock_task(struct tcb_s *tcb) rtcb = (struct tcb_s*)g_readytorun.head; - /* Then switch contexts */ + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ up_restorestate(rtcb->xcp.regs); - -#ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ - - (void)group_addrenv(rtcb); -#endif } /* We are not in an interrupt handler. Copy the user C context diff --git a/nuttx/arch/x86/src/qemu/qemu_handlers.c b/nuttx/arch/x86/src/qemu/qemu_handlers.c index 53b9ff582..ddccfa359 100644 --- a/nuttx/arch/x86/src/qemu/qemu_handlers.c +++ b/nuttx/arch/x86/src/qemu/qemu_handlers.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/x86/src/qemu/qemu_handlers.c * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012,2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -87,27 +87,49 @@ static void idt_outb(uint8_t val, uint16_t addr) #ifndef CONFIG_SUPPRESS_INTERRUPTS static uint32_t *common_handler(int irq, uint32_t *regs) { - uint32_t *savestate; - board_led_on(LED_INIRQ); - /* Nested interrupts are not supported in this implementation. If you want - * implemented nested interrupts, you would have to (1) change the way that - * current regs is handled and (2) the design associated with - * CONFIG_ARCH_INTERRUPTSTACK. - */ - /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. + * + * Nested interrupts are not supported. */ - savestate = (uint32_t*)current_regs; + DEBUGASSERT(current_regs == NULL); current_regs = regs; /* Deliver the IRQ */ irq_dispatch(irq, regs); +#if defined(CONFIG_ARCH_FPU) || defined(CONFIG_ARCH_ADDRENV) + /* Check for a context switch. If a context switch occurred, then + * current_regs will have a different value than it did on entry. If an + * interrupt level context switch has occurred, then restore the floating + * point state and the establish the correct address environment before + * returning from the interrupt. + */ + + if (regs != current_regs) + { +#ifdef CONFIG_ARCH_FPU + /* Restore floating point registers */ + + up_restorefpu((uint32_t*)current_regs); +#endif + +#ifdef CONFIG_ARCH_ADDRENV + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ + + (void)group_addrenv(rtcb); +#endif + } +#endif + /* If a context switch occurred while processing the interrupt then * current_regs may have change value. If we return any value different * from the input regs, then the lower level will know that a context @@ -116,12 +138,11 @@ static uint32_t *common_handler(int irq, uint32_t *regs) regs = (uint32_t*)current_regs; - /* Restore the previous value of current_regs. NULL would indicate that - * we are no longer in an interrupt handler. It will be non-NULL if we - * are returning from a nested interrupt. + /* Set current_regs to NULL to indicate that we are no longer in an + * interrupt handler. */ - current_regs = savestate; + current_regs = NULL; return regs; } #endif |