opal-elog.c (8021B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Error log support on PowerNV. 4 * 5 * Copyright 2013,2014 IBM Corp. 6 */ 7#include <linux/kernel.h> 8#include <linux/init.h> 9#include <linux/interrupt.h> 10#include <linux/of.h> 11#include <linux/slab.h> 12#include <linux/sysfs.h> 13#include <linux/fs.h> 14#include <linux/vmalloc.h> 15#include <linux/fcntl.h> 16#include <linux/kobject.h> 17#include <linux/uaccess.h> 18#include <asm/opal.h> 19 20struct elog_obj { 21 struct kobject kobj; 22 struct bin_attribute raw_attr; 23 uint64_t id; 24 uint64_t type; 25 size_t size; 26 char *buffer; 27}; 28#define to_elog_obj(x) container_of(x, struct elog_obj, kobj) 29 30struct elog_attribute { 31 struct attribute attr; 32 ssize_t (*show)(struct elog_obj *elog, struct elog_attribute *attr, 33 char *buf); 34 ssize_t (*store)(struct elog_obj *elog, struct elog_attribute *attr, 35 const char *buf, size_t count); 36}; 37#define to_elog_attr(x) container_of(x, struct elog_attribute, attr) 38 39static ssize_t elog_id_show(struct elog_obj *elog_obj, 40 struct elog_attribute *attr, 41 char *buf) 42{ 43 return sprintf(buf, "0x%llx\n", elog_obj->id); 44} 45 46static const char *elog_type_to_string(uint64_t type) 47{ 48 switch (type) { 49 case 0: return "PEL"; 50 default: return "unknown"; 51 } 52} 53 54static ssize_t elog_type_show(struct elog_obj *elog_obj, 55 struct elog_attribute *attr, 56 char *buf) 57{ 58 return sprintf(buf, "0x%llx %s\n", 59 elog_obj->type, 60 elog_type_to_string(elog_obj->type)); 61} 62 63static ssize_t elog_ack_show(struct elog_obj *elog_obj, 64 struct elog_attribute *attr, 65 char *buf) 66{ 67 return sprintf(buf, "ack - acknowledge log message\n"); 68} 69 70static ssize_t elog_ack_store(struct elog_obj *elog_obj, 71 struct elog_attribute *attr, 72 const char *buf, 73 size_t count) 74{ 75 /* 76 * Try to self remove this attribute. If we are successful, 77 * delete the kobject itself. 78 */ 79 if (sysfs_remove_file_self(&elog_obj->kobj, &attr->attr)) { 80 opal_send_ack_elog(elog_obj->id); 81 kobject_put(&elog_obj->kobj); 82 } 83 return count; 84} 85 86static struct elog_attribute id_attribute = 87 __ATTR(id, 0444, elog_id_show, NULL); 88static struct elog_attribute type_attribute = 89 __ATTR(type, 0444, elog_type_show, NULL); 90static struct elog_attribute ack_attribute = 91 __ATTR(acknowledge, 0660, elog_ack_show, elog_ack_store); 92 93static struct kset *elog_kset; 94 95static ssize_t elog_attr_show(struct kobject *kobj, 96 struct attribute *attr, 97 char *buf) 98{ 99 struct elog_attribute *attribute; 100 struct elog_obj *elog; 101 102 attribute = to_elog_attr(attr); 103 elog = to_elog_obj(kobj); 104 105 if (!attribute->show) 106 return -EIO; 107 108 return attribute->show(elog, attribute, buf); 109} 110 111static ssize_t elog_attr_store(struct kobject *kobj, 112 struct attribute *attr, 113 const char *buf, size_t len) 114{ 115 struct elog_attribute *attribute; 116 struct elog_obj *elog; 117 118 attribute = to_elog_attr(attr); 119 elog = to_elog_obj(kobj); 120 121 if (!attribute->store) 122 return -EIO; 123 124 return attribute->store(elog, attribute, buf, len); 125} 126 127static const struct sysfs_ops elog_sysfs_ops = { 128 .show = elog_attr_show, 129 .store = elog_attr_store, 130}; 131 132static void elog_release(struct kobject *kobj) 133{ 134 struct elog_obj *elog; 135 136 elog = to_elog_obj(kobj); 137 kfree(elog->buffer); 138 kfree(elog); 139} 140 141static struct attribute *elog_default_attrs[] = { 142 &id_attribute.attr, 143 &type_attribute.attr, 144 &ack_attribute.attr, 145 NULL, 146}; 147ATTRIBUTE_GROUPS(elog_default); 148 149static struct kobj_type elog_ktype = { 150 .sysfs_ops = &elog_sysfs_ops, 151 .release = &elog_release, 152 .default_groups = elog_default_groups, 153}; 154 155/* Maximum size of a single log on FSP is 16KB */ 156#define OPAL_MAX_ERRLOG_SIZE 16384 157 158static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj, 159 struct bin_attribute *bin_attr, 160 char *buffer, loff_t pos, size_t count) 161{ 162 int opal_rc; 163 164 struct elog_obj *elog = to_elog_obj(kobj); 165 166 /* We may have had an error reading before, so let's retry */ 167 if (!elog->buffer) { 168 elog->buffer = kzalloc(elog->size, GFP_KERNEL); 169 if (!elog->buffer) 170 return -EIO; 171 172 opal_rc = opal_read_elog(__pa(elog->buffer), 173 elog->size, elog->id); 174 if (opal_rc != OPAL_SUCCESS) { 175 pr_err_ratelimited("ELOG: log read failed for log-id=%llx\n", 176 elog->id); 177 kfree(elog->buffer); 178 elog->buffer = NULL; 179 return -EIO; 180 } 181 } 182 183 memcpy(buffer, elog->buffer + pos, count); 184 185 return count; 186} 187 188static void create_elog_obj(uint64_t id, size_t size, uint64_t type) 189{ 190 struct elog_obj *elog; 191 int rc; 192 193 elog = kzalloc(sizeof(*elog), GFP_KERNEL); 194 if (!elog) 195 return; 196 197 elog->kobj.kset = elog_kset; 198 199 kobject_init(&elog->kobj, &elog_ktype); 200 201 sysfs_bin_attr_init(&elog->raw_attr); 202 203 elog->raw_attr.attr.name = "raw"; 204 elog->raw_attr.attr.mode = 0400; 205 elog->raw_attr.size = size; 206 elog->raw_attr.read = raw_attr_read; 207 208 elog->id = id; 209 elog->size = size; 210 elog->type = type; 211 212 elog->buffer = kzalloc(elog->size, GFP_KERNEL); 213 214 if (elog->buffer) { 215 rc = opal_read_elog(__pa(elog->buffer), 216 elog->size, elog->id); 217 if (rc != OPAL_SUCCESS) { 218 pr_err("ELOG: log read failed for log-id=%llx\n", 219 elog->id); 220 kfree(elog->buffer); 221 elog->buffer = NULL; 222 } 223 } 224 225 rc = kobject_add(&elog->kobj, NULL, "0x%llx", id); 226 if (rc) { 227 kobject_put(&elog->kobj); 228 return; 229 } 230 231 /* 232 * As soon as the sysfs file for this elog is created/activated there is 233 * a chance the opal_errd daemon (or any userspace) might read and 234 * acknowledge the elog before kobject_uevent() is called. If that 235 * happens then there is a potential race between 236 * elog_ack_store->kobject_put() and kobject_uevent() which leads to a 237 * use-after-free of a kernfs object resulting in a kernel crash. 238 * 239 * To avoid that, we need to take a reference on behalf of the bin file, 240 * so that our reference remains valid while we call kobject_uevent(). 241 * We then drop our reference before exiting the function, leaving the 242 * bin file to drop the last reference (if it hasn't already). 243 */ 244 245 /* Take a reference for the bin file */ 246 kobject_get(&elog->kobj); 247 rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr); 248 if (rc == 0) { 249 kobject_uevent(&elog->kobj, KOBJ_ADD); 250 } else { 251 /* Drop the reference taken for the bin file */ 252 kobject_put(&elog->kobj); 253 } 254 255 /* Drop our reference */ 256 kobject_put(&elog->kobj); 257 258 return; 259} 260 261static irqreturn_t elog_event(int irq, void *data) 262{ 263 __be64 size; 264 __be64 id; 265 __be64 type; 266 uint64_t elog_size; 267 uint64_t log_id; 268 uint64_t elog_type; 269 int rc; 270 char name[2+16+1]; 271 struct kobject *kobj; 272 273 rc = opal_get_elog_size(&id, &size, &type); 274 if (rc != OPAL_SUCCESS) { 275 pr_err("ELOG: OPAL log info read failed\n"); 276 return IRQ_HANDLED; 277 } 278 279 elog_size = be64_to_cpu(size); 280 log_id = be64_to_cpu(id); 281 elog_type = be64_to_cpu(type); 282 283 WARN_ON(elog_size > OPAL_MAX_ERRLOG_SIZE); 284 285 if (elog_size >= OPAL_MAX_ERRLOG_SIZE) 286 elog_size = OPAL_MAX_ERRLOG_SIZE; 287 288 sprintf(name, "0x%llx", log_id); 289 290 /* we may get notified twice, let's handle 291 * that gracefully and not create two conflicting 292 * entries. 293 */ 294 kobj = kset_find_obj(elog_kset, name); 295 if (kobj) { 296 /* Drop reference added by kset_find_obj() */ 297 kobject_put(kobj); 298 return IRQ_HANDLED; 299 } 300 301 create_elog_obj(log_id, elog_size, elog_type); 302 303 return IRQ_HANDLED; 304} 305 306int __init opal_elog_init(void) 307{ 308 int rc = 0, irq; 309 310 /* ELOG not supported by firmware */ 311 if (!opal_check_token(OPAL_ELOG_READ)) 312 return -1; 313 314 elog_kset = kset_create_and_add("elog", NULL, opal_kobj); 315 if (!elog_kset) { 316 pr_warn("%s: failed to create elog kset\n", __func__); 317 return -1; 318 } 319 320 irq = opal_event_request(ilog2(OPAL_EVENT_ERROR_LOG_AVAIL)); 321 if (!irq) { 322 pr_err("%s: Can't register OPAL event irq (%d)\n", 323 __func__, irq); 324 return irq; 325 } 326 327 rc = request_threaded_irq(irq, NULL, elog_event, 328 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "opal-elog", NULL); 329 if (rc) { 330 pr_err("%s: Can't request OPAL event irq (%d)\n", 331 __func__, rc); 332 return rc; 333 } 334 335 /* We are now ready to pull error logs from opal. */ 336 if (opal_check_token(OPAL_ELOG_RESEND)) 337 opal_resend_pending_logs(); 338 339 return 0; 340}