From 9aaf4e218dc47caaf93edafe9ec60efe3dc90fd6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 15 Mar 2019 10:14:39 +0100 Subject: ramoops: probe from device tree if OFTREE is enabled Switch to a device driver probed from device tree if CONFIG_OFTREE is enabled. Also switch from postcore_initcall to device_initcall, to make sure that memory banks have been initialized before request_sdram_region is called. Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fdd92a60a5..fe65959791 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -349,8 +349,9 @@ static int ramoops_init_prz(struct ramoops_context *cxt, return 0; } -static int ramoops_probe(struct ramoops_platform_data *pdata) +static int ramoops_probe(struct device_d *dev) { + struct ramoops_platform_data *pdata = dummy_data; struct ramoops_context *cxt = &oops_cxt; size_t dump_mem_sz; phys_addr_t paddr; @@ -498,12 +499,39 @@ static void ramoops_register_dummy(void) */ dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc; - ramoops_probe(dummy_data); + if (!IS_ENABLED(CONFIG_OFTREE)) + ramoops_probe(NULL); } +static const struct of_device_id ramoops_dt_ids[] = { + { .compatible = "ramoops" }, + { }, +}; + +static struct driver_d ramoops_driver = { + .name = "ramoops", + .probe = ramoops_probe, + .of_compatible = DRV_OF_COMPAT(ramoops_dt_ids), +}; + static int __init ramoops_init(void) { + if (IS_ENABLED(CONFIG_OFTREE)) { + struct device_node *node; + + node = of_get_root_node(); + if (!node) + return 0; + + node = of_get_child_by_name(node, "reserved-memory"); + if (!node) + return 0; + + for_each_matching_node(node, ramoops_dt_ids) + of_platform_device_create(node, NULL); + } + ramoops_register_dummy(); - return 0; + return platform_driver_register(&ramoops_driver); } -postcore_initcall(ramoops_init); +device_initcall(ramoops_init); -- cgit v1.2.3 From a327b29adca7fe634d257fb7793b02aada9c88af Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Fri, 15 Mar 2019 10:14:40 +0100 Subject: pstore/ram: add Device Tree bindings ramoops is one of the remaining places where ARM vendors still rely on board-specific shims. Device Tree lets us replace those shims with generic code. These bindings mirror the ramoops module parameters, with two small differences: (1) dump_oops becomes an optional "no-dump-oops" property, since ramoops sets dump_oops=1 by default. (2) mem_type=1 becomes the more self-explanatory "unbuffered" property. Signed-off-by: Greg Hackmann [fixed platform_get_drvdata() crash, thanks to Brian Norris] [switched from u64 to u32 to simplify code, various whitespace fixes] [use dev_of_node() to gain code-elimination for CONFIG_OF=n] Signed-off-by: Kees Cook [p.zabel@pengutronix.de: ported to Barebox from Linux commit 35da60941e44] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fe65959791..98c11e456d 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #define RAMOOPS_KERNMSG_HDR "====" #define MIN_MEM_SIZE 4096UL @@ -349,6 +351,74 @@ static int ramoops_init_prz(struct ramoops_context *cxt, return 0; } +static int ramoops_parse_dt_size(struct device_d *dev, + const char *propname, u32 *value) +{ + u32 val32 = 0; + int ret; + + ret = of_property_read_u32(dev->device_node, propname, &val32); + if (ret < 0 && ret != -EINVAL) { + dev_err(dev, "failed to parse property %s: %d\n", + propname, ret); + return ret; + } + + if (val32 > INT_MAX) { + dev_err(dev, "%s %u > INT_MAX\n", propname, val32); + return -EOVERFLOW; + } + + *value = val32; + return 0; +} + +static int ramoops_parse_dt(struct device_d *dev, + struct ramoops_platform_data *pdata) +{ + struct device_node *of_node = dev->device_node; + struct device_node *mem_region; + struct resource res; + u32 value; + int ret; + + mem_region = of_parse_phandle(of_node, "memory-region", 0); + if (!mem_region) { + dev_err(dev, "no memory-region phandle\n"); + return -ENODEV; + } + + ret = of_address_to_resource(mem_region, 0, &res); + if (ret) { + dev_err(dev, + "failed to translate memory-region to resource: %d\n", + ret); + return ret; + } + + pdata->mem_size = resource_size(&res); + pdata->mem_address = res.start; + pdata->mem_type = of_property_read_bool(of_node, "unbuffered"); + pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops"); + +#define parse_size(name, field) { \ + ret = ramoops_parse_dt_size(dev, name, &value); \ + if (ret < 0) \ + return ret; \ + field = value; \ + } + + parse_size("record-size", pdata->record_size); + parse_size("console-size", pdata->console_size); + parse_size("ftrace-size", pdata->ftrace_size); + parse_size("pmsg-size", pdata->pmsg_size); + parse_size("ecc-size", pdata->ecc_info.ecc_size); + +#undef parse_size + + return 0; +} + static int ramoops_probe(struct device_d *dev) { struct ramoops_platform_data *pdata = dummy_data; @@ -358,6 +428,18 @@ static int ramoops_probe(struct device_d *dev) int err = -EINVAL; char kernelargs[512]; + if (IS_ENABLED(CONFIG_OFTREE) && !pdata) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + err = -ENOMEM; + goto fail_out; + } + + err = ramoops_parse_dt(dev, pdata); + if (err < 0) + goto fail_out; + } + /* Only a single ramoops area allowed at a time, so fail extra * probes. */ @@ -473,6 +555,7 @@ fail_init_fprz: fail_init_cprz: ramoops_free_przs(cxt); fail_out: + kfree(pdata); return err; } unsigned long arm_mem_ramoops_get(void); -- cgit v1.2.3 From 08c0102474a3f3a0fc1934e4bb047154bcdfd525 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:41 +0100 Subject: ramoops: use DT reserved-memory bindings Instead of a ramoops-specific node, use a child node of /reserved-memory. This requires that of_platform_device_create() be explicitly called for the node, though, since "/reserved-memory" does not have its own "compatible" property. Suggested-by: Rob Herring Signed-off-by: Kees Cook Acked-by: Rob Herring [p.zabel@pengutronix.de: ported to Barebox from Linux commit 529182e204db] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 98c11e456d..8dc583ea86 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -377,27 +377,19 @@ static int ramoops_parse_dt(struct device_d *dev, struct ramoops_platform_data *pdata) { struct device_node *of_node = dev->device_node; - struct device_node *mem_region; - struct resource res; + struct resource *res; u32 value; int ret; - mem_region = of_parse_phandle(of_node, "memory-region", 0); - if (!mem_region) { - dev_err(dev, "no memory-region phandle\n"); - return -ENODEV; - } - - ret = of_address_to_resource(mem_region, 0, &res); - if (ret) { + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { dev_err(dev, - "failed to translate memory-region to resource: %d\n", - ret); - return ret; + "failed to locate DT /reserved-memory resource\n"); + return -EINVAL; } - pdata->mem_size = resource_size(&res); - pdata->mem_address = res.start; + pdata->mem_size = resource_size(res); + pdata->mem_address = res->start; pdata->mem_type = of_property_read_bool(of_node, "unbuffered"); pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops"); -- cgit v1.2.3 From 478035df0705687cf3cfbb32644f434353189672 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:42 +0100 Subject: pstore: Make ramoops_init_przs generic for other prz arrays Currently ramoops_init_przs() is hard wired only for panic dump zone array. In preparation for the ftrace zone array (one zone per-cpu) and pmsg zone array, make the function more generic to be able to handle this case. Heavily based on similar work from Joel Fernandes. Signed-off-by: Kees Cook [p.zabel@pengutronix.de: ported to Barebox from Linux commit de83209249d6] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 86 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 8dc583ea86..58422dda54 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -274,49 +274,78 @@ static void ramoops_free_przs(struct ramoops_context *cxt) kfree(cxt->przs); } -static int ramoops_init_przs(struct ramoops_context *cxt, phys_addr_t *paddr, - size_t dump_mem_sz) +static int ramoops_init_przs(struct ramoops_context *cxt, + struct persistent_ram_zone ***przs, + phys_addr_t *paddr, size_t mem_sz, + ssize_t record_size, + unsigned int *cnt, u32 sig, u32 flags) { int err = -ENOMEM; int i; + size_t zone_sz; + struct persistent_ram_zone **prz_ar; - if (!cxt->record_size) + /* Allocate nothing for 0 mem_sz or 0 record_size. */ + if (mem_sz == 0 || record_size == 0) { + *cnt = 0; return 0; - - if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) { - pr_err("no room for dumps\n"); - return -ENOMEM; } - cxt->max_dump_cnt = dump_mem_sz / cxt->record_size; - if (!cxt->max_dump_cnt) - return -ENOMEM; + /* + * If we have a negative record size, calculate it based on + * mem_sz / *cnt. If we have a positive record size, calculate + * cnt from mem_sz / record_size. + */ + if (record_size < 0) { + if (*cnt == 0) + return 0; + record_size = mem_sz / *cnt; + if (record_size == 0) + goto fail; + } else { + *cnt = mem_sz / record_size; + if (*cnt == 0) + goto fail; + } - cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt, - GFP_KERNEL); - if (!cxt->przs) { - pr_err("failed to initialize a prz array for dumps\n"); - goto fail_prz; + if (*paddr + mem_sz - cxt->phys_addr > cxt->size) { + pr_err("no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", + mem_sz, (unsigned long long)*paddr, + cxt->size, (unsigned long long)cxt->phys_addr); + goto fail; } - for (i = 0; i < cxt->max_dump_cnt; i++) { - size_t sz = cxt->record_size; + zone_sz = mem_sz / *cnt; + if (!zone_sz) + goto fail; - cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, - &cxt->ecc_info, - cxt->memtype); - if (IS_ERR(cxt->przs[i])) { - err = PTR_ERR(cxt->przs[i]); + prz_ar = kcalloc(*cnt, sizeof(**przs), GFP_KERNEL); + if (!prz_ar) + goto fail; + + for (i = 0; i < *cnt; i++) { + prz_ar[i] = persistent_ram_new(*paddr, zone_sz, sig, + &cxt->ecc_info, cxt->memtype); + if (IS_ERR(prz_ar[i])) { + err = PTR_ERR(prz_ar[i]); pr_err("failed to request mem region (0x%zx@0x%llx): %d\n", - sz, (unsigned long long)*paddr, err); - goto fail_prz; + record_size, (unsigned long long)*paddr, err); + + while (i > 0) { + i--; + persistent_ram_free(prz_ar[i]); + } + kfree(prz_ar); + goto fail; } - *paddr += sz; + *paddr += zone_sz; } + *przs = prz_ar; return 0; -fail_prz: - ramoops_free_przs(cxt); + +fail: + *cnt = 0; return err; } @@ -468,7 +497,8 @@ static int ramoops_probe(struct device_d *dev) dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - cxt->pmsg_size; - err = ramoops_init_przs(cxt, &paddr, dump_mem_sz); + err = ramoops_init_przs(cxt, &cxt->przs, &paddr, dump_mem_sz, + cxt->record_size, &cxt->max_dump_cnt, 0, 0); if (err) goto fail_out; -- cgit v1.2.3 From 97885140bf64b43adee76e23179eae9bd1393296 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:43 +0100 Subject: pstore/ram: Do not use stack VLA for parity workspace Instead of using a stack VLA for the parity workspace, preallocate a memory region. The preallocation is done to keep from needing to perform allocations during crash dump writing, etc. This also fixes a missed release of librs on free. Signed-off-by: Kees Cook [p.zabel@pengutronix.de: ported to Barebox from Linux commit f2531f1976d9] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram_core.c | 28 +++++++++++++++++++++------- include/linux/pstore_ram.h | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 9de6dc614d..ed48dcddd5 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -80,24 +80,23 @@ static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, uint8_t *data, size_t len, uint8_t *ecc) { int i; - uint16_t par[prz->ecc_info.ecc_size]; /* Initialize the parity buffer */ - memset(par, 0, sizeof(par)); - encode_rs8(prz->rs_decoder, data, len, par, 0); + memset(prz->ecc_info.par, 0, + prz->ecc_info.ecc_size * sizeof(prz->ecc_info.par[0])); + encode_rs8(prz->rs_decoder, data, len, prz->ecc_info.par, 0); for (i = 0; i < prz->ecc_info.ecc_size; i++) - ecc[i] = par[i]; + ecc[i] = prz->ecc_info.par[i]; } static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz, void *data, size_t len, uint8_t *ecc) { int i; - uint16_t par[prz->ecc_info.ecc_size]; for (i = 0; i < prz->ecc_info.ecc_size; i++) - par[i] = ecc[i]; - return decode_rs8(prz->rs_decoder, data, par, len, + prz->ecc_info.par[i] = ecc[i]; + return decode_rs8(prz->rs_decoder, data, prz->ecc_info.par, len, NULL, 0, NULL, 0, NULL); } @@ -210,6 +209,15 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, return -EINVAL; } + /* allocate workspace instead of using stack VLA */ + prz->ecc_info.par = kmalloc_array(prz->ecc_info.ecc_size, + sizeof(*prz->ecc_info.par), + GFP_KERNEL); + if (!prz->ecc_info.par) { + pr_err("cannot allocate ECC parity workspace\n"); + return -ENOMEM; + } + prz->corrected_bytes = 0; prz->bad_blocks = 0; @@ -393,6 +401,12 @@ void persistent_ram_free(struct persistent_ram_zone *prz) release_sdram_region(prz->res); prz->res = NULL; } + if (prz->rs_decoder) { + free_rs(prz->rs_decoder); + prz->rs_decoder = NULL; + } + kfree(prz->ecc_info.par); + prz->ecc_info.par = NULL; persistent_ram_free_old(prz); kfree(prz); diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 5ef823a57b..ecdd229dd4 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -29,6 +29,7 @@ struct persistent_ram_ecc_info { int ecc_size; int symsize; int poly; + uint16_t *par; }; struct persistent_ram_zone { -- cgit v1.2.3 From f620beeb9af83fd6b60b7a0126e677a38d0205a1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:44 +0100 Subject: pstore: improve error report for failed setup When setting ramoops record sizes, sometimes it's not clear which parameters contributed to the allocation failure. This adds a per-zone name and expands the failure reports. Signed-off-by: Kees Cook [p.zabel@pengutronix.de: ported to Barebox from Linux commit c443a5f3f1f1] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 58422dda54..d46612fbff 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -274,7 +274,8 @@ static void ramoops_free_przs(struct ramoops_context *cxt) kfree(cxt->przs); } -static int ramoops_init_przs(struct ramoops_context *cxt, +static int ramoops_init_przs(const char *name, + struct ramoops_context *cxt, struct persistent_ram_zone ***przs, phys_addr_t *paddr, size_t mem_sz, ssize_t record_size, @@ -300,24 +301,33 @@ static int ramoops_init_przs(struct ramoops_context *cxt, if (*cnt == 0) return 0; record_size = mem_sz / *cnt; - if (record_size == 0) + if (record_size == 0) { + pr_err("%s record size == 0 (%zu / %u)\n", + name, mem_sz, *cnt); goto fail; + } } else { *cnt = mem_sz / record_size; - if (*cnt == 0) + if (*cnt == 0) { + pr_err("%s record count == 0 (%zu / %zu)\n", + name, mem_sz, record_size); goto fail; + } } if (*paddr + mem_sz - cxt->phys_addr > cxt->size) { - pr_err("no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", + pr_err("no room for %s mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", + name, mem_sz, (unsigned long long)*paddr, cxt->size, (unsigned long long)cxt->phys_addr); goto fail; } zone_sz = mem_sz / *cnt; - if (!zone_sz) + if (!zone_sz) { + pr_err("%s zone size == 0\n", name); goto fail; + } prz_ar = kcalloc(*cnt, sizeof(**przs), GFP_KERNEL); if (!prz_ar) @@ -328,8 +338,9 @@ static int ramoops_init_przs(struct ramoops_context *cxt, &cxt->ecc_info, cxt->memtype); if (IS_ERR(prz_ar[i])) { err = PTR_ERR(prz_ar[i]); - pr_err("failed to request mem region (0x%zx@0x%llx): %d\n", - record_size, (unsigned long long)*paddr, err); + pr_err("failed to request %s mem region (0x%zx@0x%llx): %d\n", + name, record_size, + (unsigned long long)*paddr, err); while (i > 0) { i--; @@ -349,7 +360,8 @@ fail: return err; } -static int ramoops_init_prz(struct ramoops_context *cxt, +static int ramoops_init_prz(const char *name, + struct ramoops_context *cxt, struct persistent_ram_zone **prz, phys_addr_t *paddr, size_t sz, u32 sig) { @@ -357,8 +369,8 @@ static int ramoops_init_prz(struct ramoops_context *cxt, return 0; if (*paddr + sz - cxt->phys_addr > cxt->size) { - pr_err("no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", - sz, (unsigned long long)*paddr, + pr_err("no room for %s mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", + name, sz, (unsigned long long)*paddr, cxt->size, (unsigned long long)cxt->phys_addr); return -ENOMEM; } @@ -368,8 +380,8 @@ static int ramoops_init_prz(struct ramoops_context *cxt, if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); - pr_err("failed to request mem region (0x%zx@0x%llx): %d\n", - sz, (unsigned long long)*paddr, err); + pr_err("failed to request %s mem region (0x%zx@0x%llx): %d\n", + name, sz, (unsigned long long)*paddr, err); return err; } @@ -497,21 +509,24 @@ static int ramoops_probe(struct device_d *dev) dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - cxt->pmsg_size; - err = ramoops_init_przs(cxt, &cxt->przs, &paddr, dump_mem_sz, - cxt->record_size, &cxt->max_dump_cnt, 0, 0); + err = ramoops_init_przs("dump", cxt, &cxt->przs, &paddr, + dump_mem_sz, cxt->record_size, + &cxt->max_dump_cnt, 0, 0); if (err) goto fail_out; - err = ramoops_init_prz(cxt, &cxt->cprz, &paddr, + err = ramoops_init_prz("console", cxt, &cxt->cprz, &paddr, cxt->console_size, 0); if (err) goto fail_init_cprz; - err = ramoops_init_prz(cxt, &cxt->fprz, &paddr, cxt->ftrace_size, 0); + err = ramoops_init_prz("ftrace", cxt, &cxt->fprz, &paddr, + cxt->ftrace_size, 0); if (err) goto fail_init_fprz; - err = ramoops_init_prz(cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0); + err = ramoops_init_prz("pmsg", cxt, &cxt->mprz, &paddr, + cxt->pmsg_size, 0); if (err) goto fail_init_mprz; -- cgit v1.2.3 From 34e46e5863fbf24af9b81bf5330d7301c9f58260 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:45 +0100 Subject: pstore/ram: Clarify resource reservation labels When ramoops reserved a memory region in the kernel, it had an unhelpful label of "persistent ram". When reading iomem, it would be repeated many times, did not hint that it was ramoops in particular, and didn't clarify very much about what each was used for: 0x4fdd4000 - 0x4fdf3fff (size 0x00020000) persistent ram 0x4fdf4000 - 0x4fe13fff (size 0x00020000) persistent ram ... 0x4ff74000 - 0x4ff93fff (size 0x00020000) persistent ram 0x4ff94000 - 0x4ffb3fff (size 0x00020000) persistent ram 0x4ffb4000 - 0x4ffd3fff (size 0x00020000) persistent ram Instead, this adds meaningful labels for how the various regions are being used: 0x4fdd4000 - 0x4fdf3fff (size 0x00020000) ramoops:dump(0/12) 0x4fdf4000 - 0x4fe13fff (size 0x00020000) ramoops:dump(1/12) ... 0x4ff74000 - 0x4ff93fff (size 0x00020000) ramoops:console 0x4ff94000 - 0x4ffb3fff (size 0x00020000) ramoops:ftrace 0x4ffb4000 - 0x4ffd3fff (size 0x00020000) ramoops:pmsg Signed-off-by: Kees Cook Reviewed-by: Joel Fernandes (Google) [p.zabel@pengutronix.de: ported to Barebox from Linux commit 1227daa43bce] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- Documentation/filesystems/pstore.rst | 44 ++++++++++++++++-------------------- fs/pstore/ram.c | 15 ++++++++++-- fs/pstore/ram_core.c | 8 +++++-- include/linux/pstore_ram.h | 3 ++- 4 files changed, 40 insertions(+), 30 deletions(-) (limited to 'fs') diff --git a/Documentation/filesystems/pstore.rst b/Documentation/filesystems/pstore.rst index 22e89b3f1f..6215f2296c 100644 --- a/Documentation/filesystems/pstore.rst +++ b/Documentation/filesystems/pstore.rst @@ -47,35 +47,29 @@ generated by Barebox. You can change these parameters in Barebox menuconfig. The RAMOOPS parameters for the Kernel are stored in the variable global.linux.bootargs.ramoops. -To see where the RAMOOPS area is located, you can execute iomem in Barebox. The -RAMOOPS area is listed as 'persistent ram': +You can adapt the *pstore* parameters in Barebox menuconfig. + +To see where the RAMOOPS area is located, you can execute the ``iomem`` command +in the Barebox shell. The RAMOOPS area is listed as 'persistent ram': .. code-block:: none 0x10000000 - 0x1fffffff (size 0x10000000) ram0 - 0x17e7c0c0 - 0x1fcf817f (size 0x07e7c0c0) malloc space - 0x1fcf8180 - 0x1fcfffff (size 0x00007e80) board data - 0x1fd00000 - 0x1fd6eeff (size 0x0006ef00) barebox - 0x1fd6ef00 - 0x1fd88dff (size 0x00019f00) barebox data - 0x1fd88e00 - 0x1fd8c3db (size 0x000035dc) bss - 0x1fdf4000 - 0x1fe13fff (size 0x00020000) persistent ram - 0x1fe14000 - 0x1fe33fff (size 0x00020000) persistent ram - 0x1fe34000 - 0x1fe53fff (size 0x00020000) persistent ram - 0x1fe54000 - 0x1fe73fff (size 0x00020000) persistent ram - 0x1fe74000 - 0x1fe93fff (size 0x00020000) persistent ram - 0x1fe94000 - 0x1feb3fff (size 0x00020000) persistent ram - 0x1feb4000 - 0x1fed3fff (size 0x00020000) persistent ram - 0x1fed4000 - 0x1fef3fff (size 0x00020000) persistent ram - 0x1fef4000 - 0x1ff13fff (size 0x00020000) persistent ram - 0x1ff14000 - 0x1ff33fff (size 0x00020000) persistent ram - 0x1ff34000 - 0x1ff53fff (size 0x00020000) persistent ram - 0x1ff54000 - 0x1ff73fff (size 0x00020000) persistent ram - 0x1ff74000 - 0x1ff93fff (size 0x00020000) persistent ram - 0x1ff94000 - 0x1ffb3fff (size 0x00020000) persistent ram - 0x1ffb4000 - 0x1ffd3fff (size 0x00020000) persistent ram - 0x1ffd4000 - 0x1fff3fff (size 0x00020000) persistent ram - 0x1fff4000 - 0x1fff7fff (size 0x00004000) ttb - 0x1fff8000 - 0x1fffffff (size 0x00008000) stack + 0x247f59c0 - 0x2fbf59bf (size 0x0b400000) malloc space + 0x2fbf59c0 - 0x2fbffffe (size 0x0000a63f) board data + 0x2fc00000 - 0x2fc8619f (size 0x000861a0) barebox + 0x2fc861a0 - 0x2fca35ef (size 0x0001d450) barebox data + 0x2fca35f0 - 0x2fca9007 (size 0x00005a18) bss + 0x2fdd4000 - 0x2fdf3fff (size 0x00020000) ramoops:dump(0/4) + 0x2fdf4000 - 0x2fe13fff (size 0x00020000) ramoops:dump(1/4) + 0x2fe14000 - 0x2fe33fff (size 0x00020000) ramoops:dump(2/4) + 0x2fe34000 - 0x2fe53fff (size 0x00020000) ramoops:dump(3/4) + 0x2fe54000 - 0x2fe73fff (size 0x00020000) ramoops:dump(4/4) + 0x2fe74000 - 0x2fe93fff (size 0x00020000) ramoops:console + 0x2fe94000 - 0x2feb3fff (size 0x00020000) ramoops:ftrace + 0x2feb4000 - 0x2fed3fff (size 0x00020000) ramoops:pmsg + 0x2fee4000 - 0x2fee7fff (size 0x00004000) ttb + 0x2fee8000 - 0x2feeffff (size 0x00008000) stack All pstore files that could be found are added to the /pstore directory. This is a read-only filesystem. If you disable the Kconfig option FS_PSTORE_RAMOOPS_RO, diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index d46612fbff..714755bd66 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -334,8 +334,16 @@ static int ramoops_init_przs(const char *name, goto fail; for (i = 0; i < *cnt; i++) { + char *label; + + if (*cnt == 1) + label = basprintf("ramoops:%s", name); + else + label = basprintf("ramoops:%s(%d/%d)", + name, i, *cnt - 1); prz_ar[i] = persistent_ram_new(*paddr, zone_sz, sig, - &cxt->ecc_info, cxt->memtype); + &cxt->ecc_info, + cxt->memtype, label); if (IS_ERR(prz_ar[i])) { err = PTR_ERR(prz_ar[i]); pr_err("failed to request %s mem region (0x%zx@0x%llx): %d\n", @@ -365,6 +373,8 @@ static int ramoops_init_prz(const char *name, struct persistent_ram_zone **prz, phys_addr_t *paddr, size_t sz, u32 sig) { + char *label; + if (!sz) return 0; @@ -375,8 +385,9 @@ static int ramoops_init_prz(const char *name, return -ENOMEM; } + label = basprintf("ramoops:%s", name); *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, - cxt->memtype); + cxt->memtype, label); if (IS_ERR(*prz)) { int err = PTR_ERR(*prz); diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index ed48dcddd5..0f7003f937 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -346,7 +346,7 @@ void persistent_ram_zap(struct persistent_ram_zone *prz) static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, struct persistent_ram_zone *prz, int memtype) { - prz->res = request_sdram_region("persistent ram", start, size); + prz->res = request_sdram_region(prz->label ?: "ramoops", start, size); if (!prz->res) return -ENOMEM; @@ -409,12 +409,13 @@ void persistent_ram_free(struct persistent_ram_zone *prz) prz->ecc_info.par = NULL; persistent_ram_free_old(prz); + kfree(prz->label); kfree(prz); } struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, u32 sig, struct persistent_ram_ecc_info *ecc_info, - unsigned int memtype) + unsigned int memtype, char *label) { struct persistent_ram_zone *prz; int ret = -ENOMEM; @@ -425,6 +426,9 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, goto err; } + /* Initialize general buffer state. */ + prz->label = label; + ret = persistent_ram_buffer_map(start, size, prz, memtype); if (ret) goto err; diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index ecdd229dd4..de6eaa93f9 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -35,6 +35,7 @@ struct persistent_ram_ecc_info { struct persistent_ram_zone { phys_addr_t paddr; size_t size; + char *label; struct persistent_ram_buffer *buffer; size_t buffer_size; struct resource *res; @@ -53,7 +54,7 @@ struct persistent_ram_zone { struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, u32 sig, struct persistent_ram_ecc_info *ecc_info, - unsigned int memtype); + unsigned int memtype, char *label); void persistent_ram_free(struct persistent_ram_zone *prz); void persistent_ram_zap(struct persistent_ram_zone *prz); -- cgit v1.2.3 From 114d41b69c1e0715fe09b2234559f545eb7721bf Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:46 +0100 Subject: pstore: Extract common arguments into structure The read/mkfile pair pass the same arguments and should be cleared between calls. Move to a structure and wipe it after every loop. Signed-off-by: Kees Cook [p.zabel@pengutronix.de: ported to Barebox from Linux commit 9abdcccc3d5f] Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/platform.c | 30 +++++++++++++++++------------- include/linux/pstore.h | 15 ++++++++++++++- 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 963ecafef8..6eebad63de 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -96,13 +96,8 @@ EXPORT_SYMBOL_GPL(pstore_register); void pstore_get_records(int quiet) { struct pstore_info *psi = psinfo; - char *buf = NULL; - ssize_t size; - u64 id; - int count; - enum pstore_type_id type; + struct pstore_record record = { .psi = psi, }; int failed = 0, rc; - bool compressed; int unzipped_len = -1; if (!psi) @@ -112,22 +107,31 @@ void pstore_get_records(int quiet) if (psi->open && psi->open(psi)) goto out; - while ((size = psi->read(&id, &type, &count, &buf, &compressed, - psi)) > 0) { - if (compressed && (type == PSTORE_TYPE_DMESG)) { + while ((record.size = psi->read(&record.id, &record.type, + &record.count, + &record.buf, &record.compressed, + record.psi)) > 0) { + if (record.compressed && + record.type == PSTORE_TYPE_DMESG) { pr_err("barebox does not have ramoops compression support\n"); continue; } - rc = pstore_mkfile(type, psi->name, id, count, buf, - compressed, (size_t)size, psi); + rc = pstore_mkfile(record.type, psi->name, record.id, + record.count, record.buf, + record.compressed, + record.size, + record.psi); if (unzipped_len < 0) { /* Free buffer other than big oops */ - kfree(buf); - buf = NULL; + kfree(record.buf); + record.buf = NULL; } else unzipped_len = -1; if (rc && (rc != -EEXIST || !quiet)) failed++; + + memset(&record, 0, sizeof(record)); + record.psi = psi; } if (psi->close) psi->close(psi); diff --git a/include/linux/pstore.h b/include/linux/pstore.h index a925e14397..23f35570aa 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -25,6 +25,8 @@ #include #include +struct module; + /* types */ enum pstore_type_id { PSTORE_TYPE_DMESG = 0, @@ -43,7 +45,18 @@ enum kmsg_dump_reason { KMSG_DUMP_UNDEF, }; -struct module; +struct pstore_info; + +struct pstore_record { + struct pstore_info *psi; + enum pstore_type_id type; + u64 id; + char *buf; + int count; + bool compressed; + ssize_t size; + ssize_t ecc_notice_size; +}; struct pstore_info { struct module *owner; -- cgit v1.2.3 From 6906ffb57888c99024f4ff2257c2fd2e50058240 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 15 Mar 2019 10:14:47 +0100 Subject: pstore: add console support Add support for writing console messages to pstore. Signed-off-by: Philipp Zabel Documentation-added-by: Juergen Borleis Signed-off-by: Sascha Hauer --- Documentation/filesystems/pstore.rst | 4 ++ fs/pstore/Kconfig | 6 +++ fs/pstore/platform.c | 74 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) (limited to 'fs') diff --git a/Documentation/filesystems/pstore.rst b/Documentation/filesystems/pstore.rst index 6215f2296c..c128daae9f 100644 --- a/Documentation/filesystems/pstore.rst +++ b/Documentation/filesystems/pstore.rst @@ -75,3 +75,7 @@ All pstore files that could be found are added to the /pstore directory. This is a read-only filesystem. If you disable the Kconfig option FS_PSTORE_RAMOOPS_RO, the RAMOOPS area is reset and its ECC recalculated. But that does not allow any writes from Barebox into that area. + +If the menu entry ``FS_PSTORE_CONSOLE`` is enabled, Barebox itself will add all +its own console output to the *ramoops:console* part, which enables the regular +userland later on to have access to the bootloaders output. diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 0e042cb162..30c2de19c8 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -8,6 +8,12 @@ menuconfig FS_PSTORE if FS_PSTORE +config FS_PSTORE_CONSOLE + bool + prompt "Log console messages" + help + When the option is enabled, pstore will log console messages. + config FS_PSTORE_RAMOOPS bool depends on RELOCATABLE diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 6eebad63de..5d0018693b 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,77 @@ void pstore_set_kmsg_bytes(int bytes) kmsg_bytes = bytes; } +#ifdef CONFIG_FS_PSTORE_CONSOLE +static void pstore_console_write(const char *s, unsigned c) +{ + const char *e = s + c; + + while (s < e) { + struct pstore_record record = { + .type = PSTORE_TYPE_CONSOLE, + .psi = psinfo, + }; + + if (c > psinfo->bufsize) + c = psinfo->bufsize; + + record.buf = (char *)s; + record.size = c; + psinfo->write_buf(PSTORE_TYPE_CONSOLE, 0, &record.id, 0, + record.buf, 0, record.size, psinfo); + s += c; + c = e - s; + } +} + +static int pstore_console_puts(struct console_device *cdev, const char *s) +{ + pstore_console_write(s, strlen(s)); + return strlen(s); +} + +static void pstore_console_putc(struct console_device *cdev, char c) +{ + const char s[1] = { c }; + + pstore_console_write(s, 1); +} + +static void pstore_console_capture_log(void) +{ + struct log_entry *log; + + list_for_each_entry(log, &barebox_logbuf, list) + pstore_console_write(log->msg, strlen(log->msg)); +} + +static struct console_device *pstore_cdev; + +static void pstore_register_console(void) +{ + struct console_device *cdev; + int ret; + + cdev = xzalloc(sizeof(struct console_device)); + pstore_cdev = cdev; + + cdev->puts = pstore_console_puts; + cdev->putc = pstore_console_putc; + cdev->devname = "pstore"; + cdev->devid = DEVICE_ID_SINGLE; + + ret = console_register(cdev); + if (ret) + pr_err("registering failed with %s\n", strerror(-ret)); + + pstore_console_capture_log(); + + console_set_active(pstore_cdev, CONSOLE_STDOUT); +} +#else +static void pstore_register_console(void) {} +#endif + static int pstore_write_compat(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, @@ -81,6 +153,8 @@ int pstore_register(struct pstore_info *psi) pstore_get_records(0); + pstore_register_console(); + pr_info("Registered %s as persistent store backend\n", psi->name); return 0; -- cgit v1.2.3 From ac960f1d6e51d7462e4f36a37ef4bc9e7f6db904 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:48 +0100 Subject: pstore: Switch pstore_mkfile to pass record Instead of the long list of arguments, just pass the new record struct. Signed-off-by: Kees Cook Signed-off-by: Sascha Hauer --- fs/pstore/fs.c | 45 ++++++++++++++++++++++++--------------------- fs/pstore/internal.h | 4 +--- fs/pstore/platform.c | 6 +----- 3 files changed, 26 insertions(+), 29 deletions(-) (limited to 'fs') diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c index 9a7e0b5526..e9c7ae7adb 100644 --- a/fs/pstore/fs.c +++ b/fs/pstore/fs.c @@ -52,68 +52,71 @@ struct pstore_private { * Load it up with "size" bytes of data from "buf". * Set the mtime & ctime to the date that this record was originally stored. */ -int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, - char *data, bool compressed, size_t size, - struct pstore_info *psi) +int pstore_mkfile(struct pstore_record *record) { struct pstore_private *private, *pos; + size_t size = record->size; list_for_each_entry(pos, &allpstore, list) { - if (pos->type == type && pos->id == id && pos->psi == psi) + if (pos->type == record->type && + pos->id == record->id && + pos->psi == record->psi) return -EEXIST; } private = xzalloc(sizeof(*private) + size); - private->type = type; - private->id = id; - private->count = count; - private->psi = psi; + private->type = record->type; + private->id = record->id; + private->count = record->count; + private->psi = record->psi; - switch (type) { + switch (record->type) { case PSTORE_TYPE_DMESG: scnprintf(private->name, sizeof(private->name), - "dmesg-%s-%lld%s", psname, id, - compressed ? ".enc.z" : ""); + "dmesg-%s-%lld%s", record->psi->name, record->id, + record->compressed ? ".enc.z" : ""); break; case PSTORE_TYPE_CONSOLE: scnprintf(private->name, sizeof(private->name), - "console-%s-%lld", psname, id); + "console-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_FTRACE: scnprintf(private->name, sizeof(private->name), - "ftrace-%s-%lld", psname, id); + "ftrace-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_MCE: scnprintf(private->name, sizeof(private->name), - "mce-%s-%lld", psname, id); + "mce-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_PPC_RTAS: scnprintf(private->name, sizeof(private->name), - "rtas-%s-%lld", psname, id); + "rtas-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_PPC_OF: scnprintf(private->name, sizeof(private->name), - "powerpc-ofw-%s-%lld", psname, id); + "powerpc-ofw-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_PPC_COMMON: scnprintf(private->name, sizeof(private->name), - "powerpc-common-%s-%lld", psname, id); + "powerpc-common-%s-%lld", record->psi->name, + record->id); break; case PSTORE_TYPE_PMSG: scnprintf(private->name, sizeof(private->name), - "pmsg-%s-%lld", psname, id); + "pmsg-%s-%lld", record->psi->name, record->id); break; case PSTORE_TYPE_UNKNOWN: scnprintf(private->name, sizeof(private->name), - "unknown-%s-%lld", psname, id); + "unknown-%s-%lld", record->psi->name, record->id); break; default: scnprintf(private->name, sizeof(private->name), - "type%d-%s-%lld", type, psname, id); + "type%d-%s-%lld", record->type, record->psi->name, + record->id); break; } - memcpy(private->data, data, size); + memcpy(private->data, record->buf, size); private->size = size; list_add(&private->list, &allpstore); diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 0a8df1f4e2..6b507e4bd3 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -11,9 +11,7 @@ extern struct pstore_info *psinfo; extern void pstore_set_kmsg_bytes(int); extern void pstore_get_records(int); -extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, - int count, char *data, bool compressed, - size_t size, struct pstore_info *psi); +extern int pstore_mkfile(struct pstore_record *record); extern int pstore_is_mounted(void); #endif diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 5d0018693b..bad735e574 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -190,11 +190,7 @@ void pstore_get_records(int quiet) pr_err("barebox does not have ramoops compression support\n"); continue; } - rc = pstore_mkfile(record.type, psi->name, record.id, - record.count, record.buf, - record.compressed, - record.size, - record.psi); + rc = pstore_mkfile(&record); if (unzipped_len < 0) { /* Free buffer other than big oops */ kfree(record.buf); -- cgit v1.2.3 From cdce7a569c947878708695bcdc383dbcc192c099 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:49 +0100 Subject: pstore: Replace arguments for read() API The argument list for the pstore_read() interface is unwieldy. This changes passes the new struct pstore_record instead. The erst backend was already doing something similar internally. Signed-off-by: Kees Cook Signed-off-by: Sascha Hauer --- fs/pstore/platform.c | 5 +---- fs/pstore/ram.c | 29 +++++++++++++++++------------ include/linux/pstore.h | 4 +--- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'fs') diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index bad735e574..54fe60bf88 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -181,10 +181,7 @@ void pstore_get_records(int quiet) if (psi->open && psi->open(psi)) goto out; - while ((record.size = psi->read(&record.id, &record.type, - &record.count, - &record.buf, &record.compressed, - record.psi)) > 0) { + while ((record.size = psi->read(&record)) > 0) { if (record.compressed && record.type == PSTORE_TYPE_DMESG) { pr_err("barebox does not have ramoops compression support\n"); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 714755bd66..fcf6b3087c 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -128,27 +128,32 @@ static bool prz_ok(struct persistent_ram_zone *prz) persistent_ram_ecc_string(prz, NULL, 0)); } -static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, - int *count, char **buf, bool *compressed, - struct pstore_info *psi) +static ssize_t ramoops_pstore_read(struct pstore_record *record) { ssize_t size; ssize_t ecc_notice_size; - struct ramoops_context *cxt = psi->data; + struct ramoops_context *cxt = record->psi->data; struct persistent_ram_zone *prz; + record->compressed = false; + prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, - cxt->max_dump_cnt, id, type, + cxt->max_dump_cnt, &record->id, + &record->type, PSTORE_TYPE_DMESG, 0); if (!prz_ok(prz)) prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, - 1, id, type, PSTORE_TYPE_CONSOLE, 0); + 1, &record->id, &record->type, + PSTORE_TYPE_CONSOLE, 0); + if (!prz_ok(prz)) prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, - 1, id, type, PSTORE_TYPE_FTRACE, 0); + 1, &record->id, &record->type, + PSTORE_TYPE_FTRACE, 0); if (!prz_ok(prz)) prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt, - 1, id, type, PSTORE_TYPE_PMSG, 0); + 1, &record->id, &record->type, + PSTORE_TYPE_PMSG, 0); if (!prz_ok(prz)) return 0; @@ -160,12 +165,12 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, /* ECC correction notice */ ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0); - *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL); - if (*buf == NULL) + record->buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL); + if (record->buf == NULL) return -ENOMEM; - memcpy(*buf, (char *)persistent_ram_old(prz), size); - persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1); + memcpy(record->buf, (char *)persistent_ram_old(prz), size); + persistent_ram_ecc_string(prz, record->buf + size, ecc_notice_size + 1); return size + ecc_notice_size; } diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 23f35570aa..b136c354b9 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -66,9 +66,7 @@ struct pstore_info { int flags; int (*open)(struct pstore_info *psi); int (*close)(struct pstore_info *psi); - ssize_t (*read)(u64 *id, enum pstore_type_id *type, - int *count, char **buf, bool *compressed, - struct pstore_info *psi); + ssize_t (*read)(struct pstore_record *record); int (*write)(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, bool compressed, -- cgit v1.2.3 From da9b86ec0fbec0eb60646e7a3c700076a423717d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Mar 2019 10:14:50 +0100 Subject: pstore: Replace arguments for write() API Similar to the pstore_info read() callback, there were too many arguments. This switches to the new struct pstore_record pointer instead. This adds "reason" and "part" to the record structure as well. Signed-off-by: Kees Cook Signed-off-by: Sascha Hauer --- fs/pstore/platform.c | 12 +++++------- include/linux/pstore.h | 12 ++++++------ 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 54fe60bf88..755363c309 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -115,14 +115,12 @@ static void pstore_register_console(void) static void pstore_register_console(void) {} #endif -static int pstore_write_compat(enum pstore_type_id type, - enum kmsg_dump_reason reason, - u64 *id, unsigned int part, int count, - bool compressed, size_t size, - struct pstore_info *psi) +static int pstore_write_compat(struct pstore_record *record) { - return psi->write_buf(type, reason, id, part, psinfo->buf, compressed, - size, psi); + return record->psi->write_buf(record->type, record->reason, + &record->id, record->part, + psinfo->buf, record->compressed, + record->size, record->psi); } /* diff --git a/include/linux/pstore.h b/include/linux/pstore.h index b136c354b9..15e1e3d6fa 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -52,10 +52,13 @@ struct pstore_record { enum pstore_type_id type; u64 id; char *buf; - int count; - bool compressed; ssize_t size; ssize_t ecc_notice_size; + + int count; + enum kmsg_dump_reason reason; + unsigned int part; + bool compressed; }; struct pstore_info { @@ -67,10 +70,7 @@ struct pstore_info { int (*open)(struct pstore_info *psi); int (*close)(struct pstore_info *psi); ssize_t (*read)(struct pstore_record *record); - int (*write)(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, int count, bool compressed, - size_t size, struct pstore_info *psi); + int (*write)(struct pstore_record *record); int (*write_buf)(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, const char *buf, bool compressed, -- cgit v1.2.3 From af85a0f8864e5888406bb13c3e3f99c5770959ca Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 15 Mar 2019 10:14:51 +0100 Subject: pstore: pass ramoops configuration to kernel via device tree Instead of setting ramoops module parameters on the kernel command line, add a /reserved-memory/ramoops node to the device tree via of_fixup. Signed-off-by: Philipp Zabel Documentation-added-by: Juergen Borleis Signed-off-by: Sascha Hauer --- Documentation/filesystems/pstore.rst | 10 ++-- fs/pstore/ram.c | 98 +++++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 22 deletions(-) (limited to 'fs') diff --git a/Documentation/filesystems/pstore.rst b/Documentation/filesystems/pstore.rst index c128daae9f..00a5a05537 100644 --- a/Documentation/filesystems/pstore.rst +++ b/Documentation/filesystems/pstore.rst @@ -42,10 +42,12 @@ written): To use pstore/RAMOOPS both Barebox and Kernel have to be compiled with pstore and RAM backend support. The kernel receives the parameters describing the -layout over the kernel command line. These parameters are automatically -generated by Barebox. You can change these parameters in Barebox menuconfig. The -RAMOOPS parameters for the Kernel are stored in the variable -global.linux.bootargs.ramoops. +layout via devicetree or - as a fallback - over the kernel command line. +To ensure both worlds are using the same memory layout, the required +configuration data for the kernel is generated on-the-fly prior booting a kernel. +For the devicetree use case Barebox adapts the kernel's devicetree, for the +kernel command line fallback the variable ``global.linux.bootargs.ramoops`` is +created and its content used to build the kernel command line. You can adapt the *pstore* parameters in Barebox menuconfig. diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fcf6b3087c..3daec0d0d8 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -468,6 +468,66 @@ static int ramoops_parse_dt(struct device_d *dev, return 0; } +static int ramoops_of_fixup(struct device_node *root, void *data) +{ + struct ramoops_platform_data *pdata = data; + struct device_node *node; + u32 reg[2]; + int ret; + + node = of_get_child_by_name(root, "reserved-memory"); + if (!node) { + pr_info("Adding reserved-memory node\n"); + node = of_create_node(root, "/reserved-memory"); + if (!node) + return -ENOMEM; + + of_property_write_u32(node, "#address-cells", 1); + of_property_write_u32(node, "#size-cells", 1); + of_new_property(node, "ranges", NULL, 0); + } + + node = of_get_child_by_name(node, "ramoops"); + if (!node) { + pr_info("Adding ramoops node\n"); + node = of_create_node(root, "/reserved-memory/ramoops"); + if (!node) + return -ENOMEM; + } + + ret = of_property_write_string(node, "compatible", "ramoops"); + if (ret) + return ret; + reg[0] = pdata->mem_address; + reg[1] = pdata->mem_size; + ret = of_property_write_u32_array(node, "reg", reg, 2); + if (ret) + return ret; + + ret = of_property_write_bool(node, "unbuffered", pdata->mem_type); + if (ret) + return ret; + ret = of_property_write_bool(node, "no-dump-oops", !pdata->dump_oops); + if (ret) + return ret; + +#define store_size(name, field) { \ + ret = of_property_write_u32(node, name, field); \ + if (ret < 0) \ + return ret; \ + } + + store_size("record-size", pdata->record_size); + store_size("console-size", pdata->console_size); + store_size("ftrace-size", pdata->ftrace_size); + store_size("pmsg-size", pdata->pmsg_size); + store_size("ecc-size", pdata->ecc_info.ecc_size); + +#undef store_size + + return 0; +} + static int ramoops_probe(struct device_d *dev) { struct ramoops_platform_data *pdata = dummy_data; @@ -574,25 +634,27 @@ static int ramoops_probe(struct device_d *dev) cxt->size, (unsigned long long)cxt->phys_addr, cxt->ecc_info.ecc_size, cxt->ecc_info.block_size); - scnprintf(kernelargs, sizeof(kernelargs), - "ramoops.record_size=0x%x " - "ramoops.console_size=0x%x " - "ramoops.ftrace_size=0x%x " - "ramoops.pmsg_size=0x%x " - "ramoops.mem_address=0x%llx " - "ramoops.mem_size=0x%lx " - "ramoops.ecc=%d", - cxt->record_size, - cxt->console_size, - cxt->ftrace_size, - cxt->pmsg_size, - (unsigned long long)cxt->phys_addr, - mem_size, - ramoops_ecc); - globalvar_add_simple("linux.bootargs.ramoops", kernelargs); - - if (IS_ENABLED(CONFIG_OFTREE)) + if (!IS_ENABLED(CONFIG_OFTREE)) { + scnprintf(kernelargs, sizeof(kernelargs), + "ramoops.record_size=0x%x " + "ramoops.console_size=0x%x " + "ramoops.ftrace_size=0x%x " + "ramoops.pmsg_size=0x%x " + "ramoops.mem_address=0x%llx " + "ramoops.mem_size=0x%lx " + "ramoops.ecc=%d", + cxt->record_size, + cxt->console_size, + cxt->ftrace_size, + cxt->pmsg_size, + (unsigned long long)cxt->phys_addr, + mem_size, + ramoops_ecc); + globalvar_add_simple("linux.bootargs.ramoops", kernelargs); + } else { of_add_reserve_entry(cxt->phys_addr, cxt->phys_addr + mem_size); + of_register_fixup(ramoops_of_fixup, pdata); + } return 0; -- cgit v1.2.3 From dc89bfe90223c12028d1f2c35d55564b7f46a326 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 15 Mar 2019 10:14:52 +0100 Subject: pstore: ramoops: allow zapping invalid buffers in read-only mode The FS_PSTORE_RAMOOPS_RO configuration option keeps barebox from zapping (clearing and fixing header ecc) all ramoops buffers on initialization. It also stops barebox from zapping invalid buffers. This causes issues when the console writing code tries to use the uninitialized, invalid console buffer. Therefore, allow barebox to zap invalid buffers, the kernel will do so anyway if it finds broken buffers during its initialization. Signed-off-by: Philipp Zabel Signed-off-by: Sascha Hauer --- fs/pstore/ram.c | 2 ++ fs/pstore/ram_core.c | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 3daec0d0d8..734d0c3c1d 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -401,7 +401,9 @@ static int ramoops_init_prz(const char *name, return err; } +#ifndef CONFIG_FS_PSTORE_RAMOOPS_RO persistent_ram_zap(*prz); +#endif /* CONFIG_FS_PSTORE_RAMOOPS_RO */ *paddr += sz; diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 0f7003f937..06be47ce53 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c @@ -330,18 +330,12 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz) prz->old_log_size = 0; } -#ifdef CONFIG_FS_PSTORE_RAMOOPS_RO -void persistent_ram_zap(struct persistent_ram_zone *prz) -{ -} -#else void persistent_ram_zap(struct persistent_ram_zone *prz) { prz->buffer->start = 0; prz->buffer->size = 0; persistent_ram_update_header_ecc(prz); } -#endif /* CONFIG_PSTORE_RAMOOPS_RO */ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, struct persistent_ram_zone *prz, int memtype) -- cgit v1.2.3