coreboot-v2/src/lib/cbmem.c
<<
>>
Prefs
   1/*
   2 * This file is part of the coreboot project.
   3 *
   4 * Copyright (C) 2009 coresystems GmbH
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; version 2 of the License.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
  18 */
  19
  20#include <types.h>
  21#include <string.h>
  22#include <cbmem.h>
  23#include <console/console.h>
  24
  25#if 1
  26#define debug(x...) printk_debug(x)
  27#else
  28#define debug(x...)
  29#endif
  30
  31// The CBMEM TOC reserves 512 bytes to keep
  32// the other entries somewhat aligned.
  33// Increase if MAX_CBMEM_ENTRIES exceeds 21
  34#define CBMEM_TOC_RESERVED      512
  35#define MAX_CBMEM_ENTRIES       16
  36#define CBMEM_MAGIC             0x434f5245
  37
  38static void *cbmem_base;
  39static int cbmem_size;
  40
  41struct cbmem_entry {
  42        u32 magic;
  43        u32 id;
  44        u64 base;
  45        u64 size;
  46} __attribute__((packed));
  47
  48#ifndef __ROMCC__
  49struct cbmem_entry *bss_cbmem_toc;
  50#endif
  51
  52/**
  53 * cbmem is a simple mechanism to do some kind of book keeping of the coreboot
  54 * high tables memory. This is a small amount of memory which is "stolen" from
  55 * the system memory for coreboot purposes. Usually this memory is used for
  56 *  - the coreboot table
  57 *  - legacy tables (PIRQ, MP table)
  58 *  - ACPI tables
  59 *  - suspend/resume backup memory
  60 */
  61
  62void cbmem_init(u64 baseaddr, u64 size)
  63{
  64        struct cbmem_entry *cbmem_toc;
  65        cbmem_toc = (struct cbmem_entry *)(unsigned long)baseaddr;
  66
  67#ifndef __ROMCC__
  68        bss_cbmem_toc = cbmem_toc;
  69#endif
  70        
  71        debug("Initializing CBMEM area to 0x%llx (%lld bytes)\n", baseaddr, size);
  72
  73        if (size < (64 * 1024)) {
  74                debug("Increase CBMEM size!!\n");
  75                for (;;) ;
  76        }
  77
  78        memset(cbmem_toc, 0, CBMEM_TOC_RESERVED);
  79
  80        cbmem_toc[0] = (struct cbmem_entry) {
  81                .magic  = CBMEM_MAGIC,
  82                .id     = CBMEM_ID_FREESPACE,
  83                .base   = baseaddr + CBMEM_TOC_RESERVED,
  84                .size   = size - CBMEM_TOC_RESERVED
  85        };
  86}
  87
  88int cbmem_reinit(u64 baseaddr)
  89{
  90        struct cbmem_entry *cbmem_toc;
  91        cbmem_toc = (struct cbmem_entry *)(unsigned long)baseaddr;
  92
  93        debug("Re-Initializing CBMEM area to 0x%lx\n", (unsigned long)baseaddr);
  94#ifndef __ROMCC__
  95        bss_cbmem_toc = cbmem_toc;
  96#endif
  97
  98        return (cbmem_toc[0].magic == CBMEM_MAGIC);
  99}
 100
 101void *cbmem_add(u32 id, u64 size)
 102{
 103        struct cbmem_entry *cbmem_toc;
 104        int i;
 105#ifdef __ROMCC__
 106         cbmem_toc = (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE);
 107#else
 108         cbmem_toc = bss_cbmem_toc;
 109#endif
 110        
 111        if (cbmem_toc == NULL) {
 112                return NULL;
 113        }
 114
 115        if (cbmem_toc[0].magic != CBMEM_MAGIC) {
 116                printk_err("ERROR: CBMEM was not initialized yet.\n");
 117                return NULL;
 118        }
 119
 120        /* Will the entry fit at all? */
 121        if (size > cbmem_toc[0].size) {
 122                printk_err("ERROR: Not enough memory for table %x\n", id);
 123                return NULL;
 124        }
 125
 126        /* Align size to 512 byte blocks */
 127
 128        size = ALIGN(size, 512) < cbmem_toc[0].size ? 
 129                ALIGN(size, 512) : cbmem_toc[0].size;
 130
 131        /* Now look for the first free/usable TOC entry */
 132        for (i = 0; i < MAX_CBMEM_ENTRIES; i++) {
 133                if (cbmem_toc[i].id == CBMEM_ID_NONE)
 134                        break;
 135        }
 136
 137        if (i >= MAX_CBMEM_ENTRIES) {
 138                printk_err("ERROR: No more CBMEM entries available.\n");
 139                return NULL;
 140        }
 141
 142        debug("Adding CBMEM entry as no. %d\n", i);
 143
 144        cbmem_toc[i] = (struct cbmem_entry) {
 145                .magic = CBMEM_MAGIC,
 146                .id     = id,
 147                .base   = cbmem_toc[0].base,
 148                .size   = size
 149        };
 150
 151        cbmem_toc[0].base += size;
 152        cbmem_toc[0].size -= size;
 153
 154        return (void *)cbmem_toc[i].base;
 155}
 156
 157void *cbmem_find(u32 id)
 158{
 159        struct cbmem_entry *cbmem_toc;
 160        int i;
 161#ifdef __ROMCC__
 162         cbmem_toc = (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE);
 163#else
 164         cbmem_toc = bss_cbmem_toc;
 165#endif
 166        
 167        if (cbmem_toc == NULL)
 168                return NULL;
 169
 170        for (i = 0; i < MAX_CBMEM_ENTRIES; i++) {
 171                if (cbmem_toc[i].id == id)
 172                        return (void *)(unsigned long)cbmem_toc[i].base;
 173        }
 174
 175        return (void *)NULL;
 176}
 177
 178#ifndef __ROMCC__
 179#if CONFIG_HAVE_ACPI_RESUME
 180extern u8 acpi_slp_type;
 181#endif
 182extern uint64_t high_tables_base, high_tables_size;
 183
 184void cbmem_initialize(void)
 185{
 186#if CONFIG_HAVE_ACPI_RESUME
 187        if (acpi_slp_type == 3) {
 188                if (!cbmem_reinit(high_tables_base)) {
 189                        /* Something went wrong, our high memory area got wiped */
 190                        acpi_slp_type == 0;
 191                        cbmem_init(high_tables_base, high_tables_size);
 192                }
 193        } else {
 194                cbmem_init(high_tables_base, high_tables_size);
 195        }
 196#else
 197        cbmem_init(high_tables_base, high_tables_size);
 198#endif
 199        cbmem_arch_init();
 200}
 201
 202#ifndef __ROMCC__
 203void cbmem_list(void)
 204{
 205        struct cbmem_entry *cbmem_toc;
 206        int i;
 207#ifdef __ROMCC__
 208         cbmem_toc = (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE);
 209#else
 210         cbmem_toc = bss_cbmem_toc;
 211#endif
 212        
 213        if (cbmem_toc == NULL)
 214                return;
 215
 216        for (i = 0; i < MAX_CBMEM_ENTRIES; i++) {
 217
 218                if (cbmem_toc[i].magic != CBMEM_MAGIC)
 219                        continue;
 220                printk_debug("%2d. ", i);
 221                switch (cbmem_toc[i].id) {
 222                case CBMEM_ID_FREESPACE: printk_debug("FREE SPACE "); break;
 223                case CBMEM_ID_GDT:       printk_debug("GDT        "); break;
 224                case CBMEM_ID_ACPI:      printk_debug("ACPI       "); break;
 225                case CBMEM_ID_CBTABLE:   printk_debug("COREBOOT   "); break;
 226                case CBMEM_ID_PIRQ:      printk_debug("IRQ TABLE  "); break;
 227                case CBMEM_ID_MPTABLE:   printk_debug("SMP TABLE  "); break;
 228                case CBMEM_ID_RESUME:    printk_debug("ACPI RESUME"); break;
 229                default: printk_debug("%08x ", cbmem_toc[i].id);
 230                }
 231                printk_debug("%08llx ", cbmem_toc[i].base);
 232                printk_debug("%08llx\n", cbmem_toc[i].size);
 233        }
 234}
 235#endif
 236
 237#endif
 238
 239
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.