File: qemu_fullcontextrestore.S - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

/**************************************************************************
 * arch/x86/src/qemu/qemu_fullcontextrestore.S
 *
 *   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.
 *
 **************************************************************************/

/**************************************************************************
 * Conditional Compilation Options
 **************************************************************************/

/**************************************************************************
 * Included Files
 **************************************************************************/

#include <nuttx/config.h>
#include <arch/irq.h>
#include "up_internal.h"

    .file   "qemu_fullcontextrestore.S"

/**************************************************************************
 * Pre-processor Definitions
 **************************************************************************/

/**************************************************************************
 * Global Variables
 **************************************************************************/

/****************************************************************************
 * Macros
 ****************************************************************************/

/* Trace macros, use like trace 'i' to print char to serial port. */

    .macro  chout, addr, ch
#ifdef CONFIG_DEBUG
    mov     $\addr, %dx
    mov     $\ch, %al
    out     %al, %dx
#endif
    .endm

    .macro  trace, ch
#ifdef CONFIG_DEBUG
    push    %eax
    push    %edx
    chout   0x3f8, \ch
    pop     %edx
    pop     %eax
#endif
    .endm

/**************************************************************************
 * Public Functions
 **************************************************************************/

    .text

/**************************************************************************
 * Name: up_fullcontextrestore
 *
 * Full C prototype:
 *  void up_fullcontextrestore(uint32_t *regs) __attribute__ ((noreturn));
 *
 **************************************************************************/

    .globl  up_fullcontextrestore
    .type   up_fullcontextrestore, @function
up_fullcontextrestore:
    /* Fetch the pointer to the register save array in EAX. */

    movl    4(%esp), %eax

    /* Disable interrupts now (the correct EFLAGS will be restored before we
     * return
     */

    cli

    /* 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.
     *
     *
     *                          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
    push    %ebx
    movl    (4*REG_EIP)(%eax), %ebx
    push    %ebx

    /* Save the value of EAX on the stack too */

    movl    (4*REG_EAX)(%eax), %ebx
    push    %ebx

    /* Now restore the remaining registers */

    movl    (4*REG_ESI)(%eax), %esi
    movl    (4*REG_EDI)(%eax), %edi
    movl    (4*REG_EBP)(%eax), %ebp
    movl    (4*REG_EBX)(%eax), %ebx
    movl    (4*REG_EDX)(%eax), %edx
    movl    (4*REG_ECX)(%eax), %ecx

    /* Restore the data segment register.  I think there is an issue that will
     * need to be address here at some time:  If the register save area is in
     * one data segment and the stack is in another, then the above would not
     * work (and, conversely, if they are in the same data segment, the
     * following is unnecessary and redundant).
     */

    mov     (4*REG_DS)(%eax), %ds

    /* Restore the correct value of EAX and then return */

    popl    %eax
    iret
    .size up_fullcontextrestore, . - up_fullcontextrestore
    .end