diff options
-rw-r--r-- | src/arch/i386/boot/tables.c | 142 |
1 files changed, 49 insertions, 93 deletions
diff --git a/src/arch/i386/boot/tables.c b/src/arch/i386/boot/tables.c index f6f7625f75..387699507f 100644 --- a/src/arch/i386/boot/tables.c +++ b/src/arch/i386/boot/tables.c @@ -1,7 +1,8 @@ /* * This file is part of the coreboot project. * - * Copyright (C) .... others + * Copyright (C) 2003 Eric Biederman + * Copyright (C) 2005 Steve Magnani * Copyright (C) 2008-2009 coresystems GmbH * * This program is free software; you can redistribute it and/or modify @@ -42,8 +43,6 @@ struct gdtarg { } __attribute__((packed)); // Copy GDT to new location and reload it -// 2003-07 by SONE Takeshi -// Ported from Etherboot to coreboot 2005-08 by Steve Magnani void move_gdt(unsigned long newgdt) { uint16_t num_gdt_bytes = &gdt_end - &gdt; @@ -57,24 +56,22 @@ void move_gdt(unsigned long newgdt) printk_debug("ok\n"); } -#if HAVE_HIGH_TABLES == 1 uint64_t high_tables_base = 0; uint64_t high_tables_size; -#endif struct lb_memory *write_tables(void) { unsigned long low_table_start, low_table_end; unsigned long rom_table_start, rom_table_end; -#if HAVE_MP_TABLE == 1 && HAVE_LOW_TABLES == 1 +#if HAVE_MP_TABLE == 1 unsigned long new_low_table_end; #endif -#if HAVE_HIGH_TABLES == 1 - /* Even if high tables are configured, all tables are copied both to the - * low and the high area, so payloads and OSes don't need to know about - * the high tables. + /* Even if high tables are configured, some tables are copied both to + * the low and the high area, so payloads and OSes don't need to know + * about the high tables. */ + unsigned long high_rsdp; unsigned long high_table_start=0, high_table_end=0; if (high_tables_base) { @@ -82,118 +79,78 @@ struct lb_memory *write_tables(void) high_table_start = high_tables_base; high_table_end = high_tables_base; } else { - printk_debug("High Tables Base is not set.\n"); + printk_err("ERROR: High Tables Base is not set.\n"); } -#endif 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. + + /* Start low addr at 0x500, so we don't run into conflicts with the BDA + * in case our data structures grow beyound 0x400. Only multiboot, GDT + * and the coreboot table use low_tables. */ low_table_start = 0; - low_table_end = 16; + low_table_end = 0x500; - post_code(0x9a); + post_code(0x99); -#if HAVE_LOW_TABLES == 1 - /* This table must be betweeen 0xf0000 & 0x100000 */ + /* This table must be between 0x0f0000 and 0x100000 */ rom_table_end = write_pirq_routing_table(rom_table_end); - rom_table_end = (rom_table_end + 1023) & ~1023; -#endif -#if HAVE_HIGH_TABLES == 1 + rom_table_end = ALIGN(rom_table_end, 1024); + + /* And add a high table version for those payloads that + * want to live in the F segment + */ if (high_tables_base) { high_table_end = write_pirq_routing_table(high_table_end); - high_table_end = (high_table_end + 1023) & ~1023; + high_table_end = ALIGN(high_table_end, 1024); } -#endif - /* Write ACPI tables */ - /* write them in the rom area because DSDT can be large (8K on epia-m) which - * pushes coreboot table out of first 4K if set up in low table area - */ + post_code(0x9a); + + /* Write ACPI tables to F segment and high tables area */ #if HAVE_ACPI_TABLES == 1 -#if HAVE_HIGH_TABLES == 1 -#if HAVE_LOW_TABLES == 1 - unsigned long high_rsdp=ALIGN(high_table_end, 16); -#endif if (high_tables_base) { + unsigned long rsdt_location; + high_rsdp = ALIGN(high_table_end, 16); high_table_end = write_acpi_tables(high_table_end); - high_table_end = (high_table_end+1023) & ~1023; + high_table_end = ALIGN(high_table_end, 1024); + rsdt_location = (unsigned long)(((acpi_rsdp_t*)high_rsdp)->rsdt_address); + printk_debug("high mem RSDP at %x, RSDT at %x\n", high_rsdp, rsdt_location); + acpi_write_rsdp((acpi_rsdp_t *)rom_table_end, (acpi_rsdt_t *)rsdt_location); + rom_table_end = ALIGN(ALIGN(rom_table_end, 16) + sizeof(acpi_rsdp_t), 16); + } else { + rom_table_end = write_acpi_tables(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); } -#if HAVE_LOW_TABLES == 1 - unsigned long rsdt_location=(unsigned long*)(((acpi_rsdp_t*)high_rsdp)->rsdt_address); - acpi_write_rsdp(rom_table_end, rsdt_location); - rom_table_end = ALIGN(ALIGN(rom_table_end, 16) + sizeof(acpi_rsdp_t), 16); #endif -#else -#if HAVE_LOW_TABLES == 1 - rom_table_end = write_acpi_tables(rom_table_end); - rom_table_end = (rom_table_end+1023) & ~1023; -#endif -#endif -#endif - /* copy the smp block to address 0 */ - post_code(0x96); + post_code(0x9b); #if HAVE_MP_TABLE == 1 - /* The smp table must be in 0-1K, 639K-640K, or 960K-1M */ -#if HAVE_LOW_TABLES == 1 - new_low_table_end = write_smp_table(low_table_end); // low_table_end is 0x10 at this point - /* 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%0lx 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 /* HAVE_LOW_TABLES */ + rom_table_end = write_smp_table(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); -#if HAVE_HIGH_TABLES == 1 + /* ... and a copy in the high tables */ if (high_tables_base) { high_table_end = write_smp_table(high_table_end); - high_table_end = (high_table_end+1023) & ~1023; + high_table_end = ALIGN(high_table_end, 1024); } -#endif #endif /* HAVE_MP_TABLE */ - if (low_table_end < 0x500) { - low_table_end = 0x500; - } + post_code(0x9c); // Relocate the GDT to reserved memory, so it won't get clobbered -#if HAVE_HIGH_TABLES == 1 if (high_tables_base) { move_gdt(high_table_end); high_table_end += &gdt_end - &gdt; - high_table_end = (high_table_end+1023) & ~1023; + high_table_end = ALIGN(high_table_end, 1024); } else { -#endif move_gdt(low_table_end); low_table_end += &gdt_end - &gdt; -#if HAVE_HIGH_TABLES == 1 } -#endif + + post_code(0x9d); #if CONFIG_MULTIBOOT /* The Multiboot information structure */ @@ -203,20 +160,19 @@ struct lb_memory *write_tables(void) rom_table_start, rom_table_end); #endif -#if HAVE_HIGH_TABLES == 1 + post_code(0x9e); + if (high_tables_base) { + /* Also put a forwarder entry into 0-4K */ write_coreboot_table(low_table_start, low_table_end, high_table_start, high_table_end); } else { - printk_err("ERROR: No high_tables_base.\n"); + /* The coreboot table must be in 0-4K or 960K-1M */ write_coreboot_table(low_table_start, low_table_end, rom_table_start, rom_table_end); } -#else - /* The coreboot table must be in 0-4K or 960K-1M */ - write_coreboot_table(low_table_start, low_table_end, - rom_table_start, rom_table_end); -#endif + post_code(0x9f); + return get_lb_mem(); } |