summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatryk Duda <pdk@semihalf.com>2020-08-28 13:44:59 +0200
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-05-01 21:28:37 +0000
commita7d9ae7d8093dbeddb09099f345ecc9df0dcd6cf (patch)
treedb62ffdd6d59a7646f7b992ff5866cb51570c76c
parenta1f6a6816f2a7f1394626e9c11cd9b29b6405c18 (diff)
downloadchrome-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.c113
-rw-r--r--include/panic.h26
-rw-r--r--include/sysjump.h47
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 */