diff options
author | Patryk Duda <pdk@semihalf.com> | 2020-08-28 13:44:59 +0200 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-05-01 21:28:37 +0000 |
commit | a7d9ae7d8093dbeddb09099f345ecc9df0dcd6cf (patch) | |
tree | db62ffdd6d59a7646f7b992ff5866cb51570c76c | |
parent | a1f6a6816f2a7f1394626e9c11cd9b29b6405c18 (diff) | |
download | chrome-ec-a7d9ae7d8093dbeddb09099f345ecc9df0dcd6cf.tar.gz |
Introduce functions that provide safe pointer to panic data
panic_get_data() function should always return pointer to panic_data
structure that can be safely interpreted. When structure layout
left by previous EC is different than ours then panic_get_data()
should return NULL. Difference in layout can occur when we are jumping
from old RO, this happens in eve.
Introduce two new functions:
get_panic_data_start() - It can be used to obtain beginning of panic
data, eg. when copying raw data or when determining where jump data is.
get_panic_data_write() - It can be used to obtain pointer to panic_data
structure that can be safely written. This function moves jump data and
jump tags if necessary.
Signed-off-by: Patryk Duda <pdk@semihalf.com>
Change-Id: If5f73c86e2176a0169b0be4b890e399c2c259740
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2379845
Reviewed-by: Jett Rink <jettrink@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4455289
Tested-by: Rob Barnes <robbarnes@google.com>
Commit-Queue: Rob Barnes <robbarnes@google.com>
Reviewed-by: Boris Mittelberg <bmbm@google.com>
-rw-r--r-- | common/panic_output.c | 113 | ||||
-rw-r--r-- | include/panic.h | 26 | ||||
-rw-r--r-- | include/sysjump.h | 47 |
3 files changed, 183 insertions, 3 deletions
diff --git a/common/panic_output.c b/common/panic_output.c index e9f8f696b3..66b33c5242 100644 --- a/common/panic_output.c +++ b/common/panic_output.c @@ -10,6 +10,8 @@ #include "host_command.h" #include "panic.h" #include "printf.h" +#include "software_panic.h" +#include "sysjump.h" #include "system.h" #include "task.h" #include "timer.h" @@ -115,7 +117,116 @@ void panic(const char *msg) struct panic_data *panic_get_data(void) { BUILD_ASSERT(sizeof(struct panic_data) <= CONFIG_PANIC_DATA_SIZE); - return pdata_ptr->magic == PANIC_DATA_MAGIC ? pdata_ptr : NULL; + + if (pdata_ptr->magic != PANIC_DATA_MAGIC || + pdata_ptr->struct_size != CONFIG_PANIC_DATA_SIZE) + return NULL; + + return pdata_ptr; +} + +/* + * Returns pointer to beginning of panic data. + * Please note that it is not safe to interpret this + * pointer as panic_data structure. + */ +uintptr_t get_panic_data_start(void) +{ + if (pdata_ptr->magic != PANIC_DATA_MAGIC) + return 0; + + return ((uintptr_t)CONFIG_PANIC_DATA_BASE + + CONFIG_PANIC_DATA_SIZE + - pdata_ptr->struct_size); +} + +/* + * Returns pointer to panic_data structure that can be safely written. + * Please note that this function can move jump data and jump tags. + * It can also delete panic data from previous boot, so this function + * should be used when we are sure that we don't need it. + */ +struct panic_data *get_panic_data_write(void) +{ + /* + * Pointer to panic_data structure. It may not point to + * the beginning of structure, but accessing struct_size + * and magic is safe because it is always placed at the + * end of RAM. + */ + struct panic_data * const pdata_ptr = PANIC_DATA_PTR; + const struct jump_data *jdata_ptr; + uintptr_t data_begin; + size_t move_size; + int delta; + + /* + * If panic data exists, jump data and jump tags should be moved + * about difference between size of panic_data structure and size of + * structure that is present in memory. + * + * If panic data doesn't exist, lets create place for a one + */ + if (pdata_ptr->magic == PANIC_DATA_MAGIC) + delta = CONFIG_PANIC_DATA_SIZE - pdata_ptr->struct_size; + else + delta = CONFIG_PANIC_DATA_SIZE; + + /* If delta is 0, there is no need to move anything */ + if (delta == 0) + return pdata_ptr; + + /* + * Expecting get_panic_data_start() will return a pointer to + * the beginning of panic data, or NULL if no panic data available + */ + data_begin = get_panic_data_start(); + if (!data_begin) + data_begin = CONFIG_RAM_BASE + CONFIG_RAM_SIZE; + + jdata_ptr = (struct jump_data *)(data_begin - sizeof(struct jump_data)); + + /* + * If we don't have valid jump_data structure we don't need to move + * anything and can just return pdata_ptr (clear memory, set magic + * and struct_size first). + */ + if (jdata_ptr->magic != JUMP_DATA_MAGIC || + jdata_ptr->version < 1 || jdata_ptr->version > 3) { + memset(pdata_ptr, 0, CONFIG_PANIC_DATA_SIZE); + pdata_ptr->magic = PANIC_DATA_MAGIC; + pdata_ptr->struct_size = CONFIG_PANIC_DATA_SIZE; + + return pdata_ptr; + } + + if (jdata_ptr->version == 1) + move_size = JUMP_DATA_SIZE_V1; + else if (jdata_ptr->version == 2) + move_size = JUMP_DATA_SIZE_V2 + jdata_ptr->jump_tag_total; + else if (jdata_ptr->version == 3) + move_size = jdata_ptr->struct_size + jdata_ptr->jump_tag_total; + else { + /* Unknown jump data version - set move size to 0 */ + move_size = 0; + } + + data_begin -= move_size; + + if (move_size != 0) { + /* Move jump_tags and jump_data */ + memmove((void *)(data_begin - delta), (void *)data_begin, move_size); + } + + /* + * Now we are sure that there is enough space for current + * panic_data structure. + */ + memset(pdata_ptr, 0, CONFIG_PANIC_DATA_SIZE); + pdata_ptr->magic = PANIC_DATA_MAGIC; + pdata_ptr->struct_size = CONFIG_PANIC_DATA_SIZE; + + return pdata_ptr; } static void panic_init(void) diff --git a/include/panic.h b/include/panic.h index 00a64b854d..80f69a85cc 100644 --- a/include/panic.h +++ b/include/panic.h @@ -165,14 +165,36 @@ void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception); void ignore_bus_fault(int ignored); /** - * Return a pointer to the saved data from a previous panic. + * Return a pointer to the saved data from a previous panic that can be + * safely interpreted * - * @param pointer to the panic data, or NULL if none available (for example, + * @param pointer to the valid panic data, or NULL if none available (for example, * the last reboot was not caused by a panic). */ struct panic_data *panic_get_data(void); /** + * Return a pointer to the beginning of panic data. This function can be + * used to obtain pointer which can be used to calculate place of other + * structures (eg. jump_data). This function should not be used to get access + * to panic_data structure as it might not be valid + * + * @param pointer to the beginning of panic_data, or NULL if there is no + * panic_data + */ +uintptr_t get_panic_data_start(void); + +/* + * Return a pointer to panic_data structure that can be safely written. + * Please note that this function can move jump data and jump tags. + * It can also delete panic data from previous boot, so this function + * should be used when we are sure that we don't need it. + * + * @param pointer to panic_data structure that can be safely written + */ +struct panic_data *get_panic_data_write(void); + +/** * Chip-specific implementation for backing up panic data to persistent * storage. This function is used to ensure that the panic data can survive loss * of VCC power rail. diff --git a/include/sysjump.h b/include/sysjump.h new file mode 100644 index 0000000000..b0cb1702d8 --- /dev/null +++ b/include/sysjump.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 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. + */ + +/* sysjump implementation-specific structures */ + +#ifndef __CROS_EC_SYSJUMP_IMPL_H +#define __CROS_EC_SYSJUMP_IMPL_H + +#include "stdint.h" + +/* + * Data passed between the current image and the next one when jumping between + * images. + */ + +#define JUMP_DATA_MAGIC 0x706d754a /* "Jump" */ +#define JUMP_DATA_VERSION 3 +#define JUMP_DATA_SIZE_V1 12 /* Size of version 1 jump data struct */ +#define JUMP_DATA_SIZE_V2 16 /* Size of version 2 jump data struct */ + +struct jump_data { + /* + * Add new fields to the _start_ of the struct, since we copy it to the + * _end_ of RAM between images. This way, the magic number will always + * be the last word in RAM regardless of how many fields are added. + */ + + /* Fields from version 3 */ + uint8_t reserved0; /* (used in proto1 to signal recovery mode) */ + int struct_size; /* Size of struct jump_data */ + + /* Fields from version 2 */ + int jump_tag_total; /* Total size of all jump tags */ + + /* Fields from version 1 */ + uint32_t reset_flags; /* Reset flags from the previous boot */ + int version; /* Version (JUMP_DATA_VERSION) */ + int magic; /* Magic number (JUMP_DATA_MAGIC). If this + * doesn't match at pre-init time, assume no valid + * data from the previous image. + */ +}; + +#endif /* __CROS_EC_SYSJUMP_IMPL_H */ |