Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3203
-gerrit
commit c4c18f728fed798fe6d283bd6259c08cfed76c14
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Thu May 2 09:42:13 2013 -0500
haswell: use asmlinkage for assembly-called funcs
When the haswell MP/SMM code was developed it was using a coreboot
repository that did not contain the asmlinkage macro. Now that the
asmlinkage macro exists use it.
BUG=None
BRANCH=None
TEST=Built and booted.
Change-Id: I662f1b16d1777263b96a427334fff8f98a407755
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/intel/haswell/haswell.h | 4 +++-
src/cpu/intel/haswell/mp_init.c | 3 +--
src/cpu/intel/haswell/romstage.c | 2 +-
src/cpu/intel/haswell/smmrelocate.c | 2 +-
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/cpu/intel/haswell/haswell.h b/src/cpu/intel/haswell/haswell.h
index a1c6f39..8f4368f 100644
--- a/src/cpu/intel/haswell/haswell.h
+++ b/src/cpu/intel/haswell/haswell.h
@@ -22,6 +22,8 @@
#ifndef _CPU_INTEL_HASWELL_H
#define _CPU_INTEL_HASWELL_H
+#include <arch/cpu.h>
+
/* Haswell bus clock is fixed at 100MHz */
#define HASWELL_BCLK 100
@@ -148,7 +150,7 @@ void romstage_common(const struct romstage_params *params);
* +32: MTTR mask 1 63:32
* ...
*/
-void * __attribute__((regparm(0))) romstage_main(unsigned long bist);
+void * asmlinkage romstage_main(unsigned long bist);
/* romstage_after_car() is the C function called after cache-as-ram has
* been torn down. It is responsible for loading the ramstage. */
void romstage_after_car(void);
diff --git a/src/cpu/intel/haswell/mp_init.c b/src/cpu/intel/haswell/mp_init.c
index ddcff6c..deba629 100644
--- a/src/cpu/intel/haswell/mp_init.c
+++ b/src/cpu/intel/haswell/mp_init.c
@@ -150,8 +150,7 @@ static void cleanup_rom_caching(void)
/* By the time APs call ap_init() caching has been setup, and microcode has
* been loaded. */
-static void __attribute__((cdecl))
-ap_init(unsigned int cpu, void *microcode_ptr)
+static void asmlinkage ap_init(unsigned int cpu, void *microcode_ptr)
{
struct cpu_info *info;
diff --git a/src/cpu/intel/haswell/romstage.c b/src/cpu/intel/haswell/romstage.c
index ff57584..077e409 100644
--- a/src/cpu/intel/haswell/romstage.c
+++ b/src/cpu/intel/haswell/romstage.c
@@ -162,7 +162,7 @@ static void *setup_romstage_stack_after_car(void)
return slot;
}
-void * __attribute__((regparm(0))) romstage_main(unsigned long bist)
+void * asmlinkage romstage_main(unsigned long bist)
{
int i;
void *romstage_stack_after_car;
diff --git a/src/cpu/intel/haswell/smmrelocate.c b/src/cpu/intel/haswell/smmrelocate.c
index a8ab841..6caeafa 100644
--- a/src/cpu/intel/haswell/smmrelocate.c
+++ b/src/cpu/intel/haswell/smmrelocate.c
@@ -164,7 +164,7 @@ static int bsp_setup_msr_save_state(struct smm_relocation_params *relo_params)
/* The relocation work is actually performed in SMM context, but the code
* resides in the ramstage module. This occurs by trampolining from the default
* SMRAM entry point to here. */
-static void __attribute__((cdecl))
+static void asmlinkage
cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime)
{
msr_t mtrr_cap;
Dave Frodin (dave.frodin(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3208
-gerrit
commit 02ac134448ce8ce59be7232164e972372f33c0ab
Author: Dave Frodin <dave.frodin(a)se-eng.com>
Date: Mon May 6 15:51:39 2013 -0600
libpayload: make cfbs searches even less verbose
The cbfs core code would print out the name of the file it is
searching for and when it is found would print out the name
again. This contributes to a lot of unnecessary messages in a
functioning payloads output. Change this message to a DEBUG one
so that it will only be printed when CONFIG_DEBUG_CBFS is enabled.
Change-Id: Ib238ff174bedba8eaaad8d1d452721fcac339b1a
Signed-off-by: Dave Frodin <dave.frodin(a)se-eng.com>
---
payloads/libpayload/libcbfs/cbfs_core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/payloads/libpayload/libcbfs/cbfs_core.c b/payloads/libpayload/libcbfs/cbfs_core.c
index 3fe6971..9274736 100644
--- a/payloads/libpayload/libcbfs/cbfs_core.c
+++ b/payloads/libpayload/libcbfs/cbfs_core.c
@@ -123,7 +123,7 @@ struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
#endif
DEBUG("CBFS location: 0x%x~0x%x, align: %d\n", offset, romsize, align);
- LOG("Looking for '%s' starting from 0x%x.\n", name, offset);
+ DEBUG("Looking for '%s' starting from 0x%x.\n", name, offset);
media->open(media);
while (offset < romsize &&
media->read(media, &file, offset, sizeof(file)) == sizeof(file)) {
@@ -150,7 +150,7 @@ struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
} else if (strcmp(file_name, name) == 0) {
int file_offset = ntohl(file.offset),
file_len = ntohl(file.len);
- LOG("Found file (offset=0x%x, len=%d).\n",
+ DEBUG("Found file (offset=0x%x, len=%d).\n",
offset + file_offset, file_len);
media->unmap(media, file_name);
file_ptr = media->map(media, offset,
the following patch was just integrated into master:
commit 3eddcffe2d9f978081ab2c06cc45ddc473939ded
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed May 1 08:40:13 2013 -0500
libpayload: make searching for a file less verbose
The cbfs core code would print out all unmatched file
names when searching for a file. This contributes to a lot
of unnecessary messages in the boot log. Change this
message to a DEBUG one so that it will only be printed when
CONFIG_DEBUG_CBFS is enabled.
Change-Id: I34c747e0d3406351318abf70994dbc0bb3fa6c01
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
Reviewed-on: http://review.coreboot.org/3164
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Marc Jones <marc.jones(a)se-eng.com>
Tested-by: build bot (Jenkins)
Build-Tested: build bot (Jenkins) at Thu May 2 03:13:40 2013, giving +1
See http://review.coreboot.org/3164 for details.
-gerrit
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 8376e7535aab2106fa65cae15431485141b7e924
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 5dcd7ba..9fde0e4 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 32af0cc..e9d072f 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();
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 18c7bdfe27d80b99e764d54e92585ee5b6aed9a1
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 ce7f400..5dcd7ba 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 a3555d8..4a31088 100644
--- a/src/arch/x86/include/arch/cpu.h
+++ b/src/arch/x86/include/arch/cpu.h
@@ -164,9 +164,14 @@ struct cpu_driver *find_cpu_driver(struct device *cpu);
#include <arch/io.h>
#endif
+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 132cd10..7cef33ed 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
@@ -465,6 +466,8 @@ void hardwaremain(int boot_complete)
hard_reset();
}
+ 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/3204
-gerrit
commit 8851349cbb02702e7a9bae7664ff05a0b98e3c8e
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Mon May 6 10:50:19 2013 -0500
boot state: add ability to block state transitions
In order to properly sequence the boot state machine it's
important that outside code can block the transition from
one state to the next. When timers are not involved there's
no reason for any of the existing code to block a state
transition. However, if there is a timer callback that needs to
complete by a certain point in the boot sequence it is necessary
place a block for the given state.
To that end, 4 new functions are added to provide the API for
blocking a state.
1. boot_state_block(boot_state_t state, boot_state_sequence_t seq);
2. boot_state_unblock(boot_state_t state, boot_state_sequence_t seq);
3. boot_state_current_block(void);
4. boot_state_current_unblock(void);
Change-Id: Ieb37050ff652fd85a6b1e0e2f81a1a2807bab8e0
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/include/bootstate.h | 8 +++
src/lib/hardwaremain.c | 137 +++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 126 insertions(+), 19 deletions(-)
diff --git a/src/include/bootstate.h b/src/include/bootstate.h
index f732d1e..fefdb57 100644
--- a/src/include/bootstate.h
+++ b/src/include/bootstate.h
@@ -156,6 +156,14 @@ int boot_state_sched_on_entry(struct boot_state_callback *bscb,
int boot_state_sched_on_exit(struct boot_state_callback *bscb,
boot_state_t state);
+/* Block/Unblock the (state, seq) pair from transitioning. Returns 0 on
+ * sucess < 0 when the phase of the (state,seq) has already ran. */
+int boot_state_block(boot_state_t state, boot_state_sequence_t seq);
+int boot_state_unblock(boot_state_t state, boot_state_sequence_t seq);
+/* Block/Unblock current state phase from transitioning. */
+void boot_state_current_block(void);
+void boot_state_current_unblock(void);
+
/* Entry into the boot state machine. */
void hardwaremain(int boot_complete);
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index 8e5481e..699946c 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -72,10 +72,18 @@ struct boot_state_times {
struct mono_time samples[MAX_TIME_SAMPLES];
};
+/* The prologue (BS_ON_ENTRY) and epilogue (BS_ON_EXIT) of a state can be
+ * blocked from transitioning to the next (state,seq) pair. When the blockers
+ * field is 0 a transition may occur. */
+struct boot_phase {
+ struct boot_state_callback *callbacks;
+ int blockers;
+};
+
struct boot_state {
const char *name;
boot_state_t id;
- struct boot_state_callback *seq_callbacks[2];
+ struct boot_phase phases[2];
boot_state_t (*run_state)(void *arg);
void *arg;
int complete : 1;
@@ -89,7 +97,7 @@ struct boot_state {
{ \
.name = #state_, \
.id = state_, \
- .seq_callbacks = { NULL, NULL }, \
+ .phases = { { NULL, 0 }, { NULL, 0 } }, \
.run_state = run_func_, \
.arg = NULL, \
.complete = 0, \
@@ -299,29 +307,55 @@ static void bs_run_timers(int drain) {}
static void bs_call_callbacks(struct boot_state *state,
boot_state_sequence_t seq)
{
- while (state->seq_callbacks[seq] != NULL) {
- struct boot_state_callback *bscb;
+ struct boot_phase *phase = &state->phases[seq];
+
+ while (1) {
+ if (phase->callbacks != NULL) {
+ struct boot_state_callback *bscb;
- /* Remove the first callback. */
- bscb = state->seq_callbacks[seq];
- state->seq_callbacks[seq] = bscb->next;
- bscb->next = NULL;
+ /* Remove the first callback. */
+ bscb = phase->callbacks;
+ phase->callbacks = bscb->next;
+ bscb->next = NULL;
#if BOOT_STATE_DEBUG
- printk(BS_DEBUG_LVL, "BS: callback (%p) @ %s.\n",
- bscb, bscb->location);
+ printk(BS_DEBUG_LVL, "BS: callback (%p) @ %s.\n",
+ bscb, bscb->location);
#endif
- bscb->callback(bscb->arg);
+ bscb->callback(bscb->arg);
+
+ continue;
+ }
+
+ /* All callbacks are complete and there are no blockers for
+ * this state. Therefore, this part of the sate is complete. */
+ if (!phase->blockers)
+ break;
+
+ /* Something is blocking this state from transitioning. As
+ * there are no more callbacks a pending timer needs to be
+ * ran to unblock the state. */
+ bs_run_timers(0);
}
}
-static void bs_walk_state_machine(boot_state_t current_state_id)
+/* Keep track of the current state. */
+static struct state_tracker {
+ boot_state_t state_id;
+ boot_state_sequence_t seq;
+} current_phase = {
+ .state_id = BS_PRE_DEVICE,
+ .seq = BS_ON_ENTRY,
+};
+
+static void bs_walk_state_machine(void)
{
while (1) {
struct boot_state *state;
+ boot_state_t next_id;
- state = &boot_states[current_state_id];
+ state = &boot_states[current_phase.state_id];
if (state->complete) {
printk(BIOS_EMERG, "BS: %s state already executed.\n",
@@ -335,17 +369,25 @@ static void bs_walk_state_machine(boot_state_t current_state_id)
bs_sample_time(state);
- bs_call_callbacks(state, BS_ON_ENTRY);
+ bs_call_callbacks(state, current_phase.seq);
+ /* Update the current sequence so that any calls to block the
+ * current state from the run_state() function will place a
+ * block on the correct phase. */
+ current_phase.seq = BS_ON_EXIT;
bs_sample_time(state);
- current_state_id = state->run_state(state->arg);
+ next_id = state->run_state(state->arg);
printk(BS_DEBUG_LVL, "BS: Exiting %s state.\n", state->name);
bs_sample_time(state);
- bs_call_callbacks(state, BS_ON_EXIT);
+ bs_call_callbacks(state, current_phase.seq);
+
+ /* Update the current phase with new state id and sequence. */
+ current_phase.state_id = next_id;
+ current_phase.seq = BS_ON_ENTRY;
bs_sample_time(state);
@@ -367,8 +409,8 @@ static int boot_state_sched_callback(struct boot_state *state,
return -1;
}
- bscb->next = state->seq_callbacks[seq];
- state->seq_callbacks[seq] = bscb;
+ bscb->next = state->phases[seq].callbacks;
+ state->phases[seq].callbacks = bscb;
return 0;
}
@@ -433,7 +475,64 @@ void hardwaremain(int boot_complete)
/* FIXME: Is there a better way to handle this? */
init_timer();
- bs_walk_state_machine(BS_PRE_DEVICE);
+ bs_walk_state_machine();
+
die("Boot state machine failure.\n");
}
+
+int boot_state_block(boot_state_t state, boot_state_sequence_t seq)
+{
+ struct boot_phase *bp;
+
+ /* Blocking a previously ran state is not appropriate. */
+ if (current_phase.state_id > state ||
+ (current_phase.state_id == state && current_phase.seq > seq) ) {
+ printk(BIOS_WARNING,
+ "BS: Completed state (%d, %d) block attempted.\n",
+ state, seq);
+ return -1;
+ }
+
+ bp = &boot_states[state].phases[seq];
+ bp->blockers++;
+
+ return 0;
+}
+
+int boot_state_unblock(boot_state_t state, boot_state_sequence_t seq)
+{
+ struct boot_phase *bp;
+
+ /* Blocking a previously ran state is not appropriate. */
+ if (current_phase.state_id > state ||
+ (current_phase.state_id == state && current_phase.seq > seq) ) {
+ printk(BIOS_WARNING,
+ "BS: Completed state (%d, %d) unblock attempted.\n",
+ state, seq);
+ return -1;
+ }
+
+ bp = &boot_states[state].phases[seq];
+
+ if (bp->blockers == 0) {
+ printk(BIOS_WARNING,
+ "BS: Unblock attempted on non-blocked state (%d, %d).\n",
+ state, seq);
+ return -1;
+ }
+
+ bp->blockers--;
+
+ return 0;
+}
+
+void boot_state_current_block(void)
+{
+ boot_state_block(current_phase.state_id, current_phase.seq);
+}
+
+void boot_state_current_unblock(void)
+{
+ boot_state_unblock(current_phase.state_id, current_phase.seq);
+}
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3203
-gerrit
commit edbeb264f21eebed9eeaf5d6927d3278e8c12e48
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Thu May 2 09:42:13 2013 -0500
haswell: use asmlinkage for assembly-called funcs
When the haswell MP/SMM code was developed it was using a coreboot
repository that did not contain the asmlinkage macro. Now that the
asmlinkage macro exists use it.
BUG=None
BRANCH=None
TEST=Built and booted.
Change-Id: I662f1b16d1777263b96a427334fff8f98a407755
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/intel/haswell/haswell.h | 4 +++-
src/cpu/intel/haswell/mp_init.c | 3 +--
src/cpu/intel/haswell/romstage.c | 2 +-
src/cpu/intel/haswell/smmrelocate.c | 2 +-
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/cpu/intel/haswell/haswell.h b/src/cpu/intel/haswell/haswell.h
index a1c6f39..8f4368f 100644
--- a/src/cpu/intel/haswell/haswell.h
+++ b/src/cpu/intel/haswell/haswell.h
@@ -22,6 +22,8 @@
#ifndef _CPU_INTEL_HASWELL_H
#define _CPU_INTEL_HASWELL_H
+#include <arch/cpu.h>
+
/* Haswell bus clock is fixed at 100MHz */
#define HASWELL_BCLK 100
@@ -148,7 +150,7 @@ void romstage_common(const struct romstage_params *params);
* +32: MTTR mask 1 63:32
* ...
*/
-void * __attribute__((regparm(0))) romstage_main(unsigned long bist);
+void * asmlinkage romstage_main(unsigned long bist);
/* romstage_after_car() is the C function called after cache-as-ram has
* been torn down. It is responsible for loading the ramstage. */
void romstage_after_car(void);
diff --git a/src/cpu/intel/haswell/mp_init.c b/src/cpu/intel/haswell/mp_init.c
index ddcff6c..deba629 100644
--- a/src/cpu/intel/haswell/mp_init.c
+++ b/src/cpu/intel/haswell/mp_init.c
@@ -150,8 +150,7 @@ static void cleanup_rom_caching(void)
/* By the time APs call ap_init() caching has been setup, and microcode has
* been loaded. */
-static void __attribute__((cdecl))
-ap_init(unsigned int cpu, void *microcode_ptr)
+static void asmlinkage ap_init(unsigned int cpu, void *microcode_ptr)
{
struct cpu_info *info;
diff --git a/src/cpu/intel/haswell/romstage.c b/src/cpu/intel/haswell/romstage.c
index ff57584..077e409 100644
--- a/src/cpu/intel/haswell/romstage.c
+++ b/src/cpu/intel/haswell/romstage.c
@@ -162,7 +162,7 @@ static void *setup_romstage_stack_after_car(void)
return slot;
}
-void * __attribute__((regparm(0))) romstage_main(unsigned long bist)
+void * asmlinkage romstage_main(unsigned long bist)
{
int i;
void *romstage_stack_after_car;
diff --git a/src/cpu/intel/haswell/smmrelocate.c b/src/cpu/intel/haswell/smmrelocate.c
index a8ab841..6caeafa 100644
--- a/src/cpu/intel/haswell/smmrelocate.c
+++ b/src/cpu/intel/haswell/smmrelocate.c
@@ -164,7 +164,7 @@ static int bsp_setup_msr_save_state(struct smm_relocation_params *relo_params)
/* The relocation work is actually performed in SMM context, but the code
* resides in the ramstage module. This occurs by trampolining from the default
* SMRAM entry point to here. */
-static void __attribute__((cdecl))
+static void asmlinkage
cpu_smm_do_relocation(void *arg, int cpu, const struct smm_runtime *runtime)
{
msr_t mtrr_cap;
Aaron Durbin (adurbin(a)google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3171
-gerrit
commit c97cfef7cd3cff03d0a74e699a4ad257b54f6953
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed May 1 15:55:14 2013 -0500
x86: harden tsc udelay() function
Since the TSC udelay() fucntion can be used in SMM that means the
TSC can count up to whatever value. The current loop was not handling
TSC rollover properly. In most cases this should not matter as the TSC
typically starts ticking at value 0, and it would take a very long time
to roll it over. However, it is my understanding that this behavior is
not guaranteed. Theoretically the TSC could start or be be written to
with a large value that would cause the rollover.
Change-Id: I2f11a5bc4f27d5543e74f8224811fa91e4a55484
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/cpu/x86/tsc/delay_tsc.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c
index 0540496..0e2a9c0 100644
--- a/src/cpu/x86/tsc/delay_tsc.c
+++ b/src/cpu/x86/tsc/delay_tsc.c
@@ -172,18 +172,18 @@ static inline unsigned long get_clocks_per_usec(void)
void udelay(unsigned us)
{
- unsigned long long count;
- unsigned long long stop;
- unsigned long long clocks;
+ unsigned long long start;
+ unsigned long long current;
+ unsigned long long clocks;
+ start = rdtscll();
clocks = us;
clocks *= get_clocks_per_usec();
- count = rdtscll();
- stop = clocks + count;
- while(stop > count) {
+ current = rdtscll();
+ while((current - start) < clocks) {
cpu_relax();
- count = rdtscll();
- }
+ current = rdtscll();
+ }
}
#if CONFIG_TSC_MONOTONIC_TIMER && !defined(__PRE_RAM__) && !defined(__SMM__)
Paul Menzel (paulepanter(a)users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3202
-gerrit
commit 7a6c4b12ae11f36f7b6da7fbd32565ef2e4167c0
Author: Paul Menzel <paulepanter(a)users.sourceforge.net>
Date: Mon May 6 15:18:57 2013 +0200
AMD AGESA Hudson: Include `stdint.h` and `io.h` to fix build
Apparently the files `smbus.{h,c}`, where never used and therefore
build beforehand. Needing one function in them for the ASUS F2A85-M
the build fails as some headers are missing. Including the headers
`stdint.h` and `io.h` fixes the following errors.
[…]
CC southbridge/amd/agesa/hudson/smbus.romstage.o
In file included from src/southbridge/amd/agesa/hudson/smbus.c:23:0:
src/southbridge/amd/agesa/hudson/smbus.h:67:24: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:67:43: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:67:55: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:68:25: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:68:44: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:68:56: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:68:69: error: unknown type name 'u8'
src/southbridge/amd/agesa/hudson/smbus.h:69:24: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:69:43: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:70:24: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:70:43: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:70:55: error: unknown type name 'u8'
src/southbridge/amd/agesa/hudson/smbus.h:71:20: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:71:35: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:71:49: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:71:59: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:71:69: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:72:20: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:72:35: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:72:49: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:72:59: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:73:20: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:73:32: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:73:44: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.h:73:54: error: unknown type name 'u32'
src/southbridge/amd/agesa/hudson/smbus.c: In function 'smbus_delay':
src/southbridge/amd/agesa/hudson/smbus.c:27:2: error: implicit declaration of function 'outb' [-Werror=implicit-function-declaration]
src/southbridge/amd/agesa/hudson/smbus.c:27:2: error: implicit declaration of function 'inb' [-Werror=implicit-function-declaration]
[…]
Probably all the (AMD(?)) `smbus.{h,c}` suffer from this and
should be fixed. Even better, as these function do not differ
between most boards, the file should be moved out from the
specific southbridge directories.
[1] http://qa.coreboot.org/job/coreboot-gerrit/6168/testReport/junit/(root)/boa…
Change-Id: I285101fa06a365da44fa27b688c536e614d57f50
Signed-off-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
---
src/southbridge/amd/agesa/hudson/smbus.c | 2 ++
src/southbridge/amd/agesa/hudson/smbus.h | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/southbridge/amd/agesa/hudson/smbus.c b/src/southbridge/amd/agesa/hudson/smbus.c
index 682b86d..e428d43 100644
--- a/src/southbridge/amd/agesa/hudson/smbus.c
+++ b/src/southbridge/amd/agesa/hudson/smbus.c
@@ -20,6 +20,8 @@
#ifndef _HUDSON_SMBUS_C_
#define _HUDSON_SMBUS_C_
+#include <io.h>
+#include <stdint.h>
#include "smbus.h"
static inline void smbus_delay(void)
diff --git a/src/southbridge/amd/agesa/hudson/smbus.h b/src/southbridge/amd/agesa/hudson/smbus.h
index b194aae..53cc0e6 100644
--- a/src/southbridge/amd/agesa/hudson/smbus.h
+++ b/src/southbridge/amd/agesa/hudson/smbus.h
@@ -20,7 +20,7 @@
#ifndef HUDSON_SMBUS_H
#define HUDSON_SMBUS_H
-//#include <stdint.h>
+#include <stdint.h>
#define SMBHSTSTAT 0x0
#define SMBSLVSTAT 0x1