11fff234dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 21fff234dSArd Biesheuvel /* 31fff234dSArd Biesheuvel * Copyright (C) 2013 Red Hat, Inc., Dave Young <dyoung@redhat.com> 41fff234dSArd Biesheuvel */ 51fff234dSArd Biesheuvel 61fff234dSArd Biesheuvel #include <linux/string.h> 71fff234dSArd Biesheuvel #include <linux/kernel.h> 81fff234dSArd Biesheuvel #include <linux/module.h> 91fff234dSArd Biesheuvel #include <linux/types.h> 101fff234dSArd Biesheuvel #include <linux/efi.h> 111fff234dSArd Biesheuvel #include <linux/slab.h> 121fff234dSArd Biesheuvel 131fff234dSArd Biesheuvel #include <asm/efi.h> 141fff234dSArd Biesheuvel #include <asm/setup.h> 151fff234dSArd Biesheuvel 161fff234dSArd Biesheuvel struct efi_runtime_map_entry { 171fff234dSArd Biesheuvel efi_memory_desc_t md; 181fff234dSArd Biesheuvel struct kobject kobj; /* kobject for each entry */ 191fff234dSArd Biesheuvel }; 201fff234dSArd Biesheuvel 211fff234dSArd Biesheuvel static struct efi_runtime_map_entry **map_entries; 221fff234dSArd Biesheuvel 231fff234dSArd Biesheuvel struct map_attribute { 241fff234dSArd Biesheuvel struct attribute attr; 251fff234dSArd Biesheuvel ssize_t (*show)(struct efi_runtime_map_entry *entry, char *buf); 261fff234dSArd Biesheuvel }; 271fff234dSArd Biesheuvel 281fff234dSArd Biesheuvel static inline struct map_attribute *to_map_attr(struct attribute *attr) 291fff234dSArd Biesheuvel { 301fff234dSArd Biesheuvel return container_of(attr, struct map_attribute, attr); 311fff234dSArd Biesheuvel } 321fff234dSArd Biesheuvel 331fff234dSArd Biesheuvel static ssize_t type_show(struct efi_runtime_map_entry *entry, char *buf) 341fff234dSArd Biesheuvel { 351fff234dSArd Biesheuvel return snprintf(buf, PAGE_SIZE, "0x%x\n", entry->md.type); 361fff234dSArd Biesheuvel } 371fff234dSArd Biesheuvel 381fff234dSArd Biesheuvel #define EFI_RUNTIME_FIELD(var) entry->md.var 391fff234dSArd Biesheuvel 401fff234dSArd Biesheuvel #define EFI_RUNTIME_U64_ATTR_SHOW(name) \ 411fff234dSArd Biesheuvel static ssize_t name##_show(struct efi_runtime_map_entry *entry, char *buf) \ 421fff234dSArd Biesheuvel { \ 431fff234dSArd Biesheuvel return snprintf(buf, PAGE_SIZE, "0x%llx\n", EFI_RUNTIME_FIELD(name)); \ 441fff234dSArd Biesheuvel } 451fff234dSArd Biesheuvel 461fff234dSArd Biesheuvel EFI_RUNTIME_U64_ATTR_SHOW(phys_addr); 471fff234dSArd Biesheuvel EFI_RUNTIME_U64_ATTR_SHOW(virt_addr); 481fff234dSArd Biesheuvel EFI_RUNTIME_U64_ATTR_SHOW(num_pages); 491fff234dSArd Biesheuvel EFI_RUNTIME_U64_ATTR_SHOW(attribute); 501fff234dSArd Biesheuvel 511fff234dSArd Biesheuvel static inline struct efi_runtime_map_entry *to_map_entry(struct kobject *kobj) 521fff234dSArd Biesheuvel { 531fff234dSArd Biesheuvel return container_of(kobj, struct efi_runtime_map_entry, kobj); 541fff234dSArd Biesheuvel } 551fff234dSArd Biesheuvel 561fff234dSArd Biesheuvel static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, 571fff234dSArd Biesheuvel char *buf) 581fff234dSArd Biesheuvel { 591fff234dSArd Biesheuvel struct efi_runtime_map_entry *entry = to_map_entry(kobj); 601fff234dSArd Biesheuvel struct map_attribute *map_attr = to_map_attr(attr); 611fff234dSArd Biesheuvel 621fff234dSArd Biesheuvel return map_attr->show(entry, buf); 631fff234dSArd Biesheuvel } 641fff234dSArd Biesheuvel 651fff234dSArd Biesheuvel static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400); 661fff234dSArd Biesheuvel static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400); 671fff234dSArd Biesheuvel static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400); 681fff234dSArd Biesheuvel static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400); 691fff234dSArd Biesheuvel static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400); 701fff234dSArd Biesheuvel 711fff234dSArd Biesheuvel /* 721fff234dSArd Biesheuvel * These are default attributes that are added for every memmap entry. 731fff234dSArd Biesheuvel */ 741fff234dSArd Biesheuvel static struct attribute *def_attrs[] = { 751fff234dSArd Biesheuvel &map_type_attr.attr, 761fff234dSArd Biesheuvel &map_phys_addr_attr.attr, 771fff234dSArd Biesheuvel &map_virt_addr_attr.attr, 781fff234dSArd Biesheuvel &map_num_pages_attr.attr, 791fff234dSArd Biesheuvel &map_attribute_attr.attr, 801fff234dSArd Biesheuvel NULL 811fff234dSArd Biesheuvel }; 821fff234dSArd Biesheuvel ATTRIBUTE_GROUPS(def); 831fff234dSArd Biesheuvel 841fff234dSArd Biesheuvel static const struct sysfs_ops map_attr_ops = { 851fff234dSArd Biesheuvel .show = map_attr_show, 861fff234dSArd Biesheuvel }; 871fff234dSArd Biesheuvel 881fff234dSArd Biesheuvel static void map_release(struct kobject *kobj) 891fff234dSArd Biesheuvel { 901fff234dSArd Biesheuvel struct efi_runtime_map_entry *entry; 911fff234dSArd Biesheuvel 921fff234dSArd Biesheuvel entry = to_map_entry(kobj); 931fff234dSArd Biesheuvel kfree(entry); 941fff234dSArd Biesheuvel } 951fff234dSArd Biesheuvel 96*42a8af0fSThomas Weißschuh static const struct kobj_type __refconst map_ktype = { 971fff234dSArd Biesheuvel .sysfs_ops = &map_attr_ops, 981fff234dSArd Biesheuvel .default_groups = def_groups, 991fff234dSArd Biesheuvel .release = map_release, 1001fff234dSArd Biesheuvel }; 1011fff234dSArd Biesheuvel 1021fff234dSArd Biesheuvel static struct kset *map_kset; 1031fff234dSArd Biesheuvel 1041fff234dSArd Biesheuvel static struct efi_runtime_map_entry * 1051fff234dSArd Biesheuvel add_sysfs_runtime_map_entry(struct kobject *kobj, int nr, 1061fff234dSArd Biesheuvel efi_memory_desc_t *md) 1071fff234dSArd Biesheuvel { 1081fff234dSArd Biesheuvel int ret; 1091fff234dSArd Biesheuvel struct efi_runtime_map_entry *entry; 1101fff234dSArd Biesheuvel 1111fff234dSArd Biesheuvel if (!map_kset) { 1121fff234dSArd Biesheuvel map_kset = kset_create_and_add("runtime-map", NULL, kobj); 1131fff234dSArd Biesheuvel if (!map_kset) 1141fff234dSArd Biesheuvel return ERR_PTR(-ENOMEM); 1151fff234dSArd Biesheuvel } 1161fff234dSArd Biesheuvel 1171fff234dSArd Biesheuvel entry = kzalloc(sizeof(*entry), GFP_KERNEL); 1181fff234dSArd Biesheuvel if (!entry) { 1191fff234dSArd Biesheuvel kset_unregister(map_kset); 1201fff234dSArd Biesheuvel map_kset = NULL; 1211fff234dSArd Biesheuvel return ERR_PTR(-ENOMEM); 1221fff234dSArd Biesheuvel } 1231fff234dSArd Biesheuvel 1241fff234dSArd Biesheuvel memcpy(&entry->md, md, sizeof(efi_memory_desc_t)); 1251fff234dSArd Biesheuvel 1261fff234dSArd Biesheuvel kobject_init(&entry->kobj, &map_ktype); 1271fff234dSArd Biesheuvel entry->kobj.kset = map_kset; 1281fff234dSArd Biesheuvel ret = kobject_add(&entry->kobj, NULL, "%d", nr); 1291fff234dSArd Biesheuvel if (ret) { 1301fff234dSArd Biesheuvel kobject_put(&entry->kobj); 1311fff234dSArd Biesheuvel kset_unregister(map_kset); 1321fff234dSArd Biesheuvel map_kset = NULL; 1331fff234dSArd Biesheuvel return ERR_PTR(ret); 1341fff234dSArd Biesheuvel } 1351fff234dSArd Biesheuvel 1361fff234dSArd Biesheuvel return entry; 1371fff234dSArd Biesheuvel } 1381fff234dSArd Biesheuvel 1391fff234dSArd Biesheuvel int efi_get_runtime_map_size(void) 1401fff234dSArd Biesheuvel { 1411fff234dSArd Biesheuvel return efi.memmap.nr_map * efi.memmap.desc_size; 1421fff234dSArd Biesheuvel } 1431fff234dSArd Biesheuvel 1441fff234dSArd Biesheuvel int efi_get_runtime_map_desc_size(void) 1451fff234dSArd Biesheuvel { 1461fff234dSArd Biesheuvel return efi.memmap.desc_size; 1471fff234dSArd Biesheuvel } 1481fff234dSArd Biesheuvel 1491fff234dSArd Biesheuvel int efi_runtime_map_copy(void *buf, size_t bufsz) 1501fff234dSArd Biesheuvel { 1511fff234dSArd Biesheuvel size_t sz = efi_get_runtime_map_size(); 1521fff234dSArd Biesheuvel 1531fff234dSArd Biesheuvel if (sz > bufsz) 1541fff234dSArd Biesheuvel sz = bufsz; 1551fff234dSArd Biesheuvel 1561fff234dSArd Biesheuvel memcpy(buf, efi.memmap.map, sz); 1571fff234dSArd Biesheuvel return 0; 1581fff234dSArd Biesheuvel } 1591fff234dSArd Biesheuvel 1601fff234dSArd Biesheuvel static int __init efi_runtime_map_init(void) 1611fff234dSArd Biesheuvel { 1621fff234dSArd Biesheuvel int i, j, ret = 0; 1631fff234dSArd Biesheuvel struct efi_runtime_map_entry *entry; 1641fff234dSArd Biesheuvel efi_memory_desc_t *md; 1651fff234dSArd Biesheuvel 1661fff234dSArd Biesheuvel if (!efi_enabled(EFI_MEMMAP) || !efi_kobj) 1671fff234dSArd Biesheuvel return 0; 1681fff234dSArd Biesheuvel 1691fff234dSArd Biesheuvel map_entries = kcalloc(efi.memmap.nr_map, sizeof(entry), GFP_KERNEL); 1701fff234dSArd Biesheuvel if (!map_entries) { 1711fff234dSArd Biesheuvel ret = -ENOMEM; 1721fff234dSArd Biesheuvel goto out; 1731fff234dSArd Biesheuvel } 1741fff234dSArd Biesheuvel 1751fff234dSArd Biesheuvel i = 0; 1761fff234dSArd Biesheuvel for_each_efi_memory_desc(md) { 1771fff234dSArd Biesheuvel entry = add_sysfs_runtime_map_entry(efi_kobj, i, md); 1781fff234dSArd Biesheuvel if (IS_ERR(entry)) { 1791fff234dSArd Biesheuvel ret = PTR_ERR(entry); 1801fff234dSArd Biesheuvel goto out_add_entry; 1811fff234dSArd Biesheuvel } 1821fff234dSArd Biesheuvel *(map_entries + i++) = entry; 1831fff234dSArd Biesheuvel } 1841fff234dSArd Biesheuvel 1851fff234dSArd Biesheuvel return 0; 1861fff234dSArd Biesheuvel out_add_entry: 1871fff234dSArd Biesheuvel for (j = i - 1; j >= 0; j--) { 1881fff234dSArd Biesheuvel entry = *(map_entries + j); 1891fff234dSArd Biesheuvel kobject_put(&entry->kobj); 1901fff234dSArd Biesheuvel } 1911fff234dSArd Biesheuvel out: 1921fff234dSArd Biesheuvel return ret; 1931fff234dSArd Biesheuvel } 1941fff234dSArd Biesheuvel subsys_initcall_sync(efi_runtime_map_init); 195