From: Kevin O'Connor Date: Mon, 9 Jun 2008 03:09:42 +0000 (-0400) Subject: Enhance e820 memory map generation - include files missing from last commit. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=59a23bb0f8d2c1a44206de3fd1571f17858492ab;p=seabios.git Enhance e820 memory map generation - include files missing from last commit. --- diff --git a/src/coreboot.c b/src/coreboot.c new file mode 100644 index 0000000..b040640 --- /dev/null +++ b/src/coreboot.c @@ -0,0 +1,136 @@ +// Coreboot interface support. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "memmap.h" // add_e820 +#include "util.h" // dprintf + + +/**************************************************************** + * Memory interface + ****************************************************************/ + +struct cb_header { + u32 signature; + u32 header_bytes; + u32 header_checksum; + u32 table_bytes; + u32 table_checksum; + u32 table_entries; +}; + +#define CB_SIGNATURE 0x4f49424C // "LBIO" + +struct cb_memory_range { + u64 start; + u64 size; + u32 type; +}; + +#define CB_MEM_TABLE 16 + +struct cb_memory { + u32 tag; + u32 size; + struct cb_memory_range map[0]; +}; + +#define CB_TAG_MEMORY 0x01 + +#define MEM_RANGE_COUNT(_rec) \ + (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0])) + +static u16 +ipchksum(char *buf, int count) +{ + u16 *p = (u16*)buf; + u32 sum = 0; + while (count > 1) { + sum += *p++; + count -= 2; + } + if (count) + sum += *(u8*)p; + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return ~sum; +} + +// Try to locate the coreboot header in a given address range. +static struct cb_header * +find_cb_header(char *addr, int len) +{ + char *end = addr + len; + for (; addr < end; addr += 16) { + struct cb_header *cbh = (struct cb_header *)addr; + if (cbh->signature != CB_SIGNATURE) + continue; + dprintf(1, "sig %p=%x\n", addr, cbh->signature); + if (! cbh->table_bytes) + continue; + if (ipchksum(addr, sizeof(*cbh)) != 0) + continue; + if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes) + != cbh->table_checksum) + continue; + return cbh; + } + return NULL; +} + +// Try to find the coreboot memory table in the given coreboot table. +static struct cb_memory * +find_cb_memory(struct cb_header *cbh) +{ + char *tbl = (char *)cbh + sizeof(*cbh); + int i; + for (i=0; itable_entries; i++) { + struct cb_memory *cbm = (struct cb_memory *)tbl; + tbl += cbm->size; + if (cbm->tag == CB_TAG_MEMORY) + return cbm; + } + return NULL; +} + +// Populate max ram and e820 map info by scanning for a coreboot table. +void +coreboot_fill_map() +{ + dprintf(3, "Attempting to find coreboot table\n"); + struct cb_header *cbh = find_cb_header(0, 0x1000); + if (!cbh) + goto fail; + struct cb_memory *cbm = find_cb_memory(cbh); + if (!cbm) + goto fail; + + u64 maxram = 0; + int i, count = MEM_RANGE_COUNT(cbm); + for (i=0; imap[i]; + u32 type = m->type; + if (type == CB_MEM_TABLE) + type = E820_RESERVED; + if ((type == E820_ACPI || type == E820_RAM) + && (m->start + m->size) > maxram) + maxram = m->start + m->size; + add_e820(m->start, m->size, type); + } + + // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this + // confuses grub. So, override it. + add_e820(0, 16*1024, E820_RAM); + + SET_EBDA(ram_size, maxram); + return; + +fail: + // No table found.. Use 16Megs as a dummy value. + dprintf(1, "Unable to find coreboot table!\n"); + SET_EBDA(ram_size, 16*1024*1024); + add_e820(0, 16*1024*1024, E820_RAM); + return; +} diff --git a/src/memmap.c b/src/memmap.c new file mode 100644 index 0000000..e7ebc2a --- /dev/null +++ b/src/memmap.c @@ -0,0 +1,138 @@ +// Support for building memory maps suitable for int 15 e820 calls. +// +// Copyright (C) 2008 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "memmap.h" // struct e820entry +#include "util.h" // dprintf.h + +// Temporary storage used during map building. +static struct e820entry e820_list[64]; +static int e820_count; + +// Remove an entry from the e820_list. +static void +remove_e820(int i) +{ + e820_count--; + memmove(&e820_list[i], &e820_list[i+1] + , sizeof(e820_list[0]) * (e820_count - i)); +} + +// Insert an entry in the e820_list at the given position. +static void +insert_e820(int i, u64 start, u64 size, u32 type) +{ + if (e820_count >= ARRAY_SIZE(e820_list)) { + dprintf(1, "Overflowed e820 list!\n"); + return; + } + + memmove(&e820_list[i+1], &e820_list[i] + , sizeof(e820_list[0]) * (e820_count - i)); + e820_count++; + struct e820entry *e = &e820_list[i]; + e->start = start; + e->size = size; + e->type = type; +} + +// Show the current e820_list. +static void +dump_map() +{ + dprintf(1, "e820 map has %d items:\n", e820_count); + int i; + for (i=0; istart + e->size; + dprintf(1, " %d: %x%x - %x%x = %d\n", i + , (u32)(e->start >> 32), (u32)e->start + , (u32)(e_end >> 32), (u32)e_end + , e->type); + } +} + +// Add a new entry to the list. This scans for overlaps and keeps the +// list sorted. +void +add_e820(u64 start, u64 size, u32 type) +{ + dprintf(8, "Add to e820 map: %x %x %d\n", (u32)start, (u32)size, type); + + if (! size) + // Huh? Nothing to do. + return; + + u64 end = start + size; + int i; + for (i=0; istart) + // Simple insertion point. + break; + u64 e_end = e->start + e->size; + if (start >= e_end) + // No overlap. + continue; + // New item overlaps with an existing one. + if (start > e->start) { + e->size = start - e->start; + i++; + if (end < e_end) + // Need to split existing item + insert_e820(i, end, e_end - end, e->type); + } + insert_e820(i, start, size, type); + i++; + // Remove all existing items that are completely overlapped. + while (istart) + break; + e_end = e->start + e->size; + if (end < e_end) { + // Existing item not completely overlapped - adjust its start. + e->start = end; + e->size = e_end - e->start; + break; + } + remove_e820(i); + } + //dump_map(); + return; + } + // Just insert item. + insert_e820(i, start, size, type); + //dump_map(); +} + +u32 bios_table_cur_addr, bios_table_end_addr; + +// Prep for memmap stuff - init bios table locations. +void +memmap_setup() +{ + bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start; + bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end; + dprintf(1, "bios_table_addr: 0x%08x end=0x%08x\n", + bios_table_cur_addr, bios_table_end_addr); +} + +// Copy the temporary e820 map info to its permanent location. +void +memmap_finalize() +{ + dump_map(); + + u32 msize = e820_count * sizeof(e820_list[0]); + if (bios_table_cur_addr + msize > bios_table_end_addr) { + dprintf(1, "No room for e820 map!\n"); + return; + } + memcpy((void*)bios_table_cur_addr, e820_list, msize); + SET_EBDA(e820_loc, bios_table_cur_addr); + SET_EBDA(e820_count, e820_count); + bios_table_cur_addr += msize; +} diff --git a/src/memmap.h b/src/memmap.h new file mode 100644 index 0000000..c0cdca5 --- /dev/null +++ b/src/memmap.h @@ -0,0 +1,25 @@ +#ifndef __E820MAP_H +#define __E820MAP_H + +#include "types.h" // u64 + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +struct e820entry { + u64 start; + u64 size; + u32 type; +}; + +void add_e820(u64 start, u64 size, u32 type); +void memmap_setup(); +void memmap_finalize(); + +// Space for exported bios tables. +extern u32 bios_table_cur_addr, bios_table_end_addr; + +#endif // e820map.h