Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3235
-gerrit
commit 079d182facbd58cde88121da494a28cc34217486
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Fri May 10 00:45:37 2013 -0500
cbmem console: use cache-as-ram API and cleanup
Allow for automatic cache-as-ram migration for the cbmem
console. The code was refactored in the thought of making
it easier to read. The #ifdefs still exist, but they are no
longer sprinkled throughout the code. The cbmem_console_p
variable now exists globally in both romstage and ramstage.
However, the cbmem_console_p is referenced using the
cache-as-ram API. When cbmem is initialized the console
is automatically copied over by calling cbmemc_reinit()
through a callback.
Change-Id: I9f4a64e33c58b8b7318db27942e37c13804e6f2c
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/lib/cbmem_console.c | 93 +++++++++++++++++++++++++++++++------------------
1 file changed, 60 insertions(+), 33 deletions(-)
diff --git a/src/lib/cbmem_console.c b/src/lib/cbmem_console.c
index 2e22dec..efb8e86 100644
--- a/src/lib/cbmem_console.c
+++ b/src/lib/cbmem_console.c
@@ -34,6 +34,8 @@ struct cbmem_console {
u8 buffer_body[0];
} __attribute__ ((__packed__));
+static struct cbmem_console *cbmem_console_p CAR_GLOBAL;
+
#ifdef __PRE_RAM__
/*
* While running from ROM, before DRAM is initialized, some area in cache as
@@ -42,7 +44,6 @@ struct cbmem_console {
*/
static struct cbmem_console car_cbmem_console CAR_CBMEM;
-#define cbmem_console_p (&car_cbmem_console)
/*
* Once DRAM is initialized and the cache as ram mode is disabled, while still
@@ -54,6 +55,7 @@ static struct cbmem_console car_cbmem_console CAR_CBMEM;
* find out where the actual console log buffer is.
*/
#define CBMEM_CONSOLE_REDIRECT (*((struct cbmem_console **)0x600))
+
#else
/*
@@ -63,41 +65,64 @@ static struct cbmem_console car_cbmem_console CAR_CBMEM;
* during the ROM stage, once CBMEM becomes available at RAM stage.
*/
static u8 static_console[40000];
-static struct cbmem_console *cbmem_console_p;
#endif
+static inline struct cbmem_console *current_console(void)
+{
+#if CONFIG_CAR_MIGRATION || !defined(__PRE_RAM__)
+ return car_get_var(cbmem_console_p);
+#else
+ /*
+ * This check allows to tell if the cache as RAM mode has been exited
+ * or not. If it has been exited, the real memory is being used
+ * (resulting in the variable on the stack located below
+ * DCACHE_RAM_BASE), use the redirect pointer to find out where the
+ * actual console buffer is.
+ */
+ if ((uintptr_t)__builtin_frame_address(0) <
+ (uintptr_t)CONFIG_DCACHE_RAM_BASE)
+ return CBMEM_CONSOLE_REDIRECT;
+ return car_get_var(cbmem_console_p);
+#endif /* CONFIG_CAR_MIGRATION */
+}
+
+static inline void current_console_set(struct cbmem_console *new_console_p)
+{
+#if CONFIG_CAR_MIGRATION || !defined(__PRE_RAM__)
+ car_set_var(cbmem_console_p, new_console_p);
+#else
+ CBMEM_CONSOLE_REDIRECT = new_console_p;
+#endif
+}
+
+static inline void init_console_ptr(void *storage, u32 total_space)
+{
+ struct cbmem_console *cbm_cons_p = storage;
+
+ /* Initialize the cache-as-ram pointer and underlying structure. */
+ car_set_var(cbmem_console_p, cbm_cons_p);
+ cbm_cons_p->buffer_size = total_space - sizeof(struct cbmem_console);
+ cbm_cons_p->buffer_cursor = 0;
+}
+
void cbmemc_init(void)
{
#ifdef __PRE_RAM__
- cbmem_console_p->buffer_size = CONFIG_CONSOLE_CAR_BUFFER_SIZE -
- sizeof(struct cbmem_console);
+ init_console_ptr(&car_cbmem_console, CONFIG_CONSOLE_CAR_BUFFER_SIZE);
#else
/*
* Initializing before CBMEM is available, use static buffer to store
* the log.
*/
- cbmem_console_p = (struct cbmem_console *) static_console;
- cbmem_console_p->buffer_size = sizeof(static_console) -
- sizeof(struct cbmem_console);
+ init_console_ptr(static_console, sizeof(static_console));
#endif
- cbmem_console_p->buffer_cursor = 0;
}
void cbmemc_tx_byte(unsigned char data)
{
- struct cbmem_console *cbm_cons_p = cbmem_console_p;
+ struct cbmem_console *cbm_cons_p = current_console();
u32 cursor;
-#ifdef __PRE_RAM__
- /*
- * This check allows to tell if the cache as RAM mode has been exited
- * or not. If it has been exited, the real memory is being used
- * (resulting in the variable on the stack located below
- * DCACHE_RAM_BASE), use the redirect pointer to find out where the
- * actual console buffer is.
- */
- if ((uintptr_t)&cursor < (uintptr_t)&car_cbmem_console)
- cbm_cons_p = CBMEM_CONSOLE_REDIRECT;
-#endif
+
if (!cbm_cons_p)
return;
@@ -119,14 +144,17 @@ static void copy_console_buffer(struct cbmem_console *new_cons_p)
{
u32 copy_size;
u32 cursor = new_cons_p->buffer_cursor;
- int overflow = cbmem_console_p->buffer_cursor >
- cbmem_console_p->buffer_size;
+ struct cbmem_console *old_cons_p;
+ int overflow;
+
+ old_cons_p = current_console();
+
+ overflow = old_cons_p->buffer_cursor > old_cons_p->buffer_size;
copy_size = overflow ?
- cbmem_console_p->buffer_size : cbmem_console_p->buffer_cursor;
+ old_cons_p->buffer_size : old_cons_p->buffer_cursor;
- memcpy(new_cons_p->buffer_body + cursor,
- cbmem_console_p->buffer_body,
+ memcpy(new_cons_p->buffer_body + cursor, old_cons_p->buffer_body,
copy_size);
cursor += copy_size;
@@ -134,7 +162,7 @@ static void copy_console_buffer(struct cbmem_console *new_cons_p)
if (overflow) {
const char loss_str1[] = "\n\n*** Log truncated, ";
const char loss_str2[] = " characters dropped. ***\n\n";
- u32 dropped_chars = cbmem_console_p->buffer_cursor - copy_size;
+ u32 dropped_chars = old_cons_p->buffer_cursor - copy_size;
/*
* When running from ROM sprintf is not available, a simple
@@ -173,7 +201,7 @@ void cbmemc_reinit(void)
cbm_cons_p = cbmem_add(CBMEM_ID_CONSOLE,
CONFIG_CONSOLE_CBMEM_BUFFER_SIZE);
if (!cbm_cons_p) {
- CBMEM_CONSOLE_REDIRECT = NULL;
+ current_console_set(NULL);
return;
}
@@ -181,18 +209,17 @@ void cbmemc_reinit(void)
sizeof(struct cbmem_console);
cbm_cons_p->buffer_cursor = 0;
-
- copy_console_buffer(cbm_cons_p);
-
- CBMEM_CONSOLE_REDIRECT = cbm_cons_p;
#else
cbm_cons_p = cbmem_find(CBMEM_ID_CONSOLE);
if (!cbm_cons_p)
return;
+#endif
copy_console_buffer(cbm_cons_p);
- cbmem_console_p = cbm_cons_p;
-#endif
+ current_console_set(cbm_cons_p);
}
+
+/* Call cbmemc_reinit() at CAR migration time. */
+CAR_MIGRATE(cbmemc_reinit)
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3206
-gerrit
commit 20500dc5f49e285a3dc1a53a68f5a3fe8736cd67
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Mon May 6 12:20:52 2013 -0500
coreboot: add thread cooperative multitasking
The cooperative multitasking support allows the boot state machine
to be ran cooperatively with other threads of work. The main thread
still continues to run the boot state machine
(src/lib/hardwaremain.c). All callbacks from the state machine are
still ran synchronously from within the main thread's context.
Without any other code added the only change to the boot sequence
when cooperative multitasking is enabled is the queueing of an idlle
thread. The idle thread is responsible for ensuring progress is made
by calling timer callbacks.
The main thread can yield to any other threads in the system. That
means that anyone that spins up a thread must ensure no shared
resources are used from 2 or more execution contexts. The support
is originally intentioned to allow for long work itesm with busy
loops to occur in parallel during a boot.
Note that the intention on when to yield a thread will be on
calls to udelay().
Change-Id: Ia4d67a38665b12ce2643474843a93babd8a40c77
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/Kconfig | 16 ++
src/arch/armv7/include/arch/cpu.h | 5 +
src/arch/x86/include/arch/cpu.h | 5 +
src/include/thread.h | 82 +++++++++
src/lib/Makefile.inc | 1 +
src/lib/hardwaremain.c | 3 +
src/lib/thread.c | 376 ++++++++++++++++++++++++++++++++++++++
7 files changed, 488 insertions(+)
diff --git a/src/Kconfig b/src/Kconfig
index ce5a048..4366bc8 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -324,6 +324,22 @@ config TIMER_QUEUE
help
Provide a timer queue for performing time-based callbacks.
+config COOP_MULTITASKING
+ def_bool n
+ depends on TIMER_QUEUE
+ help
+ Cooperative multitasking allows callbacks to be multiplexed on the
+ main thread of ramstage. With this enabled it allows for multiple
+ execution paths to take place when they have udelay() calls within
+ their code.
+
+config NUM_THREADS
+ int
+ default 4
+ depends on COOP_MULTITASKING
+ help
+ How many execution threads to cooperatively multitask with.
+
config HIGH_SCRATCH_MEMORY_SIZE
hex
default 0x0
diff --git a/src/arch/armv7/include/arch/cpu.h b/src/arch/armv7/include/arch/cpu.h
index 20a12c9..5621aed 100644
--- a/src/arch/armv7/include/arch/cpu.h
+++ b/src/arch/armv7/include/arch/cpu.h
@@ -30,9 +30,14 @@ struct cpu_driver {
struct cpu_device_id *id_table;
};
+struct thread;
+
struct cpu_info {
device_t cpu;
unsigned long index;
+#if CONFIG_COOP_MULTITASKING
+ struct thread *thread;
+#endif
};
struct cpuinfo_arm {
diff --git a/src/arch/x86/include/arch/cpu.h b/src/arch/x86/include/arch/cpu.h
index 890c77f..1fe12e5 100644
--- a/src/arch/x86/include/arch/cpu.h
+++ b/src/arch/x86/include/arch/cpu.h
@@ -159,9 +159,14 @@ struct cpu_driver {
struct cpu_driver *find_cpu_driver(struct device *cpu);
+struct thread;
+
struct cpu_info {
device_t cpu;
unsigned int index;
+#if CONFIG_COOP_MULTITASKING
+ struct thread *thread;
+#endif
};
static inline struct cpu_info *cpu_info(void)
diff --git a/src/include/thread.h b/src/include/thread.h
new file mode 100644
index 0000000..6f3419f
--- /dev/null
+++ b/src/include/thread.h
@@ -0,0 +1,82 @@
+/*
+ * 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 THREAD_H_
+#define THREAD_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <bootstate.h>
+#include <timer.h>
+#include <arch/cpu.h>
+
+#if CONFIG_COOP_MULTITASKING && !defined(__SMM__) && !defined(__PRE_RAM__)
+
+struct thread {
+ int id;
+ uintptr_t stack_current;
+ uintptr_t stack_orig;
+ struct thread *next;
+ void (*entry)(void *);
+ void *entry_arg;
+ int can_yield;
+};
+
+void threads_initialize(void);
+/* Run func(arrg) on a new thread. Return 0 on successful start of thread, < 0
+ * when thread could not be started. Note that the thread will block the
+ * current state in the boot state machine until it is complete. */
+int thread_run(void (*func)(void *), void *arg);
+/* thread_run_until is the same as thread_run() except that it blocks state
+ * transitions from occuring in the (state, seq) pair of the boot state
+ * machine. */
+int thread_run_until(void (*func)(void *), void *arg,
+ boot_state_t state, boot_state_sequence_t seq);
+/* Return 0 on successful yield for the given amount of time, < 0 when thread
+ * did not yield. */
+int thread_yield_microseconds(unsigned microsecs);
+
+/* Allow and prevent thread cooperation on current running thread. By default
+ * all threads are marked to be cooperative. That means a thread can yeild
+ * to another thread at a pre-determined switch point. Current there is
+ * only a single place where switching may occur: a call to udelay(). */
+void thread_cooperate(void);
+void thread_prevent_coop(void);
+
+static inline void thread_init_cpu_info_non_bsp(struct cpu_info *ci)
+{
+ ci->thread = NULL;
+}
+
+/* Architecture specific thread functions. */
+void asmlinkage switch_to_thread(uintptr_t new_stack, uintptr_t *saved_stack);
+/* Set up the stack frame for a new thread so that a switch_to_thread() call
+ * will enter the thread_entry() function with arg as a parameter. The
+ * saved_stack field in the struct thread needs to be updated accordingly. */
+void arch_prepare_thread(struct thread *t,
+ void asmlinkage (*thread_entry)(void *), void *arg);
+#else
+static inline void threads_initialize(void) {}
+static inline int thread_run(void (*func)(void *), void *arg) { return -1; }
+static inline int thread_yield_microseconds(unsigned microsecs) { return -1; }
+static inline void thread_cooperate(void) {}
+static inline void thread_prevent_coop(void) {}
+static inline void thread_init_cpu_info_non_bsp(struct cpu_info *ci) { }
+#endif
+
+#endif /* THREAD_H_ */
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index 7306e6d..2600aa5 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -90,6 +90,7 @@ ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
ramstage-$(CONFIG_COVERAGE) += libgcov.c
ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += edid.c
ramstage-y += memrange.c
+ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c
ramstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c
# The CBMEM implementations are chosen based on CONFIG_DYNAMIC_CBMEM.
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index 99b4a06..14b3fff 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -39,6 +39,7 @@
#endif
#include <timer.h>
#include <timestamp.h>
+#include <thread.h>
#if BOOT_STATE_DEBUG
#define BS_DEBUG_LVL BIOS_DEBUG
@@ -459,6 +460,8 @@ void hardwaremain(void)
post_code(POST_CONSOLE_BOOT_MSG);
+ threads_initialize();
+
/* Schedule the static boot state entries. */
boot_state_schedule_static_entries();
diff --git a/src/lib/thread.c b/src/lib/thread.c
new file mode 100644
index 0000000..6508bfa
--- /dev/null
+++ b/src/lib/thread.c
@@ -0,0 +1,376 @@
+/*
+ * 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
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <arch/cpu.h>
+#include <bootstate.h>
+#include <console/console.h>
+#include <thread.h>
+
+static void idle_thread_init(void);
+
+/* There needs to be at least one thread to run the ramstate state machine. */
+#define TOTAL_NUM_THREADS (CONFIG_NUM_THREADS + 1)
+extern char thread_stacks[CONFIG_NUM_THREADS*CONFIG_STACK_SIZE];
+
+/* Storage space for the thread structs .*/
+static struct thread all_threads[TOTAL_NUM_THREADS];
+
+/* All runnable (but not running) and free threads are kept on their
+ * respective lists. */
+static struct thread *runnable_threads;
+static struct thread *free_threads;
+
+static inline struct cpu_info *thread_cpu_info(const struct thread *t)
+{
+ return (void *)(t->stack_orig);
+}
+
+static inline int thread_can_yield(const struct thread *t)
+{
+ return (t != NULL && t->can_yield);
+}
+
+/* Assumes current cpu info can switch. */
+static inline struct thread *cpu_info_to_thread(const struct cpu_info *ci)
+{
+ return ci->thread;
+}
+
+static inline struct thread *current_thread(void)
+{
+ return cpu_info_to_thread(cpu_info());
+}
+
+static inline int thread_list_empty(struct thread **list)
+{
+ return *list == NULL;
+}
+
+static inline struct thread *pop_thread(struct thread **list)
+{
+ struct thread *t;
+
+ t = *list;
+ *list = t->next;
+ t->next = NULL;
+ return t;
+}
+
+static inline void push_thread(struct thread **list, struct thread *t)
+{
+ t->next = *list;
+ *list = t;
+}
+
+static inline void push_runnable(struct thread *t)
+{
+ push_thread(&runnable_threads, t);
+}
+
+static inline struct thread *pop_runnable(void)
+{
+ return pop_thread(&runnable_threads);
+}
+
+static inline struct thread *get_free_thread(void)
+{
+ struct thread *t;
+ struct cpu_info *ci;
+ struct cpu_info *new_ci;
+
+ if (thread_list_empty(&free_threads))
+ return NULL;
+
+ t = pop_thread(&free_threads);
+
+ ci = cpu_info();
+
+ /* Initialize the cpu_info structure on the new stack. */
+ new_ci = thread_cpu_info(t);
+ *new_ci = *ci;
+ new_ci->thread = t;
+
+ /* Reset the current stack value to the original. */
+ t->stack_current = t->stack_orig;
+
+ return t;
+}
+
+static inline void free_thread(struct thread *t)
+{
+ push_thread(&free_threads, t);
+}
+
+/* The idle thread is ran whenever there isn't anything else that is runnable.
+ * It's sole responsibility is to ensure progress is made by running the timer
+ * callbacks. */
+static void idle_thread(void *unused)
+{
+ /* This thread never voluntarily yields. */
+ thread_prevent_coop();
+ while (1) {
+ timers_run();
+ }
+}
+
+static void schedule(struct thread *t)
+{
+ struct thread *current = current_thread();
+
+ /* If t is NULL need to find new runnable thread. */
+ if (t == NULL) {
+ if (thread_list_empty(&runnable_threads))
+ die("Runnable thread list is empty!\n");
+ t = pop_runnable();
+ } else {
+ /* current is still runnable. */
+ push_runnable(current);
+ }
+ switch_to_thread(t->stack_current, ¤t->stack_current);
+}
+
+static void terminate_thread(struct thread *t)
+{
+ free_thread(t);
+ schedule(NULL);
+}
+
+static void asmlinkage call_wrapper(void *unused)
+{
+ struct thread *current = current_thread();
+
+ current->entry(current->entry_arg);
+ terminate_thread(current);
+}
+
+/* Block the current state transitions until thread is complete. */
+static void asmlinkage call_wrapper_block_current(void *unused)
+{
+ struct thread *current = current_thread();
+
+ boot_state_current_block();
+ current->entry(current->entry_arg);
+ boot_state_current_unblock();
+ terminate_thread(current);
+}
+
+struct block_boot_state {
+ boot_state_t state;
+ boot_state_sequence_t seq;
+};
+
+/* Block the provided state until thread is complete. */
+static void asmlinkage call_wrapper_block_state(void *arg)
+{
+ struct block_boot_state *bbs = arg;
+ struct thread *current = current_thread();
+
+ boot_state_block(bbs->state, bbs->seq);
+ current->entry(current->entry_arg);
+ boot_state_unblock(bbs->state, bbs->seq);
+ terminate_thread(current);
+}
+
+/* Prepare a thread so that it starts by executing thread_entry(thread_arg).
+ * Within thread_entry() it will call func(arg). */
+static void prepare_thread(struct thread *t, void *func, void *arg,
+ void asmlinkage (*thread_entry)(void *),
+ void *thread_arg)
+{
+ /* Stash the function and argument to run. */
+ t->entry = func;
+ t->entry_arg = arg;
+
+ /* All new threads can yield by default. */
+ t->can_yield = 1;
+
+ arch_prepare_thread(t, thread_entry, thread_arg);
+}
+
+static void thread_resume_from_timeout(struct timeout_callback *tocb)
+{
+ struct thread *to;
+
+ to = tocb->priv;
+ schedule(to);
+}
+
+static void idle_thread_init(void)
+{
+ struct thread *t;
+
+ t = get_free_thread();
+
+ if (t == NULL) {
+ die("No threads available for idle thread!\n");
+ }
+
+ /* Queue idle thread to run once all other threads have yielded. */
+ prepare_thread(t, idle_thread, NULL, call_wrapper, NULL);
+ push_runnable(t);
+ /* Mark the currently executing thread to cooperate. */
+ thread_cooperate();
+}
+
+/* Don't inline this function so the timeout_callback won't have its storage
+ * space on the stack cleaned up before the call to schedule(). */
+static int __attribute__((noinline))
+thread_yield_timed_callback(struct timeout_callback *tocb, unsigned microsecs)
+{
+ tocb->priv = current_thread();
+ tocb->callback = thread_resume_from_timeout;
+
+ if (timer_sched_callback(tocb, microsecs))
+ return -1;
+
+ /* The timer callback will wake up the current thread. */
+ schedule(NULL);
+ return 0;
+}
+
+static void *thread_alloc_space(struct thread *t, size_t bytes)
+{
+ /* Allocate the amount of space on the stack keeping the stack
+ * aligned to the pointer size. */
+ t->stack_current -= ALIGN_UP(bytes, sizeof(uintptr_t));
+
+ return (void *)t->stack_current;
+}
+
+void threads_initialize(void)
+{
+ int i;
+ struct thread *t;
+ char *stack_top;
+ struct cpu_info *ci;
+
+ /* Initialize the BSP thread first. The cpu_info structure is assumed
+ * to be just under the top of the stack. */
+ t = &all_threads[0];
+ ci = cpu_info();
+ ci->thread = t;
+ t->stack_orig = (uintptr_t)ci;
+ t->id = 0;
+
+ stack_top = &thread_stacks[CONFIG_STACK_SIZE] - sizeof(struct cpu_info);
+ for (i = 1; i < TOTAL_NUM_THREADS; i++) {
+ t = &all_threads[i];
+ t->stack_orig = (uintptr_t)stack_top;
+ t->id = i;
+ stack_top += CONFIG_STACK_SIZE;
+ free_thread(t);
+ }
+
+ idle_thread_init();
+}
+
+int thread_run(void (*func)(void *), void *arg)
+{
+ struct thread *current;
+ struct thread *t;
+
+ current = current_thread();
+
+ if (!thread_can_yield(current)) {
+ printk(BIOS_ERR,
+ "thread_run() called from non-yielding context!\n");
+ return -1;
+ }
+
+ t = get_free_thread();
+
+ if (t == NULL) {
+ printk(BIOS_ERR, "thread_run() No more threads!\n");
+ return -1;
+ }
+
+ prepare_thread(t, func, arg, call_wrapper_block_current, NULL);
+ schedule(t);
+
+ return 0;
+}
+
+int thread_run_until(void (*func)(void *), void *arg,
+ boot_state_t state, boot_state_sequence_t seq)
+{
+ struct thread *current;
+ struct thread *t;
+ struct block_boot_state *bbs;
+
+ current = current_thread();
+
+ if (!thread_can_yield(current)) {
+ printk(BIOS_ERR,
+ "thread_run() called from non-yielding context!\n");
+ return -1;
+ }
+
+ t = get_free_thread();
+
+ if (t == NULL) {
+ printk(BIOS_ERR, "thread_run() No more threads!\n");
+ return -1;
+ }
+
+ bbs = thread_alloc_space(t, sizeof(*bbs));
+ bbs->state = state;
+ bbs->seq = seq;
+ prepare_thread(t, func, arg, call_wrapper_block_state, bbs);
+ schedule(t);
+
+ return 0;
+}
+
+int thread_yield_microseconds(unsigned microsecs)
+{
+ struct thread *current;
+ struct timeout_callback tocb;
+
+ current = current_thread();
+
+ if (!thread_can_yield(current))
+ return -1;
+
+ if (thread_yield_timed_callback(&tocb, microsecs))
+ return -1;
+
+ return 0;
+}
+
+void thread_cooperate(void)
+{
+ struct thread *current;
+
+ current = current_thread();
+
+ if (current != NULL)
+ current->can_yield = 1;
+}
+
+void thread_prevent_coop(void)
+{
+ struct thread *current;
+
+ current = current_thread();
+
+ if (current != NULL)
+ current->can_yield = 0;
+}
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3207
-gerrit
commit 13add3f9027bb2a224bbe647fe72d1bc2c4d41f9
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Mon May 6 12:22:23 2013 -0500
x86: add thread support
Thread support is added for the x86 architecture. Both
the local apic and the tsc udelay() functions have a
call to thread_yield_microseconds() so as to provide an
opportunity to run pending threads.
Change-Id: Ie39b9eb565eb189676c06645bdf2a8720fe0636a
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/Kconfig | 2 +-
src/arch/x86/lib/Makefile.inc | 2 ++
src/arch/x86/lib/c_start.S | 9 ++++++
src/arch/x86/lib/thread.c | 58 ++++++++++++++++++++++++++++++++++++++
src/arch/x86/lib/thread_switch.S | 58 ++++++++++++++++++++++++++++++++++++++
src/cpu/intel/haswell/mp_init.c | 2 ++
src/cpu/x86/lapic/apic_timer.c | 4 +++
src/cpu/x86/lapic/lapic_cpu_init.c | 2 ++
src/cpu/x86/tsc/delay_tsc.c | 4 +++
9 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/src/Kconfig b/src/Kconfig
index 4366bc8..308deaa 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -326,7 +326,7 @@ config TIMER_QUEUE
config COOP_MULTITASKING
def_bool n
- depends on TIMER_QUEUE
+ depends on TIMER_QUEUE && ARCH_X86
help
Cooperative multitasking allows callbacks to be multiplexed on the
main thread of ramstage. With this enabled it allows for multiple
diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc
index 82f4e62..7cdd3c6 100644
--- a/src/arch/x86/lib/Makefile.inc
+++ b/src/arch/x86/lib/Makefile.inc
@@ -9,6 +9,8 @@ ramstage-y += memset.c
ramstage-y += memcpy.c
ramstage-y += ebda.c
ramstage-y += rom_media.c
+ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c
+ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S
romstage-$(CONFIG_EARLY_CONSOLE) += romstage_console.c
romstage-y += cbfs_and_run.c
diff --git a/src/arch/x86/lib/c_start.S b/src/arch/x86/lib/c_start.S
index 1e38aca..c725f82 100644
--- a/src/arch/x86/lib/c_start.S
+++ b/src/arch/x86/lib/c_start.S
@@ -10,6 +10,11 @@
_stack:
.space CONFIG_MAX_CPUS*CONFIG_STACK_SIZE
_estack:
+#if CONFIG_COOP_MULTITASKING
+.global thread_stacks
+thread_stacks:
+.space CONFIG_STACK_SIZE*CONFIG_NUM_THREADS
+#endif
.section ".textfirst", "ax", @progbits
.code32
@@ -45,6 +50,10 @@ _start:
/* set new stack */
movl $_estack, %esp
+#if CONFIG_COOP_MULTITASKING
+ /* Push the thread pointer. */
+ pushl $0
+#endif
/* Push the cpu index and struct cpu */
pushl $0
pushl $0
diff --git a/src/arch/x86/lib/thread.c b/src/arch/x86/lib/thread.c
new file mode 100644
index 0000000..06f8a15
--- /dev/null
+++ b/src/arch/x86/lib/thread.c
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+#include <thread.h>
+
+/* The stack frame looks like the following after a pushad instruction. */
+struct pushad_regs {
+ uint32_t edi; /* Offset 0x00 */
+ uint32_t esi; /* Offset 0x04 */
+ uint32_t ebp; /* Offset 0x08 */
+ uint32_t esp; /* Offset 0x0c */
+ uint32_t ebx; /* Offset 0x10 */
+ uint32_t edx; /* Offset 0x14 */
+ uint32_t ecx; /* Offset 0x18 */
+ uint32_t eax; /* Offset 0x1c */
+};
+
+static inline uintptr_t push_stack(uintptr_t cur_stack, uintptr_t value)
+{
+ uintptr_t *addr;
+
+ cur_stack -= sizeof(value);
+ addr = (uintptr_t *)cur_stack;
+ *addr = value;
+ return cur_stack;
+}
+
+void arch_prepare_thread(struct thread *t,
+ void asmlinkage (*thread_entry)(void *), void *arg)
+{
+ uintptr_t stack = t->stack_current;
+
+ /* Imitate thread_entry(t) with return address of 0. thread_entry()
+ * is assumed to never return. */
+ stack = push_stack(stack, (uintptr_t)arg);
+ stack = push_stack(stack, (uintptr_t)0);
+ stack = push_stack(stack, (uintptr_t)thread_entry);
+ /* Make room for the registers. Ignore intial values. */
+ stack -= sizeof(struct pushad_regs);
+
+ t->stack_current = stack;
+}
diff --git a/src/arch/x86/lib/thread_switch.S b/src/arch/x86/lib/thread_switch.S
new file mode 100644
index 0000000..8de1948
--- /dev/null
+++ b/src/arch/x86/lib/thread_switch.S
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+.code32
+.text
+
+/*
+ * stack layout after pushad:
+ * +------------+
+ * | save stack | <-- esp + 0x28
+ * +------------+
+ * | new stack | <-- esp + 0x24
+ * +------------+
+ * | ret addr | <-- esp + 0x20
+ * +------------+
+ * | eax | <-- esp + 0x1c
+ * +------------+
+ * | ecx | <-- esp + 0x18
+ * +------------+
+ * | edx | <-- esp + 0x14
+ * +------------+
+ * | ebx | <-- esp + 0x10
+ * +------------+
+ * | orig esp | <-- esp + 0x0c
+ * +------------+
+ * | ebp | <-- esp + 0x08
+ * +------------+
+ * | esi | <-- esp + 0x04
+ * +------------+
+ * | edi | <-- esp + 0x00
+ * +------------+
+ */
+.globl switch_to_thread
+switch_to_thread:
+ pusha
+ /* Save the current stack */
+ movl 0x28(%esp), %ebx
+ movl %esp, (%ebx)
+ /* Switch to the new stack. */
+ movl 0x24(%esp), %eax
+ movl %eax, %esp
+ popa
+ ret
diff --git a/src/cpu/intel/haswell/mp_init.c b/src/cpu/intel/haswell/mp_init.c
index deba629..357fbb2 100644
--- a/src/cpu/intel/haswell/mp_init.c
+++ b/src/cpu/intel/haswell/mp_init.c
@@ -36,6 +36,7 @@
#include <lib.h>
#include <smp/atomic.h>
#include <smp/spinlock.h>
+#include <thread.h>
#include "haswell.h"
/* This needs to match the layout in the .module_parametrs section. */
@@ -163,6 +164,7 @@ static void asmlinkage ap_init(unsigned int cpu, void *microcode_ptr)
info = cpu_info();
info->index = cpu;
info->cpu = cpu_devs[cpu];
+ thread_init_cpu_info_non_bsp(info);
apic_id_table[info->index] = lapicid();
info->cpu->path.apic.apic_id = apic_id_table[info->index];
diff --git a/src/cpu/x86/lapic/apic_timer.c b/src/cpu/x86/lapic/apic_timer.c
index 749fef0..e5ce62f 100644
--- a/src/cpu/x86/lapic/apic_timer.c
+++ b/src/cpu/x86/lapic/apic_timer.c
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <console/console.h>
#include <delay.h>
+#include <thread.h>
#include <arch/io.h>
#include <arch/cpu.h>
#include <cpu/x86/car.h>
@@ -95,6 +96,9 @@ void udelay(u32 usecs)
{
u32 start, value, ticks;
+ if (!thread_yield_microseconds(usecs))
+ return;
+
if (!timer_fsb || (lapic_read(LAPIC_LVTT) &
(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) !=
(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED))
diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c
index 69430d5..fbc8aa4 100644
--- a/src/cpu/x86/lapic/lapic_cpu_init.c
+++ b/src/cpu/x86/lapic/lapic_cpu_init.c
@@ -32,6 +32,7 @@
#include <smp/spinlock.h>
#include <cpu/cpu.h>
#include <cpu/intel/speedstep.h>
+#include <thread.h>
#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
/* This is a lot more paranoid now, since Linux can NOT handle
@@ -292,6 +293,7 @@ int start_cpu(device_t cpu)
info = (struct cpu_info *)stack_end;
info->index = index;
info->cpu = cpu;
+ thread_init_cpu_info_non_bsp(info);
/* Advertise the new stack and index to start_cpu */
secondary_stack = stack_end;
diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c
index 0e2a9c0..b8f2503 100644
--- a/src/cpu/x86/tsc/delay_tsc.c
+++ b/src/cpu/x86/tsc/delay_tsc.c
@@ -4,6 +4,7 @@
#include <cpu/x86/tsc.h>
#include <smp/spinlock.h>
#include <delay.h>
+#include <thread.h>
#if !defined(__PRE_RAM__)
@@ -176,6 +177,9 @@ void udelay(unsigned us)
unsigned long long current;
unsigned long long clocks;
+ if (!thread_yield_microseconds(us))
+ return;
+
start = rdtscll();
clocks = us;
clocks *= get_clocks_per_usec();
Paul Menzel (paulepanter(a)users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3232
-gerrit
commit 1ab36fe61a0246ce5e2fe57183bfb5c5829a9068
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Fri May 10 00:33:32 2013 -0500
x86: add cache-as-ram migration option
There are some boards that do a significant amount of
work after cache-as-ram is torn down but before ramstage
is loaded. For example, using vboot to verify the ramstage
is one such operation. However, there are pieces of code
that are executed that reference global variables that
are linked in the cache-as-ram region. If those variables
are referenced after cache-as-ram is torn down then the
values observed will most likely be incorrect.
Therefore provide a Kconfig option to select cache-as-ram
migration to memory using cbmem. This option is named
CAR_MIGRATION. When enabled, the address of cache-as-ram
variables may be obtained dynamically. Additionally,
when cache-as-ram migration occurs the cache-as-ram
data region for global variables is copied into cbmem.
There are also automatic callbacks for other modules
to perform their own migration, if necessary.
Change-Id: I2e77219647c2bd2b1aa845b262be3b2543f1fcb7
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/x86/init/romstage.ld | 12 +++++
src/cpu/Makefile.inc | 1 +
src/cpu/x86/Kconfig | 9 ++++
src/cpu/x86/Makefile.inc | 1 +
src/cpu/x86/car.c | 102 ++++++++++++++++++++++++++++++++++++++++++
src/include/cbmem.h | 1 +
src/include/cpu/x86/car.h | 29 ++++++++++++
src/lib/cbmem.c | 4 ++
src/lib/cbmem_info.c | 1 +
src/lib/dynamic_cbmem.c | 9 ++++
10 files changed, 169 insertions(+)
diff --git a/src/arch/x86/init/romstage.ld b/src/arch/x86/init/romstage.ld
index 88c5657..bb6259f 100644
--- a/src/arch/x86/init/romstage.ld
+++ b/src/arch/x86/init/romstage.ld
@@ -35,6 +35,10 @@ SECTIONS
*(.rodata.*);
*(.rom.data.*);
. = ALIGN(16);
+ _car_migrate_start = .;
+ *(.car.migrate);
+ _car_migrate_end = .;
+ . = ALIGN(16);
_erom = .;
}
@@ -48,8 +52,16 @@ SECTIONS
. = CONFIG_DCACHE_RAM_BASE;
.car.data . (NOLOAD) : {
+ _car_data_start = .;
*(.car.global_data);
+ /* The cbmem_console section comes last to take advantage of
+ * a zero-sized array to hold the memconsole contents that
+ * grows to a bound of CONFIG_CONSOLE_CAR_BUFFER_SIZE. However,
+ * collisions within the cache-as-ram region cannot be
+ * statically checked becuase the cache-as-ram region usage is
+ * cpu/chipset dependent. */
*(.car.cbmem_console);
+ _car_data_end = .;
}
_bogus = ASSERT((SIZEOF(.car.data) <= CONFIG_DCACHE_RAM_SIZE), "Cache as RAM area is too full");
diff --git a/src/cpu/Makefile.inc b/src/cpu/Makefile.inc
index b48a803..8d93756 100644
--- a/src/cpu/Makefile.inc
+++ b/src/cpu/Makefile.inc
@@ -6,6 +6,7 @@ subdirs-y += armltd
subdirs-y += intel
subdirs-y += samsung
subdirs-y += via
+subdirs-y += x86
################################################################################
## Rules for building the microcode blob in CBFS
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index c64a8e4..5687a7a 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -115,3 +115,12 @@ config X86_AMD_FIXED_MTRRS
help
This option informs the MTRR code to use the RdMem and WrMem fields
in the fixed MTRR MSRs.
+
+config CAR_MIGRATION
+ def_bool n
+ depends on DYNAMIC_CBMEM || EARLY_CBMEM_INIT
+ help
+ Migrate the cache-as-ram variables to cbmem once cbmem is set up
+ in romstage. This option is only needed if one will be doing more
+ work in romstage after the cache-as-ram is torn down aside from
+ loading ramstage.
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc
new file mode 100644
index 0000000..fe8648c
--- /dev/null
+++ b/src/cpu/x86/Makefile.inc
@@ -0,0 +1 @@
+romstage-$(CONFIG_CAR_MIGRATION) += car.c
diff --git a/src/cpu/x86/car.c b/src/cpu/x86/car.c
new file mode 100644
index 0000000..5a2de02
--- /dev/null
+++ b/src/cpu/x86/car.c
@@ -0,0 +1,102 @@
+/*
+ * 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
+ */
+
+#include <string.h>
+#include <console/console.h>
+#include <cbmem.h>
+#include <cpu/x86/car.h>
+
+typedef void (* const car_migration_func_t)(void);
+
+extern car_migration_func_t _car_migrate_start;
+extern car_migration_func_t _car_migrate_end;
+
+extern char _car_data_start[];
+extern char _car_data_end[];
+
+
+
+/*
+ * The car_migrated global variable determines if the cache-as-ram space has
+ * been migrated to real RAM. It does this by asumming the following things:
+ * 1. cache-as-ram space is zero'd out once it is set up.
+ * 2. Either the cache-as-ram space is memory-backed after getting torn down
+ * or the space returns 0xff's for each byte read.
+ * Based on these 2 attributes there is the ability to tell when the
+ * cache-as-ram region has been migrated.
+ */
+static int car_migrated CAR_GLOBAL;
+
+
+void *car_get_var_ptr(void *var)
+{
+ char *migrated_base;
+ int offset;
+ void * _car_start = &_car_data_start;
+ void * _car_end = &_car_data_end;
+
+ /* If the cache-as-ram has not been migrated return the pointer
+ * passed in. */
+ if (!car_migrated)
+ return var;
+
+ if (var < _car_start || var >= _car_end) {
+ printk(BIOS_ERR,
+ "Requesting CAR variable outside of CAR region: %p\n",
+ var);
+ return var;
+ }
+
+ migrated_base = cbmem_find(CBMEM_ID_CAR_GLOBALS);
+
+ if (migrated_base == NULL) {
+ printk(BIOS_ERR, "CAR: Could not find migration base!\n");
+ return var;
+ }
+
+ offset = (char *)var - (char *)_car_start;
+
+ return &migrated_base[offset];
+}
+
+void car_migrate_variables(void)
+{
+ void *migrated_base;
+ car_migration_func_t *migrate_func;
+ int car_data_size = &_car_data_end[0] - &_car_data_start[0];
+
+ migrated_base = cbmem_add(CBMEM_ID_CAR_GLOBALS, car_data_size);
+
+ if (migrated_base == NULL) {
+ printk(BIOS_ERR, "Could not migrate CAR data!\n");
+ return;
+ }
+
+ memcpy(migrated_base, &_car_data_start[0], car_data_size);
+
+ /* Mark that the data has bee moved. */
+ car_migrated = ~0;
+
+ /* Call all the migration functions. */
+ migrate_func = &_car_migrate_start;
+ while (migrate_func != &_car_migrate_end) {
+ (*migrate_func)();
+ migrate_func++;
+ }
+}
diff --git a/src/include/cbmem.h b/src/include/cbmem.h
index 67cb1cb..baec780 100644
--- a/src/include/cbmem.h
+++ b/src/include/cbmem.h
@@ -69,6 +69,7 @@
#define CBMEM_ID_RAMSTAGE_CACHE 0x9a3ca54e
#define CBMEM_ID_ROOT 0xff4007ff
#define CBMEM_ID_VBOOT_HANDOFF 0x780074f0
+#define CBMEM_ID_CAR_GLOBALS 0xcac4e6a3
#define CBMEM_ID_NONE 0x00000000
#ifndef __ASSEMBLER__
diff --git a/src/include/cpu/x86/car.h b/src/include/cpu/x86/car.h
index 2d2af03..b57620d 100644
--- a/src/include/cpu/x86/car.h
+++ b/src/include/cpu/x86/car.h
@@ -28,4 +28,33 @@
#define CAR_CBMEM
#endif
+#if CONFIG_CAR_MIGRATION && defined(__PRE_RAM__)
+#define CAR_MIGRATE_ATTR __attribute__ ((used,section (".car.migrate")))
+
+/* Call migrate_fn_() when CAR globals are migrated. */
+#define CAR_MIGRATE(migrate_fn_) \
+ static void (* const migrate_fn_ ## _ptr)(void) CAR_MIGRATE_ATTR = \
+ migrate_fn_;
+
+/* Get the correct pointer for the CAR global variable. */
+void *car_get_var_ptr(void *var);
+
+/* Get and set a primitive type global varible. */
+#define car_get_var(var) \
+ *(typeof(var) *)car_get_var_ptr(&(var))
+#define car_set_var(var, val) \
+ do { car_get_var(var) = (val); } while(0)
+
+/* Migrate the CAR variables to memory. */
+void car_migrate_variables(void);
+
+#else
+#define CAR_MIGRATE(migrate_fn_)
+static inline void *car_get_var_ptr(void *var) { return var; }
+#define car_get_var(var) (var)
+#define car_set_var(var, val) do { (var) = (val); } while (0)
+static inline void car_migrate_variables(void) { }
+#endif
+
+
#endif
diff --git a/src/lib/cbmem.c b/src/lib/cbmem.c
index e8200b6..3702da1 100644
--- a/src/lib/cbmem.c
+++ b/src/lib/cbmem.c
@@ -22,6 +22,7 @@
#include <bootstate.h>
#include <cbmem.h>
#include <console/console.h>
+#include <cpu/x86/car.h>
#if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__)
#include <arch/acpi.h>
#endif
@@ -228,6 +229,9 @@ int cbmem_initialize(void)
#ifndef __PRE_RAM__
cbmem_arch_init();
#endif
+ /* Migrate cache-as-ram variables. */
+ car_migrate_variables();
+
return rv;
}
#endif
diff --git a/src/lib/cbmem_info.c b/src/lib/cbmem_info.c
index ad8c890..7031a70 100644
--- a/src/lib/cbmem_info.c
+++ b/src/lib/cbmem_info.c
@@ -46,6 +46,7 @@ static struct cbmem_id_to_name {
{ CBMEM_ID_RAMSTAGE_CACHE, "RAMSTAGE $ " },
{ CBMEM_ID_ROOT, "CBMEM ROOT " },
{ CBMEM_ID_VBOOT_HANDOFF, "VBOOT " },
+ { CBMEM_ID_CAR_GLOBALS, "CAR GLOBALS" },
};
void cbmem_print_entry(int n, u32 id, u64 base, u64 size)
diff --git a/src/lib/dynamic_cbmem.c b/src/lib/dynamic_cbmem.c
index 5c269a0..ba7760d 100644
--- a/src/lib/dynamic_cbmem.c
+++ b/src/lib/dynamic_cbmem.c
@@ -23,6 +23,7 @@
#include <cbmem.h>
#include <string.h>
#include <stdlib.h>
+#include <cpu/x86/car.h>
#if CONFIG_HAVE_ACPI_RESUME && !defined(__PRE_RAM__)
#include <arch/acpi.h>
#endif
@@ -182,12 +183,17 @@ void cbmem_initialize_empty(void)
root, root->max_entries);
cbmem_arch_init();
+
+ /* Migrate cache-as-ram variables. */
+ car_migrate_variables();
}
static inline int cbmem_fail_recovery(void)
{
cbmem_initialize_empty();
cbmem_handle_acpi_resume();
+ /* Migrate cache-as-ram variables. */
+ car_migrate_variables();
return 1;
}
@@ -256,6 +262,9 @@ int cbmem_initialize(void)
cbmem_arch_init();
+ /* Migrate cache-as-ram variables. */
+ car_migrate_variables();
+
/* Recovery successful. */
return 0;
}
the following patch was just integrated into master:
commit c49ae3c655172c98b31bde50796fccf42683ee9f
Author: Peter Stuge <peter(a)stuge.se>
Date: Sun May 12 01:25:07 2013 +0200
Revert "PC Engines ALIX.1C: Add CMOS defaults."
Revert commit f90071faeee3358748d0c8d31e46721b53241e28 [1] as
it was merged without its dependencies and therefore the source
tree currently does not build [2][3].
OPTION option_table.h
GEN build.h
SCONFIG mainboard/pcengines/alix1c/devicetree.cb
CC arch/x86/lib/cbfs_and_run.romstage.o
CC arch/x86/lib/memcpy.romstage.o
CC arch/x86/lib/memset.romstage.o
CC arch/x86/lib/rom_media.romstage.o
CC arch/x86/lib/romstage_console.romstage.o
CC console/die.romstage.o
CC console/post.romstage.o
CC console/vtxprintf.romstage.o
CC device/device_romstage.romstage.o
CC lib/cbfs.romstage.o
CC lib/compute_ip_checksum.romstage.o
CC lib/gcc.romstage.o
CC lib/lzma.romstage.o
CC lib/memchr.romstage.o
CC lib/memcmp.romstage.o
CC lib/memmove.romstage.o
CC lib/ramtest.romstage.o
CC lib/uart8250.romstage.o
CC southbridge/amd/cs5536/smbus.romstage.o
ROMCC generated/bootblock.inc
GEN generated/bootblock.ld
make: *** No rule to make target `nvramtool', needed by `coreboot-builds/pcengines_alix1c/coreboot.pre1'. Stop.
make: *** Waiting for unfinished jobs....
OPTION cmos_layout.bin
[1] http://review.coreboot.org/#/c/3229/
[2] http://www.coreboot.org/pipermail/coreboot/2013-May/075864.html
[3] http://qa.coreboot.org/job/coreboot-gerrit/6251/testReport/junit/(root)/boa…
Change-Id: I4764d90c39ccdb4dc7e7a9aef7525c306614e1a8
Signed-off-by: Peter Stuge <peter(a)stuge.se>
Reviewed-on: http://review.coreboot.org/3245
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: David Hendricks <dhendrix(a)chromium.org>
See http://review.coreboot.org/3245 for details.
-gerrit
the following patch was just integrated into master:
commit 08d0baa77aaa9430b0f6c03cfaef8666bf19c4ce
Author: Peter Stuge <peter(a)stuge.se>
Date: Sun May 12 01:24:50 2013 +0200
Revert "Asus M4A785T-M: Add CMOS defaults."
Revert commit b8b3e8bff32ee7dddcacec11e015f6683783eb2f [1] as
it was merged without its dependencies and therefore the source
tree currently does not build [2][3].
OPTION option_table.h
SCONFIG mainboard/asus/m4a785t-m/devicetree.cb
make: *** No rule to make target `nvramtool', needed by `coreboot-builds/asus_m4a785t-m/coreboot.pre1'. Stop.
make: *** Waiting for unfinished jobs....
OPTION cmos_layout.bin
[1] http://review.coreboot.org/3224
[2] http://www.coreboot.org/pipermail/coreboot/2013-May/075864.html
[3] http://qa.coreboot.org/job/coreboot-gerrit/6251/testReport/junit/(root)/boa…
Change-Id: I8bf33b62b56627f0eea9440ff5e5136e4122ef01
Signed-off-by: Peter Stuge <peter(a)stuge.se>
Reviewed-on: http://review.coreboot.org/3244
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix(a)chromium.org>
See http://review.coreboot.org/3244 for details.
-gerrit
Paul Menzel (paulepanter(a)users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3242
-gerrit
commit 53d3fb2f44c4ea06c57ae6737f2ca48b6676b94b
Author: Paul Menzel <paulepanter(a)users.sourceforge.net>
Date: Wed May 8 17:08:55 2013 +0200
Intel Sandy Bridge: udelay.c: Add secunet’s copyright
Add secunet’s copyright to `udelay.c` as this was added to
`udelay.c` from the i945 northbridge when adding the function
`multiply_to_tsc()` to `udelay.c` in the following commit.
commit 8bacc40fc7bd07365c2992b260ddbd45cd6e4518
Author: Nico Huber <nico.huber(a)secunet.com>
Date: Thu Jul 19 16:16:59 2012 +0200
Fix udelay() implementation for i945 romstage
Reviewed-on: http://review.coreboot.org/1254
Change-Id: Ied0013ad4b1a9e5e2b330614bb867fd806f9a407
Signed-off-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
---
src/northbridge/intel/sandybridge/udelay.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/northbridge/intel/sandybridge/udelay.c b/src/northbridge/intel/sandybridge/udelay.c
index 3edd69d..5bbc383 100644
--- a/src/northbridge/intel/sandybridge/udelay.c
+++ b/src/northbridge/intel/sandybridge/udelay.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2008 coresystems GmbH
+ * 2012 secunet Security Networks AG
*
* 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