Bug #141

GRUB payload hangs in HP Elitebooks

Added by Iru Cai about 3 years ago. Updated 7 months ago.

Status:NewStart date:09/19/2017
Priority:NormalDue date:
Assignee:Iru Cai% Done:

0%

Category:-
Target version:-

Description

There may be some problem when initializing the keyboard controller, but SeaBIOS payload works fine. Using GRUB payload directly or chainload GRUB payload with SeaBIOS will both hang the system.

I modified GRUB and find it hangs in set_scancodes(void), when calling the first write_mode. After grub_outb (mode, KEYBOARD_REG_DATA);, the keyboard_controller_wait_until_ready() function goes to an infinite loop.

write_mode (int mode)
{
  unsigned i;
  for (i = 0; i < GRUB_AT_TRIES; i++)
    {
      grub_uint8_t ack;
      keyboard_controller_wait_until_ready ();
      grub_outb (0xf0, KEYBOARD_REG_DATA);
      keyboard_controller_wait_until_ready ();
      grub_outb (mode, KEYBOARD_REG_DATA);
      keyboard_controller_wait_until_ready ();
      ack = wait_ack ();
      if (ack == GRUB_AT_NACK)
        continue;
      if (ack == GRUB_AT_ACK)
        break;
      return 0;
    }

  return (i != GRUB_AT_TRIES);
}

seabios.log Magnifier (31.5 KB) Iru Cai, 05/15/2020 02:53 PM

History

#1 Updated by Paul Menzel 7 months ago

I guess Linux works fine too. What about libpayload based payloads?

Can you please attach the debug logs of SeaBIOS (yes not GRUB) with debug log level.

#2 Updated by Iru Cai 7 months ago

I've just made a SeaBIOS log (verbosity 7).

#3 Updated by Paul Menzel 7 months ago

Thank you. SeaBIOS does:

$ grep 7fee4000 seabios.log
/7fee4000\ Start thread
|7fee4000| i8042_flush
|7fee4000| i8042_command cmd=ad
|7fee4000| i8042_wait_write
|7fee4000| i8042_command cmd=a7
|7fee4000| i8042_wait_write
|7fee4000| i8042_flush
|7fee4000| i8042_command cmd=1aa
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_read
|7fee4000| i8042 param=55
|7fee4000| i8042_command cmd=1ab
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_read
|7fee4000| i8042 param=0
|7fee4000| ps2_command aux=0 cmd=1ff
|7fee4000| i8042 ctr old=30 new=30
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_sendbyte aux=0 cmd=ff
|7fee4000| i8042_kbd_write c=255
|7fee4000| i8042_wait_write
|7fee4000| ps2 read fa
|7fee4000| ps2 read aa
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_command aux=0 cmd=f5
|7fee4000| i8042 ctr old=30 new=30
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_sendbyte aux=0 cmd=f5
|7fee4000| i8042_kbd_write c=245
|7fee4000| i8042_wait_write
|7fee4000| ps2 read fa
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_command aux=0 cmd=10f0
|7fee4000| i8042 ctr old=30 new=30
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_sendbyte aux=0 cmd=f0
|7fee4000| i8042_kbd_write c=240
|7fee4000| i8042_wait_write
|7fee4000| ps2 read fa
|7fee4000| ps2_sendbyte aux=0 cmd=2
|7fee4000| i8042_kbd_write c=2
|7fee4000| i8042_wait_write
|7fee4000| ps2 read fa
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_command aux=0 cmd=f4
|7fee4000| i8042 ctr old=61 new=70
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| ps2_sendbyte aux=0 cmd=f4
|7fee4000| i8042_kbd_write c=244
|7fee4000| i8042_wait_write
|7fee4000| ps2 read fa
|7fee4000| i8042_command cmd=1060
|7fee4000| i8042_wait_write
|7fee4000| i8042_wait_write
|7fee4000| PS2 keyboard initialized
\7fee4000/ End thread

Now, one has to find out, what GRUB is doing.

As you found out, that it’s hanging below

static void
keyboard_controller_wait_until_ready (void)
{
/* 50 us would be enough but our current time resolution is 1ms. */
grub_millisleep (1);
while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)));
}

What about adding a timeout there too?

#define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02)

Also available in: Atom PDF