clear-pkgs-linux-iot-lts2018/1074-ASoC-Intel-read-DSP-st...

235 lines
8.2 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Lulko, KamilX" <kamilx.lulko@intel.com>
Date: Fri, 22 Mar 2019 12:33:02 +0100
Subject: [PATCH] ASoC: Intel: read DSP stack dump from specific core only
DSP exception notification states explicitly which core
the exception is from. Only this core will print the stack
into the memory window so there is no point in trying to read
it from all cores. Additionally add simple boundary check for
read and write pointers - these could be overwritten by DSP
and cause out of bounds offset access.
Change-Id: I1bf6caaf16a448ce7cd6c93229ffe19aa99d55cd
Tracked-On: OAM-79127
Signed-off-by: Lulko, KamilX <kamilx.lulko@intel.com>
---
sound/soc/intel/skylake/skl-sst-ipc.c | 1 +
sound/soc/intel/skylake/skl-sst-ipc.h | 2 +-
sound/soc/intel/skylake/skl-sst-utils.c | 121 +++++++++++-------------
3 files changed, 58 insertions(+), 66 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c
index af84aab4689a..891d6ca8325b 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.c
+++ b/sound/soc/intel/skylake/skl-sst-ipc.c
@@ -656,6 +656,7 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
dev_err(ipc->dev, "Exception Stack size is %d\n", (header.extension >> DSP_EXCEP_STACK_SIZE_SHIFT));
/* hexdump of the fw core exception record reg */
ret = skl_dsp_crash_dump_read(skl,
+ (header.extension & DSP_EXCEP_CORE_MASK),
(header.extension >> DSP_EXCEP_STACK_SIZE_SHIFT));
if (ret < 0) {
dev_err(ipc->dev,
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
index d28913476d3b..abddf44562b3 100644
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
@@ -481,7 +481,7 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size);
int skl_notify_tplg_change(struct skl_sst *ctx, int type);
-int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size);
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int idx, int stack_size);
void skl_ipc_set_fw_cfg(struct sst_generic_ipc *ipc, u8 instance_id,
u16 module_id, u32 *data);
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
index 344892e70d86..856a6e86be52 100644
--- a/sound/soc/intel/skylake/skl-sst-utils.c
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
@@ -35,6 +35,9 @@
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
#define MAX_DSP_EXCEPTION_STACK_SIZE (64*1024)
+#define EXCEPTION_RECORD_OFFSET(core_count, core_idx) \
+ (0x1000 - ((core_count - core_idx) * 0x158) + 4)
+
/* FW adds headers and trailing patters to extended crash data */
#define EXTRA_BYTES 256
@@ -313,42 +316,20 @@ void skl_reset_instance_id(struct skl_sst *ctx)
}
EXPORT_SYMBOL_GPL(skl_reset_instance_id);
-/* This function checks tha available data on the core id
- * passed as an argument and returns the bytes available
- */
-static int skl_check_ext_excep_data_avail(struct skl_sst *ctx, int idx)
-{
- u32 size = ctx->dsp->trace_wind.size/ctx->dsp->trace_wind.nr_dsp;
- u8 *base = (u8 __force*)ctx->dsp->trace_wind.addr;
- u32 read, write;
- u32 *ptr;
-
- /* move to the source dsp tracing window */
- base += (idx * size);
- ptr = (u32 *) base;
- read = readl(ptr);
- write = readl(ptr+1);
-
- if (write == read)
- return 0;
- else if (write > read)
- return (write - read);
- else
- return (size - 8 - read + write);
-}
-
/* Function to read the extended DSP crash information from the
* log buffer memory window, on per core basis.
* Data is read into the buffer passed as *ext_core_dump.
* number of bytes read is updated in the sz_ext_dump
*/
-static void skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
- void *ext_core_dump, int *sz_ext_dump)
+static int skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
+ void *ext_core_dump, int ext_core_dump_sz, int *sz_ext_dump)
+
{
u32 size = ctx->dsp->trace_wind.size/ctx->dsp->trace_wind.nr_dsp;
u8 *base = (u8 __force*)ctx->dsp->trace_wind.addr;
u32 read, write;
int offset = *sz_ext_dump;
+ int count;
u32 *ptr;
/* move to the current core's tracing window */
@@ -359,44 +340,49 @@ static void skl_read_ext_exception_data(struct skl_sst *ctx, int idx,
/* in case of read = write, just return */
if (read == write)
- return;
+ return 0;
+ /* check r/w pointers sanity */
+ if ((read + 8) >= size || (write + 8) >= size)
+ return -EINVAL;
- if (write > read) {
- memcpy_fromio((ext_core_dump + offset),
- (const void __iomem *)(base + 8 + read),
- (write - read));
- *sz_ext_dump = offset + write - read;
- /* advance read pointer */
- } else {
- /* wrap around condition - copy till the end */
- memcpy_fromio((ext_core_dump + offset),
- (const void __iomem *)(base + 8 + read),
- (size - 8 - read));
- *sz_ext_dump = offset + size - 8 - read;
- offset = *sz_ext_dump;
-
- /* copy from the beginnning */
- memcpy_fromio((ext_core_dump + offset),
- (const void __iomem *) (base + 8), write);
- *sz_ext_dump = offset + write;
- /* update the read pointer */
- }
- writel(write, ptr);
+ if (write > read)
+ count = write - read;
+ else
+ count = size - 8 - read;
+
+ if (offset + count > ext_core_dump_sz)
+ return -EINVAL;
+
+ memcpy_fromio((ext_core_dump + offset),
+ (const void __iomem *) (base + 8 + read), count);
+
+ *sz_ext_dump = offset + count;
+ read += count;
+ if (read >= size - 8)
+ read = 0;
+ writel(read, ptr);
+ return 0;
}
-int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
+int skl_dsp_crash_dump_read(struct skl_sst *ctx, int idx, int stack_size)
{
- int num_mod = 0, size_core_dump, sz_ext_dump = 0, idx = 0;
+ int num_mod = 0, size_core_dump, sz_ext_dump = 0;
struct uuid_module *module, *module1;
void *coredump, *ext_core_dump;
+ unsigned long ext_core_dump_sz;
void *fw_reg_addr, *offset;
struct pci_dev *pci = to_pci_dev(ctx->dsp->dev);
+ u32 stackdump_complete = 0;
u16 length0, length1, length2, length3;
struct adsp_crash_hdr *crash_data_hdr;
struct adsp_type0_crash_data *type0_data;
struct adsp_type1_crash_data *type1_data;
struct adsp_type2_crash_data *type2_data;
struct sst_dsp *sst = ctx->dsp;
+ unsigned long timeout;
+
+ if (idx < 0 || idx >= ctx->cores.count)
+ return -EINVAL;
if (list_empty(&ctx->uuid_list))
dev_info(ctx->dev, "Module list is empty\n");
@@ -406,20 +392,27 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
}
if(stack_size)
- ext_core_dump = vzalloc(stack_size + EXTRA_BYTES);
+ ext_core_dump_sz = stack_size + EXTRA_BYTES;
else
- ext_core_dump = vzalloc(MAX_DSP_EXCEPTION_STACK_SIZE + EXTRA_BYTES);
- if (!ext_core_dump) {
- dev_err(ctx->dsp->dev, "failed to allocate memory for FW Stack\n");
- return -ENOMEM;
- }
- for (idx = 0; idx < sst->trace_wind.nr_dsp; idx++) {
- if(skl_check_ext_excep_data_avail(ctx, idx) != 0) {
- while(sz_ext_dump < stack_size) {
- skl_read_ext_exception_data(ctx, idx,
- ext_core_dump, &sz_ext_dump);
- }
- }
+ ext_core_dump_sz = MAX_DSP_EXCEPTION_STACK_SIZE + EXTRA_BYTES;
+ ext_core_dump = vzalloc(ext_core_dump_sz);
+ if (!ext_core_dump) {
+ dev_err(ctx->dsp->dev, "failed to allocate memory for FW Stack\n");
+ return -ENOMEM;
+ }
+
+ fw_reg_addr = (void __force *)(ctx->dsp->mailbox.in_base -
+ ctx->dsp->addr.w0_stat_sz);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (!stackdump_complete) {
+ stackdump_complete = readl(fw_reg_addr +
+ EXCEPTION_RECORD_OFFSET(ctx->cores.count, idx));
+ if (skl_read_ext_exception_data(ctx, idx, ext_core_dump,
+ ext_core_dump_sz, &sz_ext_dump) < 0)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
}
/* Length representing in DWORD */
@@ -475,8 +468,6 @@ int skl_dsp_crash_dump_read(struct skl_sst *ctx, int stack_size)
crash_data_hdr->length = length2;
offset += sizeof(*crash_data_hdr);
type2_data = (struct adsp_type2_crash_data *) offset;
- fw_reg_addr = (void __force*)(ctx->dsp->mailbox.in_base -
- ctx->dsp->addr.w0_stat_sz);
memcpy_fromio(type2_data->fwreg, (const void __iomem *)fw_reg_addr,
sizeof(*type2_data));
offset += sizeof(*type2_data);
--
https://clearlinux.org