x86, oprom: ensure DF is always cleared
authorMathias Krause <minipli@googlemail.com>
Sun, 1 Apr 2012 09:32:09 +0000 (11:32 +0200)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Mon, 2 Apr 2012 17:50:22 +0000 (19:50 +0200)
The Option ROM might mess with the EFLAGS register and break assumptions
the C part of coreboot implicitly has, e.g. the state of the direction
flag.

Prevent Option ROMs from confusing coreboot by restoring the old EFLAGS
value after the Option ROMs has finished and always clear the direction
flag before calling the C part of the interrupt handler.

Change-Id: I84663be6681b17f95f48d93f0b730e443336b4a8
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Reviewed-on: http://review.coreboot.org/837
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
src/devices/oprom/x86_asm.S

index 488bfa6b912e625eae5b56cc4319a053e0e78839..56ebb3a885ec3789cafd88b4b5161954b11669bb 100644 (file)
@@ -75,35 +75,36 @@ __buffer = RELOCATED(.)
        .globl __realmode_call
 __realmode_call = RELOCATED(.)
        /* save all registers to the stack */
-       pushal
+       pusha
+       pushf
 
-       /* Move the protected mode stack to a safe place */
+       /* Move the protected mode stack pointer to a safe place */
        movl    %esp, __stack
-       movl    %esp, %ebp
+       movl    %esp, %ebp
 
-       /* This function is called with regparm=0 and we have
-        * to skip the 32 byte from pushal. Hence start at 36.
+       /* This function is called with regparm=0 and we have to
+        * skip the 36 byte from pushf+pusha. Hence start at 40.
         */
 
        /* entry point */
-       movl    36(%ebp), %eax
+       movl    40(%ebp), %eax
        mov     %ax, __lcall_instr + 1
        andl    $0xffff0000, %eax
        shrl    $4, %eax
        mov     %ax, __lcall_instr + 3
 
        /* initial register values */
-       movl    40(%ebp), %eax
-       movl    %eax, __registers +  0 /* eax */
        movl    44(%ebp), %eax
-       movl    %eax, __registers +  4 /* ebx */
+       movl    %eax, __registers +  0 /* eax */
        movl    48(%ebp), %eax
-       movl    %eax, __registers +  8 /* ecx */
+       movl    %eax, __registers +  4 /* ebx */
        movl    52(%ebp), %eax
-       movl    %eax, __registers + 12 /* edx */
+       movl    %eax, __registers +  8 /* ecx */
        movl    56(%ebp), %eax
-       movl    %eax, __registers + 16 /* esi */
+       movl    %eax, __registers + 12 /* edx */
        movl    60(%ebp), %eax
+       movl    %eax, __registers + 16 /* esi */
+       movl    64(%ebp), %eax
        movl    %eax, __registers + 20 /* edi */
 
        /* Activate the right segment descriptor real mode. */
@@ -193,41 +194,45 @@ __lcall_instr = RELOCATED(.)
        /* restore proper idt */
        lidt    idtarg
 
-       /* and exit */
+       /* restore stack pointer, eflags and register values */
        movl    __stack, %esp
-       popal
+       popf
+       popa
 
+       /* and exit */
        // TODO return AX from OPROM call
        ret
 
        .globl __realmode_interrupt
 __realmode_interrupt = RELOCATED(.)
        /* save all registers to the stack */
-       pushal
-       /* save the stack */
+       pusha
+       pushf
+
+       /* save the stack pointer */
        movl    %esp, __stack
-       movl    %esp, %ebp
+       movl    %esp, %ebp
 
-       /* This function is called with regparm=0 and we have
-        * to skip the 32 byte from pushal. Hence start at 36.
+       /* This function is called with regparm=0 and we have to
+        * skip the 36 byte from pushf+pusha. Hence start at 40.
         */
 
        /* prepare interrupt calling code */
-       movl    36(%ebp), %eax
+       movl    40(%ebp), %eax
        movb    %al, __intXX_instr + 1 /* intno */
 
        /* initial register values */
-       movl    40(%ebp), %eax
-       movl    %eax, __registers +  0 /* eax */
        movl    44(%ebp), %eax
-       movl    %eax, __registers +  4 /* ebx */
+       movl    %eax, __registers +  0 /* eax */
        movl    48(%ebp), %eax
-       movl    %eax, __registers +  8 /* ecx */
+       movl    %eax, __registers +  4 /* ebx */
        movl    52(%ebp), %eax
-       movl    %eax, __registers + 12 /* edx */
+       movl    %eax, __registers +  8 /* ecx */
        movl    56(%ebp), %eax
-       movl    %eax, __registers + 16 /* esi */
+       movl    %eax, __registers + 12 /* edx */
        movl    60(%ebp), %eax
+       movl    %eax, __registers + 16 /* esi */
+       movl    64(%ebp), %eax
        movl    %eax, __registers + 20 /* edi */
 
        /*  This configures CS properly for real mode. */
@@ -309,9 +314,10 @@ __intXX_instr = RELOCATED(.)
        /* restore coreboot's 32-bit IDT */
        lidt    idtarg
 
-       /* Exit */
+       /* restore stack pointer, eflags and register values and exit */
        movl    __stack, %esp
-       popal
+       popf
+       popa
        ret
 
 /* This is the 16-bit interrupt entry point called by the IDT stub code.
@@ -327,6 +333,9 @@ __interrupt_handler_16bit = RELOCATED(.)
        push    %fs
        push    %gs
 
+       /* Clear DF to not break ABI assumptions */
+       cld
+
        /* Clean up the interrupt number. We could have done this in the stub,
         * but it would have cost 2 more bytes per stub entry.
         */