From f44205b9ea928c3cdefb6848e7f20fe11d112522 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sat, 11 Apr 2009 18:30:22 -0700 Subject: [PATCH] [pcbios] Don't use "lret $2" to return from an interrupt Using "lret $2" to return from an interrupt causes interrupts to be disabled in the calling program, since the INT instruction will have disabled interrupts. Instead, patch CF on the stack and use iret to return. Interestingly, the original PC BIOS had this bug in at least one place. Signed-off-by: H. Peter Anvin Signed-off-by: Michael Brown --- src/arch/i386/firmware/pcbios/e820mangler.S | 27 ++++++++++++++------- src/arch/i386/firmware/pcbios/fakee820.c | 5 ++-- src/arch/i386/interface/pxe/pxe_entry.S | 7 ++++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/arch/i386/firmware/pcbios/e820mangler.S b/src/arch/i386/firmware/pcbios/e820mangler.S index 4ba3fb141..decb08356 100644 --- a/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/src/arch/i386/firmware/pcbios/e820mangler.S @@ -489,6 +489,18 @@ get_mangled_e820: ret .size get_mangled_e820, . - get_mangled_e820 +/**************************************************************************** + * Set/clear CF on the stack as appropriate, assumes stack is as it should + * be immediately before IRET + **************************************************************************** + */ +patch_cf: + pushw %bp + movw %sp, %bp + setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */ + popw %bp + ret + /**************************************************************************** * INT 15,e820 handler **************************************************************************** @@ -500,7 +512,8 @@ int15_e820: popw %ds call get_mangled_e820 popw %ds - lret $2 + call patch_cf + iret .size int15_e820, . - int15_e820 /**************************************************************************** @@ -512,7 +525,7 @@ int15_e801: /* Call previous handler */ pushfw lcall *%cs:int15_vector - pushfw + call patch_cf /* Edit result */ pushw %ds pushw %cs:rm_ds @@ -524,9 +537,7 @@ int15_e801: xchgw %ax, %cx xchgw %bx, %dx popw %ds - /* Restore flags returned by previous handler and return */ - popfw - lret $2 + iret .size int15_e801, . - int15_e801 /**************************************************************************** @@ -538,16 +549,14 @@ int15_88: /* Call previous handler */ pushfw lcall *%cs:int15_vector - pushfw + call patch_cf /* Edit result */ pushw %ds pushw %cs:rm_ds popw %ds call patch_1m popw %ds - /* Restore flags returned by previous handler and return */ - popfw - lret $2 + iret .size int15_88, . - int15_88 /**************************************************************************** diff --git a/src/arch/i386/firmware/pcbios/fakee820.c b/src/arch/i386/firmware/pcbios/fakee820.c index e171edfd6..552bf41d2 100644 --- a/src/arch/i386/firmware/pcbios/fakee820.c +++ b/src/arch/i386/firmware/pcbios/fakee820.c @@ -63,6 +63,8 @@ void fake_e820 ( void ) { "cmpl $0x534d4150, %%edx\n\t" "jne 99f\n\t" "pushaw\n\t" + "movw %%sp, %%bp\n\t" + "andb $~0x01, 22(%%bp)\n\t" /* Clear return CF */ "leaw e820map(%%bx), %%si\n\t" "cs rep movsb\n\t" "popaw\n\t" @@ -73,8 +75,7 @@ void fake_e820 ( void ) { "xorl %%ebx,%%ebx\n\t" "\n1:\n\t" "popfw\n\t" - "clc\n\t" - "lret $2\n\t" + "iret\n\t" "\n99:\n\t" "popfw\n\t" "ljmp *%%cs:real_int15_vector\n\t" ) diff --git a/src/arch/i386/interface/pxe/pxe_entry.S b/src/arch/i386/interface/pxe/pxe_entry.S index 22ef41814..0e8c8e2d6 100644 --- a/src/arch/i386/interface/pxe/pxe_entry.S +++ b/src/arch/i386/interface/pxe/pxe_entry.S @@ -199,9 +199,12 @@ pxe_int_1a: shll $4, %edx addl $pxenv, %edx movw $0x564e, %ax + pushw %bp + movw %sp, %bp + andb $~0x01, 8(%bp) /* Clear CF on return */ + popw %bp popfw - clc - lret $2 + iret 1: /* INT 1A,other - pass through */ popfw ljmp *%cs:pxe_int_1a_vector