Author: stepan Date: 2008-01-28 18:50:56 +0100 (Mon, 28 Jan 2008) New Revision: 565
Added: coreboot-v3/arch/x86/coreboot_table.c Removed: coreboot-v3/arch/x86/linuxbios_table.c Log: rename linuxbios_table.c
Signed-off-by: Stefan Reinauer stepan@coresystems.de Acked-by: Stefan Reinauer stepan@coresystems.de
Copied: coreboot-v3/arch/x86/coreboot_table.c (from rev 564, coreboot-v3/arch/x86/linuxbios_table.c) =================================================================== --- coreboot-v3/arch/x86/coreboot_table.c (rev 0) +++ coreboot-v3/arch/x86/coreboot_table.c 2008-01-28 17:50:56 UTC (rev 565) @@ -0,0 +1,466 @@ +/* + * table management code for coreboot tables + * + * Copyright (C) 2002 Eric Biederman, Linux NetworX + * Copyright (C) 2007 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include <console.h> +#include <ip_checksum.h> +#include <string.h> +#include <device/device.h> +#include <tables.h> +#include <mc146818rtc.h> +#include <lib.h> +//#include <cpu/cpu.h> +//#include <pirq_routing.h> +//#include <smp/mpspec.h> +//#include <acpi.h> + +struct lb_header *lb_table_init(unsigned long addr) +{ + struct lb_header *header; + + /* 16 byte align the address */ + addr += 15; + addr &= ~15; + + header = (void *)addr; + header->signature[0] = 'L'; + header->signature[1] = 'B'; + header->signature[2] = 'I'; + header->signature[3] = 'O'; + header->header_bytes = sizeof(*header); + header->header_checksum = 0; + header->table_bytes = 0; + header->table_checksum = 0; + header->table_entries = 0; + return header; +} + +struct lb_record *lb_first_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header)); + return rec; +} + +struct lb_record *lb_last_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes); + return rec; +} + +struct lb_record *lb_next_record(struct lb_record *rec) +{ + rec = (void *)(((char *)rec) + rec->size); + return rec; +} + +struct lb_record *lb_new_record(struct lb_header *header) +{ + struct lb_record *rec; + rec = lb_last_record(header); + if (header->table_entries) { + header->table_bytes += rec->size; + } + rec = lb_last_record(header); + header->table_entries++; + rec->tag = LB_TAG_UNUSED; + rec->size = sizeof(*rec); + return rec; +} + + +struct lb_memory *lb_memory(struct lb_header *header) +{ + struct lb_record *rec; + struct lb_memory *mem; + rec = lb_new_record(header); + mem = (struct lb_memory *)rec; + mem->tag = LB_TAG_MEMORY; + mem->size = sizeof(*mem); + return mem; +} + +struct lb_mainboard *lb_mainboard(struct lb_header *header) +{ + struct lb_record *rec; + struct lb_mainboard *mainboard; + extern char *mainboard_vendor, *mainboard_part_number; + rec = lb_new_record(header); + mainboard = (struct lb_mainboard *)rec; + mainboard->tag = LB_TAG_MAINBOARD; + + mainboard->size = (sizeof(*mainboard) + + strlen(mainboard_vendor) + 1 + + strlen(mainboard_part_number) + 1 + + 3) & ~3; + + mainboard->vendor_idx = 0; + mainboard->part_number_idx = strlen(mainboard_vendor) + 1; + + memcpy(mainboard->strings + mainboard->vendor_idx, + mainboard_vendor, strlen(mainboard_vendor) + 1); + memcpy(mainboard->strings + mainboard->part_number_idx, + mainboard_part_number, strlen(mainboard_part_number) + 1); + + return mainboard; +} + +struct cmos_checksum *lb_cmos_checksum(struct lb_header *header) +{ + struct lb_record *rec; + struct cmos_checksum *cmos_checksum; + rec = lb_new_record(header); + cmos_checksum = (struct cmos_checksum *)rec; + cmos_checksum->tag = LB_TAG_OPTION_CHECKSUM; + + cmos_checksum->size = (sizeof(*cmos_checksum)); + + cmos_checksum->range_start = CB_CKS_RANGE_START * 8; + cmos_checksum->range_end = ( CB_CKS_RANGE_END * 8 ) + 7; + cmos_checksum->location = CB_CKS_LOC * 8; + + cmos_checksum->type = CHECKSUM_PCBIOS; + + return cmos_checksum; +} + +void lb_strings(struct lb_header *header) +{ + static const struct { + u32 tag; + const u8 *string; + } strings[] = { + { LB_TAG_VERSION, (const u8 *)COREBOOT_VERSION }, + { LB_TAG_EXTRA_VERSION, (const u8 *)COREBOOT_EXTRA_VERSION }, + { LB_TAG_BUILD, (const u8 *)COREBOOT_BUILD }, + { LB_TAG_COMPILE_TIME, (const u8 *)COREBOOT_COMPILE_TIME }, // duplicate? + { LB_TAG_COMPILE_BY, (const u8 *)COREBOOT_COMPILE_BY }, + { LB_TAG_COMPILE_HOST, (const u8 *)COREBOOT_COMPILE_HOST }, + { LB_TAG_COMPILE_DOMAIN, (const u8 *)COREBOOT_COMPILE_DOMAIN }, + { LB_TAG_COMPILER, (const u8 *)COREBOOT_COMPILER }, + { LB_TAG_LINKER, (const u8 *)COREBOOT_LINKER }, + { LB_TAG_ASSEMBLER, (const u8 *)COREBOOT_ASSEMBLER }, + }; + unsigned int i; + for(i = 0; i < ARRAY_SIZE(strings); i++) { + struct lb_string *rec; + size_t len; + rec = (struct lb_string *)lb_new_record(header); + len = strlen((char *)strings[i].string); + rec->tag = strings[i].tag; + rec->size = (sizeof(*rec) + len + 1 + 3) & ~3; + memcpy(rec->string, strings[i].string, len+1); + } + +} + +static void lb_memory_range(struct lb_memory *mem, + u32 type, u64 start, u64 size) +{ + int entries; + + printk(BIOS_DEBUG, "%s: start 0x%llx size 0x%llx\n", + __func__, start, size); + + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + mem->map[entries].start = pack_lb64(start); + mem->map[entries].size = pack_lb64(size); + mem->map[entries].type = type; + mem->size += sizeof(mem->map[0]); +} + +static void lb_reserve_table_memory(struct lb_header *head) +{ + struct lb_record *last_rec; + struct lb_memory *mem; + u64 start; + u64 end; + int i, entries; + + last_rec = lb_last_record(head); + mem = get_lb_mem(); + start = (unsigned long)head; + end = (unsigned long)last_rec; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + /* Resize the right two memory areas so this table is in + * a reserved area of memory. Everything has been carefully + * setup so that is all we need to do. + */ + for(i = 0; i < entries; i++ ) { + u64 map_start = unpack_lb64(mem->map[i].start); + u64 map_end = map_start + unpack_lb64(mem->map[i].size); + /* Does this area need to be expanded? */ + if (map_end == start) { + mem->map[i].size = pack_lb64(end - map_start); + } + /* Does this area need to be contracted? */ + else if (map_start == start) { + mem->map[i].start = pack_lb64(end); + mem->map[i].size = pack_lb64(map_end - end); + } + } +} + +unsigned long lb_table_fini(struct lb_header *head) +{ + struct lb_record *rec, *first_rec; + rec = lb_last_record(head); + if (head->table_entries) { + head->table_bytes += rec->size; + } + lb_reserve_table_memory(head); + first_rec = lb_first_record(head); + head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes); + head->header_checksum = 0; + head->header_checksum = compute_ip_checksum(head, sizeof(*head)); + printk(BIOS_DEBUG,"Wrote coreboot table at: %p - %p checksum %x\n", + head, rec, head->table_checksum); + return (unsigned long)rec; +} + +static void lb_cleanup_memory_ranges(struct lb_memory *mem) +{ + int entries; + int i, j; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + printk(BIOS_DEBUG, "%s: # entries %d\n", __func__, entries); + for(i = 0; i < entries; i++) + printk(BIOS_INFO, " #%d: base 0x%08x size 0x%x\n", + i, mem->map[i].start.lo, mem->map[i].size.lo); + + /* Sort the lb memory ranges */ + for(i = 0; i < entries; i++) { + u64 entry_start = unpack_lb64(mem->map[i].start); + for(j = i; j < entries; j++) { + u64 temp_start = unpack_lb64(mem->map[j].start); + if (temp_start < entry_start) { + struct lb_memory_range tmp; + tmp = mem->map[i]; + mem->map[i] = mem->map[j]; + mem->map[j] = tmp; + } + } + } + + /* Merge adjacent entries */ + for(i = 0; (i + 1) < entries; i++) { + u64 start, end, nstart, nend; + if (mem->map[i].type != mem->map[i + 1].type) { + continue; + } + start = unpack_lb64(mem->map[i].start); + end = start + unpack_lb64(mem->map[i].size); + nstart = unpack_lb64(mem->map[i + 1].start); + nend = nstart + unpack_lb64(mem->map[i + 1].size); + if ((start <= nstart) && (end > nstart)) { + if (start > nstart) { + start = nstart; + } + if (end < nend) { + end = nend; + } + /* Record the new region size */ + mem->map[i].start = pack_lb64(start); + mem->map[i].size = pack_lb64(end - start); + + /* Delete the entry I have merged with */ + memmove(&mem->map[i + 1], &mem->map[i + 2], + ((entries - i - 2) * sizeof(mem->map[0]))); + mem->size -= sizeof(mem->map[0]); + entries -= 1; + /* See if I can merge with the next entry as well */ + i -= 1; + } + } +} + +static void lb_remove_memory_range(struct lb_memory *mem, + u64 start, u64 size) +{ + u64 end; + int entries; + int i; + + end = start + size; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + + /* Remove a reserved area from the memory map */ + for(i = 0; i < entries; i++) { + u64 map_start = unpack_lb64(mem->map[i].start); + u64 map_end = map_start + unpack_lb64(mem->map[i].size); + if ((start <= map_start) && (end >= map_end)) { + /* Remove the completely covered range */ + memmove(&mem->map[i], &mem->map[i + 1], + ((entries - i - 1) * sizeof(mem->map[0]))); + mem->size -= sizeof(mem->map[0]); + entries -= 1; + + /* Since the index will disappear + * revisit what will appear here + */ + i -= 1; + } + else if ((start > map_start) && (end < map_end)) { + /* Split the memory range */ + memmove(&mem->map[i + 1], &mem->map[i], + ((entries - i) * sizeof(mem->map[0]))); + mem->size += sizeof(mem->map[0]); + entries += 1; + /* Update the first map entry */ + mem->map[i].size = pack_lb64(start - map_start); + /* Update the second map entry */ + mem->map[i + 1].start = pack_lb64(end); + mem->map[i + 1].size = pack_lb64(map_end - end); + /* Don't bother with this map entry again */ + i += 1; + } + else if ((start <= map_start) && (end > map_start)) { + /* Shrink the start of the memory range */ + mem->map[i].start = pack_lb64(end); + mem->map[i].size = pack_lb64(map_end - end); + } + else if ((start < map_end) && (start > map_start)) { + /* Shrink the end of the memory range */ + mem->map[i].size = pack_lb64(start - map_start); + } + } +} + +static void lb_add_memory_range(struct lb_memory *mem, + u32 type, u64 start, u64 size) +{ + lb_remove_memory_range(mem, start, size); + lb_memory_range(mem, type, start, size); + lb_cleanup_memory_ranges(mem); +} + +/* Routines to extract part so the coreboot table or + * information from the coreboot table after we have written it. + * Currently get_lb_mem relies on a global we can change the + * implementaiton. + */ +static struct lb_memory *mem_ranges = 0; +struct lb_memory *get_lb_mem(void) +{ + return mem_ranges; +} + +static void build_lb_mem_range(void *gp, struct device *dev, struct resource *res) +{ + struct lb_memory *mem = gp; + lb_memory_range(mem, LB_MEM_RAM, res->base, res->size); +} + +static struct lb_memory *build_lb_mem(struct lb_header *head) +{ + struct lb_memory *mem; + + /* Record where the lb memory ranges will live */ + mem = lb_memory(head); + mem_ranges = mem; + + /* Build the raw table of memory */ + search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, + IORESOURCE_MEM | IORESOURCE_CACHEABLE, build_lb_mem_range, mem); + + lb_cleanup_memory_ranges(mem); + return mem; +} + +/** + * Add pointer to device tree to coreboot table. + * + * @param head Pointer to lbtable header. + * @return TODO + */ +struct lb_devtree *lb_devtree(struct lb_header *head) +{ + struct lb_devtree *lbdev = NULL; + + lbdev = (struct lb_devtree *)lb_new_record(head); + lbdev->tag = LB_TAG_DEVTREE_PTR; + lbdev->size = sizeof(*lbdev); + lbdev->dev_root_ptr = (u32)&dev_root; // XXX ouch. + + // FIXME we should either copy the device tree completely + // or at least mark it reserved. + return lbdev; +} + +unsigned long write_coreboot_table( + unsigned long low_table_start, unsigned long low_table_end, + unsigned long rom_table_start, unsigned long rom_table_end) +{ + struct lb_header *head; + struct lb_memory *mem; + struct lb_record *rec_dest, *rec_src; + + 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; + } + + /* Write the option config table... */ + + rec_src = (struct lb_record *)(void *)get_option_table(); + if (rec_src != NULL) { + rec_dest = lb_new_record(head); + + memcpy(rec_dest, rec_src, rec_src->size); + /* Create cmos checksum entry in coreboot table */ + lb_cmos_checksum(head); + } + + /* Record where RAM is located */ + mem = build_lb_mem(head); + + /* Record the mptable and the the lb_table (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 coreboot table. + * I can trivially fixup the reserved memory ranges to hold the correct + * size of the coreboot table. + */ + + /* Record our motherboard */ + lb_mainboard(head); + + /* Record our various random string information */ + lb_strings(head); + + /* Record a pointer to the coreboot device tree */ + lb_devtree(head); + + /* Remember where my valid memory ranges are */ + return lb_table_fini(head); + +}
Property changes on: coreboot-v3/arch/x86/coreboot_table.c ___________________________________________________________________ Added: svn:mergeinfo +
Deleted: coreboot-v3/arch/x86/linuxbios_table.c =================================================================== --- coreboot-v3/arch/x86/linuxbios_table.c 2008-01-27 18:54:57 UTC (rev 564) +++ coreboot-v3/arch/x86/linuxbios_table.c 2008-01-28 17:50:56 UTC (rev 565) @@ -1,466 +0,0 @@ -/* - * table management code for coreboot tables - * - * Copyright (C) 2002 Eric Biederman, Linux NetworX - * Copyright (C) 2007 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA - * - */ - -#include <console.h> -#include <ip_checksum.h> -#include <string.h> -#include <device/device.h> -#include <tables.h> -#include <mc146818rtc.h> -#include <lib.h> -//#include <cpu/cpu.h> -//#include <pirq_routing.h> -//#include <smp/mpspec.h> -//#include <acpi.h> - -struct lb_header *lb_table_init(unsigned long addr) -{ - struct lb_header *header; - - /* 16 byte align the address */ - addr += 15; - addr &= ~15; - - header = (void *)addr; - header->signature[0] = 'L'; - header->signature[1] = 'B'; - header->signature[2] = 'I'; - header->signature[3] = 'O'; - header->header_bytes = sizeof(*header); - header->header_checksum = 0; - header->table_bytes = 0; - header->table_checksum = 0; - header->table_entries = 0; - return header; -} - -struct lb_record *lb_first_record(struct lb_header *header) -{ - struct lb_record *rec; - rec = (void *)(((char *)header) + sizeof(*header)); - return rec; -} - -struct lb_record *lb_last_record(struct lb_header *header) -{ - struct lb_record *rec; - rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes); - return rec; -} - -struct lb_record *lb_next_record(struct lb_record *rec) -{ - rec = (void *)(((char *)rec) + rec->size); - return rec; -} - -struct lb_record *lb_new_record(struct lb_header *header) -{ - struct lb_record *rec; - rec = lb_last_record(header); - if (header->table_entries) { - header->table_bytes += rec->size; - } - rec = lb_last_record(header); - header->table_entries++; - rec->tag = LB_TAG_UNUSED; - rec->size = sizeof(*rec); - return rec; -} - - -struct lb_memory *lb_memory(struct lb_header *header) -{ - struct lb_record *rec; - struct lb_memory *mem; - rec = lb_new_record(header); - mem = (struct lb_memory *)rec; - mem->tag = LB_TAG_MEMORY; - mem->size = sizeof(*mem); - return mem; -} - -struct lb_mainboard *lb_mainboard(struct lb_header *header) -{ - struct lb_record *rec; - struct lb_mainboard *mainboard; - extern char *mainboard_vendor, *mainboard_part_number; - rec = lb_new_record(header); - mainboard = (struct lb_mainboard *)rec; - mainboard->tag = LB_TAG_MAINBOARD; - - mainboard->size = (sizeof(*mainboard) + - strlen(mainboard_vendor) + 1 + - strlen(mainboard_part_number) + 1 + - 3) & ~3; - - mainboard->vendor_idx = 0; - mainboard->part_number_idx = strlen(mainboard_vendor) + 1; - - memcpy(mainboard->strings + mainboard->vendor_idx, - mainboard_vendor, strlen(mainboard_vendor) + 1); - memcpy(mainboard->strings + mainboard->part_number_idx, - mainboard_part_number, strlen(mainboard_part_number) + 1); - - return mainboard; -} - -struct cmos_checksum *lb_cmos_checksum(struct lb_header *header) -{ - struct lb_record *rec; - struct cmos_checksum *cmos_checksum; - rec = lb_new_record(header); - cmos_checksum = (struct cmos_checksum *)rec; - cmos_checksum->tag = LB_TAG_OPTION_CHECKSUM; - - cmos_checksum->size = (sizeof(*cmos_checksum)); - - cmos_checksum->range_start = CB_CKS_RANGE_START * 8; - cmos_checksum->range_end = ( CB_CKS_RANGE_END * 8 ) + 7; - cmos_checksum->location = CB_CKS_LOC * 8; - - cmos_checksum->type = CHECKSUM_PCBIOS; - - return cmos_checksum; -} - -void lb_strings(struct lb_header *header) -{ - static const struct { - u32 tag; - const u8 *string; - } strings[] = { - { LB_TAG_VERSION, (const u8 *)COREBOOT_VERSION }, - { LB_TAG_EXTRA_VERSION, (const u8 *)COREBOOT_EXTRA_VERSION }, - { LB_TAG_BUILD, (const u8 *)COREBOOT_BUILD }, - { LB_TAG_COMPILE_TIME, (const u8 *)COREBOOT_COMPILE_TIME }, // duplicate? - { LB_TAG_COMPILE_BY, (const u8 *)COREBOOT_COMPILE_BY }, - { LB_TAG_COMPILE_HOST, (const u8 *)COREBOOT_COMPILE_HOST }, - { LB_TAG_COMPILE_DOMAIN, (const u8 *)COREBOOT_COMPILE_DOMAIN }, - { LB_TAG_COMPILER, (const u8 *)COREBOOT_COMPILER }, - { LB_TAG_LINKER, (const u8 *)COREBOOT_LINKER }, - { LB_TAG_ASSEMBLER, (const u8 *)COREBOOT_ASSEMBLER }, - }; - unsigned int i; - for(i = 0; i < ARRAY_SIZE(strings); i++) { - struct lb_string *rec; - size_t len; - rec = (struct lb_string *)lb_new_record(header); - len = strlen((char *)strings[i].string); - rec->tag = strings[i].tag; - rec->size = (sizeof(*rec) + len + 1 + 3) & ~3; - memcpy(rec->string, strings[i].string, len+1); - } - -} - -static void lb_memory_range(struct lb_memory *mem, - u32 type, u64 start, u64 size) -{ - int entries; - - printk(BIOS_DEBUG, "%s: start 0x%llx size 0x%llx\n", - __func__, start, size); - - entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); - mem->map[entries].start = pack_lb64(start); - mem->map[entries].size = pack_lb64(size); - mem->map[entries].type = type; - mem->size += sizeof(mem->map[0]); -} - -static void lb_reserve_table_memory(struct lb_header *head) -{ - struct lb_record *last_rec; - struct lb_memory *mem; - u64 start; - u64 end; - int i, entries; - - last_rec = lb_last_record(head); - mem = get_lb_mem(); - start = (unsigned long)head; - end = (unsigned long)last_rec; - entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); - /* Resize the right two memory areas so this table is in - * a reserved area of memory. Everything has been carefully - * setup so that is all we need to do. - */ - for(i = 0; i < entries; i++ ) { - u64 map_start = unpack_lb64(mem->map[i].start); - u64 map_end = map_start + unpack_lb64(mem->map[i].size); - /* Does this area need to be expanded? */ - if (map_end == start) { - mem->map[i].size = pack_lb64(end - map_start); - } - /* Does this area need to be contracted? */ - else if (map_start == start) { - mem->map[i].start = pack_lb64(end); - mem->map[i].size = pack_lb64(map_end - end); - } - } -} - -unsigned long lb_table_fini(struct lb_header *head) -{ - struct lb_record *rec, *first_rec; - rec = lb_last_record(head); - if (head->table_entries) { - head->table_bytes += rec->size; - } - lb_reserve_table_memory(head); - first_rec = lb_first_record(head); - head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes); - head->header_checksum = 0; - head->header_checksum = compute_ip_checksum(head, sizeof(*head)); - printk(BIOS_DEBUG,"Wrote coreboot table at: %p - %p checksum %x\n", - head, rec, head->table_checksum); - return (unsigned long)rec; -} - -static void lb_cleanup_memory_ranges(struct lb_memory *mem) -{ - int entries; - int i, j; - entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); - printk(BIOS_DEBUG, "%s: # entries %d\n", __func__, entries); - for(i = 0; i < entries; i++) - printk(BIOS_INFO, " #%d: base 0x%08x size 0x%x\n", - i, mem->map[i].start.lo, mem->map[i].size.lo); - - /* Sort the lb memory ranges */ - for(i = 0; i < entries; i++) { - u64 entry_start = unpack_lb64(mem->map[i].start); - for(j = i; j < entries; j++) { - u64 temp_start = unpack_lb64(mem->map[j].start); - if (temp_start < entry_start) { - struct lb_memory_range tmp; - tmp = mem->map[i]; - mem->map[i] = mem->map[j]; - mem->map[j] = tmp; - } - } - } - - /* Merge adjacent entries */ - for(i = 0; (i + 1) < entries; i++) { - u64 start, end, nstart, nend; - if (mem->map[i].type != mem->map[i + 1].type) { - continue; - } - start = unpack_lb64(mem->map[i].start); - end = start + unpack_lb64(mem->map[i].size); - nstart = unpack_lb64(mem->map[i + 1].start); - nend = nstart + unpack_lb64(mem->map[i + 1].size); - if ((start <= nstart) && (end > nstart)) { - if (start > nstart) { - start = nstart; - } - if (end < nend) { - end = nend; - } - /* Record the new region size */ - mem->map[i].start = pack_lb64(start); - mem->map[i].size = pack_lb64(end - start); - - /* Delete the entry I have merged with */ - memmove(&mem->map[i + 1], &mem->map[i + 2], - ((entries - i - 2) * sizeof(mem->map[0]))); - mem->size -= sizeof(mem->map[0]); - entries -= 1; - /* See if I can merge with the next entry as well */ - i -= 1; - } - } -} - -static void lb_remove_memory_range(struct lb_memory *mem, - u64 start, u64 size) -{ - u64 end; - int entries; - int i; - - end = start + size; - entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); - - /* Remove a reserved area from the memory map */ - for(i = 0; i < entries; i++) { - u64 map_start = unpack_lb64(mem->map[i].start); - u64 map_end = map_start + unpack_lb64(mem->map[i].size); - if ((start <= map_start) && (end >= map_end)) { - /* Remove the completely covered range */ - memmove(&mem->map[i], &mem->map[i + 1], - ((entries - i - 1) * sizeof(mem->map[0]))); - mem->size -= sizeof(mem->map[0]); - entries -= 1; - - /* Since the index will disappear - * revisit what will appear here - */ - i -= 1; - } - else if ((start > map_start) && (end < map_end)) { - /* Split the memory range */ - memmove(&mem->map[i + 1], &mem->map[i], - ((entries - i) * sizeof(mem->map[0]))); - mem->size += sizeof(mem->map[0]); - entries += 1; - /* Update the first map entry */ - mem->map[i].size = pack_lb64(start - map_start); - /* Update the second map entry */ - mem->map[i + 1].start = pack_lb64(end); - mem->map[i + 1].size = pack_lb64(map_end - end); - /* Don't bother with this map entry again */ - i += 1; - } - else if ((start <= map_start) && (end > map_start)) { - /* Shrink the start of the memory range */ - mem->map[i].start = pack_lb64(end); - mem->map[i].size = pack_lb64(map_end - end); - } - else if ((start < map_end) && (start > map_start)) { - /* Shrink the end of the memory range */ - mem->map[i].size = pack_lb64(start - map_start); - } - } -} - -static void lb_add_memory_range(struct lb_memory *mem, - u32 type, u64 start, u64 size) -{ - lb_remove_memory_range(mem, start, size); - lb_memory_range(mem, type, start, size); - lb_cleanup_memory_ranges(mem); -} - -/* Routines to extract part so the coreboot table or - * information from the coreboot table after we have written it. - * Currently get_lb_mem relies on a global we can change the - * implementaiton. - */ -static struct lb_memory *mem_ranges = 0; -struct lb_memory *get_lb_mem(void) -{ - return mem_ranges; -} - -static void build_lb_mem_range(void *gp, struct device *dev, struct resource *res) -{ - struct lb_memory *mem = gp; - lb_memory_range(mem, LB_MEM_RAM, res->base, res->size); -} - -static struct lb_memory *build_lb_mem(struct lb_header *head) -{ - struct lb_memory *mem; - - /* Record where the lb memory ranges will live */ - mem = lb_memory(head); - mem_ranges = mem; - - /* Build the raw table of memory */ - search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, - IORESOURCE_MEM | IORESOURCE_CACHEABLE, build_lb_mem_range, mem); - - lb_cleanup_memory_ranges(mem); - return mem; -} - -/** - * Add pointer to device tree to coreboot table. - * - * @param head Pointer to lbtable header. - * @return TODO - */ -struct lb_devtree *lb_devtree(struct lb_header *head) -{ - struct lb_devtree *lbdev = NULL; - - lbdev = (struct lb_devtree *)lb_new_record(head); - lbdev->tag = LB_TAG_DEVTREE_PTR; - lbdev->size = sizeof(*lbdev); - lbdev->dev_root_ptr = (u32)&dev_root; // XXX ouch. - - // FIXME we should either copy the device tree completely - // or at least mark it reserved. - return lbdev; -} - -unsigned long write_coreboot_table( - unsigned long low_table_start, unsigned long low_table_end, - unsigned long rom_table_start, unsigned long rom_table_end) -{ - struct lb_header *head; - struct lb_memory *mem; - struct lb_record *rec_dest, *rec_src; - - 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; - } - - /* Write the option config table... */ - - rec_src = (struct lb_record *)(void *)get_option_table(); - if (rec_src != NULL) { - rec_dest = lb_new_record(head); - - memcpy(rec_dest, rec_src, rec_src->size); - /* Create cmos checksum entry in coreboot table */ - lb_cmos_checksum(head); - } - - /* Record where RAM is located */ - mem = build_lb_mem(head); - - /* Record the mptable and the the lb_table (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 coreboot table. - * I can trivially fixup the reserved memory ranges to hold the correct - * size of the coreboot table. - */ - - /* Record our motherboard */ - lb_mainboard(head); - - /* Record our various random string information */ - lb_strings(head); - - /* Record a pointer to the coreboot device tree */ - lb_devtree(head); - - /* Remember where my valid memory ranges are */ - return lb_table_fini(head); - -}