Leroy P Leahy (leroy.p.leahy@intel.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10053
-gerrit
commit 2c4e5dc203c579272efe0c96e8ba429006548c64 Author: Lee Leahy leroy.p.leahy@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@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__ */