On Mon, Jul 21, 2008 at 2:52 PM, yhlu yinghailu@gmail.com wrote:
On Mon, Jul 21, 2008 at 2:27 PM, Roman Kononov kononov@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(); }