summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2013-05-02 00:37:07 +0800
committerChromeBot <chrome-bot@google.com>2013-05-07 09:09:50 -0700
commit0a45fa17086d4556b7cb4ea0a9f53894197bc897 (patch)
treef2363f2a2320000404125bb36225e1420929d45d
parentb02c7b461740c457c6904a5d9d9f445afaa849cb (diff)
downloadchrome-ec-stabilize-4100.38.B.tar.gz
Pthread-based emulator for unit testingstabilize-4100.38.B
This is the first version of pthread-based RTOS emulator. With this, we will be able to test high-level modules entirely on the host machine. BUG=chrome-os-partner:19325 TEST='make runtests' and see tests passing. BRANCH=None Change-Id: I1f5fcd76aa84bdb46c7d35c5e60ae5d92fd3a319 Signed-off-by: Vic Yang <victoryang@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/49954 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--Makefile.rules28
-rw-r--r--Makefile.toolchain6
-rw-r--r--board/host/board.c12
-rw-r--r--board/host/board.h21
-rw-r--r--board/host/build.mk11
-rw-r--r--board/host/chipset.c34
-rw-r--r--board/host/ec.tasklist23
-rw-r--r--chip/host/build.mk12
-rw-r--r--chip/host/config.h51
-rw-r--r--chip/host/gpio.c24
-rw-r--r--chip/host/keyboard_raw.c46
-rw-r--r--chip/host/system.c74
-rw-r--r--chip/host/uart.c86
-rw-r--r--common/main.c2
-rw-r--r--common/system_common.c2
-rw-r--r--core/host/atomic.h37
-rw-r--r--core/host/build.mk11
-rw-r--r--core/host/cpu.h13
-rw-r--r--core/host/disabled.c11
-rw-r--r--core/host/host_exe.lds80
-rw-r--r--core/host/main.c18
-rw-r--r--core/host/panic.c13
-rw-r--r--core/host/task.c208
-rw-r--r--core/host/timer.c61
-rw-r--r--include/host_test.h15
-rw-r--r--include/link_defs.h (renamed from core/cortex-m/link_defs.h)2
-rw-r--r--include/task_id.h3
-rw-r--r--test/build.mk3
-rw-r--r--test/kb_scan.c15
-rw-r--r--test/mutex.c7
-rw-r--r--test/pingpong.c7
-rw-r--r--test/timer_dos.c7
-rw-r--r--test/utils.c17
-rwxr-xr-xutil/run_host_test26
34 files changed, 964 insertions, 22 deletions
diff --git a/Makefile.rules b/Makefile.rules
index e9b0a1802c..4def77851c 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -34,12 +34,14 @@ cmd_flat_to_obj = $(CC) -T $(out)/firmware_image.lds -nostdlib $(CPPFLAGS) \
cmd_elf_to_flat = $(OBJCOPY) -O binary $^ $@
cmd_elf_to_dis = $(OBJDUMP) -D $< > $@
cmd_elf = $(LD) $(LDFLAGS) $(objs) -o $@ -T $< -Map $(out)/$*.map
+cmd_exe = $(CC) $(HOST_TEST_LDFLAGS) $(objs) -o $@
cmd_c_to_o = $(CC) $(CFLAGS) -MMD -MF $@.d -c $< -o $@
cmd_c_to_build = $(BUILDCC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) \
-MMD -MF $@.d $< -o $@
cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d $(filter %.c, $^) -o $@
cmd_qemu = ./util/run_qemu_test --image=build/$(BOARD)/$*/$*.bin test/$*.py \
$(silent)
+cmd_host_test = ./util/run_host_test $* $(silent)
cmd_version = ./util/getversion.sh > $@
cmd_mv_from_tmp = mv $(out)/$*.bin.tmp $(out)/$*.bin
cmd_extractrw-y = cd $(out) && \
@@ -47,7 +49,7 @@ cmd_extractrw-y = cd $(out) && \
mv RW_SECTION_A $(PROJECT).RW.bin
cmd_copyrw-y = cd $(out) && cp $(PROJECT).RW.flat $(PROJECT).RW.bin
-.PHONY: all tests utils
+.PHONY: all tests utils hosttests
all: $(out)/$(PROJECT).bin utils
dis-y = $(out)/$(PROJECT).RO.dis $(out)/$(PROJECT).RW.dis
@@ -55,9 +57,10 @@ dis: $(dis-y)
utils: $(build-utils) $(host-utils)
+# On board test binaries
test-targets=$(foreach t,$(test-list-y),test-$(t))
qemu-test-targets=$(foreach t,$(test-list-y),qemu-$(t))
-.PHONY: $(qemu-test-target) $(test-targets)
+.PHONY: $(qemu-test-targets) $(test-targets)
$(test-targets): test-%:
@set -e ; \
@@ -72,6 +75,24 @@ $(qemu-test-targets): qemu-%: test-%
tests: $(test-targets)
qemu-tests: $(qemu-test-targets)
+# Emulator test executables
+host-test-targets=$(foreach t,$(test-list-host),host-$(t))
+run-test-targets=$(foreach t,$(test-list-host),run-$(t))
+.PHONY: $(host-test-targets) $(run-test-targets)
+
+$(host-test-targets): host-%:
+ @set -e ; \
+ echo " BUILD host - build/host/$*" ; \
+ $(MAKE) --no-print-directory BOARD=host PROJECT=$* \
+ V=$(V) out=build/host/$* TEST_BUILD=y EMU_BUILD=y \
+ CROSS_COMPILE= build/host/$*/$*.exe
+
+$(run-test-targets): run-%: host-%
+ $(call quiet,host_test,TEST )
+
+hosttests: $(host-test-targets)
+runtests: $(run-test-targets)
+
$(out)/firmware_image.lds: common/firmware_image.lds.S
$(call quiet,lds,LDS )
$(out)/%.lds: core/$(CORE)/ec.lds.S
@@ -98,6 +119,9 @@ $(out)/%.flat: $(out)/%.elf
$(out)/%.elf: $(out)/%.lds $(objs)
$(call quiet,elf,LD )
+$(out)/$(PROJECT).exe: $(objs)
+ $(call quiet,exe,EXE )
+
$(out)/%.o:%.c
$(call quiet,c_to_o,CC )
diff --git a/Makefile.toolchain b/Makefile.toolchain
index 8b2de15a85..0ec8365d8f 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -27,7 +27,8 @@ CFLAGS_WARN=-Wall -Werror -Wundef -Wstrict-prototypes -Wno-trigraphs \
CFLAGS_DEBUG= -g
CFLAGS_INCLUDE=$(foreach i,$(includes),-I$(i) )
CFLAGS_TEST=$(if $(TEST_BUILD),-DTEST_BUILD \
- -DTEST_TASKFILE=$(PROJECT).tasklist,)
+ -DTEST_TASKFILE=$(PROJECT).tasklist,) \
+ $(if $(EMU_BUILD),-DEMU_BUILD)
CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DBOARD_TASKFILE=ec.tasklist \
-DBOARD=$(BOARD) -DBOARD_$(BOARD) -DCORE=$(CORE) \
-DCHIP_$(CHIP) -DCHIP_VARIANT=$(CHIP_VARIANT) \
@@ -49,3 +50,6 @@ BUILD_CFLAGS= $(LIBFTDI_CFLAGS) $(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN)
HOST_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN)
LDFLAGS=-nostdlib -X
BUILD_LDFLAGS=$(LIBFTDI_LDLIBS)
+# For EC emulation on host environment, we need to force 32-bit binary.
+# TODO: Fix this. See crosbug.com/p/19257
+HOST_TEST_LDFLAGS=-T core/host/host_exe.lds -m32 -lrt -pthread
diff --git a/board/host/board.c b/board/host/board.c
new file mode 100644
index 0000000000..a3b8c28aca
--- /dev/null
+++ b/board/host/board.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* Emulator board-specific configuration */
+
+#include "board.h"
+#include "gpio.h"
+
+const struct gpio_info gpio_list[GPIO_COUNT] = {
+ {"EC_INT", 0, 0, 0, 0},
+};
diff --git a/board/host/board.h b/board/host/board.h
new file mode 100644
index 0000000000..de7049bd9d
--- /dev/null
+++ b/board/host/board.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Emulator board configuration */
+
+#ifndef __BOARD_H
+#define __BOARD_H
+
+#define CONFIG_HOST_EMU
+#define CONFIG_HOSTCMD
+#define CONFIG_KEYBOARD_PROTOCOL_MKBP
+
+enum gpio_signal {
+ GPIO_EC_INT,
+
+ GPIO_COUNT
+};
+
+#endif /* __BOARD_H */
diff --git a/board/host/build.mk b/board/host/build.mk
new file mode 100644
index 0000000000..28525a7679
--- /dev/null
+++ b/board/host/build.mk
@@ -0,0 +1,11 @@
+# -*- makefile -*-
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Board specific files build
+#
+
+CHIP:=host
+
+board-y=board.o chipset.o
diff --git a/board/host/chipset.c b/board/host/chipset.c
new file mode 100644
index 0000000000..b06e293778
--- /dev/null
+++ b/board/host/chipset.c
@@ -0,0 +1,34 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Chipset module for emulator */
+
+#include <stdio.h>
+#include "chipset.h"
+#include "common.h"
+#include "task.h"
+
+test_mockable void chipset_reset(int cold_reset)
+{
+ fprintf(stderr, "Chipset reset!\n");
+}
+
+test_mockable void chipset_force_shutdown(void)
+{
+ /* Do nothing */
+}
+
+#ifdef HAS_TASK_CHIPSET
+test_mockable int chipset_in_state(int state_mask)
+{
+ return state_mask & CHIPSET_STATE_SOFT_OFF;
+}
+
+test_mockable void chipset_task(void)
+{
+ while (1)
+ task_wait_event(-1);
+}
+#endif
diff --git a/board/host/ec.tasklist b/board/host/ec.tasklist
new file mode 100644
index 0000000000..d0597f8544
--- /dev/null
+++ b/board/host/ec.tasklist
@@ -0,0 +1,23 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
+ * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
+ * where :
+ * 'n' in the name of the task
+ * 'r' in the main routine of the task
+ * 'd' in an opaque parameter passed to the routine at startup
+ * 's' is the stack size in bytes; must be a multiple of 8
+ */
+
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE)
diff --git a/chip/host/build.mk b/chip/host/build.mk
new file mode 100644
index 0000000000..ddcbefdb0b
--- /dev/null
+++ b/chip/host/build.mk
@@ -0,0 +1,12 @@
+# -*- makefile -*-
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# emulator specific files build
+#
+
+CORE:=host
+
+chip-y=system.o gpio.o uart.o
+chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
diff --git a/chip/host/config.h b/chip/host/config.h
new file mode 100644
index 0000000000..7f2df4e467
--- /dev/null
+++ b/chip/host/config.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Chip config header file */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/* Memory mapping */
+#define CONFIG_FLASH_BASE 0x08000000
+#define CONFIG_FLASH_PHYSICAL_SIZE 0x00020000
+#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
+#define CONFIG_FLASH_BANK_SIZE 0x1000
+#define CONFIG_FLASH_ERASE_SIZE 0x0400 /* erase bank size */
+#define CONFIG_FLASH_WRITE_SIZE 0x0002 /* minimum write size */
+#define CONFIG_RAM_BASE 0x20000000
+#define CONFIG_RAM_SIZE 0x00002000
+
+/* Size of one firmware image in flash */
+#define CONFIG_FW_IMAGE_SIZE (64 * 1024)
+
+#define CONFIG_FW_RO_OFF 0
+#define CONFIG_FW_RO_SIZE (CONFIG_FW_IMAGE_SIZE \
+ - CONFIG_SECTION_FLASH_PSTATE_SIZE)
+#define CONFIG_FW_RW_OFF CONFIG_FW_IMAGE_SIZE
+#define CONFIG_FW_RW_SIZE CONFIG_FW_IMAGE_SIZE
+
+#define CONFIG_SECTION_RO_OFF CONFIG_FW_RO_OFF
+#define CONFIG_SECTION_RO_SIZE CONFIG_FW_RO_SIZE
+#define CONFIG_SECTION_RW_OFF CONFIG_FW_RW_OFF
+#define CONFIG_SECTION_RW_SIZE CONFIG_FW_RW_SIZE
+#define CONFIG_SECTION_WP_RO_OFF CONFIG_FW_RO_OFF
+#define CONFIG_SECTION_WP_RO_SIZE CONFIG_FW_IMAGE_SIZE
+
+/*
+ * Put this after RO to give RW more space. This also makes RO write protect
+ * region contiguous.
+ */
+#define CONFIG_SECTION_FLASH_PSTATE_SIZE (1 * CONFIG_FLASH_BANK_SIZE)
+#define CONFIG_SECTION_FLASH_PSTATE_OFF CONFIG_FW_RO_OFF + CONFIG_FW_RO_SIZE
+
+/* Maximum number of deferrable functions */
+#define DEFERRABLE_MAX_COUNT 8
+
+/* Interval between HOOK_TICK notifications */
+#define HOOK_TICK_INTERVAL (250 * MSEC)
+
+#endif /* __CONFIG_H */
+
diff --git a/chip/host/gpio.c b/chip/host/gpio.c
new file mode 100644
index 0000000000..03cfaa4aed
--- /dev/null
+++ b/chip/host/gpio.c
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* GPIO module for emulator */
+
+#include "common.h"
+#include "gpio.h"
+
+test_mockable void gpio_pre_init(void)
+{
+ /* Nothing */
+}
+
+test_mockable int gpio_get_level(enum gpio_signal signal)
+{
+ return 0;
+}
+
+test_mockable void gpio_set_level(enum gpio_signal signal, int value)
+{
+ /* Nothing */
+}
diff --git a/chip/host/keyboard_raw.c b/chip/host/keyboard_raw.c
new file mode 100644
index 0000000000..561a72aafa
--- /dev/null
+++ b/chip/host/keyboard_raw.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Raw keyboard I/O layer for emulator */
+
+#include "common.h"
+#include "keyboard_config.h"
+#include "keyboard_raw.h"
+#include "keyboard_scan.h"
+#include "task.h"
+#include "util.h"
+
+test_mockable void keyboard_raw_init(void)
+{
+ /* Nothing */
+}
+
+test_mockable void keyboard_raw_task_start(void)
+{
+ /* Nothing */
+}
+
+test_mockable void keyboard_raw_drive_column(int out)
+{
+ /* Nothing */
+}
+
+test_mockable int keyboard_raw_read_rows(void)
+{
+ /* Nothing pressed */
+ return 0;
+}
+
+test_mockable void keyboard_raw_enable_interrupt(int enable)
+{
+ /* Nothing */
+}
+
+test_mockable void keyboard_raw_gpio_interrupt(enum gpio_signal signal)
+{
+#ifdef HAS_TASK_KEYSCAN
+ task_wake(TASK_ID_KEYSCAN);
+#endif
+}
diff --git a/chip/host/system.c b/chip/host/system.c
new file mode 100644
index 0000000000..50da8db9c0
--- /dev/null
+++ b/chip/host/system.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* System module for emulator */
+
+#include <stdlib.h>
+
+#include "host_test.h"
+#include "system.h"
+
+#define SHARED_MEM_SIZE 512 /* bytes */
+char __shared_mem_buf[SHARED_MEM_SIZE];
+
+test_mockable void system_reset(int flags)
+{
+ exit(EXIT_CODE_RESET | flags);
+}
+
+test_mockable void system_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ exit(EXIT_CODE_HIBERNATE);
+}
+
+test_mockable int system_is_locked(void)
+{
+ return 0;
+}
+
+test_mockable int system_jumped_to_this_image(void)
+{
+ return 0;
+}
+
+test_mockable uint32_t system_get_reset_flags(void)
+{
+ return RESET_FLAG_POWER_ON;
+}
+
+const char *system_get_chip_vendor(void)
+{
+ return "chromeos";
+}
+
+const char *system_get_chip_name(void)
+{
+ return "emu";
+}
+
+const char *system_get_chip_revision(void)
+{
+ return "";
+}
+
+int system_get_vbnvcontext(uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_set_vbnvcontext(const uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_usable_ram_end(void)
+{
+ return (int)(__shared_mem_buf + SHARED_MEM_SIZE);
+}
+
+void system_pre_init(void)
+{
+ /* Nothing */
+}
diff --git a/chip/host/uart.c b/chip/host/uart.c
new file mode 100644
index 0000000000..cbae79974b
--- /dev/null
+++ b/chip/host/uart.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* UART driver for emulator */
+
+#include <stdio.h>
+
+#include "board.h"
+#include "config.h"
+#include "task.h"
+#include "uart.h"
+
+static int stopped;
+static int int_disabled;
+static int init_done;
+
+static void trigger_interrupt(void)
+{
+ if (!int_disabled)
+ uart_process();
+}
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_start(void)
+{
+ stopped = 0;
+ trigger_interrupt();
+}
+
+void uart_tx_stop(void)
+{
+ stopped = 1;
+}
+
+int uart_tx_stopped(void)
+{
+ return stopped;
+}
+
+void uart_tx_flush(void)
+{
+ /* Nothing */
+}
+
+int uart_tx_ready(void)
+{
+ return 1;
+}
+
+int uart_rx_available(void)
+{
+ return 0;
+}
+
+void uart_write_char(char c)
+{
+ printf("%c", c);
+ fflush(stdout);
+}
+
+int uart_read_char(void)
+{
+ /* Should never be called for now */
+ return 0;
+}
+
+void uart_disable_interrupt(void)
+{
+ int_disabled = 1;
+}
+
+void uart_enable_interrupt(void)
+{
+ int_disabled = 0;
+}
+
+void uart_init(void)
+{
+ init_done = 1;
+}
diff --git a/common/main.c b/common/main.c
index bd1b6f4543..9a5a75f1cd 100644
--- a/common/main.c
+++ b/common/main.c
@@ -27,7 +27,7 @@
#define CPUTS(outstr) cputs(CC_SYSTEM, outstr)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
-int main(void)
+test_mockable int main(void)
{
/*
* Pre-initialization (pre-verified boot) stage. Initialization at
diff --git a/common/system_common.c b/common/system_common.c
index dbb83303b1..239dd12a75 100644
--- a/common/system_common.c
+++ b/common/system_common.c
@@ -104,7 +104,7 @@ int system_is_locked(void)
#endif
}
-int system_usable_ram_end(void)
+test_mockable int system_usable_ram_end(void)
{
/* Leave space at the end of RAM for jump data and tags.
*
diff --git a/core/host/atomic.h b/core/host/atomic.h
new file mode 100644
index 0000000000..77e9cc6ba8
--- /dev/null
+++ b/core/host/atomic.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Atomic operations for emulator */
+
+#ifndef __CROS_EC_ATOMIC_H
+#define __CROS_EC_ATOMIC_H
+
+#include "common.h"
+
+static inline void atomic_clear(uint32_t *addr, uint32_t bits)
+{
+ __sync_and_and_fetch(addr, ~bits);
+}
+
+static inline void atomic_or(uint32_t *addr, uint32_t bits)
+{
+ __sync_or_and_fetch(addr, bits);
+}
+
+static inline void atomic_add(uint32_t *addr, uint32_t value)
+{
+ __sync_add_and_fetch(addr, value);
+}
+
+static inline void atomic_sub(uint32_t *addr, uint32_t value)
+{
+ __sync_sub_and_fetch(addr, value);
+}
+
+static inline uint32_t atomic_read_clear(uint32_t *addr)
+{
+ return __sync_fetch_and_and(addr, 0);
+}
+#endif /* __CROS_EC_ATOMIC_H */
diff --git a/core/host/build.mk b/core/host/build.mk
new file mode 100644
index 0000000000..879b9266fa
--- /dev/null
+++ b/core/host/build.mk
@@ -0,0 +1,11 @@
+# -*- makefile -*-
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# emulator specific files build
+#
+
+CFLAGS_CPU=-fno-builtin -m32
+
+core-y=main.o task.o timer.o panic.o disabled.o
diff --git a/core/host/cpu.h b/core/host/cpu.h
new file mode 100644
index 0000000000..4e43da623f
--- /dev/null
+++ b/core/host/cpu.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* CPU specific header file */
+
+#ifndef __CPU_H
+#define __CPU_H
+
+static inline void cpu_init(void) { }
+
+#endif /* __CPU_H */
diff --git a/core/host/disabled.c b/core/host/disabled.c
new file mode 100644
index 0000000000..679a1ab451
--- /dev/null
+++ b/core/host/disabled.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Disabled functions */
+
+#define DISABLED(proto) proto { }
+
+DISABLED(void jtag_pre_init(void));
+DISABLED(void clock_init(void));
diff --git a/core/host/host_exe.lds b/core/host/host_exe.lds
new file mode 100644
index 0000000000..46a5097d67
--- /dev/null
+++ b/core/host/host_exe.lds
@@ -0,0 +1,80 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+SECTIONS {
+ .rodata.ec_sections : {
+ /* Symbols defined here are declared in link_defs.h */
+ __irqprio = .;
+ *(.rodata.irqprio)
+ __irqprio_end = .;
+
+ . = ALIGN(4);
+ __cmds = .;
+ *(SORT(.rodata.cmds*))
+ __cmds_end = .;
+
+ . = ALIGN(4);
+ __hcmds = .;
+ *(.rodata.hcmds)
+ __hcmds_end = .;
+
+ . = ALIGN(4);
+ __hooks_init = .;
+ *(.rodata.HOOK_INIT)
+ __hooks_init_end = .;
+
+ __hooks_freq_change = .;
+ *(.rodata.HOOK_FREQ_CHANGE)
+ __hooks_freq_change_end = .;
+
+ __hooks_sysjump = .;
+ *(.rodata.HOOK_SYSJUMP)
+ __hooks_sysjump_end = .;
+
+ __hooks_chipset_pre_init = .;
+ *(.rodata.HOOK_CHIPSET_PRE_INIT)
+ __hooks_chipset_pre_init_end = .;
+
+ __hooks_chipset_startup = .;
+ *(.rodata.HOOK_CHIPSET_STARTUP)
+ __hooks_chipset_startup_end = .;
+
+ __hooks_chipset_resume = .;
+ *(.rodata.HOOK_CHIPSET_RESUME)
+ __hooks_chipset_resume_end = .;
+
+ __hooks_chipset_suspend = .;
+ *(.rodata.HOOK_CHIPSET_SUSPEND)
+ __hooks_chipset_suspend_end = .;
+
+ __hooks_chipset_shutdown = .;
+ *(.rodata.HOOK_CHIPSET_SHUTDOWN)
+ __hooks_chipset_shutdown_end = .;
+
+ __hooks_ac_change = .;
+ *(.rodata.HOOK_AC_CHANGE)
+ __hooks_ac_change_end = .;
+
+ __hooks_lid_change = .;
+ *(.rodata.HOOK_LID_CHANGE)
+ __hooks_lid_change_end = .;
+
+ __hooks_pwrbtn_change = .;
+ *(.rodata.HOOK_POWER_BUTTON_CHANGE)
+ __hooks_pwrbtn_change_end = .;
+
+ __hooks_tick = .;
+ *(.rodata.HOOK_TICK)
+ __hooks_tick_end = .;
+
+ __hooks_second = .;
+ *(.rodata.HOOK_SECOND)
+ __hooks_second_end = .;
+
+ __deferred_funcs = .;
+ *(.rodata.deferred)
+ __deferred_funcs_end = .;
+ }
+}
+INSERT BEFORE .rodata;
diff --git a/core/host/main.c b/core/host/main.c
new file mode 100644
index 0000000000..f370e4b561
--- /dev/null
+++ b/core/host/main.c
@@ -0,0 +1,18 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Entry point of unit test executable */
+
+#include "task.h"
+#include "timer.h"
+
+int main(void)
+{
+ timer_init();
+
+ task_start();
+
+ return 0;
+}
diff --git a/core/host/panic.c b/core/host/panic.c
new file mode 100644
index 0000000000..90ddf55dd7
--- /dev/null
+++ b/core/host/panic.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "panic.h"
+#include "util.h"
+
+struct panic_data *panic_get_data(void)
+{
+ return NULL;
+}
diff --git a/core/host/task.c b/core/host/task.c
new file mode 100644
index 0000000000..caad622778
--- /dev/null
+++ b/core/host/task.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Task scheduling / events module for Chrome EC operating system */
+
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "atomic.h"
+#include "common.h"
+#include "task.h"
+#include "task_id.h"
+#include "timer.h"
+
+struct emu_task_t {
+ pthread_t thread;
+ pthread_cond_t resume;
+ uint32_t event;
+ timestamp_t wake_time;
+};
+
+struct task_args {
+ void (*routine)(void *);
+ void *d;
+};
+
+static struct emu_task_t tasks[TASK_ID_COUNT];
+static pthread_cond_t scheduler_cond;
+static pthread_mutex_t run_lock;
+
+static __thread task_id_t my_task_id; /* thread local task id */
+
+#define TASK(n, r, d, s) void r(void *);
+CONFIG_TASK_LIST
+CONFIG_TEST_TASK_LIST
+#undef TASK
+
+/* Idle task */
+void __idle(void *d)
+{
+ while (1)
+ task_wait_event(-1);
+}
+
+/* Weak reference function as an entry point for unit test */
+test_mockable void run_test(void) { }
+
+void _run_test(void *d)
+{
+ run_test();
+}
+
+#define TASK(n, r, d, s) {r, d},
+struct task_args task_info[TASK_ID_COUNT] = {
+ {__idle, NULL},
+ CONFIG_TASK_LIST
+ CONFIG_TEST_TASK_LIST
+ {_run_test, NULL},
+};
+#undef TASK
+
+#define TASK(n, r, d, s) #n,
+static const char * const task_names[] = {
+ "<< idle >>",
+ CONFIG_TASK_LIST
+ CONFIG_TEST_TASK_LIST
+ "<< test runner >>",
+};
+#undef TASK
+
+void task_pre_init(void)
+{
+ /* Nothing */
+}
+
+int in_interrupt_context(void)
+{
+ return 0; /* No interrupt support yet */
+}
+
+void interrupt_disable(void)
+{
+ /* Not supported yet */
+}
+
+void interrupt_enable(void)
+{
+ /* Not supported yet */
+}
+
+uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait)
+{
+ tasks[tskid].event = event;
+ if (wait)
+ return task_wait_event(-1);
+ return 0;
+}
+
+uint32_t task_wait_event(int timeout_us)
+{
+ int tid = task_get_current();
+ int ret;
+ if (timeout_us > 0)
+ tasks[tid].wake_time.val = get_time().val + timeout_us;
+ pthread_cond_signal(&scheduler_cond);
+ pthread_cond_wait(&tasks[tid].resume, &run_lock);
+ ret = tasks[tid].event;
+ tasks[tid].event = 0;
+ return ret;
+}
+
+void mutex_lock(struct mutex *mtx)
+{
+ int value = 0;
+ int id = 1 << task_get_current();
+
+ mtx->waiters |= id;
+
+ do {
+ if (mtx->lock == 0) {
+ mtx->lock = 1;
+ value = 1;
+ }
+
+ if (!value)
+ task_wait_event(-1);
+ } while (!value);
+
+ mtx->waiters &= ~id;
+}
+
+void mutex_unlock(struct mutex *mtx)
+{
+ int v;
+ mtx->lock = 0;
+
+ for (v = 31; v >= 0; --v)
+ if ((1ul << v) & mtx->waiters) {
+ mtx->waiters &= ~(1ul << v);
+ task_set_event(v, TASK_EVENT_MUTEX, 0);
+ break;
+ }
+}
+
+task_id_t task_get_current(void)
+{
+ return my_task_id;
+}
+
+void task_scheduler(void)
+{
+ int i;
+ timestamp_t now;
+
+ while (1) {
+ now = get_time();
+ i = TASK_ID_COUNT - 1;
+ while (i >= 0) {
+ if (tasks[i].event || now.val >= tasks[i].wake_time.val)
+ break;
+ --i;
+ }
+ if (i < 0)
+ i = TASK_ID_IDLE;
+
+ tasks[i].wake_time.val = ~0ull;
+ pthread_cond_signal(&tasks[i].resume);
+ pthread_cond_wait(&scheduler_cond, &run_lock);
+ }
+}
+
+void *_task_start_impl(void *a)
+{
+ long tid = (long)a;
+ struct task_args *arg = task_info + tid;
+ my_task_id = tid;
+ pthread_mutex_lock(&run_lock);
+ tasks[tid].event = 0;
+ (arg->routine)(arg->d);
+ while (1)
+ task_wait_event(-1);
+}
+
+int task_start(void)
+{
+ int i;
+
+ pthread_mutex_init(&run_lock, NULL);
+ pthread_cond_init(&scheduler_cond, NULL);
+
+ pthread_mutex_lock(&run_lock);
+
+ for (i = 0; i < TASK_ID_COUNT; ++i) {
+ tasks[i].event = TASK_EVENT_WAKE;
+ tasks[i].wake_time.val = ~0ull;
+ pthread_cond_init(&tasks[i].resume, NULL);
+ pthread_create(&tasks[i].thread, NULL, _task_start_impl,
+ (void *)(size_t)i);
+ pthread_cond_wait(&scheduler_cond, &run_lock);
+ }
+
+ task_scheduler();
+
+ return 0;
+}
diff --git a/core/host/timer.c b/core/host/timer.c
new file mode 100644
index 0000000000..8de12a7f3c
--- /dev/null
+++ b/core/host/timer.c
@@ -0,0 +1,61 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Timer module */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "task.h"
+#include "timer.h"
+
+static timestamp_t boot_time;
+
+void usleep(unsigned us)
+{
+ task_wait_event(us);
+}
+
+timestamp_t _get_time(void)
+{
+ struct timespec ts;
+ timestamp_t ret;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ ret.val = 1000000 * (uint64_t)ts.tv_sec + ts.tv_nsec / 1000;
+ return ret;
+}
+
+timestamp_t get_time(void)
+{
+ timestamp_t ret = _get_time();
+ ret.val -= boot_time.val;
+ return ret;
+}
+
+void udelay(unsigned us)
+{
+ timestamp_t deadline = get_time();
+ deadline.val += us;
+ while (get_time().val < deadline.val)
+ ;
+}
+
+int timestamp_expired(timestamp_t deadline, const timestamp_t *now)
+{
+ timestamp_t now_val;
+
+ if (!now) {
+ now_val = get_time();
+ now = &now_val;
+ }
+
+ return ((int64_t)(now->val - deadline.val) >= 0);
+}
+
+void timer_init(void)
+{
+ boot_time = _get_time();
+}
diff --git a/include/host_test.h b/include/host_test.h
new file mode 100644
index 0000000000..0c1b95d1fa
--- /dev/null
+++ b/include/host_test.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Unit testing for Chrome EC */
+
+#ifndef __CROS_EC_HOST_TEST_H
+#define __CROS_EC_HOST_TEST_H
+
+/* Emulator exit codes */
+#define EXIT_CODE_RESET (1 << 6) /* Leave six bits for SYSTEM_RESET_* */
+#define EXIT_CODE_HIBERNATE (1 << 7)
+
+#endif /* __CROS_EC_HOST_TEST_H */
diff --git a/core/cortex-m/link_defs.h b/include/link_defs.h
index 6681d6b371..a8c54d4afe 100644
--- a/core/cortex-m/link_defs.h
+++ b/include/link_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
diff --git a/include/task_id.h b/include/task_id.h
index 33445aee9c..985c39848c 100644
--- a/include/task_id.h
+++ b/include/task_id.h
@@ -47,6 +47,9 @@ enum {
CONFIG_TASK_LIST
/* CONFIG_TEST_TASK_LIST is a macro from the TEST_TASK_LIST file */
CONFIG_TEST_TASK_LIST
+#ifdef EMU_BUILD
+ TASK_ID_TEST_RUNNER,
+#endif
/* Number of tasks */
TASK_ID_COUNT,
/* Special task identifiers */
diff --git a/test/build.mk b/test/build.mk
index 7adf96f441..2c61e80e7d 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -24,6 +24,9 @@ test-list-$(BOARD_spring)+=kb_scan flash stress
test-list-$(BOARD_link)=
test-list-$(BOARD_slippy)=
+# Emulator tests
+test-list-host=mutex pingpong utils kb_scan
+
flash-y=flash.o
kb_mkbp-y=kb_mkbp.o
kb_scan-y=kb_scan.o
diff --git a/test/kb_scan.c b/test/kb_scan.c
index 32822d689d..c242c43e09 100644
--- a/test/kb_scan.c
+++ b/test/kb_scan.c
@@ -257,7 +257,7 @@ int lid_test(void)
}
#endif
-static int command_run_test(int argc, char **argv)
+void run_test(void)
{
error_count = 0;
lid_open = 1;
@@ -268,13 +268,16 @@ static int command_run_test(int argc, char **argv)
RUN_TEST(lid_test);
#endif
- if (error_count == 0) {
+ if (error_count == 0)
ccprintf("Pass!\n");
- return EC_SUCCESS;
- } else {
+ else
ccprintf("Fail!\n");
- return EC_ERROR_UNKNOWN;
- }
+}
+
+static int command_run_test(int argc, char **argv)
+{
+ run_test();
+ return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(runtest, command_run_test,
NULL, NULL, NULL);
diff --git a/test/mutex.c b/test/mutex.c
index 47f7fa97c4..bc20062d89 100644
--- a/test/mutex.c
+++ b/test/mutex.c
@@ -114,9 +114,14 @@ int mutex_main_task(void *unused)
return EC_SUCCESS;
}
-static int command_run_test(int argc, char **argv)
+void run_test(void)
{
task_wake(TASK_ID_MTX1);
+}
+
+static int command_run_test(int argc, char **argv)
+{
+ run_test();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(runtest, command_run_test,
diff --git a/test/pingpong.c b/test/pingpong.c
index f9266da26e..4cf5d53ced 100644
--- a/test/pingpong.c
+++ b/test/pingpong.c
@@ -58,10 +58,15 @@ int TaskTick(void *data)
return EC_SUCCESS;
}
-static int command_run_test(int argc, char **argv)
+void run_test(void)
{
task_wake(TASK_ID_TICK);
task_wake(TASK_ID_TESTA);
+}
+
+static int command_run_test(int argc, char **argv)
+{
+ run_test();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(runtest, command_run_test,
diff --git a/test/timer_dos.c b/test/timer_dos.c
index 5ac7cad5df..327206e6df 100644
--- a/test/timer_dos.c
+++ b/test/timer_dos.c
@@ -46,12 +46,17 @@ int TaskTimer(void *seed)
return EC_SUCCESS;
}
-static int command_run_test(int argc, char **argv)
+void run_test(void)
{
task_wake(TASK_ID_TMRD);
task_wake(TASK_ID_TMRC);
task_wake(TASK_ID_TMRB);
task_wake(TASK_ID_TMRA);
+}
+
+static int command_run_test(int argc, char **argv)
+{
+ run_test();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(runtest, command_run_test,
diff --git a/test/utils.c b/test/utils.c
index 1c04c0d06d..559e8a0d94 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -89,7 +89,7 @@ static int test_shared_mem(void)
for (i = 0; i < 256; ++i) {
memset(mem, i, sz);
for (j = 0; j < sz; ++j)
- TEST_ASSERT(mem[j] == i);
+ TEST_ASSERT(mem[j] == (char)i);
if ((i & 0xf) == 0)
msleep(20); /* Yield to other tasks */
@@ -100,7 +100,7 @@ static int test_shared_mem(void)
return EC_SUCCESS;
}
-static int command_run_test(int argc, char **argv)
+void run_test(void)
{
error_count = 0;
@@ -111,13 +111,16 @@ static int command_run_test(int argc, char **argv)
RUN_TEST(test_uint64divmod);
RUN_TEST(test_shared_mem);
- if (error_count) {
+ if (error_count)
ccprintf("Failed %d tests!\n", error_count);
- return EC_ERROR_UNKNOWN;
- } else {
+ else
ccprintf("Pass!\n");
- return EC_SUCCESS;
- }
+}
+
+static int command_run_test(int argc, char **argv)
+{
+ run_test();
+ return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(runtest, command_run_test,
NULL, NULL, NULL);
diff --git a/util/run_host_test b/util/run_host_test
new file mode 100755
index 0000000000..bf8d8efd97
--- /dev/null
+++ b/util/run_host_test
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import pexpect
+import sys
+
+TIMEOUT=10
+
+test_name = sys.argv[1]
+child = pexpect.spawn('build/host/{0}/{0}.exe'.format(test_name),
+ timeout=TIMEOUT)
+child.logfile = sys.stdout
+result_id = child.expect([pexpect.TIMEOUT, 'Pass!', 'Fail!'])
+if result_id == 0:
+ sys.stderr.write('Test %s timed out after %d seconds!\n' %
+ (test_name, TIMEOUT))
+ sys.exit(1)
+elif result_id == 1:
+ sys.stderr.write('Test %s passed!\n' % test_name)
+ sys.exit(0)
+elif result_id == 2:
+ sys.stderr.write('Test %s failed!\n' % test_name)
+ sys.exit(1)