[coreboot-gerrit] Patch set updated for coreboot: bd1ad9e DO NOT MERGE: include: Missing files

Leroy P Leahy (leroy.p.leahy@intel.com) gerrit at coreboot.org
Wed May 6 01:28:39 CEST 2015


Leroy P Leahy (leroy.p.leahy at intel.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10053

-gerrit

commit bd1ad9e417db4a4bcad8870d76d522d043caca2f
Author: Lee Leahy <leroy.p.leahy at intel.com>
Date:   Mon Apr 20 15:40:12 2015 -0700

    DO NOT MERGE: include: Missing files
    
    Add files from Google tree.
    
    BRANCH=none
    BUG=None
    TEST=None
    
    Change-Id: I1ff28c3019ecb1a801ad601fc91e2dccbd89259c
    Signed-off-by: Lee Leahy <leroy.p.leahy at intel.com>
---
 src/include/cpu/x86/stack.h  |  32 +++
 src/include/ramstage_cache.h |  53 +++++
 src/include/uart.h           |  44 ++++
 src/include/uart8250.h       | 148 +++++++++++++
 src/lib/dynamic_cbmem.c      | 483 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 760 insertions(+)

diff --git a/src/include/cpu/x86/stack.h b/src/include/cpu/x86/stack.h
new file mode 100644
index 0000000..158b670
--- /dev/null
+++ b/src/include/cpu/x86/stack.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 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
+ */
+
+#ifndef __CPU_X86_STACK_H
+#define __CPU_X86_STACK_H
+
+/* For now: use CONFIG_RAMBASE + 1MB - 64K (counting downwards) as stack. This
+ * makes sure that we stay completely within the 1M-64K of memory that we
+ * preserve for suspend/resume. This is basically HIGH_MEMORY_SAFE (see
+ * cbmem.h)
+ */
+
+#define ROMSTAGE_STACK_OFFSET ( (1024 - 64) * 1024 )
+#define ROMSTAGE_STACK	(CONFIG_RAMBASE + ROMSTAGE_STACK_OFFSET)
+
+#endif
diff --git a/src/include/ramstage_cache.h b/src/include/ramstage_cache.h
new file mode 100644
index 0000000..8d9b095
--- /dev/null
+++ b/src/include/ramstage_cache.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ *
+ * 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
+ */
+
+#ifndef _RAMSTAGE_CACHE_
+#define _RAMSTAGE_CACHE_
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* This structure is saved along with the relocated ramstage program when
+ * CONFIG_RELOCATED_RAMSTAGE is employed.  For x86, it can used to protect
+ * the integrity of the ramstage program on S3 resume by saving a copy of
+ * the relocated ramstage in SMM space with the assumption that the SMM region
+ * cannot be altered from the OS. The magic value just serves as a quick sanity
+ * check. */
+
+#define RAMSTAGE_CACHE_MAGIC 0xf3c3a02a
+
+struct ramstage_cache {
+	uint32_t magic;
+	uint32_t entry_point;
+	uint32_t load_address;
+	uint32_t size;
+	char program[0];
+} __attribute__((packed));
+
+/* Chipset/Board function for obtaining cache location and size. */
+struct ramstage_cache *ramstage_cache_location(long *size);
+/* Chipset/Board function called when cache is invalid on resume. */
+void ramstage_cache_invalid(struct ramstage_cache *cache);
+
+static inline int ramstage_cache_is_valid(const struct ramstage_cache *c)
+{
+	return (c != NULL && c->magic == RAMSTAGE_CACHE_MAGIC);
+}
+
+#endif  /* _RAMSTAGE_CACHE_ */
diff --git a/src/include/uart.h b/src/include/uart.h
new file mode 100644
index 0000000..9b6236a
--- /dev/null
+++ b/src/include/uart.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The ChromiumOS Authors.  All rights reserved.
+ *
+ * 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
+ */
+
+/* madness. Uarts are a mess. If you include this file, it
+ * includes ALL uart implementations which may be needed.
+ * No need to include them separately, and include this file FIRST.
+ * At least one (but at most one) of the files needs to define
+ * uart_init().
+ */
+#ifndef UART_H
+#define UART_H
+
+#include <stdint.h>
+
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL8250) || IS_ENABLED(CONFIG_CONSOLE_SERIAL8250MEM)
+#include <uart8250.h>
+#endif
+
+unsigned char uart_rx_byte(void);
+void uart_tx_byte(unsigned char data);
+void uart_tx_flush(void);
+void uart_init(void);
+int uart_can_rx_byte(void);
+
+uint32_t uartmem_getbaseaddr(void);
+uint32_t uartmem_getregwidth(void);
+
+#endif /* UART_H */
diff --git a/src/include/uart8250.h b/src/include/uart8250.h
new file mode 100644
index 0000000..cfbd619
--- /dev/null
+++ b/src/include/uart8250.h
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2003 Eric Biederman
+ *
+ * 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
+ */
+
+#ifndef __UART8250_H__
+#define __UART8250_H__
+
+#include <uart.h>
+
+/* Data */
+#define UART8250_RBR 0x00
+#define UART8250_TBR 0x00
+
+/* Control */
+#define UART8250_IER 0x01
+#define   UART8250_IER_MSI	0x08 /* Enable Modem status interrupt */
+#define   UART8250_IER_RLSI	0x04 /* Enable receiver line status interrupt */
+#define   UART8250_IER_THRI	0x02 /* Enable Transmitter holding register int. */
+#define   UART8250_IER_RDI	0x01 /* Enable receiver data interrupt */
+
+#define UART8250_IIR 0x02
+#define   UART8250_IIR_NO_INT	0x01 /* No interrupts pending */
+#define   UART8250_IIR_ID	0x06 /* Mask for the interrupt ID */
+
+#define   UART8250_IIR_MSI	0x00 /* Modem status interrupt */
+#define   UART8250_IIR_THRI	0x02 /* Transmitter holding register empty */
+#define   UART8250_IIR_RDI	0x04 /* Receiver data interrupt */
+#define   UART8250_IIR_RLSI	0x06 /* Receiver line status interrupt */
+
+#define UART8250_FCR 0x02
+#define   UART8250_FCR_FIFO_EN		0x01 /* Fifo enable */
+#define   UART8250_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
+#define   UART8250_FCR_CLEAR_XMIT	0x04 /* Clear the XMIT FIFO */
+#define   UART8250_FCR_DMA_SELECT	0x08 /* For DMA applications */
+#define   UART8250_FCR_TRIGGER_MASK	0xC0 /* Mask for the FIFO trigger range */
+#define   UART8250_FCR_TRIGGER_1	0x00 /* Mask for trigger set at 1 */
+#define   UART8250_FCR_TRIGGER_4	0x40 /* Mask for trigger set at 4 */
+#define   UART8250_FCR_TRIGGER_8	0x80 /* Mask for trigger set at 8 */
+#define   UART8250_FCR_TRIGGER_14	0xC0 /* Mask for trigger set at 14 */
+
+#define   UART8250_FCR_RXSR		0x02 /* Receiver soft reset */
+#define   UART8250_FCR_TXSR		0x04 /* Transmitter soft reset */
+
+#define UART8250_LCR 0x03
+#define   UART8250_LCR_WLS_MSK	0x03 /* character length select mask */
+#define   UART8250_LCR_WLS_5	0x00 /* 5 bit character length */
+#define   UART8250_LCR_WLS_6	0x01 /* 6 bit character length */
+#define   UART8250_LCR_WLS_7	0x02 /* 7 bit character length */
+#define   UART8250_LCR_WLS_8	0x03 /* 8 bit character length */
+#define   UART8250_LCR_STB	0x04 /* Number of stop Bits, off = 1, on = 1.5 or 2) */
+#define   UART8250_LCR_PEN	0x08 /* Parity eneble */
+#define   UART8250_LCR_EPS	0x10 /* Even Parity Select */
+#define   UART8250_LCR_STKP	0x20 /* Stick Parity */
+#define   UART8250_LCR_SBRK	0x40 /* Set Break */
+#define   UART8250_LCR_BKSE	0x80 /* Bank select enable */
+#define   UART8250_LCR_DLAB	0x80 /* Divisor latch access bit */
+
+#define UART8250_MCR 0x04
+#define   UART8250_MCR_DTR	0x01 /* DTR   */
+#define   UART8250_MCR_RTS	0x02 /* RTS   */
+#define   UART8250_MCR_OUT1	0x04 /* Out 1 */
+#define   UART8250_MCR_OUT2	0x08 /* Out 2 */
+#define   UART8250_MCR_LOOP	0x10 /* Enable loopback test mode */
+
+#define UART8250_MCR_DMA_EN	0x04
+#define UART8250_MCR_TX_DFR	0x08
+
+#define UART8250_DLL 0x00
+#define UART8250_DLM 0x01
+
+/* Status */
+#define UART8250_LSR 0x05
+#define   UART8250_LSR_DR	0x01 /* Data ready */
+#define   UART8250_LSR_OE	0x02 /* Overrun */
+#define   UART8250_LSR_PE	0x04 /* Parity error */
+#define   UART8250_LSR_FE	0x08 /* Framing error */
+#define   UART8250_LSR_BI	0x10 /* Break */
+#define   UART8250_LSR_THRE	0x20 /* Xmit holding register empty */
+#define   UART8250_LSR_TEMT	0x40 /* Xmitter empty */
+#define   UART8250_LSR_ERR	0x80 /* Error */
+
+#define UART8250_MSR 0x06
+#define   UART8250_MSR_DCD	0x80 /* Data Carrier Detect */
+#define   UART8250_MSR_RI	0x40 /* Ring Indicator */
+#define   UART8250_MSR_DSR	0x20 /* Data Set Ready */
+#define   UART8250_MSR_CTS	0x10 /* Clear to Send */
+#define   UART8250_MSR_DDCD	0x08 /* Delta DCD */
+#define   UART8250_MSR_TERI	0x04 /* Trailing edge ring indicator */
+#define   UART8250_MSR_DDSR	0x02 /* Delta DSR */
+#define   UART8250_MSR_DCTS	0x01 /* Delta CTS */
+
+#define UART8250_SCR 0x07
+#define UART8250_SPR 0x07
+
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL)
+#if ((115200 % CONFIG_TTYS0_BAUD) != 0)
+#error Bad ttyS0 baud rate
+#endif
+#endif
+
+/* Line Control Settings */
+#define UART8250_LCS	CONFIG_TTYS0_LCS
+
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL8250)
+unsigned char uart8250_rx_byte(unsigned base_port);
+int uart8250_can_rx_byte(unsigned base_port);
+void uart8250_tx_byte(unsigned base_port, unsigned char data);
+void uart8250_tx_flush(unsigned base_port);
+/* Yes it is silly to have three different uart init functions. But we used to
+ * have three different sets of uart code, so it's an improvement.
+ */
+void uart8250_init(unsigned base_port, unsigned divisor);
+#endif
+#if IS_ENABLED(CONFIG_CONSOLE_SERIAL8250MEM)
+void uartmem_init(void);
+
+/* and the same for memory mapped uarts */
+unsigned char uart8250_mem_rx_byte(unsigned base_port);
+int uart8250_mem_can_rx_byte(unsigned base_port);
+void uart8250_mem_tx_byte(unsigned base_port, unsigned char data);
+void uart8250_mem_tx_flush(unsigned base_port);
+void uart8250_mem_init(unsigned base_port, unsigned divisor);
+u32 uart_mem_init(void);
+
+#if defined(__PRE_RAM__) && CONFIG_DRIVERS_OXFORD_OXPCIE
+/* and special init for OXPCIe based cards */
+extern int oxford_oxpcie_present;
+
+void oxford_init(void);
+#endif
+#endif
+
+#endif /* __UART8250_H__ */
diff --git a/src/lib/dynamic_cbmem.c b/src/lib/dynamic_cbmem.c
new file mode 100644
index 0000000..c3c6d2a
--- /dev/null
+++ b/src/lib/dynamic_cbmem.c
@@ -0,0 +1,483 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * 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 wacbmem_entryanty 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 <bootstate.h>
+#include <boot/tables.h>
+#include <console/console.h>
+#include <cbmem.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arch/early_variables.h>
+#if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__)
+#include <arch/acpi.h>
+#endif
+#include <timestamp.h>
+
+#ifndef UINT_MAX
+#define UINT_MAX 4294967295U
+#endif
+
+/* ACPI resume needs to be cleared in the fail-to-recover case, but that
+ * condition is only handled during ramstage. */
+#if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__)
+static inline void cbmem_handle_acpi_resume(void)
+{
+	/* Something went wrong, our high memory area got wiped */
+	if (acpi_slp_type == 3 || acpi_slp_type == 2)
+		acpi_slp_type = 0;
+}
+#else
+static inline void cbmem_handle_acpi_resume(void) {}
+#endif
+
+/*
+ * The dynamic cbmem code uses a root region. The root region boundary
+ * addresses are determined by cbmem_top() and ROOT_MIN_SIZE. Just below
+ * the address returned by cbmem_top() is a pointer that points to the
+ * root data structure. The root data structure provides the book keeping
+ * for each large entry.
+ */
+
+/* The root region is at least DYN_CBMEM_ALIGN_SIZE . */
+#define ROOT_MIN_SIZE DYN_CBMEM_ALIGN_SIZE
+#define CBMEM_POINTER_MAGIC 0xc0389479
+#define CBMEM_ENTRY_MAGIC ~(CBMEM_POINTER_MAGIC)
+
+/* The cbmem_root_pointer structure lives just below address returned
+ * from cbmem_top(). It points to the root data structure that
+ * maintains the entries. */
+struct cbmem_root_pointer {
+	u32 magic;
+	u32 root;
+} __attribute__((packed));
+
+struct cbmem_entry {
+	u32 magic;
+	u32 start;
+	u32 size;
+	u32 id;
+} __attribute__((packed));
+
+struct cbmem_root {
+	u32 max_entries;
+	u32 num_entries;
+	u32 locked;
+	u32 size;
+	struct cbmem_entry entries[0];
+} __attribute__((packed));
+
+
+static inline void *cbmem_top_cached(void)
+{
+#if !defined(__PRE_RAM__)
+	static void *cached_cbmem_top;
+
+	if (cached_cbmem_top == NULL)
+		cached_cbmem_top = cbmem_top();
+
+	return cached_cbmem_top;
+#else
+	return cbmem_top();
+#endif
+}
+
+static inline void *get_top_aligned(void)
+{
+	unsigned long top;
+
+	/* Align down what is returned from cbmem_top(). */
+	top = (unsigned long)cbmem_top_cached();
+	top &= ~(DYN_CBMEM_ALIGN_SIZE - 1);
+
+	return (void *)top;
+}
+
+static inline void *get_root(void)
+{
+	unsigned long pointer_addr;
+	struct cbmem_root_pointer *pointer;
+
+	pointer_addr = (unsigned long)get_top_aligned();
+	pointer_addr -= sizeof(struct cbmem_root_pointer);
+
+	pointer = (void *)pointer_addr;
+	if (pointer->magic != CBMEM_POINTER_MAGIC)
+		return NULL;
+
+	return (void *)(uintptr_t)pointer->root;
+}
+
+static inline void cbmem_entry_assign(struct cbmem_entry *entry,
+                                      u32 id, u32 start, u32 size)
+{
+	entry->magic = CBMEM_ENTRY_MAGIC;
+	entry->start = start;
+	entry->size = size;
+	entry->id = id;
+}
+
+static inline const struct cbmem_entry *
+cbmem_entry_append(struct cbmem_root *root, u32 id, u32 start, u32 size)
+{
+	struct cbmem_entry *cbmem_entry;
+
+	cbmem_entry = &root->entries[root->num_entries];
+	root->num_entries++;
+
+	cbmem_entry_assign(cbmem_entry, id, start, size);
+
+	return cbmem_entry;
+}
+
+void cbmem_initialize_empty(void)
+{
+	cbmem_initialize_empty_id_size(0, 0);
+}
+
+void cbmem_initialize_empty_id_size(u32 id, u64 size)
+{
+	void *area;
+	unsigned long pointer_addr;
+	unsigned long root_addr;
+	unsigned long max_entries;
+	struct cbmem_root *root;
+	struct cbmem_root_pointer *pointer;
+
+	/* Place the root pointer and the root. The number of entries is
+	 * dictated by difference between the root address and the pointer
+	 * where the root address is aligned down to
+	 * DYN_CBMEM_ALIGN_SIZE. The pointer falls just below the
+	 * address returned by get_top_aligned(). */
+	pointer_addr = (unsigned long)get_top_aligned();
+	root_addr = pointer_addr - ROOT_MIN_SIZE;
+	root_addr &= ~(DYN_CBMEM_ALIGN_SIZE - 1);
+	pointer_addr -= sizeof(struct cbmem_root_pointer);
+
+	max_entries = (pointer_addr - (root_addr + sizeof(*root))) /
+	              sizeof(struct cbmem_entry);
+
+	pointer = (void *)pointer_addr;
+	pointer->magic = CBMEM_POINTER_MAGIC;
+	pointer->root = root_addr;
+
+	root = (void *)root_addr;
+	root->max_entries = max_entries;
+	root->num_entries = 0;
+	root->locked = 0;
+	root->size = pointer_addr - root_addr +
+	             sizeof(struct cbmem_root_pointer);
+
+	/* Add an entry covering the root region. */
+	cbmem_entry_append(root, CBMEM_ID_ROOT, root_addr, root->size);
+
+	printk(BIOS_DEBUG, "CBMEM: root @ %p %d entries.\n",
+	       root, root->max_entries);
+
+	/* Add the specified range first */
+	if (size)
+		area = cbmem_add(id, size);
+
+	/* Allow other areas to be added */
+	cbmem_run_init_hooks();
+
+	/* Migrate cache-as-ram variables. */
+	car_migrate_variables();
+}
+
+static inline int cbmem_fail_recovery(u32 id, u64 size)
+{
+	cbmem_initialize_empty_id_size(id, size);
+	cbmem_handle_acpi_resume();
+	return 1;
+}
+
+static int validate_entries(struct cbmem_root *root)
+{
+	unsigned int i;
+	uintptr_t current_end;
+
+	current_end = (uintptr_t)get_top_aligned();
+
+	printk(BIOS_DEBUG, "CBMEM: recovering %d/%d entries from root @ %p\n",
+	       root->num_entries, root->max_entries, root);
+
+	/* Check that all regions are properly aligned and are just below
+	 * the previous entry */
+	for (i = 0; i < root->num_entries; i++) {
+		struct cbmem_entry *entry = &root->entries[i];
+
+		if (entry->magic != CBMEM_ENTRY_MAGIC)
+			return -1;
+
+		if (entry->start & (DYN_CBMEM_ALIGN_SIZE - 1))
+			return -1;
+
+		if (entry->start + entry->size != current_end)
+			return -1;
+
+		current_end = entry->start;
+	}
+
+	return 0;
+}
+
+int cbmem_initialize(void)
+{
+	return cbmem_initialize_id_size(0, 0);
+}
+
+int cbmem_initialize_id_size(u32 id, u64 size)
+{
+	void *area;
+	struct cbmem_root *root;
+	void *top_according_to_root;
+
+	root = get_root();
+
+	/* No recovery possible since root couldn't be recovered. */
+	if (root == NULL)
+		return cbmem_fail_recovery(id, size);
+
+	/* Sanity check the root. */
+	top_according_to_root = (void *)(root->size + (unsigned long)root);
+	if (get_top_aligned() != top_according_to_root)
+		return cbmem_fail_recovery(id, size);
+
+	if (root->num_entries > root->max_entries)
+		return cbmem_fail_recovery(id, size);
+
+	if ((root->max_entries * sizeof(struct cbmem_entry)) >
+	    (root->size - sizeof(struct cbmem_root_pointer) - sizeof(*root)))
+		return cbmem_fail_recovery(id, size);
+
+	/* Validate current entries. */
+	if (validate_entries(root))
+		return cbmem_fail_recovery(id, size);
+
+#if defined(__PRE_RAM__)
+	/* Lock the root in the romstage on a recovery. The assumption is that
+	 * recovery is called during romstage on the S3 resume path. */
+	root->locked = 1;
+#endif
+
+	/* Add the specified range first */
+	if (size)
+		area = cbmem_add(id, size);
+
+	/* Allow other areas to be added */
+	cbmem_run_init_hooks();
+
+	/* Migrate cache-as-ram variables. */
+	car_migrate_variables();
+
+	/* Recovery successful. */
+	return 0;
+}
+
+static void *cbmem_base(void)
+{
+	struct cbmem_root *root;
+	uintptr_t low_addr;
+
+	root = get_root();
+
+	if (root == NULL)
+		return NULL;
+
+	low_addr = (uintptr_t)root;
+
+	/* Assume the lowest address is the last one added. */
+	if (root->num_entries > 0) {
+		low_addr = root->entries[root->num_entries - 1].start;
+	}
+
+	return (void *)low_addr;
+}
+
+
+const struct cbmem_entry *cbmem_entry_add(u32 id, u64 size64)
+{
+	struct cbmem_root *root;
+	const struct cbmem_entry *entry;
+	unsigned long base;;
+	u32 size;
+	u32 aligned_size;
+
+	entry = cbmem_entry_find(id);
+
+	if (entry != NULL)
+		return entry;
+
+	/* Only handle sizes <= UINT_MAX internally. */
+	if (size64 > (u64)UINT_MAX)
+		return NULL;
+
+	size = size64;
+
+	root = get_root();
+
+	if (root == NULL)
+		return NULL;
+
+	/* Nothing can be added once it is locked down. */
+	if (root->locked)
+		return NULL;
+
+	if (root->max_entries == root->num_entries)
+		return NULL;
+
+	aligned_size = ALIGN(size, DYN_CBMEM_ALIGN_SIZE);
+	base = (unsigned long)cbmem_base();
+	base -= aligned_size;
+
+	return cbmem_entry_append(root, id, base, aligned_size);
+}
+
+void *cbmem_add(u32 id, u64 size)
+{
+	const struct cbmem_entry *entry;
+
+	entry = cbmem_entry_add(id, size);
+
+	if (entry == NULL)
+		return NULL;
+
+	return cbmem_entry_start(entry);
+}
+
+/* Retrieve a region provided a given id. */
+const struct cbmem_entry *cbmem_entry_find(u32 id)
+{
+	struct cbmem_root *root;
+	const struct cbmem_entry *entry;
+	unsigned int i;
+
+	root = get_root();
+
+	if (root == NULL)
+		return NULL;
+
+	entry = NULL;
+
+	for (i = 0; i < root->num_entries; i++) {
+		if (root->entries[i].id == id) {
+			entry = &root->entries[i];
+			break;
+		}
+	}
+
+	return entry;
+}
+
+void *cbmem_find(u32 id)
+{
+	const struct cbmem_entry *entry;
+
+	entry = cbmem_entry_find(id);
+
+	if (entry == NULL)
+		return NULL;
+
+	return cbmem_entry_start(entry);
+}
+
+/* Remove a reserved region. Returns 0 on success, < 0 on error. Note: A region
+ * cannot be removed unless it was the last one added. */
+int cbmem_entry_remove(const struct cbmem_entry *entry)
+{
+	unsigned long entry_num;
+	struct cbmem_root *root;
+
+	root = get_root();
+
+	if (root == NULL)
+		return -1;
+
+	if (root->num_entries == 0)
+		return -1;
+
+	/* Nothing can be removed. */
+	if (root->locked)
+		return -1;
+
+	entry_num = entry - &root->entries[0];
+
+	/* If the entry is the last one in the root it can be removed. */
+	if (entry_num == (root->num_entries - 1)) {
+		root->num_entries--;
+		return 0;
+	}
+
+	return -1;
+}
+
+u64 cbmem_entry_size(const struct cbmem_entry *entry)
+{
+	return entry->size;
+}
+
+void *cbmem_entry_start(const struct cbmem_entry *entry)
+{
+	return (void *)(uintptr_t)entry->start;
+}
+
+
+#if !defined(__PRE_RAM__)
+/* selected cbmem can be initialized early in ramstage. Additionally, that
+ * means cbmem console can be reinitialized early as well. The post_device
+ * function is empty since cbmem was initialized early in ramstage. */
+static void init_cbmem_pre_device(void *unused)
+{
+	cbmem_initialize();
+}
+
+BOOT_STATE_INIT_ENTRIES(cbmem_bscb) = {
+	BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY,
+	                      init_cbmem_pre_device, NULL),
+};
+
+void cbmem_add_lb_mem(struct lb_memory *mem)
+{
+	unsigned long base;
+	unsigned long top;
+
+	base = (unsigned long)cbmem_base();
+	top = (unsigned long)get_top_aligned();
+	lb_add_memory_range(mem, LB_MEM_TABLE, base, top - base);
+}
+
+void cbmem_list(void)
+{
+	unsigned int i;
+	struct cbmem_root *root;
+
+	root = get_root();
+
+	if (root == NULL)
+		return;
+
+	for (i = 0; i < root->num_entries; i++) {
+		struct cbmem_entry *entry;
+
+		entry = &root->entries[i];
+
+		cbmem_print_entry(i, entry->id, entry->start, entry->size);
+	}
+}
+#endif /* __PRE_RAM__ */



More information about the coreboot-gerrit mailing list