| /* 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. |
| */ |
| |
| /* System module for emulator */ |
| |
| #include "common.h" |
| #include "ec_commands.h" |
| #include "host_test.h" |
| #include "panic.h" |
| #include "persistence.h" |
| #include "reboot.h" |
| #include "system.h" |
| #include "timer.h" |
| #include "util.h" |
| |
| // Forward declaration from <stdlib.h> to avoid declaration conflicts. |
| void exit(int); |
| |
| #define SHARED_MEM_SIZE 0x2000 /* bytes */ |
| #define RAM_DATA_SIZE (sizeof(struct panic_data) + 512) /* bytes */ |
| uint8_t __shared_mem_buf[SHARED_MEM_SIZE + RAM_DATA_SIZE]; |
| |
| static char *__ram_data = __shared_mem_buf + SHARED_MEM_SIZE; |
| |
| static enum ec_image __running_copy; |
| |
| static void ramdata_set_persistent(void) |
| { |
| FILE *f = get_persistent_storage("ramdata", "wb"); |
| int sz; |
| |
| ASSERT(f != NULL); |
| |
| sz = fwrite(__ram_data, RAM_DATA_SIZE, 1, f); |
| ASSERT(sz == 1); |
| |
| release_persistent_storage(f); |
| } |
| |
| static void ramdata_get_persistent(void) |
| { |
| FILE *f = get_persistent_storage("ramdata", "rb"); |
| |
| if (f == NULL) { |
| fprintf(stderr, |
| "No RAM data found. Initializing to 0x00.\n"); |
| memset(__ram_data, 0, RAM_DATA_SIZE); |
| return; |
| } |
| |
| fread(__ram_data, RAM_DATA_SIZE, 1, f); |
| |
| release_persistent_storage(f); |
| |
| /* |
| * Assumes RAM data doesn't preserve across reboot except for sysjump. |
| * Clear persistent data once it's read. |
| */ |
| remove_persistent_storage("ramdata"); |
| } |
| |
| static void set_image_copy(uint32_t copy) |
| { |
| FILE *f = get_persistent_storage("image_copy", "wb"); |
| |
| ASSERT(f != NULL); |
| ASSERT(fwrite(©, sizeof(copy), 1, f) == 1); |
| |
| release_persistent_storage(f); |
| } |
| |
| static uint32_t get_image_copy(void) |
| { |
| FILE *f = get_persistent_storage("image_copy", "rb"); |
| uint32_t ret; |
| |
| if (f == NULL) |
| return EC_IMAGE_UNKNOWN; |
| fread(&ret, sizeof(ret), 1, f); |
| release_persistent_storage(f); |
| remove_persistent_storage("image_copy"); |
| |
| return ret; |
| } |
| |
| static void save_reset_flags(uint32_t flags) |
| { |
| FILE *f = get_persistent_storage("reset_flags", "wb"); |
| |
| ASSERT(f != NULL); |
| ASSERT(fwrite(&flags, sizeof(flags), 1, f) == 1); |
| |
| release_persistent_storage(f); |
| } |
| |
| static uint32_t load_reset_flags(void) |
| { |
| FILE *f = get_persistent_storage("reset_flags", "rb"); |
| uint32_t ret; |
| |
| if (f == NULL) |
| return EC_RESET_FLAG_POWER_ON; |
| fread(&ret, sizeof(ret), 1, f); |
| release_persistent_storage(f); |
| remove_persistent_storage("reset_flags"); |
| |
| return ret; |
| } |
| |
| static void save_time(timestamp_t t) |
| { |
| FILE *f = get_persistent_storage("time", "wb"); |
| |
| ASSERT(f != NULL); |
| ASSERT(fwrite(&t, sizeof(t), 1, f) == 1); |
| |
| release_persistent_storage(f); |
| } |
| |
| static int load_time(timestamp_t *t) |
| { |
| FILE *f = get_persistent_storage("time", "rb"); |
| |
| if (f == NULL) |
| return 0; |
| fread(t, sizeof(*t), 1, f); |
| release_persistent_storage(f); |
| remove_persistent_storage("time"); |
| |
| return 1; |
| } |
| |
| test_mockable struct panic_data *panic_get_data(void) |
| { |
| return (struct panic_data *) |
| (__ram_data + RAM_DATA_SIZE - sizeof(struct panic_data)); |
| } |
| |
| test_mockable uintptr_t get_panic_data_start() |
| { |
| return (uintptr_t) |
| (__ram_data + RAM_DATA_SIZE - sizeof(struct panic_data)); |
| } |
| |
| test_mockable void system_reset(int flags) |
| { |
| uint32_t save_flags = 0; |
| if (flags & SYSTEM_RESET_PRESERVE_FLAGS) |
| save_flags = system_get_reset_flags() | EC_RESET_FLAG_PRESERVED; |
| if (flags & SYSTEM_RESET_LEAVE_AP_OFF) |
| save_flags |= EC_RESET_FLAG_AP_OFF; |
| if (flags & SYSTEM_RESET_HARD) |
| save_flags |= EC_RESET_FLAG_HARD; |
| if (save_flags) |
| save_reset_flags(save_flags); |
| emulator_reboot(); |
| } |
| |
| test_mockable void system_hibernate(uint32_t seconds, uint32_t microseconds) |
| { |
| uint32_t i; |
| |
| if (board_hibernate) |
| board_hibernate(); |
| |
| save_reset_flags(EC_RESET_FLAG_HIBERNATE); |
| |
| if (!seconds && !microseconds) |
| exit(EXIT_CODE_HIBERNATE); |
| |
| for (i = 0; i < seconds; ++i) |
| udelay(SECOND); |
| udelay(microseconds); |
| emulator_reboot(); |
| } |
| |
| test_mockable int system_is_locked(void) |
| { |
| return 0; |
| } |
| |
| #ifdef TEST_FUZZ |
| /* When fuzzing, do not allow sysjumps. */ |
| int system_run_image_copy(enum ec_image copy) |
| { |
| ccprints("Emulator would sysjump here. Fuzzing: doing nothing."); |
| return EC_ERROR_UNKNOWN; |
| } |
| #endif |
| |
| 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_bbram(enum system_bbram_idx idx, uint8_t *value) |
| { |
| return EC_ERROR_UNIMPLEMENTED; |
| } |
| |
| int system_set_bbram(enum system_bbram_idx idx, uint8_t value) |
| { |
| return EC_ERROR_UNIMPLEMENTED; |
| } |
| |
| enum ec_image system_get_image_copy(void) |
| { |
| return __running_copy; |
| } |
| |
| int system_set_scratchpad(uint32_t value) |
| { |
| FILE *f = get_persistent_storage("scratchpad", "w"); |
| |
| fprintf(f, "%lu", value); |
| release_persistent_storage(f); |
| |
| return EC_SUCCESS; |
| } |
| |
| uint32_t system_get_scratchpad(void) |
| { |
| FILE *f = get_persistent_storage("scratchpad", "r"); |
| uint32_t value; |
| int success; |
| |
| if (f == NULL) |
| return 0; |
| |
| success = fscanf(f, "%u", &value); |
| release_persistent_storage(f); |
| |
| if (success) |
| return value; |
| else |
| return 0; |
| } |
| |
| static void __jump_resetvec(void) |
| { |
| save_time(get_time()); |
| ramdata_set_persistent(); |
| emulator_reboot(); |
| } |
| |
| static void __ro_jump_resetvec(void) |
| { |
| set_image_copy(EC_IMAGE_RO); |
| __jump_resetvec(); |
| } |
| |
| static void __rw_jump_resetvec(void) |
| { |
| set_image_copy(EC_IMAGE_RW); |
| __jump_resetvec(); |
| } |
| |
| void system_pre_init(void) |
| { |
| timestamp_t t; |
| |
| if (load_time(&t)) |
| force_time(t); |
| |
| ramdata_get_persistent(); |
| __running_copy = get_image_copy(); |
| if (__running_copy == EC_IMAGE_UNKNOWN) { |
| __running_copy = EC_IMAGE_RO; |
| system_set_reset_flags(load_reset_flags()); |
| } |
| |
| *(uintptr_t *)(__host_flash + CONFIG_RO_MEM_OFF + 4) = |
| (uintptr_t)__ro_jump_resetvec; |
| *(uintptr_t *)(__host_flash + CONFIG_RW_MEM_OFF + 4) = |
| (uintptr_t)__rw_jump_resetvec; |
| } |