
On 2/26/20 10:42 AM, Frédéric Danis wrote:
This patch adds a new pstore command allowing to display or save ramoops logs (oops, panic, console, ftrace and user) generated by a previous kernel crash. PStore parameters can be set in U-Boot configuration file, or at run-time using "pstore set" command. Records size should be the same as the ones used by kernel, and should be a power of 2. This command allows:
- to display uncompressed logs
- to save compressed or uncompressed logs, compressed logs are saved as a compressed stream, it may need some work to be able to decompress it, e.g. adding a fake header: "printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" | cat - dmesg-ramoops-0.enc.z | gzip -dc"
- ECC part is not used to check memory corruption
- only 1st FTrace log is displayed or saved
Signed-off-by: Frédéric Danis frederic.danis@collabora.com
cmd/Kconfig | 63 ++++++ cmd/Makefile | 1 + cmd/pstore.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/index.rst | 7 + doc/pstore.rst | 68 +++++++ 5 files changed, 644 insertions(+) create mode 100644 cmd/pstore.c create mode 100644 doc/pstore.rst
diff --git a/cmd/Kconfig b/cmd/Kconfig index 6403bc45a5..7e78343c3d 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1736,6 +1736,69 @@ config CMD_QFW feature is to allow easy loading of files passed to qemu-system via -kernel / -initrd
+config CMD_PSTORE
- bool "pstore"
- help
This provides access to Linux PStore. The main feature is to allow to
display or save PStore records.
Linux PStore can have many backends. I would suggest to mention 'rampoops' explicitely and point to the documentation that you have added.
Please, use 'if CMD_PSTORE' to indent all options depending on CMD_PSTORE'.
+config CMD_PSTORE_ADDR
- hex "Mem Address"
Please, use whole words.
hex "Memory address"
- depends on CMD_PSTORE
- default "0x0"
- help
Base addr used for PStore ramoops memory, should be identical to
ramoops.mem_address parameter used by kernel
+config CMD_PSTORE_SIZE
Linux calls the parameter mem_size. So shouldn't we call our parameter CMD_PSTORE_MEM_SIZE.
- hex "Mem size"
hex "Memory size"
- depends on CMD_PSTORE
- default "0x0"
A value of zero will lead to an error in Linux "The memory size and the record/console size must be non-zero".
Please, provide a reasonable default.
- help
Size of PStore ramoops memory, should be identical to ramoops.mem_size
parameter used by kernel
Please, describe the constraints on ramoops.mem_size. Does it have to be larger than the some of the following parameters?
+config CMD_PSTORE_RECORD_SIZE
- hex "Dump record size"
- depends on CMD_PSTORE
- default "0x1000"
- help
Size of each dump done on oops/panic, should be identical to
ramoops.record_size parameter used by kernel
+config CMD_PSTORE_CONSOLE_SIZE
- hex "Kernel console log size"
- depends on CMD_PSTORE
- default "0x1000"
- help
Size of kernel console log, should be identical to
ramoops.console_size parameter used by kernel
Please, mention that this value must be non-zero.
+config CMD_PSTORE_FTRACE_SIZE
- hex "FTrace log size"
- depends on CMD_PSTORE
- default "0x1000"
- help
Size of ftrace log, should be identical to ramoops.ftrace_size
parameter used by kernel
+config CMD_PSTORE_PMSG_SIZE
- hex "User space message log size"
- depends on CMD_PSTORE
- default "0x1000"
- help
Size of user space message log, should be identical to
ramoops.pmsg_size parameter used by kernel
+config CMD_PSTORE_ECC_SIZE
int "ECC size"
depends on CMD_PSTORE
default "0"
help
if non-zero, the option enables ECC support and specifies ECC buffer
size in bytes (1 is a special value, means 16 bytes ECC), should be
identical to ramoops.ramoops_ecc parameter used by kernel
source "cmd/mvebu/Kconfig"
config CMD_TERMINAL
diff --git a/cmd/Makefile b/cmd/Makefile index f1dd513a4b..06d7ad7375 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_CMD_PCI) += pci.o endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PMC) += pmc.o +obj-$(CONFIG_CMD_PSTORE) += pstore.o obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o diff --git a/cmd/pstore.c b/cmd/pstore.c new file mode 100644 index 0000000000..a14b8522ce --- /dev/null +++ b/cmd/pstore.c @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright © 2019 Collabora Ltd
- */
+#include <config.h> +#include <common.h> +#include <fs.h> +#include <mapmem.h> +#include <memalign.h> +#include <part.h>
+struct persistent_ram_buffer {
- u32 sig;
- u32 start;
- u32 size;
- u8 data[0];
+};
+#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ +#define RAMOOPS_KERNMSG_HDR "===="
+#define PSTORE_TYPE_DMESG 0 +#define PSTORE_TYPE_CONSOLE 2 +#define PSTORE_TYPE_FTRACE 3 +#define PSTORE_TYPE_PMSG 7 +#define PSTORE_TYPE_ALL 255
+static phys_addr_t pstore_addr = CONFIG_CMD_PSTORE_ADDR; +static phys_size_t pstore_length = CONFIG_CMD_PSTORE_SIZE; +static unsigned int pstore_record_size = CONFIG_CMD_PSTORE_RECORD_SIZE; +static unsigned int pstore_console_size = CONFIG_CMD_PSTORE_CONSOLE_SIZE; +static unsigned int pstore_ftrace_size = CONFIG_CMD_PSTORE_FTRACE_SIZE; +static unsigned int pstore_pmsg_size = CONFIG_CMD_PSTORE_PMSG_SIZE; +static unsigned int pstore_ecc_size = CONFIG_CMD_PSTORE_ECC_SIZE; +static unsigned int buffer_size;
- /**
- pstore_read_kmsg_hdr() - Check kernel header and get compression flag if
available.
- @buffer: Kernel messages buffer.
- @compressed: Returns TRUE if kernel buffer is compressed, else FALSE.
- Check if buffer starts with a kernel header of the form:
- ====<secs>.<nsecs>[-<compression>]\n
- If <compression> is equal to 'C' then the buffer is compressed, else iter
- should be 'D'.
- Return: Length of kernel header.
- */
+static int pstore_read_kmsg_hdr(char *buffer, bool *compressed) +{
- char *ptr = buffer;
- *compressed = false;
- if (strncmp(RAMOOPS_KERNMSG_HDR, ptr, strlen(RAMOOPS_KERNMSG_HDR)) != 0)
return 0;
- ptr += strlen(RAMOOPS_KERNMSG_HDR);
- ptr = strchr(ptr, '\n');
- if (!ptr)
return 0;
- if (ptr[-2] == '-' && ptr[-1] == 'C')
*compressed = true;
- return ptr - buffer + 1;
+}
+/**
- pstore_get_buffer() - Get unwrapped record buffer
- @sig: Signature to check
- @buffer: Buffer containing wrapped record
- @size: wrapped record size
- @dest: Buffer used to store unwrapped record
- The record starts with <signature><start><size> header.
- The signature is 'DBGC' for all records except for Ftrace's record(s) wich
- use LINUX_VERSION_CODE ^ 'DBGC'.
- Use 0 for @sig to prevent checking signature.
- Start and size are 4 bytes long.
- Return: record's length
- */
+static u32 pstore_get_buffer(u32 sig, phys_addr_t buffer, u32 size, char *dest) +{
- struct persistent_ram_buffer *prb =
(struct persistent_ram_buffer *)map_sysmem(buffer, size);
- u32 dest_size;
- if (sig == 0 || prb->sig == sig) {
if (prb->size == 0) {
debug("found existing empty buffer\n");
Please, use log() as described in doc/README.log. This allows the user to control verbosity if CONFIG_LOG=y.
return 0;
}
if (prb->size > size) {
debug("found existing invalid buffer, size %u, start %u\n",
prb->size, prb->start);
return 0;
}
- } else {
debug("no valid data in buffer (sig = 0x%08x)\n", prb->sig);
return 0;
- }
- debug("found existing buffer, size %u, start %u\n",
prb->size, prb->start);
- memcpy(dest, &prb->data[prb->start], prb->size - prb->start);
- memcpy(dest + prb->size - prb->start, &prb->data[0], prb->start);
- dest_size = prb->size;
- unmap_sysmem(prb);
- return dest_size;
+}
+/**
- pstore_init_buffer_size() - Init buffer size to largest record size
- Records, console, FTrace and user logs can use different buffer sizes.
- This function allows to retrieve the biggest one.
- */
+static void pstore_init_buffer_size(void) +{
- if (pstore_record_size > buffer_size)
buffer_size = pstore_record_size;
- if (pstore_console_size > buffer_size)
buffer_size = pstore_console_size;
- if (pstore_ftrace_size > buffer_size)
buffer_size = pstore_ftrace_size;
- if (pstore_pmsg_size > buffer_size)
buffer_size = pstore_pmsg_size;
+}
+/**
- pstore_set() - Initialize PStore settings from command line arguments
- @cmdtp: Command data struct pointer
- @flag: Command flag
- @argc: Command-line argument count
- @argv: Array of command-line arguments
- Set pstore reserved memory info, starting at 'addr' for 'len' bytes.
- Default length for records is 4K.
- Mandatory arguments:
- addr: ramoops starting address
- len: ramoops total length
- Optional arguments:
- record-size: size of one panic or oops record ('dump' type)
- console-size: size of the kernel logs record
- ftrace-size: size of the ftrace record(s), this can be a single record or
divided in parts based on number of CPUs
- pmsg-size: size of the user space logs record
- ecc-size: enables/disables ECC support and specifies ECC buffer size in
bytes (0 disables it, 1 is a special value, means 16 bytes ECC)
- Return: zero on success, CMD_RET_USAGE in case of misuse and negative
- on error.
- */
+static int pstore_set(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
- if (argc < 3)
return CMD_RET_USAGE;
- /* Address is specified since argc > 2
*/
- pstore_addr = simple_strtoul(argv[1], NULL, 16);
- /* Length is specified since argc > 2
*/
- pstore_length = simple_strtoul(argv[2], NULL, 16);
- if (argc > 3)
pstore_record_size = simple_strtoul(argv[3], NULL, 16);
- if (argc > 4)
pstore_console_size = simple_strtoul(argv[4], NULL, 16);
- if (argc > 5)
pstore_ftrace_size = simple_strtoul(argv[5], NULL, 16);
- if (argc > 6)
pstore_pmsg_size = simple_strtoul(argv[6], NULL, 16);
- if (argc > 7)
pstore_ecc_size = simple_strtoul(argv[7], NULL, 16);
- if (pstore_length < (pstore_record_size + pstore_console_size
+ pstore_ftrace_size + pstore_pmsg_size)) {
printf("pstore <len> should be larger than the sum of all records sizes\n");
pstore_length = 0;
- }
- debug("pstore set done: start 0x%08llx - length 0x%llx\n",
(unsigned long long)pstore_addr,
(unsigned long long)pstore_length);
- return 0;
+}
+/**
- pstore_print_buffer() - Print buffer
- @type: buffer type
- @buffer: buffer to print
- @size: buffer size
- Print buffer type and content
- */
+static void pstore_print_buffer(char *type, char *buffer, u32 size) +{
- u32 i = 0;
- printf("**** %s\n", type);
- while (i < size && buffer[i] != 0) {
putc(buffer[i]);
i++;
- }
+}
+/**
- pstore_display() - Display existing records in pstore reserved memory
- @cmdtp: Command data struct pointer
- @flag: Command flag
- @argc: Command-line argument count
- @argv: Array of command-line arguments
- A 'record-type' can be given to only display records of this kind.
- If no 'record-type' is given, all valid records are dispayed.
- 'record-type' can be one of 'dump', 'console', 'ftrace' or 'user'. For 'dump'
- and 'ftrace' types, a 'nb' can be given to only display one record.
- Return: zero on success, CMD_RET_USAGE in case of misuse and negative
- on error.
- */
+static int pstore_display(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
- int type = PSTORE_TYPE_ALL;
- phys_addr_t ptr;
- char *buffer;
- u32 size;
- int header_len = 0;
- bool compressed;
- if (argc > 1) {
if (!strcmp(argv[1], "dump"))
type = PSTORE_TYPE_DMESG;
else if (!strcmp(argv[1], "console"))
type = PSTORE_TYPE_CONSOLE;
else if (!strcmp(argv[1], "ftrace"))
type = PSTORE_TYPE_FTRACE;
else if (!strcmp(argv[1], "user"))
type = PSTORE_TYPE_PMSG;
else
return CMD_RET_USAGE;
- }
- if (pstore_length == 0) {
printf("Please set PStore configuration\n");
return CMD_RET_USAGE;
- }
- if (buffer_size == 0)
pstore_init_buffer_size();
- buffer = malloc_cache_aligned(buffer_size);
- if (type == PSTORE_TYPE_DMESG || type == PSTORE_TYPE_ALL) {
ptr = pstore_addr;
phys_addr_t ptr_end = ptr + pstore_length - pstore_pmsg_size
- pstore_ftrace_size - pstore_console_size;
if (argc > 2) {
ptr += simple_strtoul(argv[2], NULL, 10)
* pstore_record_size;
ptr_end = ptr + pstore_record_size;
}
while (ptr < ptr_end) {
size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr,
pstore_record_size, buffer);
ptr += pstore_record_size;
if (size == 0)
continue;
header_len = pstore_read_kmsg_hdr(buffer, &compressed);
if (header_len == 0) {
debug("no valid kernel header\n");
continue;
}
if (compressed) {
printf("Compressed buffer, display not available\n");
continue;
}
pstore_print_buffer("Dump", buffer + header_len,
size - header_len);
}
- }
- if (type == PSTORE_TYPE_CONSOLE || type == PSTORE_TYPE_ALL) {
ptr = pstore_addr + pstore_length - pstore_pmsg_size
- pstore_ftrace_size - pstore_console_size;
size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr,
pstore_console_size, buffer);
if (size != 0)
pstore_print_buffer("Console", buffer, size);
- }
- if (type == PSTORE_TYPE_FTRACE || type == PSTORE_TYPE_ALL) {
ptr = pstore_addr + pstore_length - pstore_pmsg_size
- pstore_ftrace_size;
/* The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC'
* signature, pass 0 to pstore_get_buffer to prevent
* checking it
*/
size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer);
if (size != 0)
pstore_print_buffer("FTrace", buffer, size);
- }
- if (type == PSTORE_TYPE_PMSG || type == PSTORE_TYPE_ALL) {
ptr = pstore_addr + pstore_length - pstore_pmsg_size;
size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr,
pstore_pmsg_size, buffer);
if (size != 0)
pstore_print_buffer("User", buffer, size);
- }
- free(buffer);
- return 0;
+}
+/**
- pstore_save() - Save existing records from pstore reserved memory
- @cmdtp: Command data struct pointer
- @flag: Command flag
- @argc: Command-line argument count
- @argv: Array of command-line arguments
- the records are saved under 'directory path', which should already exist,
- to partition 'part' on device type 'interface' instance 'dev'
- Filenames are automatically generated, depending on record type, like in
- /sys/fs/pstore under Linux
- Return: zero on success, CMD_RET_USAGE in case of misuse and negative
- on error.
- */
+static int pstore_save(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
+{
- phys_addr_t ptr, ptr_end;
- char *buffer;
- char *save_argv[6];
- char addr[19], length[19];
- char path[256];
- u32 size;
- unsigned int index;
- int header_len = 0;
- bool compressed;
- if (argc < 4)
return CMD_RET_USAGE;
- if (pstore_length == 0) {
printf("Please set PStore configuration\n");
return CMD_RET_USAGE;
- }
- if (buffer_size == 0)
pstore_init_buffer_size();
- buffer = malloc_cache_aligned(buffer_size);
- sprintf(addr, "0x%p", buffer);
- save_argv[0] = argv[0];
- save_argv[1] = argv[1];
- save_argv[2] = argv[2];
- save_argv[3] = addr;
- save_argv[4] = path;
- save_argv[5] = length;
- /* Save all Dump records */
- ptr = pstore_addr;
- ptr_end = ptr + pstore_length - pstore_pmsg_size - pstore_ftrace_size
- pstore_console_size;
- index = 0;
- while (ptr < ptr_end) {
size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr,
pstore_record_size, buffer);
ptr += pstore_record_size;
if (size == 0)
continue;
header_len = pstore_read_kmsg_hdr(buffer, &compressed);
if (header_len == 0) {
debug("no valid kernel header\n");
continue;
}
sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer + header_len));
sprintf(length, "0x%X", size - header_len);
sprintf(path, "%s/dmesg-ramoops-%u%s", argv[3], index,
compressed ? ".enc.z" : "");
do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY);
index++;
- }
- sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer));
- /* Save Console record */
- size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_console_size,
buffer);
- if (size != 0) {
sprintf(length, "0x%X", size);
sprintf(path, "%s/console-ramoops-0", argv[3]);
do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY);
- }
- ptr += pstore_console_size;
- /* Save FTrace record(s)
* The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC' signature,
* pass 0 to pstore_get_buffer to prevent checking it
*/
- size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer);
- if (size != 0) {
sprintf(length, "0x%X", size);
sprintf(path, "%s/ftrace-ramoops-0", argv[3]);
do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY);
- }
- ptr += pstore_ftrace_size;
- /* Save Console record */
- size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_pmsg_size,
buffer);
- if (size != 0) {
sprintf(length, "0x%X", size);
sprintf(path, "%s/pmsg-ramoops-0", argv[3]);
do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY);
- }
- free(buffer);
- return 0;
+}
+static cmd_tbl_t cmd_pstore_sub[] = {
- U_BOOT_CMD_MKENT(set, 8, 0, pstore_set, "", ""),
- U_BOOT_CMD_MKENT(display, 3, 0, pstore_display, "", ""),
- U_BOOT_CMD_MKENT(save, 4, 0, pstore_save, "", ""),
+};
+static int do_pstore(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{
- cmd_tbl_t *c;
- if (argc < 2)
return CMD_RET_USAGE;
- /* Strip off leading argument */
- argc--;
- argv++;
- c = find_cmd_tbl(argv[0], cmd_pstore_sub, ARRAY_SIZE(cmd_pstore_sub));
- if (!c)
return CMD_RET_USAGE;
- return c->cmd(cmdtp, flag, argc, argv);
+}
+U_BOOT_CMD(pstore, 10, 0, do_pstore,
"Manage Linux Persistent Storage",
"set <addr> <len> [record-size] [console-size] [ftrace-size] [pmsg_size] [ecc-size]\n"
"- Set pstore reserved memory info, starting at 'addr' for 'len' bytes.\n"
" Default length for records is 4K.\n"
" 'record-size' is the size of one panic or oops record ('dump' type).\n"
" 'console-size' is the size of the kernel logs record.\n"
" 'ftrace-size' is the size of the ftrace record(s), this can be a single\n"
" record or divided in parts based on number of CPUs.\n"
" 'pmsg-size' is the size of the user space logs record.\n"
" 'ecc-size' enables/disables ECC support and specifies ECC buffer size in\n"
" bytes (0 disables it, 1 is a special value, means 16 bytes ECC).\n"
"pstore display [record-type] [nb]\n"
"- Display existing records in pstore reserved memory. A 'record-type' can\n"
" be given to only display records of this kind. 'record-type' can be one\n"
" of 'dump', 'console', 'ftrace' or 'user'. For 'dump' and 'ftrace' types,\n"
" a 'nb' can be given to only display one record.\n"
"pstore save <interface> <dev[:part]> <directory-path>\n"
"- Save existing records in pstore reserved memory under 'directory path'\n"
" to partition 'part' on device type 'interface' instance 'dev'.\n"
" Filenames are automatically generated, depending on record type, like\n"
" in /sys/fs/pstore under Linux.\n"
" The 'directory-path' should already exist.\n"
+); diff --git a/doc/index.rst b/doc/index.rst index cd98be6cc5..c556cdb607 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -98,6 +98,13 @@ Android-specific features available in U-Boot.
android/index
+Command line +------------ +.. toctree::
- :maxdepth: 2
- pstore.rst
Indices and tables
diff --git a/doc/pstore.rst b/doc/pstore.rst new file mode 100644 index 0000000000..401ba34373 --- /dev/null +++ b/doc/pstore.rst @@ -0,0 +1,68 @@ +.. SPDX-License-Identifier: GPL-2.0+
+PStore command +==============
+Design +------
+Linux PStore and Ramoops modules allow to use memory to pass data from the dying
Please, mention Linux config option PSTORE_RAM here.
+breath of a crashing kernel to its successor. This command allows to read those +records from U-Boot command line.
+Ramoops is an oops/panic logger that writes its logs to RAM before the system +crashes. It works by logging oopses and panics in a circular buffer. Ramoops +needs a system with persistent RAM so that the content of that area can survive +after a restart.
+Ramoops uses a predefined memory area to store the dump.
+Ramoops parameters can be passed as kernel parameters or through Device Tree,
Please, add the node in image_setup_libfdt() as described in Linux's Documentation/device-tree/bindings/reserved-memory/admin-guide/ramoops.rst.
+i.e.::
- ramoops.mem_address=0x30000000 ramoops.mem_size=0x100000 ramoops.record_size=0x2000 ramoops.console_size=0x2000 memmap=0x100000$0x30000000
Using the command line seems to be rather error prone.
+The same values should be set in U-Boot to be able to retrieve the records. +This values can be set at build time in U-Boot configuration file, or at runtime.
+The PStore configuration parameters are:
+======================= =======
- Name Default
+======================= ======= +CMD_PSTORE_ADDR 0x0 +CMD_PSTORE_SIZE 0x0 +CMD_PSTORE_RECORD_SIZE 0x1000 +CMD_PSTORE_CONSOLE_SIZE 0x1000 +CMD_PSTORE_FTRACE_SIZE 0x1000 +CMD_PSTORE_PMSG_SIZE 0x1000 +CMD_PSTORE_ECC_SIZE 0 +======================= =======
Please, describe the requirements on CMD_PSTORE_SIZE. I would assume that is has to be larger than the sum of the other sizes.
+Records sizes should be a power of 2.
Please, mention:
The memory size and the record/console size must be non-zero.
Best regards
Heinrich
+Usage +-----
+Generate kernel crash +~~~~~~~~~~~~~~~~~~~~~
+For test purpose, you can generate a kernel crash by setting reboot timeout to +10 seconds and trigger a panic::
- $ sudo sh -c "echo 1 > /proc/sys/kernel/sysrq"
- $ sudo sh -c "echo 10 > /proc/sys/kernel/panic"
- $ sudo sh -c "echo c > /proc/sysrq-trigger"
+Retrieve logs in U-Boot +~~~~~~~~~~~~~~~~~~~~~~~
+First of all, unless PStore parameters as been set during U-Boot configuration +and match kernel ramoops parameters, it needs to be set using 'pstore set', e.g.::
- => pstore set 0x30000000 0x100000 0x2000 0x2000
+Then all available dumps can be displayed +using::
- => pstore display
+Or saved to an existing directory in an Ext2 or Ext4 partition, e.g. on root +directory of 1st partition of the 2nd MMC::
- => pstore save mmc 1:1 /