[coreboot] kernel panics reserving EBDA pages

yhlu yinghailu at gmail.com
Tue Jul 22 00:20:19 CEST 2008


On Mon, Jul 21, 2008 at 3:16 PM, yhlu <yinghailu at gmail.com> wrote:
> On Mon, Jul 21, 2008 at 2:52 PM, yhlu <yinghailu at gmail.com> wrote:
>> On Mon, Jul 21, 2008 at 2:27 PM, Roman Kononov <kononov at dls.net> wrote:
>>> Hello,
>>>
>>> I have this chain: coreboot v2 -> etherboot as the payload -> x86_64 kernel
>>> 2.6.25.6.
>>>
>>> The kernel panics in arch/x86/e820_64.c, reserve_early() with the message:
>>>
>>> Overlapping early reservations f0-100ef EBDA to 0-fff BIOS data page
>>>
>>> reserve_early(start,end) is called from arch/x86/head64.c, reserve_ebda()
>>> with start=0xf0 and end=0x100f0.
>>>
>>> The address and size of EBDA is gotten this way:
>>>
>>>    #define EBDA_ADDR_POINTER 0x40E
>>>    ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
>>>    ebda_addr <<= 4;
>>>    ebda_size = *(unsigned short *)__va(ebda_addr);
>>>
>>> After the above sequence ebda_addr=0xf0 and ebda_size=0x2049 KiB;
>>>
>>> This all happened in a very well working system after I added the second
>>> dual-core Opteron.
>>>
>>> Without the second CPU, ebda_addr=0x12010 and ebda_size=0, which combination
>>> passes reserve_early() without overlapping. The resulting reservations are:
>>>  early res: 0 [0-fff] BIOS data page
>>>  early res: 1 [6000-7fff] SMP_TRAMPOLINE
>>>  early res: 2 [200000-75b503] TEXT DATA BSS
>>>  early res: 3 [800000-9bd8dd] RAMDISK
>>>  early res: 4 [12010-1300f] EBDA
>>>  early res: 5 [8000-cfff] PGTABLE
>>>
>>> How come? What is responsible to clear the memory at 0x40e? What is EBDA and
>>> what needs it?
>>
>> interesting, EBDA should be in [0x90000, 0x100000]
>
> linuxbios doesn't honor the 0x40e, and will use first 4k for irq table etc.
>
> please try to update write_tables like..
>
> /* 2006.1 yhlu add mptable cross 0x467 processing */
>
> #include <console/console.h>
> #include <cpu/cpu.h>
> #include <boot/tables.h>
> #include <boot/linuxbios_tables.h>
> #include <arch/pirq_routing.h>
> #include <arch/smp/mpspec.h>
> #include <arch/acpi.h>
> #include "linuxbios_table.h"
>
> struct lb_memory *write_tables(void)
> {
>        unsigned long low_table_start, low_table_end, new_low_table_end;
>        unsigned long rom_table_start, rom_table_end;
>
>        rom_table_start = 0xf0000;
>        rom_table_end =   0xf0000;
>        /* Start low addr at 16 bytes instead of 0 because of a buglet
>         * in the generic linux unzip code, as it tests for the a20 line.
>         */
>        low_table_start = 0;
>        low_table_end = 16;
>
>        post_code(0x9a);
>
>        /* This table must be betweeen 0xf0000 & 0x100000 */
>        rom_table_end = write_pirq_routing_table(rom_table_end);
>        rom_table_end = (rom_table_end + 1023) & ~1023;
>
>        /* Write ACPI tables */
>        /* write them in the rom area because DSDT can be large (8K on
> epia-m) which
>         * pushes linuxbios table out of first 4K if set up in low table area
>         */
>        rom_table_end = write_acpi_tables(rom_table_end);
>        rom_table_end = (rom_table_end+1023) & ~1023;
>
>        /* copy the smp block to address 0 */
>        post_code(0x96);
>
>        /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
>        new_low_table_end = write_smp_table(low_table_end); //
> low_table_end is 0x10 at this point
>
> #if HAVE_MP_TABLE
>        /* Don't write anything in the traditional x86 BIOS data segment,
>         * for example the linux kernel smp need to use 0x467 to pass
> reset vector
>         * or use 0x40e/0x413 for EBDA finding...
>         */
>        if(new_low_table_end>0x400){
>                unsigned mptable_size;
>                unsigned mpc_start;
>                low_table_end += SMP_FLOATING_TABLE_LEN; /* keep the
> mpf in 1k low, so kernel can find it */
>                mptable_size = new_low_table_end - low_table_end;
>                /* We can not put mptable low, we need to copy them to
> somewhere else*/
>                if((rom_table_end+mptable_size)<0x100000) {
>                        /* We can copy mptable on rom_table  */
>                        mpc_start = rom_table_end;
>                        rom_table_end += mptable_size;
>                        rom_table_end = (rom_table_end+1023) & ~1023;
>                } else {
>                        /* We can need to put mptable before rom_table */
>                        mpc_start = rom_table_start - mptable_size;
>                        mpc_start &= ~1023;
>                        rom_table_start = mpc_start;
>                }
>                printk_debug("move mptable from 0x%0x to 0x%0x, size
> 0x%0x\n", low_table_end, mpc_start, mptable_size);
>                memcpy((unsigned char *)mpc_start, (unsigned char
> *)low_table_end, mptable_size);
>                smp_write_floating_table_physaddr(low_table_end -
> SMP_FLOATING_TABLE_LEN, mpc_start);
>                memset((unsigned char *)low_table_end, '\0', mptable_size);
>        }
> #endif
>        if(low_table_end<0x500) {
>                low_table_end = 0x500;
>        }
>
>        /* The linuxbios table must be in 0-4K or 960K-1M */
>        write_linuxbios_table(low_table_start, low_table_end,
>                              rom_table_start, rom_table_end);
>
>        return get_lb_mem();
> }


and

unsigned long write_linuxbios_table(
        unsigned long low_table_start, unsigned long low_table_end,
        unsigned long rom_table_start, unsigned long rom_table_end)
{
        unsigned long table_size;
        struct lb_header *head;
        struct lb_memory *mem;

        if(low_table_end > (0x1000 - sizeof(struct lb_header))) { /* after 4K */
                /* We need to put lbtable on  to [0xf0000,0x100000) */
                head = lb_table_init(rom_table_end);
                rom_table_end = (unsigned long)head;
        } else {
                head = lb_table_init(low_table_end);
                low_table_end = (unsigned long)head;
        }

        printk_debug("Adjust low_table_end from 0x%08x to ", low_table_end);
        low_table_end += 0xfff; // 4K align
        low_table_end &= ~0xfff;
        printk_debug("0x%08x \n", low_table_end);
        /* kernel assume this position is reserved */
        printk_debug("Adjust rom_table_end from 0x%08x to ", rom_table_end);
        rom_table_end += 0xffff; // 64K align
        rom_table_end &= ~0xffff;
        printk_debug("0x%08x \n", rom_table_end);

        if (HAVE_OPTION_TABLE == 1) {
                struct lb_record *rec_dest, *rec_src;
                /* Write the option config table... */
                rec_dest = lb_new_record(head);
                rec_src = (struct lb_record *)(void *)&option_table;
                memcpy(rec_dest,  rec_src, rec_src->size);
                /* Create cmos checksum entry in linuxbios table */
                lb_cmos_checksum(head);
        }
        /* Record where RAM is located */
        mem = build_lb_mem(head);

        /* Record the mptable and the the lb_table (This will be
adjusted later) */
        lb_add_memory_range(mem, LB_MEM_TABLE,
                low_table_start, low_table_end - low_table_start);

        /* Record the pirq table, acpi tables, and maybe the mptable */
        lb_add_memory_range(mem, LB_MEM_TABLE,
                rom_table_start, rom_table_end - rom_table_start);

        /* Note:
         * I assume that there is always memory at immediately after
         * the low_table_end.  This means that after I setup the
linuxbios table.
         * I can trivially fixup the reserved memory ranges to hold the correct
         * size of the linuxbios table.
         */

        /* Record our motheboard */
        lb_mainboard(head);
        /* Record our various random string information */
        lb_strings(head);

        /* Remember where my valid memory ranges are */
        return lb_table_fini(head);

}




More information about the coreboot mailing list