Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * linux/drivers/efi/runtime-map.c
4 : : * Copyright (C) 2013 Red Hat, Inc., Dave Young <dyoung@redhat.com>
5 : : */
6 : :
7 : : #include <linux/string.h>
8 : : #include <linux/kernel.h>
9 : : #include <linux/module.h>
10 : : #include <linux/types.h>
11 : : #include <linux/efi.h>
12 : : #include <linux/slab.h>
13 : :
14 : : #include <asm/setup.h>
15 : :
16 : : struct efi_runtime_map_entry {
17 : : efi_memory_desc_t md;
18 : : struct kobject kobj; /* kobject for each entry */
19 : : };
20 : :
21 : : static struct efi_runtime_map_entry **map_entries;
22 : :
23 : : struct map_attribute {
24 : : struct attribute attr;
25 : : ssize_t (*show)(struct efi_runtime_map_entry *entry, char *buf);
26 : : };
27 : :
28 : 0 : static inline struct map_attribute *to_map_attr(struct attribute *attr)
29 : : {
30 : 0 : return container_of(attr, struct map_attribute, attr);
31 : : }
32 : :
33 : 0 : static ssize_t type_show(struct efi_runtime_map_entry *entry, char *buf)
34 : : {
35 : 0 : return snprintf(buf, PAGE_SIZE, "0x%x\n", entry->md.type);
36 : : }
37 : :
38 : : #define EFI_RUNTIME_FIELD(var) entry->md.var
39 : :
40 : : #define EFI_RUNTIME_U64_ATTR_SHOW(name) \
41 : : static ssize_t name##_show(struct efi_runtime_map_entry *entry, char *buf) \
42 : : { \
43 : : return snprintf(buf, PAGE_SIZE, "0x%llx\n", EFI_RUNTIME_FIELD(name)); \
44 : : }
45 : :
46 : 0 : EFI_RUNTIME_U64_ATTR_SHOW(phys_addr);
47 : 0 : EFI_RUNTIME_U64_ATTR_SHOW(virt_addr);
48 : 0 : EFI_RUNTIME_U64_ATTR_SHOW(num_pages);
49 : 0 : EFI_RUNTIME_U64_ATTR_SHOW(attribute);
50 : :
51 : 0 : static inline struct efi_runtime_map_entry *to_map_entry(struct kobject *kobj)
52 : : {
53 : 0 : return container_of(kobj, struct efi_runtime_map_entry, kobj);
54 : : }
55 : :
56 : 0 : static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
57 : : char *buf)
58 : : {
59 : 0 : struct efi_runtime_map_entry *entry = to_map_entry(kobj);
60 : 0 : struct map_attribute *map_attr = to_map_attr(attr);
61 : :
62 : 0 : return map_attr->show(entry, buf);
63 : : }
64 : :
65 : : static struct map_attribute map_type_attr = __ATTR_RO_MODE(type, 0400);
66 : : static struct map_attribute map_phys_addr_attr = __ATTR_RO_MODE(phys_addr, 0400);
67 : : static struct map_attribute map_virt_addr_attr = __ATTR_RO_MODE(virt_addr, 0400);
68 : : static struct map_attribute map_num_pages_attr = __ATTR_RO_MODE(num_pages, 0400);
69 : : static struct map_attribute map_attribute_attr = __ATTR_RO_MODE(attribute, 0400);
70 : :
71 : : /*
72 : : * These are default attributes that are added for every memmap entry.
73 : : */
74 : : static struct attribute *def_attrs[] = {
75 : : &map_type_attr.attr,
76 : : &map_phys_addr_attr.attr,
77 : : &map_virt_addr_attr.attr,
78 : : &map_num_pages_attr.attr,
79 : : &map_attribute_attr.attr,
80 : : NULL
81 : : };
82 : :
83 : : static const struct sysfs_ops map_attr_ops = {
84 : : .show = map_attr_show,
85 : : };
86 : :
87 : 0 : static void map_release(struct kobject *kobj)
88 : : {
89 : 0 : struct efi_runtime_map_entry *entry;
90 : :
91 : 0 : entry = to_map_entry(kobj);
92 : 0 : kfree(entry);
93 : 0 : }
94 : :
95 : : static struct kobj_type __refdata map_ktype = {
96 : : .sysfs_ops = &map_attr_ops,
97 : : .default_attrs = def_attrs,
98 : : .release = map_release,
99 : : };
100 : :
101 : : static struct kset *map_kset;
102 : :
103 : : static struct efi_runtime_map_entry *
104 : 0 : add_sysfs_runtime_map_entry(struct kobject *kobj, int nr,
105 : : efi_memory_desc_t *md)
106 : : {
107 : 0 : int ret;
108 : 0 : struct efi_runtime_map_entry *entry;
109 : :
110 [ # # ]: 0 : if (!map_kset) {
111 : 0 : map_kset = kset_create_and_add("runtime-map", NULL, kobj);
112 [ # # ]: 0 : if (!map_kset)
113 : : return ERR_PTR(-ENOMEM);
114 : : }
115 : :
116 : 0 : entry = kzalloc(sizeof(*entry), GFP_KERNEL);
117 [ # # ]: 0 : if (!entry) {
118 : 0 : kset_unregister(map_kset);
119 : 0 : map_kset = NULL;
120 : 0 : return ERR_PTR(-ENOMEM);
121 : : }
122 : :
123 : 0 : memcpy(&entry->md, md, sizeof(efi_memory_desc_t));
124 : :
125 : 0 : kobject_init(&entry->kobj, &map_ktype);
126 : 0 : entry->kobj.kset = map_kset;
127 : 0 : ret = kobject_add(&entry->kobj, NULL, "%d", nr);
128 [ # # ]: 0 : if (ret) {
129 : 0 : kobject_put(&entry->kobj);
130 : 0 : kset_unregister(map_kset);
131 : 0 : map_kset = NULL;
132 : 0 : return ERR_PTR(ret);
133 : : }
134 : :
135 : : return entry;
136 : : }
137 : :
138 : 0 : int efi_get_runtime_map_size(void)
139 : : {
140 : 0 : return efi.memmap.nr_map * efi.memmap.desc_size;
141 : : }
142 : :
143 : 0 : int efi_get_runtime_map_desc_size(void)
144 : : {
145 : 0 : return efi.memmap.desc_size;
146 : : }
147 : :
148 : 0 : int efi_runtime_map_copy(void *buf, size_t bufsz)
149 : : {
150 : 0 : size_t sz = efi_get_runtime_map_size();
151 : :
152 : 0 : if (sz > bufsz)
153 : : sz = bufsz;
154 : :
155 : 0 : memcpy(buf, efi.memmap.map, sz);
156 : 0 : return 0;
157 : : }
158 : :
159 : 0 : int __init efi_runtime_map_init(struct kobject *efi_kobj)
160 : : {
161 : 0 : int i, j, ret = 0;
162 : 0 : struct efi_runtime_map_entry *entry;
163 : 0 : efi_memory_desc_t *md;
164 : :
165 [ # # ]: 0 : if (!efi_enabled(EFI_MEMMAP))
166 : : return 0;
167 : :
168 : 0 : map_entries = kcalloc(efi.memmap.nr_map, sizeof(entry), GFP_KERNEL);
169 [ # # ]: 0 : if (!map_entries) {
170 : 0 : ret = -ENOMEM;
171 : 0 : goto out;
172 : : }
173 : :
174 : 0 : i = 0;
175 [ # # # # ]: 0 : for_each_efi_memory_desc(md) {
176 : 0 : entry = add_sysfs_runtime_map_entry(efi_kobj, i, md);
177 [ # # ]: 0 : if (IS_ERR(entry)) {
178 : 0 : ret = PTR_ERR(entry);
179 : 0 : goto out_add_entry;
180 : : }
181 : 0 : *(map_entries + i++) = entry;
182 : : }
183 : :
184 : : return 0;
185 : : out_add_entry:
186 [ # # ]: 0 : for (j = i - 1; j >= 0; j--) {
187 : 0 : entry = *(map_entries + j);
188 : 0 : kobject_put(&entry->kobj);
189 : : }
190 : 0 : out:
191 : : return ret;
192 : : }
|