mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Troy Moure <twmoure@szypr.net>
To: Krzysztof Oledzki <olel@ans.pl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Troy Moure <twmoure@szypr.net>, Greg KH <gregkh@suse.de>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	stable@kernel.org, lwn@lwn.net,
	Ian Lance Taylor <iant@google.com>
Subject: Re: Linux 2.6.27.27
Date: Wed, 22 Jul 2009 11:24:04 +0100 (BST)	[thread overview]
Message-ID: <alpine.LFD.2.00.0907221123480.11527@troy-laptop> (raw)
In-Reply-To: <alpine.LNX.1.10.0907221022380.26357@bizon.gios.gov.pl>



On Wed, 22 Jul 2009, Krzysztof Oledzki wrote:
> > 
> > Indeed, this simple change is enough to make my kernel bootable. However,
> > there is still something wrong. My console is now 80x30 instead of 128x48:
> > 
> > -Console: switching to colour frame buffer device 128x48
> > +Console: switching to colour frame buffer device 80x30
> > 
> > So, it looks like the loop may be still miscompiled.
> > 

Yes.  I took a look at the -fixed binary you sent out.  edid_checksum() is 
now compiled to this (I added some notes on the side):

ffffffff803b37ed: <edid_checksum>:
       53                      push   %rbx
       48 89 fb                mov    %rdi,%rbx		   %ebx = edid

	[... Calls to check_edid and fix_edid ... ]

       31 c9                   xor    %ecx,%ecx		   csum = 0
       31 f6                   xor    %esi,%esi		   all_null = 0
       31 d2                   xor    %edx,%edx		   i = 0
 L:    0f b6 04 1a             movzbl (%rdx,%rbx,1),%eax   %eax = *(i + edid)
       48 ff c2                inc    %rdx		   i++
       01 c1                   add    %eax,%ecx		   csum += %eax
       09 c6                   or     %eax,%esi		   all_null |= %eax
       48 81 fa 80 00 00 00    cmp    $0x80,%rdx
       75 ec                   jne    L			   if i != 80 goto L
       85 c9                   test   %ecx,%ecx
       0f 94 c0                sete   %al		%al == (csum == 0)
       85 f6                   test   %esi,%esi
       5b                      pop    %rbx
       0f 95 c2                setne  %dl		%dl == (all_null == 0)
       21 d0                   and    %edx,%eax
       0f b6 c0                movzbl %al,%eax		%eax == (%al && %dl)
       c3                      retq			return %eax

The problem is that csum is stored in %ecx (a 32-bit register) at all 
times and is never truncated to a byte.  In other words, the compiler is 
treating csum like it's an 'int', not an 'unsigned char'.

> Here is a diff between a good and a bad kernel:
> 
> -edid_checksum debug: csum=0, all_null=255, err=1
> -edid_checksum debug: csum=0, all_null=255, err=1
> -Console: switching to colour frame buffer device 128x48
> +edid_checksum debug: csum=6400, all_null=255, err=0
> +Console: switching to colour frame buffer device 80x30
> 
> In the good one the function is called twice and it returns err=1 (==OK). In
> the bad kernel it returns 0 because csum!=0x00 (==6400).

That makes sense - since csum is being treated like an 'int', it never 
wraps, so it just ends up holding the total sum of all the bytes, which 
apparently is 6400.  Notice that 6400 % 256 == 0, so if it *had* wrapped, 
it would have ended up being 0, as expected.

One "fix" might be to just make 'csum' an 'int' (since that's what the 
compiler seems to think anyway :p) and do the wrapping by hand (patch 
below, if you want to try this).

However, I wouldn't be surprised if other kernel functions are also being 
miscompiled.  It seems to me that any function that does arithmetic on 
'unsigned char's and depends on the wrapping behaviour could potentially 
be broken... 

Best regards,

	Troy

diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 5c1a2c0..6802b4c 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -256,8 +256,8 @@ static void fix_edid(unsigned char *edid, int fix)
 
 static int edid_checksum(unsigned char *edid)
 {
-	unsigned char i, csum = 0, all_null = 0;
-	int err = 0, fix = check_edid(edid);
+	unsigned char all_null = 0;
+	int i, csum = 0, err = 0, fix = check_edid(edid);
 
 	if (fix)
 		fix_edid(edid, fix);
@@ -267,7 +267,7 @@ static int edid_checksum(unsigned char *edid)
 		all_null |= edid[i];
 	}
 
-	if (csum == 0x00 && all_null) {
+	if ((csum & 0xff) == 0x00 && all_null) {
 		/* checksum passed, everything's good */
 		err = 1;
 	}

  parent reply	other threads:[~2009-07-22 10:23 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-20  4:06 Greg KH
2009-07-20  4:07 ` Greg KH
2009-07-20 11:51 ` Krzysztof Oledzki
2009-07-20 15:10   ` Greg KH
2009-07-20 16:01     ` Linus Torvalds
2009-07-20 21:45       ` Krzysztof Oledzki
2009-07-20 22:08         ` Linus Torvalds
2009-07-20 23:47           ` Marc Dionne
2009-07-20 23:56             ` Linus Torvalds
2009-07-21  0:37               ` Marc Dionne
2009-07-21  1:01                 ` Linus Torvalds
2009-07-21  6:40                   ` Krzysztof Oledzki
2009-07-21  1:05                 ` Linus Torvalds
2009-07-21  2:38                   ` Marc Dionne
2009-07-21  6:33           ` Krzysztof Oledzki
2009-07-21 10:16             ` Krzysztof Oledzki
2009-07-21 16:11               ` Linus Torvalds
2009-07-21 19:15                 ` Linus Torvalds
2009-07-21 21:34                   ` Troy Moure
2009-07-22  0:53                     ` Linus Torvalds
2009-07-22  1:07                       ` Linus Torvalds
2009-07-22  6:16                         ` Troy Moure
2009-07-22 15:58                           ` Linus Torvalds
2009-07-22  1:16                       ` Linus Torvalds
2009-07-22  8:12                         ` Krzysztof Oledzki
2009-07-22  8:32                           ` Krzysztof Oledzki
2009-07-22  9:55                             ` Krzysztof Oledzki
2009-07-22 10:44                               ` Krzysztof Oledzki
2009-07-22  9:58                             ` Jens Rosenboom
2009-07-22 10:27                               ` Troy Moure
2009-07-22 10:54                               ` Krzysztof Oledzki
2009-07-22 10:24                             ` Troy Moure [this message]
2009-07-22 10:33                             ` Dick Streefland
2009-07-22 13:48                         ` Krzysztof Oledzki
2009-07-22 15:48                           ` Linus Torvalds
2009-07-29 14:57                             ` Pavel Machek
2009-07-29 15:59                               ` Linus Torvalds
2009-07-22 11:49                       ` Krzysztof Oledzki
2009-07-22 13:27                         ` Henrique de Moraes Holschuh
2009-07-22 13:45                         ` Krzysztof Oledzki
2009-07-22 15:36                         ` Ian Lance Taylor
2009-07-23 17:33     ` Krzysztof Olędzki
2009-07-24 21:13       ` Greg KH

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=alpine.LFD.2.00.0907221123480.11527@troy-laptop \
    --to=twmoure@szypr.net \
    --cc=akpm@linux-foundation.org \
    --cc=gregkh@suse.de \
    --cc=iant@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lwn@lwn.net \
    --cc=olel@ans.pl \
    --cc=stable@kernel.org \
    --cc=torvalds@linux-foundation.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

all inboxes | Powered by JetHome®