public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Josh Triplett <josh@joshtriplett.org>
To: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ben Hutchings <ben@decadent.org.uk>,
	x86@kernel.org, 584846@bugs.debian.org,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: Bug#584846: Detects only 64MB and fails to boot on Intel Green City board if e820 hooked by GRUB2
Date: Thu, 24 Jun 2010 12:01:08 -0700	[thread overview]
Message-ID: <20100624190107.GA15329@feather> (raw)
In-Reply-To: <4C23693A.9040107@zytor.com>

On Thu, Jun 24, 2010 at 07:18:34AM -0700, H. Peter Anvin wrote:
> On 06/24/2010 12:27 AM, Josh Triplett wrote:
> > The following patch fixes GRUB; with this patch, I can reserve memory
> > (such as with drivemap), boot 2.6.35-rc3 successfully, and it detects
> > all of my RAM.
> 
> Congratulations!  You have just committed the single most common BIOS
> implementation bug.  (Sorry for the sarcasm, but this seems to be a bug
> that almost everyone who tries to implement BIOS makes at one point or
> another... even the original IBM BIOS had it in at least one place.)

And a rather large number of sample interrupt code found on the web,
including the e820 hook from the version of gPXE/Etherboot that I used
as an example. :)  Given that I just tested against Linux, which very
carefully works around that particular BIOS bug, I didn't run into any
issue.

So, how high does GRUB's bug ("stc ; iret"/"clc ; iret") rank on the
list of common BIOS implementation bugs?

> You *must not* use "lret $2" to return to the caller, because the INT
> instruction will have cleared IF after pushing the registers to the
> stack.  You have to restore the original IF, which "lret $2" will not do.

The thought had crossed my mind to preserve the caller's flags, but I'd
ignored it because I'd figured that the interrupt handler could safely
trash the caller's flags as long as it set or cleared carry
appropriately.  I'd forgotten that IF lives there too. :)

> The best way to do this is to clobber the low byte of the flags register
> on the stack.  Since CF is bit 0, and the low byte only contains
> arithmetic flags anyway, you can simply overwrite the low byte with 0
> for CF=0 and 1 for CF=1.  This will zero SF, ZF, AF and PF as side
> effect, which is OK for almost all uses (including e820/e801/88.)
> 
> If you don't already have a pointer to the stack, you have to make one,
> since it is not possible in 16-bit mode to access the stack directly.
> One option is to replace each iret with a jump to the following common code:
> 
> carry_cf_iret:
> 	pushw	%bp
> 	movw	%sp, %bp
> 	setc	6(%bp)		/* Set CF on stack based on EFLAGS */
> 	popw	%bp
> 	iret

Nice.  Cleaner than the andw/orw solution I'd thought of using (and
actually written before dropping it in favor of "lret $2") to
specifically clear/set CF on the stack, since it doesn't require
separate exit paths for success and failure.

New patch:

--- mmap/i386/pc/mmap_helper.S	2010-03-26 23:04:14 +0000
+++ mmap/i386/pc/mmap_helper.S	2010-06-24 18:52:56 +0000
@@ -59,7 +59,7 @@
 	movw %bx, %dx
 	pop %ds
 	clc
-	iret
+	jmp LOCAL (iret_cf)
 
 LOCAL (h88):
 	popf
@@ -69,7 +69,7 @@
 	movw DS (LOCAL (kbin16mb)), %ax
 	pop %ds
 	clc
-	iret
+	jmp LOCAL (iret_cf)
 
 LOCAL (e820):
 	popf
@@ -101,12 +101,19 @@
 	mov $0x534d4150, %eax
 	pop %ds
 	clc
-	iret
+	jmp LOCAL (iret_cf)
 LOCAL (errexit):
 	mov $0x534d4150, %eax
 	pop %ds
+	xor %bx, %bx
 	stc
-	xor %bx, %bx
+	jmp LOCAL (iret_cf)
+
+LOCAL (iret_cf):
+	pushw %bp
+	movw %sp, %bp
+	setc 6(%bp)
+	popw %bp
 	iret
 
 VARIABLE(grub_machine_mmaphook_mmap_num)


- Josh Triplett

  reply	other threads:[~2010-06-24 19:01 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20100612060322.29053.94187.reportbug@feather>
2010-06-12 13:58 ` Bug#584846: Detects only 64MB and fails to boot on Intel Green City board if e820 hooked by GRUB2 Ben Hutchings
2010-06-12 18:28   ` H. Peter Anvin
2010-06-12 18:55     ` Josh Triplett
2010-06-12 20:41       ` H. Peter Anvin
2010-06-12 21:45         ` Josh Triplett
     [not found]         ` <20100612222634.GA1785@feather>
2010-06-12 23:01           ` H. Peter Anvin
2010-06-12 23:02           ` H. Peter Anvin
2010-06-13  0:07             ` Josh Triplett
2010-06-13  0:16               ` H. Peter Anvin
     [not found]                 ` <20100622052236.GA9130@feather>
2010-06-22  6:07                   ` H. Peter Anvin
2010-06-22 16:07                     ` Josh Triplett
2010-06-24  7:27                     ` Josh Triplett
2010-06-24 14:18                       ` H. Peter Anvin
2010-06-24 19:01                         ` Josh Triplett [this message]
2010-06-24 20:58                           ` H. Peter Anvin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100624190107.GA15329@feather \
    --to=josh@joshtriplett.org \
    --cc=584846@bugs.debian.org \
    --cc=ben@decadent.org.uk \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox