Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * linux/drivers/efi/runtime-map.c
0004  * Copyright (C) 2013 Red Hat, Inc., Dave Young <dyoung@redhat.com>
0005  */
0006 
0007 #include <linux/string.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/efi.h>
0012 #include <linux/slab.h>
0013 
0014 #include <asm/setup.h>
0015 
0016 struct efi_runtime_map_entry {
0017     efi_memory_desc_t md;
0018     struct kobject kobj;   /* kobject for each entry */
0019 };
0020 
0021 static struct efi_runtime_map_entry **map_entries;
0022 
0023 struct map_attribute {
0024     struct attribute attr;
0025     ssize_t (*show)(struct efi_runtime_map_entry *entry, char *buf);
0026 };
0027 
0028 static inline struct map_attribute *to_map_attr(struct attribute *attr)
0029 {
0030     return container_of(attr, struct map_attribute, attr);
0031 }
0032 
0033 static ssize_t type_show(struct efi_runtime_map_entry *entry, char *buf)
0034 {
0035     return snprintf(buf, PAGE_SIZE, "0x%x\n", entry->md.type);
0036 }
0037 
0038 #define EFI_RUNTIME_FIELD(var) entry->md.var
0039 
0040 #define EFI_RUNTIME_U64_ATTR_SHOW(name) \
0041 static ssize_t name##_show(struct efi_runtime_map_entry *entry, char *buf) \
0042 { \
0043     return snprintf(buf, PAGE_SIZE, "0x%llx\n", EFI_RUNTIME_FIELD(name)); \
0044 }
0045 
0046 EFI_RUNTIME_U64_ATTR_SHOW(phys_addr);
0047 EFI_RUNTIME_U64_ATTR_SHOW(virt_addr);
0048 EFI_RUNTIME_U64_ATTR_SHOW(num_pages);
0049 EFI_RUNTIME_U64_ATTR_SHOW(attribute);
0050 
0051 static inline struct efi_runtime_map_entry *to_map_entry(struct kobject *kobj)
0052 {
0053     return container_of(kobj, struct efi_runtime_map_entry, kobj);
0054 }
0055 
0056 static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
0057                   char *buf)
0058 {
0059     struct efi_runtime_map_entry *entry = to_map_entry(kobj);
0060     struct map_attribute *map_attr = to_map_attr(attr);
0061 
0062     return map_attr->show(entry, buf);
0063 }
0064 
0065 static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400);
0066 static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400);
0067 static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400);
0068 static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400);
0069 static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400);
0070 
0071 /*
0072  * These are default attributes that are added for every memmap entry.
0073  */
0074 static struct attribute *def_attrs[] = {
0075     &map_type_attr.attr,
0076     &map_phys_addr_attr.attr,
0077     &map_virt_addr_attr.attr,
0078     &map_num_pages_attr.attr,
0079     &map_attribute_attr.attr,
0080     NULL
0081 };
0082 ATTRIBUTE_GROUPS(def);
0083 
0084 static const struct sysfs_ops map_attr_ops = {
0085     .show = map_attr_show,
0086 };
0087 
0088 static void map_release(struct kobject *kobj)
0089 {
0090     struct efi_runtime_map_entry *entry;
0091 
0092     entry = to_map_entry(kobj);
0093     kfree(entry);
0094 }
0095 
0096 static struct kobj_type __refdata map_ktype = {
0097     .sysfs_ops  = &map_attr_ops,
0098     .default_groups = def_groups,
0099     .release    = map_release,
0100 };
0101 
0102 static struct kset *map_kset;
0103 
0104 static struct efi_runtime_map_entry *
0105 add_sysfs_runtime_map_entry(struct kobject *kobj, int nr,
0106                 efi_memory_desc_t *md)
0107 {
0108     int ret;
0109     struct efi_runtime_map_entry *entry;
0110 
0111     if (!map_kset) {
0112         map_kset = kset_create_and_add("runtime-map", NULL, kobj);
0113         if (!map_kset)
0114             return ERR_PTR(-ENOMEM);
0115     }
0116 
0117     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0118     if (!entry) {
0119         kset_unregister(map_kset);
0120         map_kset = NULL;
0121         return ERR_PTR(-ENOMEM);
0122     }
0123 
0124     memcpy(&entry->md, md, sizeof(efi_memory_desc_t));
0125 
0126     kobject_init(&entry->kobj, &map_ktype);
0127     entry->kobj.kset = map_kset;
0128     ret = kobject_add(&entry->kobj, NULL, "%d", nr);
0129     if (ret) {
0130         kobject_put(&entry->kobj);
0131         kset_unregister(map_kset);
0132         map_kset = NULL;
0133         return ERR_PTR(ret);
0134     }
0135 
0136     return entry;
0137 }
0138 
0139 int efi_get_runtime_map_size(void)
0140 {
0141     return efi.memmap.nr_map * efi.memmap.desc_size;
0142 }
0143 
0144 int efi_get_runtime_map_desc_size(void)
0145 {
0146     return efi.memmap.desc_size;
0147 }
0148 
0149 int efi_runtime_map_copy(void *buf, size_t bufsz)
0150 {
0151     size_t sz = efi_get_runtime_map_size();
0152 
0153     if (sz > bufsz)
0154         sz = bufsz;
0155 
0156     memcpy(buf, efi.memmap.map, sz);
0157     return 0;
0158 }
0159 
0160 int __init efi_runtime_map_init(struct kobject *efi_kobj)
0161 {
0162     int i, j, ret = 0;
0163     struct efi_runtime_map_entry *entry;
0164     efi_memory_desc_t *md;
0165 
0166     if (!efi_enabled(EFI_MEMMAP))
0167         return 0;
0168 
0169     map_entries = kcalloc(efi.memmap.nr_map, sizeof(entry), GFP_KERNEL);
0170     if (!map_entries) {
0171         ret = -ENOMEM;
0172         goto out;
0173     }
0174 
0175     i = 0;
0176     for_each_efi_memory_desc(md) {
0177         entry = add_sysfs_runtime_map_entry(efi_kobj, i, md);
0178         if (IS_ERR(entry)) {
0179             ret = PTR_ERR(entry);
0180             goto out_add_entry;
0181         }
0182         *(map_entries + i++) = entry;
0183     }
0184 
0185     return 0;
0186 out_add_entry:
0187     for (j = i - 1; j >= 0; j--) {
0188         entry = *(map_entries + j);
0189         kobject_put(&entry->kobj);
0190     }
0191 out:
0192     return ret;
0193 }