Pthread-based emulator for unit testing

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>
This commit is contained in:
Vic Yang
2013-05-02 00:37:07 +08:00
committed by ChromeBot
parent b02c7b4617
commit 0a45fa1708
34 changed files with 964 additions and 22 deletions

View File

@@ -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 )

View File

@@ -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

12
board/host/board.c Normal file
View File

@@ -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},
};

21
board/host/board.h Normal file
View File

@@ -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 */

11
board/host/build.mk Normal file
View File

@@ -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

34
board/host/chipset.c Normal file
View File

@@ -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

23
board/host/ec.tasklist Normal file
View File

@@ -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)

12
chip/host/build.mk Normal file
View File

@@ -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

51
chip/host/config.h Normal file
View File

@@ -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 */

24
chip/host/gpio.c Normal file
View File

@@ -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 */
}

46
chip/host/keyboard_raw.c Normal file
View File

@@ -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
}

74
chip/host/system.c Normal file
View File

@@ -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 */
}

86
chip/host/uart.c Normal file
View File

@@ -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;
}

View File

@@ -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

View File

@@ -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.
*

37
core/host/atomic.h Normal file
View File

@@ -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 */

11
core/host/build.mk Normal file
View File

@@ -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

13
core/host/cpu.h Normal file
View File

@@ -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 */

11
core/host/disabled.c Normal file
View File

@@ -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));

80
core/host/host_exe.lds Normal file
View File

@@ -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;

18
core/host/main.c Normal file
View File

@@ -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;
}

13
core/host/panic.c Normal file
View File

@@ -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;
}

208
core/host/task.c Normal file
View File

@@ -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;
}

61
core/host/timer.c Normal file
View File

@@ -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();
}

15
include/host_test.h Normal file
View File

@@ -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 */

View File

@@ -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.
*

View File

@@ -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 */

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);

26
util/run_host_test Executable file
View File

@@ -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)