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
to_map_attr(struct attribute * attr)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
type_show(struct efi_runtime_map_entry * entry,char * buf)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
to_map_entry(struct kobject * kobj)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
map_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)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
map_release(struct kobject * kobj)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 *
add_sysfs_runtime_map_entry(struct kobject * kobj,int nr,efi_memory_desc_t * md)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
efi_get_runtime_map_size(void)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
efi_get_runtime_map_desc_size(void)1441fff234dSArd Biesheuvel int efi_get_runtime_map_desc_size(void)
1451fff234dSArd Biesheuvel {
1461fff234dSArd Biesheuvel return efi.memmap.desc_size;
1471fff234dSArd Biesheuvel }
1481fff234dSArd Biesheuvel
efi_runtime_map_copy(void * buf,size_t bufsz)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
efi_runtime_map_init(void)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