summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-17 22:33:49 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-17 22:33:49 +0000
commitfd5f3bf64dd35754e44942f99352d70fc71ae73b (patch)
treea6c358055f5af4656b1e85849c75a9279323c25a
parentc986d73e782c6b7f59c8d79185d845f16d5f6034 (diff)
downloadnuttx-fd5f3bf64dd35754e44942f99352d70fc71ae73b.tar.gz
nuttx-fd5f3bf64dd35754e44942f99352d70fc71ae73b.tar.bz2
nuttx-fd5f3bf64dd35754e44942f99352d70fc71ae73b.zip
Fix QEMU timer interrupt handler
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3389 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog6
-rw-r--r--nuttx/Documentation/NuttX.html6
-rwxr-xr-xnuttx/arch/x86/include/i486/irq.h117
-rw-r--r--nuttx/arch/x86/src/common/up_internal.h2
-rw-r--r--nuttx/arch/x86/src/i486/up_initialstate.c5
-rw-r--r--nuttx/arch/x86/src/i486/up_savestate.c113
-rwxr-xr-xnuttx/arch/x86/src/qemu/Make.defs2
-rw-r--r--nuttx/arch/x86/src/qemu/qemu_fullcontextrestore.S34
-rw-r--r--nuttx/arch/x86/src/qemu/qemu_saveusercontext.S21
-rwxr-xr-xnuttx/arch/x86/src/qemu/qemu_vectors.S3
10 files changed, 241 insertions, 68 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 1b9b774b7..205904158 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -1574,4 +1574,8 @@
LPC17xx with some caveats as described in the TODO list under
LPC17xx.
* arch/x86/include/i486/irq.h -- Fix irqrestore() macro... it was not
- correctly re-enabling interrupts. \ No newline at end of file
+ correctly re-enabling interrupts.
+ * arch/x86/src - Fix numerous problems with i486/QEMU context
+ switching. Basically, the logic was missing the cases to handle
+ the differing stack frames when a priority change occurs and when
+ no priority change occurs.
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index 1ac727263..59c8686f5 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
- <p>Last Updated: March 16, 2011</p>
+ <p>Last Updated: March 17, 2011</p>
</td>
</tr>
</table>
@@ -2202,6 +2202,10 @@ nuttx-5.20 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
LPC17xx.
* arch/x86/include/i486/irq.h -- Fix irqrestore() macro... it was not
correctly re-enabling interrupts.
+ * arch/x86/src - Fix numerous problems with i486/QEMU context
+ switching. Basically, the logic was missing the cases to handle
+ the differing stack frames when a priority change occurs and when
+ no priority change occurs.
apps-5.20 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
diff --git a/nuttx/arch/x86/include/i486/irq.h b/nuttx/arch/x86/include/i486/irq.h
index 9b1162671..437352199 100755
--- a/nuttx/arch/x86/include/i486/irq.h
+++ b/nuttx/arch/x86/include/i486/irq.h
@@ -56,55 +56,55 @@
/* ISR and IRQ numbers */
-#define ISR0 0
-#define ISR1 1
-#define ISR2 2
-#define ISR3 3
-#define ISR4 4
-#define ISR5 5
-#define ISR6 6
-#define ISR7 7
-#define ISR8 8
-#define ISR9 9
-#define ISR10 10
-#define ISR11 11
-#define ISR12 12
-#define ISR13 13
-#define ISR14 14
-#define ISR15 15
-#define ISR16 16
-#define ISR17 17
-#define ISR18 18
-#define ISR19 19
-#define ISR20 20
-#define ISR21 21
-#define ISR22 22
-#define ISR23 23
-#define ISR24 24
-#define ISR25 25
-#define ISR26 26
-#define ISR27 27
-#define ISR28 28
-#define ISR29 29
-#define ISR30 30
-#define ISR31 31
-
-#define IRQ0 32
-#define IRQ1 33
-#define IRQ2 34
-#define IRQ3 35
-#define IRQ4 36
-#define IRQ5 37
-#define IRQ6 38
-#define IRQ7 39
-#define IRQ8 40
-#define IRQ9 41
-#define IRQ10 42
-#define IRQ11 43
-#define IRQ12 44
-#define IRQ13 45
-#define IRQ14 46
-#define IRQ15 47
+#define ISR0 0 /* Division by zero exception */
+#define ISR1 1 /* Debug exception */
+#define ISR2 2 /* Non maskable interrupt */
+#define ISR3 3 /* Breakpoint exception */
+#define ISR4 4 /* 'Into detected overflow' */
+#define ISR5 5 /* Out of bounds exception */
+#define ISR6 6 /* Invalid opcode exception */
+#define ISR7 7 /* No coprocessor exception */
+#define ISR8 8 /* Double fault (pushes an error code) */
+#define ISR9 9 /* Coprocessor segment overrun */
+#define ISR10 10 /* Bad TSS (pushes an error code) */
+#define ISR11 11 /* Segment not present (pushes an error code) */
+#define ISR12 12 /* Stack fault (pushes an error code) */
+#define ISR13 13 /* General protection fault (pushes an error code) */
+#define ISR14 14 /* Page fault (pushes an error code) */
+#define ISR15 15 /* Unknown interrupt exception */
+#define ISR16 16 /* Coprocessor fault */
+#define ISR17 17 /* Alignment check exception */
+#define ISR18 18 /* Machine check exception */
+#define ISR19 19 /* Reserved */
+#define ISR20 20 /* Reserved */
+#define ISR21 21 /* Reserved */
+#define ISR22 22 /* Reserved */
+#define ISR23 23 /* Reserved */
+#define ISR24 24 /* Reserved */
+#define ISR25 25 /* Reserved */
+#define ISR26 26 /* Reserved */
+#define ISR27 27 /* Reserved */
+#define ISR28 28 /* Reserved */
+#define ISR29 29 /* Reserved */
+#define ISR30 30 /* Reserved */
+#define ISR31 31 /* Reserved */
+
+#define IRQ0 32 /* System timer (cannot be changed) */
+#define IRQ1 33 /* Keyboard controller (cannot be changed) */
+#define IRQ2 34 /* Cascaded signals from IRQs 8–15 */
+#define IRQ3 35 /* Serial port controller for COM2/4 */
+#define IRQ4 36 /* serial port controller for COM1/3 */
+#define IRQ5 37 /* LPT port 2 or sound card */
+#define IRQ6 38 /* Floppy disk controller */
+#define IRQ7 39 /* LPT port 1 or sound card */
+#define IRQ8 40 /* Real time clock (RTC) */
+#define IRQ9 41 /* Open interrupt/available or SCSI host adapter */
+#define IRQ10 42 /* Open interrupt/available or SCSI or NIC */
+#define IRQ11 43 /* Open interrupt/available or SCSI or NIC */
+#define IRQ12 44 /* Mouse on PS/2 connector */
+#define IRQ13 45 /* Math coprocessor */
+#define IRQ14 46 /* Primary ATA channel */
+#define IRQ15 47 /* Secondary ATA channel */
#define NR_IRQS 48
@@ -138,6 +138,25 @@
#define XCPTCONTEXT_REGS (16)
#define XCPTCONTEXT_SIZE (4 * XCPTCONTEXT_REGS)
+/* Some special landmarks in the stack frame:
+ *
+ * TOP_PUSHA - The offset (in 32-bit words) from the beginning of the
+ * save area on the stack to the value that should be in REG_ESP.
+ * BOTTOM_PUSHA - The offset (in 32-bit words) from the stack position before
+ * the interrupt occurred to the value that should be in REG_ESP.
+ * save area on the stack to the value that should be in REG_ESP.
+ * OFFSET_PRIO - The offset from the value of REG_ESP to the value of the
+ * stack pointer before the interrupt occurred (assuming that a priority
+ * change occurred.
+ * OFFSET_PRIO - The offset from the value of REG_ESP to the value of the
+ * stack pointer before the interrupt occurred (assuming that NO priority
+ * change occurred.
+ */
+
+#define TOP_PUSHA REG_IRQNO
+#define BOTTOM_PRIO (XCPTCONTEXT_REGS-REG_IRQNO)
+#define BOTTOM_NOPRIO (REG_SP-REG_IRQNO)
+
/****************************************************************************
* Public Types
****************************************************************************/
diff --git a/nuttx/arch/x86/src/common/up_internal.h b/nuttx/arch/x86/src/common/up_internal.h
index d8e25329e..51f79beb3 100644
--- a/nuttx/arch/x86/src/common/up_internal.h
+++ b/nuttx/arch/x86/src/common/up_internal.h
@@ -80,7 +80,6 @@
* referenced is passed to get the state from the TCB.
*/
-#define up_savestate(regs) up_copystate(regs, current_regs)
#define up_restorestate(regs) (current_regs = regs)
/****************************************************************************
@@ -150,6 +149,7 @@ extern uint32_t _ebss; /* End+1 of .bss */
extern void up_boot(void);
extern void up_copystate(uint32_t *dest, uint32_t *src);
+extern void up_savestate(uint32_t *regs);
extern void up_decodeirq(uint32_t *regs);
extern void up_irqinitialize(void);
#ifdef CONFIG_ARCH_DMA
diff --git a/nuttx/arch/x86/src/i486/up_initialstate.c b/nuttx/arch/x86/src/i486/up_initialstate.c
index 1a13b8991..9ca40feb3 100644
--- a/nuttx/arch/x86/src/i486/up_initialstate.c
+++ b/nuttx/arch/x86/src/i486/up_initialstate.c
@@ -85,7 +85,10 @@ void up_initial_state(_TCB *tcb)
memset(xcp, 0, sizeof(struct xcptcontext));
- /* Save the initial stack pointer */
+ /* Save the initial stack pointer... the value of the stackpointer before
+ * the "interrupt occurs." We don't know the value of REG_ESP yet..
+ * that depends on if a priority change is required or not.
+ */
xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr;
diff --git a/nuttx/arch/x86/src/i486/up_savestate.c b/nuttx/arch/x86/src/i486/up_savestate.c
new file mode 100644
index 000000000..d5f97fa85
--- /dev/null
+++ b/nuttx/arch/x86/src/i486/up_savestate.c
@@ -0,0 +1,113 @@
+/****************************************************************************
+ * arch/x86/src/i486/up_savestate.c
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+
+#include <arch/arch.h>
+#include <arch/irq.h>
+
+#include "up_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+/****************************************************************************
+ * Name: up_savestate
+ *
+ * Description:
+ * This function saves the interrupt level context information in the
+ * TCB. This would just be a up_copystate but we have to handle one
+ * special case. In the case where the privilige level changes, the
+ * value of sp and ss will not be saved on stack by the interrupt handler.
+ * So, in that case, we will have to fudge those values here.
+ *
+ ****************************************************************************/
+
+void up_savestate(uint32_t *regs)
+{
+ uint8_t cpl;
+ uint8_t rpl;
+
+ /* First, just copy all of the registers */
+
+ up_copystate(regs, current_regs);
+
+ /* The RES_SP and REG_SS values will not be saved by the interrupt handling
+ * logic if there is no change in privilege level. In that case, we will
+ * have to "fudge" those values here. For now, just overwrite the REG_SP
+ * and REG_SS values with what we believe to be correct. Obviously, this
+ * will have to change in the future to support multi-segment operation.
+ *
+ * Check for a change in privilege level.
+ */
+
+ rpl = regs[REG_CS] & 3;
+ cpl = up_getcs() & 3;
+ DEBUGASSERT(rpl >= cpl);
+
+ if (rpl == cpl)
+ {
+ /* No priority change, SP and SS are not present in the stack frame.
+ *
+ * The value saved in the REG_ESP will be the stackpointer value prior to
+ * the execution of the PUSHA. It will point at REG_IRQNO.
+ */
+
+ regs[REG_SP] = current_regs[REG_ESP] + 4*BOTTOM_NOPRIO;
+ regs[REG_SS] = up_getss();
+ }
+ else
+ {
+ DEBUGASSERT(regs[REG_SP] == current_regs[REG_ESP] + 4*BOTTOM_PRIO);
+ }
+}
diff --git a/nuttx/arch/x86/src/qemu/Make.defs b/nuttx/arch/x86/src/qemu/Make.defs
index 3177f3db4..ee239910b 100755
--- a/nuttx/arch/x86/src/qemu/Make.defs
+++ b/nuttx/arch/x86/src/qemu/Make.defs
@@ -45,7 +45,7 @@ CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
up_initialize.c up_initialstate.c up_interruptcontext.c up_irq.c \
up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c up_regdump.c \
up_releasepending.c up_releasestack.c up_reprioritizertr.c \
- up_sigdeliver.c up_schedulesigaction.c up_unblocktask.c \
+ up_savestate.c up_sigdeliver.c up_schedulesigaction.c up_unblocktask.c \
up_usestack.c
# Required QEMU files
diff --git a/nuttx/arch/x86/src/qemu/qemu_fullcontextrestore.S b/nuttx/arch/x86/src/qemu/qemu_fullcontextrestore.S
index 9a1e1e64e..ded55a147 100644
--- a/nuttx/arch/x86/src/qemu/qemu_fullcontextrestore.S
+++ b/nuttx/arch/x86/src/qemu/qemu_fullcontextrestore.S
@@ -106,26 +106,43 @@ up_fullcontextrestore:
cli
- /* We now have everything we need from the old stack. Now get the new
- * stack pointer.
+ /* Get the value of the stack pointer as it was when the pusha was
+ * executed the interrupt handler.
*/
movl (4*REG_SP)(%eax), %esp
/* Create an interrupt stack frame for the final iret.
*
- * SP Before ->
- * SS
- * ESP
- * EFLAGS
- * CS
- * SP After -> EIP
+ *
+ * IRET STACK
+ * PRIO CHANGE No PRIO CHANGE
+ * --------------- -----------------
+ * SP Before ->
+ * SS EFLAGS
+ * ESP CS
+ * EFLAGS -> EIP
+ * CS ...
+ * SP After -> EIP
+ *
+ * So, first check for a priority change.
*/
+ movl (4*REG_CS)(%eax), %edx
+ andl $3, %edx
+ mov %cs, %ebx
+ andl $3, %ebx
+ cmpb %bl, %dl
+ je .Lnopriochange
+
+ /* The priority will change... put SS and ESP on the stack */
+
mov (4*REG_SS)(%eax), %ebx
push %ebx
movl (4*REG_SP)(%eax), %ebx
push %ebx
+
+.Lnopriochange:
movl (4*REG_EFLAGS)(%eax), %ebx
push %ebx
mov (4*REG_CS)(%eax), %ebx
@@ -162,4 +179,3 @@ up_fullcontextrestore:
iret
.size up_fullcontextrestore, . - up_fullcontextrestore
.end
-
diff --git a/nuttx/arch/x86/src/qemu/qemu_saveusercontext.S b/nuttx/arch/x86/src/qemu/qemu_saveusercontext.S
index e9a98b331..427c3bd5d 100644
--- a/nuttx/arch/x86/src/qemu/qemu_saveusercontext.S
+++ b/nuttx/arch/x86/src/qemu/qemu_saveusercontext.S
@@ -126,11 +126,26 @@ up_saveusercontext:
mov %cs, (4*REG_CS)(%eax)
mov %ds, (4*REG_DS)(%eax)
- /* Save the value of SP as will be after we return (don't bother to save
- * REG_ESP).
+ /* Save the value of SP as will be at the time of the IRET that will
+ * appear to be the return from this function.
+ *
+ *
+ * CURRENT STACK IRET STACK
+ * PRIO CHANGE No PRIO CHANGE
+ * --------------- --------------- -----------------
+ * EIP
+ * CS ...
+ * EFLAGS EIP
+ * -> ESP CS
+ * ESP->Return address SS EFLAGS
+ * Argument Argument Argument
+ *
+ * NOTE: We don't yet know the value for REG_ESP! That depends upon
+ * if a priority change occurs or not.
*/
- leal 4(%esp), %ecx
+
+ leal -4(%esp), %ecx
movl %ecx, (4*REG_SP)(%eax)
/* Fetch the PC from the stack and save it in the save block */
diff --git a/nuttx/arch/x86/src/qemu/qemu_vectors.S b/nuttx/arch/x86/src/qemu/qemu_vectors.S
index 87412c21b..d6e17e57b 100755
--- a/nuttx/arch/x86/src/qemu/qemu_vectors.S
+++ b/nuttx/arch/x86/src/qemu/qemu_vectors.S
@@ -266,7 +266,6 @@ irq_common:
popa /* Pops edi,esi,ebp... */
add $8, %esp /* Cleans up the pushed error code and pushed ISR number */
- sti
- iret /* Pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP */
+ iret /* Pops 3-5 things at once: CS, EIP, EFLAGS (and maybe SS and ESP) */
.size irq_common, . - irq_common
.end