Bug #78

Skylake ramstage crashes if CONFIG_RELOCATABLE_RAMSTAGE is selected

Added by Trammell Hudson almost 4 years ago. Updated about 3 years ago.

Status:RejectedStart date:10/06/2016
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:board support
Target version:-

Description

As discussed on the mailing list: https://www.coreboot.org/pipermail/coreboot/2016-October/082121.html

Skylake (the Chell Chromebook) reboots following the LGDT instruction in the ramstage entry if it is built as relocatable.

CBFS: 'Master Header Locator' located CBFS at [a00100:ffffc0)
CBFS: Locating 'fallback/ramstage'
CBFS: Found @ offset afc0 size 12e29
Decompressing stage fallback/ramstage @ 0x7abbffc0 (743408 bytes)
Loading module at 7abc0000/7abc0000 with entry 7abc0000. filesize: 0x28d88 memsize: 0xb57b0
Processing 2472 relocs. Offset value of 0x7aac0000
src/arch/x86/boot.c:223: jumping to 7abc0000

(and then it crashes, asserting LPC reset and rebooting)

Aaron Durbin suggested disabling CONFIG_RELOCATABLE_RAMSTAGE, but CONFIG_SOC_INTEL_SKYLAKE forces the relocatable ramstage flag. I've modified src/soc/intel/skylake/Kconfig to not select it and now coreboot makes it all the way into the Linux payload. By adding the i915 framebuffer driver to the Linux kernel, it is able to bring up the console in a miniscule font! https://www.flickr.com/photos/osr/30026718432/in/photostream/lightbox/

History

#1 Updated by Aaron Durbin almost 4 years ago

I responded with these suggestions to attempt to further debug:

I don't understand that behavior at all. When you objdump -d -r -S
ramstage.debug do you see the ljmp instruction?

You can dump the ramstage relocations (with is still enabled) by changing

#define PK_ADJ_LEVEL BIOS_DEBUG

in src/lib/rmdoule.c.

#2 Updated by Trammell Hudson almost 4 years ago

The ramstage.debug looks fine:

Disassembly of section .text:

00100000 <_program>:
#else
        .code32
#endif
        .globl _start
_start:
        cli
  100000:       fa                      cli    
        lgdt    %cs:gdtaddr
  100001:       2e 0f 01 15 1f 01 10    lgdtl  %cs:0x10011f
  100008:       00 
                        100005: R_386_32        .text
#ifndef __x86_64__
        ljmp    $0x10, $1f
  100009:       ea 10 00 10 00 10 00    ljmp   $0x10,$0x100010
                        10000a: R_386_32        .text
#endif
...

Something appears to be wrong in the relocation code -- it appears to be stuck on the first address rather than updating the other relocations.

Decompressing stage fallback/ramstage @ 0x7abbffc0 (743408 bytes)
src/lib/rmodule.c:310
src/lib/rmodule.c:314
Loading module at 7abc0000/7abc0000 with entry 7abc0000. filesize: 0x28d88 memsize: 0xb57b0
Processing 2472 relocs. Offset value of 0x7aac0000
Adjusting 7aac0000: 0x5a5a5a5a -> 0xd5065a5a
Adjusting 7aac0000: 0xd5065a5a -> 0x4fb25a5a
Adjusting 7aac0000: 0x4fb25a5a -> 0xca5e5a5a
Adjusting 7aac0000: 0xca5e5a5a -> 0x450a5a5a
Adjusting 7aac0000: 0x450a5a5a -> 0xbfb65a5a
Adjusting 7aac0000: 0xbfb65a5a -> 0x3a625a5a
Adjusting 7aac0000: 0x3a625a5a -> 0xb50e5a5a
Adjusting 7aac0000: 0xb50e5a5a -> 0x2fba5a5a
...

#3 Updated by Trammell Hudson almost 4 years ago

The SMM relocation looks fine, however:

Loading module at 00038000/00124a6c with entry 00038000. filesize: 0x160 memsize: 0x160
Processing 10 relocs. Offset value of 0x00038000
Adjusting 00038002: 0x00000024 -> 0x00038024
Adjusting 0003801d: 0x0000003c -> 0x0003803c
Adjusting 00038026: 0x00000024 -> 0x00038024
Adjusting 00038054: 0x000000d8 -> 0x000380d8
Adjusting 00038066: 0x00000160 -> 0x00038160
Adjusting 0003806d: 0x000000c0 -> 0x000380c0
Adjusting 00038075: 0x000000c4 -> 0x000380c4
Adjusting 0003807e: 0x000000d0 -> 0x000380d0
Adjusting 00038085: 0x000000cc -> 0x000380cc
Adjusting 0003808b: 0x000000c8 -> 0x000380c8
SMM Module: stub loaded at 00038000. Will call 00112e17(00000000)
Installing SMM handler to 0x7b000000

#4 Updated by Trammell Hudson almost 4 years ago

Decompressing stage fallback/ramstage @ 0x7abbffc0 (743408 bytes)
src/lib/rmodule.c:329
src/lib/rmodule.c:333
Loading module at 7abc0000/7abc0000 with entry 7abc0000. filesize: 0x28f88 memsize: 0xb57b0
Processing 2482 relocs @ 7abe8f88. Offset value of 0x7aac0000
module->location=7abc0000
module->header->module_link_start_address=00100000
7abe8f88: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
...
7abc0000: fa 2e 0f 01 15 1f 01 10 00 ea 10 00 10 00 10 00  ................
7abc0010: b8 18 00 00 00 8e d8 8e c0 8e d0 8e e0 8e e8 b0  ................
7abc0020: 13 e6 80 fc 8d 3d 00 90 12 00 b9 00 10 13 00 29  .....=.........)
7abc0030: f9 c1 e9 02 b8 ef be ad de f3 ab bc 00 10 13 00  ................

Adding hexdumps of the regions, the code appears to be correctly mapped (fa 2e 0f... are the first instructions in the .program text segment). However the .relocs section does not appear to be correctly populated in memory.

According to readelf, the .relocs should start at offset 0x02afc8 in the file, although it appears that the module->relocations offset is 0x28ff8 (i.e., directly after the .program section):

readelf -S ramstage.elf 
There are 8 section headers, starting at offset 0x34:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .shstrtab         STRTAB          00000000 000194 00003b 00      0   0  0
  [ 2] .strtab           STRTAB          00000000 001000 001000 00      0   0  1
  [ 3] .symtab           NULL            00000000 002000 000000 10      0   0  4
  [ 4] .header           PROGBITS        00000000 002000 000040 00 WAX  0   0  0
  [ 5] .program          PROGBITS        00000040 002040 028f88 00 WAX  0   0  0
  [ 6] .relocs           PROGBITS        00028fc8 02afc8 0026c8 00 WAX  0   0  0
  [ 7] .empty            NOBITS          0002b690 02d690 08a160 00   A  0   0  0

#5 Updated by Trammell Hudson almost 4 years ago

Oops. This is my own bug.

A while ago I added code to rmodule_copy_payload() to ensure that the SMM region was entirely zeroed, but this does not take into account the reloc section, only the code section. This needs to be re-considered:

static void rmodule_copy_payload(const struct rmodule *module)
{
        const size_t mem_size = rmodule_memory_size(module);

        printk(BIOS_DEBUG, "Loading module at %p/%p with entry %p. "
               "filesize: 0x%x memsize: 0x%zx\n",
               module->location, module->payload, rmodule_entry(module),
               module->payload_size, mem_size);

        // zero the excess memory if there is any
        if (mem_size > module->payload_size)
        {
                memset((uint8_t*) module->location + module->payload_size,
                        0,
                        mem_size - module->payload_size
                );
        }

        /* No need to copy the payload if the load location and the
         * payload location are the same. */
        if (module->location == module->payload)
                return;

        memcpy(module->location, module->payload, module->payload_size);
}

#6 Updated by Aaron Durbin almost 4 years ago

If you want to zero out memory you need to do it after the rmodule has been loaded. However, that zero'ing of memory is largely taken care of in the normal load path.

#7 Updated by Nico Huber about 3 years ago

  • Status changed from New to Rejected

Do I read it correctly that this bug was never upstream?

Also available in: Atom PDF