diff options
Diffstat (limited to 'core/host')
-rw-r--r-- | core/host/atomic.h | 40 | ||||
-rw-r--r-- | core/host/build.mk | 11 | ||||
-rw-r--r-- | core/host/cpu.h | 13 | ||||
-rw-r--r-- | core/host/disabled.c | 10 | ||||
-rw-r--r-- | core/host/host_exe.lds | 136 | ||||
-rw-r--r-- | core/host/host_task.h | 37 | ||||
-rw-r--r-- | core/host/irq_handler.h | 30 | ||||
-rw-r--r-- | core/host/main.c | 108 | ||||
-rw-r--r-- | core/host/panic.c | 22 | ||||
-rw-r--r-- | core/host/stack_trace.c | 97 | ||||
-rw-r--r-- | core/host/task.c | 564 | ||||
-rw-r--r-- | core/host/timer.c | 105 |
12 files changed, 0 insertions, 1173 deletions
diff --git a/core/host/atomic.h b/core/host/atomic.h deleted file mode 100644 index 83786de904..0000000000 --- a/core/host/atomic.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 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" - -typedef int atomic_t; -typedef atomic_t atomic_val_t; - -static inline atomic_val_t atomic_clear_bits(atomic_t *addr, atomic_val_t bits) -{ - return __atomic_fetch_and(addr, ~bits, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_or(atomic_t *addr, atomic_val_t bits) -{ - return __atomic_fetch_or(addr, bits, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_add(atomic_t *addr, atomic_val_t value) -{ - return __atomic_fetch_add(addr, value, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_sub(atomic_t *addr, atomic_val_t value) -{ - return __atomic_fetch_sub(addr, value, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_clear(atomic_t *addr) -{ - return __atomic_exchange_n(addr, 0, __ATOMIC_SEQ_CST); -} -#endif /* __CROS_EC_ATOMIC_H */ diff --git a/core/host/build.mk b/core/host/build.mk deleted file mode 100644 index 503aa5538a..0000000000 --- a/core/host/build.mk +++ /dev/null @@ -1,11 +0,0 @@ -# -*- makefile -*- -# Copyright 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 - -core-y=main.o task.o timer.o panic.o disabled.o stack_trace.o diff --git a/core/host/cpu.h b/core/host/cpu.h deleted file mode 100644 index d990e06afa..0000000000 --- a/core/host/cpu.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright 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 __CROS_EC_CPU_H -#define __CROS_EC_CPU_H - -static inline void cpu_init(void) { } - -#endif /* __CROS_EC_CPU_H */ diff --git a/core/host/disabled.c b/core/host/disabled.c deleted file mode 100644 index 759c215ebd..0000000000 --- a/core/host/disabled.c +++ /dev/null @@ -1,10 +0,0 @@ -/* Copyright 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 clock_init(void)); diff --git a/core/host/host_exe.lds b/core/host/host_exe.lds deleted file mode 100644 index ab8d352ecc..0000000000 --- a/core/host/host_exe.lds +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright 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(8); - __cmds = .; - *(SORT(.rodata.cmds*)) - __cmds_end = .; - - . = ALIGN(8); - __hcmds = .; - *(SORT(.rodata.hcmds*)) - __hcmds_end = .; - - . = ALIGN(4); - __mkbp_evt_srcs = .; - KEEP(*(.rodata.evtsrcs)) - __mkbp_evt_srcs_end = .; - - . = ALIGN(8); - __hooks_init = .; - *(.rodata.HOOK_INIT) - __hooks_init_end = .; - - __hooks_pre_freq_change = .; - *(.rodata.HOOK_PRE_FREQ_CHANGE) - __hooks_pre_freq_change_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_chipset_shutdown_complete = .; - *(.rodata.HOOK_CHIPSET_SHUTDOWN_COMPLETE) - __hooks_chipset_shutdown_complete_end = .; - - __hooks_chipset_hard_off = .; - KEEP(*(.rodata.HOOK_CHIPSET_HARD_OFF)) - __hooks_chipset_hard_off_end = .; - - __hooks_chipset_reset = .; - *(.rodata.HOOK_CHIPSET_RESET) - __hooks_chipset_reset_end = .; - - __hooks_ac_change = .; - *(.rodata.HOOK_AC_CHANGE) - __hooks_ac_change_end = .; - - __hooks_lid_change = .; - *(.rodata.HOOK_LID_CHANGE) - __hooks_lid_change_end = .; - - __hooks_tablet_mode_change = .; - KEEP(*(.rodata.HOOK_TABLET_MODE_CHANGE)) - __hooks_tablet_mode_change_end = .; - - __hooks_base_attached_change = .; - KEEP(*(.rodata.HOOK_BASE_ATTACHED_CHANGE)) - __hooks_base_attached_change_end = .; - - __hooks_pwrbtn_change = .; - *(.rodata.HOOK_POWER_BUTTON_CHANGE) - __hooks_pwrbtn_change_end = .; - - __hooks_battery_soc_change = .; - *(.rodata.HOOK_BATTERY_SOC_CHANGE) - __hooks_battery_soc_change_end = .; - - __hooks_tick = .; - *(.rodata.HOOK_TICK) - __hooks_tick_end = .; - - __hooks_second = .; - *(.rodata.HOOK_SECOND) - __hooks_second_end = .; - - __hooks_usb_pd_disconnect = .; - *(.rodata.HOOK_USB_PD_DISCONNECT) - __hooks_usb_pd_disconnect_end = .; - - __hooks_usb_pd_connect = .; - KEEP(*(.rodata.HOOK_USB_PD_CONNECT)) - __hooks_usb_pd_connect_end = .; - - __deferred_funcs = .; - *(.rodata.deferred) - __deferred_funcs_end = .; - - __test_i2c_xfer = .; - *(.rodata.test_i2c.xfer) - __test_i2c_xfer_end = .; - } -} -INSERT BEFORE .rodata; - -SECTIONS { - .bss.ec_sections : { - /* Symbols defined here are declared in link_defs.h */ - . = ALIGN(8); - __deferred_until = .; - . += (__deferred_funcs_end - __deferred_funcs) * (8 / 4); - __deferred_until_end = .; - } -} -INSERT BEFORE .bss; diff --git a/core/host/host_task.h b/core/host/host_task.h deleted file mode 100644 index 30cd2ff594..0000000000 --- a/core/host/host_task.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2014 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 task scheduling module */ - -#ifndef __CROS_EC_HOST_TASK_H -#define __CROS_EC_HOST_TASK_H - -#include <pthread.h> - -#include "task.h" - -/** - * Returns the thread corresponding to the task. - */ -pthread_t task_get_thread(task_id_t tskid); - -/** - * Returns the ID of the active task, regardless of current thread - * context. - */ -task_id_t task_get_running(void); - -/** - * Initializes the interrupt semaphore and associates a signal handler with - * SIGNAL_INTERRUPT. - */ -void task_register_interrupt(void); - -/** - * Returns the process ID of the calling process. - */ -pid_t getpid(void); - -#endif /* __CROS_EC_HOST_TASK_H */ diff --git a/core/host/irq_handler.h b/core/host/irq_handler.h deleted file mode 100644 index f905f463c1..0000000000 --- a/core/host/irq_handler.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2014 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. - */ - -/* Helper to declare IRQ handling routines */ - -#ifndef __CROS_EC_IRQ_HANDLER_H -#define __CROS_EC_IRQ_HANDLER_H - -/* Helper macros to build the IRQ handler and priority struct names */ -#define IRQ_HANDLER(irqname) CONCAT3(irq_, irqname, _handler) -#define IRQ_PRIORITY(irqname) CONCAT2(prio_, irqname) -/* - * Macro to connect the interrupt handler "routine" to the irq number "irq" and - * ensure it is enabled in the interrupt controller with the right priority. - */ -#define DECLARE_IRQ(irq, routine, priority) \ - void routine(void); \ - void IRQ_HANDLER(irq)(void) \ - { \ - void *ret = __builtin_return_address(0); \ - task_start_irq_handler(ret); \ - routine(); \ - task_resched_if_needed(ret); \ - } \ - const struct irq_priority __keep IRQ_PRIORITY(irq) \ - __attribute__((section(".rodata.irqprio"))) \ - = {irq, priority} -#endif /* __CROS_EC_IRQ_HANDLER_H */ diff --git a/core/host/main.c b/core/host/main.c deleted file mode 100644 index ed7032eb63..0000000000 --- a/core/host/main.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 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 "console.h" -#include "flash.h" -#include "hooks.h" -#include "host_task.h" -#include "keyboard_scan.h" -#include "stack_trace.h" -#include "system.h" -#include "task.h" -#include "test_util.h" -#include "timer.h" -#include "uart.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_SYSTEM, outstr) -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) - -const char *__prog_name; - -const char *__get_prog_name(void) -{ - return __prog_name; -} - -static int test_main(void) -{ - /* - * In order to properly service IRQs before task switching is enabled, - * we must set up our signal handler for the main thread. - */ - task_register_interrupt(); - - task_register_tracedump(); - - register_test_end_hook(); - - crec_flash_pre_init(); - system_pre_init(); - system_common_pre_init(); - - test_init(); - - timer_init(); -#ifdef HAS_TASK_KEYSCAN - keyboard_scan_init(); -#endif - uart_init(); - - if (system_jumped_to_this_image()) { - CPRINTS("Emulator initialized after sysjump"); - } else { - CPUTS("\n\n--- Emulator initialized after reboot ---\n"); - CPUTS("[Reset cause: "); - system_print_reset_flags(); - CPUTS("]\n"); - } - - task_start(); - - return 0; -} - -#ifdef TEST_FUZZ -/* - * Fuzzing tests need to start the main function in a thread, so that - * LLVMFuzzerTestOneInput can run freely. - */ -void *_main_thread(void *a) -{ - test_main(); - return NULL; -} - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - static int initialized; - static pthread_t main_t; - /* - * We lose the program name as LLVM fuzzer takes over main function: - * make up one. - */ - static const char *name = STRINGIFY(PROJECT)".exe"; - - if (!initialized) { - __prog_name = name; - pthread_create(&main_t, NULL, _main_thread, NULL); - initialized = 1; - /* We can't sleep yet, busy loop waiting for tasks to start. */ - wait_for_task_started_nosleep(); - /* Let tasks settle. */ - msleep(50 * MSEC); - } - - return test_fuzz_one_input(data, size); -} -#else -int main(int argc, char **argv) -{ - __prog_name = argv[0]; - return test_main(); -} -#endif diff --git a/core/host/panic.c b/core/host/panic.c deleted file mode 100644 index 7b0829989d..0000000000 --- a/core/host/panic.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 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 <stdio.h> -#include <stdlib.h> - -#include "stack_trace.h" - -void panic_assert_fail(const char *msg, const char *func, const char *fname, - int linenum) -{ - fprintf(stderr, "ASSERTION FAIL: %s:%d:%s - %s\n", - fname, linenum, func, msg); - task_dump_trace(); - - puts("Fail!"); /* Inform test runner */ - fflush(stdout); - - exit(1); -} diff --git a/core/host/stack_trace.c b/core/host/stack_trace.c deleted file mode 100644 index adef66dd44..0000000000 --- a/core/host/stack_trace.c +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright 2014 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 <execinfo.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> - -#include "host_task.h" -#include "host_test.h" -#include "timer.h" - -#define SIGNAL_TRACE_DUMP SIGTERM -#define MAX_TRACE 30 -/* - * When trace dump is requested from signal handler, skip: - * _task_dump_trace_impl - * _task_dump_trace_dispath - * A function in libc - */ -#define SIGNAL_TRACE_OFFSET 3 -/* - * When trace dump is requested from task_dump_trace(), skip: - * task_dump_trace - * _task_dump_trace_impl - */ -#define DIRECT_TRACE_OFFSET 2 - -static pthread_t main_thread; - -static void __attribute__((noinline)) _task_dump_trace_impl(int offset) -{ - void *trace[MAX_TRACE]; - size_t sz; - char **messages; - char buf[256]; - FILE *file; - int i, nb; - - sz = backtrace(trace, MAX_TRACE); - messages = backtrace_symbols(trace + offset, sz - offset); - - for (i = 0; i < sz - offset; ++i) { - fprintf(stderr, "#%-2d %s\n", i, messages[i]); - /* %p is correct (as opposed to %pP) since this is the host */ - sprintf(buf, "addr2line %p -e %s", - trace[i + offset], __get_prog_name()); - file = popen(buf, "r"); - if (file) { - nb = fread(buf, 1, sizeof(buf) - 1, file); - buf[nb] = '\0'; - fprintf(stderr, " %s", buf); - pclose(file); - } - } - fflush(stderr); - free(messages); -} - -void __attribute__((noinline)) task_dump_trace(void) -{ - _task_dump_trace_impl(DIRECT_TRACE_OFFSET); -} - -static void __attribute__((noinline)) _task_dump_trace_dispatch(int sig) -{ - int need_dispatch = 1; - task_id_t running = task_get_running(); - - if (!pthread_equal(pthread_self(), main_thread)) { - need_dispatch = 0; - } else if (!task_start_called()) { - fprintf(stderr, "Stack trace of main thread:\n"); - need_dispatch = 0; - } else if (in_interrupt_context()) { - fprintf(stderr, "Stack trace of ISR:\n"); - } else { - fprintf(stderr, "Stack trace of task %d (%s):\n", - running, task_get_name(running)); - } - - if (need_dispatch) { - pthread_kill(task_get_thread(running), SIGNAL_TRACE_DUMP); - } else { - _task_dump_trace_impl(SIGNAL_TRACE_OFFSET); - exit(1); - } -} - -void task_register_tracedump(void) -{ - /* Trace dumper MUST be registered from main thread */ - main_thread = pthread_self(); - signal(SIGNAL_TRACE_DUMP, _task_dump_trace_dispatch); -} diff --git a/core/host/task.c b/core/host/task.c deleted file mode 100644 index be7ed3c579..0000000000 --- a/core/host/task.c +++ /dev/null @@ -1,564 +0,0 @@ -/* Copyright 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 <malloc.h> -#include <pthread.h> -#include <semaphore.h> -#include <signal.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "atomic.h" -#include "common.h" -#include "console.h" -#include "host_task.h" -#include "task.h" -#include "task_id.h" -#include "test_util.h" -#include "timer.h" - -#define SIGNAL_INTERRUPT SIGUSR1 - -struct emu_task_t { - pthread_t thread; - pthread_cond_t resume; - uint32_t event; - timestamp_t wake_time; - uint8_t started; -}; - -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 task_id_t running_task_id; -static int task_started; - -static sem_t interrupt_sem; -static pthread_mutex_t interrupt_lock; -static pthread_t interrupt_thread; -static int in_interrupt; -static int interrupt_disabled; -static void (*pending_isr)(void); -static int generator_sleeping; -static timestamp_t generator_sleep_deadline; -static int has_interrupt_generator = 1; - -/* thread local task id */ -static __thread task_id_t my_task_id = TASK_ID_INVALID; - -static void task_enable_all_tasks_callback(void); - -#define TASK(n, r, d, s) void r(void *); -CONFIG_TASK_LIST -CONFIG_TEST_TASK_LIST -CONFIG_CTS_TASK_LIST -#undef TASK - -/* usleep that uses OS functions, instead of emulated timer. */ -void _usleep(int usec) -{ - struct timespec req; - - req.tv_sec = usec / 1000000; - req.tv_nsec = (usec % 1000000) * 1000; - - nanosleep(&req, NULL); -} - -/* msleep that uses OS functions, instead of emulated timer. */ -void _msleep(int msec) -{ - _usleep(1000 * msec); -} - -/* Idle task */ -void __idle(void *d) -{ - while (1) - task_wait_event(-1); -} - -void _run_test(void *d) -{ - run_test(0, NULL); -} - -#define TASK(n, r, d, s) {r, d}, -const struct task_args task_info[TASK_ID_COUNT] = { - {__idle, NULL}, - CONFIG_TASK_LIST - CONFIG_TEST_TASK_LIST - CONFIG_CTS_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 - CONFIG_CTS_TASK_LIST - "<< test runner >>", -}; -#undef TASK - -void task_pre_init(void) -{ - /* Nothing */ -} - -int in_interrupt_context(void) -{ - return !!in_interrupt; -} - -test_mockable void interrupt_disable(void) -{ - pthread_mutex_lock(&interrupt_lock); - interrupt_disabled = 1; - pthread_mutex_unlock(&interrupt_lock); -} - -test_mockable void interrupt_enable(void) -{ - pthread_mutex_lock(&interrupt_lock); - interrupt_disabled = 0; - pthread_mutex_unlock(&interrupt_lock); -} - -inline int is_interrupt_enabled(void) -{ - return !interrupt_disabled; -} - -static void _task_execute_isr(int sig) -{ - in_interrupt = 1; - pending_isr(); - sem_post(&interrupt_sem); - in_interrupt = 0; -} - -void task_register_interrupt(void) -{ - sem_init(&interrupt_sem, 0, 0); - signal(SIGNAL_INTERRUPT, _task_execute_isr); -} - -void task_trigger_test_interrupt(void (*isr)(void)) -{ - pid_t main_pid; - pthread_mutex_lock(&interrupt_lock); - if (interrupt_disabled) { - pthread_mutex_unlock(&interrupt_lock); - return; - } - - /* Suspend current task and excute ISR */ - pending_isr = isr; - if (task_started) { - pthread_kill(tasks[running_task_id].thread, SIGNAL_INTERRUPT); - } else { - main_pid = getpid(); - kill(main_pid, SIGNAL_INTERRUPT); - } - - /* Wait for ISR to complete */ - sem_wait(&interrupt_sem); - while (in_interrupt) - _usleep(10); - pending_isr = NULL; - - pthread_mutex_unlock(&interrupt_lock); -} - -void interrupt_generator_udelay(unsigned us) -{ - generator_sleep_deadline.val = get_time().val + us; - generator_sleeping = 1; - while (get_time().val < generator_sleep_deadline.val) - ; - generator_sleeping = 0; -} - -const char *task_get_name(task_id_t tskid) -{ - return task_names[tskid]; -} - -pthread_t task_get_thread(task_id_t tskid) -{ - return tasks[tskid].thread; -} - -uint32_t task_set_event(task_id_t tskid, uint32_t event) -{ - atomic_or(&tasks[tskid].event, event); - return 0; -} - -uint32_t *task_get_event_bitmap(task_id_t tskid) -{ - return &tasks[tskid].event; -} - -uint32_t task_wait_event(int timeout_us) -{ - int tid = task_get_current(); - int ret; - pthread_mutex_lock(&interrupt_lock); - if (timeout_us > 0) - tasks[tid].wake_time.val = get_time().val + timeout_us; - - /* Transfer control to scheduler */ - pthread_cond_signal(&scheduler_cond); - pthread_cond_wait(&tasks[tid].resume, &run_lock); - - /* Resume */ - ret = atomic_clear(&tasks[tid].event); - pthread_mutex_unlock(&interrupt_lock); - return ret; -} - -uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us) -{ - uint64_t deadline = get_time().val + timeout_us; - uint32_t events = 0; - int time_remaining_us = timeout_us; - - /* Add the timer event to the mask so we can indicate a timeout */ - event_mask |= TASK_EVENT_TIMER; - - while (!(events & event_mask)) { - /* Collect events to re-post later */ - events |= task_wait_event(time_remaining_us); - - time_remaining_us = deadline - get_time().val; - if (timeout_us > 0 && time_remaining_us <= 0) { - /* Ensure we return a TIMER event if we timeout */ - events |= TASK_EVENT_TIMER; - break; - } - } - - /* Re-post any other events collected */ - if (events & ~event_mask) - atomic_or(&tasks[task_get_current()].event, - events & ~event_mask); - - return events & event_mask; -} - -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_mask(TASK_EVENT_MUTEX, 0); - } 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); - break; - } -} - -task_id_t task_get_current(void) -{ - return my_task_id; -} - -task_id_t task_get_running(void) -{ - return running_task_id; -} - -void task_print_list(void) -{ - int i; - - ccputs("Name Events\n"); - - for (i = 0; i < TASK_ID_COUNT; i++) { - ccprintf("%4d %-16s %08x\n", i, task_names[i], tasks[i].event); - cflush(); - } -} - -int command_task_info(int argc, char **argv) -{ - task_print_list(); - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(taskinfo, command_task_info, - NULL, - "Print task info"); - -static void _wait_for_task_started(int can_sleep) -{ - int i, ok; - - while (1) { - ok = 1; - for (i = 0; i < TASK_ID_COUNT - 1; ++i) { - if (!tasks[i].started) { - if (can_sleep) - msleep(10); - else - _msleep(10); - ok = 0; - break; - } - } - if (ok) - return; - } -} - -void wait_for_task_started(void) -{ - _wait_for_task_started(1); -} - -void wait_for_task_started_nosleep(void) -{ - _wait_for_task_started(0); -} - -static task_id_t task_get_next_wake(void) -{ - int i; - timestamp_t min_time; - int which_task = TASK_ID_INVALID; - - min_time.val = ~0ull; - - for (i = TASK_ID_COUNT - 1; i >= 0; --i) - if (min_time.val >= tasks[i].wake_time.val) { - min_time.val = tasks[i].wake_time.val; - which_task = i; - } - - return which_task; -} - -static int fast_forward(void) -{ - /* - * No task has event pending, and thus the next time we have an - * event to process must be either of: - * 1. Interrupt generator triggers an interrupt - * 2. The next wake alarm is reached - * So we should check whether an interrupt may happen, and fast - * forward to the nearest among: - * 1. When interrupt generator wakes up - * 2. When the next task wakes up - */ - int task_id = task_get_next_wake(); - - if (!has_interrupt_generator) { - if (task_id == TASK_ID_INVALID) { - return TASK_ID_IDLE; - } else { - force_time(tasks[task_id].wake_time); - return task_id; - } - } - - if (!generator_sleeping) - return TASK_ID_IDLE; - - if (task_id != TASK_ID_INVALID && - tasks[task_id].thread != (pthread_t)NULL && - tasks[task_id].wake_time.val < generator_sleep_deadline.val) { - force_time(tasks[task_id].wake_time); - return task_id; - } else { - force_time(generator_sleep_deadline); - return TASK_ID_IDLE; - } -} - -int task_start_called(void) -{ - return task_started; -} - -void task_scheduler(void) -{ - int i; - timestamp_t now; - - task_started = 1; - - while (1) { - now = get_time(); - i = TASK_ID_COUNT - 1; - while (i >= 0) { - /* - * Only tasks with spawned threads are valid to be - * resumed. - */ - if (tasks[i].thread) { - if (tasks[i].event || - now.val >= tasks[i].wake_time.val) - break; - } - --i; - } - if (i < 0) - i = fast_forward(); - - now = get_time(); - if (now.val >= tasks[i].wake_time.val) - tasks[i].event |= TASK_EVENT_TIMER; - tasks[i].wake_time.val = ~0ull; - running_task_id = i; - tasks[i].started = 1; - pthread_cond_signal(&tasks[i].resume); - pthread_cond_wait(&scheduler_cond, &run_lock); - } -} - -void *_task_start_impl(void *a) -{ - long tid = (long)a; - const struct task_args *arg = task_info + tid; - my_task_id = tid; - pthread_mutex_lock(&run_lock); - - /* Wait for scheduler */ - task_wait_event(1); - tasks[tid].event = 0; - - /* Start the task routine */ - (arg->routine)(arg->d); - - /* Catch exited routine */ - while (1) - task_wait_event(-1); -} - -test_mockable void interrupt_generator(void) -{ - has_interrupt_generator = 0; -} - -void *_task_int_generator_start(void *d) -{ - my_task_id = TASK_ID_INT_GEN; - interrupt_generator(); - return NULL; -} - -int task_start(void) -{ - int i = TASK_ID_HOOKS; - - pthread_mutex_init(&run_lock, NULL); - pthread_mutex_init(&interrupt_lock, NULL); - pthread_cond_init(&scheduler_cond, NULL); - - pthread_mutex_lock(&run_lock); - - /* - * Initialize the hooks task first. After its init, it will callback to - * enable the remaining tasks. - */ - tasks[i].event = TASK_EVENT_WAKE; - tasks[i].wake_time.val = ~0ull; - tasks[i].started = 0; - pthread_cond_init(&tasks[i].resume, NULL); - pthread_create(&tasks[i].thread, NULL, _task_start_impl, - (void *)(uintptr_t)i); - pthread_cond_wait(&scheduler_cond, &run_lock); - /* - * Interrupt lock is grabbed by the task which just started. - * Let's unlock it so the next task can be started. - */ - pthread_mutex_unlock(&interrupt_lock); - - /* - * The hooks task is waiting in task_wait_event(). Lock interrupt_lock - * here so the first task chosen sees it locked. - */ - pthread_mutex_lock(&interrupt_lock); - - pthread_create(&interrupt_thread, NULL, - _task_int_generator_start, NULL); - - /* - * Tell the hooks task to continue so that it can call back to enable - * the other tasks. - */ - pthread_cond_signal(&tasks[i].resume); - pthread_cond_wait(&scheduler_cond, &run_lock); - task_enable_all_tasks_callback(); - - task_scheduler(); - - return 0; -} - -static void task_enable_all_tasks_callback(void) -{ - int i; - - /* Initialize the remaning tasks. */ - for (i = 0; i < TASK_ID_COUNT; ++i) { - if (tasks[i].thread != (pthread_t)NULL) - continue; - - tasks[i].event = TASK_EVENT_WAKE; - tasks[i].wake_time.val = ~0ull; - tasks[i].started = 0; - pthread_cond_init(&tasks[i].resume, NULL); - pthread_create(&tasks[i].thread, NULL, _task_start_impl, - (void *)(uintptr_t)i); - /* - * Interrupt lock is grabbed by the task which just started. - * Let's unlock it so the next task can be started. - */ - pthread_mutex_unlock(&interrupt_lock); - pthread_cond_wait(&scheduler_cond, &run_lock); - } - -} - -void task_enable_all_tasks(void) -{ - /* Signal to the scheduler to enable the remaining tasks. */ - pthread_cond_signal(&scheduler_cond); -} diff --git a/core/host/timer.c b/core/host/timer.c deleted file mode 100644 index 3c3695cad4..0000000000 --- a/core/host/timer.c +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright 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 "task.h" -#include "test_util.h" -#include "timer.h" -#include "util.h" - -static timestamp_t boot_time; -static int time_set; - -void usleep(unsigned us) -{ - if (!task_start_called() || task_get_current() == TASK_ID_INVALID) { - udelay(us); - return; - } - - ASSERT(!in_interrupt_context() && - task_get_current() != TASK_ID_INT_GEN); - - task_wait_event(us); -} - -timestamp_t _get_time(void) -{ - static timestamp_t time; - - /* - * We just monotonically increase the microsecond every time we check - * the time. Do not depend on host system time as this introduces - * flakyness in tests. The time is periodically fast forwarded with - * force_time() during the host's task scheduler implementation. - */ - ++time.val; - return time; -} - -test_mockable timestamp_t get_time(void) -{ - timestamp_t ret = _get_time(); - ret.val -= boot_time.val; - return ret; -} - -uint32_t __hw_clock_source_read(void) -{ - return get_time().le.lo; -} - -void force_time(timestamp_t ts) -{ - timestamp_t now = _get_time(); - boot_time.val = now.val - ts.val; - time_set = 1; -} - -void udelay(unsigned us) -{ - timestamp_t deadline; - - if (!in_interrupt_context() && task_get_current() == TASK_ID_INT_GEN) { - interrupt_generator_udelay(us); - return; - } - - deadline.val = get_time().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) -{ - - if (!time_set) { - /* - * Start the timer just before the 64-bit rollover to try - * and catch 32-bit rollover/truncation bugs. - */ - timestamp_t ts = { - .val = 0xFFFFFFF0 - }; - - force_time(ts); - } -} |