[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